mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
refactor(files): Refactor FileTransferWidget
Rational here is that the current FileTransferWidget is quite entangled with core logic. If we are going to instantiate the FileTransferWidget without an active file transfer the widget needs to behave sanely without getting messages from toxcore. This changeset is an attempt to allow us to move from any FileTransferWidget state to any other state without having to go through the appropriate state transitions.
This commit is contained in:
parent
f188409b8c
commit
157be30b11
|
@ -249,6 +249,8 @@ set(${PROJECT_NAME}_SOURCES
|
|||
src/chatlog/documentcache.h
|
||||
src/chatlog/pixmapcache.cpp
|
||||
src/chatlog/pixmapcache.h
|
||||
src/chatlog/toxfileprogress.cpp
|
||||
src/chatlog/toxfileprogress.h
|
||||
src/chatlog/textformatter.cpp
|
||||
src/chatlog/textformatter.h
|
||||
src/core/coreav.cpp
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
// The leftButton is used to accept, pause, or resume a file transfer, as well as to open a
|
||||
// received file.
|
||||
// The rightButton is used to cancel a file transfer, or to open the directory a file was
|
||||
|
@ -50,7 +51,6 @@ FileTransferWidget::FileTransferWidget(QWidget* parent, ToxFile file)
|
|||
: QWidget(parent)
|
||||
, ui(new Ui::FileTransferWidget)
|
||||
, fileInfo(file)
|
||||
, lastTick(QTime::currentTime())
|
||||
, backgroundColor(Style::getColor(Style::LightGrey))
|
||||
, buttonColor(Style::getColor(Style::Yellow))
|
||||
, buttonBackgroundColor(Style::getColor(Style::White))
|
||||
|
@ -84,8 +84,6 @@ FileTransferWidget::FileTransferWidget(QWidget* parent, ToxFile file)
|
|||
update();
|
||||
});
|
||||
|
||||
setBackgroundColor(Style::getColor(Style::LightGrey), false);
|
||||
|
||||
connect(Core::getInstance(), &Core::fileTransferInfo, this,
|
||||
&FileTransferWidget::onFileTransferInfo);
|
||||
connect(Core::getInstance(), &Core::fileTransferAccepted, this,
|
||||
|
@ -105,16 +103,11 @@ FileTransferWidget::FileTransferWidget(QWidget* parent, ToxFile file)
|
|||
connect(ui->previewButton, &QPushButton::clicked, this,
|
||||
&FileTransferWidget::onPreviewButtonClicked);
|
||||
|
||||
setupButtons();
|
||||
// Set lastStatus to anything but the file's current value, this forces an update
|
||||
lastStatus = file.status == ToxFile::FINISHED ? ToxFile::INITIALIZING : ToxFile::FINISHED;
|
||||
updateWidget(file);
|
||||
|
||||
// preview
|
||||
if (fileInfo.direction == ToxFile::SENDING) {
|
||||
showPreview(fileInfo.filePath);
|
||||
ui->progressLabel->setText(tr("Waiting to send...", "file transfer widget"));
|
||||
} else {
|
||||
ui->progressLabel->setText(tr("Accept to receive this file", "file transfer widget"));
|
||||
}
|
||||
|
||||
setFixedHeight(64);
|
||||
}
|
||||
|
||||
|
@ -267,154 +260,32 @@ void FileTransferWidget::paintEvent(QPaintEvent*)
|
|||
|
||||
void FileTransferWidget::onFileTransferInfo(ToxFile file)
|
||||
{
|
||||
QTime now = QTime::currentTime();
|
||||
qint64 dt = lastTick.msecsTo(now); // ms
|
||||
|
||||
if (fileInfo != file || dt < 1000)
|
||||
return;
|
||||
|
||||
fileInfo = file;
|
||||
|
||||
if (fileInfo.status == ToxFile::TRANSMITTING) {
|
||||
// update progress
|
||||
qreal progress = static_cast<qreal>(file.bytesSent) / static_cast<qreal>(file.filesize);
|
||||
ui->progressBar->setValue(static_cast<int>(progress * 100.0));
|
||||
|
||||
// ETA, speed
|
||||
qreal deltaSecs = dt / 1000.0;
|
||||
|
||||
// (can't use ::abs or ::max on unsigned types substraction, they'd just overflow)
|
||||
quint64 deltaBytes = file.bytesSent > lastBytesSent ? file.bytesSent - lastBytesSent
|
||||
: lastBytesSent - file.bytesSent;
|
||||
qreal bytesPerSec = static_cast<int>(static_cast<qreal>(deltaBytes) / deltaSecs);
|
||||
|
||||
// calculate mean
|
||||
meanIndex = meanIndex % TRANSFER_ROLLING_AVG_COUNT;
|
||||
meanData[meanIndex++] = bytesPerSec;
|
||||
|
||||
qreal meanBytesPerSec = 0.0;
|
||||
for (size_t i = 0; i < TRANSFER_ROLLING_AVG_COUNT; ++i)
|
||||
meanBytesPerSec += meanData[i];
|
||||
|
||||
meanBytesPerSec /= static_cast<qreal>(TRANSFER_ROLLING_AVG_COUNT);
|
||||
|
||||
// update UI
|
||||
if (meanBytesPerSec > 0) {
|
||||
// ETA
|
||||
QTime toGo = QTime(0, 0).addSecs((file.filesize - file.bytesSent) / meanBytesPerSec);
|
||||
QString format = toGo.hour() > 0 ? "hh:mm:ss" : "mm:ss";
|
||||
ui->etaLabel->setText(toGo.toString(format));
|
||||
} else {
|
||||
ui->etaLabel->setText("");
|
||||
}
|
||||
|
||||
ui->progressLabel->setText(getHumanReadableSize(meanBytesPerSec) + "/s");
|
||||
|
||||
lastBytesSent = file.bytesSent;
|
||||
}
|
||||
|
||||
lastTick = now;
|
||||
|
||||
// trigger repaint
|
||||
update();
|
||||
updateWidget(file);
|
||||
}
|
||||
|
||||
void FileTransferWidget::onFileTransferAccepted(ToxFile file)
|
||||
{
|
||||
if (fileInfo != file)
|
||||
return;
|
||||
|
||||
fileInfo = file;
|
||||
|
||||
setBackgroundColor(Style::getColor(Style::LightGrey), false);
|
||||
|
||||
setupButtons();
|
||||
updateWidget(file);
|
||||
}
|
||||
|
||||
void FileTransferWidget::onFileTransferCancelled(ToxFile file)
|
||||
{
|
||||
if (fileInfo != file)
|
||||
return;
|
||||
|
||||
fileInfo = file;
|
||||
active = false;
|
||||
|
||||
setBackgroundColor(Style::getColor(Style::Red), true);
|
||||
|
||||
setupButtons();
|
||||
hideWidgets();
|
||||
|
||||
disconnect(Core::getInstance(), nullptr, this, nullptr);
|
||||
updateWidget(file);
|
||||
}
|
||||
|
||||
void FileTransferWidget::onFileTransferPaused(ToxFile file)
|
||||
{
|
||||
if (fileInfo != file)
|
||||
return;
|
||||
|
||||
fileInfo = file;
|
||||
|
||||
ui->etaLabel->setText("");
|
||||
ui->progressLabel->setText(tr("Paused", "file transfer widget"));
|
||||
|
||||
// reset mean
|
||||
meanIndex = 0;
|
||||
for (size_t i = 0; i < TRANSFER_ROLLING_AVG_COUNT; ++i)
|
||||
meanData[i] = 0.0;
|
||||
|
||||
setBackgroundColor(Style::getColor(Style::LightGrey), false);
|
||||
|
||||
setupButtons();
|
||||
updateWidget(file);
|
||||
}
|
||||
|
||||
void FileTransferWidget::onFileTransferResumed(ToxFile file)
|
||||
{
|
||||
if (fileInfo != file)
|
||||
return;
|
||||
|
||||
fileInfo = file;
|
||||
|
||||
ui->etaLabel->setText("");
|
||||
ui->progressLabel->setText(tr("Resuming...", "file transfer widget"));
|
||||
|
||||
// reset mean
|
||||
meanIndex = 0;
|
||||
for (size_t i = 0; i < TRANSFER_ROLLING_AVG_COUNT; ++i)
|
||||
meanData[i] = 0.0;
|
||||
|
||||
setBackgroundColor(Style::getColor(Style::LightGrey), false);
|
||||
|
||||
setupButtons();
|
||||
updateWidget(file);
|
||||
}
|
||||
|
||||
void FileTransferWidget::onFileTransferFinished(ToxFile file)
|
||||
{
|
||||
if (fileInfo != file)
|
||||
return;
|
||||
|
||||
fileInfo = file;
|
||||
active = false;
|
||||
|
||||
setBackgroundColor(Style::getColor(Style::Green), true);
|
||||
|
||||
setupButtons();
|
||||
hideWidgets();
|
||||
|
||||
ui->leftButton->setIcon(QIcon(Style::getImagePath("fileTransferInstance/yes.svg")));
|
||||
ui->leftButton->setObjectName("ok");
|
||||
ui->leftButton->setToolTip(tr("Open file"));
|
||||
ui->leftButton->show();
|
||||
|
||||
ui->rightButton->setIcon(QIcon(Style::getImagePath("fileTransferInstance/dir.svg")));
|
||||
ui->rightButton->setObjectName("dir");
|
||||
ui->rightButton->setToolTip(tr("Open file directory"));
|
||||
ui->rightButton->show();
|
||||
|
||||
// preview
|
||||
if (fileInfo.direction == ToxFile::RECEIVING)
|
||||
showPreview(fileInfo.filePath);
|
||||
|
||||
disconnect(Core::getInstance(), nullptr, this, nullptr);
|
||||
updateWidget(file);
|
||||
}
|
||||
|
||||
void FileTransferWidget::fileTransferRemotePausedUnpaused(ToxFile file, bool paused)
|
||||
|
@ -443,18 +314,146 @@ QString FileTransferWidget::getHumanReadableSize(qint64 size)
|
|||
return QString().setNum(size / pow(1024, exp), 'f', exp > 1 ? 2 : 0).append(suffix[exp]);
|
||||
}
|
||||
|
||||
void FileTransferWidget::hideWidgets()
|
||||
void FileTransferWidget::updateWidgetColor(ToxFile const& file)
|
||||
{
|
||||
ui->leftButton->hide();
|
||||
ui->rightButton->hide();
|
||||
if (lastStatus == file.status)
|
||||
return;
|
||||
|
||||
switch (file.status) {
|
||||
case ToxFile::INITIALIZING:
|
||||
case ToxFile::PAUSED:
|
||||
case ToxFile::TRANSMITTING:
|
||||
setBackgroundColor(Style::getColor(Style::LightGrey), false);
|
||||
break;
|
||||
case ToxFile::BROKEN:
|
||||
case ToxFile::CANCELED:
|
||||
setBackgroundColor(Style::getColor(Style::Red), true);
|
||||
break;
|
||||
case ToxFile::FINISHED:
|
||||
setBackgroundColor(Style::getColor(Style::Green), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FileTransferWidget::updateWidgetText(ToxFile const& file)
|
||||
{
|
||||
if (lastStatus == file.status)
|
||||
return;
|
||||
|
||||
switch (file.status) {
|
||||
case ToxFile::INITIALIZING:
|
||||
if (file.direction == ToxFile::SENDING) {
|
||||
ui->progressLabel->setText(tr("Waiting to send...", "file transfer widget"));
|
||||
} else {
|
||||
ui->progressLabel->setText(tr("Accept to receive this file", "file transfer widget"));
|
||||
}
|
||||
break;
|
||||
case ToxFile::PAUSED:
|
||||
ui->etaLabel->setText("");
|
||||
ui->progressLabel->setText(tr("Paused", "file transfer widget"));
|
||||
break;
|
||||
case ToxFile::TRANSMITTING:
|
||||
ui->etaLabel->setText("");
|
||||
ui->progressLabel->setText(tr("Resuming...", "file transfer widget"));
|
||||
break;
|
||||
case ToxFile::BROKEN:
|
||||
case ToxFile::CANCELED:
|
||||
break;
|
||||
case ToxFile::FINISHED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FileTransferWidget::updatePreview(ToxFile const& file)
|
||||
{
|
||||
if (lastStatus == file.status)
|
||||
return;
|
||||
|
||||
switch (file.status) {
|
||||
case ToxFile::INITIALIZING:
|
||||
case ToxFile::PAUSED:
|
||||
case ToxFile::TRANSMITTING:
|
||||
case ToxFile::BROKEN:
|
||||
case ToxFile::CANCELED:
|
||||
if (file.direction == ToxFile::SENDING) {
|
||||
showPreview(file.filePath);
|
||||
}
|
||||
break;
|
||||
case ToxFile::FINISHED:
|
||||
showPreview(file.filePath);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FileTransferWidget::updateFileProgress(ToxFile const& file)
|
||||
{
|
||||
switch (file.status) {
|
||||
case ToxFile::INITIALIZING:
|
||||
break;
|
||||
case ToxFile::PAUSED:
|
||||
fileProgress.resetSpeed();
|
||||
break;
|
||||
case ToxFile::TRANSMITTING: {
|
||||
if (!fileProgress.needsUpdate())
|
||||
break;
|
||||
|
||||
fileProgress.addSample(file);
|
||||
auto speed = fileProgress.getSpeed();
|
||||
auto progress = fileProgress.getProgress();
|
||||
auto remainingTime = fileProgress.getTimeLeftSeconds();
|
||||
|
||||
ui->progressBar->setValue(static_cast<int>(progress * 100.0));
|
||||
|
||||
// update UI
|
||||
if (speed > 0) {
|
||||
// ETA
|
||||
QTime toGo = QTime(0, 0).addSecs(remainingTime);
|
||||
QString format = toGo.hour() > 0 ? "hh:mm:ss" : "mm:ss";
|
||||
ui->etaLabel->setText(toGo.toString(format));
|
||||
} else {
|
||||
ui->etaLabel->setText("");
|
||||
}
|
||||
|
||||
ui->progressLabel->setText(getHumanReadableSize(speed) + "/s");
|
||||
break;
|
||||
}
|
||||
case ToxFile::BROKEN:
|
||||
case ToxFile::CANCELED:
|
||||
case ToxFile::FINISHED: {
|
||||
ui->progressBar->hide();
|
||||
ui->progressLabel->hide();
|
||||
ui->etaLabel->hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileTransferWidget::setupButtons()
|
||||
void FileTransferWidget::updateSignals(ToxFile const& file)
|
||||
{
|
||||
switch (fileInfo.status) {
|
||||
if (lastStatus == file.status)
|
||||
return;
|
||||
|
||||
switch (file.status) {
|
||||
case ToxFile::CANCELED:
|
||||
case ToxFile::BROKEN:
|
||||
case ToxFile::FINISHED:
|
||||
active = false;
|
||||
disconnect(Core::getInstance(), nullptr, this, nullptr);
|
||||
break;
|
||||
case ToxFile::INITIALIZING:
|
||||
case ToxFile::PAUSED:
|
||||
case ToxFile::TRANSMITTING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FileTransferWidget::setupButtons(ToxFile const& file)
|
||||
{
|
||||
if (lastStatus == file.status)
|
||||
return;
|
||||
|
||||
switch (file.status) {
|
||||
case ToxFile::TRANSMITTING:
|
||||
ui->leftButton->setIcon(QIcon(Style::getImagePath("fileTransferInstance/pause.svg")));
|
||||
ui->leftButton->setObjectName("pause");
|
||||
|
@ -479,13 +478,12 @@ void FileTransferWidget::setupButtons()
|
|||
setButtonColor(Style::getColor(Style::LightGrey));
|
||||
break;
|
||||
|
||||
case ToxFile::STOPPED:
|
||||
case ToxFile::BROKEN:
|
||||
case ToxFile::INITIALIZING:
|
||||
ui->rightButton->setIcon(QIcon(Style::getImagePath("fileTransferInstance/no.svg")));
|
||||
ui->rightButton->setObjectName("cancel");
|
||||
ui->rightButton->setToolTip(tr("Cancel transfer"));
|
||||
|
||||
if (fileInfo.direction == ToxFile::SENDING) {
|
||||
if (file.direction == ToxFile::SENDING) {
|
||||
ui->leftButton->setIcon(QIcon(Style::getImagePath("fileTransferInstance/pause.svg")));
|
||||
ui->leftButton->setObjectName("pause");
|
||||
ui->leftButton->setToolTip(tr("Pause transfer"));
|
||||
|
@ -494,6 +492,23 @@ void FileTransferWidget::setupButtons()
|
|||
ui->leftButton->setObjectName("accept");
|
||||
ui->leftButton->setToolTip(tr("Accept transfer"));
|
||||
}
|
||||
break;
|
||||
case ToxFile::CANCELED:
|
||||
case ToxFile::BROKEN:
|
||||
ui->leftButton->hide();
|
||||
ui->rightButton->hide();
|
||||
break;
|
||||
case ToxFile::FINISHED:
|
||||
ui->leftButton->setIcon(QIcon(Style::getImagePath("fileTransferInstance/yes.svg")));
|
||||
ui->leftButton->setObjectName("ok");
|
||||
ui->leftButton->setToolTip(tr("Open file"));
|
||||
ui->leftButton->show();
|
||||
|
||||
ui->rightButton->setIcon(QIcon(Style::getImagePath("fileTransferInstance/dir.svg")));
|
||||
ui->rightButton->setObjectName("dir");
|
||||
ui->rightButton->setToolTip(tr("Open file directory"));
|
||||
ui->rightButton->show();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -549,7 +564,8 @@ void FileTransferWidget::showPreview(const QString& filename)
|
|||
}
|
||||
const QByteArray imageFileData = imageFile.readAll();
|
||||
QImage image = QImage::fromData(imageFileData);
|
||||
const int exifOrientation = getExifOrientation(imageFileData.constData(), imageFileData.size());
|
||||
const int exifOrientation =
|
||||
getExifOrientation(imageFileData.constData(), imageFileData.size());
|
||||
if (exifOrientation) {
|
||||
applyTransformation(exifOrientation, image);
|
||||
}
|
||||
|
@ -565,10 +581,9 @@ void FileTransferWidget::showPreview(const QString& filename)
|
|||
const int maxPreviewHeight{desktopSize.height() / 2};
|
||||
const QImage previewImage = [&image, maxPreviewWidth, maxPreviewHeight]() {
|
||||
if (image.width() > maxPreviewWidth || image.height() > maxPreviewHeight) {
|
||||
return image.scaled(maxPreviewWidth, maxPreviewHeight,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
else {
|
||||
return image.scaled(maxPreviewWidth, maxPreviewHeight, Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
} else {
|
||||
return image;
|
||||
}
|
||||
}();
|
||||
|
@ -578,8 +593,7 @@ void FileTransferWidget::showPreview(const QString& filename)
|
|||
buffer.open(QIODevice::WriteOnly);
|
||||
previewImage.save(&buffer, "PNG");
|
||||
buffer.close();
|
||||
ui->previewButton->setToolTip("<img src=data:image/png;base64," + imageData.toBase64()
|
||||
+ "/>");
|
||||
ui->previewButton->setToolTip("<img src=data:image/png;base64," + imageData.toBase64() + "/>");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,8 +655,7 @@ int FileTransferWidget::getExifOrientation(const char* data, const int size)
|
|||
void FileTransferWidget::applyTransformation(const int orientation, QImage& image)
|
||||
{
|
||||
QTransform exifTransform;
|
||||
switch(static_cast<ExifOrientation>(orientation))
|
||||
{
|
||||
switch (static_cast<ExifOrientation>(orientation)) {
|
||||
case ExifOrientation::TopLeft:
|
||||
break;
|
||||
case ExifOrientation::TopRight:
|
||||
|
@ -673,3 +686,33 @@ void FileTransferWidget::applyTransformation(const int orientation, QImage& imag
|
|||
}
|
||||
image = image.transformed(exifTransform);
|
||||
}
|
||||
|
||||
void FileTransferWidget::updateWidget(ToxFile const& file)
|
||||
{
|
||||
if (fileInfo != file)
|
||||
return;
|
||||
|
||||
fileInfo = file;
|
||||
|
||||
// If we repainted on every packet our gui would be *very* slow
|
||||
bool bTransmitNeedsUpdate = fileProgress.needsUpdate();
|
||||
|
||||
updatePreview(file);
|
||||
updateFileProgress(file);
|
||||
updateWidgetText(file);
|
||||
updateWidgetColor(file);
|
||||
setupButtons(file);
|
||||
updateSignals(file);
|
||||
|
||||
lastStatus = file.status;
|
||||
|
||||
// trigger repaint
|
||||
switch (file.status) {
|
||||
case ToxFile::TRANSMITTING:
|
||||
if (!bTransmitNeedsUpdate)
|
||||
break;
|
||||
// fallthrough
|
||||
default:
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <QWidget>
|
||||
|
||||
#include "src/chatlog/chatlinecontent.h"
|
||||
#include "src/chatlog/toxfileprogress.h"
|
||||
#include "src/core/toxfile.h"
|
||||
|
||||
|
||||
|
@ -56,8 +57,12 @@ protected slots:
|
|||
|
||||
protected:
|
||||
QString getHumanReadableSize(qint64 size);
|
||||
void hideWidgets();
|
||||
void setupButtons();
|
||||
void updateWidgetColor(ToxFile const& file);
|
||||
void updateWidgetText(ToxFile const& file);
|
||||
void updateFileProgress(ToxFile const& file);
|
||||
void updateSignals(ToxFile const& file);
|
||||
void updatePreview(ToxFile const& file);
|
||||
void setupButtons(ToxFile const& file);
|
||||
void handleButton(QPushButton* btn);
|
||||
void showPreview(const QString& filename);
|
||||
void acceptTransfer(const QString& filepath);
|
||||
|
@ -79,28 +84,29 @@ private:
|
|||
static void applyTransformation(const int oritentation, QImage& image);
|
||||
static bool tryRemoveFile(const QString &filepath);
|
||||
|
||||
void updateWidget(ToxFile const& file);
|
||||
|
||||
private:
|
||||
Ui::FileTransferWidget* ui;
|
||||
ToxFileProgress fileProgress;
|
||||
ToxFile fileInfo;
|
||||
QTime lastTick;
|
||||
quint64 lastBytesSent = 0;
|
||||
QVariantAnimation* backgroundColorAnimation = nullptr;
|
||||
QVariantAnimation* buttonColorAnimation = nullptr;
|
||||
QColor backgroundColor;
|
||||
QColor buttonColor;
|
||||
QColor buttonBackgroundColor;
|
||||
|
||||
static const uint8_t TRANSFER_ROLLING_AVG_COUNT = 4;
|
||||
uint8_t meanIndex = 0;
|
||||
qreal meanData[TRANSFER_ROLLING_AVG_COUNT] = {0.0};
|
||||
|
||||
bool active;
|
||||
enum class ExifOrientation {
|
||||
ToxFile::FileStatus lastStatus = ToxFile::INITIALIZING;
|
||||
|
||||
enum class ExifOrientation
|
||||
{
|
||||
/* do not change values, this is exif spec
|
||||
*
|
||||
* name corresponds to where the 0 row and 0 column is in form row-column
|
||||
* i.e. entry 5 here means that the 0'th row corresponds to the left side of the scene and the 0'th column corresponds
|
||||
* to the top of the captured scene. This means that the image needs to be mirrored and rotated to be displayed.
|
||||
* i.e. entry 5 here means that the 0'th row corresponds to the left side of the scene and
|
||||
* the 0'th column corresponds to the top of the captured scene. This means that the image
|
||||
* needs to be mirrored and rotated to be displayed.
|
||||
*/
|
||||
TopLeft = 1,
|
||||
TopRight = 2,
|
||||
|
|
92
src/chatlog/toxfileprogress.cpp
Normal file
92
src/chatlog/toxfileprogress.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright © 2018 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
qTox is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "toxfileprogress.h"
|
||||
|
||||
#include "src/core/toxfile.h"
|
||||
|
||||
bool ToxFileProgress::needsUpdate() const
|
||||
{
|
||||
QTime now = QTime::currentTime();
|
||||
qint64 dt = lastTick.msecsTo(now); // ms
|
||||
|
||||
if (dt < 1000) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ToxFileProgress::addSample(ToxFile const& file)
|
||||
{
|
||||
QTime now = QTime::currentTime();
|
||||
qint64 dt = lastTick.msecsTo(now); // ms
|
||||
|
||||
if (dt < 1000) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ETA, speed
|
||||
qreal deltaSecs = dt / 1000.0;
|
||||
|
||||
// (can't use ::abs or ::max on unsigned types substraction, they'd just overflow)
|
||||
quint64 deltaBytes = file.bytesSent > lastBytesSent ? file.bytesSent - lastBytesSent
|
||||
: lastBytesSent - file.bytesSent;
|
||||
qreal bytesPerSec = static_cast<int>(static_cast<qreal>(deltaBytes) / deltaSecs);
|
||||
|
||||
// Update member variables
|
||||
meanIndex = meanIndex % TRANSFER_ROLLING_AVG_COUNT;
|
||||
meanData[meanIndex++] = bytesPerSec;
|
||||
|
||||
double meanBytesPerSec = 0.0;
|
||||
for (size_t i = 0; i < TRANSFER_ROLLING_AVG_COUNT; ++i)
|
||||
meanBytesPerSec += meanData[i];
|
||||
meanBytesPerSec /= static_cast<qreal>(TRANSFER_ROLLING_AVG_COUNT);
|
||||
|
||||
lastTick = now;
|
||||
|
||||
progress = static_cast<double>(file.bytesSent) / static_cast<double>(file.filesize);
|
||||
speedBytesPerSecond = meanBytesPerSec;
|
||||
timeLeftSeconds = (file.filesize - file.bytesSent) / getSpeed();
|
||||
|
||||
lastBytesSent = file.bytesSent;
|
||||
}
|
||||
|
||||
void ToxFileProgress::resetSpeed()
|
||||
{
|
||||
meanIndex = 0;
|
||||
for (auto& item : meanData) {
|
||||
item = 0;
|
||||
}
|
||||
}
|
||||
|
||||
double ToxFileProgress::getProgress() const
|
||||
{
|
||||
return progress;
|
||||
}
|
||||
|
||||
double ToxFileProgress::getSpeed() const
|
||||
{
|
||||
return speedBytesPerSecond;
|
||||
}
|
||||
|
||||
double ToxFileProgress::getTimeLeftSeconds() const
|
||||
{
|
||||
return timeLeftSeconds;
|
||||
}
|
53
src/chatlog/toxfileprogress.h
Normal file
53
src/chatlog/toxfileprogress.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright © 2018 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
qTox is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TOXFILEPROGRESS_H
|
||||
#define TOXFILEPROGRESS_H
|
||||
|
||||
#include <QTime>
|
||||
|
||||
struct ToxFile;
|
||||
|
||||
class ToxFileProgress
|
||||
{
|
||||
public:
|
||||
bool needsUpdate() const;
|
||||
void addSample(ToxFile const& file);
|
||||
void resetSpeed();
|
||||
|
||||
double getProgress() const;
|
||||
double getSpeed() const;
|
||||
double getTimeLeftSeconds() const;
|
||||
|
||||
private:
|
||||
uint64_t lastBytesSent = 0;
|
||||
|
||||
static const uint8_t TRANSFER_ROLLING_AVG_COUNT = 4;
|
||||
uint8_t meanIndex = 0;
|
||||
double meanData[TRANSFER_ROLLING_AVG_COUNT] = {0.0};
|
||||
|
||||
QTime lastTick = QTime::currentTime();
|
||||
|
||||
double speedBytesPerSecond;
|
||||
double timeLeftSeconds;
|
||||
double progress;
|
||||
};
|
||||
|
||||
|
||||
#endif // TOXFILEPROGRESS_H
|
|
@ -199,7 +199,7 @@ void CoreFile::cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId)
|
|||
return;
|
||||
}
|
||||
|
||||
file->status = ToxFile::STOPPED;
|
||||
file->status = ToxFile::CANCELED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
|
@ -212,7 +212,7 @@ void CoreFile::cancelFileRecv(Core* core, uint32_t friendId, uint32_t fileId)
|
|||
qWarning("cancelFileRecv: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
file->status = ToxFile::CANCELED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
|
@ -225,7 +225,7 @@ void CoreFile::rejectFileRecvRequest(Core* core, uint32_t friendId, uint32_t fil
|
|||
qWarning("rejectFileRecvRequest: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
file->status = ToxFile::CANCELED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
|
@ -379,6 +379,7 @@ void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId,
|
|||
if (control == TOX_FILE_CONTROL_CANCEL) {
|
||||
if (file->fileKind != TOX_FILE_KIND_AVATAR)
|
||||
qDebug() << "File tranfer" << friendId << ":" << fileId << "cancelled by friend";
|
||||
file->status = ToxFile::CANCELED;
|
||||
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
|
||||
removeFile(friendId, fileId);
|
||||
} else if (control == TOX_FILE_CONTROL_PAUSE) {
|
||||
|
@ -409,6 +410,7 @@ void CoreFile::onFileDataCallback(Tox* tox, uint32_t friendId, uint32_t fileId,
|
|||
|
||||
// If we reached EOF, ack and cleanup the transfer
|
||||
if (!length) {
|
||||
file->status = ToxFile::FINISHED;
|
||||
if (file->fileKind != TOX_FILE_KIND_AVATAR) {
|
||||
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
||||
emit static_cast<Core*>(core)->fileUploadFinished(file->filePath);
|
||||
|
@ -429,6 +431,7 @@ void CoreFile::onFileDataCallback(Tox* tox, uint32_t friendId, uint32_t fileId,
|
|||
nread = file->file->read((char*)data.get(), length);
|
||||
if (nread <= 0) {
|
||||
qWarning("onFileDataCallback: Failed to read from file");
|
||||
file->status = ToxFile::CANCELED;
|
||||
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
|
||||
tox_file_send_chunk(tox, friendId, fileId, pos, nullptr, 0, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
|
@ -458,14 +461,17 @@ void CoreFile::onFileRecvChunkCallback(Tox* tox, uint32_t friendId, uint32_t fil
|
|||
|
||||
if (file->bytesSent != position) {
|
||||
qWarning("onFileRecvChunkCallback: Received a chunk out-of-order, aborting transfer");
|
||||
if (file->fileKind != TOX_FILE_KIND_AVATAR)
|
||||
if (file->fileKind != TOX_FILE_KIND_AVATAR) {
|
||||
file->status = ToxFile::CANCELED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
}
|
||||
tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!length) {
|
||||
file->status = ToxFile::FINISHED;
|
||||
if (file->fileKind == TOX_FILE_KIND_AVATAR) {
|
||||
QPixmap pic;
|
||||
pic.loadFromData(file->avatarData);
|
||||
|
|
|
@ -28,10 +28,9 @@ ToxFile::ToxFile(uint32_t fileNum, uint32_t friendId, QByteArray filename, QStri
|
|||
, file{new QFile(filePath)}
|
||||
, bytesSent{0}
|
||||
, filesize{0}
|
||||
, status{STOPPED}
|
||||
, status{INITIALIZING}
|
||||
, direction{Direction}
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
bool ToxFile::operator==(const ToxFile& other) const
|
||||
{
|
||||
|
|
|
@ -11,10 +11,12 @@ struct ToxFile
|
|||
{
|
||||
enum FileStatus
|
||||
{
|
||||
STOPPED,
|
||||
INITIALIZING,
|
||||
PAUSED,
|
||||
TRANSMITTING,
|
||||
BROKEN
|
||||
BROKEN,
|
||||
CANCELED,
|
||||
FINISHED,
|
||||
};
|
||||
|
||||
enum FileDirection : bool
|
||||
|
@ -26,9 +28,7 @@ struct ToxFile
|
|||
ToxFile() = default;
|
||||
ToxFile(uint32_t FileNum, uint32_t FriendId, QByteArray FileName, QString filePath,
|
||||
FileDirection Direction);
|
||||
~ToxFile()
|
||||
{
|
||||
}
|
||||
~ToxFile() {}
|
||||
|
||||
bool operator==(const ToxFile& other) const;
|
||||
bool operator!=(const ToxFile& other) const;
|
||||
|
|
Loading…
Reference in New Issue
Block a user