mirror of
https://github.com/telegramdesktop/tdesktop
synced 2024-12-25 16:02:52 +00:00
Improve export progress / finished design.
This commit is contained in:
parent
329db0d8e9
commit
e8dd277a00
@ -1687,6 +1687,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_export_state_video_message" = "Round video message";
|
||||
"lng_export_state_sticker" = "Sticker";
|
||||
"lng_export_state_gif" = "Animated GIF";
|
||||
"lng_export_progress" = "Note: Please don't close Telegram while exporting files and personal data.";
|
||||
"lng_export_stop" = "Stop";
|
||||
"lng_export_sure_stop" = "Are you sure you want to stop exporting your data?\n\nThis action cannot be undone.";
|
||||
"lng_export_about_done" = "Your data is successfully exported.";
|
||||
"lng_export_done" = "Show my data";
|
||||
"lng_export_finished" = "Export is finished.";
|
||||
"lng_export_total_files" = "Total files: {count}";
|
||||
"lng_export_total_size" = "Total size: {size}";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
|
@ -22,7 +22,6 @@ struct PasswordCheckState {
|
||||
bool requesting = true;
|
||||
bool hasPassword = false;
|
||||
bool checked = false;
|
||||
|
||||
};
|
||||
|
||||
struct ProcessingState {
|
||||
@ -65,22 +64,20 @@ struct ProcessingState {
|
||||
QString bytesName;
|
||||
int bytesLoaded = 0;
|
||||
int bytesCount = 0;
|
||||
|
||||
};
|
||||
|
||||
struct ApiErrorState {
|
||||
RPCError data;
|
||||
|
||||
};
|
||||
|
||||
struct OutputErrorState {
|
||||
QString path;
|
||||
|
||||
};
|
||||
|
||||
struct FinishedState {
|
||||
QString path;
|
||||
|
||||
int filesCount = 0;
|
||||
int64 bytesCount = 0;
|
||||
};
|
||||
|
||||
using State = base::optional_variant<
|
||||
|
@ -818,7 +818,7 @@ QString TextWriter::mainFilePath() {
|
||||
}
|
||||
|
||||
QString TextWriter::mainFileRelativePath() const {
|
||||
return "result.txt";
|
||||
return "overview.txt";
|
||||
}
|
||||
|
||||
QString TextWriter::pathWithRelativePath(const QString &path) const {
|
||||
|
@ -58,11 +58,31 @@ exportProgressLabel: FlatLabel(boxLabel) {
|
||||
exportProgressInfoLabel: FlatLabel(boxLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
maxHeight: 20px;
|
||||
style: boxTextStyle;
|
||||
}
|
||||
exportProgressWidth: 3px;
|
||||
exportProgressFg: mediaPlayerActiveFg;
|
||||
exportProgressBg: mediaPlayerInactiveFg;
|
||||
|
||||
exportCancelButton: RoundButton(attentionBoxButton) {
|
||||
width: 200px;
|
||||
height: 44px;
|
||||
textTop: 12px;
|
||||
font: font(semibold 15px);
|
||||
}
|
||||
exportCancelBottom: 30px;
|
||||
exportDoneButton: RoundButton(defaultActiveButton) {
|
||||
width: 200px;
|
||||
height: 44px;
|
||||
textTop: 12px;
|
||||
font: font(semibold 15px);
|
||||
}
|
||||
|
||||
exportAboutLabel: FlatLabel(boxLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
}
|
||||
exportAboutPadding: margins(22px, 10px, 22px, 0px);
|
||||
|
||||
exportTopBarLabel: FlatLabel(defaultFlatLabel) {
|
||||
maxHeight: 20px;
|
||||
palette: TextPalette(defaultTextPalette) {
|
||||
|
@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Export {
|
||||
namespace View {
|
||||
|
||||
const QString Content::kDoneId = "done";
|
||||
|
||||
Content ContentFromState(const ProcessingState &state) {
|
||||
using Step = ProcessingState::Step;
|
||||
|
||||
@ -101,6 +103,29 @@ Content ContentFromState(const ProcessingState &state) {
|
||||
break;
|
||||
default: Unexpected("Step in ContentFromState.");
|
||||
}
|
||||
while (result.rows.size() < 3) {
|
||||
result.rows.push_back(Content::Row());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Content ContentFromState(const FinishedState &state) {
|
||||
auto result = Content();
|
||||
result.rows.push_back({
|
||||
Content::kDoneId,
|
||||
lang(lng_export_finished),
|
||||
QString(),
|
||||
1. });
|
||||
result.rows.push_back({
|
||||
Content::kDoneId,
|
||||
lng_export_total_files(lt_count, QString::number(state.filesCount)),
|
||||
QString(),
|
||||
1. });
|
||||
result.rows.push_back({
|
||||
Content::kDoneId,
|
||||
lng_export_total_size(lt_size, formatSizeText(state.bytesCount)),
|
||||
QString(),
|
||||
1. });
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,12 @@ struct Content {
|
||||
|
||||
std::vector<Row> rows;
|
||||
|
||||
static const QString kDoneId;
|
||||
|
||||
};
|
||||
|
||||
Content ContentFromState(const ProcessingState &state);
|
||||
Content ContentFromState(const FinishedState &state);
|
||||
|
||||
inline auto ContentFromState(rpl::producer<State> state) {
|
||||
return std::move(
|
||||
@ -34,8 +37,10 @@ inline auto ContentFromState(rpl::producer<State> state) {
|
||||
}) | rpl::map([](const State &state) {
|
||||
if (const auto process = base::get_if<ProcessingState>(&state)) {
|
||||
return ContentFromState(*process);
|
||||
} else if (const auto done = base::get_if<FinishedState>(&state)) {
|
||||
return ContentFromState(*done);
|
||||
}
|
||||
return Content();
|
||||
Unexpected("State type in ContentFromState.");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -13,9 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/separate_panel.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "styles/style_export.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace Export {
|
||||
namespace View {
|
||||
@ -102,13 +104,39 @@ void PanelController::showProgress() {
|
||||
|
||||
progress->cancelClicks(
|
||||
) | rpl::start_with_next([=] {
|
||||
_panel->hideGetDuration();
|
||||
stopWithConfirmation();
|
||||
}, progress->lifetime());
|
||||
|
||||
progress->doneClicks(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (const auto finished = base::get_if<FinishedState>(&_state)) {
|
||||
File::ShowInFolder(finished->path);
|
||||
_panel->hideGetDuration();
|
||||
}
|
||||
}, progress->lifetime());
|
||||
|
||||
_panel->showInner(std::move(progress));
|
||||
_panel->setHideOnDeactivate(true);
|
||||
}
|
||||
|
||||
void PanelController::stopWithConfirmation() {
|
||||
auto box = Box<ConfirmBox>(
|
||||
lang(lng_export_sure_stop),
|
||||
lang(lng_export_stop),
|
||||
st::attentionBoxButton,
|
||||
[=] { stopExport(); });
|
||||
_panel->showBox(
|
||||
std::move(box),
|
||||
LayerOption::KeepOther,
|
||||
anim::type::normal);
|
||||
}
|
||||
|
||||
void PanelController::stopExport() {
|
||||
_stopRequested = true;
|
||||
_panel->showAndActivate();
|
||||
_panel->hideGetDuration();
|
||||
}
|
||||
|
||||
void PanelController::showDone(const QString &path) {
|
||||
_panel->setTitle(Lang::Viewer(lng_export_title));
|
||||
|
||||
@ -133,7 +161,7 @@ rpl::producer<> PanelController::closed() const {
|
||||
return _panelCloseEvents.events(
|
||||
) | rpl::flatten_latest(
|
||||
) | rpl::filter([=] {
|
||||
return !_state.is<ProcessingState>();
|
||||
return !_state.is<ProcessingState>() || _stopRequested;
|
||||
});
|
||||
}
|
||||
|
||||
@ -147,7 +175,8 @@ void PanelController::updateState(State &&state) {
|
||||
} else if (const auto error = base::get_if<OutputErrorState>(&_state)) {
|
||||
showError(*error);
|
||||
} else if (const auto finished = base::get_if<FinishedState>(&_state)) {
|
||||
showDone(finished->path);
|
||||
_panel->setHideOnDeactivate(false);
|
||||
// showDone(finished->path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ public:
|
||||
PanelController(not_null<ControllerWrap*> process);
|
||||
|
||||
void activatePanel();
|
||||
void stopWithConfirmation();
|
||||
|
||||
rpl::producer<> closed() const;
|
||||
|
||||
@ -39,6 +40,7 @@ public:
|
||||
~PanelController();
|
||||
|
||||
private:
|
||||
void stopExport();
|
||||
void createPanel();
|
||||
void updateState(State &&state);
|
||||
void showSettings();
|
||||
@ -54,6 +56,7 @@ private:
|
||||
|
||||
State _state;
|
||||
rpl::event_stream<rpl::producer<>> _panelCloseEvents;
|
||||
bool _stopRequested = false;
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
@ -237,61 +237,64 @@ ProgressWidget::ProgressWidget(
|
||||
rpl::producer<Content> content)
|
||||
: RpWidget(parent)
|
||||
, _body(this) {
|
||||
initFooter();
|
||||
|
||||
widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
_body->resizeToWidth(width);
|
||||
_body->moveToLeft(0, 0);
|
||||
}, _body->lifetime());
|
||||
|
||||
_about = _body->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
this,
|
||||
lang(lng_export_progress),
|
||||
Ui::FlatLabel::InitType::Simple,
|
||||
st::exportAboutLabel),
|
||||
st::exportAboutPadding);
|
||||
|
||||
std::move(
|
||||
content
|
||||
) | rpl::start_with_next([=](Content &&content) {
|
||||
updateState(std::move(content));
|
||||
}, lifetime());
|
||||
|
||||
_cancel = base::make_unique_q<Ui::RoundButton>(
|
||||
this,
|
||||
langFactory(lng_export_stop),
|
||||
st::exportCancelButton);
|
||||
setupBottomButton(_cancel.get());
|
||||
}
|
||||
|
||||
rpl::producer<> ProgressWidget::cancelClicks() const {
|
||||
return _cancel->clicks();
|
||||
return _cancel ? _cancel->clicks() : rpl::never<>();
|
||||
}
|
||||
|
||||
void ProgressWidget::initFooter() {
|
||||
const auto buttonsPadding = st::boxButtonPadding;
|
||||
const auto buttonsHeight = buttonsPadding.top()
|
||||
+ st::defaultBoxButton.height
|
||||
+ buttonsPadding.bottom();
|
||||
const auto buttons = Ui::CreateChild<Ui::FixedHeightWidget>(
|
||||
this,
|
||||
buttonsHeight);
|
||||
rpl::producer<> ProgressWidget::doneClicks() const {
|
||||
return _doneClicks.events();
|
||||
}
|
||||
|
||||
void ProgressWidget::setupBottomButton(not_null<Ui::RoundButton*> button) {
|
||||
button->show();
|
||||
|
||||
sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
buttons->resizeToWidth(size.width());
|
||||
buttons->moveToLeft(0, size.height() - buttons->height());
|
||||
}, lifetime());
|
||||
|
||||
_cancel = Ui::CreateChild<Ui::RoundButton>(
|
||||
buttons,
|
||||
langFactory(lng_cancel),
|
||||
st::defaultBoxButton);
|
||||
_cancel->show();
|
||||
|
||||
buttons->widthValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto right = st::boxButtonPadding.right();
|
||||
const auto top = st::boxButtonPadding.top();
|
||||
_cancel->moveToRight(right, top);
|
||||
}, _cancel->lifetime());
|
||||
button->move(
|
||||
(size.width() - button->width()) / 2,
|
||||
(size.height() - st::exportCancelBottom - button->height()));
|
||||
}, button->lifetime());
|
||||
}
|
||||
|
||||
void ProgressWidget::updateState(Content &&content) {
|
||||
if (!content.rows.empty() && content.rows[0].id == Content::kDoneId) {
|
||||
showDone();
|
||||
}
|
||||
|
||||
auto index = 0;
|
||||
for (auto &row : content.rows) {
|
||||
if (index < _rows.size()) {
|
||||
_rows[index]->updateData(std::move(row));
|
||||
} else {
|
||||
_rows.push_back(_body->add(
|
||||
_rows.push_back(_body->insert(
|
||||
index,
|
||||
object_ptr<Row>(this, std::move(row)),
|
||||
st::exportProgressRowPadding));
|
||||
}
|
||||
@ -302,6 +305,17 @@ void ProgressWidget::updateState(Content &&content) {
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressWidget::showDone() {
|
||||
_cancel = nullptr;
|
||||
_about->setText(lang(lng_export_about_done));
|
||||
_done = base::make_unique_q<Ui::RoundButton>(
|
||||
this,
|
||||
langFactory(lng_export_done),
|
||||
st::exportDoneButton);
|
||||
_done->clicks() | rpl::start_to_stream(_doneClicks, _done->lifetime());
|
||||
setupBottomButton(_done.get());
|
||||
}
|
||||
|
||||
ProgressWidget::~ProgressWidget() = default;
|
||||
|
||||
} // namespace View
|
||||
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Ui {
|
||||
class VerticalLayout;
|
||||
class RoundButton;
|
||||
class FlatLabel;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Export {
|
||||
@ -25,12 +26,14 @@ public:
|
||||
rpl::producer<Content> content);
|
||||
|
||||
rpl::producer<> cancelClicks() const;
|
||||
rpl::producer<> doneClicks() const;
|
||||
|
||||
~ProgressWidget();
|
||||
|
||||
private:
|
||||
void initFooter();
|
||||
void setupBottomButton(not_null<Ui::RoundButton*> button);
|
||||
void updateState(Content &&content);
|
||||
void showDone();
|
||||
|
||||
Content _content;
|
||||
|
||||
@ -38,7 +41,10 @@ private:
|
||||
object_ptr<Ui::VerticalLayout> _body;
|
||||
std::vector<not_null<Row*>> _rows;
|
||||
|
||||
QPointer<Ui::RoundButton> _cancel;
|
||||
QPointer<Ui::FlatLabel> _about;
|
||||
base::unique_qptr<Ui::RoundButton> _cancel;
|
||||
base::unique_qptr<Ui::RoundButton> _done;
|
||||
rpl::event_stream<> _doneClicks;
|
||||
|
||||
};
|
||||
|
||||
|
@ -1693,7 +1693,8 @@ void MainWidget::setCurrentExportView(Export::View::PanelController *view) {
|
||||
if (_currentExportView) {
|
||||
_currentExportView->progressState(
|
||||
) | rpl::start_with_next([=](Export::View::Content &&data) {
|
||||
if (data.rows.empty()) {
|
||||
if (!data.rows.empty()
|
||||
&& data.rows[0].id == Export::View::Content::kDoneId) {
|
||||
destroyExportTopBar();
|
||||
} else if (!_exportTopBar) {
|
||||
createExportTopBar(std::move(data));
|
||||
|
Loading…
Reference in New Issue
Block a user