From 0b7bb806b7f7cfb75fc97e39490a7a75237b0bf7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 12 Jul 2018 00:06:35 +0300 Subject: [PATCH] Improve export HTML layout. --- Telegram/Resources/export_html/css/style.css | 6 - Telegram/Resources/langs/lang.strings | 4 +- Telegram/Resources/qrc/telegram.qrc | 2 - .../export/data/export_data_types.cpp | 49 ++++-- .../export/data/export_data_types.h | 10 +- .../SourceFiles/export/export_api_wrap.cpp | 61 ++++--- Telegram/SourceFiles/export/export_api_wrap.h | 13 +- .../SourceFiles/export/export_controller.cpp | 143 ++------------- .../SourceFiles/export/export_controller.h | 2 - .../export/output/export_output_abstract.cpp | 7 +- .../export/output/export_output_abstract.h | 9 - .../export/output/export_output_html.cpp | 163 +++++++----------- .../export/output/export_output_html.h | 36 ++-- .../export/output/export_output_json.cpp | 98 +++++------ .../export/output/export_output_json.h | 39 ++--- .../export/output/export_output_text.cpp | 137 +++++++-------- .../export/output/export_output_text.h | 40 ++--- .../export/view/export_view_content.cpp | 2 - 18 files changed, 331 insertions(+), 490 deletions(-) diff --git a/Telegram/Resources/export_html/css/style.css b/Telegram/Resources/export_html/css/style.css index 4fa6823d5..d873e35f8 100644 --- a/Telegram/Resources/export_html/css/style.css +++ b/Telegram/Resources/export_html/css/style.css @@ -400,9 +400,6 @@ a.block_link:hover { .section.web { background-image: url(../images/section_web.png); } -.section.leftchats { - background-image: url(../images/section_leftchats.png); -} .section.other { background-image: url(../images/section_other.png) } @@ -464,9 +461,6 @@ a.block_link:hover { .section.web { background-image: url(../images/section_web@2x.png); } -.section.leftchats { - background-image: url(../images/section_leftchats@2x.png); -} .section.other { background-image: url(../images/section_other@2x.png); } diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 9cd44f43f..68764ad23 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1731,11 +1731,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_export_suggest_cancel" = "Not now"; "lng_export_about_telegram" = "Here is all the data you requested. Remember: we don’t use your data for ad targeting, we don’t sell it to others, and we’re not part of any “family of companies.”\n\nTelegram only keeps the information it needs to function as a feature-rich cloud service – for example, your cloud chats so that you can access them from any devices without using third-party backups, or your contacts so that you can rely on your existing social graph when messaging people on Telegram.\n\nCheck out Settings > Privacy & Security on Telegram's mobile apps for relevant settings."; "lng_export_about_contacts" = "If you allow access, your contacts are continuously synced with Telegram. Thanks to this, you can easily switch to Telegram without losing your existing social graph – and connect with friends across all your devices. We use data about your contacts to let you know when they join Telegram. We also use it to make sure that you see the names you have in your phone book instead of the screen names people choose for themselves.\n\nYou can disable contact syncing or delete your stored contacts in Settings > Privacy & Security on Telegram's mobile apps."; -"lng_export_about_frequent" = "This rating shows which people you are likelier to message frequently. Telegram uses this data to populate the 'People' box at the top of the Search section. This rating is also calculated for inline bots so that the app can suggest the bots you are most likely to use in the attachment menu (or when you start a new message with \"@\").\n\nTo delete this data, go to Settings > Privacy & Security and disable 'Suggest Frequent Contacts' (requires Telegram for iOS v.4.8.3 or Telegram for Android v.4.8.10 or higher). See this page for more information: https://telegram.org/faq_export"; +"lng_export_about_frequent" = "This rating shows which people you are likelier to message frequently. Telegram uses this data to populate the 'People' box at the top of the Search section. This rating is also calculated for inline bots so that the app can suggest the bots you are most likely to use in the attachment menu (or when you start a new message with \"@\").\n\nTo delete this data, go to Settings > Privacy & Security and disable 'Suggest Frequent Contacts' (requires Telegram for iOS v.4.8.3 or Telegram for Android v.4.8.10 or higher)."; "lng_export_about_sessions" = "We store session info to display your connected devices in Settings > Privacy & Security > Active Sessions."; "lng_export_about_web_sessions" = "We store this to display the websites where you logged in using authentication via Telegram. This information is shown in Settings > Privacy & Security > Active Sessions."; "lng_export_about_chats" = "This page lists all chats from this export and where to look for their data."; -"lng_export_about_left_chats" = "This page lists all supergroups and channels from this export that you've left and where to look for their data.\n\nNote that when you leave a channel or supergroup you've created, you have the option to either delete it, or simply leave (in case you want to rejoin later, or keep the community alive despite not being a member)."; +"lng_export_about_left_chats" = "Below are the supergroups and channels from this export that you've left or where you were banned.\n\nNote that when you leave a channel or supergroup you've created, you have the option to either delete it, or simply leave (in case you want to rejoin later, or keep the community alive despite not being a member)."; // Wnd specific diff --git a/Telegram/Resources/qrc/telegram.qrc b/Telegram/Resources/qrc/telegram.qrc index 15fcbb130..e96b25780 100644 --- a/Telegram/Resources/qrc/telegram.qrc +++ b/Telegram/Resources/qrc/telegram.qrc @@ -31,8 +31,6 @@ ../export_html/images/section_contacts@2x.png ../export_html/images/section_frequent.png ../export_html/images/section_frequent@2x.png - ../export_html/images/section_leftchats.png - ../export_html/images/section_leftchats@2x.png ../export_html/images/section_other.png ../export_html/images/section_other@2x.png ../export_html/images/section_photos.png diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index 539adfb51..f835dc2f9 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -1296,6 +1296,28 @@ SessionsList ParseWebSessionsList( }); } +DialogInfo *DialogsInfo::item(int index) { + const auto chatsCount = chats.size(); + return (index < 0) + ? nullptr + : (index < chatsCount) + ? &chats[index] + : (index - chatsCount < left.size()) + ? &left[index - chatsCount] + : nullptr; +} + +const DialogInfo *DialogsInfo::item(int index) const { + const auto chatsCount = chats.size(); + return (index < 0) + ? nullptr + : (index < chatsCount) + ? &chats[index] + : (index - chatsCount < left.size()) + ? &left[index - chatsCount] + : nullptr; +} + DialogInfo::Type DialogTypeFromChat(const Chat &chat) { using Type = DialogInfo::Type; return chat.username.isEmpty() @@ -1325,7 +1347,7 @@ DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) { }, [&](const auto &data) { // MTPDmessages_dialogs &data) { const auto peers = ParsePeersLists(data.vusers, data.vchats); const auto messages = ParseMessagesList(data.vmessages, folder); - result.list.reserve(result.list.size() + data.vdialogs.v.size()); + result.chats.reserve(result.chats.size() + data.vdialogs.v.size()); for (const auto &dialog : data.vdialogs.v) { if (dialog.type() != mtpc_dialog) { continue; @@ -1358,7 +1380,7 @@ DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) { const auto &message = messageIt->second; info.topMessageDate = message.date; } - result.list.push_back(std::move(info)); + result.chats.push_back(std::move(info)); } }); return result; @@ -1367,7 +1389,7 @@ DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) { DialogsInfo ParseLeftChannelsInfo(const MTPmessages_Chats &data) { auto result = DialogsInfo(); data.match([&](const auto &data) { //MTPDmessages_chats &data) { - result.list.reserve(data.vchats.v.size()); + result.left.reserve(data.vchats.v.size()); for (const auto &single : data.vchats.v) { const auto chat = ParseChat(single); auto info = DialogInfo(); @@ -1377,17 +1399,20 @@ DialogsInfo ParseLeftChannelsInfo(const MTPmessages_Chats &data) { info.topMessageDate = 0; info.topMessageId = 0; info.type = DialogTypeFromChat(chat); - result.list.push_back(std::move(info)); + info.isLeftChannel = true; + result.left.push_back(std::move(info)); } }); return result; } void FinalizeDialogsInfo(DialogsInfo &info, const Settings &settings) { - auto &list = info.list; - const auto digits = Data::NumberToString(list.size() - 1).size(); + auto &chats = info.chats; + auto &left = info.left; + const auto fullCount = chats.size() + left.size(); + const auto digits = Data::NumberToString(fullCount - 1).size(); auto index = 0; - for (auto &dialog : list) { + for (auto &dialog : chats) { const auto number = Data::NumberToString(++index, digits, '0'); dialog.relativePath = "chats/chat_" + number + '/'; @@ -1410,15 +1435,9 @@ void FinalizeDialogsInfo(DialogsInfo &info, const Settings &settings) { ranges::reverse(dialog.splits); } -} - -void FinalizeLeftChannelsInfo(DialogsInfo &info, const Settings &settings) { - auto &list = info.list; - const auto digits = Data::NumberToString(list.size() - 1).size(); - auto index = 0; - for (auto &dialog : list) { + for (auto &dialog : left) { const auto number = Data::NumberToString(++index, digits, '0'); - dialog.relativePath = "chats/left_" + number + '/'; + dialog.relativePath = "chats/chat_" + number + '/'; dialog.onlyMyMessages = true; } } diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 840eb457f..cea1c7dc6 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -521,13 +521,14 @@ struct DialogInfo { MTPInputPeer input = MTP_inputPeerEmpty(); int32 topMessageId = 0; TimeId topMessageDate = 0; - PeerId peerId; + PeerId peerId = 0; // User messages splits which contained that dialog. std::vector splits; // Filled after the whole dialogs list is accumulated. bool onlyMyMessages = false; + bool isLeftChannel = false; QString relativePath; // Filled when requesting dialog messages. @@ -535,7 +536,11 @@ struct DialogInfo { }; struct DialogsInfo { - std::vector list; + DialogInfo *item(int index); + const DialogInfo *item(int index) const; + + std::vector chats; + std::vector left; }; DialogInfo::Type DialogTypeFromChat(const Chat &chat); @@ -543,7 +548,6 @@ DialogInfo::Type DialogTypeFromChat(const Chat &chat); DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data); DialogsInfo ParseLeftChannelsInfo(const MTPmessages_Chats &data); void FinalizeDialogsInfo(DialogsInfo &info, const Settings &settings); -void FinalizeLeftChannelsInfo(DialogsInfo &info, const Settings &settings); struct MessagesSlice { std::vector list; diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp index 61a737ed1..790ad8059 100644 --- a/Telegram/SourceFiles/export/export_api_wrap.cpp +++ b/Telegram/SourceFiles/export/export_api_wrap.cpp @@ -536,8 +536,8 @@ void ApiWrap::requestLeftChannelsCount() { Expects(_startProcess != nullptr); Expects(_leftChannelsProcess != nullptr); - _startProcess->info.leftChannelsCount - = _leftChannelsProcess->fullCount; + _startProcess->info.dialogsCount + += _leftChannelsProcess->fullCount; sendNextStartRequest(); }); } @@ -569,7 +569,6 @@ void ApiWrap::requestLeftChannelsSlice() { if (_leftChannelsProcess->finished) { const auto process = base::take(_leftChannelsProcess); - Data::FinalizeLeftChannelsInfo(process->info, *_settings); process->done(std::move(process->info)); } else { requestLeftChannelsSlice(); @@ -987,10 +986,10 @@ void ApiWrap::requestDialogsSlice() { }); auto info = Data::ParseDialogsInfo(result); - _dialogsProcess->processedCount += info.list.size(); - const auto last = info.list.empty() + _dialogsProcess->processedCount += info.chats.size(); + const auto last = info.chats.empty() ? Data::DialogInfo() - : info.list.back(); + : info.chats.back(); appendDialogsSlice(std::move(info)); if (!_dialogsProcess->progress(_dialogsProcess->processedCount)) { @@ -1007,7 +1006,7 @@ void ApiWrap::requestDialogsSlice() { _dialogsProcess->offsetDate = 0; _dialogsProcess->offsetPeer = MTP_inputPeerEmpty(); } else { - finishDialogsList(); + requestLeftChannelsIfNeeded(); return; } requestDialogsSlice(); @@ -1020,16 +1019,35 @@ void ApiWrap::appendDialogsSlice(Data::DialogsInfo &&info) { appendChatsSlice( *_dialogsProcess, - std::move(info), + _dialogsProcess->info.chats, + std::move(info.chats), _dialogsProcess->splitIndexPlusOne - 1); } +void ApiWrap::requestLeftChannelsIfNeeded() { + if (_settings->types & Settings::Type::GroupsChannelsMask) { + requestLeftChannelsList([=](int count) { + Expects(_dialogsProcess != nullptr); + + return _dialogsProcess->progress( + _dialogsProcess->processedCount + count); + }, [=](Data::DialogsInfo &&result) { + Expects(_dialogsProcess != nullptr); + + _dialogsProcess->info.left = std::move(result.left); + finishDialogsList(); + }); + } else { + finishDialogsList(); + } +} + void ApiWrap::finishDialogsList() { Expects(_dialogsProcess != nullptr); const auto process = base::take(_dialogsProcess); - ranges::reverse(process->info.list); + ranges::reverse(process->info.chats); Data::FinalizeDialogsInfo(process->info, *_settings); process->done(std::move(process->info)); @@ -1067,7 +1085,7 @@ void ApiWrap::requestLeftChannelsSliceGeneric(FnMut done) { }); if (process->progress) { - if (!process->progress(process->info.list.size())) { + if (!process->progress(process->info.left.size())) { return; } } @@ -1082,32 +1100,33 @@ void ApiWrap::appendLeftChannelsSlice(Data::DialogsInfo &&info) { appendChatsSlice( *_leftChannelsProcess, - std::move(info), + _leftChannelsProcess->info.left, + std::move(info.left), _splits.size() - 1); } void ApiWrap::appendChatsSlice( - ChatsProcess &to, - Data::DialogsInfo &&info, + ChatsProcess &process, + std::vector &to, + std::vector &&from, int splitIndex) { Expects(_settings != nullptr); const auto types = _settings->types; auto filtered = ranges::view::all( - info.list + from ) | ranges::view::filter([&](const Data::DialogInfo &info) { return (types & SettingsFromDialogsType(info.type)) != 0; }); - auto &list = to.info.list; - list.reserve(list.size() + info.list.size()); + to.reserve(to.size() + from.size()); for (auto &info : filtered) { - const auto nextIndex = list.size(); - const auto [i, ok] = to.indexByPeer.emplace(info.peerId, nextIndex); + const auto nextIndex = to.size(); + const auto [i, ok] = process.indexByPeer.emplace(info.peerId, nextIndex); if (ok) { - list.push_back(std::move(info)); + to.push_back(std::move(info)); } - list[i->second].splits.push_back(splitIndex); - list[i->second].messagesCountPerSplit.push_back(0); + to[i->second].splits.push_back(splitIndex); + to[i->second].messagesCountPerSplit.push_back(0); } } diff --git a/Telegram/SourceFiles/export/export_api_wrap.h b/Telegram/SourceFiles/export/export_api_wrap.h index cdddc9df6..e9594c68d 100644 --- a/Telegram/SourceFiles/export/export_api_wrap.h +++ b/Telegram/SourceFiles/export/export_api_wrap.h @@ -42,16 +42,12 @@ public: struct StartInfo { int userpicsCount = 0; int dialogsCount = 0; - int leftChannelsCount = 0; }; void startExport( const Settings &settings, Output::Stats *stats, FnMut done); - void requestLeftChannelsList( - Fn progress, - FnMut done); void requestDialogsList( Fn progress, FnMut done); @@ -129,13 +125,18 @@ private: void appendDialogsSlice(Data::DialogsInfo &&info); void finishDialogsList(); + void requestLeftChannelsIfNeeded(); + void requestLeftChannelsList( + Fn progress, + FnMut done); void requestLeftChannelsSliceGeneric(FnMut done); void requestLeftChannelsSlice(); void appendLeftChannelsSlice(Data::DialogsInfo &&info); void appendChatsSlice( - ChatsProcess &to, - Data::DialogsInfo &&info, + ChatsProcess &process, + std::vector &to, + std::vector &&from, int splitIndex); void requestMessagesCount(int localSplitIndex); diff --git a/Telegram/SourceFiles/export/export_controller.cpp b/Telegram/SourceFiles/export/export_controller.cpp index 1dd31effa..d2467f002 100644 --- a/Telegram/SourceFiles/export/export_controller.cpp +++ b/Telegram/SourceFiles/export/export_controller.cpp @@ -54,7 +54,6 @@ private: void exportNext(); void initialize(); void initialized(const ApiWrap::StartInfo &info); - void collectLeftChannels(); void collectDialogsList(); void exportPersonalInfo(); void exportUserpics(); @@ -63,31 +62,24 @@ private: void exportOtherData(); void exportDialogs(); void exportNextDialog(); - void exportLeftChannels(); - void exportNextLeftChannel(); template ProcessingState prepareState( Step step, Callback &&callback = kNullStateCallback) const; ProcessingState stateInitializing() const; - ProcessingState stateLeftChannelsList(int processed) const; ProcessingState stateDialogsList(int processed) const; ProcessingState statePersonalInfo() const; ProcessingState stateUserpics(const DownloadProgress &progress) const; ProcessingState stateContacts() const; ProcessingState stateSessions() const; ProcessingState stateOtherData() 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, - int addIndex, - int addCount) const; + const DownloadProgress &progress) const; int substepsInStep(Step step) const; @@ -97,9 +89,6 @@ private: Settings _settings; Environment _environment; - Data::DialogsInfo _leftChannelsInfo; - int _leftChannelIndex = -1; - Data::DialogsInfo _dialogsInfo; int _dialogIndex = -1; @@ -241,9 +230,6 @@ void Controller::startExport( void Controller::fillExportSteps() { using Type = Settings::Type; _steps.push_back(Step::Initializing); - if (_settings.types & Type::GroupsChannelsMask) { - _steps.push_back(Step::LeftChannelsList); - } if (_settings.types & Type::AnyChatsMask) { _steps.push_back(Step::DialogsList); } @@ -265,9 +251,6 @@ void Controller::fillExportSteps() { if (_settings.types & Type::AnyChatsMask) { _steps.push_back(Step::Dialogs); } - if (_settings.types & Type::GroupsChannelsMask) { - _steps.push_back(Step::LeftChannels); - } } void Controller::fillSubstepsInSteps(const ApiWrap::StartInfo &info) { @@ -280,9 +263,6 @@ void Controller::fillSubstepsInSteps(const ApiWrap::StartInfo &info) { result[index] = count; }; push(Step::Initializing, 1); - if (_settings.types & Settings::Type::GroupsChannelsMask) { - push(Step::LeftChannelsList, 1); - } if (_settings.types & Settings::Type::AnyChatsMask) { push(Step::DialogsList, 1); } @@ -301,9 +281,6 @@ void Controller::fillSubstepsInSteps(const ApiWrap::StartInfo &info) { if (_settings.types & Settings::Type::OtherData) { push(Step::OtherData, 1); } - if (_settings.types & Settings::Type::GroupsChannelsMask) { - push(Step::LeftChannels, info.leftChannelsCount); - } if (_settings.types & Settings::Type::AnyChatsMask) { push(Step::Dialogs, info.dialogsCount); } @@ -330,14 +307,12 @@ void Controller::exportNext() { const auto step = _steps[_stepIndex]; switch (step) { case Step::Initializing: return initialize(); - case Step::LeftChannelsList: return collectLeftChannels(); case Step::DialogsList: return collectDialogsList(); case Step::PersonalInfo: return exportPersonalInfo(); case Step::Userpics: return exportUserpics(); case Step::Contacts: return exportContacts(); case Step::Sessions: return exportSessions(); case Step::OtherData: return exportOtherData(); - case Step::LeftChannels: return exportLeftChannels(); case Step::Dialogs: return exportDialogs(); } Unexpected("Step in Controller::exportNext."); @@ -358,17 +333,6 @@ void Controller::initialized(const ApiWrap::StartInfo &info) { exportNext(); } -void Controller::collectLeftChannels() { - setState(stateLeftChannelsList(0)); - _api.requestLeftChannelsList([=](int count) { - setState(stateLeftChannelsList(count)); - return true; - }, [=](Data::DialogsInfo &&result) { - _leftChannelsInfo = std::move(result); - exportNext(); - }); -} - void Controller::collectDialogsList() { setState(stateDialogsList(0)); _api.requestDialogsList([=](int count) { @@ -457,9 +421,9 @@ void Controller::exportDialogs() { void Controller::exportNextDialog() { const auto index = ++_dialogIndex; - if (index < _dialogsInfo.list.size()) { - const auto &info = _dialogsInfo.list[index]; - _api.requestMessages(info, [=](const Data::DialogInfo &info) { + const auto info = _dialogsInfo.item(index); + if (info) { + _api.requestMessages(*info, [=](const Data::DialogInfo &info) { if (ioCatchError(_writer->writeDialogStart(info))) { return false; } @@ -493,52 +457,6 @@ void Controller::exportNextDialog() { exportNext(); } -void Controller::exportLeftChannels() { - if (ioCatchError(_writer->writeLeftChannelsStart(_leftChannelsInfo))) { - return; - } - - exportNextLeftChannel(); -} - -void Controller::exportNextLeftChannel() { - const auto index = ++_leftChannelIndex; - if (index < _leftChannelsInfo.list.size()) { - const auto &info = _leftChannelsInfo.list[index]; - _api.requestMessages(info, [=](const Data::DialogInfo &info) { - if (ioCatchError(_writer->writeLeftChannelStart(info))) { - return false; - } - _messagesWritten = 0; - _messagesCount = ranges::accumulate( - info.messagesCountPerSplit, - 0); - setState(stateLeftChannels(DownloadProgress())); - return true; - }, [=](DownloadProgress progress) { - setState(stateLeftChannels(progress)); - return true; - }, [=](Data::MessagesSlice &&result) { - if (ioCatchError(_writer->writeLeftChannelSlice(result))) { - return false; - } - _messagesWritten += result.list.size(); - setState(stateLeftChannels(DownloadProgress())); - return true; - }, [=] { - if (ioCatchError(_writer->writeLeftChannelEnd())) { - return; - } - exportNextLeftChannel(); - }); - return; - } - if (ioCatchError(_writer->writeLeftChannelsEnd())) { - return; - } - exportNext(); -} - template ProcessingState Controller::prepareState( Step step, @@ -561,22 +479,11 @@ ProcessingState Controller::stateInitializing() const { return ProcessingState(); } -ProcessingState Controller::stateLeftChannelsList(int processed) const { - return prepareState(Step::LeftChannelsList, [&]( - ProcessingState &result) { - result.entityIndex = processed; - result.entityCount = std::max( - processed, - substepsInStep(Step::LeftChannels)) - + substepsInStep(Step::Dialogs); - }); -} - ProcessingState Controller::stateDialogsList(int processed) const { const auto step = Step::DialogsList; return prepareState(step, [&](ProcessingState &result) { - result.entityIndex = substepsInStep(Step::LeftChannels) + processed; - result.entityCount = substepsInStep(Step::LeftChannels) + std::max( + result.entityIndex = processed; + result.entityCount = std::max( processed, substepsInStep(Step::Dialogs)); }); @@ -612,35 +519,15 @@ ProcessingState Controller::stateOtherData() const { return prepareState(Step::OtherData); } -ProcessingState Controller::stateLeftChannels( - const DownloadProgress & progress) const { - const auto step = Step::LeftChannels; - return prepareState(step, [&](ProcessingState &result) { - const auto addIndex = _dialogsInfo.list.size(); - const auto addCount = addIndex; - fillMessagesState( - result, - _leftChannelsInfo, - _leftChannelIndex, - progress, - addIndex, - addCount); - }); -} - ProcessingState Controller::stateDialogs( const DownloadProgress &progress) const { const auto step = Step::Dialogs; return prepareState(step, [&](ProcessingState &result) { - const auto addIndex = 0; - const auto addCount = _leftChannelsInfo.list.size(); fillMessagesState( result, _dialogsInfo, _dialogIndex, - progress, - addIndex, - addCount); + progress); }); } @@ -648,14 +535,14 @@ void Controller::fillMessagesState( ProcessingState &result, const Data::DialogsInfo &info, int index, - const DownloadProgress &progress, - int addIndex, - int addCount) const { - const auto &dialog = info.list[index]; - result.entityIndex = index + addIndex; - result.entityCount = info.list.size() + addCount; - result.entityName = dialog.name; - result.entityType = (dialog.type == Data::DialogInfo::Type::Self) + const DownloadProgress &progress) const { + const auto dialog = info.item(index); + Assert(dialog != nullptr); + + result.entityIndex = index; + result.entityCount = info.chats.size() + info.left.size(); + result.entityName = dialog->name; + result.entityType = (dialog->type == Data::DialogInfo::Type::Self) ? ProcessingState::EntityType::SavedMessages : ProcessingState::EntityType::Chat; result.itemIndex = _messagesWritten + progress.itemIndex; diff --git a/Telegram/SourceFiles/export/export_controller.h b/Telegram/SourceFiles/export/export_controller.h index 0ec6ca670..29c96b26c 100644 --- a/Telegram/SourceFiles/export/export_controller.h +++ b/Telegram/SourceFiles/export/export_controller.h @@ -28,14 +28,12 @@ struct PasswordCheckState { struct ProcessingState { enum class Step { Initializing, - LeftChannelsList, DialogsList, PersonalInfo, Userpics, Contacts, Sessions, OtherData, - LeftChannels, Dialogs, }; enum class FileType { diff --git a/Telegram/SourceFiles/export/output/export_output_abstract.cpp b/Telegram/SourceFiles/export/output/export_output_abstract.cpp index 28c9831ed..bc55dd5eb 100644 --- a/Telegram/SourceFiles/export/output/export_output_abstract.cpp +++ b/Telegram/SourceFiles/export/output/export_output_abstract.cpp @@ -467,8 +467,8 @@ Stats AbstractWriter::produceTestExample( dialogChat.splits.push_back(1); dialogChat.topMessageDate = sliceChat2.list.back().date; dialogChat.topMessageId = sliceChat2.list.back().id; - dialogs.list.push_back(dialogBot); - dialogs.list.push_back(dialogChat); + dialogs.chats.push_back(dialogBot); + dialogs.chats.push_back(dialogChat); check(writeDialogsStart(dialogs)); check(writeDialogStart(dialogBot)); @@ -481,9 +481,6 @@ Stats AbstractWriter::produceTestExample( check(writeDialogEnd()); check(writeDialogsEnd()); - check(writeLeftChannelsStart(Data::DialogsInfo())); - check(writeLeftChannelsEnd()); - check(finish()); return result; diff --git a/Telegram/SourceFiles/export/output/export_output_abstract.h b/Telegram/SourceFiles/export/output/export_output_abstract.h index 540c139c8..e764731c7 100644 --- a/Telegram/SourceFiles/export/output/export_output_abstract.h +++ b/Telegram/SourceFiles/export/output/export_output_abstract.h @@ -75,15 +75,6 @@ public: [[nodiscard]] virtual Result writeDialogEnd() = 0; [[nodiscard]] virtual Result writeDialogsEnd() = 0; - [[nodiscard]] virtual Result writeLeftChannelsStart( - const Data::DialogsInfo &data) = 0; - [[nodiscard]] virtual Result writeLeftChannelStart( - const Data::DialogInfo &data) = 0; - [[nodiscard]] virtual Result writeLeftChannelSlice( - const Data::MessagesSlice &data) = 0; - [[nodiscard]] virtual Result writeLeftChannelEnd() = 0; - [[nodiscard]] virtual Result writeLeftChannelsEnd() = 0; - [[nodiscard]] virtual Result finish() = 0; [[nodiscard]] virtual QString mainFilePath() = 0; diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index 2ae9d6229..36af78bc0 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -1755,7 +1755,6 @@ Result HtmlWriter::start( "images/section_chats.png", "images/section_contacts.png", "images/section_frequent.png", - "images/section_leftchats.png", "images/section_other.png", "images/section_photos.png", "images/section_sessions.png", @@ -1874,7 +1873,7 @@ Result HtmlWriter::writeUserpicsStart(const Data::UserpicsInfo &data) { _userpics = fileWithRelativePath(userpicsFilePath()); auto block = _userpics->pushHeader( - "Personal photos", + "Profile pictures", mainFileRelativePath()); block.append(_userpics->pushDiv("page_body list_page")); block.append(_userpics->pushDiv("entry_list")); @@ -2198,98 +2197,36 @@ Result HtmlWriter::writeOtherData(const Data::File &data) { } Result HtmlWriter::writeDialogsStart(const Data::DialogsInfo &data) { - return writeChatsStart( - data, - "Chats", - "chats", - _environment.aboutChats, - "lists/chats.html"); -} - -Result HtmlWriter::writeDialogStart(const Data::DialogInfo &data) { - return writeChatStart(data); -} - -Result HtmlWriter::writeDialogSlice(const Data::MessagesSlice &data) { - return writeChatSlice(data); -} - -Result HtmlWriter::writeDialogEnd() { - return writeChatEnd(); -} - -Result HtmlWriter::writeDialogsEnd() { - return writeChatsEnd(); -} - -Result HtmlWriter::writeLeftChannelsStart(const Data::DialogsInfo &data) { - return writeChatsStart( - data, - "Left chats", - "leftchats", - _environment.aboutLeftChats, - "lists/left_chats.html"); -} - -Result HtmlWriter::writeLeftChannelStart(const Data::DialogInfo &data) { - return writeChatStart(data); -} - -Result HtmlWriter::writeLeftChannelSlice(const Data::MessagesSlice &data) { - return writeChatSlice(data); -} - -Result HtmlWriter::writeLeftChannelEnd() { - return writeChatEnd(); -} - -Result HtmlWriter::writeLeftChannelsEnd() { - return writeChatsEnd(); -} - -Result HtmlWriter::writeChatsStart( - const Data::DialogsInfo &data, - const QByteArray &listName, - const QByteArray &buttonClass, - const QByteArray &about, - const QString &fileName) { Expects(_summary != nullptr); Expects(_chats == nullptr); - if (data.list.empty()) { + if (data.chats.empty() && data.left.empty()) { return Result::Success(); } - _dialogsRelativePath = fileName; - _chats = fileWithRelativePath(fileName); - _dialogIndex = 0; - _dialogsCount = data.list.size(); + _dialogsRelativePath = "lists/chats.html"; + _chats = fileWithRelativePath(_dialogsRelativePath); auto block = _chats->pushHeader( - listName, + "Chats", mainFileRelativePath()); block.append(_chats->pushDiv("page_body list_page")); - block.append(_chats->pushAbout(about)); - block.append(_chats->pushDiv("entry_list")); if (const auto result = _chats->writeBlock(block); !result) { return result; } pushSection( 0, - listName, - buttonClass, - data.list.size(), - fileName); + "Chats", + "chats", + data.chats.size() + data.left.size(), + "lists/chats.html"); return writeSections(); } -Result HtmlWriter::writeChatStart(const Data::DialogInfo &data) { +Result HtmlWriter::writeDialogStart(const Data::DialogInfo &data) { Expects(_chat == nullptr); - Expects(_dialogIndex < _dialogsCount); - const auto digits = Data::NumberToString(_dialogsCount - 1).size(); - const auto number = Data::NumberToString(++_dialogIndex, digits, '0'); _chat = fileWithRelativePath(data.relativePath + messagesFile(0)); _chatFileEmpty = true; _messagesCount = 0; @@ -2299,29 +2236,7 @@ Result HtmlWriter::writeChatStart(const Data::DialogInfo &data) { return Result::Success(); } -Result HtmlWriter::writeChatOpening(int index) { - const auto name = (_dialog.name.isEmpty() - && _dialog.lastName.isEmpty()) - ? QByteArray("Deleted Account") - : (_dialog.name + ' ' + _dialog.lastName); - auto block = _chat->pushHeader( - name, - _dialogsRelativePath); - block.append(_chat->pushDiv("page_body chat_page")); - block.append(_chat->pushDiv("history")); - if (index > 0) { - const auto previousPath = messagesFile(index - 1); - block.append(_chat->pushTag("a", { - { "class", "pagination block_link" }, - { "href", previousPath.toUtf8() } - })); - block.append("Previous messages part"); - block.append(_chat->popTag()); - } - return _chat->writeBlock(block); -} - -Result HtmlWriter::writeChatSlice(const Data::MessagesSlice &data) { +Result HtmlWriter::writeDialogSlice(const Data::MessagesSlice &data) { Expects(_chat != nullptr); Expects(!data.list.empty()); @@ -2331,7 +2246,7 @@ Result HtmlWriter::writeChatSlice(const Data::MessagesSlice &data) { auto block = QByteArray(); for (const auto &message : data.list) { if (_chatFileEmpty) { - if (const auto result = writeChatOpening(oldIndex); !result) { + if (const auto result = writeDialogOpening(oldIndex); !result) { return result; } _chatFileEmpty = false; @@ -2378,7 +2293,7 @@ Result HtmlWriter::writeChatSlice(const Data::MessagesSlice &data) { return _chat->writeBlock(block); } -Result HtmlWriter::writeChatEnd() { +Result HtmlWriter::writeDialogEnd() { Expects(_chats != nullptr); Expects(_chat != nullptr); @@ -2446,6 +2361,12 @@ Result HtmlWriter::writeChatEnd() { }; userpic.firstName = NameString(_dialog); userpic.lastName = LastNameString(_dialog); + + const auto result = validateDialogsMode(_dialog.isLeftChannel); + if (!result) { + return result; + } + return _chats->writeBlock(_chats->pushListEntry( userpic, ComposeName(userpic, DeletedString(_dialog.type)), @@ -2456,13 +2377,55 @@ Result HtmlWriter::writeChatEnd() { : QString()))); } -Result HtmlWriter::writeChatsEnd() { +Result HtmlWriter::validateDialogsMode(bool isLeftChannel) { + const auto mode = isLeftChannel + ? DialogsMode::Left + : DialogsMode::Chats; + if (_dialogsMode == mode) { + return Result::Success(); + } else if (_dialogsMode != DialogsMode::None) { + const auto result = _chats->writeBlock(_chats->popTag()); + if (!result) { + return result; + } + } + _dialogsMode = mode; + auto block = _chats->pushAbout(isLeftChannel + ? _environment.aboutLeftChats + : _environment.aboutChats); + block.append(_chats->pushDiv("entry_list")); + return _chats->writeBlock(block); +} + +Result HtmlWriter::writeDialogsEnd() { if (_chats) { return base::take(_chats)->close(); } return Result::Success(); } +Result HtmlWriter::writeDialogOpening(int index) { + const auto name = (_dialog.name.isEmpty() + && _dialog.lastName.isEmpty()) + ? QByteArray("Deleted Account") + : (_dialog.name + ' ' + _dialog.lastName); + auto block = _chat->pushHeader( + name, + _dialogsRelativePath); + block.append(_chat->pushDiv("page_body chat_page")); + block.append(_chat->pushDiv("history")); + if (index > 0) { + const auto previousPath = messagesFile(index - 1); + block.append(_chat->pushTag("a", { + { "class", "pagination block_link" }, + { "href", previousPath.toUtf8() } + })); + block.append("Previous messages"); + block.append(_chat->popTag()); + } + return _chat->writeBlock(block); +} + void HtmlWriter::pushSection( int priority, const QByteArray &label, @@ -2513,7 +2476,7 @@ Result HtmlWriter::switchToNextChatFile(int index) { { "class", "pagination block_link" }, { "href", nextPath.toUtf8() } }); - next.append("Next messages part"); + next.append("Next messages"); next.append(_chat->popTag()); if (const auto result = _chat->writeBlock(next); !result) { return result; diff --git a/Telegram/SourceFiles/export/output/export_output_html.h b/Telegram/SourceFiles/export/output/export_output_html.h index eb1bd7e68..838c627d3 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.h +++ b/Telegram/SourceFiles/export/output/export_output_html.h @@ -71,12 +71,6 @@ public: Result writeDialogEnd() override; Result writeDialogsEnd() override; - Result writeLeftChannelsStart(const Data::DialogsInfo &data) override; - Result writeLeftChannelStart(const Data::DialogInfo &data) override; - Result writeLeftChannelSlice(const Data::MessagesSlice &data) override; - Result writeLeftChannelEnd() override; - Result writeLeftChannelsEnd() override; - Result finish() override; QString mainFilePath() override; @@ -89,15 +83,21 @@ private: using MediaData = details::MediaData; class Wrap; struct MessageInfo; + enum class DialogsMode { + None, + Chats, + Left, + }; [[nodiscard]] Result copyFile( const QString &source, const QString &relativePath) const; - QString mainFileRelativePath() const; - QString pathWithRelativePath(const QString &path) const; - std::unique_ptr fileWithRelativePath(const QString &path) const; - QString messagesFile(int index) const; + [[nodiscard]] QString mainFileRelativePath() const; + [[nodiscard]] QString pathWithRelativePath(const QString &path) const; + [[nodiscard]] std::unique_ptr fileWithRelativePath( + const QString &path) const; + [[nodiscard]] QString messagesFile(int index) const; [[nodiscard]] Result writeSavedContacts(const Data::ContactsList &data); [[nodiscard]] Result writeFrequentContacts(const Data::ContactsList &data); @@ -105,17 +105,8 @@ private: [[nodiscard]] Result writeSessions(const Data::SessionsList &data); [[nodiscard]] Result writeWebSessions(const Data::SessionsList &data); - [[nodiscard]] Result writeChatsStart( - const Data::DialogsInfo &data, - const QByteArray &listName, - const QByteArray &buttonClass, - const QByteArray &about, - const QString &fileName); - [[nodiscard]] Result writeChatStart(const Data::DialogInfo &data); - [[nodiscard]] Result writeChatOpening(int index); - [[nodiscard]] Result writeChatSlice(const Data::MessagesSlice &data); - [[nodiscard]] Result writeChatEnd(); - [[nodiscard]] Result writeChatsEnd(); + [[nodiscard]] Result validateDialogsMode(bool isLeftChannel); + [[nodiscard]] Result writeDialogOpening(int index); [[nodiscard]] Result switchToNextChatFile(int index); void pushSection( @@ -153,10 +144,9 @@ private: int _userpicsCount = 0; std::unique_ptr _userpics; - int _dialogsCount = 0; - int _dialogIndex = 0; QString _dialogsRelativePath; Data::DialogInfo _dialog; + DialogsMode _dialogsMode = DialogsMode::None; int _messagesCount = 0; std::unique_ptr _lastMessageInfo; diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index b00f2cead..e306db49b 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -593,7 +593,10 @@ Result JsonWriter::start( _stats = stats; _output = fileWithRelativePath(mainFileRelativePath()); - return _output->writeBlock(pushNesting(Context::kObject)); + auto block = pushNesting(Context::kObject); + block.append(prepareObjectItemStart("about")); + block.append(SerializeString(_environment.aboutTelegram)); + return _output->writeBlock(block); } QByteArray JsonWriter::pushNesting(Context::Type type) { @@ -943,56 +946,16 @@ Result JsonWriter::writeWebSessions(const Data::SessionsList &data) { } Result JsonWriter::writeDialogsStart(const Data::DialogsInfo &data) { - return writeChatsStart(data, "chats"); + return Result::Success(); } Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) { - return writeChatStart(data); -} - -Result JsonWriter::writeDialogSlice(const Data::MessagesSlice &data) { - return writeChatSlice(data); -} - -Result JsonWriter::writeDialogEnd() { - return writeChatEnd(); -} - -Result JsonWriter::writeDialogsEnd() { - return writeChatsEnd(); -} - -Result JsonWriter::writeLeftChannelsStart(const Data::DialogsInfo &data) { - return writeChatsStart(data, "left_chats"); -} - -Result JsonWriter::writeLeftChannelStart(const Data::DialogInfo &data) { - return writeChatStart(data); -} - -Result JsonWriter::writeLeftChannelSlice(const Data::MessagesSlice &data) { - return writeChatSlice(data); -} - -Result JsonWriter::writeLeftChannelEnd() { - return writeChatEnd(); -} - -Result JsonWriter::writeLeftChannelsEnd() { - return writeChatsEnd(); -} - -Result JsonWriter::writeChatsStart( - const Data::DialogsInfo &data, - const QByteArray &listName) { Expects(_output != nullptr); - auto block = prepareObjectItemStart(listName); - return _output->writeBlock(block + pushNesting(Context::kArray)); -} - -Result JsonWriter::writeChatStart(const Data::DialogInfo &data) { - Expects(_output != nullptr); + const auto result = validateDialogsMode(data.isLeftChannel); + if (!result) { + return result; + } using Type = Data::DialogInfo::Type; const auto TypeString = [](Type type) { @@ -1023,7 +986,26 @@ Result JsonWriter::writeChatStart(const Data::DialogInfo &data) { return _output->writeBlock(block); } -Result JsonWriter::writeChatSlice(const Data::MessagesSlice &data) { +Result JsonWriter::validateDialogsMode(bool isLeftChannel) { + const auto mode = isLeftChannel + ? DialogsMode::Left + : DialogsMode::Chats; + if (_dialogsMode == mode) { + return Result::Success(); + } else if (_dialogsMode != DialogsMode::None) { + if (const auto result = writeChatsEnd(); !result) { + return result; + } + } + _dialogsMode = mode; + return writeChatsStart( + isLeftChannel ? "left_chats" : "chats", + (isLeftChannel + ? _environment.aboutLeftChats + : _environment.aboutChats)); +} + +Result JsonWriter::writeDialogSlice(const Data::MessagesSlice &data) { Expects(_output != nullptr); auto block = QByteArray(); @@ -1037,17 +1019,35 @@ Result JsonWriter::writeChatSlice(const Data::MessagesSlice &data) { return _output->writeBlock(block); } -Result JsonWriter::writeChatEnd() { +Result JsonWriter::writeDialogEnd() { Expects(_output != nullptr); auto block = popNesting(); return _output->writeBlock(block + popNesting()); } +Result JsonWriter::writeDialogsEnd() { + return writeChatsEnd(); +} + +Result JsonWriter::writeChatsStart( + const QByteArray &listName, + const QByteArray &about) { + Expects(_output != nullptr); + + auto block = prepareObjectItemStart(listName); + block.append(pushNesting(Context::kObject)); + block.append(prepareObjectItemStart("about")); + block.append(SerializeString(about)); + block.append(prepareObjectItemStart("list")); + return _output->writeBlock(block + pushNesting(Context::kArray)); +} + Result JsonWriter::writeChatsEnd() { Expects(_output != nullptr); - return _output->writeBlock(popNesting()); + auto block = popNesting(); + return _output->writeBlock(block + popNesting()); } Result JsonWriter::finish() { diff --git a/Telegram/SourceFiles/export/output/export_output_json.h b/Telegram/SourceFiles/export/output/export_output_json.h index 3718d8867..49f7035b0 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.h +++ b/Telegram/SourceFiles/export/output/export_output_json.h @@ -56,41 +56,39 @@ public: Result writeDialogEnd() override; Result writeDialogsEnd() override; - Result writeLeftChannelsStart(const Data::DialogsInfo &data) override; - Result writeLeftChannelStart(const Data::DialogInfo &data) override; - Result writeLeftChannelSlice(const Data::MessagesSlice &data) override; - Result writeLeftChannelEnd() override; - Result writeLeftChannelsEnd() override; - Result finish() override; QString mainFilePath() override; private: using Context = details::JsonContext; + enum class DialogsMode { + None, + Chats, + Left, + }; [[nodiscard]] QByteArray pushNesting(Context::Type type); [[nodiscard]] QByteArray prepareObjectItemStart(const QByteArray &key); [[nodiscard]] QByteArray prepareArrayItemStart(); [[nodiscard]] QByteArray popNesting(); - QString mainFileRelativePath() const; - QString pathWithRelativePath(const QString &path) const; - std::unique_ptr fileWithRelativePath(const QString &path) const; + [[nodiscard]] QString mainFileRelativePath() const; + [[nodiscard]] QString pathWithRelativePath(const QString &path) const; + [[nodiscard]] std::unique_ptr fileWithRelativePath( + const QString &path) const; - Result writeSavedContacts(const Data::ContactsList &data); - Result writeFrequentContacts(const Data::ContactsList &data); + [[nodiscard]] Result writeSavedContacts(const Data::ContactsList &data); + [[nodiscard]] Result writeFrequentContacts(const Data::ContactsList &data); - Result writeSessions(const Data::SessionsList &data); - Result writeWebSessions(const Data::SessionsList &data); + [[nodiscard]] Result writeSessions(const Data::SessionsList &data); + [[nodiscard]] Result writeWebSessions(const Data::SessionsList &data); - Result writeChatsStart( - const Data::DialogsInfo &data, - const QByteArray &listName); - Result writeChatStart(const Data::DialogInfo &data); - Result writeChatSlice(const Data::MessagesSlice &data); - Result writeChatEnd(); - Result writeChatsEnd(); + [[nodiscard]] Result validateDialogsMode(bool isLeftChannel); + [[nodiscard]] Result writeChatsStart( + const QByteArray &listName, + const QByteArray &about); + [[nodiscard]] Result writeChatsEnd(); Settings _settings; Environment _environment; @@ -98,6 +96,7 @@ private: Context _context; bool _currentNestingHadItem = false; + DialogsMode _dialogsMode = DialogsMode::None; std::unique_ptr _output; diff --git a/Telegram/SourceFiles/export/output/export_output_text.cpp b/Telegram/SourceFiles/export/output/export_output_text.cpp index ef15470a9..97f2a88c8 100644 --- a/Telegram/SourceFiles/export/output/export_output_text.cpp +++ b/Telegram/SourceFiles/export/output/export_output_text.cpp @@ -786,95 +786,47 @@ Result TextWriter::writeOtherData(const Data::File &data) { } Result TextWriter::writeDialogsStart(const Data::DialogsInfo &data) { - return writeChatsStart( - data, - "Chats", - _environment.aboutChats, - "lists/chats.txt"); + _dialogsCount = data.chats.size(); + _leftChannelsCount = data.left.size(); + return Result::Success(); } Result TextWriter::writeDialogStart(const Data::DialogInfo &data) { - return writeChatStart(data); -} + Expects(_chat == nullptr); -Result TextWriter::writeDialogSlice(const Data::MessagesSlice &data) { - return writeChatSlice(data); -} - -Result TextWriter::writeDialogEnd() { - return writeChatEnd(); -} - -Result TextWriter::writeDialogsEnd() { - return writeChatsEnd(); -} - -Result TextWriter::writeLeftChannelsStart(const Data::DialogsInfo &data) { - return writeChatsStart( - data, - "Left chats", - _environment.aboutLeftChats, - "lists/left_chats.txt"); -} - -Result TextWriter::writeLeftChannelStart(const Data::DialogInfo &data) { - return writeChatStart(data); -} - -Result TextWriter::writeLeftChannelSlice(const Data::MessagesSlice &data) { - return writeChatSlice(data); -} - -Result TextWriter::writeLeftChannelEnd() { - return writeChatEnd(); -} - -Result TextWriter::writeLeftChannelsEnd() { - return writeChatsEnd(); -} - -Result TextWriter::writeChatsStart( - const Data::DialogsInfo &data, - const QByteArray &listName, - const QByteArray &about, - const QString &fileName) { - Expects(_summary != nullptr); - Expects(_chats == nullptr); - - if (data.list.empty()) { - return Result::Success(); - } - - _chats = fileWithRelativePath(fileName); - _dialogIndex = 0; - _dialogsCount = data.list.size(); - - const auto block = about + kLineBreak; - if (const auto result = _chats->writeBlock(block); !result) { + const auto result = validateDialogsMode(data.isLeftChannel); + if (!result) { return result; } - const auto header = listName + " " - "(" + Data::NumberToString(data.list.size()) + ") - " - + fileName.toUtf8() - + kLineBreak - + kLineBreak; - return _summary->writeBlock(header); -} - -Result TextWriter::writeChatStart(const Data::DialogInfo &data) { - Expects(_chat == nullptr); - Expects(_dialogIndex < _dialogsCount); - - const auto digits = Data::NumberToString(_dialogsCount - 1).size(); - const auto number = Data::NumberToString(++_dialogIndex, digits, '0'); _chat = fileWithRelativePath(data.relativePath + "messages.txt"); _messagesCount = 0; _dialog = data; return Result::Success(); } -Result TextWriter::writeChatSlice(const Data::MessagesSlice &data) { +Result TextWriter::validateDialogsMode(bool isLeftChannel) { + const auto mode = isLeftChannel + ? DialogsMode::Left + : DialogsMode::Chats; + if (_dialogsMode == mode) { + return Result::Success(); + } else if (_dialogsMode != DialogsMode::None) { + if (const auto result = writeChatsEnd(); !result) { + return result; + } + } + _dialogsMode = mode; + return writeChatsStart( + isLeftChannel ? _leftChannelsCount : _dialogsCount, + isLeftChannel ? "Left chats" : "Chats", + (isLeftChannel + ? _environment.aboutLeftChats + : _environment.aboutChats), + isLeftChannel ? "lists/left_chats.txt" : "lists/chats.txt"); +} + +Result TextWriter::writeDialogSlice(const Data::MessagesSlice &data) { Expects(_chat != nullptr); Expects(!data.list.empty()); @@ -893,7 +845,7 @@ Result TextWriter::writeChatSlice(const Data::MessagesSlice &data) { return _chat->writeBlock(full); } -Result TextWriter::writeChatEnd() { +Result TextWriter::writeDialogEnd() { Expects(_chats != nullptr); Expects(_chat != nullptr); @@ -954,6 +906,37 @@ Result TextWriter::writeChatEnd() { })); } +Result TextWriter::writeDialogsEnd() { + return writeChatsEnd(); +} + +Result TextWriter::writeChatsStart( + int count, + const QByteArray &listName, + const QByteArray &about, + const QString &fileName) { + Expects(_summary != nullptr); + Expects(_chats == nullptr); + + if (!count) { + return Result::Success(); + } + + _chats = fileWithRelativePath(fileName); + + const auto block = about + kLineBreak; + if (const auto result = _chats->writeBlock(block); !result) { + return result; + } + + const auto header = listName + " " + "(" + Data::NumberToString(count) + ") - " + + fileName.toUtf8() + + kLineBreak + + kLineBreak; + return _summary->writeBlock(header); +} + Result TextWriter::writeChatsEnd() { _chats = nullptr; return Result::Success(); diff --git a/Telegram/SourceFiles/export/output/export_output_text.h b/Telegram/SourceFiles/export/output/export_output_text.h index e3a2e8bbc..26a4ab998 100644 --- a/Telegram/SourceFiles/export/output/export_output_text.h +++ b/Telegram/SourceFiles/export/output/export_output_text.h @@ -44,36 +44,35 @@ public: Result writeDialogEnd() override; Result writeDialogsEnd() override; - Result writeLeftChannelsStart(const Data::DialogsInfo &data) override; - Result writeLeftChannelStart(const Data::DialogInfo &data) override; - Result writeLeftChannelSlice(const Data::MessagesSlice &data) override; - Result writeLeftChannelEnd() override; - Result writeLeftChannelsEnd() override; - Result finish() override; QString mainFilePath() override; private: - QString mainFileRelativePath() const; - QString pathWithRelativePath(const QString &path) const; - std::unique_ptr fileWithRelativePath(const QString &path) const; + enum class DialogsMode { + None, + Chats, + Left, + }; - Result writeSavedContacts(const Data::ContactsList &data); - Result writeFrequentContacts(const Data::ContactsList &data); + [[nodiscard]] QString mainFileRelativePath() const; + [[nodiscard]] QString pathWithRelativePath(const QString &path) const; + [[nodiscard]] std::unique_ptr fileWithRelativePath( + const QString &path) const; - Result writeSessions(const Data::SessionsList &data); - Result writeWebSessions(const Data::SessionsList &data); + [[nodiscard]] Result writeSavedContacts(const Data::ContactsList &data); + [[nodiscard]] Result writeFrequentContacts(const Data::ContactsList &data); - Result writeChatsStart( - const Data::DialogsInfo &data, + [[nodiscard]] Result writeSessions(const Data::SessionsList &data); + [[nodiscard]] Result writeWebSessions(const Data::SessionsList &data); + + [[nodiscard]] Result validateDialogsMode(bool isLeftChannel); + [[nodiscard]] Result writeChatsStart( + int count, const QByteArray &listName, const QByteArray &about, const QString &fileName); - Result writeChatStart(const Data::DialogInfo &data); - Result writeChatSlice(const Data::MessagesSlice &data); - Result writeChatEnd(); - Result writeChatsEnd(); + [[nodiscard]] Result writeChatsEnd(); Settings _settings; Environment _environment; @@ -85,8 +84,9 @@ private: std::unique_ptr _userpics; int _dialogsCount = 0; - int _dialogIndex = 0; + int _leftChannelsCount = 0; Data::DialogInfo _dialog; + DialogsMode _dialogsMode = DialogsMode::None; int _messagesCount = 0; std::unique_ptr _chats; diff --git a/Telegram/SourceFiles/export/view/export_view_content.cpp b/Telegram/SourceFiles/export/view/export_view_content.cpp index a217b1ea2..23032e140 100644 --- a/Telegram/SourceFiles/export/view/export_view_content.cpp +++ b/Telegram/SourceFiles/export/view/export_view_content.cpp @@ -61,7 +61,6 @@ Content ContentFromState(const ProcessingState &state) { case Step::Initializing: pushMain(lang(lng_export_state_initializing)); break; - case Step::LeftChannelsList: case Step::DialogsList: pushMain(lang(lng_export_state_chats_list)); break; @@ -83,7 +82,6 @@ Content ContentFromState(const ProcessingState &state) { case Step::OtherData: pushMain(lang(lng_export_option_other)); break; - case Step::LeftChannels: case Step::Dialogs: pushMain(lang(lng_export_state_chats)); push(