Skip to content

Commit

Permalink
Display export progress.
Browse files Browse the repository at this point in the history
  • Loading branch information
john-preston committed Jun 19, 2018
1 parent 5f01751 commit 4115d3d
Show file tree
Hide file tree
Showing 13 changed files with 543 additions and 77 deletions.
5 changes: 4 additions & 1 deletion Telegram/SourceFiles/export/export_api_wrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,13 +571,15 @@ void ApiWrap::finishUserpicsSlice() {
}

bool ApiWrap::loadUserpicProgress(FileProgress progress) {
Expects(_fileProcess != nullptr);
Expects(_userpicsProcess != nullptr);
Expects(_userpicsProcess->slice.has_value());
Expects((_userpicsProcess->fileIndex >= 0)
&& (_userpicsProcess->fileIndex
< _userpicsProcess->slice->list.size()));

return _userpicsProcess->fileProgress(DownloadProgress{
_fileProcess->relativePath,
_userpicsProcess->fileIndex,
progress.ready,
progress.total });
Expand Down Expand Up @@ -886,12 +888,14 @@ void ApiWrap::finishMessagesSlice() {
}

bool ApiWrap::loadMessageFileProgress(FileProgress progress) {
Expects(_fileProcess != nullptr);
Expects(_chatProcess != nullptr);
Expects(_chatProcess->slice.has_value());
Expects((_chatProcess->fileIndex >= 0)
&& (_chatProcess->fileIndex < _chatProcess->slice->list.size()));

return _chatProcess->fileProgress(DownloadProgress{
_fileProcess->relativePath,
_chatProcess->fileIndex,
progress.ready,
progress.total });
Expand Down Expand Up @@ -996,7 +1000,6 @@ void ApiWrap::loadFile(
_fileProcess->progress = std::move(progress);
_fileProcess->done = std::move(done);


if (_fileProcess->progress) {
const auto progress = FileProgress{
_fileProcess->file.size(),
Expand Down
1 change: 1 addition & 0 deletions Telegram/SourceFiles/export/export_api_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class ApiWrap {
void requestPersonalInfo(FnMut<void(Data::PersonalInfo&&)> done);

struct DownloadProgress {
QString path;
int itemIndex = 0;
int ready = 0;
int total = 0;
Expand Down
110 changes: 80 additions & 30 deletions Telegram/SourceFiles/export/export_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,17 @@ class Controller {
ProcessingState stateLeftChannelsList(int processed) const;
ProcessingState stateDialogsList(int processed) const;
ProcessingState statePersonalInfo() const;
ProcessingState stateUserpics(DownloadProgress progress) const;
ProcessingState stateUserpics(const DownloadProgress &progress) const;
ProcessingState stateContacts() const;
ProcessingState stateSessions() const;
ProcessingState stateLeftChannels(DownloadProgress progress) const;
ProcessingState stateDialogs(DownloadProgress progress) const;
ProcessingState stateLeftChannels(
const DownloadProgress &progress) const;
ProcessingState stateDialogs(const DownloadProgress &progress) const;
void fillMessagesState(
ProcessingState &result,
const Data::DialogsInfo &info,
int index,
const DownloadProgress &progress) const;

int substepsInStep(Step step) const;

Expand All @@ -96,7 +102,10 @@ class Controller {
// rpl::variable<State> fails to compile in MSVC :(
State _state;
rpl::event_stream<State> _stateChanges;
std::shared_ptr<const std::vector<int>> _substepsInStep;
std::vector<int> _substepsInStep;
int _substepsTotal = 0;
mutable int _substepsPassed = 0;
mutable Step _lastProcessingStep = Step::Initializing;

std::unique_ptr<Output::AbstractWriter> _writer;
std::vector<Step> _steps;
Expand Down Expand Up @@ -292,7 +301,7 @@ void Controller::fillSubstepsInSteps(const ApiWrap::StartInfo &info) {
push(Step::PersonalInfo, 1);
}
if (_settings.types & Settings::Type::Userpics) {
push(Step::Userpics, info.userpicsCount);
push(Step::Userpics, 1);
}
if (_settings.types & Settings::Type::Contacts) {
push(Step::Contacts, 1);
Expand All @@ -306,8 +315,8 @@ void Controller::fillSubstepsInSteps(const ApiWrap::StartInfo &info) {
if (_settings.types & Settings::Type::AnyChatsMask) {
push(Step::Dialogs, info.dialogsCount);
}
_substepsInStep = std::make_shared<const std::vector<int>>(
std::move(result));
_substepsInStep = std::move(result);
_substepsTotal = ranges::accumulate(_substepsInStep, 0);
}

void Controller::exportNext() {
Expand Down Expand Up @@ -512,10 +521,17 @@ template <typename Callback>
ProcessingState Controller::prepareState(
Step step,
Callback &&callback) const {
if (step != _lastProcessingStep) {
_substepsPassed += substepsInStep(_lastProcessingStep);
_lastProcessingStep = step;
}

auto result = ProcessingState();
callback(result);
result.step = step;
result.substepsInStep = _substepsInStep;
result.substepsPassed = _substepsPassed;
result.substepsNow = substepsInStep(_lastProcessingStep);
result.substepsTotal = _substepsTotal;
return result;
}

Expand All @@ -524,28 +540,38 @@ ProcessingState Controller::stateInitializing() const {
}

ProcessingState Controller::stateLeftChannelsList(int processed) const {
const auto step = Step::LeftChannelsList;
return prepareState(step, [&](ProcessingState &result) {
return prepareState(Step::LeftChannelsList, [&](
ProcessingState &result) {
result.entityIndex = processed;
result.entityCount = std::max(processed, substepsInStep(step));
result.entityCount = std::max(
processed,
substepsInStep(Step::LeftChannels));
});
}

ProcessingState Controller::stateDialogsList(int processed) const {
const auto step = Step::DialogsList;
return prepareState(step, [&](ProcessingState &result) {
result.entityIndex = processed;
result.entityCount = std::max(processed, substepsInStep(step));
result.entityCount = std::max(
processed,
substepsInStep(Step::Dialogs));
});
}
ProcessingState Controller::statePersonalInfo() const {
return prepareState(Step::PersonalInfo);
}

ProcessingState Controller::stateUserpics(DownloadProgress progress) const {
ProcessingState Controller::stateUserpics(
const DownloadProgress &progress) const {
return prepareState(Step::Userpics, [&](ProcessingState &result) {
result.entityIndex = _userpicsWritten + progress.itemIndex;
result.entityCount = std::max(_userpicsCount, result.entityIndex);
result.bytesType = ProcessingState::FileType::Photo;
if (!progress.path.isEmpty()) {
const auto last = progress.path.lastIndexOf('/');
result.bytesName = progress.path.mid(last + 1);
}
result.bytesLoaded = progress.ready;
result.bytesCount = progress.total;
});
Expand All @@ -560,35 +586,59 @@ ProcessingState Controller::stateSessions() const {
}

ProcessingState Controller::stateLeftChannels(
DownloadProgress progress) const {
const DownloadProgress & progress) const {
const auto step = Step::LeftChannels;
return prepareState(step, [&](ProcessingState &result) {
result.entityIndex = _leftChannelIndex;
result.entityCount = _leftChannelsInfo.list.size();
result.itemIndex = _messagesWritten + progress.itemIndex;
result.itemCount = std::max(_messagesCount, result.entityIndex);
result.bytesLoaded = progress.ready;
result.bytesCount = progress.total;
fillMessagesState(
result,
_leftChannelsInfo,
_leftChannelIndex,
progress);
});
}

ProcessingState Controller::stateDialogs(DownloadProgress progress) const {
ProcessingState Controller::stateDialogs(
const DownloadProgress &progress) const {
const auto step = Step::Dialogs;
return prepareState(step, [&](ProcessingState &result) {
result.entityIndex = _dialogIndex;
result.entityCount = _dialogsInfo.list.size();
result.itemIndex = _messagesWritten + progress.itemIndex;
result.itemCount = std::max(_messagesCount, result.entityIndex);
result.bytesLoaded = progress.ready;
result.bytesCount = progress.total;
fillMessagesState(
result,
_dialogsInfo,
_dialogIndex,
progress);
});
}

void Controller::fillMessagesState(
ProcessingState &result,
const Data::DialogsInfo &info,
int index,
const DownloadProgress &progress) const {
const auto &dialog = info.list[index];
auto count = 0;
for (const auto &dialog : info.list) {
if (dialog.name.isEmpty()) {
++count;
}
}
result.entityIndex = index;
result.entityCount = info.list.size();
result.entityName = dialog.name;
result.itemIndex = _messagesWritten + progress.itemIndex;
result.itemCount = std::max(_messagesCount, result.entityIndex);
result.bytesType = ProcessingState::FileType::File; // TODO
if (!progress.path.isEmpty()) {
const auto last = progress.path.lastIndexOf('/');
result.bytesName = progress.path.mid(last + 1);
}
result.bytesLoaded = progress.ready;
result.bytesCount = progress.total;
}

int Controller::substepsInStep(Step step) const {
Expects(_substepsInStep != 0);
Expects(_substepsInStep->size() > static_cast<int>(step));
Expects(_substepsInStep.size() > static_cast<int>(step));

return (*_substepsInStep)[static_cast<int>(step)];
return _substepsInStep[static_cast<int>(step)];
}

void Controller::setFinishedState() {
Expand Down
16 changes: 8 additions & 8 deletions Telegram/SourceFiles/export/export_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ struct ProcessingState {
LeftChannels,
Dialogs,
};
enum class Item {
Other,
enum class FileType {
None,
Photo,
Video,
VoiceMessage,
Expand All @@ -50,21 +50,21 @@ struct ProcessingState {

Step step = Step::Initializing;

std::shared_ptr<const std::vector<int>> substepsInStep;
int substepsPassed = 0;
int substepsNow = 0;
int substepsTotal = 0;

QString entityName;
int entityIndex = 0;
int entityCount = 1;
QString entityName;

int itemIndex = 0;
int itemCount = 0;
Item itemType = Item::Other;
QString itemName;
QString itemId;

FileType bytesType = FileType::None;
QString bytesName;
int bytesLoaded = 0;
int bytesCount = 0;
QString objectId;

};

Expand Down
20 changes: 20 additions & 0 deletions Telegram/SourceFiles/export/view/export.style
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,23 @@ exportErrorLabel: FlatLabel(boxLabel) {
align: align(top);
textFg: boxTextFgError;
}

exportProgressDuration: 200;
exportProgressRowHeight: 30px;
exportProgressRowPadding: margins(22px, 10px, 22px, 20px);
exportProgressLabel: FlatLabel(boxLabel) {
textFg: windowBoldFg;
maxHeight: 20px;
style: TextStyle(defaultTextStyle) {
font: font(14px semibold);
linkFont: font(14px semibold);
linkFontOver: font(14px semibold);
}
}
exportProgressInfoLabel: FlatLabel(boxLabel) {
textFg: windowSubTextFg;
maxHeight: 20px;
}
exportProgressWidth: 3px;
exportProgressFg: mediaPlayerActiveFg;
exportProgressBg: mediaPlayerInactiveFg;
71 changes: 63 additions & 8 deletions Telegram/SourceFiles/export/view/export_view_content.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ For license and copyright information please follow this link:
#include "export/view/export_view_content.h"

#include "lang/lang_keys.h"
#include "layout.h"

namespace Export {
namespace View {
Expand All @@ -23,26 +24,80 @@ Content ContentFromState(const ProcessingState &state) {
float64 progress) {
result.rows.push_back({ id, label, info, progress });
};
const auto pushMain = [&](const QString &label) {
const auto info = (state.entityCount > 0)
? (QString::number(state.entityIndex)
+ " / "
+ QString::number(state.entityCount))
: QString();
if (!state.substepsTotal) {
push("main", label, info, 0.);
return;
}
const auto substepsTotal = state.substepsTotal;
const auto step = static_cast<int>(state.step);
const auto done = state.substepsPassed;
const auto add = state.substepsNow;
const auto doneProgress = done / float64(substepsTotal);
const auto addProgress = (state.entityCount > 0)
? ((float64(add) * state.entityIndex)
/ (float64(substepsTotal) * state.entityCount))
: 0.;
push("main", label, info, doneProgress + addProgress);
};
const auto pushBytes = [&](const QString &id, const QString &label) {
if (!state.bytesCount) {
return;
}
const auto progress = state.bytesLoaded / float64(state.bytesCount);
const auto info = formatDownloadText(
state.bytesLoaded,
state.bytesCount);
push(id, label, info, progress);
};
switch (state.step) {
case Step::Initializing:
pushMain(lang(lng_export_state_initializing));
break;
case Step::LeftChannelsList:
case Step::DialogsList:
pushMain(lang(lng_export_state_chats_list));
break;
case Step::PersonalInfo:
pushMain(lang(lng_export_option_info));
break;
case Step::Userpics:
pushMain(lang(lng_export_state_userpics));
pushBytes(
"userpic" + QString::number(state.entityIndex),
"Photo_" + QString::number(state.entityIndex + 1) + ".jpg");
break;
case Step::Contacts:
pushMain(lang(lng_export_option_contacts));
break;
case Step::Sessions:
pushMain(lang(lng_export_option_sessions));
break;
case Step::LeftChannels:
case Step::Dialogs:
push("init", lang(lng_export_state_initializing), QString(), 0.);
if (state.entityCount > 0) {
push("entity", QString(), QString::number(state.entityIndex) + '/' + QString::number(state.entityCount), 0.);
}
pushMain(lang(lng_export_state_chats));
if (state.itemCount > 0) {
push("item", QString(), QString::number(state.itemIndex) + '/' + QString::number(state.itemCount), 0.);
}
if (state.bytesCount > 0) {
push("bytes", QString(), QString::number(state.bytesLoaded) + '/' + QString::number(state.bytesCount), 0.);
push(
"chat" + QString::number(state.entityIndex),
(state.entityName.isEmpty()
? lang(lng_deleted)
: state.entityName),
(QString::number(state.itemIndex)
+ " / "
+ QString::number(state.itemCount)),
state.itemIndex / float64(state.itemCount));
}
pushBytes(
("file"
+ QString::number(state.entityIndex)
+ '_'
+ QString::number(state.itemIndex)),
state.bytesName);
break;
default: Unexpected("Step in ContentFromState.");
}
Expand Down
Loading

0 comments on commit 4115d3d

Please sign in to comment.