From 0143fd28af7d35d5cf4de3ce9ba9c510c84dca4d Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 23 Jun 2018 00:18:43 +0100 Subject: [PATCH] Suggest start export when time comes. --- Telegram/Resources/langs/lang.strings | 3 + Telegram/SourceFiles/core/basic_types.h | 1 + Telegram/SourceFiles/core/utils.h | 1 - Telegram/SourceFiles/data/data_session.cpp | 23 ++++++ Telegram/SourceFiles/data/data_session.h | 4 ++ .../export/data/export_data_types.h | 1 - .../SourceFiles/export/export_api_wrap.cpp | 2 +- Telegram/SourceFiles/export/export_settings.h | 2 + .../view/export_view_panel_controller.cpp | 72 ++++++++++++++++++- .../view/export_view_panel_controller.h | 2 + Telegram/SourceFiles/mainwidget.cpp | 5 ++ Telegram/SourceFiles/storage/localstorage.cpp | 18 +++-- 12 files changed, 123 insertions(+), 11 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 37c1854de..ad2e207b5 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1703,6 +1703,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_export_folder" = "Choose export folder"; "lng_export_invalid" = "Sorry, you have started a new data export, so this data export is now cancelled."; "lng_export_delay" = "Sorry, for security reasons, you will be able to begin downloading your data in 24 hours. We have notified all your devices about the export request to make sure it's authorized and give you time to react if it's not.\n\nPlease come back on {date} and repeat the request using the same device."; +"lng_export_suggest_title" = "Data export ready"; +"lng_export_suggest_text" = "You can now download the data you requested. Start exporting data?"; +"lng_export_suggest_cancel" = "Not now"; // Wnd specific diff --git a/Telegram/SourceFiles/core/basic_types.h b/Telegram/SourceFiles/core/basic_types.h index 9a67d963c..309ff41b4 100644 --- a/Telegram/SourceFiles/core/basic_types.h +++ b/Telegram/SourceFiles/core/basic_types.h @@ -40,6 +40,7 @@ using float32 = float; using float64 = double; using TimeMs = int64; +using TimeId = int32; #define qsl(s) QStringLiteral(s) #define qstr(s) QLatin1String((s), sizeof(s) - 1) diff --git a/Telegram/SourceFiles/core/utils.h b/Telegram/SourceFiles/core/utils.h index a5ce12a88..1e71dd3e3 100644 --- a/Telegram/SourceFiles/core/utils.h +++ b/Telegram/SourceFiles/core/utils.h @@ -188,7 +188,6 @@ inline void accumulate_max(T &a, const T &b) { if (a < b) a = b; } template inline void accumulate_min(T &a, const T &b) { if (a > b) a = b; } -using TimeId = int32; void unixtimeInit(); void unixtimeSet(TimeId serverTime, bool force = false); TimeId unixtime(); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 9eab477c7..ac360256c 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -83,6 +83,29 @@ void Session::startExport() { }, _export->lifetime()); } +void Session::suggestStartExport(TimeId availableAt) { + _exportAvailableAt = availableAt; + suggestStartExport(); +} + +void Session::suggestStartExport() { + if (_exportAvailableAt <= 0) { + return; + } + const auto now = unixtime(); + const auto left = (_exportAvailableAt <= now) + ? 0 + : (_exportAvailableAt - now); + if (!left) { + Export::View::SuggestStart(); + } else { + App::CallDelayed( + std::min(left + 5, 3600) * TimeMs(1000), + _session, + [=] { suggestStartExport(); }); + } +} + rpl::producer Session::currentExportView( ) const { return _exportViewChanges.events_starting_with(_exportPanel.get()); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index b0c0cd0ff..ecd294a8e 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -52,6 +52,7 @@ public: } void startExport(); + void suggestStartExport(TimeId availableAt); rpl::producer currentExportView() const; bool exportInProgress() const; void stopExportWithConfirmation(FnMut callback); @@ -408,6 +409,8 @@ public: } private: + void suggestStartExport(); + void setupContactViewsViewer(); void setupChannelLeavingViewer(); void photoApplyFields( @@ -505,6 +508,7 @@ private: std::unique_ptr _export; std::unique_ptr _exportPanel; rpl::event_stream _exportViewChanges; + TimeId _exportAvailableAt = 0; base::Variable _contactsLoaded = { false }; base::Variable _allChatsLoaded = { false }; diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index bb0095643..9c60bbc1c 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -20,7 +20,6 @@ namespace Export { struct Settings; namespace Data { -using TimeId = int32; using Utf8String = QByteArray; using PeerId = uint64; diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp index 439120abe..8e64aeaea 100644 --- a/Telegram/SourceFiles/export/export_api_wrap.cpp +++ b/Telegram/SourceFiles/export/export_api_wrap.cpp @@ -180,7 +180,7 @@ struct ApiWrap::LeftChannelsProcess : ChatsProcess { struct ApiWrap::DialogsProcess : ChatsProcess { int splitIndexPlusOne = 0; - Data::TimeId offsetDate = 0; + TimeId offsetDate = 0; int32 offsetId = 0; MTPInputPeer offsetPeer = MTP_inputPeerEmpty(); }; diff --git a/Telegram/SourceFiles/export/export_settings.h b/Telegram/SourceFiles/export/export_settings.h index 355d46a3c..129d43f73 100644 --- a/Telegram/SourceFiles/export/export_settings.h +++ b/Telegram/SourceFiles/export/export_settings.h @@ -76,6 +76,8 @@ struct Settings { Types fullChats = DefaultFullChats(); MediaSettings media; + TimeId availableAt = 0; + static inline Types DefaultTypes() { return Type::PersonalInfo | Type::Userpics diff --git a/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp b/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp index 020e95a60..9fbae0300 100644 --- a/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp +++ b/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp @@ -17,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/localstorage.h" #include "core/file_utilities.h" #include "platform/platform_specific.h" +#include "auth_session.h" +#include "data/data_session.h" #include "styles/style_export.h" #include "styles/style_boxes.h" @@ -24,11 +26,72 @@ namespace Export { namespace View { namespace { -constexpr auto kAddDelay = TimeId(60); constexpr auto kSaveSettingsTimeout = TimeMs(1000); +class SuggestBox : public BoxContent { +public: + SuggestBox(QWidget*); + +protected: + void prepare() override; + +private: + bool _cleared = false; + +}; + +SuggestBox::SuggestBox(QWidget*) { +} + +void SuggestBox::prepare() { + setTitle(langFactory(lng_export_suggest_title)); + + const auto clear = [=] { + if (_cleared) { + return; + } + _cleared = true; + + auto settings = Local::ReadExportSettings(); + settings.availableAt = 0; + Local::WriteExportSettings(settings); + }; + + addButton(langFactory(lng_box_ok), [=] { + clear(); + closeBox(); + Auth().data().startExport(); + }); + addButton(langFactory(lng_export_suggest_cancel), [=] { closeBox(); }); + setCloseByOutsideClick(false); + + const auto content = Ui::CreateChild( + this, + lang(lng_export_suggest_text), + Ui::FlatLabel::InitType::Simple, + st::boxLabel); + widthValue( + ) | rpl::start_with_next([=](int width) { + const auto contentWidth = width + - st::boxPadding.left() + - st::boxPadding.right(); + content->resizeToWidth(contentWidth); + content->moveToLeft(st::boxPadding.left(), 0); + }, content->lifetime()); + content->heightValue( + ) | rpl::start_with_next([=](int height) { + setDimensions(st::boxWidth, height + st::boxPadding.bottom()); + }, content->lifetime()); + + boxClosing() | rpl::start_with_next(clear, lifetime()); +} + } // namespace +void SuggestStart() { + Ui::show(Box(), LayerOption::KeepOther); +} + PanelController::PanelController(not_null process) : _process(process) , _settings(std::make_unique(Local::ReadExportSettings())) @@ -91,10 +154,15 @@ void PanelController::showError(const ApiErrorState &error) { showError(lang(lng_export_invalid)); } else if (error.data.type().startsWith(qstr("TAKEOUT_INIT_DELAY_"))) { const auto seconds = std::max(error.data.type().mid( - qstr("TAKEOUT_INIT_DELAY_").size()).toInt(), 0) + kAddDelay; + qstr("TAKEOUT_INIT_DELAY_").size()).toInt(), 1); const auto now = QDateTime::currentDateTime(); const auto when = now.addSecs(seconds); showError(lng_export_delay(lt_date, langDateTimeFull(when))); + + _settings->availableAt = unixtime() + seconds; + _saveSettingsTimer.callOnce(kSaveSettingsTimeout); + + Auth().data().suggestStartExport(_settings->availableAt); } else { showCriticalError("API Error happened :(\n" + QString::number(error.data.code()) + ": " + error.data.type() diff --git a/Telegram/SourceFiles/export/view/export_view_panel_controller.h b/Telegram/SourceFiles/export/view/export_view_panel_controller.h index 0656f243e..0189e81c4 100644 --- a/Telegram/SourceFiles/export/view/export_view_panel_controller.h +++ b/Telegram/SourceFiles/export/view/export_view_panel_controller.h @@ -21,6 +21,8 @@ class SeparatePanel; namespace Export { namespace View { +void SuggestStart(); + class Panel; class PanelController { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 681c6444f..fffdaab7e 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -79,6 +79,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/update_checker.h" #include "calls/calls_instance.h" #include "calls/calls_top_bar.h" +#include "export/export_settings.h" #include "export/view/export_view_top_bar.h" #include "export/view/export_view_panel_controller.h" #include "auth_session.h" @@ -3821,6 +3822,10 @@ void MainWidget::start(const MTPUser *self) { Local::readRecentStickers(); Local::readFavedStickers(); Local::readSavedGifs(); + if (const auto availableAt = Local::ReadExportSettings().availableAt) { + Auth().data().suggestStartExport(availableAt); + } + _history->start(); Messenger::Instance().checkStartUrl(); diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 57d7c03db..4aa807afe 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -4623,7 +4623,8 @@ void WriteExportSettings(const Export::Settings &settings) { && settings.media.types == check.media.types && settings.media.sizeLimit == check.media.sizeLimit && settings.path == check.path - && settings.format == check.format) { + && settings.format == check.format + && settings.availableAt == check.availableAt) { if (_exportSettingsKey) { clearKey(_exportSettingsKey); _exportSettingsKey = 0; @@ -4636,7 +4637,7 @@ void WriteExportSettings(const Export::Settings &settings) { _mapChanged = true; _writeMap(WriteMapWhen::Fast); } - quint32 size = sizeof(quint32) * 5 + quint32 size = sizeof(quint32) * 6 + Serialize::stringSize(settings.path); EncryptedDescriptor data(size); data.stream @@ -4645,7 +4646,8 @@ void WriteExportSettings(const Export::Settings &settings) { << quint32(settings.media.types) << quint32(settings.media.sizeLimit) << quint32(settings.format) - << settings.path; + << settings.path + << quint32(settings.availableAt); FileWriteDescriptor file(_exportSettingsKey); file.writeEncrypted(data); @@ -4663,7 +4665,7 @@ Export::Settings ReadExportSettings() { quint32 types = 0, fullChats = 0; quint32 mediaTypes = 0, mediaSizeLimit = 0; - quint32 format = 0; + quint32 format = 0, availableAt = 0; QString path; file.stream >> types @@ -4671,7 +4673,8 @@ Export::Settings ReadExportSettings() { >> mediaTypes >> mediaSizeLimit >> format - >> path; + >> path + >> availableAt; auto result = Export::Settings(); result.types = Export::Settings::Types::from_raw(types); result.fullChats = Export::Settings::Types::from_raw(fullChats); @@ -4679,7 +4682,10 @@ Export::Settings ReadExportSettings() { result.media.sizeLimit = mediaSizeLimit; result.format = Export::Output::Format(format); result.path = path; - return result.validate() ? result : Export::Settings(); + result.availableAt = availableAt; + return (file.stream.status() == QDataStream::Ok && result.validate()) + ? result + : Export::Settings(); } void writeSavedPeers() {