diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 8b6ee2b29..cee1f54c8 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -164,7 +164,7 @@ jobs: - name: Opus cache. id: cache-opus - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/opus key: ${{ runner.OS }}-opus-${{ env.CACHE_KEY }} @@ -209,7 +209,7 @@ jobs: - name: FFmpeg cache. id: cache-ffmpeg - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/ffmpeg-cache key: ${{ runner.OS }}-ffmpeg-${{ env.CACHE_KEY }} @@ -363,7 +363,7 @@ jobs: - name: OpenSSL cache. id: cache-openssl - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/openssl-cache key: ${{ runner.OS }}-${{ env.OPENSSL_VER }}-${{ env.CACHE_KEY }} @@ -419,7 +419,7 @@ jobs: - name: Qt 5.12.8 cache. id: cache-qt - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/qt-cache key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qt*_5_12_8/*') }} @@ -468,7 +468,7 @@ jobs: - name: Breakpad cache. id: cache-breakpad - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/breakpad-cache key: ${{ runner.OS }}-breakpad-${{ env.CACHE_KEY }} diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index d96ae3e77..073f0652e 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -140,7 +140,7 @@ jobs: - name: OpenSSL cache. id: cache-openssl - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/openssl_${{ env.OPENSSL_VER }} key: ${{ runner.OS }}-${{ env.OPENSSL_VER }}-${{ env.CACHE_KEY }} @@ -170,7 +170,7 @@ jobs: - name: Opus cache. id: cache-opus - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/opus key: ${{ runner.OS }}-opus-${{ env.CACHE_KEY }} @@ -192,7 +192,7 @@ jobs: - name: Libiconv cache. id: cache-libiconv - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/${{ env.LIBICONV_VER }} key: ${{ runner.OS }}-${{ env.LIBICONV_VER }}-${{ env.CACHE_KEY }} @@ -213,7 +213,7 @@ jobs: - name: FFmpeg cache. id: cache-ffmpeg - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/ffmpeg-cache key: ${{ runner.OS }}-ffmpeg-${{ env.CACHE_KEY }} @@ -369,7 +369,7 @@ jobs: - name: Crashpad cache. id: cache-crashpad - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/crashpad key: ${{ runner.OS }}-crashpad-${{ env.CACHE_KEY }}-${{ hashFiles('**/crashpad.diff') }}-${{ hashFiles('**/mini_chromium.diff') }} @@ -408,7 +408,7 @@ jobs: - name: Qt 5.12.8 cache. id: cache-qt - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/qt-cache key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8/*') }} diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml index b229199d4..44a6e48e1 100644 --- a/.github/workflows/win.yml +++ b/.github/workflows/win.yml @@ -140,7 +140,7 @@ jobs: - name: OpenSSL cache. id: cache-openssl - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/openssl_${{ env.OPENSSL_VER }} key: ${{ runner.OS }}-${{ env.CACHE_KEY }}-${{ env.OPENSSL_VER }} @@ -184,7 +184,7 @@ jobs: - name: OpenAL Soft cache. id: cache-openal - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/openal-soft key: ${{ runner.OS }}-openal-soft-${{ env.CACHE_KEY }} @@ -208,7 +208,7 @@ jobs: - name: Breakpad cache. id: cache-breakpad - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/breakpad key: ${{ runner.OS }}-breakpad-${{ env.CACHE_KEY }}-${{ hashFiles('**/breakpad.diff') }} @@ -257,7 +257,7 @@ jobs: - name: Opus cache. id: cache-opus - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/opus key: ${{ runner.OS }}-opus-${{ env.CACHE_KEY }} @@ -276,7 +276,7 @@ jobs: - name: FFmpeg cache. id: cache-ffmpeg - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/ffmpeg key: ${{ runner.OS }}-ffmpeg-${{ env.CACHE_KEY }}-2-${{ hashFiles('**/build_ffmpeg_win.sh') }} @@ -298,7 +298,7 @@ jobs: - name: Qt 5.12.8 cache. id: cache-qt - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ${{ env.LibrariesPath }}/Qt-5.12.8 key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8/*') }} diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 7a7763048..8cfa55d28 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_menu_back" = "Back"; "lng_menu_night_mode" = "Night Mode"; "lng_menu_add_account" = "Add Account"; +"lng_menu_activate" = "Activate"; "lng_disable_notifications_from_tray" = "Disable notifications"; "lng_enable_notifications_from_tray" = "Enable notifications"; @@ -291,6 +292,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_empty_bio" = "None"; "lng_settings_section_notify" = "Notifications"; +"lng_settings_show_from" = "Show notifications from"; +"lng_settings_notify_all" = "All accounts"; +"lng_settings_notify_all_about" = "Turn this off if you want to receive notifications only from the account you are currently using."; "lng_settings_notify_title" = "Notifications for chats"; "lng_settings_desktop_notify" = "Desktop notifications"; "lng_settings_show_name" = "Show sender's name"; diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index feb557542..915dbf61c 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="2.1.16.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 96a5eefb3..98d5d1d2b 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,1,14,0 - PRODUCTVERSION 2,1,14,0 + FILEVERSION 2,1,16,0 + PRODUCTVERSION 2,1,16,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "2.1.14.0" + VALUE "FileVersion", "2.1.16.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "2.1.14.0" + VALUE "ProductVersion", "2.1.16.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 337a5df9a..a29102114 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,1,14,0 - PRODUCTVERSION 2,1,14,0 + FILEVERSION 2,1,16,0 + PRODUCTVERSION 2,1,16,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -53,10 +53,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "2.1.14.0" + VALUE "FileVersion", "2.1.16.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "2.1.14.0" + VALUE "ProductVersion", "2.1.16.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index f88e2ac3b..b3dd94624 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -368,7 +368,6 @@ public: not_null peer, const std::vector> &users); - rpl::producer sendActions() const { return _sendActions.events(); } diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index 8de1d447a..e3f45eae5 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -781,12 +781,12 @@ bool BackgroundPreviewBox::Start( Ui::show(Box(tr::lng_background_bad_link(tr::now))); return false; } - controller->session().api().requestWallPaper(slug, [=]( + controller->session().api().requestWallPaper(slug, crl::guard(controller, [=]( const Data::WallPaper &result) { Ui::show(Box( controller, result.withUrlParams(params))); - }, [](const RPCError &error) { + }), [](const RPCError &error) { Ui::show(Box(tr::lng_background_bad_link(tr::now))); }); return true; diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index 64a14bc6a..ea364f437 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -171,7 +171,7 @@ private: }; -class ProxyBox : public Ui::BoxContent { +class ProxyBox final : public Ui::BoxContent { public: ProxyBox( QWidget*, @@ -179,12 +179,14 @@ public: Fn callback, Fn shareCallback); -protected: - void prepare() override; - private: using Type = ProxyData::Type; + void prepare() override; + void setInnerFocus() override { + _host->setFocusFast(); + } + void refreshButtons(); ProxyData collectData(); void save(); @@ -693,8 +695,8 @@ void ProxiesBox::applyView(View &&view) { setupButtons(id, i->second.get()); if (_noRows) { _noRows.reset(); - wrap->resizeToWidth(width()); } + wrap->resizeToWidth(width()); } else if (view.host.isEmpty()) { _rows.erase(i); } else { @@ -765,6 +767,31 @@ ProxyBox::ProxyBox( void ProxyBox::prepare() { setTitle(tr::lng_proxy_edit()); + connect(_host.data(), &Ui::InputField::changed, [=] { + Ui::PostponeCall(_host, [=] { + const auto host = _host->getLastText().trimmed(); + static const auto mask = u"^\\d+\\.\\d+\\.\\d+\\.\\d+:(\\d*)$"_q; + const auto match = QRegularExpression(mask).match(host); + if (_host->textCursor().position() == host.size() + && match.hasMatch()) { + const auto port = match.captured(1); + _port->setText(port); + _port->setCursorPosition(port.size()); + _port->setFocus(); + _host->setText(host.mid(0, host.size() - port.size() - 1)); + } + }); + }); + _port.data()->events( + ) | rpl::start_with_next([=](not_null e) { + if (e->type() == QEvent::KeyPress + && (static_cast(e.get())->key() == Qt::Key_Backspace) + && _port->cursorPosition() == 0) { + _host->setCursorPosition(_host->getLastText().size()); + _host->setFocus(); + } + }, _port->lifetime()); + refreshButtons(); setDimensionsToContent(st::boxWideWidth, _content); } diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h index a0f52ba68..76282a341 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h @@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rp_widget.h" #include "base/timer.h" #include "base/object_ptr.h" -#include "data/stickers/data_stickers.h" namespace Ui { class ScrollArea; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index 1d405bcd6..602a6f447 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -2512,7 +2512,11 @@ void StickersListWidget::refreshRecentStickers(bool performResize) { externalLayout, std::move(recentPack)); if (recentIt == _mySets.end()) { - _mySets.push_back(std::move(set)); + const auto where = (_mySets.empty() + || _mySets.begin()->id != Data::Stickers::FavedSetId) + ? _mySets.begin() + : (_mySets.begin() + 1); + _mySets.insert(where, std::move(set)); } else { std::swap(*recentIt, set); takeHeavyData(*recentIt, set); @@ -2537,7 +2541,7 @@ void StickersListWidget::refreshFavedStickers() { const auto set = it->second.get(); const auto externalLayout = false; const auto shortName = QString(); - _mySets.emplace_back( + _mySets.insert(_mySets.begin(), Set{ Data::Stickers::FavedSetId, nullptr, (MTPDstickerSet::Flag::f_official @@ -2546,7 +2550,8 @@ void StickersListWidget::refreshFavedStickers() { shortName, set->count, externalLayout, - PrepareStickers(set->stickers)); + PrepareStickers(set->stickers) + }); _favedStickersMap = base::flat_set> { set->stickers.begin(), set->stickers.end() diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 8f72e7739..edcbb3cd8 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -174,6 +174,7 @@ Application::~Application() { _window = nullptr; _mediaView = nullptr; + _notifications->clearAllFast(); _domain->finish(); Local::finish(); @@ -206,6 +207,7 @@ void Application::run() { refreshGlobalProxy(); // Depends on Global::start(). // Depends on OpenSSL on macOS, so on ThirdParty::start(). + // Depends on notifications settings. _notifications = std::make_unique(); startLocalStorage(); diff --git a/Telegram/SourceFiles/core/application.h b/Telegram/SourceFiles/core/application.h index 0e073493c..83d93a9df 100644 --- a/Telegram/SourceFiles/core/application.h +++ b/Telegram/SourceFiles/core/application.h @@ -347,6 +347,11 @@ private: base::Timer _clearEmojiImageLoaderTimer; const std::unique_ptr _audio; mutable std::unique_ptr _fallbackProductionConfig; + + // Notifications should be destroyed before _audio, after _domain. + // Mutable because is created in run() after OpenSSL is inited. + std::unique_ptr _notifications; + const std::unique_ptr _domain; const std::unique_ptr _exportManager; const std::unique_ptr _calls; @@ -363,10 +368,6 @@ private: Media::Player::FloatDelegate *_defaultFloatPlayerDelegate = nullptr; Media::Player::FloatDelegate *_replacementFloatPlayerDelegate = nullptr; - // Notifications should be destroyed before _audio. - // Mutable because is created in run() after OpenSSL is inited. - std::unique_ptr _notifications; - const QImage _logo; const QImage _logoBlue; const QImage _logoGreen; diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index c88373baf..5e7cb62b5 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -94,7 +94,18 @@ QByteArray Settings::serialize() const { } stream << qint32(_autoDownloadDictionaries.current() ? 1 : 0) - << qint32(_mainMenuAccountsShown.current() ? 1 : 0); + << qint32(_mainMenuAccountsShown.current() ? 1 : 0) + << qint32(_tabbedSelectorSectionEnabled ? 1 : 0) + << qint32(_floatPlayerColumn) + << qint32(_floatPlayerCorner) + << qint32(_thirdSectionInfoEnabled ? 1 : 0) + << qint32(snap( + qRound(_dialogsWidthRatio.current() * 1000000), + 0, + 1000000)) + << qint32(_thirdColumnWidth.current()) + << qint32(_thirdSectionExtendedBy) + << qint32(_notifyFromAll ? 1 : 0); } return result; } @@ -150,6 +161,14 @@ void Settings::addFromSerialized(const QByteArray &serialized) { std::vector dictionariesEnabled; qint32 autoDownloadDictionaries = _autoDownloadDictionaries.current() ? 1 : 0; qint32 mainMenuAccountsShown = _mainMenuAccountsShown.current() ? 1 : 0; + qint32 tabbedSelectorSectionEnabled = 1; + qint32 floatPlayerColumn = static_cast(Window::Column::Second); + qint32 floatPlayerCorner = static_cast(RectPart::TopRight); + qint32 thirdSectionInfoEnabled = 0; + float64 dialogsWidthRatio = _dialogsWidthRatio.current(); + qint32 thirdColumnWidth = _thirdColumnWidth.current(); + qint32 thirdSectionExtendedBy = _thirdSectionExtendedBy; + qint32 notifyFromAll = _notifyFromAll ? 1 : 0; stream >> themesAccentColors; if (!stream.atEnd()) { @@ -211,6 +230,19 @@ void Settings::addFromSerialized(const QByteArray &serialized) { >> autoDownloadDictionaries >> mainMenuAccountsShown; } + if (!stream.atEnd()) { + auto dialogsWidthRatioInt = qint32(); + stream + >> tabbedSelectorSectionEnabled + >> floatPlayerColumn + >> floatPlayerCorner + >> thirdSectionInfoEnabled + >> dialogsWidthRatioInt + >> thirdColumnWidth + >> thirdSectionExtendedBy + >> notifyFromAll; + dialogsWidthRatio = snap(dialogsWidthRatioInt / 1000000., 0., 1.); + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Core::Settings::constructFromSerialized()")); @@ -281,6 +313,28 @@ void Settings::addFromSerialized(const QByteArray &serialized) { _dictionariesEnabled = std::move(dictionariesEnabled); _autoDownloadDictionaries = (autoDownloadDictionaries == 1); _mainMenuAccountsShown = (mainMenuAccountsShown == 1); + _tabbedSelectorSectionEnabled = (tabbedSelectorSectionEnabled == 1); + auto uncheckedColumn = static_cast(floatPlayerColumn); + switch (uncheckedColumn) { + case Window::Column::First: + case Window::Column::Second: + case Window::Column::Third: _floatPlayerColumn = uncheckedColumn; break; + } + auto uncheckedCorner = static_cast(floatPlayerCorner); + switch (uncheckedCorner) { + case RectPart::TopLeft: + case RectPart::TopRight: + case RectPart::BottomLeft: + case RectPart::BottomRight: _floatPlayerCorner = uncheckedCorner; break; + } + _thirdSectionInfoEnabled = thirdSectionInfoEnabled; + _dialogsWidthRatio = dialogsWidthRatio; + _thirdColumnWidth = thirdColumnWidth; + _thirdSectionExtendedBy = thirdSectionExtendedBy; + if (_thirdSectionInfoEnabled) { + _tabbedSelectorSectionEnabled = false; + } + _notifyFromAll = (notifyFromAll == 1); } bool Settings::chatWide() const { @@ -412,6 +466,7 @@ void Settings::resetOnLastLogout() { _thirdSectionExtendedBy = -1; // per-window _dialogsWidthRatio = DefaultDialogsWidthRatio(); // per-window _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w + _notifyFromAll = true; _tabbedReplacedWithInfo = false; // per-window } diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index 907e37fd5..cedbe6a94 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -401,6 +401,12 @@ public: void setThirdColumnWidth(int width); [[nodiscard]] int thirdColumnWidth() const; [[nodiscard]] rpl::producer thirdColumnWidthChanges() const; + void setNotifyFromAll(bool value) { + _notifyFromAll = value; + } + [[nodiscard]] bool notifyFromAll() const { + return _notifyFromAll; + } [[nodiscard]] static bool ThirdColumnByDefault(); [[nodiscard]] float64 DefaultDialogsWidthRatio(); @@ -467,6 +473,7 @@ private: int _thirdSectionExtendedBy = -1; // per-window rpl::variable _dialogsWidthRatio; // per-window rpl::variable _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w + bool _notifyFromAll = true; bool _tabbedReplacedWithInfo = false; // per-window rpl::event_stream _tabbedReplacedWithInfoValue; // per-window diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 607d65b18..249b6c847 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -304,16 +304,13 @@ bool ResolveUsername( } const auto clickFromMessageId = context.value(); const auto searchParam = params.value(qsl("query")); - if (const auto controller = App::wnd()->sessionController()) { - controller->content()->openPeerByName( - domain, - post, - startToken, - clickFromMessageId, - searchParam); - return true; - } - return false; + controller->content()->openPeerByName( + domain, + post, + startToken, + clickFromMessageId, + searchParam); + return true; } bool ResolvePrivatePost( @@ -331,12 +328,12 @@ bool ResolvePrivatePost( if (!channelId || !IsServerMsgId(msgId)) { return false; } - const auto done = [=](not_null peer) { - App::wnd()->sessionController()->showPeerHistory( + const auto done = crl::guard(controller, [=](not_null peer) { + controller->showPeerHistory( peer->id, Window::SectionShow::Way::Forward, msgId); - }; + }); const auto fail = [=] { Ui::show(Box(tr::lng_error_post_link_invalid(tr::now))); }; @@ -400,7 +397,7 @@ bool HandleUnknown( return false; } const auto request = match->captured(1); - const auto callback = [=](const MTPDhelp_deepLinkInfo &result) { + const auto callback = crl::guard(controller, [=](const MTPDhelp_deepLinkInfo &result) { const auto text = TextWithEntities{ qs(result.vmessage()), Api::EntitiesFromMTP( @@ -420,7 +417,7 @@ bool HandleUnknown( } else { Ui::show(Box(text)); } - }; + }); controller->session().api().requestDeepLinkInfo(request, callback); return true; } diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 0fc34e9b5..07f94556f 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -23,7 +23,7 @@ constexpr auto AppId = "{C4A4AE8F-B9F7-4CC7-8A6C-BF7EEE87ACA5}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Kotatogram Desktop"_cs; constexpr auto AppFile = "Kotatogram"_cs; -constexpr auto AppVersion = 2001014; -constexpr auto AppVersionStr = "2.1.14"; +constexpr auto AppVersion = 2001016; +constexpr auto AppVersionStr = "2.1.16"; constexpr auto AppBetaVersion = true; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/SourceFiles/data/data_chat_filters.cpp b/Telegram/SourceFiles/data/data_chat_filters.cpp index 56d6c266b..6c1abbbea 100644 --- a/Telegram/SourceFiles/data/data_chat_filters.cpp +++ b/Telegram/SourceFiles/data/data_chat_filters.cpp @@ -226,7 +226,7 @@ bool ChatFilter::contains(not_null history) const { } ChatFilters::ChatFilters(not_null owner) : _owner(owner) { - load(); + crl::on_main(&owner->session(), [=] { load(); }); } ChatFilters::~ChatFilters() = default; @@ -242,6 +242,16 @@ not_null ChatFilters::chatsList(FilterId filterId) { return pointer.get(); } +void ChatFilters::setPreloaded(const QVector &result) { + _loadRequestId = -1; + received(result); + crl::on_main(&_owner->session(), [=] { + if (_loadRequestId == -1) { + _loadRequestId = 0; + } + }); +} + void ChatFilters::load() { load(false); } @@ -254,40 +264,44 @@ void ChatFilters::load(bool force) { api.request(_loadRequestId).cancel(); _loadRequestId = api.request(MTPmessages_GetDialogFilters( )).done([=](const MTPVector &result) { - auto position = 0; - auto changed = false; - for (const auto &filter : result.v) { - auto parsed = ChatFilter::FromTL(filter, _owner); - const auto b = begin(_list) + position, e = end(_list); - const auto i = ranges::find(b, e, parsed.id(), &ChatFilter::id); - if (i == e) { - applyInsert(std::move(parsed), position); - changed = true; - } else if (i == b) { - if (applyChange(*b, std::move(parsed))) { - changed = true; - } - } else { - std::swap(*i, *b); - applyChange(*b, std::move(parsed)); - changed = true; - } - ++position; - } - while (position < _list.size()) { - applyRemove(position); - changed = true; - } - if (changed || !_loaded) { - _loaded = true; - _listChanged.fire({}); - } + received(result.v); _loadRequestId = 0; }).fail([=](const RPCError &error) { _loadRequestId = 0; }).send(); } +void ChatFilters::received(const QVector &list) { + auto position = 0; + auto changed = false; + for (const auto &filter : list) { + auto parsed = ChatFilter::FromTL(filter, _owner); + const auto b = begin(_list) + position, e = end(_list); + const auto i = ranges::find(b, e, parsed.id(), &ChatFilter::id); + if (i == e) { + applyInsert(std::move(parsed), position); + changed = true; + } else if (i == b) { + if (applyChange(*b, std::move(parsed))) { + changed = true; + } + } else { + std::swap(*i, *b); + applyChange(*b, std::move(parsed)); + changed = true; + } + ++position; + } + while (position < _list.size()) { + applyRemove(position); + changed = true; + } + if (changed || !_loaded) { + _loaded = true; + _listChanged.fire({}); + } +} + void ChatFilters::apply(const MTPUpdate &update) { update.match([&](const MTPDupdateDialogFilter &data) { if (const auto filter = data.vfilter()) { diff --git a/Telegram/SourceFiles/data/data_chat_filters.h b/Telegram/SourceFiles/data/data_chat_filters.h index 5723c8985..a6ecf18b0 100644 --- a/Telegram/SourceFiles/data/data_chat_filters.h +++ b/Telegram/SourceFiles/data/data_chat_filters.h @@ -99,6 +99,8 @@ public: explicit ChatFilters(not_null owner); ~ChatFilters(); + void setPreloaded(const QVector &result); + void load(); void apply(const MTPUpdate &update); void set(ChatFilter filter); @@ -129,6 +131,7 @@ public: private: void load(bool force); + void received(const QVector &list); bool applyOrder(const QVector &order); bool applyChange(ChatFilter &filter, ChatFilter &&updated); void applyInsert(ChatFilter filter, int position); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index a9c32d861..2dfcc24a9 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -462,9 +462,6 @@ not_null Session::processUser(const MTPUser &data) { : QString()) : result->nameOrPhone; - if (!minimal && data.is_self() && uname != result->username) { - CrashReports::SetAnnotation("Username", uname); - } result->setName(fname, lname, pname, uname); if (const auto photo = data.vphoto()) { result->setPhoto(*photo); @@ -2559,6 +2556,7 @@ not_null Session::processWebpage(const MTPWebPage &data) { const auto result = webpage(data.c_webPageEmpty().vid().v); if (result->pendingTill > 0) { result->pendingTill = -1; // failed + notifyWebPageUpdateDelayed(result); } return result; } break; diff --git a/Telegram/SourceFiles/data/stickers/data_stickers.cpp b/Telegram/SourceFiles/data/stickers/data_stickers.cpp index 08ef4297c..c60c3db5c 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers.cpp +++ b/Telegram/SourceFiles/data/stickers/data_stickers.cpp @@ -892,7 +892,7 @@ void Stickers::gifsReceived(const QVector &items, int32 hash) { const auto document = owner().processDocument(item); if (!document->isGifv()) { LOG(("API Error: " - "bad document returned in HistoryWidget::savedGifsGot!")); + "bad document returned in Stickers::gifsReceived!")); continue; } diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 563ab4862..77572ace1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -3056,7 +3056,7 @@ void InnerWidget::setupShortcuts() { }) | rpl::start_with_next([=](not_null request) { using Command = Shortcuts::Command; - if (_controller->content()->selectingPeer()) { + if (_controller->selectingPeer()) { return; } const auto row = _controller->activeChatEntryCurrent(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 43d781b96..c1da80a65 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -212,7 +212,7 @@ Widget::Widget( }); _inner->chosenRow( ) | rpl::start_with_next([=](const ChosenRow &row) { - const auto openSearchResult = !controller->content()->selectingPeer() + const auto openSearchResult = !controller->selectingPeer() && row.filteredRow; if (const auto history = row.key.history()) { controller->content()->choosePeer( @@ -701,7 +701,7 @@ void Widget::escape() { } else if (controller()->activeChatsFilterCurrent() != cDefaultFilterId()) { controller()->setActiveChatsFilter(cDefaultFilterId()); } - } else if (!_searchInChat && !controller()->content()->selectingPeer()) { + } else if (!_searchInChat && !controller()->selectingPeer()) { if (controller()->activeChatEntryCurrent().key) { emit cancelled(); } @@ -1267,7 +1267,7 @@ void Widget::peopleFailed(const RPCError &error, mtpRequestId requestId) { void Widget::dragEnterEvent(QDragEnterEvent *e) { using namespace Storage; - if (controller()->content()->selectingPeer()) { + if (controller()->selectingPeer()) { return; } @@ -1616,7 +1616,7 @@ void Widget::updateControlsGeometry() { } void Widget::updateForwardBar() { - auto selecting = controller()->content()->selectingPeer(); + auto selecting = controller()->selectingPeer(); auto oneColumnSelecting = (Adaptive::OneColumn() && selecting); if (!oneColumnSelecting == !_forwardCancel) { return; @@ -1759,7 +1759,7 @@ bool Widget::onCancelSearch() { void Widget::onCancelSearchInChat() { cancelSearchRequest(); if (_searchInChat) { - if (Adaptive::OneColumn() && !controller()->content()->selectingPeer()) { + if (Adaptive::OneColumn() && !controller()->selectingPeer()) { if (const auto peer = _searchInChat.peer()) { Ui::showPeerHistory(peer, ShowAtUnreadMsgId); //} else if (const auto feed = _searchInChat.feed()) { // #feed @@ -1774,7 +1774,7 @@ void Widget::onCancelSearchInChat() { _filter->clear(); _filter->updatePlaceholder(); applyFilterUpdate(); - if (!Adaptive::OneColumn() && !controller()->content()->selectingPeer()) { + if (!Adaptive::OneColumn() && !controller()->selectingPeer()) { emit cancelled(); } } @@ -1786,6 +1786,8 @@ void Widget::onDialogMoved(int movedFrom, int movedTo) { } } -Widget::~Widget() = default; +Widget::~Widget() { + cancelSearchRequest(); +} } // namespace Dialogs diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 0280af7f4..2198b484a 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -46,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_scheduled_messages.h" #include "data/data_file_origin.h" #include "data/data_histories.h" +#include "data/stickers/data_stickers.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_message.h" @@ -260,6 +261,7 @@ HistoryWidget::HistoryWidget( QWidget *parent, not_null controller) : Window::AbstractSectionWidget(parent, controller) +, _api(&controller->session().mtp()) , _updateEditTimeLeftDisplay([=] { updateField(); }) , _fieldBarCancel(this, st::historyReplyCancel) , _previewTimer([=] { requestPreview(); }) @@ -1219,14 +1221,14 @@ void HistoryWidget::updateInlineBotQuery() { if (_inlineBotUsername != query.username) { _inlineBotUsername = query.username; if (_inlineBotResolveRequestId) { - session().api().request(_inlineBotResolveRequestId).cancel(); + _api.request(_inlineBotResolveRequestId).cancel(); _inlineBotResolveRequestId = 0; } if (query.lookingUpBot) { _inlineBot = nullptr; _inlineLookingUpBot = true; const auto username = _inlineBotUsername; - _inlineBotResolveRequestId = session().api().request(MTPcontacts_ResolveUsername( + _inlineBotResolveRequestId = _api.request(MTPcontacts_ResolveUsername( MTP_string(username) )).done([=](const MTPcontacts_ResolvedPeer &result) { inlineBotResolveDone(result); @@ -1477,7 +1479,7 @@ void HistoryWidget::cancelSendAction( SendAction::Type type) { const auto i = _sendActionRequests.find({ history, type }); if (i != _sendActionRequests.end()) { - session().api().request(i->second).cancel(); + _api.request(i->second).cancel(); _sendActionRequests.erase(i); } } @@ -1518,7 +1520,7 @@ void HistoryWidget::updateSendAction( case Type::ChooseContact: action = MTP_sendMessageChooseContactAction(); break; case Type::PlayGame: action = MTP_sendMessageGamePlayAction(); break; } - const auto requestId = session().api().request(MTPmessages_SetTyping( + const auto requestId = _api.request(MTPmessages_SetTyping( peer->input, action )).done([=](const MTPBool &result, mtpRequestId requestId) { @@ -3155,6 +3157,7 @@ void HistoryWidget::saveEditMsg() { sendFlags |= MTPmessages_EditMessage::Flag::f_entities; } + const auto weak = Ui::MakeWeak(this); const auto history = _history; _saveEditMsgRequestId = history->session().api().request( MTPmessages_EditMessage( @@ -3166,55 +3169,60 @@ void HistoryWidget::saveEditMsg() { MTPReplyMarkup(), sentEntities, MTP_int(0) - )).done([=](const MTPUpdates &result, mtpRequestId requestId) { - saveEditMsgDone(history, result, requestId); - }).fail([=](const RPCError &error, mtpRequestId requestId) { - saveEditMsgFail(history, error, requestId); + )).done([history, weak](const MTPUpdates &result, mtpRequestId requestId) { + SaveEditMsgDone(history, result, requestId); + if (const auto strong = weak.data()) { + if (requestId == strong->_saveEditMsgRequestId) { + strong->_saveEditMsgRequestId = 0; + strong->cancelEdit(); + } + } + }).fail([history, weak](const RPCError &error, mtpRequestId requestId) { + SaveEditMsgFail(history, error, requestId); + if (const auto strong = weak.data()) { + if (requestId == strong->_saveEditMsgRequestId) { + strong->_saveEditMsgRequestId = 0; + } + const auto &err = error.type(); + if (err == qstr("MESSAGE_ID_INVALID") + || err == qstr("CHAT_ADMIN_REQUIRED") + || err == qstr("MESSAGE_EDIT_TIME_EXPIRED")) { + Ui::show(Box(tr::lng_edit_error(tr::now))); + } else if (err == qstr("MESSAGE_NOT_MODIFIED")) { + strong->cancelEdit(); + } else if (err == qstr("MESSAGE_EMPTY")) { + strong->_field->selectAll(); + strong->_field->setFocus(); + } else { + Ui::show(Box(tr::lng_edit_error(tr::now))); + } + strong->update(); + } }).send(); } -void HistoryWidget::saveEditMsgDone( +void HistoryWidget::SaveEditMsgDone( not_null history, const MTPUpdates &updates, mtpRequestId requestId) { - session().api().applyUpdates(updates); - if (requestId == _saveEditMsgRequestId) { - _saveEditMsgRequestId = 0; - cancelEdit(); - } + history->session().api().applyUpdates(updates); if (auto editDraft = history->editDraft()) { if (editDraft->saveRequestId == requestId) { history->clearEditDraft(); - session().local().writeDrafts(history); + history->session().local().writeDrafts(history); } } } -void HistoryWidget::saveEditMsgFail( +void HistoryWidget::SaveEditMsgFail( not_null history, const RPCError &error, mtpRequestId requestId) { - if (requestId == _saveEditMsgRequestId) { - _saveEditMsgRequestId = 0; - } if (auto editDraft = history->editDraft()) { if (editDraft->saveRequestId == requestId) { editDraft->saveRequestId = 0; } } - - const auto &err = error.type(); - if (err == qstr("MESSAGE_ID_INVALID") || err == qstr("CHAT_ADMIN_REQUIRED") || err == qstr("MESSAGE_EDIT_TIME_EXPIRED")) { - Ui::show(Box(tr::lng_edit_error(tr::now))); - } else if (err == qstr("MESSAGE_NOT_MODIFIED")) { - cancelEdit(); - } else if (err == qstr("MESSAGE_EMPTY")) { - _field->selectAll(); - _field->setFocus(); - } else { - Ui::show(Box(tr::lng_edit_error(tr::now))); - } - update(); } void HistoryWidget::hideSelectorControlsAnimated() { @@ -3775,6 +3783,7 @@ void HistoryWidget::app_sendBotCallback( using ButtonType = HistoryMessageMarkupButton::Type; BotCallbackInfo info = { + &session(), bot, msg->fullId(), row, @@ -3789,15 +3798,24 @@ void HistoryWidget::app_sendBotCallback( flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data; sendData = button->data; } + const auto weak = Ui::MakeWeak(this); button->requestId = session().api().request(MTPmessages_GetBotCallbackAnswer( MTP_flags(flags), _peer->input, MTP_int(msg->id), MTP_bytes(sendData) - )).done([=](const MTPmessages_BotCallbackAnswer &result, mtpRequestId requestId) { - botCallbackDone(info, result, requestId); - }).fail([=](const RPCError &error, mtpRequestId requestId) { - botCallbackFail(info, error, requestId); + )).done([info, weak](const MTPmessages_BotCallbackAnswer &result, mtpRequestId requestId) { + BotCallbackDone(info, result, requestId); + result.match([&](const MTPDmessages_botCallbackAnswer &data) { + const auto item = info.session->data().message(info.msgId); + if (!data.vmessage() && data.vurl() && info.game && item) { + if (const auto strong = weak.data()) { + strong->updateSendAction(item->history(), SendAction::Type::PlayGame); + } + } + }); + }).fail([info](const RPCError &error, mtpRequestId requestId) { + BotCallbackFail(info, error, requestId); }).send(); session().data().requestItemRepaint(msg); @@ -3810,19 +3828,20 @@ void HistoryWidget::app_sendBotCallback( } } -void HistoryWidget::botCallbackDone( +void HistoryWidget::BotCallbackDone( BotCallbackInfo info, const MTPmessages_BotCallbackAnswer &answer, mtpRequestId req) { - const auto item = session().data().message(info.msgId); + const auto session = info.session; + const auto item = session->data().message(info.msgId); const auto button = HistoryMessageMarkupButton::Get( - &session().data(), + &session->data(), info.msgId, info.row, info.col); if (button && button->requestId == req) { button->requestId = 0; - session().data().requestItemRepaint(item); + session->data().requestItemRepaint(item); } answer.match([&](const MTPDmessages_botCallbackAnswer &data) { if (const auto message = data.vmessage()) { @@ -3834,11 +3853,8 @@ void HistoryWidget::botCallbackDone( } else if (const auto url = data.vurl()) { auto link = qs(*url); if (info.game) { - link = AppendShareGameScoreUrl(&session(), link, info.msgId); + link = AppendShareGameScoreUrl(session, link, info.msgId); BotGameUrlClickHandler(info.bot, link).onClick({}); - if (item) { - updateSendAction(item->history(), SendAction::Type::PlayGame); - } } else { UrlClickHandler::Open(link); } @@ -3846,21 +3862,21 @@ void HistoryWidget::botCallbackDone( }); } -bool HistoryWidget::botCallbackFail( +void HistoryWidget::BotCallbackFail( BotCallbackInfo info, const RPCError &error, mtpRequestId req) { // show error? + const auto owner = &info.session->data(); const auto button = HistoryMessageMarkupButton::Get( - &session().data(), + owner, info.msgId, info.row, info.col); if (button && button->requestId == req) { button->requestId = 0; - session().data().requestItemRepaint(session().data().message(info.msgId)); + owner->requestItemRepaint(owner->message(info.msgId)); } - return true; } bool HistoryWidget::insertBotCommand(const QString &cmd) { @@ -5037,12 +5053,11 @@ void HistoryWidget::updateControlsGeometry() { } void HistoryWidget::itemRemoved(not_null item) { - if (item == _replyEditMsg) { - if (_editMsgId) { - cancelEdit(); - } else { - cancelReply(); - } + if (item == _replyEditMsg && _editMsgId) { + cancelEdit(); + } + if (item == _replyEditMsg && _replyToId) { + cancelReply(); } while (item == _replyReturn) { calcNextReplyReturn(); @@ -6129,7 +6144,13 @@ void HistoryWidget::pinMessage(FullMsgId itemId) { } void HistoryWidget::unpinMessage(FullMsgId itemId) { - const auto peer = _peer; + if (!_peer) { + return; + } + UnpinMessage(_peer); +} + +void HistoryWidget::UnpinMessage(not_null peer) { if (!peer) { return; } @@ -6291,7 +6312,7 @@ void HistoryWidget::cancelFieldAreaState() { } void HistoryWidget::previewCancel() { - session().api().request(base::take(_previewRequest)).cancel(); + _api.request(base::take(_previewRequest)).cancel(); _previewData = nullptr; _previewLinks.clear(); updatePreview(); @@ -6307,7 +6328,7 @@ void HistoryWidget::checkPreview() { } const auto links = _parsedLinks.join(' '); if (_previewLinks != links) { - session().api().request(base::take(_previewRequest)).cancel(); + _api.request(base::take(_previewRequest)).cancel(); _previewLinks = links; if (_previewLinks.isEmpty()) { if (_previewData && _previewData->pendingTill >= 0) { @@ -6316,7 +6337,7 @@ void HistoryWidget::checkPreview() { } else { const auto i = _previewCache.constFind(links); if (i == _previewCache.cend()) { - _previewRequest = session().api().request(MTPmessages_GetWebPagePreview( + _previewRequest = _api.request(MTPmessages_GetWebPagePreview( MTP_flags(0), MTP_string(links), MTPVector() @@ -6340,7 +6361,7 @@ void HistoryWidget::requestPreview() { return; } const auto links = _previewLinks; - _previewRequest = session().api().request(MTPmessages_GetWebPagePreview( + _previewRequest = _api.request(MTPmessages_GetWebPagePreview( MTP_flags(0), MTP_string(links), MTPVector() diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index dd26b52c0..4d0c51c40 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/input_fields.h" #include "ui/effects/animations.h" #include "ui/rp_widget.h" +#include "mtproto/sender.h" #include "base/flags.h" #include "base/timer.h" @@ -339,6 +340,7 @@ private: using TabbedSelector = ChatHelpers::TabbedSelector; using DragState = Storage::MimeDataState; struct BotCallbackInfo { + not_null session; UserData *bot; FullMsgId msgId; int row, col; @@ -571,8 +573,8 @@ private: void createUnreadBarAndResize(); void saveEditMsg(); - void saveEditMsgDone(not_null history, const MTPUpdates &updates, mtpRequestId requestId); - void saveEditMsgFail(not_null history, const RPCError &error, mtpRequestId requestId); + static void SaveEditMsgDone(not_null history, const MTPUpdates &updates, mtpRequestId requestId); + static void SaveEditMsgFail(not_null history, const RPCError &error, mtpRequestId requestId); void checkPreview(); void requestPreview(); @@ -582,8 +584,10 @@ private: void addMessagesToFront(PeerData *peer, const QVector &messages); void addMessagesToBack(PeerData *peer, const QVector &messages); - void botCallbackDone(BotCallbackInfo info, const MTPmessages_BotCallbackAnswer &answer, mtpRequestId req); - bool botCallbackFail(BotCallbackInfo info, const RPCError &error, mtpRequestId req); + static void UnpinMessage(not_null peer); + + static void BotCallbackDone(BotCallbackInfo info, const MTPmessages_BotCallbackAnswer &answer, mtpRequestId req); + static void BotCallbackFail(BotCallbackInfo info, const RPCError &error, mtpRequestId req); void updateHistoryGeometry(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 }); void updateListSize(); @@ -648,6 +652,7 @@ private: void setupScheduledToggle(); void refreshScheduledToggle(); + MTP::Sender _api; MsgId _replyToId = 0; Ui::Text::String _replyToName; int _replyToNameVersion = 0; diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index 6afdb3670..f8f526c47 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -27,6 +27,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/slide_animation.h" #include "data/data_user.h" #include "data/data_auto_download.h" +#include "data/data_session.h" +#include "data/data_chat_filters.h" #include "window/window_controller.h" #include "window/themes/window_theme.h" #include "app.h" @@ -160,6 +162,18 @@ void Step::finish(const MTPUser &user, QImage &&photo) { } } + api().request(MTPmessages_GetDialogFilters( + )).done([=](const MTPVector &result) { + createSession(user, photo, result.v); + }).fail([=](const RPCError &error) { + createSession(user, photo, QVector()); + }).send(); +} + +void Step::createSession( + const MTPUser &user, + QImage photo, + const QVector &filters) { // Save the default language if we've suggested some other and user ignored it. const auto currentId = Lang::Current().id(); const auto defaultId = Lang::DefaultLanguageId(); @@ -168,12 +182,20 @@ void Step::finish(const MTPUser &user, QImage &&photo) { Lang::Current().switchToId(Lang::DefaultLanguage()); Local::writeLangPack(); } + + auto settings = std::make_unique(); + settings->setDialogsFiltersEnabled(!filters.isEmpty()); + const auto account = _account; - account->createSession(user); + account->createSession(user, std::move(settings)); // "this" is already deleted here by creating the main widget. account->local().writeMtpData(); auto &session = account->session(); + session.data().chatsFilters().setPreloaded(filters); + if (!filters.isEmpty()) { + session.saveSettingsDelayed(); + } if (!photo.isNull()) { session.api().uploadPeerPhoto(session.user(), std::move(photo)); } diff --git a/Telegram/SourceFiles/intro/intro_step.h b/Telegram/SourceFiles/intro/intro_step.h index bc9548800..b98349a44 100644 --- a/Telegram/SourceFiles/intro/intro_step.h +++ b/Telegram/SourceFiles/intro/intro_step.h @@ -106,6 +106,10 @@ protected: return _data; } void finish(const MTPUser &user, QImage &&photo = QImage()); + void createSession( + const MTPUser &user, + QImage photo, + const QVector &filters); void goBack(); diff --git a/Telegram/SourceFiles/kotato/settings_menu.cpp b/Telegram/SourceFiles/kotato/settings_menu.cpp index 365b74583..935fa86f5 100644 --- a/Telegram/SourceFiles/kotato/settings_menu.cpp +++ b/Telegram/SourceFiles/kotato/settings_menu.cpp @@ -426,7 +426,7 @@ void SetupKotatoSystem( AddSkip(container); AddSubsectionTitle(container, tr::ktg_settings_system()); -#if defined Q_OS_WIN || defined Q_OS_MAC +#if defined Q_OS_WIN || defined Q_OS_MAC || QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) || defined DESKTOP_APP_QT_PATCHED const auto useNativeDecorationsToggled = Ui::CreateChild>( container.get()); AddButton( @@ -453,7 +453,7 @@ void SetupKotatoSystem( confirmed, cancelled)); }, container->lifetime()); -#endif // Q_OS_WIN || Q_OS_MAC +#endif // Q_OS_WIN || Q_OS_MAC || Qt >= 5.15 || DESKTOP_APP_QT_PATCHED AddButton( container, diff --git a/Telegram/SourceFiles/main/main_account.cpp b/Telegram/SourceFiles/main/main_account.cpp index c2e9958d4..a4b2eb8fb 100644 --- a/Telegram/SourceFiles/main/main_account.cpp +++ b/Telegram/SourceFiles/main/main_account.cpp @@ -131,8 +131,14 @@ uint64 Account::willHaveSessionUniqueId(MTP::Config *config) const { | (config && config->isTestMode() ? 0x0100'0000'0000'0000ULL : 0ULL); } -void Account::createSession(const MTPUser &user) { - createSession(user, QByteArray(), 0, std::make_unique()); +void Account::createSession( + const MTPUser &user, + std::unique_ptr settings) { + createSession( + user, + QByteArray(), + 0, + settings ? std::move(settings) : std::make_unique()); } void Account::createSession( diff --git a/Telegram/SourceFiles/main/main_account.h b/Telegram/SourceFiles/main/main_account.h index d63eab11a..8c14b1793 100644 --- a/Telegram/SourceFiles/main/main_account.h +++ b/Telegram/SourceFiles/main/main_account.h @@ -49,7 +49,9 @@ public: void start(std::unique_ptr config); [[nodiscard]] uint64 willHaveSessionUniqueId(MTP::Config *config) const; - void createSession(const MTPUser &user); + void createSession( + const MTPUser &user, + std::unique_ptr settings = nullptr); void createSession( UserId id, QByteArray serialized, diff --git a/Telegram/SourceFiles/main/main_app_config.cpp b/Telegram/SourceFiles/main/main_app_config.cpp index 4f86f2bcf..077c97e0a 100644 --- a/Telegram/SourceFiles/main/main_app_config.cpp +++ b/Telegram/SourceFiles/main/main_app_config.cpp @@ -24,6 +24,13 @@ AppConfig::AppConfig(not_null account) : _account(account) { _api.emplace(instance); refresh(); }, _lifetime); + + account->sessionChanges( + ) | rpl::filter([=](Session *session) { + return (session != nullptr); + }) | rpl::start_with_next([=] { + refresh(); + }, _lifetime); } void AppConfig::refresh() { diff --git a/Telegram/SourceFiles/main/main_domain.cpp b/Telegram/SourceFiles/main/main_domain.cpp index 6b8fd61cc..d9525fb73 100644 --- a/Telegram/SourceFiles/main/main_domain.cpp +++ b/Telegram/SourceFiles/main/main_domain.cpp @@ -9,15 +9,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "core/shortcuts.h" +#include "core/crash_reports.h" #include "main/main_account.h" #include "main/main_session.h" #include "data/data_session.h" +#include "data/data_changes.h" +#include "data/data_user.h" #include "mtproto/mtproto_config.h" #include "mtproto/mtproto_dc_options.h" #include "storage/storage_domain.h" #include "storage/storage_account.h" #include "storage/localstorage.h" #include "export/export_settings.h" +#include "window/notifications_manager.h" #include "facades.h" namespace Main { @@ -28,6 +32,22 @@ Domain::Domain(const QString &dataName) _active.changes( ) | rpl::take(1) | rpl::start_with_next([] { Local::rewriteSettingsIfNeeded(); + Core::App().notifications().createManager(); + }, _lifetime); + + _active.changes( + ) | rpl::map([](Main::Account *account) { + return account ? account->sessionValue() : rpl::never(); + }) | rpl::flatten_latest( + ) | rpl::map([](Main::Session *session) { + return session + ? session->changes().peerFlagsValue( + session->user(), + Data::PeerUpdate::Flag::Username) + : rpl::never(); + }) | rpl::flatten_latest( + ) | rpl::start_with_next([](const Data::PeerUpdate &update) { + CrashReports::SetAnnotation("Username", update.peer->userName()); }, _lifetime); } @@ -253,6 +273,20 @@ not_null Domain::add(MTP::Environment environment) { return account; } +void Domain::addActivated(MTP::Environment environment) { + if (accounts().size() < Main::Domain::kMaxAccounts) { + activate(add(environment)); + } else { + for (auto &[index, account] : accounts()) { + if (!account->sessionExists() + && account->mtp().environment() == environment) { + activate(account.get()); + break; + } + } + } +} + void Domain::watchSession(not_null account) { account->sessionValue( ) | rpl::filter([=](Session *session) { diff --git a/Telegram/SourceFiles/main/main_domain.h b/Telegram/SourceFiles/main/main_domain.h index 6e9da8386..4adadf21e 100644 --- a/Telegram/SourceFiles/main/main_domain.h +++ b/Telegram/SourceFiles/main/main_domain.h @@ -64,6 +64,7 @@ public: [[nodiscard]] not_null add(MTP::Environment environment); void activate(not_null account); + void addActivated(MTP::Environment environment); // Interface for Storage::Domain. void accountAddedInStorage(AccountWithIndex accountWithIndex); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 8bfccf434..60f4e9bd0 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -230,6 +230,7 @@ MainWidget::MainWidget( not_null controller) : RpWidget(parent) , _controller(controller) +, _api(&controller->session().mtp()) , _dialogsWidth(st::columnMinimalWidthLeft) , _thirdColumnWidth(st::columnMinimalWidthThird) , _sideShadow(this) @@ -370,8 +371,6 @@ MainWidget::MainWidget( cSetOtherOnline(0); _history->start(); - - Core::App().checkStartUrl(); } MainWidget::~MainWidget() = default; @@ -621,6 +620,8 @@ void MainWidget::clearHider(not_null instance) { return; } _hider.release(); + controller()->setSelectingPeer(false); + if (Adaptive::OneColumn()) { if (_mainSection || (_history->peer() && _history->peer()->id)) { auto animationParams = ([=] { @@ -646,6 +647,8 @@ void MainWidget::hiderLayer(base::unique_qptr hider) { } _hider = std::move(hider); + controller()->setSelectingPeer(true); + _hider->setParent(this); _hider->hidden( @@ -1274,7 +1277,6 @@ void MainWidget::scheduleViewIncrement(HistoryItem *item) { } void MainWidget::viewsIncrement() { - const auto api = &session().api(); for (auto i = _viewsToIncrement.begin(); i != _viewsToIncrement.cend();) { if (_viewsIncrementRequests.contains(i->first)) { ++i; @@ -1286,7 +1288,7 @@ void MainWidget::viewsIncrement() { for (const auto msgId : i->second) { ids.push_back(MTP_int(msgId)); } - const auto requestId = api->request(MTPmessages_GetMessagesViews( + const auto requestId = _api.request(MTPmessages_GetMessagesViews( i->first->input, MTP_vector(ids), MTP_bool(true) @@ -1417,6 +1419,7 @@ void MainWidget::ui_showPeerHistory( if (_hider) { _hider->startHide(); _hider.release(); + controller()->setSelectingPeer(false); } auto animatedShow = [&] { @@ -2648,7 +2651,7 @@ void MainWidget::openPeerByName( }); } } else { - session().api().request(MTPcontacts_ResolveUsername( + _api.request(MTPcontacts_ResolveUsername( MTP_string(username) )).done([=](const MTPcontacts_ResolvedPeer &result) { usernameResolveDone(result, msgId, startToken); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 4a1e5fc67..6dbe28af4 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rp_widget.h" #include "ui/effects/animations.h" #include "media/player/media_player_float.h" +#include "mtproto/sender.h" #include "data/data_pts_waiter.h" class RPCError; @@ -355,6 +356,7 @@ private: void handleHistoryBack(); const not_null _controller; + MTP::Sender _api; Ui::Animations::Simple _a_show; bool _showBack = false; diff --git a/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp b/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp index 135453ba5..d21a1fbdc 100644 --- a/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp +++ b/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp @@ -39,7 +39,7 @@ VolumeController::VolumeController( Core::App().settings().setRememberedSongVolume(volume); } applyVolumeChange(volume); - controller->session().saveSettingsDelayed(); + Core::App().saveSettingsDelayed(); }); Core::App().settings().songVolumeChanges( ) | rpl::start_with_next([=](float64 volume) { diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index 0bc26ebf4..f7fa56b8b 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -132,6 +132,7 @@ Widget::Widget(QWidget *parent, not_null session) ? 0. : Core::App().settings().rememberedSongVolume(); Core::App().settings().setSongVolume(volume); + Core::App().saveSettingsDelayed(); mixer()->setSongVolume(volume); }); Core::App().settings().songVolumeChanges( diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 00d560807..2911c5ca3 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -2655,10 +2655,8 @@ void OverlayWidget::playbackControlsSeekFinished(crl::time position) { void OverlayWidget::playbackControlsVolumeChanged(float64 volume) { Core::App().settings().setVideoVolume(volume); + Core::App().saveSettingsDelayed(); updateMixerVideoVolume(); - if (_document) { - _document->session().saveSettingsDelayed(); - } } float64 OverlayWidget::playbackControlsCurrentVolume() { diff --git a/Telegram/SourceFiles/platform/linux/linux_libs.cpp b/Telegram/SourceFiles/platform/linux/linux_libs.cpp index e0706f293..0d6a5bf1f 100644 --- a/Telegram/SourceFiles/platform/linux/linux_libs.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_libs.cpp @@ -253,11 +253,10 @@ void start() { // change the icon theme only if it isn't already set by a platformtheme plugin // if QT_QPA_PLATFORMTHEME=(gtk2|gtk3), then force-apply the icon theme - if ((((QIcon::themeName() == qstr("hicolor") // QGenericUnixTheme + if (((QIcon::themeName() == qstr("hicolor") // QGenericUnixTheme && QIcon::fallbackThemeName() == qstr("hicolor")) || (QIcon::themeName() == qstr("Adwaita") // QGnomeTheme && QIcon::fallbackThemeName() == qstr("gnome"))) - && DesktopEnvironment::IsGtkBased()) || IsGtkIntegrationForced()) { DEBUG_LOG(("Set GTK icon theme")); QIcon::setThemeName(gtkSetting("gtk-icon-theme-name")); diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index cf12821ce..62463eb7a 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -582,7 +582,9 @@ void Manager::Private::showNotification( const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) { - if (!Supported()) return; + if (!Supported()) { + return; + } const auto key = FullPeer{ .sessionId = peer->session().uniqueId(), @@ -630,7 +632,9 @@ void Manager::Private::showNotification( } void Manager::Private::clearAll() { - if (!Supported()) return; + if (!Supported()) { + return; + } for (const auto &[key, notifications] : base::take(_notifications)) { for (const auto &[msgId, notification] : notifications) { @@ -640,7 +644,9 @@ void Manager::Private::clearAll() { } void Manager::Private::clearFromHistory(not_null history) { - if (!Supported()) return; + if (!Supported()) { + return; + } const auto key = FullPeer{ .sessionId = history->session().uniqueId(), @@ -658,23 +664,29 @@ void Manager::Private::clearFromHistory(not_null history) { } void Manager::Private::clearFromSession(not_null session) { - if (!Supported()) return; + if (!Supported()) { + return; + } const auto sessionId = session->uniqueId(); for (auto i = _notifications.begin(); i != _notifications.end();) { - if (i->first.sessionId == sessionId) { - const auto temp = base::take(i->second); - i = _notifications.erase(i); + if (i->first.sessionId != sessionId) { + ++i; + continue; + } + const auto temp = base::take(i->second); + i = _notifications.erase(i); - for (const auto &[msgId, notification] : temp) { - notification->close(); - } + for (const auto &[msgId, notification] : temp) { + notification->close(); } } } void Manager::Private::clearNotification(NotificationId id) { - if (!Supported()) return; + if (!Supported()) { + return; + } auto i = _notifications.find(id.full); if (i != _notifications.cend()) { diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index a3a644158..44ee92c00 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -520,6 +520,7 @@ QString GetIconName() { } bool GtkClipboardSupported() { +#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION return (Libs::gtk_clipboard_get != nullptr) && (Libs::gtk_clipboard_wait_for_contents != nullptr) && (Libs::gtk_clipboard_wait_for_image != nullptr) @@ -531,6 +532,9 @@ bool GtkClipboardSupported() { && (Libs::gdk_pixbuf_get_rowstride != nullptr) && (Libs::gdk_pixbuf_get_has_alpha != nullptr) && (Libs::gdk_atom_intern != nullptr); +#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION + + return false; } QImage GetImageFromClipboard() { diff --git a/Telegram/SourceFiles/platform/mac/mac_touchbar.h b/Telegram/SourceFiles/platform/mac/mac_touchbar.h index 931face15..979e054e7 100644 --- a/Telegram/SourceFiles/platform/mac/mac_touchbar.h +++ b/Telegram/SourceFiles/platform/mac/mac_touchbar.h @@ -1,10 +1,13 @@ /* - This file is part of Telegram Desktop, - the official desktop application for the Telegram messaging service. +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. - For license and copyright information please follow this link: - https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL - */ +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#ifndef OS_OSX #include "platform/platform_specific.h" #include "media/audio/media_audio.h" @@ -12,13 +15,15 @@ #import namespace Platform { + enum class TouchBarType { None, Main, AudioPlayer, AudioPlayerForce, }; -} // namespace + +} // namespace Platform @interface TouchBar : NSTouchBar @@ -31,3 +36,5 @@ enum class TouchBarType { - (void) showInputFieldItem:(bool)show; @end + +#endif // OS_OSX diff --git a/Telegram/SourceFiles/platform/mac/mac_touchbar.mm b/Telegram/SourceFiles/platform/mac/mac_touchbar.mm index 6e4bdd317..e9a9c8697 100644 --- a/Telegram/SourceFiles/platform/mac/mac_touchbar.mm +++ b/Telegram/SourceFiles/platform/mac/mac_touchbar.mm @@ -1,13 +1,13 @@ /* - This file is part of Telegram Desktop, - the official desktop application for the Telegram messaging service. +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. - For license and copyright information please follow this link: - https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL - */ +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "platform/mac/mac_touchbar.h" -#import "mac_touchbar.h" -#import +#ifndef OS_OSX #include "api/api_sending.h" #include "apiwrap.h" @@ -49,6 +49,8 @@ #include "window/window_controller.h" #include "window/window_session_controller.h" +#import + namespace { //https://developer.apple.com/design/human-interface-guidelines/macos/touch-bar/touch-bar-icons-and-images/ constexpr auto kIdealIconSize = 36; @@ -1905,3 +1907,5 @@ void AppendEmojiPacks( } @end // @implementation TouchBar + +#endif // OS_OSX diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index f9828dc90..43ec78a07 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -144,9 +144,9 @@ public: void didExitFullScreen(); bool clipboardHasText(); - +#ifndef OS_OSX TouchBar *_touchBar = nil; - +#endif // OS_OSX ~Private(); private: @@ -197,7 +197,9 @@ private: } - (void) darkModeChanged:(NSNotification *)aNotification { - Core::App().domain().notifyUnreadBadgeChanged(); + Core::Sandbox::Instance().customEnterFromEventLoop([&] { + Core::App().domain().notifyUnreadBadgeChanged(); + }); } - (void) screenIsLocked:(NSNotification *)aNotification { @@ -486,6 +488,7 @@ MainWindow::MainWindow(not_null controller) } void MainWindow::initTouchBar() { +#ifndef OS_OSX if (!IsMac10_13OrGreater()) { return; } @@ -513,14 +516,17 @@ void MainWindow::initTouchBar() { destroyCurrentTouchBar(); } }, lifetime()); +#endif // OS_OSX } void MainWindow::destroyCurrentTouchBar() { +#ifndef OS_OSX if (_private->_touchBar) { [_private->_touchBar setTouchBar:Platform::TouchBarType::None]; [_private->_touchBar release]; } _private->_touchBar = nil; +#endif // OS_OSX } void MainWindow::closeWithoutDestroy() { @@ -844,9 +850,13 @@ void MainWindow::updateGlobalMenuHook() { canCopy = list->canCopySelected(); canDelete = list->canDeleteSelected(); } + +#ifndef OS_OSX if (_private->_touchBar) { [_private->_touchBar showInputFieldItem:showTouchBarItem]; } +#endif // OS_OSX + App::wnd()->updateIsActive(); const auto logged = (sessionController() != nullptr); const auto inactive = !logged || controller().locked(); diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp index f5cfdf51d..5fd6c591f 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -415,7 +415,9 @@ Manager::Private::~Private() { } void Manager::Private::clearAll() { - if (!_notifier) return; + if (!_notifier) { + return; + } auto temp = base::take(_notifications); for (const auto &[key, notifications] : base::take(_notifications)) { @@ -426,7 +428,9 @@ void Manager::Private::clearAll() { } void Manager::Private::clearFromHistory(not_null history) { - if (!_notifier) return; + if (!_notifier) { + return; + } auto i = _notifications.find(FullPeer{ .sessionId = history->session().uniqueId(), @@ -443,17 +447,21 @@ void Manager::Private::clearFromHistory(not_null history) { } void Manager::Private::clearFromSession(not_null session) { - if (!_notifier) return; + if (!_notifier) { + return; + } const auto sessionId = session->uniqueId(); for (auto i = _notifications.begin(); i != _notifications.end();) { - if (i->first.sessionId == sessionId) { - const auto temp = base::take(i->second); - _notifications.erase(i); + if (i->first.sessionId != sessionId) { + ++i; + continue; + } + const auto temp = base::take(i->second); + _notifications.erase(i); - for (const auto &[msgId, notification] : temp) { - _notifier->Hide(notification.p.Get()); - } + for (const auto &[msgId, notification] : temp) { + _notifier->Hide(notification.p.Get()); } } } diff --git a/Telegram/SourceFiles/settings/settings_calls.cpp b/Telegram/SourceFiles/settings/settings_calls.cpp index cc8872050..b4b01ec57 100644 --- a/Telegram/SourceFiles/settings/settings_calls.cpp +++ b/Telegram/SourceFiles/settings/settings_calls.cpp @@ -52,7 +52,7 @@ Calls::Calls( Calls::~Calls() { if (_needWriteSettings) { - _controller->session().saveSettingsDelayed(); + Core::App().saveSettingsDelayed(); } } @@ -134,7 +134,7 @@ void Calls::setupContent() { : "default"; Core::App().settings().setCallOutputDeviceID( QString::fromStdString(deviceId)); - _controller->session().saveSettingsDelayed(); + Core::App().saveSettingsDelayed(); if (const auto call = Core::App().calls().currentCall()) { call->setCurrentAudioDevice(false, deviceId); } @@ -210,7 +210,7 @@ void Calls::setupContent() { : "default"; Core::App().settings().setCallInputDeviceID( QString::fromStdString(deviceId)); - _controller->session().saveSettingsDelayed(); + Core::App().saveSettingsDelayed(); if (_micTester) { stopTestingMicrophone(); } diff --git a/Telegram/SourceFiles/settings/settings_common.cpp b/Telegram/SourceFiles/settings/settings_common.cpp index 78da4381a..543b3fb02 100644 --- a/Telegram/SourceFiles/settings/settings_common.cpp +++ b/Telegram/SourceFiles/settings/settings_common.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_folders.h" #include "settings/settings_calls.h" #include "kotato/settings_menu.h" +#include "core/application.h" #include "ui/wrap/padding_wrap.h" #include "ui/wrap/vertical_layout.h" #include "ui/widgets/labels.h" @@ -30,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwindow.h" #include "app.h" #include "main/main_session.h" +#include "main/main_domain.h" #include "styles/style_layers.h" #include "styles/style_settings.h" @@ -200,6 +202,12 @@ void FillMenu( tr::lng_settings_bg_theme_create(tr::now), [=] { window->show(Box(Window::Theme::CreateBox, window)); }); } else { + const auto &list = Core::App().domain().accounts(); + if (list.size() < ::Main::Domain::kMaxAccounts) { + addAction(tr::lng_menu_add_account(tr::now), [=] { + Core::App().domain().addActivated(MTP::Environment{}); + }); + } const auto customSettingsFile = cWorkingDir() + "tdata/kotato-settings-custom.json"; if (type != Type::Kotato && !controller->session().supportMode()) { addAction( diff --git a/Telegram/SourceFiles/settings/settings_notifications.cpp b/Telegram/SourceFiles/settings/settings_notifications.cpp index da8fd0a2b..2dd8fa158 100644 --- a/Telegram/SourceFiles/settings/settings_notifications.cpp +++ b/Telegram/SourceFiles/settings/settings_notifications.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwindow.h" #include "core/application.h" #include "main/main_session.h" +#include "main/main_account.h" #include "main/main_domain.h" #include "apiwrap.h" #include "facades.h" @@ -540,9 +541,49 @@ void SetupAdvancedNotifications( AddSkip(container, st::settingsCheckboxesSkip); } +void SetupMultiAccountNotifications( + not_null controller, + not_null container) { + if (Core::App().domain().accounts().size() < 2) { + return; + } + AddSubsectionTitle(container, tr::lng_settings_show_from()); + + const auto fromAll = container->add( + object_ptr( + container, + tr::lng_settings_notify_all(tr::now), + Core::App().settings().notifyFromAll(), + st::settingsCheckbox), + st::settingsCheckboxPadding); + fromAll->checkedChanges( + ) | rpl::filter([](bool checked) { + return (checked != Core::App().settings().notifyFromAll()); + }) | rpl::start_with_next([=](bool checked) { + Core::App().settings().setNotifyFromAll(checked); + Core::App().saveSettingsDelayed(); + if (!checked) { + auto ¬ifications = Core::App().notifications(); + const auto &list = Core::App().domain().accounts(); + for (const auto &[index, account] : list) { + if (account.get() == &Core::App().domain().active()) { + continue; + } else if (const auto session = account->maybeSession()) { + notifications.clearFromSession(session); + } + } + } + }, fromAll->lifetime()); + + AddSkip(container); + AddDividerText(container, tr::lng_settings_notify_all_about()); +} + void SetupNotificationsContent( not_null controller, not_null container) { + SetupMultiAccountNotifications(controller, container); + AddSubsectionTitle(container, tr::lng_settings_notify_title()); const auto session = &controller->session(); diff --git a/Telegram/SourceFiles/storage/serialize_peer.cpp b/Telegram/SourceFiles/storage/serialize_peer.cpp index e888b7cac..4e8b896bf 100644 --- a/Telegram/SourceFiles/storage/serialize_peer.cpp +++ b/Telegram/SourceFiles/storage/serialize_peer.cpp @@ -204,8 +204,9 @@ PeerData *readPeer( const auto loaded = (peerId == selfId) ? session->user().get() : session->data().peerLoaded(peerId); + const auto apply = !loaded || (loaded->loadedStatus != PeerData::FullLoaded); const auto result = loaded ? loaded : session->data().peer(peerId).get(); - if (!loaded) { + if (apply) { result->loadedStatus = PeerData::FullLoaded; } if (const auto user = result->asUser()) { @@ -230,7 +231,7 @@ PeerData *readPeer( ? App::formatPhone(phone) : QString(); - if (!loaded) { + if (apply) { user->setPhone(phone); user->setName(first, last, pname, username); @@ -268,7 +269,7 @@ PeerData *readPeer( if (oldForbidden) { flags |= quint32(MTPDchat_ClientFlag::f_forbidden); } - if (!loaded) { + if (apply) { chat->setName(name); chat->count = count; chat->date = date; @@ -296,7 +297,7 @@ PeerData *readPeer( if (oldForbidden) { flags |= quint32(MTPDchannel_ClientFlag::f_forbidden); } - if (!loaded) { + if (apply) { channel->setName(name, QString()); channel->access = access; channel->date = date; @@ -312,7 +313,7 @@ PeerData *readPeer( channel->inputChannel = MTP_inputChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); } } - if (!loaded) { + if (apply) { using LocationType = StorageFileLocation::Type; const auto location = (userpic->valid() && userpic->isLegacy()) ? userpic->convertToModern( diff --git a/Telegram/SourceFiles/storage/storage_media_prepare.cpp b/Telegram/SourceFiles/storage/storage_media_prepare.cpp index 48ce0d75d..2a05a4837 100644 --- a/Telegram/SourceFiles/storage/storage_media_prepare.cpp +++ b/Telegram/SourceFiles/storage/storage_media_prepare.cpp @@ -286,7 +286,6 @@ std::optional PreparedList::PreparedFileFromFilesDialog( } if (!result.remoteContent.isEmpty()) { - auto list = Storage::PrepareMediaFromImage( QImage(), std::move(result.remoteContent), @@ -311,7 +310,7 @@ std::optional PreparedList::PreparedFileFromFilesDialog( } } Expects(list.files.size() == 1); - return std::move(list); + return list; } else if (!result.paths.isEmpty()) { const auto isSingleFile = (result.paths.size() == 1); auto temp = Storage::PrepareMediaList(result.paths, previewWidth); @@ -366,7 +365,7 @@ std::optional PreparedList::PreparedFileFromFilesDialog( list.allFilesForCompress = temp.allFilesForCompress; list.files = std::move(filteredFiles); - return std::move(list); + return list; } return std::nullopt; } diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index 2f2edc4f9..c950f269c 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -52,8 +52,6 @@ constexpr auto kSystemAlertDuration = crl::time(0); System::System() : _waitTimer([=] { showNext(); }) , _waitForAllGroupedTimer([=] { showGrouped(); }) { - createManager(); - subscribe(settingsChanged(), [=](ChangeType type) { if (type == ChangeType::DesktopEnabled) { App::wnd()->updateTrayMenu(); @@ -93,6 +91,9 @@ System::SkipState System::skipNotification( const auto notifyBy = item->specialNotificationPeer(); if (App::quitting() || !history->currentNotification()) { return { SkipState::Skip }; + } else if (!Core::App().settings().notifyFromAll() + && &history->session().account() != &Core::App().domain().active()) { + return { SkipState::Skip }; } const auto scheduled = item->out() && item->isFromScheduled(); @@ -176,7 +177,9 @@ void System::schedule(not_null item) { } void System::clearAll() { - _manager->clearAll(); + if (_manager) { + _manager->clearAll(); + } for (auto i = _whenMaps.cbegin(), e = _whenMaps.cend(); i != e; ++i) { i->first->clearNotifications(); @@ -188,7 +191,9 @@ void System::clearAll() { } void System::clearFromHistory(not_null history) { - _manager->clearFromHistory(history); + if (_manager) { + _manager->clearFromHistory(history); + } history->clearNotifications(); _whenMaps.remove(history); @@ -201,19 +206,21 @@ void System::clearFromHistory(not_null history) { } void System::clearFromSession(not_null session) { - _manager->clearFromSession(session); + if (_manager) { + _manager->clearFromSession(session); + } for (auto i = _whenMaps.begin(); i != _whenMaps.end();) { const auto history = i->first; - if (&history->session() == session) { - history->clearNotifications(); - i = _whenMaps.erase(i); - _whenAlerts.remove(history); - _waiters.remove(history); - _settingWaiters.remove(history); - } else { + if (&history->session() != session) { ++i; + continue; } + history->clearNotifications(); + i = _whenMaps.erase(i); + _whenAlerts.remove(history); + _waiters.remove(history); + _settingWaiters.remove(history); } const auto clearFrom = [&](auto &map) { for (auto i = map.begin(); i != map.end();) { @@ -230,17 +237,23 @@ void System::clearFromSession(not_null session) { } void System::clearIncomingFromHistory(not_null history) { - _manager->clearFromHistory(history); + if (_manager) { + _manager->clearFromHistory(history); + } history->clearIncomingNotifications(); _whenAlerts.remove(history); } void System::clearFromItem(not_null item) { - _manager->clearFromItem(item); + if (_manager) { + _manager->clearFromItem(item); + } } void System::clearAllFast() { - _manager->clearAllFast(); + if (_manager) { + _manager->clearAllFast(); + } _whenMaps.clear(); _whenAlerts.clear(); @@ -295,6 +308,8 @@ void System::checkDelayed() { } void System::showGrouped() { + Expects(_manager != nullptr); + if (const auto session = findSession(_lastHistorySessionId)) { if (const auto lastItem = session->data().message(_lastHistoryItemId)) { _waitForAllGroupedTimer.cancel(); @@ -307,7 +322,11 @@ void System::showGrouped() { } void System::showNext() { - if (App::quitting()) return; + Expects(_manager != nullptr); + + if (App::quitting()) { + return; + } const auto isSameGroup = [=](HistoryItem *item) { if (!_lastHistorySessionId || !_lastHistoryItemId || !item) { @@ -538,7 +557,9 @@ void System::ensureSoundCreated() { } void System::updateAll() { - _manager->updateAll(); + if (_manager) { + _manager->updateAll(); + } } Manager::DisplayOptions Manager::GetNotificationOptions(HistoryItem *item) { @@ -561,7 +582,17 @@ Manager::DisplayOptions Manager::GetNotificationOptions(HistoryItem *item) { QString Manager::addTargetAccountName( const QString &title, not_null session) { - return (Core::App().domain().accounts().size() > 1) + const auto add = [&] { + for (const auto &[index, account] : Core::App().domain().accounts()) { + if (const auto other = account->maybeSession()) { + if (other != session) { + return true; + } + } + } + return false; + }(); + return add ? (title + accountNameSeparator() + (session->user()->username.isEmpty() diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index 6091fbb3f..3356a7bf5 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -192,7 +192,7 @@ void Manager::showNextFromQueue() { return; } int count = Core::App().settings().notificationsCount(); - for_const (auto ¬ification, _notifications) { + for (const auto ¬ification : _notifications) { if (notification->isUnlinked()) continue; --count; } diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 6a30f7be8..586868027 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -85,9 +85,6 @@ void Controller::showAccount(not_null account) { setupIntro(); _widget.updateGlobalMenu(); } - if (was) { - was->session().updates().updateOnline(); - } }, _accountLifetime); } diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index 8f01447b7..4858d8767 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_common.h" #include "base/qt_signal_producer.h" #include "boxes/about_box.h" +#include "boxes/confirm_box.h" #include "boxes/peer_list_controllers.h" #include "calls/calls_box_controller.h" #include "lang/lang_keys.h" @@ -53,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_dialogs.h" #include "styles/style_settings.h" #include "styles/style_boxes.h" +#include "styles/style_layers.h" #include #include @@ -100,13 +102,15 @@ public: private: void paintEvent(QPaintEvent *e) override; + void contextMenuEvent(QContextMenuEvent *e) override; void paintUserpic(Painter &p); - const not_null _account; + const not_null _session; const style::Menu &_st; std::shared_ptr _userpicView; InMemoryKey _userpicKey = {}; QImage _userpicCache; + base::unique_qptr _menu; Dialogs::Layout::UnreadBadgeStyle _unreadSt; int _unreadBadge = 0; @@ -154,7 +158,7 @@ MainMenu::AccountButton::AccountButton( QWidget *parent, not_null account) : RippleButton(parent, st::defaultRippleAnimation) -, _account(account) +, _session(&account->session()) , _st(st::mainMenu){ const auto height = _st.itemPadding.top() + _st.itemStyle.font->height @@ -168,33 +172,27 @@ MainMenu::AccountButton::AccountButton( } }); - _account->sessionValue( - ) | rpl::filter([=](Main::Session *session) { - return (session != nullptr); - }) | rpl::start_with_next([=](not_null session) { - rpl::single( - rpl::empty_value() - ) | rpl::then( - session->data().unreadBadgeChanges() - ) | rpl::start_with_next([=] { - _unreadBadge = session->data().unreadBadge(); - _unreadBadgeMuted = session->data().unreadBadgeMuted(); - update(); - }, lifetime()); + rpl::single( + rpl::empty_value() + ) | rpl::then( + _session->data().unreadBadgeChanges() + ) | rpl::start_with_next([=] { + _unreadBadge = _session->data().unreadBadge(); + _unreadBadgeMuted = _session->data().unreadBadgeMuted(); + update(); }, lifetime()); } void MainMenu::AccountButton::paintUserpic(Painter &p) { - Expects(_account->sessionExists()); - const auto size = st::mainMenuAccountSize; const auto iconSize = height() - 2 * _st.itemIconPosition.y(); const auto shift = (size - iconSize) / 2; const auto x = _st.itemIconPosition.x() - shift; const auto y = (height() - size) / 2; - const auto check = (_account == &Core::App().domain().active()); - const auto user = _account->session().user(); + const auto check = (&_session->account() + == &Core::App().domain().active()); + const auto user = _session->user(); if (!check) { user->paintUserpicLeft(p, _userpicView, x, y, width(), size); return; @@ -235,8 +233,6 @@ void MainMenu::AccountButton::paintUserpic(Painter &p) { } void MainMenu::AccountButton::paintEvent(QPaintEvent *e) { - Expects(_account->sessionExists()); - auto p = Painter(this); const auto over = isOver(); p.fillRect(rect(), over ? _st.itemBgOver : _st.itemBg); @@ -245,7 +241,8 @@ void MainMenu::AccountButton::paintEvent(QPaintEvent *e) { paintUserpic(p); auto available = width() - _st.itemPadding.left(); - if (_unreadBadge && _account != &Core::App().activeAccount()) { + if (_unreadBadge + && (&_session->account() != &Core::App().activeAccount())) { _unreadSt.muted = _unreadBadgeMuted; const auto string = (_unreadBadge > 99) ? "99+" @@ -268,13 +265,39 @@ void MainMenu::AccountButton::paintEvent(QPaintEvent *e) { } p.setPen(over ? _st.itemFgOver : _st.itemFg); - _account->session().user()->nameText().drawElided( + _session->user()->nameText().drawElided( p, _st.itemPadding.left(), _st.itemPadding.top(), available); } +void MainMenu::AccountButton::contextMenuEvent(QContextMenuEvent *e) { + if (&_session->account() == &Core::App().activeAccount() || _menu) { + return; + } + _menu = base::make_unique_q(this); + _menu->addAction(tr::lng_menu_activate(tr::now), crl::guard(this, [=] { + Core::App().domain().activate(&_session->account()); + })); + _menu->addAction(tr::lng_settings_logout(tr::now), crl::guard(this, [=] { + const auto session = _session; + const auto box = std::make_shared>(); + const auto callback = [=] { + if (*box) { + (*box)->closeBox(); + } + Core::App().logout(&session->account()); + }; + *box = Ui::show(Box( + tr::lng_sure_logout(tr::now), + tr::lng_settings_logout(tr::now), + st::attentionBoxButton, + crl::guard(session, callback))); + })); + _menu->popup(QCursor::pos()); +} + MainMenu::ToggleAccountsButton::ToggleAccountsButton(QWidget *parent) : AbstractButton(parent) { rpl::single( @@ -642,14 +665,17 @@ void MainMenu::setupCloudButton() { } void MainMenu::setupUserpicButton() { - _userpicButton->setClickedCallback([=] { - _controller->content()->choosePeer( - _controller->session().userPeerId(), - ShowAtUnreadMsgId); - }); + _userpicButton->setClickedCallback([=] { toggleAccounts(); }); _userpicButton->show(); } +void MainMenu::toggleAccounts() { + auto &settings = Core::App().settings(); + const auto shown = !settings.mainMenuAccountsShown(); + settings.setMainMenuAccountsShown(shown); + Core::App().saveSettingsDelayed(); +} + void MainMenu::setupAccounts() { const auto inner = _accounts->entity(); @@ -688,7 +714,6 @@ void MainMenu::setupAccounts() { rebuildAccounts(); }, lifetime()); - _accounts->toggleOn(Core::App().settings().mainMenuAccountsShownValue()); _accounts->toggleOn(Core::App().settings().mainMenuAccountsShownValue()); _accounts->finishAnimating(); @@ -772,18 +797,7 @@ not_null*> MainMenu::setupAddAccount( }, button->lifetime()); const auto add = [=](MTP::Environment environment) { - auto &domain = Core::App().domain(); - if (domain.accounts().size() < Main::Domain::kMaxAccounts) { - domain.activate(domain.add(environment)); - } else { - for (auto &[index, account] : domain.accounts()) { - if (!account->sessionExists() - && account->mtp().environment() == environment) { - domain.activate(account.get()); - break; - } - } - } + Core::App().domain().addActivated(environment); }; button->setAcceptBoth(true); @@ -812,12 +826,7 @@ not_null*> MainMenu::setupAddAccount( void MainMenu::setupAccountsToggle() { _toggleAccounts->show(); - _toggleAccounts->setClickedCallback([=] { - auto &settings = Core::App().settings(); - const auto shown = !settings.mainMenuAccountsShown(); - settings.setMainMenuAccountsShown(shown); - Core::App().saveSettingsDelayed(); - }); + _toggleAccounts->setClickedCallback([=] { toggleAccounts(); }); } void MainMenu::parentResized() { diff --git a/Telegram/SourceFiles/window/window_main_menu.h b/Telegram/SourceFiles/window/window_main_menu.h index 51e10a9bf..661364ab2 100644 --- a/Telegram/SourceFiles/window/window_main_menu.h +++ b/Telegram/SourceFiles/window/window_main_menu.h @@ -68,6 +68,7 @@ private: void initResetScaleButton(); void refreshMenu(); void refreshBackground(); + void toggleAccounts(); const not_null _controller; object_ptr _userpicButton; diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index f10961699..2adb9669c 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -1245,7 +1245,7 @@ void PeerMenuAddChannelMembers( return; } const auto api = &channel->session().api(); - api->requestChannelMembersForAdd(channel, [=]( + api->requestChannelMembersForAdd(channel, crl::guard(navigation, [=]( const MTPchannels_ChannelParticipants &result) { api->parseChannelParticipants(channel, result, [&]( int availableCount, @@ -1267,7 +1267,7 @@ void PeerMenuAddChannelMembers( channel, { already.begin(), already.end() }); }); - }); + })); } void PeerMenuAddMuteAction( diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 04148ba91..4d753d226 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -116,7 +116,7 @@ struct SectionShow { class SessionController; -class SessionNavigation { +class SessionNavigation : public base::has_weak_ptr { public: explicit SessionNavigation(not_null session); @@ -156,10 +156,7 @@ private: }; -class SessionController - : public SessionNavigation - , public base::has_weak_ptr - , private base::Subscriber { +class SessionController : public SessionNavigation, private base::Subscriber { public: SessionController( not_null session, @@ -171,6 +168,15 @@ public: [[nodiscard]] not_null<::MainWindow*> widget() const; [[nodiscard]] not_null content() const; + // We need access to this from MainWidget::MainWidget, where + // we can't call content() yet. + void setSelectingPeer(bool selecting) { + _selectingPeer = selecting; + } + [[nodiscard]] bool selectingPeer() const { + return _selectingPeer; + } + [[nodiscard]] auto tabbedSelector() const -> not_null; void takeTabbedSelectorOwnershipFrom(not_null parent); @@ -335,6 +341,7 @@ private: base::Variable _dialogsListDisplayForced = { false }; std::deque _chatEntryHistory; int _chatEntryHistoryPosition = -1; + bool _selectingPeer = false; rpl::variable _activeChatsFilter; diff --git a/Telegram/SourceFiles/window/window_title_qt.cpp b/Telegram/SourceFiles/window/window_title_qt.cpp index 17edd2368..92dd3d9da 100644 --- a/Telegram/SourceFiles/window/window_title_qt.cpp +++ b/Telegram/SourceFiles/window/window_title_qt.cpp @@ -116,6 +116,12 @@ bool TitleWidgetQt::eventFilter(QObject *obj, QEvent *e) { return startResize(mouseEvent->windowPos().toPoint()); } } + } else if (e->type() == QEvent::Leave) { + if (window() == static_cast(obj)) { + while (QGuiApplication::overrideCursor()) { + QGuiApplication::restoreOverrideCursor(); + } + } } return TitleWidget::eventFilter(obj, e); diff --git a/Telegram/build/version b/Telegram/build/version index f96758021..71f03d59c 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 2001014 +AppVersion 2001016 AppVersionStrMajor 2.1 -AppVersionStrSmall 2.1.14 -AppVersionStr 2.1.14 +AppVersionStrSmall 2.1.16 +AppVersionStr 2.1.16 BetaChannel 1 AlphaVersion 0 -AppVersionOriginal 2.1.14.beta +AppVersionOriginal 2.1.16.beta diff --git a/changelog.txt b/changelog.txt index 78c284d2b..756f9b0f7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,13 @@ +2.1.16 beta (01.07.20) + +- Crash fix. + +2.1.15 beta (30.06.20) + +- Receive notifications only from the active account in Settings > Notifications. +- Fix saving chats list width between application relaunches. +- Multiple crash fixes. + 2.1.14 beta (29.06.20) - Support for multiple accounts.