mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Cache avatar sending, fix image file preview
- Add AvatarBroadcaster, in charge of making sure our friends have our avatar without spamming file transfers - Fix file sending code not closing the file after transfer, which prevented file previews, and make the QFile a shared_ptr to fix the obvious memory leak Some small additions to Core to support AvatarBroadcaster
This commit is contained in:
parent
9ece486e22
commit
bd5eebbc2e
6
qtox.pro
6
qtox.pro
|
@ -430,7 +430,8 @@ SOURCES += \
|
||||||
src/core/coreencryption.cpp \
|
src/core/coreencryption.cpp \
|
||||||
src/core/corefile.cpp \
|
src/core/corefile.cpp \
|
||||||
src/core/corestructs.cpp \
|
src/core/corestructs.cpp \
|
||||||
src/profilelocker.cpp
|
src/profilelocker.cpp \
|
||||||
|
src/avatarbroadcaster.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/audio.h \
|
src/audio.h \
|
||||||
|
@ -455,4 +456,5 @@ HEADERS += \
|
||||||
src/widget/gui.h \
|
src/widget/gui.h \
|
||||||
src/toxme.h \
|
src/toxme.h \
|
||||||
src/misc/qrwidget.h \
|
src/misc/qrwidget.h \
|
||||||
src/profilelocker.h
|
src/profilelocker.h \
|
||||||
|
src/avatarbroadcaster.h
|
||||||
|
|
41
src/avatarbroadcaster.cpp
Normal file
41
src/avatarbroadcaster.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include "avatarbroadcaster.h"
|
||||||
|
#include "src/core/core.h"
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
QByteArray AvatarBroadcaster::avatarData;
|
||||||
|
QMap<uint32_t, bool> AvatarBroadcaster::friendsSentTo;
|
||||||
|
|
||||||
|
static QMetaObject::Connection autoBroadcastConn;
|
||||||
|
static auto autoBroadcast = [](uint32_t friendId, Status)
|
||||||
|
{
|
||||||
|
AvatarBroadcaster::sendAvatarTo(friendId);
|
||||||
|
};
|
||||||
|
|
||||||
|
void AvatarBroadcaster::setAvatar(QByteArray data)
|
||||||
|
{
|
||||||
|
avatarData = data;
|
||||||
|
friendsSentTo.clear();
|
||||||
|
|
||||||
|
QVector<uint32_t> friends = Core::getInstance()->getFriendList();
|
||||||
|
for (uint32_t friendId : friends)
|
||||||
|
sendAvatarTo(friendId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarBroadcaster::sendAvatarTo(uint32_t friendId)
|
||||||
|
{
|
||||||
|
if (friendsSentTo.contains(friendId) && friendsSentTo[friendId])
|
||||||
|
return;
|
||||||
|
if (!Core::getInstance()->isFriendOnline(friendId))
|
||||||
|
return;
|
||||||
|
qDebug() << "AvatarBroadcaster: Sending avatar to "<<friendId;
|
||||||
|
Core::getInstance()->sendAvatarFile(friendId, avatarData);
|
||||||
|
friendsSentTo[friendId] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarBroadcaster::enableAutoBroadcast(bool state)
|
||||||
|
{
|
||||||
|
QObject::disconnect(autoBroadcastConn);
|
||||||
|
if (state)
|
||||||
|
autoBroadcastConn = QObject::connect(Core::getInstance(), &Core::friendStatusChanged, autoBroadcast);
|
||||||
|
}
|
28
src/avatarbroadcaster.h
Normal file
28
src/avatarbroadcaster.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef AVATARBROADCASTER_H
|
||||||
|
#define AVATARBROADCASTER_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
/// Takes care of broadcasting avatar changes to our friends in a smart way
|
||||||
|
/// Cache a copy of our current avatar and friends who have received it
|
||||||
|
/// so we don't spam avatar transfers to a friend who already has it.
|
||||||
|
class AvatarBroadcaster
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
AvatarBroadcaster()=delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Set our current avatar
|
||||||
|
static void setAvatar(QByteArray data);
|
||||||
|
/// Send our current avatar to this friend, if not already sent
|
||||||
|
static void sendAvatarTo(uint32_t friendId);
|
||||||
|
/// If true, we automatically broadcast our avatar to friends when they come online
|
||||||
|
static void enableAutoBroadcast(bool state = true);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QByteArray avatarData;
|
||||||
|
static QMap<uint32_t, bool> friendsSentTo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AVATARBROADCASTER_H
|
|
@ -23,6 +23,7 @@
|
||||||
#include "src/historykeeper.h"
|
#include "src/historykeeper.h"
|
||||||
#include "src/audio.h"
|
#include "src/audio.h"
|
||||||
#include "src/profilelocker.h"
|
#include "src/profilelocker.h"
|
||||||
|
#include "src/avatarbroadcaster.h"
|
||||||
#include "corefile.h"
|
#include "corefile.h"
|
||||||
|
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
@ -479,22 +480,10 @@ void Core::onUserStatusChanged(Tox*/* tox*/, uint32_t friendId, TOX_USER_STATUS
|
||||||
|
|
||||||
void Core::onConnectionStatusChanged(Tox*/* tox*/, uint32_t friendId, TOX_CONNECTION status, void* core)
|
void Core::onConnectionStatusChanged(Tox*/* tox*/, uint32_t friendId, TOX_CONNECTION status, void* core)
|
||||||
{
|
{
|
||||||
Status friendStatus = status ? Status::Online : Status::Offline;
|
Status friendStatus = status != TOX_CONNECTION_NONE ? Status::Online : Status::Offline;
|
||||||
emit static_cast<Core*>(core)->friendStatusChanged(friendId, friendStatus);
|
emit static_cast<Core*>(core)->friendStatusChanged(friendId, friendStatus);
|
||||||
if (friendStatus == Status::Offline)
|
if (friendStatus == Status::Offline)
|
||||||
{
|
|
||||||
static_cast<Core*>(core)->checkLastOnline(friendId);
|
static_cast<Core*>(core)->checkLastOnline(friendId);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QPixmap pic = Settings::getInstance().getSavedAvatar(static_cast<Core*>(core)->getSelfId().toString());
|
|
||||||
QByteArray bytes;
|
|
||||||
QBuffer buffer(&bytes);
|
|
||||||
buffer.open(QIODevice::WriteOnly);
|
|
||||||
pic.save(&buffer, "PNG");
|
|
||||||
buffer.close();
|
|
||||||
CoreFile::sendAvatarFile(static_cast<Core*>(core), friendId, bytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::onGroupAction(Tox*, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void* _core)
|
void Core::onGroupAction(Tox*, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void* _core)
|
||||||
|
@ -664,6 +653,11 @@ void Core::sendFile(uint32_t friendId, QString Filename, QString FilePath, long
|
||||||
CoreFile::sendFile(this, friendId, Filename, FilePath, filesize);
|
CoreFile::sendFile(this, friendId, Filename, FilePath, filesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::sendAvatarFile(uint32_t friendId, const QByteArray& data)
|
||||||
|
{
|
||||||
|
CoreFile::sendAvatarFile(this, friendId, data);
|
||||||
|
}
|
||||||
|
|
||||||
void Core::pauseResumeFileSend(uint32_t friendId, uint32_t fileNum)
|
void Core::pauseResumeFileSend(uint32_t friendId, uint32_t fileNum)
|
||||||
{
|
{
|
||||||
CoreFile::pauseResumeFileSend(this, friendId, fileNum);
|
CoreFile::pauseResumeFileSend(this, friendId, fileNum);
|
||||||
|
@ -754,11 +748,8 @@ void Core::setAvatar(const QByteArray& data)
|
||||||
Settings::getInstance().saveAvatar(pic, getSelfId().toString());
|
Settings::getInstance().saveAvatar(pic, getSelfId().toString());
|
||||||
emit selfAvatarChanged(pic);
|
emit selfAvatarChanged(pic);
|
||||||
|
|
||||||
// Broadcast our new avatar!
|
AvatarBroadcaster::setAvatar(data);
|
||||||
// according to tox.h, we need not broadcast this ourselves, but initial testing indicated elsewise
|
AvatarBroadcaster::enableAutoBroadcast();
|
||||||
const uint32_t friendCount = tox_self_get_friend_list_size(tox);
|
|
||||||
for (unsigned i=0; i<friendCount; i++)
|
|
||||||
CoreFile::sendAvatarFile(this, i, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ToxID Core::getSelfId() const
|
ToxID Core::getSelfId() const
|
||||||
|
@ -1044,6 +1035,14 @@ void Core::checkLastOnline(uint32_t friendId) {
|
||||||
emit friendLastSeenChanged(friendId, QDateTime::fromTime_t(lastOnline));
|
emit friendLastSeenChanged(friendId, QDateTime::fromTime_t(lastOnline));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<uint32_t> Core::getFriendList() const
|
||||||
|
{
|
||||||
|
QVector<uint32_t> friends;
|
||||||
|
friends.resize(tox_self_get_friend_list_size(tox));
|
||||||
|
tox_self_get_friend_list(tox, friends.data());
|
||||||
|
return friends;
|
||||||
|
}
|
||||||
|
|
||||||
int Core::getGroupNumberPeers(int groupId) const
|
int Core::getGroupNumberPeers(int groupId) const
|
||||||
{
|
{
|
||||||
return tox_group_number_peers(tox, groupId);
|
return tox_group_number_peers(tox, groupId);
|
||||||
|
@ -1153,6 +1152,11 @@ bool Core::isGroupAvEnabled(int groupId)
|
||||||
return tox_group_get_type(tox, groupId) == TOX_GROUPCHAT_TYPE_AV;
|
return tox_group_get_type(tox, groupId) == TOX_GROUPCHAT_TYPE_AV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Core::isFriendOnline(uint32_t friendId) const
|
||||||
|
{
|
||||||
|
return tox_friend_get_connection_status(tox, friendId, nullptr) != TOX_CONNECTION_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
bool Core::hasFriendWithAddress(const QString &addr) const
|
bool Core::hasFriendWithAddress(const QString &addr) const
|
||||||
{
|
{
|
||||||
// Valid length check
|
// Valid length check
|
||||||
|
|
|
@ -57,15 +57,17 @@ public:
|
||||||
|
|
||||||
QString getPeerName(const ToxID& id) const;
|
QString getPeerName(const ToxID& id) const;
|
||||||
|
|
||||||
|
QVector<uint32_t> getFriendList() const; ///< Returns the list of friendIds in our friendlist, an empty list on error
|
||||||
int getGroupNumberPeers(int groupId) const; ///< Return the number of peers in the group chat on success, or -1 on failure
|
int getGroupNumberPeers(int groupId) const; ///< Return the number of peers in the group chat on success, or -1 on failure
|
||||||
QString getGroupPeerName(int groupId, int peerId) const; ///< Get the name of a peer of a group
|
QString getGroupPeerName(int groupId, int peerId) const; ///< Get the name of a peer of a group
|
||||||
ToxID getGroupPeerToxID(int groupId, int peerId) const; ///< Get the ToxID of a peer of a group
|
ToxID getGroupPeerToxID(int groupId, int peerId) const; ///< Get the ToxID of a peer of a group
|
||||||
QList<QString> getGroupPeerNames(int groupId) const; ///< Get the names of the peers of a group
|
QList<QString> getGroupPeerNames(int groupId) const; ///< Get the names of the peers of a group
|
||||||
QString getFriendAddress(uint32_t friendNumber) const; ///< Get the full address if known, or Tox ID of a friend
|
QString getFriendAddress(uint32_t friendId) const; ///< Get the full address if known, or Tox ID of a friend
|
||||||
QString getFriendUsername(uint32_t friendNumber) const; ///< Get the username of a friend
|
QString getFriendUsername(uint32_t friendId) const; ///< Get the username of a friend
|
||||||
|
bool isFriendOnline(uint32_t friendId) const; ///< Check if a friend is online. Unknown friends are considered offline.
|
||||||
bool hasFriendWithAddress(const QString &addr) const; ///< Check if we have a friend by address
|
bool hasFriendWithAddress(const QString &addr) const; ///< Check if we have a friend by address
|
||||||
bool hasFriendWithPublicKey(const QString &pubkey) const; ///< Check if we have a friend by public key
|
bool hasFriendWithPublicKey(const QString &pubkey) const; ///< Check if we have a friend by public key
|
||||||
int joinGroupchat(int32_t friendNumber, uint8_t type, const uint8_t* pubkey,uint16_t length) const; ///< Accept a groupchat invite
|
int joinGroupchat(int32_t friendId, uint8_t type, const uint8_t* pubkey,uint16_t length) const; ///< Accept a groupchat invite
|
||||||
void quitGroupChat(int groupId) const; ///< Quit a groupchat
|
void quitGroupChat(int groupId) const; ///< Quit a groupchat
|
||||||
|
|
||||||
QString getIDString() const; ///< Get the 12 first characters of our Tox ID
|
QString getIDString() const; ///< Get the 12 first characters of our Tox ID
|
||||||
|
@ -113,6 +115,7 @@ public slots:
|
||||||
void sendTyping(uint32_t friendId, bool typing);
|
void sendTyping(uint32_t friendId, bool typing);
|
||||||
|
|
||||||
void sendFile(uint32_t friendId, QString Filename, QString FilePath, long long filesize);
|
void sendFile(uint32_t friendId, QString Filename, QString FilePath, long long filesize);
|
||||||
|
void sendAvatarFile(uint32_t friendId, const QByteArray& data);
|
||||||
void cancelFileSend(uint32_t friendId, uint32_t fileNum);
|
void cancelFileSend(uint32_t friendId, uint32_t fileNum);
|
||||||
void cancelFileRecv(uint32_t friendId, uint32_t fileNum);
|
void cancelFileRecv(uint32_t friendId, uint32_t fileNum);
|
||||||
void rejectFileRecvRequest(uint32_t friendId, uint32_t fileNum);
|
void rejectFileRecvRequest(uint32_t friendId, uint32_t fileNum);
|
||||||
|
@ -170,7 +173,7 @@ signals:
|
||||||
void friendLastSeenChanged(uint32_t friendId, const QDateTime& dateTime);
|
void friendLastSeenChanged(uint32_t friendId, const QDateTime& dateTime);
|
||||||
|
|
||||||
void emptyGroupCreated(int groupnumber);
|
void emptyGroupCreated(int groupnumber);
|
||||||
void groupInviteReceived(uint32_t friendNumber, uint8_t type, QByteArray publicKey);
|
void groupInviteReceived(uint32_t friendId, uint8_t type, QByteArray publicKey);
|
||||||
void groupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction);
|
void groupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction);
|
||||||
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
|
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
|
||||||
void groupTitleChanged(int groupnumber, const QString& author, const QString& title);
|
void groupTitleChanged(int groupnumber, const QString& author, const QString& title);
|
||||||
|
@ -241,14 +244,14 @@ private:
|
||||||
static void onConnectionStatusChanged(Tox* tox, uint32_t friendId, TOX_CONNECTION status, void* core);
|
static void onConnectionStatusChanged(Tox* tox, uint32_t friendId, TOX_CONNECTION status, void* core);
|
||||||
static void onGroupAction(Tox* tox, int groupnumber, int peernumber, const uint8_t * action,
|
static void onGroupAction(Tox* tox, int groupnumber, int peernumber, const uint8_t * action,
|
||||||
uint16_t length, void* core);
|
uint16_t length, void* core);
|
||||||
static void onGroupInvite(Tox *tox, int32_t friendNumber, uint8_t type, const uint8_t *data,
|
static void onGroupInvite(Tox *tox, int32_t friendId, uint8_t type, const uint8_t *data,
|
||||||
uint16_t length, void *userdata);
|
uint16_t length, void *userdata);
|
||||||
static void onGroupMessage(Tox *tox, int groupnumber, int friendgroupnumber,
|
static void onGroupMessage(Tox *tox, int groupnumber, int friendgroupnumber,
|
||||||
const uint8_t * message, uint16_t length, void *userdata);
|
const uint8_t * message, uint16_t length, void *userdata);
|
||||||
static void onGroupNamelistChange(Tox *tox, int groupId, int peerId, uint8_t change, void *core);
|
static void onGroupNamelistChange(Tox *tox, int groupId, int peerId, uint8_t change, void *core);
|
||||||
static void onGroupTitleChange(Tox*, int groupnumber, int peernumber,
|
static void onGroupTitleChange(Tox*, int groupnumber, int peernumber,
|
||||||
const uint8_t* title, uint8_t len, void* _core);
|
const uint8_t* title, uint8_t len, void* _core);
|
||||||
static void onReadReceiptCallback(Tox *tox, uint32_t friendnumber, uint32_t receipt, void *core);
|
static void onReadReceiptCallback(Tox *tox, uint32_t friendId, uint32_t receipt, void *core);
|
||||||
|
|
||||||
static void onAvInvite(void* toxav, int32_t call_index, void* core);
|
static void onAvInvite(void* toxav, int32_t call_index, void* core);
|
||||||
static void onAvStart(void* toxav, int32_t call_index, void* core);
|
static void onAvStart(void* toxav, int32_t call_index, void* core);
|
||||||
|
|
|
@ -178,7 +178,7 @@ ToxFile* CoreFile::findFile(uint32_t friendId, uint32_t fileId)
|
||||||
uint64_t key = ((uint64_t)friendId<<32) + (uint64_t)fileId;
|
uint64_t key = ((uint64_t)friendId<<32) + (uint64_t)fileId;
|
||||||
if (!fileMap.contains(key))
|
if (!fileMap.contains(key))
|
||||||
{
|
{
|
||||||
qWarning() << "CoreFile::addFile: File transfer with ID "<<friendId<<':'<<fileId<<" doesn't exist";
|
qWarning() << "CoreFile::findFile: File transfer with ID "<<friendId<<':'<<fileId<<" doesn't exist";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -196,8 +196,13 @@ void CoreFile::addFile(uint32_t friendId, uint32_t fileId, const ToxFile& file)
|
||||||
void CoreFile::removeFile(uint32_t friendId, uint32_t fileId)
|
void CoreFile::removeFile(uint32_t friendId, uint32_t fileId)
|
||||||
{
|
{
|
||||||
uint64_t key = ((uint64_t)friendId<<32) + (uint64_t)fileId;
|
uint64_t key = ((uint64_t)friendId<<32) + (uint64_t)fileId;
|
||||||
if (!fileMap.remove(key))
|
if (!fileMap.contains(key))
|
||||||
|
{
|
||||||
qWarning() << "CoreFile::removeFile: No such file in queue";
|
qWarning() << "CoreFile::removeFile: No such file in queue";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fileMap[key].file->close();
|
||||||
|
fileMap.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, uint32_t kind,
|
void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, uint32_t kind,
|
||||||
|
@ -331,7 +336,8 @@ void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
|
||||||
void CoreFile::onFileRecvChunkCallback(Tox *tox, uint32_t friendId, uint32_t fileId, uint64_t position,
|
void CoreFile::onFileRecvChunkCallback(Tox *tox, uint32_t friendId, uint32_t fileId, uint64_t position,
|
||||||
const uint8_t *data, size_t length, void *core)
|
const uint8_t *data, size_t length, void *core)
|
||||||
{
|
{
|
||||||
//qDebug() << QString("CoreFile: Received file chunk for request %1:%2").arg(friendId).arg(fileId);
|
qDebug() << QString("CoreFile: Received chunk for %1:%2 pos %3 size %4")
|
||||||
|
.arg(friendId).arg(fileId).arg(position).arg(length);
|
||||||
|
|
||||||
ToxFile* file = findFile(friendId, fileId);
|
ToxFile* file = findFile(friendId, fileId);
|
||||||
if (!file)
|
if (!file)
|
||||||
|
@ -352,13 +358,7 @@ void CoreFile::onFileRecvChunkCallback(Tox *tox, uint32_t friendId, uint32_t fil
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file->fileKind == TOX_FILE_KIND_AVATAR)
|
if (!length)
|
||||||
file->avatarData.append((char*)data, length);
|
|
||||||
else
|
|
||||||
file->file->write((char*)data,length);
|
|
||||||
file->bytesSent += length;
|
|
||||||
|
|
||||||
if (file->bytesSent == file->filesize)
|
|
||||||
{
|
{
|
||||||
if (file->fileKind == TOX_FILE_KIND_AVATAR)
|
if (file->fileKind == TOX_FILE_KIND_AVATAR)
|
||||||
{
|
{
|
||||||
|
@ -376,9 +376,16 @@ void CoreFile::onFileRecvChunkCallback(Tox *tox, uint32_t friendId, uint32_t fil
|
||||||
{
|
{
|
||||||
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
||||||
}
|
}
|
||||||
|
removeFile(friendId, fileId);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (file->fileKind != TOX_FILE_KIND_AVATAR)
|
|
||||||
{
|
if (file->fileKind == TOX_FILE_KIND_AVATAR)
|
||||||
|
file->avatarData.append((char*)data, length);
|
||||||
|
else
|
||||||
|
file->file->write((char*)data,length);
|
||||||
|
file->bytesSent += length;
|
||||||
|
|
||||||
|
if (file->fileKind != TOX_FILE_KIND_AVATAR)
|
||||||
emit static_cast<Core*>(core)->fileTransferInfo(*file);
|
emit static_cast<Core*>(core)->fileTransferInfo(*file);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
// They should include this file directly instead to reduce compilation times
|
// They should include this file directly instead to reduce compilation times
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <memory>
|
||||||
class QFile;
|
class QFile;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ struct ToxFile
|
||||||
uint32_t friendId;
|
uint32_t friendId;
|
||||||
QByteArray fileName;
|
QByteArray fileName;
|
||||||
QString filePath;
|
QString filePath;
|
||||||
QFile* file;
|
std::shared_ptr<QFile> file;
|
||||||
quint64 bytesSent;
|
quint64 bytesSent;
|
||||||
quint64 filesize;
|
quint64 filesize;
|
||||||
FileStatus status;
|
FileStatus status;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user