From 6cf9157fb5040a1f39b69a854a627ab2050bf03c Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 6 Feb 2020 13:19:33 +0400 Subject: [PATCH 001/140] Fix jump-to-time from audio captions. --- .../media/player/media_player_instance.cpp | 12 +++++++----- .../SourceFiles/media/player/media_player_instance.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp index e150eb08b..214f1252c 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.cpp +++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp @@ -189,14 +189,16 @@ void Instance::setCurrent(const AudioMsgId &audioId) { } } -void Instance::clearStreamed(not_null data) { +void Instance::clearStreamed(not_null data, bool savePosition) { if (!data->streamed || data->streamed->clearing) { return; } data->streamed->clearing = true; - SaveLastPlaybackPosition( - data->current.audio(), - data->streamed->instance.player().prepareLegacyState()); + if (savePosition) { + SaveLastPlaybackPosition( + data->current.audio(), + data->streamed->instance.player().prepareLegacyState()); + } data->streamed->instance.stop(); data->isPlaying = false; requestRoundVideoResize(); @@ -414,7 +416,7 @@ void Instance::playStreamed( const auto data = getData(audioId.type()); Assert(data != nullptr); - clearStreamed(data); + clearStreamed(data, data->current.audio() != audioId.audio()); data->streamed = std::make_unique( audioId, std::move(shared)); diff --git a/Telegram/SourceFiles/media/player/media_player_instance.h b/Telegram/SourceFiles/media/player/media_player_instance.h index d5472e40f..be8aa3a7d 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.h +++ b/Telegram/SourceFiles/media/player/media_player_instance.h @@ -225,7 +225,7 @@ private: not_null data, Streaming::Error &&error); - void clearStreamed(not_null data); + void clearStreamed(not_null data, bool savePosition = true); void emitUpdate(AudioMsgId::Type type); template void emitUpdate(AudioMsgId::Type type, CheckCallback check); From 1f16d72667e16a98cab9e3784289fcd1bb1f5b85 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 6 Feb 2020 13:27:21 +0400 Subject: [PATCH 002/140] Allow setSpeed() on non-active streaming player. --- .../media/streaming/media_streaming_player.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp index 643d2fd90..c2bc13648 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp @@ -827,7 +827,6 @@ float64 Player::speed() const { } void Player::setSpeed(float64 speed) { - Expects(active()); Expects(speed >= 0.5 && speed <= 2.); if (!Media::Audio::SupportsSpeedControl()) { @@ -835,11 +834,13 @@ void Player::setSpeed(float64 speed) { } if (_options.speed != speed) { _options.speed = speed; - if (_audio) { - _audio->setSpeed(speed); - } - if (_video) { - _video->setSpeed(speed); + if (active()) { + if (_audio) { + _audio->setSpeed(speed); + } + if (_video) { + _video->setSpeed(speed); + } } } } From 9e3fa2e4bcd176024cddb1c96f0e9754dba69826 Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Thu, 6 Feb 2020 10:49:22 +0100 Subject: [PATCH 003/140] Check action id when invoked Makes it more resilient --- .../linux/notifications_manager_linux.cpp | 20 ++++++++++++------- .../linux/notifications_manager_linux.h | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index c399f97b2..f7fd5debc 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -118,7 +118,7 @@ NotificationData::NotificationData( kInterface.utf16(), qsl("ActionInvoked"), this, - SLOT(notificationClicked(uint))); + SLOT(notificationClicked(uint,QString))); if (capabilities.contains(qsl("inline-reply"))) { _actions << qsl("inline-reply") @@ -261,13 +261,19 @@ void NotificationData::notificationClosed(uint id) { } } -void NotificationData::notificationClicked(uint id) { - if (id == _notificationId) { - const auto manager = _manager; - crl::on_main(manager, [=] { - manager->notificationActivated(_peerId, _msgId); - }); +void NotificationData::notificationClicked(uint id, const QString &actionId) { + if (id != _notificationId) { + return; } + + if (actionId != qsl("default") && actionId != qsl("mail-reply-sender")) { + return; + } + + const auto manager = _manager; + crl::on_main(manager, [=] { + manager->notificationActivated(_peerId, _msgId); + }); } void NotificationData::notificationReplied(uint id, const QString &text) { diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h index 1addbb701..4ac937216 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h @@ -72,7 +72,7 @@ private: private slots: void notificationClosed(uint id); - void notificationClicked(uint id); + void notificationClicked(uint id, const QString &actionId); void notificationReplied(uint id, const QString &text); }; From 6206b6f843626996d1cad0c56f9a181ae93f4a5e Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Thu, 6 Feb 2020 15:34:28 +0400 Subject: [PATCH 004/140] Adapt indicator-application check for sandboxed environments Fix quality loss in the tray icon image Fix window showing by clicking on the tray icon on macOS Fix tray icon displaying on KDE --- .github/workflows/linux.yml | 5 +- Telegram/SourceFiles/mainwindow.cpp | 9 +- .../platform/linux/main_window_linux.cpp | 109 +++++++++++------- .../platform/linux/main_window_linux.h | 2 +- .../platform/mac/main_window_mac.mm | 11 +- Telegram/SourceFiles/qt_static_plugins.cpp | 1 + .../statusnotifieritem/statusnotifieritem.cpp | 9 ++ .../statusnotifieritem/statusnotifieritem.h | 6 + docs/building-cmake.md | 3 +- 9 files changed, 98 insertions(+), 57 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 02727c532..78004ab3b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,7 +31,7 @@ jobs: CMAKE_VER: "3.16.3" UPLOAD_ARTIFACT: "false" ONLY_CACHE: "false" - MANUAL_CACHING: "2" + MANUAL_CACHING: "3" DOC_PATH: "docs/building-cmake.md" steps: @@ -364,10 +364,11 @@ jobs: git clone git://code.qt.io/qt/qt5.git qt_$QT cd qt_$QT - perl init-repository --module-subset=qtbase,qtimageformats + perl init-repository --module-subset=qtbase,qtimageformats,qtsvg git checkout v5.12.5 git submodule update qtbase git submodule update qtimageformats + git submodule update qtsvg cd qtbase git apply ../../patches/qtbase_$QT.diff cd src/plugins/platforminputcontexts diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 3388cb186..b404807dc 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -556,8 +556,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *e) { void MainWindow::updateTrayMenu(bool force) { if (!trayIconMenu || (Platform::IsWindows() && !force)) return; - auto iconMenu = trayIconMenu; - auto actions = iconMenu->actions(); + auto actions = trayIconMenu->actions(); if (Platform::IsLinux()) { auto minimizeAction = actions.at(1); minimizeAction->setEnabled(isVisible()); @@ -571,12 +570,6 @@ void MainWindow::updateTrayMenu(bool force) { toggleAction->setText(active ? tr::lng_minimize_to_tray(tr::now) : tr::lng_open_from_tray(tr::now)); - - // On macOS just remove trayIcon menu if the window is not active. - // So we will activate the window on click instead of showing the menu. - if (!active && Platform::IsMac()) { - iconMenu = nullptr; - } } auto notificationAction = actions.at(Platform::IsLinux() ? 2 : 1); auto notificationActionText = Global::DesktopNotify() diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 83be08f3e..63a2a5ecb 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "facades.h" #include "app.h" +#include + #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #include #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION @@ -73,33 +75,49 @@ QImage TrayIconImageGen() { const auto iconThemeName = QIcon::themeName(); const auto iconName = GetTrayIconName(); + const auto desiredSize = QSize(_trayIconSize, _trayIconSize); if (_trayIconImage.isNull() - || _trayIconImage.width() != _trayIconSize + || _trayIconImage.size() != desiredSize || iconThemeName != _trayIconThemeName || iconName != _trayIconName || muted != _trayIconMuted || counterSlice != _trayIconCount) { if (_trayIconImageBack.isNull() - || _trayIconImageBack.width() != _trayIconSize + || _trayIconImageBack.size() != desiredSize || iconThemeName != _trayIconThemeName || iconName != _trayIconName) { - _trayIconImageBack = Core::App().logo(); + const auto hasPanelIcon = QIcon::hasThemeIcon(iconName); - _trayIconImageBack = QIcon::fromTheme( - iconName, - QIcon::fromTheme( - kTrayIconName.utf16(), - QIcon(QPixmap::fromImage(_trayIconImageBack))) - ).pixmap(_trayIconSize, _trayIconSize).toImage(); + if (hasPanelIcon || QIcon::hasThemeIcon(kTrayIconName.utf16())) { + QIcon systemIcon; - auto w = _trayIconImageBack.width(), - h = _trayIconImageBack.height(); + if (hasPanelIcon) { + systemIcon = QIcon::fromTheme(iconName); + } else { + systemIcon = QIcon::fromTheme(kTrayIconName.utf16()); + } - if (w != _trayIconSize || h != _trayIconSize) { + if (systemIcon.actualSize(desiredSize) == desiredSize) { + _trayIconImageBack = systemIcon + .pixmap(desiredSize) + .toImage(); + } else { + const auto biggestSize = systemIcon + .availableSizes() + .last(); + + _trayIconImageBack = systemIcon + .pixmap(biggestSize) + .toImage(); + } + } else { + _trayIconImageBack = Core::App().logo(); + } + + if (_trayIconImageBack.size() != desiredSize) { _trayIconImageBack = _trayIconImageBack.scaled( - _trayIconSize, - _trayIconSize, + desiredSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } @@ -107,8 +125,8 @@ QImage TrayIconImageGen() { _trayIconImageBack = _trayIconImageBack.convertToFormat( QImage::Format_ARGB32); - w = _trayIconImageBack.width(); - h = _trayIconImageBack.height(); + const auto w = _trayIconImageBack.width(); + const auto h = _trayIconImageBack.height(); const auto perline = _trayIconImageBack.bytesPerLine(); auto *bytes = _trayIconImageBack.bits(); @@ -166,26 +184,31 @@ QImage TrayIconImageGen() { return _trayIconImage; } +bool IsAppIndicator() { +#ifdef TDESKTOP_DISABLE_DBUS_INTEGRATION + static const auto AppIndicator = false; +#else // TDESKTOP_DISABLE_DBUS_INTEGRATION + static const auto AppIndicator = QDBusInterface( + qsl("com.canonical.indicator.application"), + qsl("/com/canonical/indicator/application/service"), + qsl("com.canonical.indicator.application.service")).isValid() + || QDBusInterface( + qsl("org.ayatana.indicator.application"), + qsl("/org/ayatana/indicator/application/service"), + qsl("org.ayatana.indicator.application.service")).isValid(); +#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION + + return AppIndicator; +} + #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION static bool NeedTrayIconFile() { // Hack for indicator-application, which doesn't handle icons sent across D-Bus: // save the icon to a temp file and set the icon name to that filename. - static const auto TrayIconFileNeeded = [&] { - auto necessary = false; - const auto session = QDBusConnection::sessionBus(); - const auto pid = session.interface() - ->servicePid(kSNIWatcherService.utf16()).value(); - const auto processName = ProcessNameByPID(QString::number(pid)); - necessary = processName.endsWith( - qsl("indicator-application-service")); - if (!necessary) { - // Accessing to process name might be not allowed if the application - // is confined, thus we can just rely on the current desktop in use - necessary = DesktopEnvironment::IsUnity() - || DesktopEnvironment::IsMATE(); - } - return necessary; - }(); + static const auto TrayIconFileNeeded = IsAppIndicator() + // Ubuntu's tray extension doesn't zoom image data, but zooms image file + || DesktopEnvironment::IsGnome(); + return TrayIconFileNeeded; } @@ -196,7 +219,7 @@ static inline QString TrayIconFileTemplate() { } std::unique_ptr TrayIconFile( - const QPixmap &icon, QObject *parent) { + const QImage &icon, QObject *parent) { auto ret = std::make_unique( TrayIconFileTemplate(), parent); @@ -268,7 +291,7 @@ void MainWindow::psTrayMenuUpdated() { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION void MainWindow::setSNITrayIcon( - const QIcon &icon, const QPixmap &iconPixmap) { + const QIcon &icon, const QImage &iconImage) { if (!NeedTrayIconFile()) { _sniTrayIcon->setIconByPixmap(icon); _sniTrayIcon->setToolTipIconByPixmap(icon); @@ -279,7 +302,7 @@ void MainWindow::setSNITrayIcon( _sniTrayIcon->setIconByName(iconName); _sniTrayIcon->setToolTipIconByName(iconName); } else if (NeedTrayIconFile()) { - _trayIconFile = TrayIconFile(iconPixmap, this); + _trayIconFile = TrayIconFile(iconImage, this); if (_trayIconFile) { _sniTrayIcon->setIconByName(_trayIconFile->fileName()); @@ -311,8 +334,8 @@ void MainWindow::attachToSNITrayIcon() { #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION void MainWindow::psSetupTrayIcon() { - const auto iconPixmap = QPixmap::fromImage(TrayIconImageGen()); - const auto icon = QIcon(iconPixmap); + const auto iconImage = TrayIconImageGen(); + const auto icon = QIcon(QPixmap::fromImage(iconImage)); if (IsSNIAvailable()) { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION @@ -322,8 +345,8 @@ void MainWindow::psSetupTrayIcon() { QCoreApplication::applicationName(), this); - _sniTrayIcon->setTitle(QCoreApplication::applicationName()); - setSNITrayIcon(icon, iconPixmap); + _sniTrayIcon->setTitle(AppName.utf16()); + setSNITrayIcon(icon, iconImage); attachToSNITrayIcon(); } @@ -406,13 +429,13 @@ void MainWindow::updateIconCounters() { } #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - const auto iconPixmap = QPixmap::fromImage(TrayIconImageGen()); - const auto icon = QIcon(iconPixmap); + const auto iconImage = TrayIconImageGen(); + const auto icon = QIcon(QPixmap::fromImage(iconImage)); if (IsSNIAvailable()) { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION if (_sniTrayIcon) { - setSNITrayIcon(icon, iconPixmap); + setSNITrayIcon(icon, iconImage); } #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION } else if (trayIcon) { @@ -427,7 +450,7 @@ void MainWindow::LibsLoaded() { qDBusRegisterMetaType(); #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - if (!IsSNIAvailable()) { + if (!IsSNIAvailable() || IsAppIndicator()) { _trayIconSize = 22; } } diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index b83132280..fa175b2e1 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -70,7 +70,7 @@ private: StatusNotifierItem *_sniTrayIcon = nullptr; std::unique_ptr _trayIconFile = nullptr; - void setSNITrayIcon(const QIcon &icon, const QPixmap &iconPixmap); + void setSNITrayIcon(const QIcon &icon, const QImage &iconImage); void attachToSNITrayIcon(); #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index ed81efae5..32f6ae0a5 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -548,8 +548,15 @@ void MainWindow::psShowTrayMenu() { } void MainWindow::psTrayMenuUpdated() { - if (trayIcon && trayIconMenu && trayIcon->contextMenu() != trayIconMenu) { - trayIcon->setContextMenu(trayIconMenu); + // On macOS just remove trayIcon menu if the window is not active. + // So we will activate the window on click instead of showing the menu. + if (isActive()) { + if (trayIcon && trayIconMenu + && trayIcon->contextMenu() != trayIconMenu) { + trayIcon->setContextMenu(trayIconMenu); + } + } else { + trayIcon->setContextMenu(0); } } diff --git a/Telegram/SourceFiles/qt_static_plugins.cpp b/Telegram/SourceFiles/qt_static_plugins.cpp index fb68f2439..8d3e03633 100644 --- a/Telegram/SourceFiles/qt_static_plugins.cpp +++ b/Telegram/SourceFiles/qt_static_plugins.cpp @@ -23,6 +23,7 @@ Q_IMPORT_PLUGIN(QGenericEnginePlugin) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) Q_IMPORT_PLUGIN(QGenericEnginePlugin) Q_IMPORT_PLUGIN(QComposePlatformInputContextPlugin) +Q_IMPORT_PLUGIN(QSvgIconPlugin) #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION Q_IMPORT_PLUGIN(QConnmanEnginePlugin) Q_IMPORT_PLUGIN(QNetworkManagerEnginePlugin) diff --git a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp index 96a3a537b..a55079740 100644 --- a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp +++ b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp @@ -42,6 +42,7 @@ StatusNotifierItem::StatusNotifierItem(QString id, QObject *parent) mId(id), mTitle(QLatin1String("Test")), mStatus(QLatin1String("Active")), + mCategory(QLatin1String("ApplicationStatus")), mMenu(nullptr), mMenuPath(QLatin1String("/NO_DBUSMENU")), mMenuExporter(nullptr), @@ -116,6 +117,14 @@ void StatusNotifierItem::setStatus(const QString &status) Q_EMIT mAdaptor->NewStatus(mStatus); } +void StatusNotifierItem::setCategory(const QString &category) +{ + if (mCategory == category) + return; + + mCategory = category; +} + void StatusNotifierItem::setMenuPath(const QString& path) { mMenuPath.setPath(path); diff --git a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h index 3a689d11d..60739ea53 100644 --- a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h +++ b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h @@ -43,6 +43,7 @@ class StatusNotifierItem : public QObject { Q_OBJECT + Q_PROPERTY(QString Category READ category) Q_PROPERTY(QString Title READ title) Q_PROPERTY(QString Id READ id) Q_PROPERTY(QString Status READ status) @@ -74,6 +75,10 @@ public: { return mStatus; } void setStatus(const QString &status); + QString category() const + { return mCategory; } + void setCategory(const QString &category); + QDBusObjectPath menu() const { return mMenuPath; } void setMenuPath(const QString &path); @@ -162,6 +167,7 @@ private: QString mId; QString mTitle; QString mStatus; + QString mCategory; // icons QString mIconName, mOverlayIconName, mAttentionIconName; diff --git a/docs/building-cmake.md b/docs/building-cmake.md index f1b4b8763..2bcdd072a 100644 --- a/docs/building-cmake.md +++ b/docs/building-cmake.md @@ -235,10 +235,11 @@ Go to ***BuildPath*** and run git clone git://code.qt.io/qt/qt5.git qt_5_12_5 cd qt_5_12_5 - perl init-repository --module-subset=qtbase,qtimageformats + perl init-repository --module-subset=qtbase,qtimageformats,qtsvg git checkout v5.12.5 git submodule update qtbase git submodule update qtimageformats + git submodule update qtsvg cd qtbase git apply ../../patches/qtbase_5_12_5.diff cd src/plugins/platforminputcontexts From fb2bbd87b7d2850366f8d742e735eba6fb1ed4db Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 8 Feb 2020 08:29:51 +0400 Subject: [PATCH 005/140] Fix zlib linkage --- .github/workflows/linux.yml | 10 ---------- docs/building-cmake.md | 9 +-------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 78004ab3b..ef39c3a0f 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -111,16 +111,6 @@ jobs: cmake --version - - name: Zlib. - run: | - cd $LibrariesPath - - git clone $GIT/madler/zlib.git - cd zlib - ./configure - make -j$(nproc) - sudo make install - - name: Opus cache. id: cache-opus uses: actions/cache@v1 diff --git a/docs/building-cmake.md b/docs/building-cmake.md index 2bcdd072a..d5ba75cd4 100644 --- a/docs/building-cmake.md +++ b/docs/building-cmake.md @@ -58,13 +58,6 @@ Go to ***BuildPath*** and run cd ../ git clone --branch 0.10.0 https://github.com/ericniebler/range-v3 - git clone https://github.com/madler/zlib.git - cd zlib - ./configure - make $MAKE_THREADS_CNT - sudo make install - cd .. - git clone https://github.com/xiph/opus cd opus git checkout v1.3 @@ -254,12 +247,12 @@ Go to ***BuildPath*** and run -force-debug-info \ -opensource \ -confirm-license \ + -qt-zlib \ -qt-libpng \ -qt-libjpeg \ -qt-harfbuzz \ -qt-pcre \ -qt-xcb \ - -system-zlib \ -system-freetype \ -fontconfig \ -no-opengl \ From 77719750ee01910189c6717d70ee438ff8eaa40f Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Mon, 10 Feb 2020 07:58:57 +0400 Subject: [PATCH 006/140] Fix name of the snap desktop file Use new switch for GSL --- .../platform/linux/specific_linux.cpp | 29 ++++++++++--------- snap/snapcraft.yaml | 11 +------ 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 0ba17b6e7..0cfe83ef6 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -264,22 +264,23 @@ QString SingleInstanceLocalServerName(const QString &hash) { QString GetLauncherBasename() { static const auto LauncherBasename = [&] { - QString launcherBasename; - - if (InSnap()) { - launcherBasename = qsl("%1_%2") - .arg(QString::fromLatin1(qgetenv("SNAP_NAME"))) - .arg(qsl(MACRO_TO_STRING(TDESKTOP_LAUNCHER_BASENAME))); - - LOG(("SNAP Environment detected, " - "launcher filename is %1.desktop") - .arg(launcherBasename)); - } else { - launcherBasename = - qsl(MACRO_TO_STRING(TDESKTOP_LAUNCHER_BASENAME)); + if (!InSnap()) { + return qsl(MACRO_TO_STRING(TDESKTOP_LAUNCHER_BASENAME)); } - return launcherBasename; + const auto snapNameKey = + qEnvironmentVariableIsSet("SNAP_INSTANCE_NAME") + ? "SNAP_INSTANCE_NAME" + : "SNAP_NAME"; + + const auto result = qsl("%1_%2") + .arg(QString::fromLatin1(snapNameKey)) + .arg(cExeName()); + + LOG(("SNAP Environment detected, launcher filename is %1.desktop") + .arg(result)); + + return result; }(); return LauncherBasename; diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 7a14e8c45..333b45199 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -92,6 +92,7 @@ parts: - -DTDESKTOP_API_ID=611335 - -DTDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c - -DDESKTOP_APP_USE_PACKAGED_FONTS=OFF + - -DDESKTOP_APP_USE_PACKAGED_GSL=OFF - -DDESKTOP_APP_USE_PACKAGED_EXPECTED=OFF - -DDESKTOP_APP_USE_PACKAGED_RLOTTIE=OFF - -DTDESKTOP_USE_PACKAGED_TGVOIP=OFF @@ -115,7 +116,6 @@ parts: - cmake - desktop-qt5 - enchant - - gsl - range-v3 - xxhash @@ -205,15 +205,6 @@ parts: - --enable-relocatable prime: [-./bin/*] - gsl: - source: https://github.com/microsoft/GSL.git - source-depth: 1 - source-tag: v2.1.0 - plugin: cmake - configflags: - - -DGSL_TEST=OFF - prime: [-./*] - range-v3: source: https://github.com/ericniebler/range-v3.git source-depth: 1 From 07cc05f62e6381cfff535c1468272803fb65a308 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 7 Feb 2020 13:34:24 +0400 Subject: [PATCH 007/140] Fix loading thumbnails in videos in albums. Once more fixes #6332. --- Telegram/SourceFiles/history/view/media/history_view_gif.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 5dc6ba35c..3b584aba2 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -1120,6 +1120,9 @@ void Gif::validateGroupedCache( && thumb->height() < kUseNonBlurredThreshold)); if (good && !useGood) { good->load({}); + if (!useThumb) { + _data->loadThumbnail(_realParent->fullId()); + } } const auto loadLevel = useGood ? 3 : useThumb ? 2 : image ? 1 : 0; From 770678e32a2f5a443676574d21cc1a54a090aa3b Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 10 Feb 2020 15:58:58 +0400 Subject: [PATCH 008/140] Fix crash in updates handling. --- Telegram/SourceFiles/mainwidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4dfd75199..31525f415 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3807,8 +3807,8 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { : nullptr; }; if (const auto id = owner.messageIdByRandomId(randomId)) { - if (const auto local = owner.message(id); - local->isScheduled()) { + const auto local = owner.message(id); + if (local && local->isScheduled()) { owner.scheduledMessages().sendNowSimpleMessage(d, local); } } From 093c2887c3755f19d77d767903c00e89916be682 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 10 Feb 2020 18:45:23 +0400 Subject: [PATCH 009/140] Fix PiP on multi-monitor setup. --- Telegram/SourceFiles/media/view/media_view_pip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp index 040561f08..cba1ecf92 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp @@ -47,7 +47,7 @@ constexpr auto kMsInSecond = 1000; [[nodiscard]] QRect ScreenFromPosition(QPoint point) { const auto screen = [&]() -> QScreen* { for (const auto screen : QGuiApplication::screens()) { - if (screen->virtualGeometry().contains(point)) { + if (screen->geometry().contains(point)) { return screen; } } From fd8ae60dc1938cf001655fc75e07771c43b3df73 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 10 Feb 2020 19:28:41 +0400 Subject: [PATCH 010/140] Change show order of MainWindow/OverlayWindow. Fixes #6804. --- Telegram/SourceFiles/window/main_window.cpp | 32 +++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index a6cb8761e..7e160d4c0 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -392,14 +392,18 @@ void MainWindow::initSize() { auto position = cWindowPos(); DEBUG_LOG(("Window Pos: Initializing first %1, %2, %3, %4 (maximized %5)").arg(position.x).arg(position.y).arg(position.w).arg(position.h).arg(Logs::b(position.maximized))); - auto avail = QDesktopWidget().availableGeometry(); + const auto primaryScreen = QGuiApplication::primaryScreen(); + auto geometryScreen = primaryScreen; + const auto available = primaryScreen + ? primaryScreen->availableGeometry() + : QRect(0, 0, st::windowDefaultWidth, st::windowDefaultHeight); bool maximized = false; - auto geom = QRect( - avail.x() + std::max( - (avail.width() - st::windowDefaultWidth) / 2, + auto geometry = QRect( + available.x() + std::max( + (available.width() - st::windowDefaultWidth) / 2, 0), - avail.y() + std::max( - (avail.height() - st::windowDefaultHeight) / 2, + available.y() + std::max( + (available.height() - st::windowDefaultHeight) / 2, 0), st::windowDefaultWidth, st::windowDefaultHeight); @@ -420,7 +424,8 @@ void MainWindow::initSize() { if (position.x + st::windowMinWidth <= screenGeometry.x() + screenGeometry.width() && position.y + st::windowMinHeight <= screenGeometry.y() + screenGeometry.height()) { DEBUG_LOG(("Window Pos: Resulting geometry is %1, %2, %3, %4").arg(position.x).arg(position.y).arg(position.w).arg(position.h)); - geom = QRect(position.x, position.y, position.w, position.h); + geometry = QRect(position.x, position.y, position.w, position.h); + geometryScreen = screen; } } break; @@ -428,8 +433,17 @@ void MainWindow::initSize() { } maximized = position.maximized; } - DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4").arg(geom.x()).arg(geom.y()).arg(geom.width()).arg(geom.height())); - setGeometry(geom); + DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4").arg(geometry.x()).arg(geometry.y()).arg(geometry.width()).arg(geometry.height())); + setGeometry(geometry); + if (geometryScreen != primaryScreen) { + // In case screen DPI changed we show the window now, + // so that when we call setGeometry() once again after + // make_unique it already + // has adjusted by dpi geometry saved in QWidget. + // + // Somehow should fix https://github.com/telegramdesktop/tdesktop/issues/6804 + show(); + } } void MainWindow::positionUpdated() { From a0e7ef61fcf124e1667655680db33cd6d19bd026 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 10 Feb 2020 19:30:09 +0400 Subject: [PATCH 011/140] Update submodules. --- Telegram/lib_lottie | 2 +- Telegram/lib_ui | 2 +- cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Telegram/lib_lottie b/Telegram/lib_lottie index 2d75b1a35..17b6a6d53 160000 --- a/Telegram/lib_lottie +++ b/Telegram/lib_lottie @@ -1 +1 @@ -Subproject commit 2d75b1a35a984f2a0379acbd0869b50b66acdf3c +Subproject commit 17b6a6d53252b3e3ff02b113e352c152bd697896 diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 628d3b9ab..44c463368 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 628d3b9ab6443acd352617ac78cc3131ba41dbbc +Subproject commit 44c46336847a8d8ece3fb00301875af58ca69bf4 diff --git a/cmake b/cmake index 4efeb76e0..8bc157ce0 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 4efeb76e0c1a8b9e1dfc6b830e57a9a2426b0f0d +Subproject commit 8bc157ce0388ec74e4ab31602475c3bdc390f452 From e62f727135f57c557f67c13c766e70d8cc9ae704 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Mon, 10 Feb 2020 18:19:38 +0400 Subject: [PATCH 012/140] Fix creating of autostart launcher in snap --- .../platform/linux/specific_linux.cpp | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 0cfe83ef6..e757bd9b4 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -43,6 +43,7 @@ using Platform::File::internal::EscapeShell; namespace { constexpr auto kDesktopFile = ":/misc/telegramdesktop.desktop"_cs; +constexpr auto kSnapLauncherDir = "/var/lib/snapd/desktop/applications/"_cs; bool XDGDesktopPortalPresent = false; @@ -125,19 +126,25 @@ bool GenerateDesktopFile(const QString &targetPath, const QString &args) { DEBUG_LOG(("App Info: placing .desktop file to %1").arg(targetPath)); if (!QDir(targetPath).exists()) QDir().mkpath(targetPath); + const auto sourceFile = [&] { + if (InSnap()) { + return kSnapLauncherDir.utf16() + GetLauncherFilename(); + } else { + return kDesktopFile.utf16(); + } + }(); + const auto targetFile = targetPath + GetLauncherFilename(); QString fileText; - QFile source(kDesktopFile.utf16()); + QFile source(sourceFile); if (source.open(QIODevice::ReadOnly)) { QTextStream s(&source); fileText = s.readAll(); source.close(); } else { - LOG(("App Error: Could not open '%1' for read") - .arg(kDesktopFile.utf16())); - + LOG(("App Error: Could not open '%1' for read").arg(sourceFile)); return false; } @@ -540,10 +547,19 @@ void psAutoStart(bool start, bool silent) { SandboxAutostart(start); #endif } else { - const auto autostart = - QStandardPaths::writableLocation( - QStandardPaths::GenericConfigLocation) - + qsl("/autostart/"); + const auto autostart = [&] { + if (InSnap()) { + QDir realHomeDir(home); + realHomeDir.cd(qsl("../../..")); + + return realHomeDir + .absoluteFilePath(qsl(".config/autostart/")); + } else { + return QStandardPaths::writableLocation( + QStandardPaths::GenericConfigLocation) + + qsl("/autostart/"); + } + }(); if (start) { GenerateDesktopFile(autostart, qsl("-autostart")); From 38bef584e1d9dfb0d285fa892ad7e732e8fc05eb Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 10 Feb 2020 19:49:10 +0400 Subject: [PATCH 013/140] Beta version 1.9.11. - Bug fixes and other minor improvements. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 4 ++-- Telegram/build/version | 8 ++++---- changelog.txt | 4 ++++ 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 1cc443d70..00338a6c0 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.11.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index c90cffb4b..baa123af4 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,10,0 - PRODUCTVERSION 1,9,10,0 + FILEVERSION 1,9,11,0 + PRODUCTVERSION 1,9,11,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.10.0" + VALUE "FileVersion", "1.9.11.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.10.0" + VALUE "ProductVersion", "1.9.11.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index aa37644c2..d9ed70e10 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,10,0 - PRODUCTVERSION 1,9,10,0 + FILEVERSION 1,9,11,0 + PRODUCTVERSION 1,9,11,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.10.0" + VALUE "FileVersion", "1.9.11.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.10.0" + VALUE "ProductVersion", "1.9.11.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index e920ec29f..86286e6fb 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009010; -constexpr auto AppVersionStr = "1.9.10"; +constexpr auto AppVersion = 1009011; +constexpr auto AppVersionStr = "1.9.11"; constexpr auto AppBetaVersion = true; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index bd2a78228..69d0e84f5 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009010 +AppVersion 1009011 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.10 -AppVersionStr 1.9.10 +AppVersionStrSmall 1.9.11 +AppVersionStr 1.9.11 BetaChannel 1 AlphaVersion 0 -AppVersionOriginal 1.9.10.beta +AppVersionOriginal 1.9.11.beta diff --git a/changelog.txt b/changelog.txt index 31099cc48..10ca3198f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +1.9.11 beta (10.02.20) + +- Bug fixes and other minor improvements. + 1.9.10 beta (05.02.20) - Switch to the Picture-in-Picture mode to watch your video in a small window. From 9c562931a2f0bf743553dac17f6962acbcfc81ed Mon Sep 17 00:00:00 2001 From: Kirsan <17767561+kirsan31@users.noreply.github.com> Date: Sat, 8 Feb 2020 21:45:38 +0300 Subject: [PATCH 014/140] Respect user settings "Send by ..." for: forward dialog send file dialog edit caption dialog notification replay schedule messages new channel dialog group description edit dialog create poll dialog rate call dialog report bot dialog support mode --- Telegram/SourceFiles/boxes/add_contact_box.cpp | 1 + Telegram/SourceFiles/boxes/create_poll_box.cpp | 1 + Telegram/SourceFiles/boxes/edit_caption_box.cpp | 2 +- Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp | 1 + Telegram/SourceFiles/boxes/rate_call_box.cpp | 2 +- Telegram/SourceFiles/boxes/report_box.cpp | 3 ++- Telegram/SourceFiles/boxes/send_files_box.cpp | 2 +- Telegram/SourceFiles/boxes/share_box.cpp | 1 + .../SourceFiles/history/view/history_view_compose_controls.cpp | 1 + Telegram/SourceFiles/support/support_helper.cpp | 2 +- Telegram/SourceFiles/window/notifications_manager_default.cpp | 2 +- 11 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index 06e10fc37..f303c4b93 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -494,6 +494,7 @@ void GroupInfoBox::prepare() { _description->setInstantReplaces(Ui::InstantReplaces::Default()); _description->setInstantReplacesEnabled( _navigation->session().settings().replaceEmojiValue()); + _description->setSubmitSettings(_navigation->session().settings().sendSubmitWay()); connect(_description, &Ui::InputField::resized, [=] { descriptionResized(); }); connect(_description, &Ui::InputField::submitted, [=] { submit(); }); diff --git a/Telegram/SourceFiles/boxes/create_poll_box.cpp b/Telegram/SourceFiles/boxes/create_poll_box.cpp index 040f5fd09..6b11472b9 100644 --- a/Telegram/SourceFiles/boxes/create_poll_box.cpp +++ b/Telegram/SourceFiles/boxes/create_poll_box.cpp @@ -767,6 +767,7 @@ not_null CreatePollBox::setupQuestion( st::createPollFieldPadding); InitField(getDelegate()->outerContainer(), question, _session); question->setMaxLength(kQuestionLimit + kErrorLimit); + question->setSubmitSettings(_session->settings().sendSubmitWay()); const auto warning = CreateWarningLabel( container, diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index dd20abb01..f00f74c3b 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -260,7 +260,7 @@ EditCaptionBox::EditCaptionBox( tr::lng_photo_caption(), editData); _field->setMaxLength(Global::CaptionLengthMax()); - _field->setSubmitSettings(Ui::InputField::SubmitSettings::Both); + _field->setSubmitSettings(_controller->session().settings().sendSubmitWay()); _field->setInstantReplaces(Ui::InstantReplaces::Default()); _field->setInstantReplacesEnabled( _controller->session().settings().replaceEmojiValue()); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index 7dd7e538f..4732f50f6 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -500,6 +500,7 @@ object_ptr Controller::createDescriptionEdit() { result->entity()->setInstantReplaces(Ui::InstantReplaces::Default()); result->entity()->setInstantReplacesEnabled( _peer->session().settings().replaceEmojiValue()); + result->entity()->setSubmitSettings(_peer->session().settings().sendSubmitWay()); Ui::Emoji::SuggestionsController::Init( _wrap->window(), result->entity(), diff --git a/Telegram/SourceFiles/boxes/rate_call_box.cpp b/Telegram/SourceFiles/boxes/rate_call_box.cpp index 85294a3fe..e1c97e6e8 100644 --- a/Telegram/SourceFiles/boxes/rate_call_box.cpp +++ b/Telegram/SourceFiles/boxes/rate_call_box.cpp @@ -85,7 +85,7 @@ void RateCallBox::ratingChanged(int value) { Ui::InputField::Mode::MultiLine, tr::lng_call_rate_comment()); _comment->show(); - _comment->setSubmitSettings(Ui::InputField::SubmitSettings::Both); + _comment->setSubmitSettings(_session->settings().sendSubmitWay()); _comment->setMaxLength(kRateCallCommentLengthMax); _comment->resize(width() - (st::callRatingPadding.left() + st::callRatingPadding.right()), _comment->height()); diff --git a/Telegram/SourceFiles/boxes/report_box.cpp b/Telegram/SourceFiles/boxes/report_box.cpp index 28697df52..ff95cc5aa 100644 --- a/Telegram/SourceFiles/boxes/report_box.cpp +++ b/Telegram/SourceFiles/boxes/report_box.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "data/data_peer.h" +#include "main/main_session.h" #include "boxes/confirm_box.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" @@ -106,7 +107,7 @@ void ReportBox::reasonChanged(Reason reason) { Ui::InputField::Mode::MultiLine, tr::lng_report_reason_description()); _reasonOtherText->show(); - _reasonOtherText->setSubmitSettings(Ui::InputField::SubmitSettings::Both); + _reasonOtherText->setSubmitSettings(_peer->session().settings().sendSubmitWay()); _reasonOtherText->setMaxLength(kReportReasonLengthMax); _reasonOtherText->resize(width() - (st::boxPadding.left() + st::boxOptionListPadding.left() + st::boxPadding.right()), _reasonOtherText->height()); diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 04376241a..ec573c695 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -2046,7 +2046,7 @@ void SendFilesBox::applyAlbumOrder() { void SendFilesBox::setupCaption() { _caption->setMaxLength(Global::CaptionLengthMax()); - _caption->setSubmitSettings(Ui::InputField::SubmitSettings::Both); + _caption->setSubmitSettings(_controller->session().settings().sendSubmitWay()); connect(_caption, &Ui::InputField::resized, [=] { captionResized(); }); diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index 1608c8557..9719bee0b 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -206,6 +206,7 @@ void ShareBox::prepareCommentField() { field->setMarkdownReplacesEnabled(rpl::single(true)); field->setEditLinkCallback( DefaultEditLinkCallback(&_navigation->session(), field)); + field->setSubmitSettings(_navigation->session().settings().sendSubmitWay()); InitSpellchecker(&_navigation->session(), field); Ui::SendPendingMoveResizeEvents(_comment); diff --git a/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp index b6c27a34e..20d3ba4cb 100644 --- a/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp @@ -201,6 +201,7 @@ void ComposeControls::init() { void ComposeControls::initField() { _field->setMaxHeight(st::historyComposeFieldMaxHeight); + _field->setSubmitSettings(_window->session().settings().sendSubmitWay()); //Ui::Connect(_field, &Ui::InputField::submitted, [=] { send(); }); Ui::Connect(_field, &Ui::InputField::cancelled, [=] { escape(); }); //Ui::Connect(_field, &Ui::InputField::tabbed, [=] { fieldTabbed(); }); diff --git a/Telegram/SourceFiles/support/support_helper.cpp b/Telegram/SourceFiles/support/support_helper.cpp index 00d3cf6dc..79010e8b4 100644 --- a/Telegram/SourceFiles/support/support_helper.cpp +++ b/Telegram/SourceFiles/support/support_helper.cpp @@ -77,7 +77,7 @@ EditInfoBox::EditInfoBox( text) , _submit(std::move(submit)) { _field->setMaxLength(kMaxSupportInfoLength); - _field->setSubmitSettings(Ui::InputField::SubmitSettings::Both); + _field->setSubmitSettings(session->settings().sendSubmitWay()); _field->setInstantReplaces(Ui::InstantReplaces::Default()); _field->setInstantReplacesEnabled( session->settings().replaceEmojiValue()); diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index b70b25fe3..288f03419 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -858,7 +858,7 @@ void Notification::showReplyField() { _replyArea->show(); _replyArea->setFocus(); _replyArea->setMaxLength(MaxMessageSize); - _replyArea->setSubmitSettings(Ui::InputField::SubmitSettings::Both); + _replyArea->setSubmitSettings(_item->history()->session().settings().sendSubmitWay()); _replyArea->setInstantReplaces(Ui::InstantReplaces::Default()); _replyArea->setInstantReplacesEnabled( _item->history()->session().settings().replaceEmojiValue()); From 4fececb94f97d39cb3368ea983f173a7bd05990e Mon Sep 17 00:00:00 2001 From: Kirsan <17767561+kirsan31@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:19:32 +0300 Subject: [PATCH 015/140] Revert changes to notification replay. And replace user settings with Both (Enter and Ctrl+Enter) to polls. --- Telegram/SourceFiles/boxes/create_poll_box.cpp | 2 +- Telegram/SourceFiles/window/notifications_manager_default.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/boxes/create_poll_box.cpp b/Telegram/SourceFiles/boxes/create_poll_box.cpp index 6b11472b9..510b91bea 100644 --- a/Telegram/SourceFiles/boxes/create_poll_box.cpp +++ b/Telegram/SourceFiles/boxes/create_poll_box.cpp @@ -767,7 +767,7 @@ not_null CreatePollBox::setupQuestion( st::createPollFieldPadding); InitField(getDelegate()->outerContainer(), question, _session); question->setMaxLength(kQuestionLimit + kErrorLimit); - question->setSubmitSettings(_session->settings().sendSubmitWay()); + question->setSubmitSettings(Ui::InputField::SubmitSettings::Both); const auto warning = CreateWarningLabel( container, diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index 288f03419..b70b25fe3 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -858,7 +858,7 @@ void Notification::showReplyField() { _replyArea->show(); _replyArea->setFocus(); _replyArea->setMaxLength(MaxMessageSize); - _replyArea->setSubmitSettings(_item->history()->session().settings().sendSubmitWay()); + _replyArea->setSubmitSettings(Ui::InputField::SubmitSettings::Both); _replyArea->setInstantReplaces(Ui::InstantReplaces::Default()); _replyArea->setInstantReplacesEnabled( _item->history()->session().settings().replaceEmojiValue()); From 5171c0bd7792998158976365474a7b9917705edf Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Tue, 11 Feb 2020 10:40:50 +0400 Subject: [PATCH 016/140] Fix crash when tray icon is disabled on macOS --- Telegram/SourceFiles/platform/mac/main_window_mac.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index 32f6ae0a5..023ab2b90 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -555,8 +555,8 @@ void MainWindow::psTrayMenuUpdated() { && trayIcon->contextMenu() != trayIconMenu) { trayIcon->setContextMenu(trayIconMenu); } - } else { - trayIcon->setContextMenu(0); + } else if (trayIcon) { + trayIcon->setContextMenu(nullptr); } } From bcd0fe38f0ff6f5a45e33c97ae1d4865e6e4a998 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 11 Feb 2020 13:01:08 +0400 Subject: [PATCH 017/140] Fix invisible passcode field. Regression was introduced in fd8ae60dc. --- Telegram/SourceFiles/core/application.cpp | 6 ++---- Telegram/SourceFiles/mainwindow.cpp | 1 + .../SourceFiles/platform/win/main_window_win.cpp | 4 ---- Telegram/SourceFiles/window/main_window.cpp | 9 --------- .../SourceFiles/window/window_lock_widgets.cpp | 14 ++++++++------ Telegram/SourceFiles/window/window_lock_widgets.h | 1 + 6 files changed, 12 insertions(+), 23 deletions(-) diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 734850ab2..ae0213791 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -207,10 +207,6 @@ void Application::run() { _window = std::make_unique(&activeAccount()); - const auto currentGeometry = _window->widget()->geometry(); - _mediaView = std::make_unique(); - _window->widget()->setGeometry(currentGeometry); - QCoreApplication::instance()->installEventFilter(this); connect( static_cast(QCoreApplication::instance()), @@ -242,6 +238,8 @@ void Application::run() { DEBUG_LOG(("Application Info: showing.")); _window->firstShow(); + _mediaView = std::make_unique(); + if (!locked() && cStartToSettings()) { _window->showSettings(); } diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index b404807dc..84113702e 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -194,6 +194,7 @@ void MainWindow::setupPasscodeLock() { if (animated) { _passcodeLock->showAnimated(bg); } else { + _passcodeLock->showFinished(); setInnerFocus(); } } diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index d69ca9a38..2dffbccfb 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -833,12 +833,8 @@ void MainWindow::psFirstShow() { if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) { hide(); - } else { - show(); } showShadows = false; - } else { - show(); } setPositionInited(); diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index 7e160d4c0..b608c4d3a 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -435,15 +435,6 @@ void MainWindow::initSize() { } DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4").arg(geometry.x()).arg(geometry.y()).arg(geometry.width()).arg(geometry.height())); setGeometry(geometry); - if (geometryScreen != primaryScreen) { - // In case screen DPI changed we show the window now, - // so that when we call setGeometry() once again after - // make_unique it already - // has adjusted by dpi geometry saved in QWidget. - // - // Somehow should fix https://github.com/telegramdesktop/tdesktop/issues/6804 - show(); - } } void MainWindow::positionUpdated() { diff --git a/Telegram/SourceFiles/window/window_lock_widgets.cpp b/Telegram/SourceFiles/window/window_lock_widgets.cpp index 8f3af9398..6489273b8 100644 --- a/Telegram/SourceFiles/window/window_lock_widgets.cpp +++ b/Telegram/SourceFiles/window/window_lock_widgets.cpp @@ -69,15 +69,17 @@ void LockWidget::showAnimated(const QPixmap &bgAnimCache, bool back) { void LockWidget::animationCallback() { update(); if (!_a_show.animating()) { - showChildren(); - _window->widget()->setInnerFocus(); - - Ui::showChatsList(); - - _cacheUnder = _cacheOver = QPixmap(); + showFinished(); } } +void LockWidget::showFinished() { + showChildren(); + _window->widget()->setInnerFocus(); + Ui::showChatsList(); + _cacheUnder = _cacheOver = QPixmap(); +} + void LockWidget::paintEvent(QPaintEvent *e) { Painter p(this); diff --git a/Telegram/SourceFiles/window/window_lock_widgets.h b/Telegram/SourceFiles/window/window_lock_widgets.h index 9e6d83400..848fbafd8 100644 --- a/Telegram/SourceFiles/window/window_lock_widgets.h +++ b/Telegram/SourceFiles/window/window_lock_widgets.h @@ -32,6 +32,7 @@ public: virtual void setInnerFocus(); void showAnimated(const QPixmap &bgAnimCache, bool back = false); + void showFinished(); protected: void paintEvent(QPaintEvent *e) override; From 3574a9c8743c4d31d94e6573f8f2f952e993f6e6 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Tue, 11 Feb 2020 12:54:13 +0400 Subject: [PATCH 018/140] Fix lost qgetenv in GetLauncherBasename --- Telegram/SourceFiles/platform/linux/specific_linux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index e757bd9b4..b83ddd0c7 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -281,7 +281,7 @@ QString GetLauncherBasename() { : "SNAP_NAME"; const auto result = qsl("%1_%2") - .arg(QString::fromLatin1(snapNameKey)) + .arg(QString::fromLatin1(qgetenv(snapNameKey))) .arg(cExeName()); LOG(("SNAP Environment detected, launcher filename is %1.desktop") From 75de65564206d7ccfd9aba631be55ae90916aefc Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 11 Feb 2020 13:28:53 +0400 Subject: [PATCH 019/140] Fix #6804 once again. --- Telegram/SourceFiles/core/application.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index ae0213791..6d2ea38a2 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -238,7 +238,9 @@ void Application::run() { DEBUG_LOG(("Application Info: showing.")); _window->firstShow(); + const auto currentGeometry = _window->widget()->geometry(); _mediaView = std::make_unique(); + _window->widget()->setGeometry(currentGeometry); if (!locked() && cStartToSettings()) { _window->showSettings(); From 3c5f8d08adcbc574028547217f2c4093e997bfc5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 11 Feb 2020 14:12:42 +0400 Subject: [PATCH 020/140] Fix radial animations in emoji download. --- .../chat_helpers/emoji_sets_manager.cpp | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index ad1f896fc..03af31483 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -127,6 +127,7 @@ private: void setupHandler(); void load(); void radialAnimationCallback(crl::time now); + void updateLoadingToFinished(); int _id = 0; bool _switching = false; @@ -152,6 +153,12 @@ int GetDownloadSize(int id) { return ranges::find(sets, id, &Set::id)->size; } +[[nodiscard]] float64 CountProgress(not_null loading) { + return (loading->size > 0) + ? (loading->already / float64(loading->size)) + : 0.; +} + MTP::DedicatedLoader::Location GetDownloadLocation(int id) { constexpr auto kUsername = "tdhbcfiles"; const auto sets = Sets(); @@ -379,6 +386,9 @@ void Row::paintPreview(Painter &p) const { } void Row::paintRadio(Painter &p) { + if (_loading && !_loading->animating()) { + _loading = nullptr; + } const auto loading = _loading ? _loading->computeState() : Ui::RadialState{ 0., 0, FullArcLength }; @@ -580,14 +590,20 @@ void Row::setupPreview(const Set &set) { } } +void Row::updateLoadingToFinished() { + _loading->update( + _state.current().is() ? 0. : 1., + true, + crl::now()); +} + void Row::radialAnimationCallback(crl::time now) { const auto updated = [&] { const auto state = _state.current(); if (const auto loading = base::get_if(&state)) { - const auto progress = (loading->size > 0) - ? (loading->already / float64(loading->size)) - : 0.; - return _loading->update(progress, false, now); + return _loading->update(CountProgress(loading), false, now); + } else { + updateLoadingToFinished(); } return false; }(); @@ -636,15 +652,9 @@ void Row::setupAnimation() { if (loading && !_loading) { _loading = std::make_unique( [=](crl::time now) { radialAnimationCallback(now); }); - const auto progress = (loading->size > 0) - ? (loading->already / float64(loading->size)) - : 0.; - _loading->start(progress); + _loading->start(CountProgress(loading)); } else if (!loading && _loading) { - _loading->update( - _state.current().is() ? 0. : 1., - true, - crl::now()); + updateLoadingToFinished(); } }, lifetime()); From 356e3c690730105e9809e6952f87bf39eb337960 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 11 Feb 2020 16:00:04 +0400 Subject: [PATCH 021/140] Enable night mode by default on Mac App Store. --- Telegram/SourceFiles/storage/localstorage.cpp | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index fa8bf75fc..d1182ab45 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_drafts.h" #include "data/data_user.h" #include "boxes/send_files_box.h" +#include "base/platform/base_platform_info.h" #include "ui/widgets/input_fields.h" #include "ui/emoji_config.h" #include "export/export_settings.h" @@ -2049,7 +2050,10 @@ bool _readOldMtpData(bool remove, ReadSettingsContext &context) { } void _writeUserSettings() { - if (_readingUserSettings) { + if (!_userWorking()) { + LOG(("App Error: attempt to write user settings too early!")); + return; + } else if (_readingUserSettings) { LOG(("App Error: attempt to write settings while reading them!")); return; } @@ -2573,6 +2577,7 @@ void finish() { } void InitialLoadTheme(); +bool ApplyDefaultNightMode(); void readLangPack(); void start() { @@ -2592,7 +2597,10 @@ void start() { _readOldMtpData(false, context); // needed further in _readMtpData applyReadContext(std::move(context)); - return writeSettings(); + if (!ApplyDefaultNightMode()) { + writeSettings(); + } + return; } LOG(("App Info: reading settings...")); @@ -4372,6 +4380,20 @@ void InitialLoadTheme() { } } +bool ApplyDefaultNightMode() { + const auto NightByDefault = Platform::IsMacStoreBuild(); + if (!NightByDefault + || Window::Theme::IsNightMode() + || _themeKeyDay + || _themeKeyNight + || _themeKeyLegacy) { + return false; + } + Window::Theme::ToggleNightMode(); + Window::Theme::KeepApplied(); + return true; +} + Window::Theme::Saved readThemeAfterSwitch() { const auto key = Window::Theme::IsNightMode() ? _themeKeyNight From 1210ba37c42527c75d94961ca6a3d01d53ef615d Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 11 Feb 2020 19:10:09 +0400 Subject: [PATCH 022/140] Version 1.9.12. - Switch to Picture-in-Picture mode to watch your video in a small window while doing something else. - Change playback speed in the '...' menu when watching videos. - Rotate photos and videos in the media viewer using the rotate button in the bottom right corner. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 6 +++--- Telegram/build/version | 10 +++++----- changelog.txt | 6 ++++++ cmake | 2 +- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 00338a6c0..f6c146707 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.12.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index baa123af4..3ee39b39e 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,11,0 - PRODUCTVERSION 1,9,11,0 + FILEVERSION 1,9,12,0 + PRODUCTVERSION 1,9,12,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.11.0" + VALUE "FileVersion", "1.9.12.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.11.0" + VALUE "ProductVersion", "1.9.12.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index d9ed70e10..8d30b67d1 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,11,0 - PRODUCTVERSION 1,9,11,0 + FILEVERSION 1,9,12,0 + PRODUCTVERSION 1,9,12,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.11.0" + VALUE "FileVersion", "1.9.12.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.11.0" + VALUE "ProductVersion", "1.9.12.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 86286e6fb..f2d1480de 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009011; -constexpr auto AppVersionStr = "1.9.11"; -constexpr auto AppBetaVersion = true; +constexpr auto AppVersion = 1009012; +constexpr auto AppVersionStr = "1.9.12"; +constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 69d0e84f5..62551fae8 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009011 +AppVersion 1009012 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.11 -AppVersionStr 1.9.11 -BetaChannel 1 +AppVersionStrSmall 1.9.12 +AppVersionStr 1.9.12 +BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 1.9.11.beta +AppVersionOriginal 1.9.12 diff --git a/changelog.txt b/changelog.txt index 10ca3198f..7b046b422 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,9 @@ +1.9.12 (11.02.20) + +- Switch to Picture-in-Picture mode to watch your video in a small window while doing something else. +- Change playback speed in the '...' menu when watching videos. +- Rotate photos and videos in the media viewer using the rotate button in the bottom right corner. + 1.9.11 beta (10.02.20) - Bug fixes and other minor improvements. diff --git a/cmake b/cmake index 8bc157ce0..e86afe11f 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 8bc157ce0388ec74e4ab31602475c3bdc390f452 +Subproject commit e86afe11f8a9d7fa5f137e3b90bad32366fbc916 From 1a2b2c15c5ade505e94a005f1e002e8d951c380c Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 30 Jan 2020 10:59:58 +0300 Subject: [PATCH 023/140] Disable Wayland in Snap build. --- snap/snapcraft.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 333b45199..8e87c1b10 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -14,6 +14,8 @@ apps: environment: # Use GTK3 cursor theme, icon theme and open/save file dialogs. QT_QPA_PLATFORMTHEME: gtk3 + # Wayland support is still too bad. + DISABLE_WAYLAND: 1 plugs: - desktop - desktop-legacy From a88423a33f29adf903c16dd42f0a763ea2901694 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 12 Feb 2020 12:09:17 +0400 Subject: [PATCH 024/140] Fix bad window rendering with maximize-on-launch. I have no idea why MainWindow is ruined completely in case you call MainWindow::show, MainWindow::setWindowState(maximized) and then in the same context (without crl::on_main) create full screen viewer. --- Telegram/SourceFiles/core/application.cpp | 15 ++++++- Telegram/SourceFiles/mainwindow.cpp | 43 ++++++++++++++++++- Telegram/SourceFiles/mainwindow.h | 4 +- .../platform/linux/main_window_linux.cpp | 26 +---------- .../platform/linux/main_window_linux.h | 3 +- .../platform/mac/main_window_mac.h | 5 +-- .../platform/mac/main_window_mac.mm | 25 +---------- .../platform/win/main_window_win.cpp | 31 +++---------- .../platform/win/main_window_win.h | 3 +- Telegram/SourceFiles/window/main_window.h | 9 ++++ .../SourceFiles/window/window_controller.cpp | 4 +- .../SourceFiles/window/window_controller.h | 2 +- 12 files changed, 81 insertions(+), 89 deletions(-) diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 6d2ea38a2..f3bbacb66 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -235,13 +235,16 @@ void Application::run() { _window->setupIntro(); } } - DEBUG_LOG(("Application Info: showing.")); - _window->firstShow(); + + _window->widget()->show(); const auto currentGeometry = _window->widget()->geometry(); _mediaView = std::make_unique(); _window->widget()->setGeometry(currentGeometry); + DEBUG_LOG(("Application Info: showing.")); + _window->finishFirstShow(); + if (!locked() && cStartToSettings()) { _window->showSettings(); } @@ -274,6 +277,8 @@ void Application::showPhoto(not_null link) { } void Application::showPhoto(not_null photo, HistoryItem *item) { + Expects(_mediaView != nullptr); + _mediaView->showPhoto(photo, item); _mediaView->activateWindow(); _mediaView->setFocus(); @@ -282,12 +287,16 @@ void Application::showPhoto(not_null photo, HistoryItem *item) { void Application::showPhoto( not_null photo, not_null peer) { + Expects(_mediaView != nullptr); + _mediaView->showPhoto(photo, peer); _mediaView->activateWindow(); _mediaView->setFocus(); } void Application::showDocument(not_null document, HistoryItem *item) { + Expects(_mediaView != nullptr); + if (cUseExternalVideoPlayer() && document->isVideoFile() && document->loaded()) { @@ -302,6 +311,8 @@ void Application::showDocument(not_null document, HistoryItem *it void Application::showTheme( not_null document, const Data::CloudTheme &cloud) { + Expects(_mediaView != nullptr); + _mediaView->showTheme(document, cloud); _mediaView->activateWindow(); _mediaView->setFocus(); diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 84113702e..6e360c89d 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -130,7 +130,7 @@ void MainWindow::initHook() { Qt::QueuedConnection); } -void MainWindow::firstShow() { +void MainWindow::createTrayIconMenu() { #ifdef Q_OS_WIN trayIconMenu = new Ui::PopupMenu(nullptr); trayIconMenu->deleteOnHide(false); @@ -148,9 +148,48 @@ void MainWindow::firstShow() { trayIconMenu->addAction(tr::lng_minimize_to_tray(tr::now), this, SLOT(minimizeToTray())); trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray())); trayIconMenu->addAction(tr::lng_quit_from_tray(tr::now), this, SLOT(quitFromTray())); + + initTrayMenuHook(); +} + +void MainWindow::applyInitialWorkMode() { Global::RefWorkMode().setForced(Global::WorkMode().value(), true); - psFirstShow(); + if (cWindowPos().maximized) { + DEBUG_LOG(("Window Pos: First show, setting maximized.")); + setWindowState(Qt::WindowMaximized); + } + if (cStartInTray() + || (cLaunchMode() == LaunchModeAutoStart + && cStartMinimized() + && !Core::App().passcodeLocked())) { + const auto minimizeAndHide = [=] { + DEBUG_LOG(("Window Pos: First show, setting minimized after.")); + setWindowState(windowState() | Qt::WindowMinimized); + if (Global::WorkMode().value() == dbiwmTrayOnly + || Global::WorkMode().value() == dbiwmWindowAndTray) { + hide(); + } + }; + + if (Platform::IsLinux()) { + // If I call hide() synchronously here after show() then on Ubuntu 14.04 + // it will show a window frame with transparent window body, without content. + // And to be able to "Show from tray" one more hide() will be required. + crl::on_main(this, minimizeAndHide); + } else { + minimizeAndHide(); + } + } + setPositionInited(); +} + +void MainWindow::finishFirstShow() { + createTrayIconMenu(); + initShadows(); + applyInitialWorkMode(); + createGlobalMenu(); + firstShadowsUpdate(); updateTrayMenu(); windowDeactivateEvents( diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 11ba00c6d..4635bbea6 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -49,7 +49,7 @@ public: explicit MainWindow(not_null controller); ~MainWindow(); - void firstShow(); + void finishFirstShow(); void setupPasscodeLock(); void clearPasscodeLock(); @@ -152,9 +152,11 @@ signals: private: [[nodiscard]] bool skipTrayClick() const; + void createTrayIconMenu(); void handleTrayIconActication( QSystemTrayIcon::ActivationReason reason) override; + void applyInitialWorkMode(); void ensureLayerCreated(); void destroyLayer(); diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 63a2a5ecb..75ce5ce95 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -455,7 +455,7 @@ void MainWindow::LibsLoaded() { } } -void MainWindow::psFirstShow() { +void MainWindow::initTrayMenuHook() { const auto trayAvailable = IsSNIAvailable() || QSystemTrayIcon::isSystemTrayAvailable(); @@ -490,30 +490,6 @@ void MainWindow::psFirstShow() { LOG(("Not using Unity Launcher count.")); } #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - - show(); - if (cWindowPos().maximized) { - DEBUG_LOG(("Window Pos: First show, setting maximized.")); - setWindowState(Qt::WindowMaximized); - } - - if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) - || cStartInTray()) { - // If I call hide() synchronously here after show() then on Ubuntu 14.04 - // it will show a window frame with transparent window body, without content. - // And to be able to "Show from tray" one more hide() will be required. - crl::on_main(this, [=] { - setWindowState(Qt::WindowMinimized); - if (Global::WorkMode().value() == dbiwmTrayOnly - || Global::WorkMode().value() == dbiwmWindowAndTray) { - hide(); - } else { - show(); - } - }); - } - - setPositionInited(); } MainWindow::~MainWindow() { diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index fa175b2e1..104e8e5b6 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -24,8 +24,6 @@ class MainWindow : public Window::MainWindow { public: explicit MainWindow(not_null controller); - void psFirstShow(); - virtual QImage iconWithCounter( int size, int count, @@ -43,6 +41,7 @@ public slots: protected: void unreadCounterChangedHook() override; + void initTrayMenuHook() override; bool hasTrayIcon() const override; void workmodeUpdated(DBIWorkMode mode) override; diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.h b/Telegram/SourceFiles/platform/mac/main_window_mac.h index f02027294..f8a90c9d7 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.h +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.h @@ -23,8 +23,6 @@ class MainWindow : public Window::MainWindow { public: explicit MainWindow(not_null controller); - void psFirstShow(); - bool psFilterNativeEvent(void *event); virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0; @@ -87,14 +85,15 @@ protected: QTimer psUpdatedPositionTimer; + void initShadows() override; void closeWithoutDestroy() override; + void createGlobalMenu() override; private: friend class Private; void initTouchBar(); void hideAndDeactivate(); - void createGlobalMenu(); void updateTitleCounter(); void updateIconCounters(); diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index 023ab2b90..58927dc3c 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -663,31 +663,8 @@ void MainWindow::updateIconCounters() { } } -void MainWindow::psFirstShow() { - bool showShadows = true; - - show(); +void MainWindow::initShadows() { _private->enableShadow(winId()); - if (cWindowPos().maximized) { - DEBUG_LOG(("Window Pos: First show, setting maximized.")); - setWindowState(Qt::WindowMaximized); - } - - if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) { - setWindowState(Qt::WindowMinimized); - if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) { - hide(); - } else { - show(); - } - showShadows = false; - } else { - show(); - } - - setPositionInited(); - - createGlobalMenu(); } void MainWindow::createGlobalMenu() { diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index 2dffbccfb..4192df23f 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -808,37 +808,15 @@ void MainWindow::initHook() { psInitSysMenu(); } -Q_DECLARE_METATYPE(QMargins); -void MainWindow::psFirstShow() { +void MainWindow::initShadows() { _psShadowWindows.init(this, st::windowShadowFg->c); _shadowsWorking = true; - psUpdateMargins(); - shadowsUpdate(ShadowsChange::Hidden); - bool showShadows = true; +} - show(); - if (cWindowPos().maximized) { - DEBUG_LOG(("Window Pos: First show, setting maximized.")); - setWindowState(Qt::WindowMaximized); - } - - if (cStartInTray() - || (cLaunchMode() == LaunchModeAutoStart - && cStartMinimized() - && !Core::App().passcodeLocked())) { - DEBUG_LOG(("Window Pos: First show, setting minimized after.")); - setWindowState(windowState() | Qt::WindowMinimized); - if (Global::WorkMode().value() == dbiwmTrayOnly - || Global::WorkMode().value() == dbiwmWindowAndTray) { - hide(); - } - showShadows = false; - } - - setPositionInited(); - if (showShadows) { +void MainWindow::firstShadowsUpdate() { + if (!(windowState() & Qt::WindowMinimized) && !isHidden()) { shadowsUpdate(ShadowsChange::Moved | ShadowsChange::Resized | ShadowsChange::Shown); } } @@ -896,6 +874,7 @@ void MainWindow::updateSystemMenu(Qt::WindowState state) { } } +Q_DECLARE_METATYPE(QMargins); void MainWindow::psUpdateMargins() { if (!ps_hWnd || _inUpdateMargins) return; diff --git a/Telegram/SourceFiles/platform/win/main_window_win.h b/Telegram/SourceFiles/platform/win/main_window_win.h index 6ec9648d1..f599de881 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.h +++ b/Telegram/SourceFiles/platform/win/main_window_win.h @@ -28,7 +28,6 @@ public: HWND psHwnd() const; HMENU psMenu() const; - void psFirstShow(); void psInitSysMenu(); void updateSystemMenu(Qt::WindowState state); void psUpdateMargins(); @@ -77,6 +76,8 @@ protected: int32 screenNameChecksum(const QString &name) const override; void unreadCounterChangedHook() override; + void initShadows() override; + void firstShadowsUpdate() override; void stateChangedHook(Qt::WindowState state) override; bool hasTrayIcon() const override { diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index a8eedea57..3282483f0 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -137,6 +137,8 @@ protected: virtual void updateGlobalMenuHook() { } + virtual void initTrayMenuHook() { + } virtual bool hasTrayIcon() const { return false; } @@ -148,6 +150,13 @@ protected: virtual void updateControlsGeometry(); + virtual void createGlobalMenu() { + } + virtual void initShadows() { + } + virtual void firstShadowsUpdate() { + } + // This one is overriden in Windows for historical reasons. virtual int32 screenNameChecksum(const QString &name) const; diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index a6e4c8da9..69afd5e88 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -42,8 +42,8 @@ Controller::~Controller() { _widget.clearWidgets(); } -void Controller::firstShow() { - _widget.firstShow(); +void Controller::finishFirstShow() { + _widget.finishFirstShow(); checkThemeEditor(); } diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h index d8adfc2e6..7ce23ca04 100644 --- a/Telegram/SourceFiles/window/window_controller.h +++ b/Telegram/SourceFiles/window/window_controller.h @@ -34,7 +34,7 @@ public: return _sessionController.get(); } - void firstShow(); + void finishFirstShow(); void setupPasscodeLock(); void clearPasscodeLock(); From 0beec6e33571203206a943bd061800d236dbf6c4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 12 Feb 2020 13:03:08 +0400 Subject: [PATCH 025/140] Fix maximized window on secondary screen. --- Telegram/SourceFiles/window/main_window.cpp | 41 +++++++++++---------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index b608c4d3a..a282de86c 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -525,6 +525,7 @@ void MainWindow::savePosition(Qt::WindowState state) { if (state == Qt::WindowMaximized) { realPosition.maximized = 1; + DEBUG_LOG(("Window Pos: Saving maximized position.")); } else { auto r = geometry(); realPosition.x = r.x(); @@ -533,29 +534,29 @@ void MainWindow::savePosition(Qt::WindowState state) { realPosition.h = r.height(); realPosition.maximized = 0; realPosition.moncrc = 0; - } - DEBUG_LOG(("Window Pos: Saving position: %1, %2, %3, %4 (maximized %5)").arg(realPosition.x).arg(realPosition.y).arg(realPosition.w).arg(realPosition.h).arg(Logs::b(realPosition.maximized))); - auto centerX = realPosition.x + realPosition.w / 2; - auto centerY = realPosition.y + realPosition.h / 2; - int minDelta = 0; - QScreen *chosen = nullptr; - auto screens = QGuiApplication::screens(); - for (auto screen : QGuiApplication::screens()) { - auto delta = (screen->geometry().center() - QPoint(centerX, centerY)).manhattanLength(); - if (!chosen || delta < minDelta) { - minDelta = delta; - chosen = screen; + DEBUG_LOG(("Window Pos: Saving non-maximized position: %1, %2, %3, %4").arg(realPosition.x).arg(realPosition.y).arg(realPosition.w).arg(realPosition.h)); + + auto centerX = realPosition.x + realPosition.w / 2; + auto centerY = realPosition.y + realPosition.h / 2; + int minDelta = 0; + QScreen *chosen = nullptr; + auto screens = QGuiApplication::screens(); + for (auto screen : QGuiApplication::screens()) { + auto delta = (screen->geometry().center() - QPoint(centerX, centerY)).manhattanLength(); + if (!chosen || delta < minDelta) { + minDelta = delta; + chosen = screen; + } + } + if (chosen) { + auto screenGeometry = chosen->geometry(); + DEBUG_LOG(("Window Pos: Screen found, geometry: %1, %2, %3, %4").arg(screenGeometry.x()).arg(screenGeometry.y()).arg(screenGeometry.width()).arg(screenGeometry.height())); + realPosition.x -= screenGeometry.x(); + realPosition.y -= screenGeometry.y(); + realPosition.moncrc = screenNameChecksum(chosen->name()); } } - if (chosen) { - auto screenGeometry = chosen->geometry(); - DEBUG_LOG(("Window Pos: Screen found, geometry: %1, %2, %3, %4").arg(screenGeometry.x()).arg(screenGeometry.y()).arg(screenGeometry.width()).arg(screenGeometry.height())); - realPosition.x -= screenGeometry.x(); - realPosition.y -= screenGeometry.y(); - realPosition.moncrc = screenNameChecksum(chosen->name()); - } - if (realPosition.w >= st::windowMinWidth && realPosition.h >= st::windowMinHeight) { if (realPosition.x != savedPosition.x || realPosition.y != savedPosition.y From 6bbcec0c23d0f34a4ece450c3e699a5adc672aac Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 12 Feb 2020 13:03:46 +0400 Subject: [PATCH 026/140] Version 1.9.13. - Bug fixes and other minor improvements. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 4 ++-- Telegram/build/version | 8 ++++---- changelog.txt | 4 ++++ 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index f6c146707..198504e2b 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.13.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 3ee39b39e..76f3ed661 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,12,0 - PRODUCTVERSION 1,9,12,0 + FILEVERSION 1,9,13,0 + PRODUCTVERSION 1,9,13,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.12.0" + VALUE "FileVersion", "1.9.13.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.12.0" + VALUE "ProductVersion", "1.9.13.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 8d30b67d1..c8771038b 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,12,0 - PRODUCTVERSION 1,9,12,0 + FILEVERSION 1,9,13,0 + PRODUCTVERSION 1,9,13,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.12.0" + VALUE "FileVersion", "1.9.13.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.12.0" + VALUE "ProductVersion", "1.9.13.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index f2d1480de..2d2d10843 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009012; -constexpr auto AppVersionStr = "1.9.12"; +constexpr auto AppVersion = 1009013; +constexpr auto AppVersionStr = "1.9.13"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 62551fae8..6e6f97816 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009012 +AppVersion 1009013 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.12 -AppVersionStr 1.9.12 +AppVersionStrSmall 1.9.13 +AppVersionStr 1.9.13 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 1.9.12 +AppVersionOriginal 1.9.13 diff --git a/changelog.txt b/changelog.txt index 7b046b422..ce065fcfc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +1.9.13 (12.02.20) + +- Bug fixes and other minor improvements. + 1.9.12 (11.02.20) - Switch to Picture-in-Picture mode to watch your video in a small window while doing something else. From 5c079b0bbdb335109f73d9bbd653904bab88a9e1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 12 Feb 2020 19:36:05 +0400 Subject: [PATCH 027/140] Add additional QR code login debug logs. --- Telegram/SourceFiles/intro/intro_phone.cpp | 6 +++++- Telegram/SourceFiles/intro/intro_start.cpp | 1 + Telegram/SourceFiles/main/main_app_config.cpp | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/intro/intro_phone.cpp b/Telegram/SourceFiles/intro/intro_phone.cpp index c7f70c521..e689f8726 100644 --- a/Telegram/SourceFiles/intro/intro_phone.cpp +++ b/Telegram/SourceFiles/intro/intro_phone.cpp @@ -70,9 +70,11 @@ void PhoneWidget::setupQrLogin() { ) | rpl::then( account().appConfig().refreshed() ) | rpl::map([=] { - return account().appConfig().get( + const auto result = account().appConfig().get( "qr_login_code", "disabled"); + DEBUG_LOG(("PhoneWidget.qr_login_code: %1").arg(result)); + return result; }) | rpl::filter([](const QString &value) { return (value != "disabled"); }) | rpl::take(1) | rpl::start_with_next([=] { @@ -81,6 +83,8 @@ void PhoneWidget::setupQrLogin() { tr::lng_phone_to_qr(tr::now)); qrLogin->show(); + DEBUG_LOG(("PhoneWidget.qrLogin link created and shown.")); + rpl::combine( sizeValue(), qrLogin->widthValue() diff --git a/Telegram/SourceFiles/intro/intro_start.cpp b/Telegram/SourceFiles/intro/intro_start.cpp index 53ed00685..38eadab37 100644 --- a/Telegram/SourceFiles/intro/intro_start.cpp +++ b/Telegram/SourceFiles/intro/intro_start.cpp @@ -34,6 +34,7 @@ void StartWidget::submit() { const auto qrLogin = account().appConfig().get( "qr_login_code", "disabled"); + DEBUG_LOG(("qr_login_code: %1").arg(qrLogin)); if (qrLogin == "primary") { goNext(); } else { diff --git a/Telegram/SourceFiles/main/main_app_config.cpp b/Telegram/SourceFiles/main/main_app_config.cpp index 0f09e2ea0..08254a15a 100644 --- a/Telegram/SourceFiles/main/main_app_config.cpp +++ b/Telegram/SourceFiles/main/main_app_config.cpp @@ -47,6 +47,7 @@ void AppConfig::refresh() { _data.emplace_or_assign(qs(data.vkey()), data.vvalue()); }); } + DEBUG_LOG(("getAppConfig result handled.")); } _refreshed.fire({}); }).fail([=](const RPCError &error) { From f5fdcc3af0a23fd671151a587b19c2a8eb4945a5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 12 Feb 2020 19:42:59 +0400 Subject: [PATCH 028/140] Enable secondary QR code login by default. --- Telegram/SourceFiles/intro/intro_phone.cpp | 2 +- Telegram/SourceFiles/intro/intro_start.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/intro/intro_phone.cpp b/Telegram/SourceFiles/intro/intro_phone.cpp index e689f8726..d31b3fea7 100644 --- a/Telegram/SourceFiles/intro/intro_phone.cpp +++ b/Telegram/SourceFiles/intro/intro_phone.cpp @@ -72,7 +72,7 @@ void PhoneWidget::setupQrLogin() { ) | rpl::map([=] { const auto result = account().appConfig().get( "qr_login_code", - "disabled"); + "[not-set]"); DEBUG_LOG(("PhoneWidget.qr_login_code: %1").arg(result)); return result; }) | rpl::filter([](const QString &value) { diff --git a/Telegram/SourceFiles/intro/intro_start.cpp b/Telegram/SourceFiles/intro/intro_start.cpp index 38eadab37..0fe3cb61b 100644 --- a/Telegram/SourceFiles/intro/intro_start.cpp +++ b/Telegram/SourceFiles/intro/intro_start.cpp @@ -33,7 +33,7 @@ void StartWidget::submit() { account().destroyStaleAuthorizationKeys(); const auto qrLogin = account().appConfig().get( "qr_login_code", - "disabled"); + "[not-set]"); DEBUG_LOG(("qr_login_code: %1").arg(qrLogin)); if (qrLogin == "primary") { goNext(); From 23bab2aeb9c17e5489f822497ca370ed6f3b1647 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 12 Feb 2020 19:36:19 +0400 Subject: [PATCH 029/140] Version 1.9.13: Update libtgvoip submodule. --- Telegram/ThirdParty/libtgvoip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/ThirdParty/libtgvoip b/Telegram/ThirdParty/libtgvoip index ade4434f1..522550a1e 160000 --- a/Telegram/ThirdParty/libtgvoip +++ b/Telegram/ThirdParty/libtgvoip @@ -1 +1 @@ -Subproject commit ade4434f1c6efabecc3b548ca1f692f8d103d22a +Subproject commit 522550a1e975b17e9048d7a2ab2d5b97cfc2f5d4 From 7bf2b607f92de40fabf840e348d986509ef2c00a Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 13 Feb 2020 13:49:34 +0400 Subject: [PATCH 030/140] Return glib event loop in static builds. Regression was introduced in 3f5eaa8f0a. Fixes problem with GTK file dialog running as modal windows. Fixes #7186. --- .github/workflows/linux.yml | 3 +-- cmake | 2 +- docs/building-cmake.md | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index ef39c3a0f..f437ba48f 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,7 +31,7 @@ jobs: CMAKE_VER: "3.16.3" UPLOAD_ARTIFACT: "false" ONLY_CACHE: "false" - MANUAL_CACHING: "3" + MANUAL_CACHING: "4" DOC_PATH: "docs/building-cmake.md" steps: @@ -381,7 +381,6 @@ jobs: -system-freetype \ -fontconfig \ -no-opengl \ - -no-glib \ -no-gtk \ -static \ -openssl-linked \ diff --git a/cmake b/cmake index e86afe11f..ba9eb09bc 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit e86afe11f8a9d7fa5f137e3b90bad32366fbc916 +Subproject commit ba9eb09bc03ecb2b3c64ea1aa35ba534c8d3d5fe diff --git a/docs/building-cmake.md b/docs/building-cmake.md index d5ba75cd4..aed14aff0 100644 --- a/docs/building-cmake.md +++ b/docs/building-cmake.md @@ -256,7 +256,6 @@ Go to ***BuildPath*** and run -system-freetype \ -fontconfig \ -no-opengl \ - -no-glib \ -no-gtk \ -static \ -openssl-linked \ From 05c95a0307d4cd57077e6711393b6af019205073 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 13 Feb 2020 16:34:19 +0400 Subject: [PATCH 031/140] Fix fullscreen rotate, fix rotate phrase. --- Telegram/Resources/langs/lang.strings | 1 + .../media/view/media_view_overlay_widget.cpp | 15 ++++++++++++--- .../media/view/media_view_playback_controls.cpp | 3 ++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index ddeb6c9cb..5578b330e 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1581,6 +1581,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_mediaview_video_loading" = "Loading - {percent}"; "lng_mediaview_playback_speed" = "Playback speed"; "lng_mediaview_playback_speed_normal" = "Normal"; +"lng_mediaview_rotate_video" = "Rotate video"; "lng_theme_preview_title" = "Theme Preview"; "lng_theme_preview_generating" = "Generating color theme preview..."; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 44b4f9368..c82d7cae7 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -920,8 +920,8 @@ void OverlayWidget::resizeContentByScreenSize() { _w = _width; _h = _height; } - _x = skipWidth + (usew - _w) / 2; - _y = skipHeight + (useh - _h) / 2; + _x = (width() - _w) / 2; + _y = (height() - _h) / 2; } float64 OverlayWidget::radialProgress() const { @@ -2571,17 +2571,26 @@ void OverlayWidget::playbackControlsVolumeChangeFinished() { } void OverlayWidget::playbackControlsSpeedChanged(float64 speed) { + DEBUG_LOG(("Media playback speed: change to %1.").arg(speed)); if (_doc) { + DEBUG_LOG(("Media playback speed: %1 to settings.").arg(speed)); _doc->session().settings().setVideoPlaybackSpeed(speed); _doc->session().saveSettingsDelayed(); } if (_streamed && !videoIsGifv()) { + DEBUG_LOG(("Media playback speed: %1 to _streamed.").arg(speed)); _streamed->instance.setSpeed(speed); } } float64 OverlayWidget::playbackControlsCurrentSpeed() { - return _doc ? _doc->session().settings().videoPlaybackSpeed() : 1.; + const auto result = _doc + ? _doc->session().settings().videoPlaybackSpeed() + : 1.; + DEBUG_LOG(("Media playback speed: now %1 (doc %2)." + ).arg(result + ).arg(Logs::b(_doc != nullptr))); + return result; } void OverlayWidget::switchToPip() { diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp index 8228db670..3b57c63a6 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp @@ -223,7 +223,7 @@ void PlaybackControls::showMenu() { addSpeed(1.75); addSpeed(2.); _menu.emplace(this, st::mediaviewControlsPopupMenu); - _menu->addAction("Rotate video", [=] { + _menu->addAction(tr::lng_mediaview_rotate_video(tr::now), [=] { _delegate->playbackControlsRotate(); }); _menu->addSeparator(); @@ -235,6 +235,7 @@ void PlaybackControls::showMenu() { } void PlaybackControls::updatePlaybackSpeed(float64 speed) { + DEBUG_LOG(("Media playback speed: update to %1.").arg(speed)); _delegate->playbackControlsSpeedChanged(speed); resizeEvent(nullptr); } From 555fe70df38142120a74237664ff555fc0e963f8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 13 Feb 2020 18:39:29 +0400 Subject: [PATCH 032/140] Don't delete old localstorage file copies. --- Telegram/SourceFiles/storage/localstorage.cpp | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index d1182ab45..7f4d548a5 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -44,6 +44,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include +#ifndef Q_OS_WIN +#include +#endif // Q_OS_WIN + extern "C" { #include } // extern "C" @@ -250,28 +254,25 @@ struct FileWriteDescriptor { } // detect order of read attempts and file version - QString toTry[2]; - toTry[0] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '0'; + QString toWrite[2]; + toWrite[0] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '0'; if (options & FileOption::Safe) { - toTry[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; - QFileInfo toTry0(toTry[0]); - QFileInfo toTry1(toTry[1]); - if (toTry0.exists()) { - if (toTry1.exists()) { - QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified(); + toWrite[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; + QFileInfo toWrite0(toWrite[0]); + QFileInfo toWrite1(toWrite[1]); + if (toWrite0.exists()) { + if (toWrite1.exists()) { + QDateTime mod0 = toWrite0.lastModified(), mod1 = toWrite1.lastModified(); if (mod0 > mod1) { - qSwap(toTry[0], toTry[1]); + qSwap(toWrite[0], toWrite[1]); } } else { - qSwap(toTry[0], toTry[1]); + qSwap(toWrite[0], toWrite[1]); } - toDelete = toTry[1]; - } else if (toTry1.exists()) { - toDelete = toTry[1]; } } - file.setFileName(toTry[0]); + file.setFileName(toWrite[0]); if (file.open(QIODevice::WriteOnly)) { file.write(tdfMagic, tdfMagicLen); qint32 version = AppVersion; @@ -326,17 +327,15 @@ struct FileWriteDescriptor { md5.feed(&version, sizeof(version)); md5.feed(tdfMagic, tdfMagicLen); file.write((const char*)md5.result(), 0x10); + file.flush(); +#ifndef Q_OS_WIN + fsync(file.handle()); +#endif // Q_OS_WIN file.close(); - - if (!toDelete.isEmpty()) { - QFile::remove(toDelete); - } } QFile file; QDataStream stream; - QString toDelete; - HashMd5 md5; int32 dataSize = 0; From 3bb9e8c7ebe6e17675fea0d702bf234319af1a9a Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 14 Feb 2020 18:11:32 +0400 Subject: [PATCH 033/140] Fix power outage logout only by fsync. --- Telegram/SourceFiles/storage/localstorage.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 7f4d548a5..0ac58bec4 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -269,6 +269,9 @@ struct FileWriteDescriptor { } else { qSwap(toWrite[0], toWrite[1]); } + toDelete = toWrite[1]; + } else if (toWrite1.exists()) { + toDelete = toWrite[1]; } } @@ -332,10 +335,16 @@ struct FileWriteDescriptor { fsync(file.handle()); #endif // Q_OS_WIN file.close(); + + if (!toDelete.isEmpty()) { + QFile::remove(toDelete); + } } QFile file; QDataStream stream; + QString toDelete; + HashMd5 md5; int32 dataSize = 0; From 82aa64ca0a9818e1067794e29f10abbc0dd98343 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 15 Feb 2020 22:45:50 +0400 Subject: [PATCH 034/140] Enable third column by default in Mac App Store build. --- Telegram/SourceFiles/main/main_settings.cpp | 8 ++++++++ Telegram/SourceFiles/main/main_settings.h | 6 ++++-- Telegram/SourceFiles/window/main_window.cpp | 14 ++++++++++---- Telegram/SourceFiles/window/window.style | 2 ++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/main/main_settings.cpp b/Telegram/SourceFiles/main/main_settings.cpp index 00c24c45d..83975e9f5 100644 --- a/Telegram/SourceFiles/main/main_settings.cpp +++ b/Telegram/SourceFiles/main/main_settings.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "support/support_common.h" #include "storage/serialize_common.h" #include "boxes/send_files_box.h" +#include "base/platform/base_platform_info.h" namespace Main { namespace { @@ -38,10 +39,17 @@ Settings::Variables::Variables() , selectorTab(ChatHelpers::SelectorTab::Emoji) , floatPlayerColumn(Window::Column::Second) , floatPlayerCorner(RectPart::TopRight) +, dialogsWidthRatio(ThirdColumnByDefault() + ? kDefaultBigDialogsWidthRatio + : kDefaultDialogsWidthRatio) , sendSubmitWay(Ui::InputSubmitSettings::Enter) , supportSwitch(Support::SwitchSettings::Next) { } +bool Settings::ThirdColumnByDefault() { + return Platform::IsMacStoreBuild(); +} + QByteArray Settings::serialize() const { const auto autoDownload = _variables.autoDownload.serialize(); auto size = sizeof(qint32) * 38; diff --git a/Telegram/SourceFiles/main/main_settings.h b/Telegram/SourceFiles/main/main_settings.h index c8cedc9d4..020a8fc97 100644 --- a/Telegram/SourceFiles/main/main_settings.h +++ b/Telegram/SourceFiles/main/main_settings.h @@ -254,11 +254,14 @@ public: _variables.videoPipGeometry = geometry; } + [[nodiscard]] static bool ThirdColumnByDefault(); + private: struct Variables { Variables(); static constexpr auto kDefaultDialogsWidthRatio = 5. / 14; + static constexpr auto kDefaultBigDialogsWidthRatio = 0.275; static constexpr auto kDefaultThirdColumnWidth = 0; bool lastSeenWarningSeen = false; @@ -273,8 +276,7 @@ private: bool thirdSectionInfoEnabled = true; // per-window bool smallDialogsList = false; // per-window int thirdSectionExtendedBy = -1; // per-window - rpl::variable dialogsWidthRatio - = kDefaultDialogsWidthRatio; // per-window + rpl::variable dialogsWidthRatio; // per-window rpl::variable thirdColumnWidth = kDefaultThirdColumnWidth; // per-window Ui::InputSubmitSettings sendSubmitWay; diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index a282de86c..50b956497 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -398,15 +398,21 @@ void MainWindow::initSize() { ? primaryScreen->availableGeometry() : QRect(0, 0, st::windowDefaultWidth, st::windowDefaultHeight); bool maximized = false; + const auto initialWidth = Main::Settings::ThirdColumnByDefault() + ? st::windowBigDefaultWidth + : st::windowDefaultWidth; + const auto initialHeight = Main::Settings::ThirdColumnByDefault() + ? st::windowBigDefaultHeight + : st::windowDefaultHeight; auto geometry = QRect( available.x() + std::max( - (available.width() - st::windowDefaultWidth) / 2, + (available.width() - initialWidth) / 2, 0), available.y() + std::max( - (available.height() - st::windowDefaultHeight) / 2, + (available.height() - initialHeight) / 2, 0), - st::windowDefaultWidth, - st::windowDefaultHeight); + initialWidth, + initialHeight); if (position.w && position.h) { for (auto screen : QGuiApplication::screens()) { if (position.moncrc == screenNameChecksum(screen->name())) { diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index bc12c5843..140f0140a 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -14,6 +14,8 @@ windowMinWidth: 380px; windowMinHeight: 480px; windowDefaultWidth: 800px; windowDefaultHeight: 600px; +windowBigDefaultWidth: 1024px; +windowBigDefaultHeight: 768px; columnMinimalWidthLeft: 260px; columnMaximalWidthLeft: 540px; From 2f698de3b6152db1ef1d697faeefede7da38d7b1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 2 Jan 2020 16:51:25 +0300 Subject: [PATCH 035/140] Update build scripts for Xcode 11 tools. --- Telegram/build/build.sh | 6 +++--- docs/building-osx.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Telegram/build/build.sh b/Telegram/build/build.sh index da5439714..7b3ab4039 100755 --- a/Telegram/build/build.sh +++ b/Telegram/build/build.sh @@ -289,7 +289,7 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "osx" ] || [ "$BuildTarget fi echo "Dumping debug symbols.." - "$HomePath/../../Libraries/breakpad/src/tools/mac/dump_syms/build/Release/dump_syms" "$ReleasePath/$BinaryName.app.dSYM" > "$ReleasePath/$BinaryName.sym" 2>/dev/null + "$HomePath/../../Libraries/macos/breakpad/src/tools/mac/dump_syms/build/Release/dump_syms" "$ReleasePath/$BinaryName.app.dSYM" > "$ReleasePath/$BinaryName.sym" 2>/dev/null echo "Done!" echo "Stripping the executable.." @@ -378,7 +378,7 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "osx" ] || [ "$BuildTarget if [ "$BuildTarget" == "mac" ]; then echo "Beginning notarization process." set +e - xcrun altool --notarize-app --primary-bundle-id "com.tdesktop.Telegram" --username "$AC_USERNAME" --password "@keychain:AC_PASSWORD" --file "$SetupFile" 2> request_uuid.txt + xcrun altool --notarize-app --primary-bundle-id "com.tdesktop.Telegram" --username "$AC_USERNAME" --password "@keychain:AC_PASSWORD" --file "$SetupFile" > request_uuid.txt set -e while IFS='' read -r line || [[ -n "$line" ]]; do Prefix=$(echo $line | cut -d' ' -f 1) @@ -398,7 +398,7 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "osx" ] || [ "$BuildTarget LogFile= while [[ "$RequestStatus" == "" ]]; do sleep 5 - xcrun altool --notarization-info "$RequestUUID" --username "$AC_USERNAME" --password "@keychain:AC_PASSWORD" 2> request_result.txt + xcrun altool --notarization-info "$RequestUUID" --username "$AC_USERNAME" --password "@keychain:AC_PASSWORD" > request_result.txt while IFS='' read -r line || [[ -n "$line" ]]; do Prefix=$(echo $line | cut -d' ' -f 1) Value=$(echo $line | cut -d' ' -f 2) diff --git a/docs/building-osx.md b/docs/building-osx.md index 23f11b64b..7bfd9a9ef 100644 --- a/docs/building-osx.md +++ b/docs/building-osx.md @@ -207,7 +207,7 @@ Go to ***BuildPath*** and run cd openal-soft git checkout v1.19 cd build - CFLAGS='-Werror=unguarded-availability-new' CPPFLAGS='-Werror=unguarded-availability-new' cmake -D -D ALSOFT_EXAMPLES=OFF -D LIBTYPE:STRING=STATIC -D CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.10 .. + CFLAGS='-Werror=unguarded-availability-new' CPPFLAGS='-Werror=unguarded-availability-new' cmake -D ALSOFT_EXAMPLES=OFF -D LIBTYPE:STRING=STATIC -D CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.10 .. make $MAKE_THREADS_CNT sudo make install cd ../.. From c5c77ddb673828f1ac032fbd226ef498d069189c Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 16 Feb 2020 08:32:39 +0400 Subject: [PATCH 036/140] Rename Telegram Desktop to Telegram Lite. --- Telegram/CMakeLists.txt | 6 +++--- ...gram Desktop.entitlements => Telegram Lite.entitlements} | 0 Telegram/build/build.sh | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename Telegram/Telegram/{Telegram Desktop.entitlements => Telegram Lite.entitlements} (100%) diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 96701f773..5a9ee4bcc 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1076,8 +1076,8 @@ endif() if (build_macstore) set(bundle_identifier "org.telegram.desktop") - set(bundle_entitlements "Telegram Desktop.entitlements") - set(output_name "Telegram Desktop") + set(bundle_entitlements "Telegram Lite.entitlements") + set(output_name "Telegram Lite") set_target_properties(Telegram PROPERTIES XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${libs_loc}/breakpad/src/client/mac/build/Release ) @@ -1121,7 +1121,7 @@ set_target_properties(Telegram PROPERTIES ) set(entitlement_sources "${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Telegram.entitlements" - "${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Telegram Desktop.entitlements" + "${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Telegram Lite.entitlements" ) target_sources(Telegram PRIVATE ${entitlement_sources}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/Telegram PREFIX Resources FILES ${entitlement_sources}) diff --git a/Telegram/Telegram/Telegram Desktop.entitlements b/Telegram/Telegram/Telegram Lite.entitlements similarity index 100% rename from Telegram/Telegram/Telegram Desktop.entitlements rename to Telegram/Telegram/Telegram Lite.entitlements diff --git a/Telegram/build/build.sh b/Telegram/build/build.sh index 7b3ab4039..3de5e19cf 100755 --- a/Telegram/build/build.sh +++ b/Telegram/build/build.sh @@ -87,7 +87,7 @@ elif [ "$BuildTarget" == "macstore" ]; then echo "Building version $AppVersionStrFull for Mac App Store.." ProjectPath="$HomePath/../out" ReleasePath="$ProjectPath/Release" - BinaryName="Telegram Desktop" + BinaryName="Telegram Lite" else Error "Invalid target!" fi @@ -300,7 +300,7 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "osx" ] || [ "$BuildTarget if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "osx" ]; then codesign --force --deep --timestamp --options runtime --sign "Developer ID Application: John Preston" "$ReleasePath/$BinaryName.app" --entitlements "$HomePath/Telegram/Telegram.entitlements" elif [ "$BuildTarget" == "macstore" ]; then - codesign --force --deep --sign "3rd Party Mac Developer Application: TELEGRAM MESSENGER LLP (6N38VWS5BX)" "$ReleasePath/$BinaryName.app" --entitlements "$HomePath/Telegram/Telegram Desktop.entitlements" + codesign --force --deep --sign "3rd Party Mac Developer Application: TELEGRAM MESSENGER LLP (6N38VWS5BX)" "$ReleasePath/$BinaryName.app" --entitlements "$HomePath/Telegram/Telegram Lite.entitlements" echo "Making an installer.." productbuild --sign "3rd Party Mac Developer Installer: TELEGRAM MESSENGER LLP (6N38VWS5BX)" --component "$ReleasePath/$BinaryName.app" /Applications "$ReleasePath/$BinaryName.pkg" fi From 775d5b6dccf48c3310aed044b9022fc3d0a3518f Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 17 Feb 2020 16:44:08 +0400 Subject: [PATCH 037/140] Use 64 byte alignment for ffmpeg frames. Fixes #7225. --- Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp | 3 ++- Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp index a03d191ca..6cb988a28 100644 --- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp +++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp @@ -23,7 +23,8 @@ extern "C" { namespace FFmpeg { namespace { -constexpr auto kAlignImageBy = 16; +// See https://github.com/telegramdesktop/tdesktop/issues/7225 +constexpr auto kAlignImageBy = 64; constexpr auto kImageFormat = QImage::Format_ARGB32_Premultiplied; constexpr auto kMaxScaleByAspectRatio = 16; constexpr auto kAvioBlockSize = 4096; diff --git a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp index 68b56a388..e8fda438a 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp +++ b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp @@ -16,8 +16,10 @@ namespace Clip { namespace internal { namespace { -constexpr int kSkipInvalidDataPackets = 10; -constexpr int kAlignImageBy = 16; +constexpr auto kSkipInvalidDataPackets = 10; + +// See https://github.com/telegramdesktop/tdesktop/issues/7225 +constexpr auto kAlignImageBy = 64; void alignedImageBufferCleanupHandler(void *data) { auto buffer = static_cast(data); From 901a199035bae951440af62e887cdef516243a5b Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 17 Feb 2020 17:09:17 +0400 Subject: [PATCH 038/140] Version 1.9.14. - Bug fixes and other minor improvements. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 4 ++-- Telegram/build/version | 8 ++++---- changelog.txt | 4 ++++ 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 198504e2b..63028397b 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.14.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 76f3ed661..345ef0176 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,13,0 - PRODUCTVERSION 1,9,13,0 + FILEVERSION 1,9,14,0 + PRODUCTVERSION 1,9,14,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.13.0" + VALUE "FileVersion", "1.9.14.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.13.0" + VALUE "ProductVersion", "1.9.14.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index c8771038b..fd3ccd378 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,13,0 - PRODUCTVERSION 1,9,13,0 + FILEVERSION 1,9,14,0 + PRODUCTVERSION 1,9,14,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.13.0" + VALUE "FileVersion", "1.9.14.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.13.0" + VALUE "ProductVersion", "1.9.14.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 2d2d10843..79766c78c 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009013; -constexpr auto AppVersionStr = "1.9.13"; +constexpr auto AppVersion = 1009014; +constexpr auto AppVersionStr = "1.9.14"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 6e6f97816..1ce9141a3 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009013 +AppVersion 1009014 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.13 -AppVersionStr 1.9.13 +AppVersionStrSmall 1.9.14 +AppVersionStr 1.9.14 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 1.9.13 +AppVersionOriginal 1.9.14 diff --git a/changelog.txt b/changelog.txt index ce065fcfc..0d4d83a23 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +1.9.14 (17.02.20) + +- Bug fixes and other minor improvements. + 1.9.13 (12.02.20) - Bug fixes and other minor improvements. From 9d0ae61ee0da8b8683748213b5f69eae0561c06c Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sun, 16 Feb 2020 12:01:05 +0400 Subject: [PATCH 039/140] Revert tray icon size to 22 on Linux (except KDE) and fix tray counter disabling in KDE --- .../platform/linux/main_window_linux.cpp | 42 +++---------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 75ce5ce95..28073de3b 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -38,7 +38,7 @@ constexpr auto kAttentionPanelTrayIconName = "telegram-attention-panel"_cs; constexpr auto kSNIWatcherService = "org.kde.StatusNotifierWatcher"_cs; constexpr auto kTrayIconFilename = "tdesktop-trayicon-XXXXXX.png"_cs; -int32 _trayIconSize = 48; +int32 _trayIconSize = 22; bool _trayIconMuted = true; int32 _trayIconCount = 0; QImage _trayIconImageBack, _trayIconImage; @@ -50,11 +50,6 @@ QString UnityCountDesktopFile; QString UnityCountDBusPath = "/"; #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION -#define QT_RED 0 -#define QT_GREEN 1 -#define QT_BLUE 2 -#define QT_ALPHA 3 - QString GetTrayIconName() { const auto counter = Core::App().unreadBadge(); const auto muted = Core::App().unreadBadgeMuted(); @@ -121,29 +116,6 @@ QImage TrayIconImageGen() { Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } - - _trayIconImageBack = _trayIconImageBack.convertToFormat( - QImage::Format_ARGB32); - - const auto w = _trayIconImageBack.width(); - const auto h = _trayIconImageBack.height(); - const auto perline = _trayIconImageBack.bytesPerLine(); - auto *bytes = _trayIconImageBack.bits(); - - for (int32 y = 0; y < h; ++y) { - for (int32 x = 0; x < w; ++x) { - int32 srcoff = y * perline + x * 4; - bytes[srcoff + QT_RED ] = qMax( - bytes[srcoff + QT_RED ], - uchar(224)); - bytes[srcoff + QT_GREEN] = qMax( - bytes[srcoff + QT_GREEN], - uchar(165)); - bytes[srcoff + QT_BLUE ] = qMax( - bytes[srcoff + QT_BLUE ], - uchar(44)); - } - } } _trayIconImage = _trayIconImageBack; @@ -292,11 +264,6 @@ void MainWindow::psTrayMenuUpdated() { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION void MainWindow::setSNITrayIcon( const QIcon &icon, const QImage &iconImage) { - if (!NeedTrayIconFile()) { - _sniTrayIcon->setIconByPixmap(icon); - _sniTrayIcon->setToolTipIconByPixmap(icon); - } - if (qEnvironmentVariableIsSet(kDisableTrayCounter.utf8())) { const auto iconName = GetTrayIconName(); _sniTrayIcon->setIconByName(iconName); @@ -308,6 +275,9 @@ void MainWindow::setSNITrayIcon( _sniTrayIcon->setIconByName(_trayIconFile->fileName()); _sniTrayIcon->setToolTipIconByName(_trayIconFile->fileName()); } + } else { + _sniTrayIcon->setIconByPixmap(icon); + _sniTrayIcon->setToolTipIconByPixmap(icon); } } @@ -450,8 +420,8 @@ void MainWindow::LibsLoaded() { qDBusRegisterMetaType(); #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - if (!IsSNIAvailable() || IsAppIndicator()) { - _trayIconSize = 22; + if (DesktopEnvironment::IsKDE()) { + _trayIconSize = 48; } } From 742de6282f329424fabf54c3579f71c361452c04 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 18 Feb 2020 12:28:06 +0400 Subject: [PATCH 040/140] Version 1.9.14: Update CMake helpers. --- cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake b/cmake index ba9eb09bc..395c12deb 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit ba9eb09bc03ecb2b3c64ea1aa35ba534c8d3d5fe +Subproject commit 395c12deb157130c923eb5d2f0a6ac28e8edae8a From 8128f851d1f819abad7b690210dc275d05bf1053 Mon Sep 17 00:00:00 2001 From: RadRussianRus Date: Tue, 18 Feb 2020 16:25:37 +0300 Subject: [PATCH 041/140] Changed libvdpau source url --- .github/workflows/linux.yml | 3 +-- docs/building-cmake.md | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index f437ba48f..b102fbd9d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -147,9 +147,8 @@ jobs: run: | cd $LibrariesPath - git clone git://anongit.freedesktop.org/vdpau/libvdpau + git clone https://gitlab.freedesktop.org/vdpau/libvdpau.git --depth=1 -b libvdpau-1.2 cd libvdpau - git checkout libvdpau-1.2 ./autogen.sh --enable-static make -j$(nproc) sudo make install diff --git a/docs/building-cmake.md b/docs/building-cmake.md index aed14aff0..ff0786835 100644 --- a/docs/building-cmake.md +++ b/docs/building-cmake.md @@ -74,9 +74,8 @@ Go to ***BuildPath*** and run sudo make install cd .. - git clone git://anongit.freedesktop.org/vdpau/libvdpau + git clone https://gitlab.freedesktop.org/vdpau/libvdpau.git --depth=1 -b libvdpau-1.2 cd libvdpau - git checkout libvdpau-1.2 ./autogen.sh --enable-static make $MAKE_THREADS_CNT sudo make install From bbc516cf436aaa81c185c4d994c817bebccc0ed5 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sun, 16 Feb 2020 13:25:26 +0400 Subject: [PATCH 042/140] Move TDESKTOP_DISABLE_DBUS_INTEGRATION to cmake_helpers --- .github/workflows/linux.yml | 3 ++- Telegram/CMakeLists.txt | 2 +- Telegram/cmake/telegram_options.cmake | 3 +-- docs/building-cmake.md | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index b102fbd9d..1f8e4abd0 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,7 +31,7 @@ jobs: CMAKE_VER: "3.16.3" UPLOAD_ARTIFACT: "false" ONLY_CACHE: "false" - MANUAL_CACHING: "4" + MANUAL_CACHING: "5" DOC_PATH: "docs/building-cmake.md" steps: @@ -382,6 +382,7 @@ jobs: -no-opengl \ -no-gtk \ -static \ + -dbus-runtime \ -openssl-linked \ -I "$OPENSSL_PREFIX/include" OPENSSL_LIBS="$OPENSSL_PREFIX/lib/libssl.a $OPENSSL_PREFIX/lib/libcrypto.a -ldl -lpthread" \ -nomake examples \ diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 5a9ee4bcc..2ed1ee430 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -77,7 +77,7 @@ if (DESKTOP_APP_USE_PACKAGED) ) endif() -if (LINUX AND NOT TDESKTOP_DISABLE_DBUS_INTEGRATION) +if (LINUX AND NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION) target_link_libraries(Telegram PRIVATE desktop-app::external_statusnotifieritem diff --git a/Telegram/cmake/telegram_options.cmake b/Telegram/cmake/telegram_options.cmake index 6bac7e658..9bc19e5ae 100644 --- a/Telegram/cmake/telegram_options.cmake +++ b/Telegram/cmake/telegram_options.cmake @@ -9,7 +9,6 @@ option(TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME "Disable automatic 'tg://' URL sc option(TDESKTOP_DISABLE_NETWORK_PROXY "Disable all code for working through Socks5 or MTProxy." OFF) option(TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION "Disable automatic '.desktop' file generation (Linux only)." ${DESKTOP_APP_USE_PACKAGED}) option(TDESKTOP_DISABLE_GTK_INTEGRATION "Disable all code for GTK integration (Linux only)." ON) -option(TDESKTOP_DISABLE_DBUS_INTEGRATION "Disable all code for D-Bus integration (Linux only)." OFF) option(TDESKTOP_USE_PACKAGED_TGVOIP "Find libtgvoip using CMake instead of bundled one." ${DESKTOP_APP_USE_PACKAGED}) option(TDESKTOP_API_TEST "Use test API credentials." OFF) set(TDESKTOP_API_ID "0" CACHE STRING "Provide 'api_id' for the Telegram API access.") @@ -86,7 +85,7 @@ if (TDESKTOP_DISABLE_GTK_INTEGRATION) target_compile_definitions(Telegram PRIVATE TDESKTOP_DISABLE_GTK_INTEGRATION) endif() -if (TDESKTOP_DISABLE_DBUS_INTEGRATION) +if (DESKTOP_APP_DISABLE_DBUS_INTEGRATION) target_compile_definitions(Telegram PRIVATE TDESKTOP_DISABLE_DBUS_INTEGRATION) endif() diff --git a/docs/building-cmake.md b/docs/building-cmake.md index ff0786835..32661ef66 100644 --- a/docs/building-cmake.md +++ b/docs/building-cmake.md @@ -257,6 +257,7 @@ Go to ***BuildPath*** and run -no-opengl \ -no-gtk \ -static \ + -dbus-runtime \ -openssl-linked \ -I "$OPENSSL_DIR/include" OPENSSL_LIBS="$OPENSSL_DIR/lib/libssl.a $OPENSSL_DIR/lib/libcrypto.a -ldl -lpthread" \ -nomake examples \ From ca1623f34a5aafd8f7d4b9044fa399c0b689b5da Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Wed, 19 Feb 2020 18:44:26 +0400 Subject: [PATCH 043/140] Use XDG Desktop Portal only when variable is set --- .../platform/linux/file_utilities_linux.cpp | 2 +- .../platform/linux/specific_linux.cpp | 32 +++++++++++++------ .../platform/linux/specific_linux.h | 1 + 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp b/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp index d1676cdba..47dd56a41 100644 --- a/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp @@ -87,7 +87,7 @@ bool NativeSupported() { #ifndef TDESKTOP_FORCE_GTK_FILE_DIALOG return false; #endif // TDESKTOP_FORCE_GTK_FILE_DIALOG - return !Platform::IsXDGDesktopPortalPresent() + return !Platform::UseXDGDesktopPortal() && Platform::internal::GdkHelperLoaded() && (Libs::gtk_widget_hide_on_delete != nullptr) && (Libs::gtk_clipboard_store != nullptr) diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index b83ddd0c7..08c9ab45c 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -45,8 +45,6 @@ namespace { constexpr auto kDesktopFile = ":/misc/telegramdesktop.desktop"_cs; constexpr auto kSnapLauncherDir = "/var/lib/snapd/desktop/applications/"_cs; -bool XDGDesktopPortalPresent = false; - #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION void SandboxAutostart(bool autostart) { QVariantMap options; @@ -203,9 +201,22 @@ bool InSnap() { } bool IsXDGDesktopPortalPresent() { +#ifdef TDESKTOP_DISABLE_DBUS_INTEGRATION + static const auto XDGDesktopPortalPresent = false; +#else // TDESKTOP_DISABLE_DBUS_INTEGRATION + static const auto XDGDesktopPortalPresent = QDBusInterface( + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop").isValid(); +#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION return XDGDesktopPortalPresent; } +bool UseXDGDesktopPortal() { + static const auto UsePortal = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL") + && IsXDGDesktopPortalPresent(); + return UsePortal; +} + QString ProcessNameByPID(const QString &pid) { constexpr auto kMaxPath = 1024; char result[kMaxPath] = { 0 }; @@ -414,20 +425,21 @@ namespace Platform { void start() { FallbackFontConfig(); -#if !defined(TDESKTOP_DISABLE_DBUS_INTEGRATION) && defined(TDESKTOP_FORCE_GTK_FILE_DIALOG) +#ifdef TDESKTOP_FORCE_GTK_FILE_DIALOG LOG(("Checking for XDG Desktop Portal...")); - XDGDesktopPortalPresent = QDBusInterface( - "org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop").isValid(); - // this can give us a chance to use a proper file dialog for current session - if(XDGDesktopPortalPresent) { + if(IsXDGDesktopPortalPresent()) { LOG(("XDG Desktop Portal is present!")); - qputenv("QT_QPA_PLATFORMTHEME", "xdgdesktopportal"); + if(UseXDGDesktopPortal()) { + LOG(("Usage of XDG Desktop Portal is enabled.")); + qputenv("QT_QPA_PLATFORMTHEME", "xdgdesktopportal"); + } else { + LOG(("Usage of XDG Desktop Portal is disabled.")); + } } else { LOG(("XDG Desktop Portal is not present :(")); } -#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION && TDESKTOP_FORCE_GTK_FILE_DIALOG +#endif // TDESKTOP_FORCE_GTK_FILE_DIALOG } void finish() { diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.h b/Telegram/SourceFiles/platform/linux/specific_linux.h index 3ce0640ff..f878dac71 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.h +++ b/Telegram/SourceFiles/platform/linux/specific_linux.h @@ -24,6 +24,7 @@ bool InSandbox(); bool InSnap(); bool IsXDGDesktopPortalPresent(); +bool UseXDGDesktopPortal(); QString ProcessNameByPID(const QString &pid); QString CurrentExecutablePath(int argc, char *argv[]); From 5bdc0db9e2009f196688907b0e2e93cd44066fbe Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Thu, 20 Feb 2020 07:00:26 +0400 Subject: [PATCH 044/140] Generalize backward compatibility of linux launcher --- .../platform/linux/main_window_linux.cpp | 57 +++++++------------ .../platform/linux/specific_linux.cpp | 35 +++++++----- 2 files changed, 43 insertions(+), 49 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 28073de3b..3d8681a40 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -44,12 +44,6 @@ int32 _trayIconCount = 0; QImage _trayIconImageBack, _trayIconImage; QString _trayIconThemeName, _trayIconName; -#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION -bool UseUnityCount = false; -QString UnityCountDesktopFile; -QString UnityCountDBusPath = "/"; -#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - QString GetTrayIconName() { const auto counter = Core::App().unreadBadge(); const auto muted = Core::App().unreadBadgeMuted(); @@ -222,6 +216,18 @@ bool IsSNIAvailable() { return SNIAvailable; } +bool UseUnityCounter() { +#ifdef TDESKTOP_DISABLE_DBUS_INTEGRATION + static const auto UnityCounter = false; +#else // TDESKTOP_DISABLE_DBUS_INTEGRATION + static const auto UnityCounter = QDBusInterface( + "com.canonical.Unity", + "/").isValid(); +#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION + + return UnityCounter; +} + quint32 djbStringHash(QString string) { quint32 hash = 5381; QByteArray chars = string.toLatin1(); @@ -375,8 +381,9 @@ void MainWindow::updateIconCounters() { updateWindowIcon(); #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION - if (UseUnityCount) { + if (UseUnityCounter()) { const auto counter = Core::App().unreadBadge(); + const auto launcherUrl = "application://" + GetLauncherFilename(); QVariantMap dbusUnityProperties; if (counter > 0) { // Gnome requires that count is a 64bit integer @@ -384,16 +391,17 @@ void MainWindow::updateIconCounters() { "count", (qint64) ((counter > 9999) ? 9999 - : (counter))); + : counter)); dbusUnityProperties.insert("count-visible", true); } else { dbusUnityProperties.insert("count-visible", false); } QDBusMessage signal = QDBusMessage::createSignal( - UnityCountDBusPath, + "/com/canonical/unity/launcherentry/" + + QString::number(djbStringHash(launcherUrl)), "com.canonical.Unity.LauncherEntry", "Update"); - signal << "application://" + UnityCountDesktopFile; + signal << launcherUrl; signal << dbusUnityProperties; QDBusConnection::sessionBus().send(signal); } @@ -432,34 +440,11 @@ void MainWindow::initTrayMenuHook() { LOG(("System tray available: %1").arg(Logs::b(trayAvailable))); cSetSupportTray(trayAvailable); -#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION - if (QDBusInterface("com.canonical.Unity", "/").isValid()) { - const std::vector possibleDesktopFiles = { - GetLauncherFilename(), - "Telegram.desktop" - }; - - for (auto it = possibleDesktopFiles.begin(); - it != possibleDesktopFiles.end(); it++) { - if (!QStandardPaths::locate( - QStandardPaths::ApplicationsLocation, *it).isEmpty()) { - UnityCountDesktopFile = *it; - LOG(("Found Unity Launcher entry %1!") - .arg(UnityCountDesktopFile)); - UseUnityCount = true; - break; - } - } - if (!UseUnityCount) { - LOG(("Could not get Unity Launcher entry!")); - } - UnityCountDBusPath = "/com/canonical/unity/launcherentry/" - + QString::number( - djbStringHash("application://" + UnityCountDesktopFile)); + if (UseUnityCounter()) { + LOG(("Using Unity launcher counter.")); } else { - LOG(("Not using Unity Launcher count.")); + LOG(("Not using Unity launcher counter.")); } -#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION } MainWindow::~MainWindow() { diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 08c9ab45c..609c3d7e5 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -282,25 +282,34 @@ QString SingleInstanceLocalServerName(const QString &hash) { QString GetLauncherBasename() { static const auto LauncherBasename = [&] { - if (!InSnap()) { - return qsl(MACRO_TO_STRING(TDESKTOP_LAUNCHER_BASENAME)); + if (InSnap()) { + const auto snapNameKey = + qEnvironmentVariableIsSet("SNAP_INSTANCE_NAME") + ? "SNAP_INSTANCE_NAME" + : "SNAP_NAME"; + + return qsl("%1_%2") + .arg(QString::fromLatin1(qgetenv(snapNameKey))) + .arg(cExeName()); } - const auto snapNameKey = - qEnvironmentVariableIsSet("SNAP_INSTANCE_NAME") - ? "SNAP_INSTANCE_NAME" - : "SNAP_NAME"; + const auto possibleBasenames = std::vector{ + qsl(MACRO_TO_STRING(TDESKTOP_LAUNCHER_BASENAME)), + qsl("Telegram") + }; - const auto result = qsl("%1_%2") - .arg(QString::fromLatin1(qgetenv(snapNameKey))) - .arg(cExeName()); + for (const auto &it : possibleBasenames) { + if (!QStandardPaths::locate( + QStandardPaths::ApplicationsLocation, + it + qsl(".desktop")).isEmpty()) { + return it; + } + } - LOG(("SNAP Environment detected, launcher filename is %1.desktop") - .arg(result)); - - return result; + return possibleBasenames[0]; }(); + LOG(("Launcher filename is %1.desktop").arg(LauncherBasename)); return LauncherBasename; } From 02bc999bd50ed76fd2bb9bc3b49b377dffa304ac Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 18:15:41 +0400 Subject: [PATCH 045/140] Update cmake_helpers. --- cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake b/cmake index 395c12deb..99278254e 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 395c12deb157130c923eb5d2f0a6ac28e8edae8a +Subproject commit 99278254e352029ce36dc7b597b346b245d9860c From db2aa7000a264e08465a54cc3d88e4a1871aef94 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Thu, 20 Feb 2020 05:13:15 +0400 Subject: [PATCH 046/140] Fallback to non-panel icon when tray counter is disabled --- .../platform/linux/main_window_linux.cpp | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 3d8681a40..fe5e75355 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -44,7 +44,7 @@ int32 _trayIconCount = 0; QImage _trayIconImageBack, _trayIconImage; QString _trayIconThemeName, _trayIconName; -QString GetTrayIconName() { +QString GetPanelIconName() { const auto counter = Core::App().unreadBadge(); const auto muted = Core::App().unreadBadgeMuted(); @@ -55,6 +55,24 @@ QString GetTrayIconName() { : kPanelTrayIconName.utf16(); } +QString GetTrayIconName() { + const auto panelIconName = GetPanelIconName(); + + if (QIcon::hasThemeIcon(panelIconName)) { + return panelIconName; + } else if (InSandbox()) { + const auto launcherBasename = GetLauncherBasename(); + + if (QIcon::hasThemeIcon(launcherBasename)) { + return launcherBasename; + } + } else if (QIcon::hasThemeIcon(kTrayIconName.utf16())) { + return kTrayIconName.utf16(); + } + + return QString(); +} + QImage TrayIconImageGen() { const auto counter = Core::App().unreadBadge(); const auto muted = Core::App().unreadBadgeMuted(); @@ -76,16 +94,8 @@ QImage TrayIconImageGen() { || _trayIconImageBack.size() != desiredSize || iconThemeName != _trayIconThemeName || iconName != _trayIconName) { - const auto hasPanelIcon = QIcon::hasThemeIcon(iconName); - - if (hasPanelIcon || QIcon::hasThemeIcon(kTrayIconName.utf16())) { - QIcon systemIcon; - - if (hasPanelIcon) { - systemIcon = QIcon::fromTheme(iconName); - } else { - systemIcon = QIcon::fromTheme(kTrayIconName.utf16()); - } + if (!iconName.isEmpty()) { + const auto systemIcon = QIcon::fromTheme(iconName); if (systemIcon.actualSize(desiredSize) == desiredSize) { _trayIconImageBack = systemIcon @@ -118,7 +128,8 @@ QImage TrayIconImageGen() { _trayIconThemeName = iconThemeName; _trayIconName = iconName; - if (counter > 0) { + if (!qEnvironmentVariableIsSet(kDisableTrayCounter.utf8()) + && counter > 0) { QPainter p(&_trayIconImage); int32 layerSize = -16; @@ -270,8 +281,10 @@ void MainWindow::psTrayMenuUpdated() { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION void MainWindow::setSNITrayIcon( const QIcon &icon, const QImage &iconImage) { - if (qEnvironmentVariableIsSet(kDisableTrayCounter.utf8())) { - const auto iconName = GetTrayIconName(); + const auto iconName = GetTrayIconName(); + + if (qEnvironmentVariableIsSet(kDisableTrayCounter.utf8()) + && !iconName.isEmpty()) { _sniTrayIcon->setIconByName(iconName); _sniTrayIcon->setToolTipIconByName(iconName); } else if (NeedTrayIconFile()) { From 70408f0e221a195b65d3ee6db24e848cb0139d69 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 11 Feb 2020 15:23:51 +0400 Subject: [PATCH 047/140] First version of reading-while-scrolling. --- Telegram/SourceFiles/apiwrap.cpp | 13 +- Telegram/SourceFiles/apiwrap.h | 2 +- Telegram/SourceFiles/history/history.cpp | 133 ++++++++++++++++-- Telegram/SourceFiles/history/history.h | 7 + .../history/history_inner_widget.cpp | 69 +++++++-- .../history/history_inner_widget.h | 1 + .../SourceFiles/history/history_widget.cpp | 76 ++++------ Telegram/SourceFiles/history/history_widget.h | 5 +- Telegram/SourceFiles/mainwidget.cpp | 17 +-- Telegram/SourceFiles/mainwidget.h | 5 +- Telegram/SourceFiles/mainwindow.cpp | 20 +-- Telegram/SourceFiles/mainwindow.h | 3 +- 12 files changed, 238 insertions(+), 113 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 121dccca2..dbf8b238b 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -6009,13 +6009,16 @@ void ApiWrap::readServerHistory(not_null history) { } } -void ApiWrap::readServerHistoryForce(not_null history) { +void ApiWrap::readServerHistoryForce( + not_null history, + MsgId upTo) { const auto peer = history->peer; - const auto upTo = history->readInbox(); if (!upTo) { - return; + upTo = history->readInbox(); + if (!upTo) { + return; + } } - if (const auto channel = peer->asChannel()) { if (!channel->amIn()) { return; // no read request for channels that I didn't join @@ -6099,7 +6102,7 @@ void ApiWrap::sendReadRequest(not_null peer, MsgId upTo) { sendReadRequest(peer, *next); } else if (const auto history = _session->data().historyLoaded(peer)) { - if (!history->unreadCountKnown()) { + if (history->unreadCountRefreshNeeded()) { requestDialogEntry(history); } } diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 0a57a619b..276dc5ed2 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -390,7 +390,7 @@ public: const SendAction &action); void shareContact(not_null user, const SendAction &action); void readServerHistory(not_null history); - void readServerHistoryForce(not_null history); + void readServerHistoryForce(not_null history, MsgId upTo = 0); //void readFeed( // #feed // not_null feed, // Data::MessagePosition position); diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index f1a2559ce..fe2a8d8ed 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1592,11 +1592,12 @@ void History::calculateFirstUnreadMessage() { } void History::readClientSideMessages() { - for (const auto &block : blocks) { - for (const auto &view : block->messages) { - const auto item = view->data(); - if (!item->out()) { - item->markClientSideAsRead(); + auto unread = unreadCount(); + for (const auto item : _localMessages) { + if (!item->out() && item->unread()) { + item->markClientSideAsRead(); + if (unread > 0) { + setUnreadCount(--unread); } } } @@ -1604,16 +1605,117 @@ void History::readClientSideMessages() { MsgId History::readInbox() { const auto upTo = msgIdForRead(); + readClientSideMessages(); if (unreadCountKnown()) { setUnreadCount(0); } - readClientSideMessages(); if (upTo) { inboxRead(upTo); } return upTo; } +void History::readInboxTill(not_null item) { + if (!IsServerMsgId(item->id)) { + auto view = item->mainView(); + if (!view) { + return; + } + auto block = view->block(); + auto blockIndex = block->indexInHistory(); + auto itemIndex = view->indexInBlock(); + while (blockIndex > 0 || itemIndex > 0) { + if (itemIndex > 0) { + view = block->messages[--itemIndex].get(); + } else { + while (blockIndex > 0) { + block = blocks[--blockIndex].get(); + itemIndex = block->messages.size(); + if (itemIndex > 0) { + view = block->messages[--itemIndex].get(); + break; + } + } + } + item = view->data(); + if (IsServerMsgId(item->id)) { + break; + } + } + if (!IsServerMsgId(item->id)) { + LOG(("App Error: " + "Can't read history till unknown local message.")); + return; + } + } + readClientSideMessages(); + if (unreadMark()) { + session().api().changeDialogUnreadMark(this, false); + } + if (_inboxReadTillLocal >= item->id) { + return; + } + _inboxReadTillLocal = item->id; + const auto stillUnread = countStillUnreadLocal(); + if (!stillUnread) { + session().api().readServerHistoryForce(this, _inboxReadTillLocal); + return; + } + setInboxReadTill(_inboxReadTillLocal); + if (stillUnread && _unreadCount && *stillUnread == *_unreadCount) { + return; + } + setUnreadCount(*stillUnread); + session().api().readServerHistoryForce(this, _inboxReadTillLocal); + updateChatListEntry(); +} + +bool History::unreadCountRefreshNeeded() const { + return !unreadCountKnown() + || ((_inboxReadTillLocal + 1) > _inboxReadBefore.value_or(0)); +} + +std::optional History::countStillUnreadLocal() const { + if (isEmpty()) { + return std::nullopt; + } + const auto till = _inboxReadTillLocal; + if (_inboxReadBefore) { + const auto before = *_inboxReadBefore; + if (minMsgId() <= before && maxMsgId() >= till) { + auto result = 0; + for (const auto &block : blocks) { + for (const auto &message : block->messages) { + const auto item = message->data(); + if (item->out() || !IsServerMsgId(item->id)) { + continue; + } else if (item->id > till) { + break; + } else if (item->id >= before) { + ++result; + } + } + } + if (_unreadCount) { + return std::max(*_unreadCount - result, 0); + } + } + } + if (!loadedAtBottom() || minMsgId() > till) { + return std::nullopt; + } + auto result = 0; + for (const auto &block : blocks) { + for (const auto &message : block->messages) { + const auto item = message->data(); + if (!item->out() && IsServerMsgId(item->id) && item->id > till) { + ++result; + } + } + } + return result; +} + void History::applyInboxReadUpdate( FolderId folderId, MsgId upTo, @@ -1625,10 +1727,12 @@ void History::applyInboxReadUpdate( session().api().requestDialogEntry(this); session().api().requestDialogEntry(folder); } - if (!peer->isChannel() || peer->asChannel()->pts() == channelPts) { - inboxRead(upTo, stillUnread); - } else { - inboxRead(upTo); + if (_inboxReadTillLocal <= upTo) { + if (!peer->isChannel() || peer->asChannel()->pts() == channelPts) { + inboxRead(upTo, stillUnread); + } else { + inboxRead(upTo); + } } } @@ -1645,9 +1749,9 @@ void History::inboxRead(MsgId upTo, std::optional stillUnread) { } setInboxReadTill(upTo); updateChatListEntry(); - if (peer->migrateTo()) { - if (auto migrateTo = peer->owner().historyLoaded(peer->migrateTo()->id)) { - migrateTo->updateChatListEntry(); + if (const auto to = peer->migrateTo()) { + if (const auto migrated = peer->owner().historyLoaded(to->id)) { + migrated->updateChatListEntry(); } } @@ -2656,7 +2760,7 @@ void History::applyDialogFields( } else { clearFolder(); } - if (!skipUnreadUpdate()) { + if (!skipUnreadUpdate() && maxInboxRead >= _inboxReadTillLocal) { setUnreadCount(unreadCount); setInboxReadTill(maxInboxRead); } @@ -2690,6 +2794,7 @@ void History::setInboxReadTill(MsgId upTo) { } else { _inboxReadBefore = upTo + 1; } + accumulate_max(_inboxReadTillLocal, upTo); } void History::setOutboxReadTill(MsgId upTo) { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 327445a3f..83d8a9f15 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -159,6 +159,7 @@ public: [[nodiscard]] HistoryItem *latestSendingMessage() const; MsgId readInbox(); + void readInboxTill(not_null item); void applyInboxReadUpdate( FolderId folderId, MsgId upTo, @@ -174,6 +175,10 @@ public: [[nodiscard]] int unreadCount() const; [[nodiscard]] bool unreadCountKnown() const; + + // Some old unread count is known, but we read history till some place. + [[nodiscard]] bool unreadCountRefreshNeeded() const; + void setUnreadCount(int newUnreadCount); void setUnreadMark(bool unread); [[nodiscard]] bool unreadMark() const; @@ -469,6 +474,7 @@ private: void getNextFirstUnreadMessage(); bool nonEmptyCountMoreThan(int count) const; std::optional countUnread(MsgId upTo) const; + std::optional countStillUnreadLocal() const; // Creates if necessary a new block for adding item. // Depending on isBuildingFrontBlock() gets front or back block. @@ -497,6 +503,7 @@ private: std::optional _inboxReadBefore; std::optional _outboxReadBefore; + MsgId _inboxReadTillLocal = 0; std::optional _unreadCount; std::optional _unreadMentionsCount; base::flat_set _unreadMentions; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index d9cec64fc..85e7c9716 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "window/window_peer_menu.h" #include "window/window_controller.h" +#include "window/notifications_manager.h" #include "boxes/confirm_box.h" #include "boxes/report_box.h" #include "boxes/sticker_set_box.h" @@ -655,13 +656,13 @@ void HistoryInner::paintEvent(QPaintEvent *e) { auto iItem = (_curHistory == _history ? _curItem : 0); auto view = block->messages[iItem].get(); auto item = view->data(); - + auto readTill = (HistoryItem*)nullptr; auto hclip = clip.intersected(QRect(0, hdrawtop, width(), clip.top() + clip.height())); auto y = htop + block->y() + view->y(); p.save(); p.translate(0, y); while (y < drawToY) { - auto h = view->height(); + const auto h = view->height(); if (hclip.y() < y + h && hdrawtop < y + h) { const auto selection = itemRenderSelection( view, @@ -669,12 +670,20 @@ void HistoryInner::paintEvent(QPaintEvent *e) { seltoy - htop); view->draw(p, hclip.translated(0, -y), selection, ms); - if (item->hasViews()) { - App::main()->scheduleViewIncrement(item); + const auto middle = y + h / 2; + const auto bottom = y + h; + if (_visibleAreaBottom >= bottom) { + readTill = view->data(); } - if (item->isUnreadMention() && !item->isUnreadMedia()) { - readMentions.insert(item); - _widget->enqueueMessageHighlight(view); + if (_visibleAreaBottom >= middle + && _visibleAreaTop <= middle) { + if (item->hasViews()) { + App::main()->scheduleViewIncrement(item); + } + if (item->isUnreadMention() && !item->isUnreadMedia()) { + readMentions.insert(item); + _widget->enqueueMessageHighlight(view); + } } } p.translate(0, h); @@ -693,9 +702,13 @@ void HistoryInner::paintEvent(QPaintEvent *e) { item = view->data(); } p.restore(); + + if (readTill) { + _history->readInboxTill(readTill); + } } - if (!readMentions.empty() && App::wnd()->doWeReadMentions()) { + if (!readMentions.empty() && _widget->doWeReadMentions()) { session().api().markMediaRead(readMentions); } @@ -2013,6 +2026,42 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) { } } +void HistoryInner::checkHistoryActivation() { + if (!_widget->doWeReadServerHistory()) { + return; + } + adjustCurrent(_visibleAreaBottom); + if (_history->loadedAtBottom() && _visibleAreaBottom >= height()) { + // Clear possible scheduled messages notifications. + session().notifications().clearFromHistory(_history); + } + if (_curHistory != _history || _history->isEmpty()) { + return; + } + auto block = _history->blocks[_curBlock].get(); + auto view = block->messages[_curItem].get(); + while (_curBlock > 0 || _curItem > 0) { + const auto top = itemTop(view); + const auto bottom = itemTop(view) + view->height(); + if (_visibleAreaBottom >= bottom) { + break; + } + if (_curItem > 0) { + view = block->messages[--_curItem].get(); + } else { + while (_curBlock > 0) { + block = _history->blocks[--_curBlock].get(); + _curItem = block->messages.size(); + if (_curItem > 0) { + view = block->messages[--_curItem].get(); + break; + } + } + } + } + _history->readInboxTill(view->data()); +} + void HistoryInner::recountHistoryGeometry() { _contentWidth = _scroll->width(); @@ -2178,6 +2227,7 @@ void HistoryInner::visibleAreaUpdated(int top, int bottom) { const auto from = _visibleAreaTop - pages * visibleAreaHeight; const auto till = _visibleAreaBottom + pages * visibleAreaHeight; session().data().unloadHeavyViewParts(ElementDelegate(), from, till); + checkHistoryActivation(); } bool HistoryInner::displayScrollDate() const { @@ -2326,7 +2376,8 @@ void HistoryInner::adjustCurrent(int32 y) const { } void HistoryInner::adjustCurrent(int32 y, History *history) const { - Assert(!history->isEmpty()); + Expects(!history->isEmpty()); + _curHistory = history; if (_curBlock >= history->blocks.size()) { _curBlock = history->blocks.size() - 1; diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 4a4773bcf..a0b551450 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -62,6 +62,7 @@ public: void touchScrollUpdated(const QPoint &screenPos); + void checkHistoryActivation(); void recountHistoryGeometry(); void updateSize(); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 993a5f094..e7892de32 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2265,16 +2265,18 @@ void HistoryWidget::unreadMessageAdded(not_null item) { // - on second we get wrong doWeReadServerHistory() and read both. session().data().sendHistoryChangeNotifications(); - if (_scroll->scrollTop() + 1 > _scroll->scrollTopMax()) { - destroyUnreadBar(); + const auto atBottom = (_scroll->scrollTop() >= _scroll->scrollTopMax()); + if (!atBottom) { + return; } - if (!App::wnd()->doWeReadServerHistory()) { + destroyUnreadBar(); + if (!doWeReadServerHistory()) { return; } if (item->isUnreadMention() && !item->isUnreadMedia()) { session().api().markMediaRead(item); } - session().api().readServerHistoryForce(_history); + _history->readInboxTill(item); // Also clear possible scheduled messages notifications. session().notifications().clearFromHistory(_history); @@ -2403,7 +2405,9 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages addMessagesToBack(peer, *histList); _preloadDownRequest = 0; preloadHistoryIfNeeded(); - if (_history->loadedAtBottom() && App::wnd()) App::wnd()->checkHistoryActivation(); + if (_history->loadedAtBottom()) { + App::wnd()->checkHistoryActivation(); + } } else if (_firstLoadRequest == requestId) { if (toMigrated) { _history->clear(History::ClearType::Unload); @@ -2472,30 +2476,21 @@ void HistoryWidget::windowShown() { } bool HistoryWidget::doWeReadServerHistory() const { - if (!_history || !_list) return true; - if (_firstLoadRequest || _a_show.animating()) return false; - if (_history->loadedAtBottom()) { - int scrollTop = _scroll->scrollTop(); - if (scrollTop + 1 > _scroll->scrollTopMax()) return true; - - if (const auto unread = firstUnreadMessage()) { - const auto scrollBottom = scrollTop + _scroll->height(); - if (scrollBottom > _list->itemTop(unread)) { - return true; - } - } - } - if (_history->hasNotFreezedUnreadBar() - || (_migrated && _migrated->hasNotFreezedUnreadBar())) { - return true; - } - return false; + return doWeReadMentions() && !session().supportMode(); } bool HistoryWidget::doWeReadMentions() const { - if (!_history || !_list) return true; - if (_firstLoadRequest || _a_show.animating()) return false; - return true; + return _history + && _list + && !_firstLoadRequest + && !_a_show.animating() + && App::wnd()->doWeMarkAsRead(); +} + +void HistoryWidget::checkHistoryActivation() { + if (_list) { + _list->checkHistoryActivation(); + } } void HistoryWidget::firstLoadMessages() { @@ -2714,24 +2709,6 @@ void HistoryWidget::visibleAreaUpdated() { const auto scrollBottom = scrollTop + _scroll->height(); _list->visibleAreaUpdated(scrollTop, scrollBottom); controller()->floatPlayerAreaUpdated().notify(true); - - const auto atBottom = (scrollTop >= _scroll->scrollTopMax()); - if (_history->loadedAtBottom() - && atBottom - && App::wnd()->doWeReadServerHistory()) { - // Clear possible scheduled messages notifications. - session().api().readServerHistory(_history); - session().notifications().clearFromHistory(_history); - } else if (_history->loadedAtBottom() - && (_history->unreadCount() > 0 - || (_migrated && _migrated->unreadCount() > 0))) { - const auto unread = firstUnreadMessage(); - const auto unreadVisible = unread - && (scrollBottom > _list->itemTop(unread)); - if (unreadVisible && App::wnd()->doWeReadServerHistory()) { - session().api().readServerHistory(_history); - } - } } } @@ -2820,9 +2797,8 @@ void HistoryWidget::historyDownClicked() { } else if (_replyReturn && _replyReturn->history() == _migrated) { showHistory(_peer->id, -_replyReturn->id); } else if (_peer) { - showHistory( - _peer->id, - session().supportMode() ? ShowAtTheEndMsgId : ShowAtUnreadMsgId); + showHistory(_peer->id, ShowAtTheEndMsgId); // #TODO reading + // session().supportMode() ? ShowAtTheEndMsgId : ShowAtUnreadMsgId); } } @@ -3178,10 +3154,8 @@ void HistoryWidget::doneShow() { handlePendingHistoryUpdate(); } preloadHistoryIfNeeded(); - if (App::wnd()) { - App::wnd()->checkHistoryActivation(); - App::wnd()->setInnerFocus(); - } + App::wnd()->checkHistoryActivation(); + App::wnd()->setInnerFocus(); } void HistoryWidget::finishAnimating() { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 8e473b601..79070c736 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -109,9 +109,10 @@ public: void historyLoaded(); void windowShown(); - bool doWeReadServerHistory() const; - bool doWeReadMentions() const; + [[nodiscard]] bool doWeReadServerHistory() const; + [[nodiscard]] bool doWeReadMentions() const; bool skipItemRepaint(); + void checkHistoryActivation(); void leaveToChildEvent(QEvent *e, QWidget *child) override; void dragEnterEvent(QDragEnterEvent *e) override; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 31525f415..ec105b29b 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -2217,10 +2217,8 @@ void MainWidget::dialogsToUp() { _dialogs->jumpToTop(); } -void MainWidget::markActiveHistoryAsRead() { - if (const auto activeHistory = _history->history()) { - session().api().readServerHistory(activeHistory); - } +void MainWidget::checkHistoryActivation() { + _history->checkHistoryActivation(); } void MainWidget::showAnimated(const QPixmap &bgAnimCache, bool back) { @@ -3519,15 +3517,8 @@ bool MainWidget::isActive() const { return !_isIdle && isVisible() && !_a_show.animating(); } -bool MainWidget::doWeReadServerHistory() const { - return isActive() - && !session().supportMode() - && !_mainSection - && _history->doWeReadServerHistory(); -} - -bool MainWidget::doWeReadMentions() const { - return isActive() && !_mainSection && _history->doWeReadMentions(); +bool MainWidget::doWeMarkAsRead() const { + return isActive() && !_mainSection; } bool MainWidget::lastWasOnline() const { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 6a41d156e..61bbdab6e 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -148,7 +148,7 @@ public: bool deleteChannelFailed(const RPCError &error); void historyToDown(History *hist); void dialogsToUp(); - void markActiveHistoryAsRead(); + void checkHistoryActivation(); PeerData *peer(); @@ -173,8 +173,7 @@ public: void updateOnlineDisplayIn(int32 msecs); bool isActive() const; - bool doWeReadServerHistory() const; - bool doWeReadMentions() const; + [[nodiscard]] bool doWeMarkAsRead() const; bool lastWasOnline() const; crl::time lastSetOnline() const; diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 6e360c89d..652ae6763 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -503,23 +503,17 @@ void MainWindow::themeUpdated(const Window::Theme::BackgroundUpdate &data) { } } -bool MainWindow::doWeReadServerHistory() { +bool MainWindow::doWeMarkAsRead() { + if (!_main || Ui::isLayerShown()) { + return false; + } updateIsActive(0); - return isActive() - && !Ui::isLayerShown() - && (_main ? _main->doWeReadServerHistory() : false); -} - -bool MainWindow::doWeReadMentions() { - updateIsActive(0); - return isActive() - && !Ui::isLayerShown() - && (_main ? _main->doWeReadMentions() : false); + return isActive(); } void MainWindow::checkHistoryActivation() { - if (doWeReadServerHistory()) { - _main->markActiveHistoryAsRead(); + if (_main) { + _main->checkHistoryActivation(); } } diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 4635bbea6..076ff1b23 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -62,8 +62,7 @@ public: MainWidget *mainWidget(); - bool doWeReadServerHistory(); - bool doWeReadMentions(); + [[nodiscard]] bool doWeMarkAsRead(); void activate(); From b0e1ae3948fa24c383e7b7e888f4df1aa7750472 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 18 Feb 2020 15:39:24 +0400 Subject: [PATCH 048/140] Prepare Data::Histories for requests interdependencies. --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/apiwrap.cpp | 2 +- Telegram/SourceFiles/apiwrap.h | 6 +- Telegram/SourceFiles/data/data_histories.cpp | 339 ++++++++++++++++++ Telegram/SourceFiles/data/data_histories.h | 93 +++++ Telegram/SourceFiles/data/data_session.cpp | 23 +- Telegram/SourceFiles/data/data_session.h | 6 +- Telegram/SourceFiles/history/history.cpp | 87 ++--- Telegram/SourceFiles/history/history.h | 10 +- .../SourceFiles/history/history_widget.cpp | 2 + 10 files changed, 482 insertions(+), 88 deletions(-) create mode 100644 Telegram/SourceFiles/data/data_histories.cpp create mode 100644 Telegram/SourceFiles/data/data_histories.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 2ed1ee430..98c142c95 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -335,6 +335,8 @@ PRIVATE data/data_game.h data/data_groups.cpp data/data_groups.h + data/data_histories.cpp + data/data_histories.h data/data_location.cpp data/data_location.h data/data_media_rotation.cpp diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index dbf8b238b..860489070 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -6102,7 +6102,7 @@ void ApiWrap::sendReadRequest(not_null peer, MsgId upTo) { sendReadRequest(peer, *next); } else if (const auto history = _session->data().historyLoaded(peer)) { - if (history->unreadCountRefreshNeeded()) { + if (!history->unreadCountKnown()) { requestDialogEntry(history); } } diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 276dc5ed2..137169659 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -394,6 +394,9 @@ public: //void readFeed( // #feed // not_null feed, // Data::MessagePosition position); + void applyAffectedMessages( + not_null peer, + const MTPmessages_AffectedMessages &result); void sendVoiceMessage( QByteArray result, @@ -628,9 +631,6 @@ private: not_null peer, const MTPmessages_AffectedHistory &result); void applyAffectedMessages(const MTPmessages_AffectedMessages &result); - void applyAffectedMessages( - not_null peer, - const MTPmessages_AffectedMessages &result); void deleteAllFromUserSend( not_null channel, diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp new file mode 100644 index 000000000..fa30a0743 --- /dev/null +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -0,0 +1,339 @@ +/* +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 +*/ +#include "data/data_histories.h" + +#include "data/data_session.h" +#include "data/data_channel.h" +#include "main/main_session.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/view/history_view_element.h" +#include "apiwrap.h" + +namespace Data { +namespace { + +constexpr auto kReadRequestTimeout = 3 * crl::time(1000); +constexpr auto kReadRequestSent = std::numeric_limits::max(); + +} // namespace + +Histories::Histories(not_null owner) +: _owner(owner) +, _readRequestsTimer([=] { sendReadRequests(); }) { +} + +Session &Histories::owner() const { + return *_owner; +} + +Main::Session &Histories::session() const { + return _owner->session(); +} + +History *Histories::find(PeerId peerId) { + const auto i = peerId ? _map.find(peerId) : end(_map); + return (i != end(_map)) ? i->second.get() : nullptr; +} + +not_null Histories::findOrCreate(PeerId peerId) { + Expects(peerId != 0); + + if (const auto result = find(peerId)) { + return result; + } + const auto [i, ok] = _map.emplace( + peerId, + std::make_unique(&owner(), peerId)); + return i->second.get(); +} + +void Histories::unloadAll() { + for (const auto &[peerId, history] : _map) { + history->clear(History::ClearType::Unload); + } +} + +void Histories::clearAll() { + _map.clear(); +} + +void Histories::readInboxTill( + not_null history, + not_null item) { + if (!IsServerMsgId(item->id)) { + auto view = item->mainView(); + if (!view) { + return; + } + auto block = view->block(); + auto blockIndex = block->indexInHistory(); + auto itemIndex = view->indexInBlock(); + while (blockIndex > 0 || itemIndex > 0) { + if (itemIndex > 0) { + view = block->messages[--itemIndex].get(); + } else { + while (blockIndex > 0) { + block = history->blocks[--blockIndex].get(); + itemIndex = block->messages.size(); + if (itemIndex > 0) { + view = block->messages[--itemIndex].get(); + break; + } + } + } + item = view->data(); + if (IsServerMsgId(item->id)) { + break; + } + } + if (!IsServerMsgId(item->id)) { + LOG(("App Error: " + "Can't read history till unknown local message.")); + return; + } + } + const auto tillId = item->id; + if (!history->readInboxTillNeedsRequest(tillId)) { + return; + } + const auto maybeState = lookup(history); + if (maybeState && maybeState->readTill >= tillId) { + return; + } + const auto stillUnread = history->countStillUnreadLocal(tillId); + if (stillUnread + && history->unreadCountKnown() + && *stillUnread == history->unreadCount()) { + history->setInboxReadTill(tillId); + return; + } + auto &state = _states[history]; + const auto wasWaiting = (state.readTill != 0); + state.readTill = tillId; + if (!stillUnread) { + state.readWhen = 0; + sendReadRequests(); + return; + } else if (!wasWaiting) { + state.readWhen = crl::now() + kReadRequestTimeout; + if (!_readRequestsTimer.isActive()) { + _readRequestsTimer.callOnce(kReadRequestTimeout); + } + } + history->setInboxReadTill(tillId); + history->setUnreadCount(*stillUnread); + history->updateChatListEntry(); +} + +void Histories::sendPendingReadInbox(not_null history) { + if (const auto state = lookup(history)) { + if (state->readTill && state->readWhen) { + state->readWhen = 0; + sendReadRequests(); + } + } +} + +void Histories::sendReadRequests() { + if (_states.empty()) { + return; + } + const auto now = crl::now(); + auto next = std::optional(); + for (auto &[history, state] : _states) { + if (state.readTill && state.readWhen <= now) { + sendReadRequest(history, state); + } else if (!next || *next > state.readWhen) { + next = state.readWhen; + } + } + if (next.has_value()) { + _readRequestsTimer.callOnce(*next - now); + } +} + +void Histories::sendReadRequest(not_null history, State &state) { + const auto tillId = state.readTill; + state.readWhen = kReadRequestSent; + sendRequest(history, RequestType::ReadInbox, [=](Fn done) { + const auto finished = [=] { + const auto state = lookup(history); + Assert(state != nullptr); + if (history->unreadCountRefreshNeeded(tillId)) { + session().api().requestDialogEntry(history); + } + if (state->readWhen == kReadRequestSent) { + state->readWhen = 0; + state->readTill = 0; + } + done(); + }; + if (const auto channel = history->peer->asChannel()) { + return session().api().request(MTPchannels_ReadHistory( + channel->inputChannel, + MTP_int(tillId) + )).done([=](const MTPBool &result) { + finished(); + }).fail([=](const RPCError &error) { + finished(); + }).send(); + } else { + return session().api().request(MTPmessages_ReadHistory( + history->peer->input, + MTP_int(tillId) + )).done([=](const MTPmessages_AffectedMessages &result) { + session().api().applyAffectedMessages(history->peer, result); + finished(); + }).fail([=](const RPCError &error) { + finished(); + }).send(); + } + }); +} + +void Histories::checkEmptyState(not_null history) { + const auto empty = [](const State &state) { + return state.postponed.empty() + && state.sent.empty() + && (state.readTill == 0); + }; + const auto i = _states.find(history); + if (i != end(_states) && empty(i->second)) { + _states.erase(i); + } +} + +int Histories::sendRequest( + not_null history, + RequestType type, + Fn done)> generator) { + Expects(type != RequestType::None); + + auto &state = _states[history]; + const auto id = ++state.autoincrement; + const auto action = chooseAction(state, type); + if (action == Action::Send) { + state.sent.emplace(id, SentRequest{ + generator([=] { checkPostponed(history, id); }), + type + }); + if (base::take(state.thenRequestEntry)) { + session().api().requestDialogEntry(history); + } + } else if (action == Action::Postpone) { + state.postponed.emplace( + id, + PostponedRequest{ std::move(generator), type }); + } + return id; +} + +void Histories::checkPostponed(not_null history, int requestId) { + const auto state = lookup(history); + Assert(state != nullptr); + + state->sent.remove(requestId); + if (!state->postponed.empty()) { + auto &entry = state->postponed.front(); + const auto action = chooseAction(*state, entry.second.type, true); + if (action == Action::Send) { + const auto id = entry.first; + state->postponed.remove(id); + state->sent.emplace(id, SentRequest{ + entry.second.generator([=] { checkPostponed(history, id); }), + entry.second.type + }); + if (base::take(state->thenRequestEntry)) { + session().api().requestDialogEntry(history); + } + } else { + Assert(action == Action::Postpone); + } + } + checkEmptyState(history); +} + +Histories::Action Histories::chooseAction( + State &state, + RequestType type, + bool fromPostponed) const { + switch (type) { + case RequestType::ReadInbox: + for (const auto &[_, sent] : state.sent) { + if (sent.type == RequestType::ReadInbox + || sent.type == RequestType::DialogsEntry + || sent.type == RequestType::Delete) { + if (!fromPostponed) { + auto &postponed = state.postponed; + for (auto i = begin(postponed); i != end(postponed);) { + if (i->second.type == RequestType::ReadInbox) { + i = postponed.erase(i); + } else { + ++i; + } + } + } + return Action::Postpone; + } + } + return Action::Send; + + case RequestType::DialogsEntry: + for (const auto &[_, sent] : state.sent) { + if (sent.type == RequestType::DialogsEntry) { + return Action::Skip; + } + if (sent.type == RequestType::ReadInbox + || sent.type == RequestType::Delete) { + if (!fromPostponed) { + auto &postponed = state.postponed; + for (const auto &[_, postponed] : state.postponed) { + if (postponed.type == RequestType::DialogsEntry) { + return Action::Skip; + } + } + } + return Action::Postpone; + } + } + return Action::Send; + + case RequestType::History: + for (const auto &[_, sent] : state.sent) { + if (sent.type == RequestType::Delete) { + return Action::Postpone; + } + } + return Action::Send; + + case RequestType::Delete: + for (const auto &[_, sent] : state.sent) { + if (sent.type == RequestType::History + || sent.type == RequestType::ReadInbox) { + return Action::Postpone; + } + } + for (auto i = begin(state.sent); i != end(state.sent);) { + if (i->second.type == RequestType::DialogsEntry) { + session().api().request(i->second.id).cancel(); + i = state.sent.erase(i); + state.thenRequestEntry = true; + } + } + return Action::Send; + } + Unexpected("Request type in Histories::chooseAction."); +} + +Histories::State *Histories::lookup(not_null history) { + const auto i = _states.find(history); + return (i != end(_states)) ? &i->second : nullptr; +} + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h new file mode 100644 index 000000000..de62ef09d --- /dev/null +++ b/Telegram/SourceFiles/data/data_histories.h @@ -0,0 +1,93 @@ +/* +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 +*/ +#pragma once + +#include "base/timer.h" + +class History; +class HistoryItem; + +namespace Main { +class Session; +} // namespace Main + +namespace Data { + +class Session; + +class Histories final { +public: + explicit Histories(not_null owner); + + [[nodiscard]] Session &owner() const; + [[nodiscard]] Main::Session &session() const; + + [[nodiscard]] History *find(PeerId peerId); + [[nodiscard]] not_null findOrCreate(PeerId peerId); + + void unloadAll(); + void clearAll(); + + void readInboxTill( + not_null history, + not_null item); + void sendPendingReadInbox(not_null history); + +private: + enum class RequestType : uchar { + None, + DialogsEntry, + History, + ReadInbox, + Delete, + }; + enum class Action : uchar { + Send, + Postpone, + Skip, + }; + struct PostponedRequest { + Fn done)> generator; + RequestType type = RequestType::None; + }; + struct SentRequest { + mtpRequestId id = 0; + RequestType type = RequestType::None; + }; + struct State { + base::flat_map postponed; + base::flat_map sent; + crl::time readWhen = 0; + MsgId readTill = 0; + int autoincrement = 0; + bool thenRequestEntry = false; + }; + + void sendReadRequests(); + void sendReadRequest(not_null history, State &state); + [[nodiscard]] State *lookup(not_null history); + void checkEmptyState(not_null history); + int sendRequest( + not_null history, + RequestType type, + Fn done)> generator); + void checkPostponed(not_null history, int requestId); + [[nodiscard]] Action chooseAction( + State &state, + RequestType type, + bool fromPostponed = false) const; + + const not_null _owner; + + std::unordered_map> _map; + base::flat_map, State> _states; + base::Timer _readRequestsTimer; + +}; + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 6638aa870..36f054075 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -48,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_cloud_themes.h" #include "data/data_streaming.h" #include "data/data_media_rotation.h" +#include "data/data_histories.h" #include "base/platform/base_platform_info.h" #include "base/unixtime.h" #include "base/call_delayed.h" @@ -194,7 +195,8 @@ Session::Session(not_null session) , _scheduledMessages(std::make_unique(this)) , _cloudThemes(std::make_unique(session)) , _streaming(std::make_unique(this)) -, _mediaRotation(std::make_unique()) { +, _mediaRotation(std::make_unique()) +, _histories(std::make_unique(this)) { _cache->open(Local::cacheKey()); _bigFileCache->open(Local::cacheBigFileKey()); @@ -215,9 +217,7 @@ Session::Session(not_null session) void Session::clear() { _sendActions.clear(); - for (const auto &[peerId, history] : _histories) { - history->clear(History::ClearType::Unload); - } + _histories->unloadAll(); _scheduledMessages = nullptr; _dependentMessages.clear(); base::take(_messages); @@ -227,7 +227,7 @@ void Session::clear() { cSetRecentInlineBots(RecentInlineBots()); cSetRecentStickers(RecentStickerPack()); App::clearMousedItems(); - _histories.clear(); + _histories->clearAll(); } not_null Session::peer(PeerId id) { @@ -768,20 +768,11 @@ void Session::enumerateChannels( } not_null Session::history(PeerId peerId) { - Expects(peerId != 0); - - if (const auto result = historyLoaded(peerId)) { - return result; - } - const auto [i, ok] = _histories.emplace( - peerId, - std::make_unique(this, peerId)); - return i->second.get(); + return _histories->findOrCreate(peerId); } History *Session::historyLoaded(PeerId peerId) const { - const auto i = peerId ? _histories.find(peerId) : end(_histories); - return (i != end(_histories)) ? i->second.get() : nullptr; + return _histories->find(peerId); } not_null Session::history(not_null peer) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 9b24d5294..aa2774292 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -61,6 +61,7 @@ class ScheduledMessages; class CloudThemes; class Streaming; class MediaRotation; +class Histories; class Session final { public: @@ -96,6 +97,9 @@ public: [[nodiscard]] MediaRotation &mediaRotation() const { return *_mediaRotation; } + [[nodiscard]] Histories &histories() const { + return *_histories; + } [[nodiscard]] MsgId nextNonHistoryEntryId() { return ++_nonHistoryEntryId; } @@ -968,7 +972,6 @@ private: base::Timer _unmuteByFinishedTimer; std::unordered_map> _peers; - std::unordered_map> _histories; MessageIdsList _mimeForwardIds; @@ -989,6 +992,7 @@ private: std::unique_ptr _cloudThemes; std::unique_ptr _streaming; std::unique_ptr _mediaRotation; + std::unique_ptr _histories; MsgId _nonHistoryEntryId = ServerMaxMsgId; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index fe2a8d8ed..325bae8f5 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_user.h" +#include "data/data_histories.h" #include "lang/lang_keys.h" #include "apiwrap.h" #include "mainwidget.h" @@ -1591,6 +1592,16 @@ void History::calculateFirstUnreadMessage() { } } +bool History::readInboxTillNeedsRequest(MsgId tillId) { + Expects(IsServerMsgId(tillId)); + + readClientSideMessages(); + if (unreadMark()) { + session().api().changeDialogUnreadMark(this, false); + } + return (_inboxReadBefore.value_or(1) <= tillId); +} + void History::readClientSideMessages() { auto unread = unreadCount(); for (const auto item : _localMessages) { @@ -1616,80 +1627,28 @@ MsgId History::readInbox() { } void History::readInboxTill(not_null item) { - if (!IsServerMsgId(item->id)) { - auto view = item->mainView(); - if (!view) { - return; - } - auto block = view->block(); - auto blockIndex = block->indexInHistory(); - auto itemIndex = view->indexInBlock(); - while (blockIndex > 0 || itemIndex > 0) { - if (itemIndex > 0) { - view = block->messages[--itemIndex].get(); - } else { - while (blockIndex > 0) { - block = blocks[--blockIndex].get(); - itemIndex = block->messages.size(); - if (itemIndex > 0) { - view = block->messages[--itemIndex].get(); - break; - } - } - } - item = view->data(); - if (IsServerMsgId(item->id)) { - break; - } - } - if (!IsServerMsgId(item->id)) { - LOG(("App Error: " - "Can't read history till unknown local message.")); - return; - } - } - readClientSideMessages(); - if (unreadMark()) { - session().api().changeDialogUnreadMark(this, false); - } - if (_inboxReadTillLocal >= item->id) { - return; - } - _inboxReadTillLocal = item->id; - const auto stillUnread = countStillUnreadLocal(); - if (!stillUnread) { - session().api().readServerHistoryForce(this, _inboxReadTillLocal); - return; - } - setInboxReadTill(_inboxReadTillLocal); - if (stillUnread && _unreadCount && *stillUnread == *_unreadCount) { - return; - } - setUnreadCount(*stillUnread); - session().api().readServerHistoryForce(this, _inboxReadTillLocal); - updateChatListEntry(); + owner().histories().readInboxTill(this, item); } -bool History::unreadCountRefreshNeeded() const { +bool History::unreadCountRefreshNeeded(MsgId readTillId) const { return !unreadCountKnown() - || ((_inboxReadTillLocal + 1) > _inboxReadBefore.value_or(0)); + || ((readTillId + 1) > _inboxReadBefore.value_or(0)); } -std::optional History::countStillUnreadLocal() const { +std::optional History::countStillUnreadLocal(MsgId readTillId) const { if (isEmpty()) { return std::nullopt; } - const auto till = _inboxReadTillLocal; if (_inboxReadBefore) { const auto before = *_inboxReadBefore; - if (minMsgId() <= before && maxMsgId() >= till) { + if (minMsgId() <= before && maxMsgId() >= readTillId) { auto result = 0; for (const auto &block : blocks) { for (const auto &message : block->messages) { const auto item = message->data(); if (item->out() || !IsServerMsgId(item->id)) { continue; - } else if (item->id > till) { + } else if (item->id > readTillId) { break; } else if (item->id >= before) { ++result; @@ -1701,14 +1660,16 @@ std::optional History::countStillUnreadLocal() const { } } } - if (!loadedAtBottom() || minMsgId() > till) { + if (!loadedAtBottom() || minMsgId() > readTillId) { return std::nullopt; } auto result = 0; for (const auto &block : blocks) { for (const auto &message : block->messages) { const auto item = message->data(); - if (!item->out() && IsServerMsgId(item->id) && item->id > till) { + if (!item->out() + && IsServerMsgId(item->id) + && item->id > readTillId) { ++result; } } @@ -1727,7 +1688,7 @@ void History::applyInboxReadUpdate( session().api().requestDialogEntry(this); session().api().requestDialogEntry(folder); } - if (_inboxReadTillLocal <= upTo) { + if (_inboxReadBefore.value_or(1) <= upTo) { if (!peer->isChannel() || peer->asChannel()->pts() == channelPts) { inboxRead(upTo, stillUnread); } else { @@ -2760,7 +2721,8 @@ void History::applyDialogFields( } else { clearFolder(); } - if (!skipUnreadUpdate() && maxInboxRead >= _inboxReadTillLocal) { + if (!skipUnreadUpdate() + && maxInboxRead >= _inboxReadBefore.value_or(1)) { setUnreadCount(unreadCount); setInboxReadTill(maxInboxRead); } @@ -2794,7 +2756,6 @@ void History::setInboxReadTill(MsgId upTo) { } else { _inboxReadBefore = upTo + 1; } - accumulate_max(_inboxReadTillLocal, upTo); } void History::setOutboxReadTill(MsgId upTo) { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 83d8a9f15..9b57e4d62 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -160,6 +160,7 @@ public: MsgId readInbox(); void readInboxTill(not_null item); + [[nodiscard]] bool readInboxTillNeedsRequest(MsgId tillId); void applyInboxReadUpdate( FolderId folderId, MsgId upTo, @@ -177,7 +178,7 @@ public: [[nodiscard]] bool unreadCountKnown() const; // Some old unread count is known, but we read history till some place. - [[nodiscard]] bool unreadCountRefreshNeeded() const; + [[nodiscard]] bool unreadCountRefreshNeeded(MsgId readTillId) const; void setUnreadCount(int newUnreadCount); void setUnreadMark(bool unread); @@ -349,6 +350,10 @@ public: HistoryItem *folderDialogItem = nullptr); void clearFolder(); + // Interface for Data::Histories. + void setInboxReadTill(MsgId upTo); + std::optional countStillUnreadLocal(MsgId readTillId) const; + // Still public data. std::deque> blocks; @@ -437,7 +442,6 @@ private: TimeId adjustedChatListTimeId() const override; void changedChatListPinHook() override; - void setInboxReadTill(MsgId upTo); void setOutboxReadTill(MsgId upTo); void readClientSideMessages(); @@ -474,7 +478,6 @@ private: void getNextFirstUnreadMessage(); bool nonEmptyCountMoreThan(int count) const; std::optional countUnread(MsgId upTo) const; - std::optional countStillUnreadLocal() const; // Creates if necessary a new block for adding item. // Depending on isBuildingFrontBlock() gets front or back block. @@ -503,7 +506,6 @@ private: std::optional _inboxReadBefore; std::optional _outboxReadBefore; - MsgId _inboxReadTillLocal = 0; std::optional _unreadCount; std::optional _unreadMentionsCount; base::flat_set _unreadMentions; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index e7892de32..ea4701bd3 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -41,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user.h" #include "data/data_scheduled_messages.h" #include "data/data_file_origin.h" +#include "data/data_histories.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_message.h" @@ -1706,6 +1707,7 @@ void HistoryWidget::showHistory( return; } updateSendAction(_history, SendAction::Type::Typing, -1); + session().data().histories().sendPendingReadInbox(_history); cancelTypingAction(); } From 9cccea9a871ea802f8a4dbdad43a9b96fd0752d8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 18 Feb 2020 16:15:43 +0400 Subject: [PATCH 049/140] All read history done through Data::Histories. --- Telegram/SourceFiles/apiwrap.cpp | 80 +------------------ Telegram/SourceFiles/apiwrap.h | 15 ---- Telegram/SourceFiles/data/data_histories.cpp | 5 +- Telegram/SourceFiles/data/data_histories.h | 1 + Telegram/SourceFiles/history/history.cpp | 47 +++++++++-- Telegram/SourceFiles/history/history.h | 2 +- .../SourceFiles/window/window_peer_menu.cpp | 2 +- 7 files changed, 48 insertions(+), 104 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 860489070..9e6d5d085 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -4432,7 +4432,7 @@ void ApiWrap::userPhotosDone( //} void ApiWrap::sendAction(const SendAction &action) { - readServerHistory(action.history); + action.history->readInbox(); action.history->getReadyFor(ShowAtTheEndMsgId); _sendActions.fire_copy(action); } @@ -4459,7 +4459,7 @@ void ApiWrap::forwardMessages( const auto history = action.history; const auto peer = history->peer; - readServerHistory(history); + history->readInbox(); const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto silentPost = action.options.silent @@ -6000,46 +6000,6 @@ void ApiWrap::reloadPollResults(not_null item) { _pollReloadRequestIds.emplace(itemId, requestId); } -void ApiWrap::readServerHistory(not_null history) { - if (history->unreadCount()) { - readServerHistoryForce(history); - } - if (history->unreadMark()) { - changeDialogUnreadMark(history, false); - } -} - -void ApiWrap::readServerHistoryForce( - not_null history, - MsgId upTo) { - const auto peer = history->peer; - if (!upTo) { - upTo = history->readInbox(); - if (!upTo) { - return; - } - } - if (const auto channel = peer->asChannel()) { - if (!channel->amIn()) { - return; // no read request for channels that I didn't join - } else if (const auto migrateFrom = channel->migrateFrom()) { - if (const auto migrated = _session->data().historyLoaded(migrateFrom)) { - readServerHistory(migrated); - } - } - } - - if (_readRequests.contains(peer)) { - const auto i = _readRequestsPending.find(peer); - if (i == _readRequestsPending.cend()) { - _readRequestsPending.emplace(peer, upTo); - } else if (i->second < upTo) { - i->second = upTo; - } - } else { - sendReadRequest(peer, upTo); - } -} // // #feed //void ApiWrap::readFeed( // not_null feed, @@ -6093,39 +6053,3 @@ void ApiWrap::readServerHistoryForce( // _feedReadTimer.callOnce(delay); // } //} - -void ApiWrap::sendReadRequest(not_null peer, MsgId upTo) { - const auto requestId = [&] { - const auto finished = [=] { - _readRequests.remove(peer); - if (const auto next = _readRequestsPending.take(peer)) { - sendReadRequest(peer, *next); - } else if (const auto history - = _session->data().historyLoaded(peer)) { - if (!history->unreadCountKnown()) { - requestDialogEntry(history); - } - } - }; - if (const auto channel = peer->asChannel()) { - return request(MTPchannels_ReadHistory( - channel->inputChannel, - MTP_int(upTo) - )).done([=](const MTPBool &result) { - finished(); - }).fail([=](const RPCError &error) { - finished(); - }).send(); - } - return request(MTPmessages_ReadHistory( - peer->input, - MTP_int(upTo) - )).done([=](const MTPmessages_AffectedMessages &result) { - applyAffectedMessages(peer, result); - finished(); - }).fail([=](const RPCError &error) { - finished(); - }).send(); - }(); - _readRequests.emplace(peer, requestId, upTo); -} diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 137169659..f7bddf0af 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -389,8 +389,6 @@ public: const QString &lastName, const SendAction &action); void shareContact(not_null user, const SendAction &action); - void readServerHistory(not_null history); - void readServerHistoryForce(not_null history, MsgId upTo = 0); //void readFeed( // #feed // not_null feed, // Data::MessagePosition position); @@ -626,7 +624,6 @@ private: not_null peer, bool justClear, bool revoke); - void sendReadRequest(not_null peer, MsgId upTo); int applyAffectedHistory( not_null peer, const MTPmessages_AffectedHistory &result); @@ -800,18 +797,6 @@ private: rpl::event_stream _sendActions; - struct ReadRequest { - ReadRequest(mtpRequestId requestId, MsgId upTo) - : requestId(requestId) - , upTo(upTo) { - } - - mtpRequestId requestId = 0; - MsgId upTo = 0; - }; - base::flat_map, ReadRequest> _readRequests; - base::flat_map, MsgId> _readRequestsPending; - std::unique_ptr _fileLoader; base::flat_map> _sendingAlbums; diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index fa30a0743..9c8dc7d82 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -98,7 +98,10 @@ void Histories::readInboxTill( return; } } - const auto tillId = item->id; + readInboxTill(history, item->id); +} + +void Histories::readInboxTill(not_null history, MsgId tillId) { if (!history->readInboxTillNeedsRequest(tillId)) { return; } diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index de62ef09d..ebf6f8648 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -36,6 +36,7 @@ public: void readInboxTill( not_null history, not_null item); + void readInboxTill(not_null history, MsgId tillId); void sendPendingReadInbox(not_null history); private: diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 325bae8f5..c7be764d9 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1614,16 +1614,47 @@ void History::readClientSideMessages() { } } -MsgId History::readInbox() { - const auto upTo = msgIdForRead(); - readClientSideMessages(); - if (unreadCountKnown()) { - setUnreadCount(0); +void History::readInbox() { + if (_lastMessage) { + if (!*_lastMessage) { + owner().histories().readInboxTill(this, 0); + return; + } else if (IsServerMsgId((*_lastMessage)->id)) { + readInboxTill(*_lastMessage); + return; + } } - if (upTo) { - inboxRead(upTo); + if (loadedAtBottom()) { + const auto last = [&]() -> HistoryItem* { + for (const auto &block : ranges::view::reverse(blocks)) { + const auto &messages = block->messages; + for (const auto &item : ranges::view::reverse(messages)) { + if (IsServerMsgId(item->data()->id)) { + return item->data(); + } + } + } + return nullptr; + }(); + if (last) { + readInboxTill(last); + return; + } else if (loadedAtTop()) { + owner().histories().readInboxTill(this, 0); + return; + } } - return upTo; + session().api().requestDialogEntry(this, [=] { + Expects(_lastMessage.has_value()); + + if (!*_lastMessage) { + owner().histories().readInboxTill(this, 0); + } else if (IsServerMsgId((*_lastMessage)->id)) { + readInboxTill(*_lastMessage); + } else { + Unexpected("Local _lastMessage after requestDialogEntry."); + } + }); } void History::readInboxTill(not_null item) { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 9b57e4d62..47d833970 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -158,7 +158,7 @@ public: void unregisterLocalMessage(not_null item); [[nodiscard]] HistoryItem *latestSendingMessage() const; - MsgId readInbox(); + void readInbox(); void readInboxTill(not_null item); [[nodiscard]] bool readInboxTillNeedsRequest(MsgId tillId); void applyInboxReadUpdate( diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 5fa03afab..47881396a 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -303,7 +303,7 @@ void Filler::addToggleUnreadMark() { const auto markAsRead = isUnread(peer); const auto handle = [&](not_null history) { if (markAsRead) { - peer->session().api().readServerHistory(history); + history->readInbox(); } else { peer->session().api().changeDialogUnreadMark( history, From 32d93e265121402b9f467bf773c86c2e56774ef9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 19 Feb 2020 16:40:01 +0400 Subject: [PATCH 050/140] Fix several read requests together. --- Telegram/SourceFiles/data/data_histories.cpp | 14 +++++++++++--- Telegram/SourceFiles/history/history.cpp | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 9c8dc7d82..27aef7d02 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -117,13 +117,13 @@ void Histories::readInboxTill(not_null history, MsgId tillId) { return; } auto &state = _states[history]; - const auto wasWaiting = (state.readTill != 0); + const auto wasReadTill = state.readTill; state.readTill = tillId; if (!stillUnread) { state.readWhen = 0; sendReadRequests(); return; - } else if (!wasWaiting) { + } else if (!wasReadTill) { state.readWhen = crl::now() + kReadRequestTimeout; if (!_readRequestsTimer.isActive()) { _readRequestsTimer.callOnce(kReadRequestTimeout); @@ -158,6 +158,8 @@ void Histories::sendReadRequests() { } if (next.has_value()) { _readRequestsTimer.callOnce(*next - now); + } else { + _readRequestsTimer.cancel(); } } @@ -168,12 +170,18 @@ void Histories::sendReadRequest(not_null history, State &state) { const auto finished = [=] { const auto state = lookup(history); Assert(state != nullptr); + Assert(state->readTill >= tillId); + if (history->unreadCountRefreshNeeded(tillId)) { session().api().requestDialogEntry(history); } if (state->readWhen == kReadRequestSent) { state->readWhen = 0; - state->readTill = 0; + if (state->readTill == tillId) { + state->readTill = 0; + } else { + sendReadRequests(); + } } done(); }; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index c7be764d9..247b9893d 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1667,7 +1667,7 @@ bool History::unreadCountRefreshNeeded(MsgId readTillId) const { } std::optional History::countStillUnreadLocal(MsgId readTillId) const { - if (isEmpty()) { + if (isEmpty() || !folderKnown()) { return std::nullopt; } if (_inboxReadBefore) { From c04f3a704800144948fbe114a33f56fd95384517 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 19 Feb 2020 17:49:49 +0400 Subject: [PATCH 051/140] Don't replace local with server last message. --- Telegram/SourceFiles/history/history.cpp | 33 ++++++++++--------- Telegram/SourceFiles/history/history.h | 1 + .../SourceFiles/history/history_widget.cpp | 19 ----------- 3 files changed, 19 insertions(+), 34 deletions(-) diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 247b9893d..15834f0d4 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1937,8 +1937,8 @@ void History::setFolder( not_null folder, HistoryItem *folderDialogItem) { setFolderPointer(folder); - if (folderDialogItem && _lastMessage != folderDialogItem) { - setLastMessage(folderDialogItem); + if (folderDialogItem) { + setLastServerMessage(folderDialogItem); } } @@ -2369,16 +2369,19 @@ void History::clearSharedMedia() { //} } +void History::setLastServerMessage(HistoryItem *item) { + if (_lastMessage + && *_lastMessage + && !IsServerMsgId((*_lastMessage)->id) + && (!item || (*_lastMessage)->date() > item->date())) { + return; + } + setLastMessage(item); +} + void History::setLastMessage(HistoryItem *item) { - if (_lastMessage) { - if (*_lastMessage == item) { - return; - } else if (*_lastMessage - && item - && !IsServerMsgId((*_lastMessage)->id) - && (*_lastMessage)->date() > item->date()) { - return; - } + if (_lastMessage && *_lastMessage == item) { + return; } _lastMessage = item; if (peer->migrateTo()) { @@ -2766,12 +2769,12 @@ void History::applyDialogTopMessage(MsgId topMessageId) { channelId(), topMessageId); if (const auto item = owner().message(itemId)) { - setLastMessage(item); + setLastServerMessage(item); } else { - setLastMessage(nullptr); + setLastServerMessage(nullptr); } } else { - setLastMessage(nullptr); + setLastServerMessage(nullptr); } if (clearUnreadOnClientSide()) { setUnreadCount(0); @@ -3167,7 +3170,7 @@ void History::clear(ClearType type) { setUnreadCount(0); } if (type == ClearType::DeleteChat) { - setLastMessage(nullptr); + setLastServerMessage(nullptr); } else if (_lastMessage && *_lastMessage) { if (IsServerMsgId((*_lastMessage)->id)) { (*_lastMessage)->applyEditionToHistoryCleared(); diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 47d833970..9385c6da7 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -455,6 +455,7 @@ private: // After adding a new history slice check lastMessage / loadedAtBottom. void checkLastMessage(); void setLastMessage(HistoryItem *item); + void setLastServerMessage(HistoryItem *item); void refreshChatListMessage(); void setChatListMessage(HistoryItem *item); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index ea4701bd3..d34e0cc13 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -145,22 +145,6 @@ void ActivateWindow(not_null controller) { Ui::ActivateWindowDelayed(window); } -bool ShowHistoryEndInsteadOfUnread( - not_null session, - PeerId peerId) { - // Ignore unread messages in case of unread changelogs. - // We must show this history at end for the changelog to be visible. - if (peerId != PeerData::kServiceNotificationsId) { - return false; - } - const auto history = session->history(peerId); - if (!history->unreadCount()) { - return false; - } - const auto last = history->lastMessage(); - return (last != nullptr) && !IsServerMsgId(last->id); -} - object_ptr SetupDiscussButton( not_null parent, not_null controller) { @@ -1646,9 +1630,6 @@ void HistoryWidget::showHistory( const auto startBot = (showAtMsgId == ShowAndStartBotMsgId); if (startBot) { showAtMsgId = ShowAtTheEndMsgId; - } else if ((showAtMsgId == ShowAtUnreadMsgId) - && ShowHistoryEndInsteadOfUnread(&session().data(), peerId)) { - showAtMsgId = ShowAtTheEndMsgId; } clearHighlightMessages(); From 5b7f7ed70e8e357657bf354d23bb8c4c3ec75ba1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 19 Feb 2020 19:35:26 +0400 Subject: [PATCH 052/140] Fix reading of currently opened chat. --- Telegram/SourceFiles/apiwrap.cpp | 5 +- Telegram/SourceFiles/data/data_histories.cpp | 78 ++++++++++-- Telegram/SourceFiles/data/data_histories.h | 8 +- Telegram/SourceFiles/history/history.cpp | 117 +++++------------- Telegram/SourceFiles/history/history.h | 6 +- .../history/history_inner_widget.cpp | 5 +- .../SourceFiles/history/history_widget.cpp | 2 +- .../SourceFiles/window/window_peer_menu.cpp | 3 +- 8 files changed, 115 insertions(+), 109 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 9e6d5d085..d2aa28548 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_user.h" #include "data/data_cloud_themes.h" +#include "data/data_histories.h" #include "dialogs/dialogs_key.h" #include "core/core_cloud_password.h" #include "core/application.h" @@ -4432,7 +4433,7 @@ void ApiWrap::userPhotosDone( //} void ApiWrap::sendAction(const SendAction &action) { - action.history->readInbox(); + session().data().histories().readInbox(action.history); action.history->getReadyFor(ShowAtTheEndMsgId); _sendActions.fire_copy(action); } @@ -4459,7 +4460,7 @@ void ApiWrap::forwardMessages( const auto history = action.history; const auto peer = history->peer; - history->readInbox(); + session().data().histories().readInbox(history); const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto silentPost = action.options.silent diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 27aef7d02..5e06e4367 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -63,10 +63,32 @@ void Histories::clearAll() { _map.clear(); } -void Histories::readInboxTill( - not_null history, - not_null item) { +void Histories::readInbox(not_null history) { + if (history->lastServerMessageKnown()) { + const auto last = history->lastServerMessage(); + readInboxTill(history, last ? last->id : 0); + return; + } else if (history->loadedAtBottom()) { + if (const auto lastId = history->maxMsgId()) { + readInboxTill(history, lastId); + return; + } else if (history->loadedAtTop()) { + readInboxTill(history, 0); + return; + } + } + session().api().requestDialogEntry(history, [=] { + Expects(history->lastServerMessageKnown()); + + const auto last = history->lastServerMessage(); + readInboxTill(history, last ? last->id : 0); + }); +} + +void Histories::readInboxTill(not_null item) { + const auto history = item->history(); if (!IsServerMsgId(item->id)) { + readClientSideMessage(item); auto view = item->mainView(); if (!view) { return; @@ -102,15 +124,23 @@ void Histories::readInboxTill( } void Histories::readInboxTill(not_null history, MsgId tillId) { - if (!history->readInboxTillNeedsRequest(tillId)) { - return; - } - const auto maybeState = lookup(history); - if (maybeState && maybeState->readTill >= tillId) { + readInboxTill(history, tillId, false); +} +void Histories::readInboxTill( + not_null history, + MsgId tillId, + bool force) { + if (!history->readInboxTillNeedsRequest(tillId) && !force) { return; + } else if (!force) { + const auto maybeState = lookup(history); + if (maybeState && maybeState->readTill >= tillId) { + return; + } } const auto stillUnread = history->countStillUnreadLocal(tillId); - if (stillUnread + if (!force + && stillUnread && history->unreadCountKnown() && *stillUnread == history->unreadCount()) { history->setInboxReadTill(tillId); @@ -119,10 +149,12 @@ void Histories::readInboxTill(not_null history, MsgId tillId) { auto &state = _states[history]; const auto wasReadTill = state.readTill; state.readTill = tillId; - if (!stillUnread) { + if (force || !stillUnread || !*stillUnread) { state.readWhen = 0; sendReadRequests(); - return; + if (!stillUnread) { + return; + } } else if (!wasReadTill) { state.readWhen = crl::now() + kReadRequestTimeout; if (!_readRequestsTimer.isActive()) { @@ -134,6 +166,25 @@ void Histories::readInboxTill(not_null history, MsgId tillId) { history->updateChatListEntry(); } +void Histories::readInboxOnNewMessage(not_null item) { + if (!IsServerMsgId(item->id)) { + readClientSideMessage(item); + } else { + readInboxTill(item->history(), item->id, true); + } +} + +void Histories::readClientSideMessage(not_null item) { + if (item->out() || !item->unread()) { + return; + } + const auto history = item->history(); + item->markClientSideAsRead(); + if (const auto unread = history->unreadCount()) { + history->setUnreadCount(unread - 1); + } +} + void Histories::sendPendingReadInbox(not_null history) { if (const auto state = lookup(history)) { if (state->readTill && state->readWhen) { @@ -255,10 +306,11 @@ void Histories::checkPostponed(not_null history, int requestId) { const auto action = chooseAction(*state, entry.second.type, true); if (action == Action::Send) { const auto id = entry.first; + const auto postponed = std::move(entry.second); state->postponed.remove(id); state->sent.emplace(id, SentRequest{ - entry.second.generator([=] { checkPostponed(history, id); }), - entry.second.type + postponed.generator([=] { checkPostponed(history, id); }), + postponed.type }); if (base::take(state->thenRequestEntry)) { session().api().requestDialogEntry(history); diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index ebf6f8648..42a9641ce 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -33,10 +33,11 @@ public: void unloadAll(); void clearAll(); - void readInboxTill( - not_null history, - not_null item); + void readInbox(not_null history); + void readInboxTill(not_null item); void readInboxTill(not_null history, MsgId tillId); + void readInboxOnNewMessage(not_null item); + void readClientSideMessage(not_null item); void sendPendingReadInbox(not_null history); private: @@ -69,6 +70,7 @@ private: bool thenRequestEntry = false; }; + void readInboxTill(not_null history, MsgId tillId, bool force); void sendReadRequests(); void sendReadRequest(not_null history, State &state); [[nodiscard]] State *lookup(not_null history); diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 15834f0d4..66e46c0e7 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -136,6 +136,9 @@ void History::itemRemoved(not_null item) { _joinedMessage = nullptr; } item->removeMainView(); + if (_lastServerMessage == item) { + _lastServerMessage = std::nullopt; + } if (lastMessage() == item) { _lastMessage = std::nullopt; if (loadedAtBottom()) { @@ -1546,27 +1549,6 @@ void History::addToSharedMedia( } } -std::optional History::countUnread(MsgId upTo) const { - if (!folderKnown() || !loadedAtBottom()) { - return std::nullopt; - } - auto result = 0; - for (auto i = blocks.cend(), e = blocks.cbegin(); i != e;) { - --i; - const auto &messages = (*i)->messages; - for (auto j = messages.cend(), en = messages.cbegin(); j != en;) { - --j; - const auto item = (*j)->data(); - if (item->id > 0 && item->id <= upTo) { - return result; - } else if (!item->out() && item->unread()) { - ++result; - } - } - } - return std::nullopt; -} - void History::calculateFirstUnreadMessage() { if (_firstUnreadView || !_inboxReadBefore) { return; @@ -1603,64 +1585,12 @@ bool History::readInboxTillNeedsRequest(MsgId tillId) { } void History::readClientSideMessages() { - auto unread = unreadCount(); + auto &histories = owner().histories(); for (const auto item : _localMessages) { - if (!item->out() && item->unread()) { - item->markClientSideAsRead(); - if (unread > 0) { - setUnreadCount(--unread); - } - } + histories.readClientSideMessage(item); } } -void History::readInbox() { - if (_lastMessage) { - if (!*_lastMessage) { - owner().histories().readInboxTill(this, 0); - return; - } else if (IsServerMsgId((*_lastMessage)->id)) { - readInboxTill(*_lastMessage); - return; - } - } - if (loadedAtBottom()) { - const auto last = [&]() -> HistoryItem* { - for (const auto &block : ranges::view::reverse(blocks)) { - const auto &messages = block->messages; - for (const auto &item : ranges::view::reverse(messages)) { - if (IsServerMsgId(item->data()->id)) { - return item->data(); - } - } - } - return nullptr; - }(); - if (last) { - readInboxTill(last); - return; - } else if (loadedAtTop()) { - owner().histories().readInboxTill(this, 0); - return; - } - } - session().api().requestDialogEntry(this, [=] { - Expects(_lastMessage.has_value()); - - if (!*_lastMessage) { - owner().histories().readInboxTill(this, 0); - } else if (IsServerMsgId((*_lastMessage)->id)) { - readInboxTill(*_lastMessage); - } else { - Unexpected("Local _lastMessage after requestDialogEntry."); - } - }); -} - -void History::readInboxTill(not_null item) { - owner().histories().readInboxTill(this, item); -} - bool History::unreadCountRefreshNeeded(MsgId readTillId) const { return !unreadCountKnown() || ((readTillId + 1) > _inboxReadBefore.value_or(0)); @@ -1691,17 +1621,22 @@ std::optional History::countStillUnreadLocal(MsgId readTillId) const { } } } - if (!loadedAtBottom() || minMsgId() > readTillId) { + const auto minimalServerId = minMsgId(); + if (!loadedAtBottom() + || (!loadedAtTop() && !minimalServerId) + || minimalServerId > readTillId) { return std::nullopt; } auto result = 0; - for (const auto &block : blocks) { - for (const auto &message : block->messages) { + for (const auto &block : ranges::view::reverse(blocks)) { + for (const auto &message : ranges::view::reverse(block->messages)) { const auto item = message->data(); - if (!item->out() - && IsServerMsgId(item->id) - && item->id > readTillId) { - ++result; + if (IsServerMsgId(item->id)) { + if (item->id <= readTillId) { + return result; + } else if (!item->out()) { + ++result; + } } } } @@ -1734,7 +1669,7 @@ void History::inboxRead(MsgId upTo, std::optional stillUnread) { } if (stillUnread.has_value() && folderKnown()) { setUnreadCount(*stillUnread); - } else if (const auto still = countUnread(upTo)) { + } else if (const auto still = countStillUnreadLocal(upTo)) { setUnreadCount(*still); } else { session().api().requestDialogEntry(this); @@ -2370,6 +2305,7 @@ void History::clearSharedMedia() { } void History::setLastServerMessage(HistoryItem *item) { + _lastServerMessage = item; if (_lastMessage && *_lastMessage && !IsServerMsgId((*_lastMessage)->id) @@ -2384,6 +2320,9 @@ void History::setLastMessage(HistoryItem *item) { return; } _lastMessage = item; + if (!item || IsServerMsgId(item->id)) { + _lastServerMessage = item; + } if (peer->migrateTo()) { // We don't want to request last message for all deactivated chats. // This is a heavy request for them, because we need to get last @@ -2583,6 +2522,14 @@ bool History::lastMessageKnown() const { return _lastMessage.has_value(); } +HistoryItem *History::lastServerMessage() const { + return _lastServerMessage.value_or(nullptr); +} + +bool History::lastServerMessageKnown() const { + return _lastServerMessage.has_value(); +} + void History::updateChatListExistence() { Entry::updateChatListExistence(); //if (const auto channel = peer->asChannel()) { // #feed @@ -2691,7 +2638,9 @@ void History::applyDialog( } void History::dialogEntryApplied() { - if (!lastMessageKnown()) { + if (!lastServerMessageKnown()) { + setLastServerMessage(nullptr); + } else if (!lastMessageKnown()) { setLastMessage(nullptr); } if (peer->migrateTo()) { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 9385c6da7..f54cfc1f8 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -158,8 +158,6 @@ public: void unregisterLocalMessage(not_null item); [[nodiscard]] HistoryItem *latestSendingMessage() const; - void readInbox(); - void readInboxTill(not_null item); [[nodiscard]] bool readInboxTillNeedsRequest(MsgId tillId); void applyInboxReadUpdate( FolderId folderId, @@ -203,7 +201,9 @@ public: void getReadyFor(MsgId msgId); [[nodiscard]] HistoryItem *lastMessage() const; + [[nodiscard]] HistoryItem *lastServerMessage() const; [[nodiscard]] bool lastMessageKnown() const; + [[nodiscard]] bool lastServerMessageKnown() const; void unknownMessageDeleted(MsgId messageId); void applyDialogTopMessage(MsgId topMessageId); void applyDialog(Data::Folder *requestFolder, const MTPDdialog &data); @@ -478,7 +478,6 @@ private: HistoryItem *lastAvailableMessage() const; void getNextFirstUnreadMessage(); bool nonEmptyCountMoreThan(int count) const; - std::optional countUnread(MsgId upTo) const; // Creates if necessary a new block for adding item. // Depending on isBuildingFrontBlock() gets front or back block. @@ -511,6 +510,7 @@ private: std::optional _unreadMentionsCount; base::flat_set _unreadMentions; std::optional _lastMessage; + std::optional _lastServerMessage; base::flat_set> _localMessages; // This almost always is equal to _lastMessage. The only difference is diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 85e7c9716..815bb3175 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_photo.h" #include "data/data_user.h" #include "data/data_file_origin.h" +#include "data/data_histories.h" #include "facades.h" #include "app.h" @@ -704,7 +705,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { p.restore(); if (readTill) { - _history->readInboxTill(readTill); + session().data().histories().readInboxTill(readTill); } } @@ -2059,7 +2060,7 @@ void HistoryInner::checkHistoryActivation() { } } } - _history->readInboxTill(view->data()); + session().data().histories().readInboxTill(view->data()); } void HistoryInner::recountHistoryGeometry() { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index d34e0cc13..8eeccd3ea 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2259,7 +2259,7 @@ void HistoryWidget::unreadMessageAdded(not_null item) { if (item->isUnreadMention() && !item->isUnreadMedia()) { session().api().markMediaRead(item); } - _history->readInboxTill(item); + session().data().histories().readInboxOnNewMessage(item); // Also clear possible scheduled messages notifications. session().notifications().clearFromHistory(_history); diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 47881396a..64220b5a2 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_drafts.h" #include "data/data_user.h" #include "data/data_scheduled_messages.h" +#include "data/data_histories.h" #include "dialogs/dialogs_key.h" #include "boxes/peers/edit_peer_info_box.h" #include "facades.h" @@ -303,7 +304,7 @@ void Filler::addToggleUnreadMark() { const auto markAsRead = isUnread(peer); const auto handle = [&](not_null history) { if (markAsRead) { - history->readInbox(); + peer->session().data().histories().readInbox(history); } else { peer->session().api().changeDialogUnreadMark( history, From b5dcd845135e35b65bb257c4715e430de70fdfd9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 19 Feb 2020 20:54:19 +0400 Subject: [PATCH 053/140] Fix stop-auto-read when the system is idle. --- Telegram/SourceFiles/data/data_histories.cpp | 1 + Telegram/SourceFiles/history/history_inner_widget.cpp | 7 +++++-- Telegram/SourceFiles/mainwindow.cpp | 6 ++++-- Telegram/SourceFiles/mainwindow.h | 1 + 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 5e06e4367..c3e945da5 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -126,6 +126,7 @@ void Histories::readInboxTill(not_null item) { void Histories::readInboxTill(not_null history, MsgId tillId) { readInboxTill(history, tillId, false); } + void Histories::readInboxTill( not_null history, MsgId tillId, diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 815bb3175..3b195f368 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -674,7 +674,10 @@ void HistoryInner::paintEvent(QPaintEvent *e) { const auto middle = y + h / 2; const auto bottom = y + h; if (_visibleAreaBottom >= bottom) { - readTill = view->data(); + const auto item = view->data(); + if (!item->out() && item->unread()) { + readTill = item; + } } if (_visibleAreaBottom >= middle && _visibleAreaTop <= middle) { @@ -704,7 +707,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } p.restore(); - if (readTill) { + if (readTill && _widget->doWeReadServerHistory()) { session().data().histories().readInboxTill(readTill); } } diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 652ae6763..6df70cd0d 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -508,7 +508,7 @@ bool MainWindow::doWeMarkAsRead() { return false; } updateIsActive(0); - return isActive(); + return isActive() && _main->doWeMarkAsRead(); } void MainWindow::checkHistoryActivation() { @@ -549,10 +549,12 @@ bool MainWindow::eventFilter(QObject *object, QEvent *e) { } break; case QEvent::MouseMove: { - if (_main && _main->isIdle()) { + const auto position = static_cast(e)->globalPos(); + if (_main && _main->isIdle() && _lastMousePosition != position) { Core::App().updateNonIdle(); _main->checkIdleFinish(); } + _lastMousePosition = position; } break; case QEvent::MouseButtonRelease: { diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 076ff1b23..d9b6fae0c 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -167,6 +167,7 @@ private: QImage icon16, icon32, icon64, iconbig16, iconbig32, iconbig64; crl::time _lastTrayClickTime = 0; + QPoint _lastMousePosition; object_ptr _passcodeLock = { nullptr }; object_ptr _intro = { nullptr }; From 635752990143b58073df2be41b19ac3eb1256fe8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 10:55:50 +0400 Subject: [PATCH 054/140] Fix 90/270 degrees photo rotation. Fixes #7197. --- .../SourceFiles/media/view/media_view_overlay_widget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index c82d7cae7..22c661655 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -2689,12 +2689,12 @@ void OverlayWidget::validatePhotoImage(Image *image, bool blurred) { } else if (!_staticContent.isNull() && (blurred || !_blurred)) { return; } - const auto w = _width * cIntRetinaFactor(); - const auto h = _height * cIntRetinaFactor(); + const auto use = flipSizeByRotation({ _width, _height }) + * cIntRetinaFactor(); _staticContent = image->pixNoCache( fileOrigin(), - w, - h, + use.width(), + use.height(), Images::Option::Smooth | (blurred ? Images::Option::Blurred : Images::Option(0))); _staticContent.setDevicePixelRatio(cRetinaFactor()); From c8d2ac95831d466494566367572838e517d3702f Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 12:45:25 +0400 Subject: [PATCH 055/140] Move message ownership to History. --- Telegram/SourceFiles/apiwrap.cpp | 7 +- .../boxes/background_preview_box.cpp | 3 +- Telegram/SourceFiles/data/data_channel.cpp | 3 + Telegram/SourceFiles/data/data_session.cpp | 39 ++------ Telegram/SourceFiles/data/data_session.h | 23 +---- .../admin_log/history_admin_log_item.cpp | 33 +++---- Telegram/SourceFiles/history/history.cpp | 92 +++++++++++++------ Telegram/SourceFiles/history/history.h | 21 +++++ Telegram/SourceFiles/history/history_item.cpp | 29 ++---- .../SourceFiles/history/history_service.cpp | 7 +- .../SourceFiles/history/history_service.h | 2 +- .../settings/settings_privacy_controllers.cpp | 3 +- .../support/support_autocomplete.cpp | 6 +- 13 files changed, 138 insertions(+), 130 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index d2aa28548..319399bfb 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2424,7 +2424,8 @@ int ApiWrap::OnlineTillFromStatus( void ApiWrap::clearHistory(not_null peer, bool revoke) { auto deleteTillId = MsgId(0); - if (const auto history = _session->data().historyLoaded(peer)) { + const auto history = _session->data().historyLoaded(peer); + if (history) { while (history->lastMessageKnown()) { const auto last = history->lastMessage(); if (!last) { @@ -2446,7 +2447,6 @@ void ApiWrap::clearHistory(not_null peer, bool revoke) { return; } deleteTillId = history->lastMessage()->id; - history->clear(History::ClearType::ClearHistory); } if (const auto channel = peer->asChannel()) { if (const auto migrated = peer->migrateFrom()) { @@ -2461,6 +2461,9 @@ void ApiWrap::clearHistory(not_null peer, bool revoke) { } else { deleteHistory(peer, true, revoke); } + if (history) { + history->clear(History::ClearType::ClearHistory); + } } void ApiWrap::deleteConversation(not_null peer, bool revoke) { diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index e72908a01..475c04009 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -293,8 +293,7 @@ AdminLog::OwnedItem GenerateTextItem( const auto clientFlags = MTPDmessage_ClientFlag::f_fake_history_item; const auto replyTo = 0; const auto viaBotId = 0; - const auto item = history->owner().makeMessage( - history, + const auto item = history->makeMessage( ++id, flags, clientFlags, diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index a7eefdbd3..38c5c5c06 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -740,6 +740,9 @@ void ApplyChannelUpdate( channel->session().api().applyNotifySettings( MTP_inputNotifyPeer(channel->input), update.vnotify_settings()); + + // For clearUpTill() call. + channel->owner().sendHistoryChangeNotifications(); } void ApplyMegagroupAdmins( diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 36f054075..dc19add6e 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1724,18 +1724,15 @@ auto Session::messagesListForInsert(ChannelId channelId) : &_channelMessages[channelId]; } -HistoryItem *Session::registerMessage(std::unique_ptr item) { - Expects(item != nullptr); - - const auto result = item.get(); - const auto list = messagesListForInsert(result->channelId()); - const auto i = list->find(result->id); +void Session::registerMessage(not_null item) { + const auto list = messagesListForInsert(item->channelId()); + const auto itemId = item->id; + const auto i = list->find(itemId); if (i != list->end()) { LOG(("App Error: Trying to re-registerMessage().")); i->second->destroy(); } - list->emplace(result->id, std::move(item)); - return result; + list->emplace(itemId, item); } void Session::processMessagesDeleted( @@ -1754,7 +1751,7 @@ void Session::processMessagesDeleted( const auto i = list ? list->find(messageId.v) : Messages::iterator(); if (list && i != list->end()) { const auto history = i->second->history(); - destroyMessage(i->second.get()); + i->second->destroy(); if (!history->chatListMessageKnown()) { historiesToCheck.emplace(history); } @@ -1780,32 +1777,12 @@ void Session::removeDependencyMessage(not_null item) { } } -void Session::destroyMessage(not_null item) { - Expects(item->isHistoryEntry() || !item->mainView()); - +void Session::unregisterMessage(not_null item) { const auto peerId = item->history()->peer->id; - if (item->isHistoryEntry()) { - // All this must be done for all items manually in History::clear()! - item->eraseFromUnreadMentions(); - if (IsServerMsgId(item->id)) { - if (const auto types = item->sharedMediaTypes()) { - session().storage().remove(Storage::SharedMediaRemoveOne( - peerId, - types, - item->id)); - } - } else { - session().api().cancelLocalItem(item); - } - item->history()->itemRemoved(item); - } _itemRemoved.fire_copy(item); groups().unregisterMessage(item); removeDependencyMessage(item); - session().notifications().clearFromItem(item); - - const auto list = messagesListForInsert(peerToChannel(peerId)); - list->erase(item->id); + messagesListForInsert(peerToChannel(peerId))->erase(item->id); } MsgId Session::nextLocalMessageId() { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index aa2774292..f7d7a95f7 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -371,22 +371,8 @@ public: const Dialogs::Key &key1, const Dialogs::Key &key2); - template - not_null makeMessage(Args &&...args) { - return static_cast( - registerMessage( - std::make_unique( - std::forward(args)...))); - } - - template - not_null makeServiceMessage(Args &&...args) { - return static_cast( - registerMessage( - std::make_unique( - std::forward(args)...))); - } - void destroyMessage(not_null item); + void registerMessage(not_null item); + void unregisterMessage(not_null item); // Returns true if item found and it is not detached. bool checkEntitiesAndViewsUpdate(const MTPDmessage &data); @@ -698,7 +684,7 @@ public: void clearLocalStorage(); private: - using Messages = std::unordered_map>; + using Messages = std::unordered_map>; void suggestStartExport(); @@ -719,7 +705,8 @@ private: const Messages *messagesList(ChannelId channelId) const; not_null messagesListForInsert(ChannelId channelId); - HistoryItem *registerMessage(std::unique_ptr item); + not_null registerMessage( + std::unique_ptr item); void changeMessageId(ChannelId channel, MsgId wasId, MsgId nowId); void removeDependencyMessage(not_null item); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index 41615d44a..04e029f3f 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -392,10 +392,9 @@ void GenerateItems( auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) { auto message = HistoryService::PreparedText { text }; message.links.push_back(fromLink); - addPart(history->owner().makeServiceMessage( - history, - MTPDmessage_ClientFlag::f_admin_log_entry, + addPart(history->makeServiceMessage( history->nextNonHistoryEntryId(), + MTPDmessage_ClientFlag::f_admin_log_entry, date, message, MTPDmessage::Flags(0), @@ -433,8 +432,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto newDescription = PrepareText(newValue, QString()); - auto body = history->owner().makeMessage( - history, + auto body = history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -469,8 +467,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto newLink = newValue.isEmpty() ? TextWithEntities() : PrepareText(Core::App().createInternalLinkFull(newValue), QString()); - auto body = history->owner().makeMessage( - history, + auto body = history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -609,8 +606,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vparticipant()); - addPart(history->owner().makeMessage( - history, + addPart(history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -628,8 +624,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant(), &action.vprev_participant()); - addPart(history->owner().makeMessage( - history, + addPart(history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -653,8 +648,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant(), &action.vprev_participant()); - addPart(history->owner().makeMessage( - history, + addPart(history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -687,10 +681,9 @@ void GenerateItems( auto message = HistoryService::PreparedText { text }; message.links.push_back(fromLink); message.links.push_back(setLink); - addPart(history->owner().makeServiceMessage( - history, - MTPDmessage_ClientFlag::f_admin_log_entry, + addPart(history->makeServiceMessage( history->nextNonHistoryEntryId(), + MTPDmessage_ClientFlag::f_admin_log_entry, date, message, MTPDmessage::Flags(0), @@ -712,8 +705,7 @@ void GenerateItems( auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto bodyText = GenerateDefaultBannedRightsChangeText(channel, action.vnew_banned_rights(), action.vprev_banned_rights()); - addPart(history->owner().makeMessage( - history, + addPart(history->makeMessage( history->nextNonHistoryEntryId(), bodyFlags, bodyClientFlags, @@ -763,10 +755,9 @@ void GenerateItems( auto message = HistoryService::PreparedText{ text }; message.links.push_back(fromLink); message.links.push_back(chatLink); - addPart(history->owner().makeServiceMessage( - history, - MTPDmessage_ClientFlag::f_admin_log_entry, + addPart(history->makeServiceMessage( history->nextNonHistoryEntryId(), + MTPDmessage_ClientFlag::f_admin_log_entry, date, message, MTPDmessage::Flags(0), diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 66e46c0e7..c225d8cb8 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -637,6 +637,50 @@ HistoryItem *History::addNewMessage( return addNewItem(item, unread); } +not_null History::insertItem( + std::unique_ptr item) { + Expects(item != nullptr); + + const auto [i, ok] = _messages.insert(std::move(item)); + + const auto result = i->get(); + owner().registerMessage(result); + + Ensures(ok); + return result; +} + +void History::destroyMessage(not_null item) { + Expects(item->isHistoryEntry() || !item->mainView()); + + const auto peerId = peer->id; + if (item->isHistoryEntry()) { + // All this must be done for all items manually in History::clear()! + item->eraseFromUnreadMentions(); + if (IsServerMsgId(item->id)) { + if (const auto types = item->sharedMediaTypes()) { + session().storage().remove(Storage::SharedMediaRemoveOne( + peerId, + types, + item->id)); + } + } else { + session().api().cancelLocalItem(item); + } + itemRemoved(item); + } + + owner().unregisterMessage(item); + session().notifications().clearFromItem(item); + + auto hack = std::unique_ptr(item.get()); + const auto i = _messages.find(hack); + hack.release(); + + Assert(i != end(_messages)); + _messages.erase(i); +} + not_null History::addNewItem( not_null item, bool unread) { @@ -693,8 +737,7 @@ not_null History::addNewLocalMessage( const QString &postAuthor, not_null forwardOriginal) { return addNewItem( - owner().makeMessage( - this, + makeMessage( id, flags, clientFlags, @@ -718,8 +761,7 @@ not_null History::addNewLocalMessage( const TextWithEntities &caption, const MTPReplyMarkup &markup) { return addNewItem( - owner().makeMessage( - this, + makeMessage( id, flags, clientFlags, @@ -747,8 +789,7 @@ not_null History::addNewLocalMessage( const TextWithEntities &caption, const MTPReplyMarkup &markup) { return addNewItem( - owner().makeMessage( - this, + makeMessage( id, flags, clientFlags, @@ -775,8 +816,7 @@ not_null History::addNewLocalMessage( not_null game, const MTPReplyMarkup &markup) { return addNewItem( - owner().makeMessage( - this, + makeMessage( id, flags, clientFlags, @@ -3097,10 +3137,10 @@ void History::clear(ClearType type) { removeJoinedMessage(); forgetScrollState(); + blocks.clear(); + owner().notifyHistoryUnloaded(this); + lastKeyboardInited = false; if (type == ClearType::Unload) { - blocks.clear(); - owner().notifyHistoryUnloaded(this); - lastKeyboardInited = false; _loadedAtTop = _loadedAtBottom = false; } else { // Leave the 'sending' messages in local messages. @@ -3145,7 +3185,6 @@ void History::clear(ClearType type) { //} } } - owner().notifyHistoryChangeDelayed(this); if (const auto chat = peer->asChat()) { chat->lastAuthors.clear(); @@ -3153,27 +3192,28 @@ void History::clear(ClearType type) { } else if (const auto channel = peer->asMegagroup()) { channel->mgInfo->markupSenders.clear(); } + + owner().notifyHistoryChangeDelayed(this); + owner().sendHistoryChangeNotifications(); } void History::clearUpTill(MsgId availableMinId) { - auto minId = minMsgId(); - if (!minId || minId > availableMinId) { - return; - } - do { - const auto item = blocks.front()->messages.front()->data(); + auto remove = std::vector>(); + remove.reserve(_messages.size()); + for (const auto &item : _messages) { const auto itemId = item->id; - if (IsServerMsgId(itemId) && itemId >= availableMinId) { - if (itemId == availableMinId) { - item->applyEditionToHistoryCleared(); - } - break; + if (!IsServerMsgId(itemId)) { + continue; + } else if (itemId == availableMinId) { + item->applyEditionToHistoryCleared(); + } else if (itemId < availableMinId) { + remove.push_back(item.get()); } + } + for (const auto item : remove) { item->destroy(); - } while (!isEmpty()); - + } requestChatListMessage(); - owner().sendHistoryChangeNotifications(); } void History::applyGroupAdminChanges(const base::flat_set &changes) { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index f54cfc1f8..5ea915201 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -90,6 +90,25 @@ public: void applyGroupAdminChanges(const base::flat_set &changes); + template + not_null makeMessage(Args &&...args) { + return static_cast( + insertItem( + std::make_unique( + this, + std::forward(args)...)).get()); + } + + template + not_null makeServiceMessage(Args &&...args) { + return static_cast( + insertItem( + std::make_unique( + this, + std::forward(args)...)).get()); + } + void destroyMessage(not_null item); + HistoryItem *addNewMessage( const MTPMessage &msg, MTPDmessage_ClientFlags clientFlags, @@ -405,6 +424,7 @@ private: void removeBlock(not_null block); void clearSharedMedia(); + not_null insertItem(std::unique_ptr item); not_null addNewItem( not_null item, bool unread); @@ -512,6 +532,7 @@ private: std::optional _lastMessage; std::optional _lastServerMessage; base::flat_set> _localMessages; + std::unordered_set> _messages; // This almost always is equal to _lastMessage. The only difference is // for a group that migrated to a supergroup. Then _lastMessage can diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 821e53b9c..ce7883a71 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -75,8 +75,7 @@ not_null CreateUnsupportedMessage( EntityInText(EntityType::Italic, 0, text.text.size())); flags &= ~MTPDmessage::Flag::f_post_author; flags |= MTPDmessage::Flag::f_legacy; - return history->owner().makeMessage( - history, + return history->makeMessage( msgId, flags, clientFlags, @@ -413,7 +412,7 @@ bool HistoryItem::isScheduled() const { } void HistoryItem::destroy() { - _history->owner().destroyMessage(this); + _history->destroyMessage(this); } void HistoryItem::refreshMainView() { @@ -929,37 +928,29 @@ not_null HistoryItem::Create( const auto text = HistoryService::PreparedText { tr::lng_message_empty(tr::now) }; - return history->owner().makeServiceMessage( - history, - clientFlags, + return history->makeServiceMessage( data.vid().v, + clientFlags, data.vdate().v, text, data.vflags().v, data.vfrom_id().value_or_empty()); } else if (checked == MediaCheckResult::HasTimeToLive) { - return history->owner().makeServiceMessage( - history, - data, - clientFlags); + return history->makeServiceMessage(data, clientFlags); } - return history->owner().makeMessage(history, data, clientFlags); + return history->makeMessage(data, clientFlags); }, [&](const MTPDmessageService &data) -> HistoryItem* { if (data.vaction().type() == mtpc_messageActionPhoneCall) { - return history->owner().makeMessage(history, data, clientFlags); + return history->makeMessage(data, clientFlags); } - return history->owner().makeServiceMessage( - history, - data, - clientFlags); + return history->makeServiceMessage(data, clientFlags); }, [&](const MTPDmessageEmpty &data) -> HistoryItem* { const auto text = HistoryService::PreparedText{ tr::lng_message_empty(tr::now) }; - return history->owner().makeServiceMessage( - history, - clientFlags, + return history->makeServiceMessage( data.vid().v, + clientFlags, TimeId(0), text); }); diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index 48c905d37..4856847d2 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -525,8 +525,8 @@ HistoryService::HistoryService( HistoryService::HistoryService( not_null history, - MTPDmessage_ClientFlags clientFlags, MsgId id, + MTPDmessage_ClientFlags clientFlags, TimeId date, const PreparedText &message, MTPDmessage::Flags flags, @@ -797,10 +797,9 @@ not_null GenerateJoinedMessage( TimeId inviteDate, not_null inviter, MTPDmessage::Flags flags) { - return new HistoryService( - history, - MTPDmessage_ClientFlag::f_local_history_entry, + return history->makeServiceMessage( history->owner().nextLocalMessageId(), + MTPDmessage_ClientFlag::f_local_history_entry, inviteDate, GenerateJoinedText(history, inviter), flags); diff --git a/Telegram/SourceFiles/history/history_service.h b/Telegram/SourceFiles/history/history_service.h index e1a50c71a..fe06d26ad 100644 --- a/Telegram/SourceFiles/history/history_service.h +++ b/Telegram/SourceFiles/history/history_service.h @@ -68,8 +68,8 @@ public: MTPDmessage_ClientFlags clientFlags); HistoryService( not_null history, - MTPDmessage_ClientFlags clientFlags, MsgId id, + MTPDmessage_ClientFlags clientFlags, TimeId date, const PreparedText &message, MTPDmessage::Flags flags = 0, diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp index 5368c1ece..9954ca90e 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp @@ -165,8 +165,7 @@ AdminLog::OwnedItem GenerateForwardedItem( //MTPMessageReactions(), MTPVector() ).match([&](const MTPDmessage &data) { - return history->owner().makeMessage( - history, + return history->makeMessage( data, MTPDmessage_ClientFlag::f_fake_history_item); }, [](auto &&) -> not_null { diff --git a/Telegram/SourceFiles/support/support_autocomplete.cpp b/Telegram/SourceFiles/support/support_autocomplete.cpp index ddc65146d..a8724c310 100644 --- a/Telegram/SourceFiles/support/support_autocomplete.cpp +++ b/Telegram/SourceFiles/support/support_autocomplete.cpp @@ -275,8 +275,7 @@ AdminLog::OwnedItem GenerateCommentItem( const auto clientFlags = MTPDmessage_ClientFlag::f_fake_history_item; const auto replyTo = 0; const auto viaBotId = 0; - const auto item = history->owner().makeMessage( - history, + const auto item = history->makeMessage( id, flags, clientFlags, @@ -322,8 +321,7 @@ AdminLog::OwnedItem GenerateContactItem( MTP_long(0), //MTPMessageReactions(), MTPVector()); - const auto item = history->owner().makeMessage( - history, + const auto item = history->makeMessage( message.c_message(), MTPDmessage_ClientFlag::f_fake_history_item); return AdminLog::OwnedItem(delegate, item); From 7cffb0ef9dee14acc91b316638ce38dfc6595719 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 12:51:53 +0400 Subject: [PATCH 056/140] First send delete request, then destroy locally. --- Telegram/SourceFiles/boxes/confirm_box.cpp | 23 ++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index c8b6efcd2..70cc1f954 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -785,6 +785,8 @@ void DeleteMessagesBox::deleteAndClear() { _deleteConfirmedCallback(); } + auto remove = std::vector>(); + remove.reserve(_ids.size()); base::flat_map, QVector> idsByPeer; base::flat_map, QVector> scheduledIdsByPeer; for (const auto itemId : _ids) { @@ -801,15 +803,9 @@ void DeleteMessagesBox::deleteAndClear() { } continue; } - const auto wasOnServer = IsServerMsgId(item->id); - const auto wasLast = (history->lastMessage() == item); - const auto wasInChats = (history->chatListMessage() == item); - item->destroy(); - - if (wasOnServer) { + remove.push_back(item); + if (IsServerMsgId(item->id)) { idsByPeer[history->peer].push_back(MTP_int(itemId.msg)); - } else if (wasLast || wasInChats) { - history->requestChatListMessage(); } } } @@ -826,6 +822,17 @@ void DeleteMessagesBox::deleteAndClear() { }).send(); } + for (const auto item : remove) { + const auto history = item->history(); + const auto wasLast = (history->lastMessage() == item); + const auto wasInChats = (history->chatListMessage() == item); + item->destroy(); + + if (wasLast || wasInChats) { + history->requestChatListMessage(); + } + } + const auto session = _session; Ui::hideLayer(); session->data().sendHistoryChangeNotifications(); From 388173f0ad35c2865cff416e965169382f92cfa7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 13:30:09 +0400 Subject: [PATCH 057/140] Fix delete+leave from a legacy group. We first need to leave and receive a new message update about us leaving the group and only after that remove the conversation locally from the chats list, otherwise it reappears in the list. --- Telegram/SourceFiles/apiwrap.cpp | 105 ++++++++++++++++--------------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 319399bfb..d6f49630e 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2423,9 +2423,33 @@ int ApiWrap::OnlineTillFromStatus( } void ApiWrap::clearHistory(not_null peer, bool revoke) { + deleteHistory(peer, true, revoke); +} + +void ApiWrap::deleteConversation(not_null peer, bool revoke) { + if (const auto chat = peer->asChat()) { + request(MTPmessages_DeleteChatUser( + chat->inputChat, + _session->user()->inputUser + )).done([=](const MTPUpdates &updates) { + applyUpdates(updates); + deleteHistory(peer, false, revoke); + }).fail([=](const RPCError &error) { + deleteHistory(peer, false, revoke); + }).send(); + } else { + deleteHistory(peer, false, revoke); + } +} + +void ApiWrap::deleteHistory( + not_null peer, + bool justClear, + bool revoke) { auto deleteTillId = MsgId(0); const auto history = _session->data().historyLoaded(peer); - if (history) { + if (history && justClear) { + // In case of clear history we need to know the last server message. while (history->lastMessageKnown()) { const auto last = history->lastMessage(); if (!last) { @@ -2442,67 +2466,50 @@ void ApiWrap::clearHistory(not_null peer, bool revoke) { requestDialogEntry(history, [=] { Expects(history->lastMessageKnown()); - clearHistory(peer, revoke); + deleteHistory(peer, justClear, revoke); }); return; } deleteTillId = history->lastMessage()->id; } if (const auto channel = peer->asChannel()) { - if (const auto migrated = peer->migrateFrom()) { - clearHistory(migrated, revoke); - } - if (IsServerMsgId(deleteTillId)) { - request(MTPchannels_DeleteHistory( - channel->inputChannel, - MTP_int(deleteTillId) - )).send(); + if (!justClear) { + channel->ptsWaitingForShortPoll(-1); + leaveChannel(channel); + } else { + if (const auto migrated = peer->migrateFrom()) { + clearHistory(migrated, revoke); + } + if (IsServerMsgId(deleteTillId)) { + request(MTPchannels_DeleteHistory( + channel->inputChannel, + MTP_int(deleteTillId) + )).send(); + } } } else { - deleteHistory(peer, true, revoke); + using Flag = MTPmessages_DeleteHistory::Flag; + const auto flags = Flag(0) + | (justClear ? Flag::f_just_clear : Flag(0)) + | ((peer->isUser() && revoke) ? Flag::f_revoke : Flag(0)); + request(MTPmessages_DeleteHistory( + MTP_flags(flags), + peer->input, + MTP_int(0) + )).done([=](const MTPmessages_AffectedHistory &result) { + const auto offset = applyAffectedHistory(peer, result); + if (offset > 0) { + deleteHistory(peer, justClear, revoke); + } + }).send(); } - if (history) { + if (!justClear) { + _session->data().deleteConversationLocally(peer); + } else if (history) { history->clear(History::ClearType::ClearHistory); } } -void ApiWrap::deleteConversation(not_null peer, bool revoke) { - if (const auto chat = peer->asChat()) { - request(MTPmessages_DeleteChatUser( - chat->inputChat, - _session->user()->inputUser - )).done([=](const MTPUpdates &updates) { - applyUpdates(updates); - deleteHistory(peer, false, revoke); - }).fail([=](const RPCError &error) { - deleteHistory(peer, false, revoke); - }).send(); - } else if (const auto channel = peer->asChannel()) { - channel->ptsWaitingForShortPoll(-1); - leaveChannel(channel); - } else { - deleteHistory(peer, false, revoke); - } - _session->data().deleteConversationLocally(peer); -} - -void ApiWrap::deleteHistory(not_null peer, bool justClear, bool revoke) { - using Flag = MTPmessages_DeleteHistory::Flag; - const auto flags = Flag(0) - | (justClear ? Flag::f_just_clear : Flag(0)) - | ((peer->isUser() && revoke) ? Flag::f_revoke : Flag(0)); - request(MTPmessages_DeleteHistory( - MTP_flags(flags), - peer->input, - MTP_int(0) - )).done([=](const MTPmessages_AffectedHistory &result) { - const auto offset = applyAffectedHistory(peer, result); - if (offset > 0) { - deleteHistory(peer, justClear, revoke); - } - }).send(); -} - int ApiWrap::applyAffectedHistory( not_null peer, const MTPmessages_AffectedHistory &result) { From a3f19c073bf642e9ce1449056d5dbba9767c8428 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 13:37:00 +0400 Subject: [PATCH 058/140] Fix 'reading' of an empty history. --- Telegram/SourceFiles/data/data_histories.cpp | 6 +++++- Telegram/SourceFiles/history/history.cpp | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index c3e945da5..f3516d2ca 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -131,6 +131,8 @@ void Histories::readInboxTill( not_null history, MsgId tillId, bool force) { + Expects(IsServerMsgId(tillId) || (!tillId && !force)); + if (!history->readInboxTillNeedsRequest(tillId) && !force) { return; } else if (!force) { @@ -202,7 +204,9 @@ void Histories::sendReadRequests() { const auto now = crl::now(); auto next = std::optional(); for (auto &[history, state] : _states) { - if (state.readTill && state.readWhen <= now) { + if (!state.readTill) { + continue; + } else if (state.readWhen <= now) { sendReadRequest(history, state); } else if (!next || *next > state.readWhen) { next = state.readWhen; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index c225d8cb8..d0c953fe3 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1615,13 +1615,13 @@ void History::calculateFirstUnreadMessage() { } bool History::readInboxTillNeedsRequest(MsgId tillId) { - Expects(IsServerMsgId(tillId)); + Expects(!tillId || IsServerMsgId(tillId)); readClientSideMessages(); if (unreadMark()) { session().api().changeDialogUnreadMark(this, false); } - return (_inboxReadBefore.value_or(1) <= tillId); + return IsServerMsgId(tillId) && (_inboxReadBefore.value_or(1) <= tillId); } void History::readClientSideMessages() { From 1980c1004e94589d2c79b3ad4a1fe8e4100dce54 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 16:43:51 +0400 Subject: [PATCH 059/140] Mark as read only in inited history view. --- Telegram/SourceFiles/history/history_widget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 8eeccd3ea..8f6a1c2d7 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2465,6 +2465,7 @@ bool HistoryWidget::doWeReadServerHistory() const { bool HistoryWidget::doWeReadMentions() const { return _history && _list + && _historyInited && !_firstLoadRequest && !_a_show.animating() && App::wnd()->doWeMarkAsRead(); From ee3e9af63a8ba995fe433a75557e331db8724382 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 18:16:42 +0400 Subject: [PATCH 060/140] Remove counter from unread bar. --- Telegram/Resources/langs/lang.strings | 2 +- Telegram/SourceFiles/history/history.cpp | 25 ++--------- Telegram/SourceFiles/history/history.h | 1 - .../SourceFiles/history/history_widget.cpp | 7 ++- .../history/view/history_view_element.cpp | 45 ++++++------------- .../history/view/history_view_element.h | 20 +-------- .../history/view/history_view_list_widget.cpp | 11 ++--- 7 files changed, 26 insertions(+), 85 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 5578b330e..b15250cf7 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1369,7 +1369,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_user_action_upload_file" = "{user} is sending a file"; "lng_unread_bar#one" = "{count} unread message"; "lng_unread_bar#other" = "{count} unread messages"; -//"lng_unread_bar_some" = "Unread messages"; +"lng_unread_bar_some" = "Unread messages"; "lng_maps_point" = "Location"; "lng_save_photo" = "Save image"; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index d0c953fe3..69a7d57fe 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1367,8 +1367,8 @@ HistoryBlock *History::prepareBlockForAddingItem() { } void History::viewReplaced(not_null was, Element *now) { - if (scrollTopItem == was) scrollTopItem= now; - if (_firstUnreadView == was) _firstUnreadView= now; + if (scrollTopItem == was) scrollTopItem = now; + if (_firstUnreadView == was) _firstUnreadView = now; if (_unreadBarView == was) _unreadBarView = now; } @@ -1803,14 +1803,6 @@ void History::setUnreadCount(int newUnreadCount) { calculateFirstUnreadMessage(); } } - if (_unreadBarView) { - const auto count = chatListUnreadCount(); - if (count > 0) { - _unreadBarView->setUnreadBarCount(count); - } else { - _unreadBarView->setUnreadBarFreezed(); - } - } Notify::peerUpdatedDelayed( peer, Notify::PeerUpdate::Flag::UnreadViewChanged); @@ -2064,7 +2056,7 @@ void History::addUnreadBar() { } if (const auto count = chatListUnreadCount()) { _unreadBarView = _firstUnreadView; - _unreadBarView->setUnreadBarCount(count); + _unreadBarView->createUnreadBar(); } } @@ -2074,17 +2066,6 @@ void History::destroyUnreadBar() { } } -bool History::hasNotFreezedUnreadBar() const { - if (_firstUnreadView) { - if (const auto view = _unreadBarView) { - if (const auto bar = view->Get()) { - return !bar->freezed; - } - } - } - return false; -} - void History::unsetFirstUnreadMessage() { _firstUnreadView = nullptr; } diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 5ea915201..2abe674ed 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -205,7 +205,6 @@ public: bool changeMute(bool newMute); void addUnreadBar(); void destroyUnreadBar(); - [[nodiscard]] bool hasNotFreezedUnreadBar() const; [[nodiscard]] Element *unreadBar() const; void calculateFirstUnreadMessage(); void unsetFirstUnreadMessage(); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 8f6a1c2d7..cbaae0148 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2389,7 +2389,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages _preloadDownRequest = 0; preloadHistoryIfNeeded(); if (_history->loadedAtBottom()) { - App::wnd()->checkHistoryActivation(); + checkHistoryActivation(); } } else if (_firstLoadRequest == requestId) { if (toMigrated) { @@ -3138,7 +3138,7 @@ void HistoryWidget::doneShow() { handlePendingHistoryUpdate(); } preloadHistoryIfNeeded(); - App::wnd()->checkHistoryActivation(); + checkHistoryActivation(); App::wnd()->setInnerFocus(); } @@ -4986,7 +4986,6 @@ int HistoryWidget::countAutomaticScrollTop() { if (history->unreadBar() != nullptr) { setMsgId(ShowAtUnreadMsgId); result = countInitialScrollTop(); - App::wnd()->checkHistoryActivation(); if (session().supportMode()) { history->unsetFirstUnreadMessage(); } @@ -5109,7 +5108,7 @@ void HistoryWidget::updateHistoryGeometry( _historyInited = true; _scrollToAnimation.stop(); } - auto newScrollTop = initial + const auto newScrollTop = initial ? countInitialScrollTop() : countAutomaticScrollTop(); if (_scroll->scrollTop() == newScrollTop) { diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 96a84ecaa..4a287222d 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -127,14 +127,8 @@ TextSelection ShiftItemSelection( return ShiftItemSelection(selection, byText.length()); } -void UnreadBar::init(int newCount) { - if (freezed) { - return; - } - count = newCount; - text = /*(count == kCountUnknown) // #feed - ? tr::lng_unread_bar_some(tr::now) - : */tr::lng_unread_bar(tr::now, lt_count, count); +void UnreadBar::init() { + text = tr::lng_unread_bar_some(tr::now); width = st::semiboldFont->width(text); } @@ -416,6 +410,18 @@ bool Element::computeIsAttachToPrevious(not_null previous) { return false; } +void Element::createUnreadBar() { + if (!AddComponents(UnreadBar::Bit())) { + return; + } + const auto bar = Get(); + bar->init(); + if (data()->mainView() == this) { + recountAttachToPreviousInBlocks(); + } + history()->owner().requestViewResize(this); +} + void Element::destroyUnreadBar() { if (!Has()) { return; @@ -427,29 +433,6 @@ void Element::destroyUnreadBar() { } } -void Element::setUnreadBarCount(int count) { - const auto changed = AddComponents(UnreadBar::Bit()); - const auto bar = Get(); - if (bar->freezed) { - return; - } - bar->init(count); - if (changed) { - if (data()->mainView() == this) { - recountAttachToPreviousInBlocks(); - } - history()->owner().requestViewResize(this); - } else { - history()->owner().requestViewRepaint(this); - } -} - -void Element::setUnreadBarFreezed() { - if (const auto bar = Get()) { - bar->freezed = true; - } -} - int Element::displayedDateHeight() const { if (auto date = Get()) { return date->height(); diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 41bbd4feb..734ba8a79 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -96,26 +96,15 @@ TextSelection ShiftItemSelection( // Any HistoryView::Element can have this Component for // displaying the unread messages bar above the message. struct UnreadBar : public RuntimeComponent { - void init(int newCount); + void init(); static int height(); static int marginTop(); void paint(Painter &p, int y, int w) const; - static constexpr auto kCountUnknown = std::numeric_limits::max(); - QString text; int width = 0; - int count = 0; - - // If unread bar is freezed the new messages do not - // increment the counter displayed by this bar. - // - // It happens when we've opened the conversation and - // we've seen the bar and new messages are marked as read - // as soon as they are added to the chat history. - bool freezed = false; }; @@ -192,14 +181,9 @@ public: bool computeIsAttachToPrevious(not_null previous); - void setUnreadBarCount(int count); + void createUnreadBar(); void destroyUnreadBar(); - // marks the unread bar as freezed so that unread - // messages count will not change for this bar - // when the new messages arrive in this chat history - void setUnreadBarFreezed(); - int displayedDateHeight() const; bool displayDate() const; bool isInOneDayWithPrevious() const; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index c5f449cf7..cf0bb871a 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -462,7 +462,7 @@ void ListWidget::checkUnreadBarCreation() { if (!_unreadBarElement) { if (const auto index = _delegate->listUnreadBarView(_items)) { _unreadBarElement = _items[*index].get(); - _unreadBarElement->setUnreadBarCount(UnreadBar::kCountUnknown); + _unreadBarElement->createUnreadBar(); refreshAttachmentsAtIndex(*index); } } @@ -2497,14 +2497,9 @@ void ListWidget::viewReplaced(not_null was, Element *now) { if (_overElement == was) _overElement = now; if (_unreadBarElement == was) { const auto bar = _unreadBarElement->Get(); - const auto count = bar ? bar->count : 0; - const auto freezed = bar ? bar->freezed : false; _unreadBarElement = now; - if (now && count) { - _unreadBarElement->setUnreadBarCount(count); - if (freezed) { - _unreadBarElement->setUnreadBarFreezed(); - } + if (now && bar) { + _unreadBarElement->createUnreadBar(); } } } From 49c4d35afa550498efc1d03ab262b26c1950b6e3 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 19:25:31 +0400 Subject: [PATCH 061/140] Improve working with unread bar. --- Telegram/SourceFiles/history/history.cpp | 26 ++- .../SourceFiles/history/history_widget.cpp | 175 ++++++++---------- Telegram/SourceFiles/history/history_widget.h | 4 +- 3 files changed, 89 insertions(+), 116 deletions(-) diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 69a7d57fe..c04c7bba2 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1590,22 +1590,22 @@ void History::addToSharedMedia( } void History::calculateFirstUnreadMessage() { - if (_firstUnreadView || !_inboxReadBefore) { + if (!_inboxReadBefore) { return; } - for (auto i = blocks.cend(); i != blocks.cbegin();) { - --i; - const auto &messages = (*i)->messages; - for (auto j = messages.cend(); j != messages.cbegin();) { - --j; - const auto view = j->get(); - const auto item = view->data(); + _firstUnreadView = nullptr; + if (!unreadCount()) { + return; + } + for (const auto &block : ranges::view::reverse(blocks)) { + for (const auto &message : ranges::view::reverse(block->messages)) { + const auto item = message->data(); if (!IsServerMsgId(item->id)) { continue; - } else if (!item->out() || !_firstUnreadView) { + } else if (!item->out()) { if (item->id >= *_inboxReadBefore) { - _firstUnreadView = view; + _firstUnreadView = message.get(); } else { return; } @@ -1798,10 +1798,8 @@ void History::setUnreadCount(int newUnreadCount) { if (const auto last = msgIdForRead()) { setInboxReadTill(last); } - } else { - if (!_firstUnreadView && !_unreadBarView && loadedAtBottom()) { - calculateFirstUnreadMessage(); - } + } else if (!_firstUnreadView && !_unreadBarView && loadedAtBottom()) { + calculateFirstUnreadMessage(); } Notify::peerUpdatedDelayed( peer, diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index cbaae0148..e0ce67b25 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1551,10 +1551,7 @@ void HistoryWidget::fastShowAtEnd(not_null history) { } clearAllLoadRequests(); - setMsgId(ShowAtUnreadMsgId); - _historyInited = false; - if (_history->isReadyFor(_showAtMsgId)) { historyLoaded(); } else { @@ -1637,7 +1634,7 @@ void HistoryWidget::showHistory( if (_peer->id == peerId && !reload) { updateForwarding(); - bool canShowNow = _history->isReadyFor(showAtMsgId); + const auto canShowNow = _history->isReadyFor(showAtMsgId); if (!canShowNow) { delayedShowAt(showAtMsgId); } else { @@ -1659,10 +1656,8 @@ void HistoryWidget::showHistory( setMsgId(showAtMsgId); if (_historyInited) { - countHistoryShowFrom(); - destroyUnreadBar(); - - auto item = getItemFromHistoryOrMigrated(_showAtMsgId); + const auto item = getItemFromHistoryOrMigrated( + _showAtMsgId); animatedScrollToY(countInitialScrollTop(), item); } else { historyLoaded(); @@ -1712,7 +1707,7 @@ void HistoryWidget::showHistory( _history->showAtMsgId = _showAtMsgId; - destroyUnreadBar(); + destroyUnreadBarOnClose(); destroyPinnedBar(); _membersDropdown.destroy(); _scrollToAnimation.stop(); @@ -1822,7 +1817,9 @@ void HistoryWidget::showHistory( _updateHistoryItems.stop(); pinnedMsgVisibilityUpdated(); - if (_history->scrollTopItem || (_migrated && _migrated->scrollTopItem) || _history->isReadyFor(_showAtMsgId)) { + if (_history->scrollTopItem + || (_migrated && _migrated->scrollTopItem) + || _history->isReadyFor(_showAtMsgId)) { historyLoaded(); } else { firstLoadMessages(); @@ -2236,8 +2233,22 @@ void HistoryWidget::destroyUnreadBar() { if (_migrated) _migrated->destroyUnreadBar(); } +void HistoryWidget::destroyUnreadBarOnClose() { + if (!_history || !_historyInited) { + return; + } else if (_scroll->scrollTop() == _scroll->scrollTopMax()) { + destroyUnreadBar(); + return; + } + const auto top = unreadBarTop(); + if (top && *top < _scroll->scrollTop()) { + destroyUnreadBar(); + return; + } +} + void HistoryWidget::unreadMessageAdded(not_null item) { - if (_history != item->history()) { + if (_history != item->history() || !_historyInited) { return; } @@ -2442,15 +2453,12 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages } setMsgId(_delayedShowAtMsgId); - - _historyInited = false; historyLoaded(); } } void HistoryWidget::historyLoaded() { - countHistoryShowFrom(); - destroyUnreadBar(); + _historyInited = false; doneShow(); } @@ -2478,7 +2486,9 @@ void HistoryWidget::checkHistoryActivation() { } void HistoryWidget::firstLoadMessages() { - if (!_history || _firstLoadRequest) return; + if (!_history || _firstLoadRequest) { + return; + } auto from = _peer; auto offsetId = 0; @@ -2535,13 +2545,18 @@ void HistoryWidget::firstLoadMessages() { } void HistoryWidget::loadMessages() { - if (!_history || _preloadRequest) return; + if (!_history || _preloadRequest) { + return; + } if (_history->isEmpty() && _migrated && _migrated->isEmpty()) { return firstLoadMessages(); } - auto loadMigrated = _migrated && (_history->isEmpty() || _history->loadedAtTop() || (!_migrated->isEmpty() && !_migrated->loadedAtBottom())); + auto loadMigrated = _migrated + && (_history->isEmpty() + || _history->loadedAtTop() + || (!_migrated->isEmpty() && !_migrated->loadedAtBottom())); auto from = loadMigrated ? _migrated : _history; if (from->loadedAtTop()) { return; @@ -2572,7 +2587,9 @@ void HistoryWidget::loadMessages() { } void HistoryWidget::loadMessagesDown() { - if (!_history || _preloadDownRequest) return; + if (!_history || _preloadDownRequest) { + return; + } if (_history->isEmpty() && _migrated && _migrated->isEmpty()) { return firstLoadMessages(); @@ -4949,9 +4966,11 @@ int HistoryWidget::countInitialScrollTop() { auto result = ScrollMax; if (_history->scrollTopItem || (_migrated && _migrated->scrollTopItem)) { result = _list->historyScrollTop(); - } else if (_showAtMsgId && (_showAtMsgId > 0 || -_showAtMsgId < ServerMaxMsgId)) { - auto item = getItemFromHistoryOrMigrated(_showAtMsgId); - auto itemTop = _list->itemTop(item); + } else if (_showAtMsgId + && (IsServerMsgId(_showAtMsgId) + || IsServerMsgId(-_showAtMsgId))) { + const auto item = getItemFromHistoryOrMigrated(_showAtMsgId); + const auto itemTop = _list->itemTop(item); if (itemTop < 0) { setMsgId(0); return countInitialScrollTop(); @@ -4971,8 +4990,14 @@ int HistoryWidget::countInitialScrollTop() { } int HistoryWidget::countAutomaticScrollTop() { + Expects(_history != nullptr); + Expects(_list != nullptr); + auto result = ScrollMax; - if (const auto unread = firstUnreadMessage()) { + if (!_historyInited) { + _history->calculateFirstUnreadMessage(); + } + if (const auto unread = _history->firstUnreadMessage()) { result = _list->itemTop(unread); const auto possibleUnreadBarTop = _scroll->scrollTopMax() + HistoryView::UnreadBar::height() @@ -5037,10 +5062,10 @@ void HistoryWidget::updateHistoryGeometry( if (newScrollHeight <= 0) { return; } - auto wasScrollTop = _scroll->scrollTop(); - auto wasScrollTopMax = _scroll->scrollTopMax(); - auto wasAtBottom = wasScrollTop + 1 > wasScrollTopMax; - auto needResize = (_scroll->width() != width()) || (_scroll->height() != newScrollHeight); + const auto wasScrollTop = _scroll->scrollTop(); + const auto wasAtBottom = (wasScrollTop == _scroll->scrollTopMax()); + const auto needResize = (_scroll->width() != width()) + || (_scroll->height() != newScrollHeight); if (needResize) { _scroll->resize(width(), newScrollHeight); // on initial updateListSize we didn't put the _scroll->scrollTop correctly yet @@ -5069,52 +5094,30 @@ void HistoryWidget::updateHistoryGeometry( updateListSize(); _updateHistoryGeometryRequired = false; - if ((!initial && !wasAtBottom) - || (loadedDown - && (!_history->firstUnreadMessage() - || _history->unreadBar() - || _history->loadedAtBottom()) - && (!_migrated - || !_migrated->firstUnreadMessage() - || _migrated->unreadBar() - || _history->loadedAtBottom()))) { - const auto historyScrollTop = _list->historyScrollTop(); - if (!wasAtBottom && historyScrollTop == ScrollMax) { - // History scroll top was not inited yet. - // If we're showing locally unread messages, we get here - // from destroyUnreadBar() before we have time to scroll - // to good initial position, like top of an unread bar. - return; - } - auto toY = qMin(_list->historyScrollTop(), _scroll->scrollTopMax()); - if (change.type == ScrollChangeAdd) { - toY += change.value; - } else if (change.type == ScrollChangeNoJumpToBottom) { - toY = wasScrollTop; - } else if (_addToScroll) { - toY += _addToScroll; - _addToScroll = 0; - } - toY = snap(toY, 0, _scroll->scrollTopMax()); - if (_scroll->scrollTop() == toY) { - visibleAreaUpdated(); - } else { - synteticScrollToY(toY); - } - return; - } - + auto newScrollTop = 0; if (initial) { + newScrollTop = countInitialScrollTop(); _historyInited = true; _scrollToAnimation.stop(); + } else if (wasAtBottom && !loadedDown) { + newScrollTop = countAutomaticScrollTop(); + } else { + newScrollTop = std::min( + _list->historyScrollTop(), + _scroll->scrollTopMax()); + if (change.type == ScrollChangeAdd) { + newScrollTop += change.value; + } else if (change.type == ScrollChangeNoJumpToBottom) { + newScrollTop = wasScrollTop; + } else if (const auto add = base::take(_addToScroll)) { + newScrollTop += add; + } } - const auto newScrollTop = initial - ? countInitialScrollTop() - : countAutomaticScrollTop(); - if (_scroll->scrollTop() == newScrollTop) { + const auto toY = std::clamp(newScrollTop, 0, _scroll->scrollTopMax()); + if (_scroll->scrollTop() == toY) { visibleAreaUpdated(); } else { - synteticScrollToY(newScrollTop); + synteticScrollToY(toY); } } @@ -5137,15 +5140,13 @@ bool HistoryWidget::hasPendingResizedItems() const { } std::optional HistoryWidget::unreadBarTop() const { - auto getUnreadBar = [this]() -> HistoryView::Element* { + const auto bar = [&]() -> HistoryView::Element* { if (const auto bar = _migrated ? _migrated->unreadBar() : nullptr) { return bar; - } else if (const auto bar = _history->unreadBar()) { - return bar; } - return nullptr; - }; - if (const auto bar = getUnreadBar()) { + return _history->unreadBar(); + }(); + if (bar) { const auto result = _list->itemTop(bar) + HistoryView::UnreadBar::marginTop(); if (bar->Has()) { @@ -5156,15 +5157,6 @@ std::optional HistoryWidget::unreadBarTop() const { return std::nullopt; } -HistoryView::Element *HistoryWidget::firstUnreadMessage() const { - if (_migrated) { - if (const auto result = _migrated->firstUnreadMessage()) { - return result; - } - } - return _history ? _history->firstUnreadMessage() : nullptr; -} - void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector &messages) { _list->messagesReceived(peer, messages); if (!_firstLoadRequest) { @@ -5180,21 +5172,6 @@ void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector } } -void HistoryWidget::countHistoryShowFrom() { - if (_migrated - && _showAtMsgId == ShowAtUnreadMsgId - && _migrated->unreadCount()) { - _migrated->calculateFirstUnreadMessage(); - } - if ((_migrated && _migrated->firstUnreadMessage()) - || (_showAtMsgId != ShowAtUnreadMsgId) - || !_history->unreadCount()) { - _history->unsetFirstUnreadMessage(); - } else { - _history->calculateFirstUnreadMessage(); - } -} - void HistoryWidget::updateBotKeyboard(History *h, bool force) { if (h && h != _history && h != _migrated) { return; @@ -5311,7 +5288,7 @@ void HistoryWidget::updateHistoryDownPosition() { void HistoryWidget::updateHistoryDownVisibility() { if (_a_show.animating()) return; - auto haveUnreadBelowBottom = [&](History *history) { + const auto haveUnreadBelowBottom = [&](History *history) { if (!_list || !history || history->unreadCount() <= 0) { return false; } @@ -5322,7 +5299,7 @@ void HistoryWidget::updateHistoryDownVisibility() { const auto top = _list->itemTop(unread); return (top >= _scroll->scrollTop() + _scroll->height()); }; - auto historyDownIsVisible = [&] { + const auto historyDownIsVisible = [&] { if (!_list || _firstLoadRequest) { return false; } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 79070c736..432991e88 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -557,6 +557,7 @@ private: // destroys _history and _migrated unread bars void destroyUnreadBar(); + void destroyUnreadBarOnClose(); void saveEditMsg(); void saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req); @@ -583,15 +584,12 @@ private: std::optional unreadBarTop() const; int itemTopForHighlight(not_null view) const; void scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId); - HistoryView::Element *firstUnreadMessage() const; // Scroll to current y without updating the _lastUserScrolled time. // Used to distinguish between user scrolls and syntetic scrolls. // This one is syntetic. void synteticScrollToY(int y); - void countHistoryShowFrom(); - void writeDrafts(Data::Draft **localDraft, Data::Draft **editDraft); void writeDrafts(History *history); void setFieldText( From f72cb979c0638683bf98e541a95feb28b22a02af Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 20:22:30 +0400 Subject: [PATCH 062/140] Create unread bar when jumping to a message. --- .../SourceFiles/history/history_widget.cpp | 69 ++++++++++++++----- Telegram/SourceFiles/history/history_widget.h | 1 + 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index e0ce67b25..4316bf882 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1634,6 +1634,9 @@ void HistoryWidget::showHistory( if (_peer->id == peerId && !reload) { updateForwarding(); + if (showAtMsgId == ShowAtUnreadMsgId) { + showAtMsgId = ShowAtTheEndMsgId; + } const auto canShowNow = _history->isReadyFor(showAtMsgId); if (!canShowNow) { delayedShowAt(showAtMsgId); @@ -1658,7 +1661,12 @@ void HistoryWidget::showHistory( if (_historyInited) { const auto item = getItemFromHistoryOrMigrated( _showAtMsgId); - animatedScrollToY(countInitialScrollTop(), item); + animatedScrollToY( + std::clamp( + countInitialScrollTop(), + 0, + _scroll->scrollTopMax()), + item); } else { historyLoaded(); } @@ -4963,9 +4971,8 @@ MsgId HistoryWidget::replyToId() const { } int HistoryWidget::countInitialScrollTop() { - auto result = ScrollMax; if (_history->scrollTopItem || (_migrated && _migrated->scrollTopItem)) { - result = _list->historyScrollTop(); + return _list->historyScrollTop(); } else if (_showAtMsgId && (IsServerMsgId(_showAtMsgId) || IsServerMsgId(-_showAtMsgId))) { @@ -4978,31 +4985,44 @@ int HistoryWidget::countInitialScrollTop() { const auto view = item->mainView(); Assert(view != nullptr); - result = itemTopForHighlight(view); enqueueMessageHighlight(view); + const auto result = itemTopForHighlight(view); + createUnreadBarIfBelowVisibleArea(result); + return result; } } else if (const auto top = unreadBarTop()) { - result = *top; + return *top; } else { + _history->calculateFirstUnreadMessage(); return countAutomaticScrollTop(); } - return qMin(result, _scroll->scrollTopMax()); +} + +void HistoryWidget::createUnreadBarIfBelowVisibleArea(int withScrollTop) { + if (_history->unreadBar()) { + return; + } + _history->calculateFirstUnreadMessage(); + if (const auto unread = _history->firstUnreadMessage()) { + if (_list->itemTop(unread) > withScrollTop) { + _history->addUnreadBar(); + if (hasPendingResizedItems()) { + updateListSize(); + } + } + } } int HistoryWidget::countAutomaticScrollTop() { Expects(_history != nullptr); Expects(_list != nullptr); - auto result = ScrollMax; - if (!_historyInited) { - _history->calculateFirstUnreadMessage(); - } if (const auto unread = _history->firstUnreadMessage()) { - result = _list->itemTop(unread); + const auto firstUnreadTop = _list->itemTop(unread); const auto possibleUnreadBarTop = _scroll->scrollTopMax() + HistoryView::UnreadBar::height() - HistoryView::UnreadBar::marginTop(); - if (result < possibleUnreadBarTop) { + if (firstUnreadTop < possibleUnreadBarTop) { const auto history = unread->data()->history(); history->addUnreadBar(); if (hasPendingResizedItems()) { @@ -5010,15 +5030,11 @@ int HistoryWidget::countAutomaticScrollTop() { } if (history->unreadBar() != nullptr) { setMsgId(ShowAtUnreadMsgId); - result = countInitialScrollTop(); - if (session().supportMode()) { - history->unsetFirstUnreadMessage(); - } - return result; + return countInitialScrollTop(); } } } - return qMin(result, _scroll->scrollTopMax()); + return ScrollMax; } void HistoryWidget::updateHistoryGeometry( @@ -5165,8 +5181,23 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector } } -void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector &messages) { +void HistoryWidget::addMessagesToBack( + PeerData *peer, + const QVector &messages) { + const auto checkForUnreadStart = [&] { + if (_history->unreadBar() || !_history->inChatList()) { + return false; + } + _history->calculateFirstUnreadMessage(); + return !_history->firstUnreadMessage(); + }(); _list->messagesReceivedDown(peer, messages); + if (checkForUnreadStart) { + _history->calculateFirstUnreadMessage(); + if (const auto unread = _history->firstUnreadMessage()) { + _history->addUnreadBar(); + } + } if (!_firstLoadRequest) { updateHistoryGeometry(false, true, { ScrollChangeNoJumpToBottom, 0 }); } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 432991e88..41cb14761 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -558,6 +558,7 @@ private: // destroys _history and _migrated unread bars void destroyUnreadBar(); void destroyUnreadBarOnClose(); + void createUnreadBarIfBelowVisibleArea(int withScrollTop); void saveEditMsg(); void saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req); From ee8028cd5381fb6a58098ab247d22b3e7f270ef8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2020 20:46:56 +0400 Subject: [PATCH 063/140] From above the unread jump to unread by down button. --- .../SourceFiles/history/history_widget.cpp | 25 ++++++++++++++++--- Telegram/SourceFiles/history/history_widget.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 4316bf882..2d666936a 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1617,6 +1617,18 @@ void HistoryWidget::applyCloudDraft(History *history) { } } +bool HistoryWidget::insideJumpToEndInsteadOfToUnread() const { + if (session().supportMode()) { + return true; + } else if (!_historyInited) { + return false; + } + _history->calculateFirstUnreadMessage(); + const auto unread = _history->firstUnreadMessage(); + const auto visibleBottom = _scroll->scrollTop() + _scroll->height(); + return unread && _list->itemTop(unread) <= visibleBottom; +} + void HistoryWidget::showHistory( const PeerId &peerId, MsgId showAtMsgId, @@ -1634,9 +1646,15 @@ void HistoryWidget::showHistory( if (_peer->id == peerId && !reload) { updateForwarding(); - if (showAtMsgId == ShowAtUnreadMsgId) { + if (showAtMsgId == ShowAtUnreadMsgId + && insideJumpToEndInsteadOfToUnread()) { showAtMsgId = ShowAtTheEndMsgId; } + if (!IsServerMsgId(showAtMsgId) + && !IsServerMsgId(-showAtMsgId)) { + // To end or to unread. + destroyUnreadBar(); + } const auto canShowNow = _history->isReadyFor(showAtMsgId); if (!canShowNow) { delayedShowAt(showAtMsgId); @@ -2806,8 +2824,7 @@ void HistoryWidget::historyDownClicked() { } else if (_replyReturn && _replyReturn->history() == _migrated) { showHistory(_peer->id, -_replyReturn->id); } else if (_peer) { - showHistory(_peer->id, ShowAtTheEndMsgId); // #TODO reading - // session().supportMode() ? ShowAtTheEndMsgId : ShowAtUnreadMsgId); + showHistory(_peer->id, ShowAtUnreadMsgId); } } @@ -4990,6 +5007,8 @@ int HistoryWidget::countInitialScrollTop() { createUnreadBarIfBelowVisibleArea(result); return result; } + } else if (_showAtMsgId == ShowAtTheEndMsgId) { + return ScrollMax; } else if (const auto top = unreadBarTop()) { return *top; } else { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 41cb14761..da9a8fb1c 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -559,6 +559,7 @@ private: void destroyUnreadBar(); void destroyUnreadBarOnClose(); void createUnreadBarIfBelowVisibleArea(int withScrollTop); + [[nodiscard]] bool insideJumpToEndInsteadOfToUnread() const; void saveEditMsg(); void saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req); From f133210db39d19b4634126d34617c8651d901f5a Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 10:37:57 +0400 Subject: [PATCH 064/140] Fix scroll first to unread then to end. --- .../SourceFiles/history/history_widget.cpp | 42 +++++++++++-------- Telegram/SourceFiles/history/history_widget.h | 1 + 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 2d666936a..b8fbae6b5 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -796,6 +796,7 @@ void HistoryWidget::scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId void HistoryWidget::animatedScrollToItem(MsgId msgId) { Expects(_history != nullptr); + if (hasPendingResizedItems()) { updateListSize(); } @@ -814,6 +815,7 @@ void HistoryWidget::animatedScrollToItem(MsgId msgId) { void HistoryWidget::animatedScrollToY(int scrollTo, HistoryItem *attachTo) { Expects(_history != nullptr); + if (hasPendingResizedItems()) { updateListSize(); } @@ -1677,13 +1679,11 @@ void HistoryWidget::showHistory( setMsgId(showAtMsgId); if (_historyInited) { + const auto to = countInitialScrollTop(); const auto item = getItemFromHistoryOrMigrated( _showAtMsgId); animatedScrollToY( - std::clamp( - countInitialScrollTop(), - 0, - _scroll->scrollTopMax()), + std::clamp(to, 0, _scroll->scrollTopMax()), item); } else { historyLoaded(); @@ -2655,7 +2655,10 @@ void HistoryWidget::loadMessagesDown() { } void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { - if (!_history || (_delayedShowAtRequest && _delayedShowAtMsgId == showAtMsgId)) return; + if (!_history + || (_delayedShowAtRequest && _delayedShowAtMsgId == showAtMsgId)) { + return; + } clearDelayedShowAt(); _delayedShowAtMsgId = showAtMsgId; @@ -5024,14 +5027,23 @@ void HistoryWidget::createUnreadBarIfBelowVisibleArea(int withScrollTop) { _history->calculateFirstUnreadMessage(); if (const auto unread = _history->firstUnreadMessage()) { if (_list->itemTop(unread) > withScrollTop) { - _history->addUnreadBar(); - if (hasPendingResizedItems()) { - updateListSize(); - } + createUnreadBarAndResize(); } } } +void HistoryWidget::createUnreadBarAndResize() { + if (!_history->firstUnreadMessage()) { + return; + } + const auto was = base::take(_historyInited); + _history->addUnreadBar(); + if (hasPendingResizedItems()) { + updateListSize(); + } + _historyInited = was; +} + int HistoryWidget::countAutomaticScrollTop() { Expects(_history != nullptr); Expects(_list != nullptr); @@ -5042,12 +5054,8 @@ int HistoryWidget::countAutomaticScrollTop() { + HistoryView::UnreadBar::height() - HistoryView::UnreadBar::marginTop(); if (firstUnreadTop < possibleUnreadBarTop) { - const auto history = unread->data()->history(); - history->addUnreadBar(); - if (hasPendingResizedItems()) { - updateListSize(); - } - if (history->unreadBar() != nullptr) { + createUnreadBarAndResize(); + if (_history->unreadBar() != nullptr) { setMsgId(ShowAtUnreadMsgId); return countInitialScrollTop(); } @@ -5213,9 +5221,7 @@ void HistoryWidget::addMessagesToBack( _list->messagesReceivedDown(peer, messages); if (checkForUnreadStart) { _history->calculateFirstUnreadMessage(); - if (const auto unread = _history->firstUnreadMessage()) { - _history->addUnreadBar(); - } + createUnreadBarAndResize(); } if (!_firstLoadRequest) { updateHistoryGeometry(false, true, { ScrollChangeNoJumpToBottom, 0 }); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index da9a8fb1c..f8b720792 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -560,6 +560,7 @@ private: void destroyUnreadBarOnClose(); void createUnreadBarIfBelowVisibleArea(int withScrollTop); [[nodiscard]] bool insideJumpToEndInsteadOfToUnread() const; + void createUnreadBarAndResize(); void saveEditMsg(); void saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req); From a954b459b49bc84508399763dda1553a703c3ee0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 11:11:27 +0400 Subject: [PATCH 065/140] Fix crash on reading in support mode. --- Telegram/SourceFiles/data/data_histories.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index f3516d2ca..d78822965 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -190,7 +190,9 @@ void Histories::readClientSideMessage(not_null item) { void Histories::sendPendingReadInbox(not_null history) { if (const auto state = lookup(history)) { - if (state->readTill && state->readWhen) { + if (state->readTill + && state->readWhen + && state->readWhen != kReadRequestSent) { state->readWhen = 0; sendReadRequests(); } From 9bdcd0823353cc08ccadf3a9b09617a755345ce2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 11:34:24 +0400 Subject: [PATCH 066/140] Don't read history for guest channels. --- Telegram/SourceFiles/data/data_histories.cpp | 2 ++ Telegram/SourceFiles/history/history.cpp | 9 ++++++++- Telegram/SourceFiles/history/history.h | 1 + Telegram/SourceFiles/history/history_widget.cpp | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index d78822965..efe4c3200 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -135,6 +135,8 @@ void Histories::readInboxTill( if (!history->readInboxTillNeedsRequest(tillId) && !force) { return; + } else if (!history->trackUnreadMessages()) { + return; } else if (!force) { const auto maybeState = lookup(history); if (maybeState && maybeState->readTill >= tillId) { diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index c04c7bba2..78fe529a4 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1595,7 +1595,7 @@ void History::calculateFirstUnreadMessage() { } _firstUnreadView = nullptr; - if (!unreadCount()) { + if (!unreadCount() || !trackUnreadMessages()) { return; } for (const auto &block : ranges::view::reverse(blocks)) { @@ -2575,6 +2575,13 @@ int History::fixedOnTopIndex() const { return useProxyPromotion() ? kProxyPromotionFixOnTopIndex : 0; } +bool History::trackUnreadMessages() const { + if (const auto channel = peer->asChannel()) { + return channel->amIn(); + } + return true; +} + bool History::shouldBeInChatList() const { if (peer->migrateTo() || !folderKnown()) { return false; diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 2abe674ed..8ef86d070 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -191,6 +191,7 @@ public: not_null item) const; [[nodiscard]] MsgId loadAroundId() const; + [[nodiscard]] bool trackUnreadMessages() const; [[nodiscard]] int unreadCount() const; [[nodiscard]] bool unreadCountKnown() const; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b8fbae6b5..f70e5fa8d 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -5212,7 +5212,7 @@ void HistoryWidget::addMessagesToBack( PeerData *peer, const QVector &messages) { const auto checkForUnreadStart = [&] { - if (_history->unreadBar() || !_history->inChatList()) { + if (_history->unreadBar() || !_history->trackUnreadMessages()) { return false; } _history->calculateFirstUnreadMessage(); From db322cc19a478b71298e401dae79463580626be2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 11:58:50 +0400 Subject: [PATCH 067/140] Move requestDialogEntry to Histories. --- Telegram/SourceFiles/api/api_sending.cpp | 2 +- Telegram/SourceFiles/apiwrap.cpp | 134 +---------------- Telegram/SourceFiles/apiwrap.h | 17 --- .../SourceFiles/boxes/mute_settings_box.cpp | 2 +- Telegram/SourceFiles/data/data_channel.cpp | 8 +- Telegram/SourceFiles/data/data_document.cpp | 2 +- Telegram/SourceFiles/data/data_folder.cpp | 5 +- Telegram/SourceFiles/data/data_histories.cpp | 138 +++++++++++++++++- Telegram/SourceFiles/data/data_histories.h | 20 +++ Telegram/SourceFiles/data/data_peer.cpp | 3 +- Telegram/SourceFiles/data/data_session.cpp | 4 +- .../dialogs/dialogs_inner_widget.cpp | 3 +- Telegram/SourceFiles/history/history.cpp | 22 +-- .../SourceFiles/history/history_widget.cpp | 8 +- Telegram/SourceFiles/mainwidget.cpp | 9 +- .../SourceFiles/window/window_peer_menu.cpp | 4 +- 16 files changed, 198 insertions(+), 183 deletions(-) diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index 45476bfd5..bc6788818 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -169,7 +169,7 @@ void SendExistingDocument( if (document->sticker()) { if (const auto main = App::main()) { main->incrementSticker(document); - document->session().data().notifyRecentStickersUpdated(); + document->owner().notifyRecentStickersUpdated(); } } } diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index d6f49630e..ff5c309a3 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -344,7 +344,7 @@ void ApiWrap::proxyPromotionDone(const MTPhelp_ProxyData &proxy) { const auto peer = _session->data().peer(peerId); _session->data().setProxyPromoted(peer); if (const auto history = _session->data().historyLoaded(peer)) { - requestDialogEntry(history); + history->owner().histories().requestDialogEntry(history); } }); } @@ -1012,134 +1012,6 @@ rpl::producer ApiWrap::dialogsLoadBlockedByDate() const { return _dialogsLoadBlockedByDate.value(); } -void ApiWrap::requestDialogEntry(not_null folder) { - if (_dialogFolderRequests.contains(folder)) { - return; - } - _dialogFolderRequests.emplace(folder); - - auto peers = QVector( - 1, - MTP_inputDialogPeerFolder(MTP_int(folder->id()))); - request(MTPmessages_GetPeerDialogs( - MTP_vector(std::move(peers)) - )).done([=](const MTPmessages_PeerDialogs &result) { - applyPeerDialogs(result); - _dialogFolderRequests.remove(folder); - }).fail([=](const RPCError &error) { - _dialogFolderRequests.remove(folder); - }).send(); -} - -void ApiWrap::requestDialogEntry( - not_null history, - Fn callback) { - const auto i = _dialogRequests.find(history); - if (i != end(_dialogRequests)) { - if (callback) { - i->second.push_back(std::move(callback)); - } - return; - } - - const auto [j, ok] = _dialogRequestsPending.try_emplace(history); - if (callback) { - j->second.push_back(std::move(callback)); - } - if (!ok) { - return; - } - if (_dialogRequestsPending.size() > 1) { - return; - } - Core::App().postponeCall(crl::guard(_session, [=] { - sendDialogRequests(); - })); -} - -void ApiWrap::sendDialogRequests() { - if (_dialogRequestsPending.empty()) { - return; - } - auto histories = std::vector>(); - ranges::transform( - _dialogRequestsPending, - ranges::back_inserter(histories), - [](const auto &pair) { return pair.first; }); - auto peers = QVector(); - const auto dialogPeer = [](not_null history) { - return MTP_inputDialogPeer(history->peer->input); - }; - ranges::transform( - histories, - ranges::back_inserter(peers), - dialogPeer); - for (auto &[history, callbacks] : base::take(_dialogRequestsPending)) { - _dialogRequests.emplace(history, std::move(callbacks)); - } - - const auto finalize = [=] { - for (const auto history : histories) { - dialogEntryApplied(history); - history->updateChatListExistence(); - } - }; - request(MTPmessages_GetPeerDialogs( - MTP_vector(std::move(peers)) - )).done([=](const MTPmessages_PeerDialogs &result) { - applyPeerDialogs(result); - finalize(); - }).fail([=](const RPCError &error) { - finalize(); - }).send(); -} - -void ApiWrap::dialogEntryApplied(not_null history) { - history->dialogEntryApplied(); - if (const auto callbacks = _dialogRequestsPending.take(history)) { - for (const auto &callback : *callbacks) { - callback(); - } - } - if (const auto callbacks = _dialogRequests.take(history)) { - for (const auto &callback : *callbacks) { - callback(); - } - } -} - -void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) { - Expects(dialogs.type() == mtpc_messages_peerDialogs); - - const auto &data = dialogs.c_messages_peerDialogs(); - _session->data().processUsers(data.vusers()); - _session->data().processChats(data.vchats()); - _session->data().processMessages(data.vmessages(), NewMessageType::Last); - for (const auto &dialog : data.vdialogs().v) { - dialog.match([&](const MTPDdialog &data) { - if (const auto peerId = peerFromMTP(data.vpeer())) { - _session->data().history(peerId)->applyDialog(nullptr, data); - } - }, [&](const MTPDdialogFolder &data) { - const auto folder = _session->data().processFolder(data.vfolder()); - folder->applyDialog(data); - }); - } - _session->data().sendHistoryChangeNotifications(); -} - -void ApiWrap::changeDialogUnreadMark( - not_null history, - bool unread) { - history->setUnreadMark(unread); - - using Flag = MTPmessages_MarkDialogUnread::Flag; - request(MTPmessages_MarkDialogUnread( - MTP_flags(unread ? Flag::f_unread : Flag(0)), - MTP_inputDialogPeer(history->peer->input) - )).send(); -} - void ApiWrap::requestFakeChatListMessage( not_null history) { if (_fakeChatListRequests.contains(history)) { @@ -1787,7 +1659,7 @@ void ApiWrap::requestSelfParticipant(not_null channel) { history->checkLocalMessages(); history->owner().sendHistoryChangeNotifications(); } else { - requestDialogEntry(history); + history->owner().histories().requestDialogEntry(history); } } }; @@ -2463,7 +2335,7 @@ void ApiWrap::deleteHistory( } } if (!history->lastMessageKnown()) { - requestDialogEntry(history, [=] { + history->owner().histories().requestDialogEntry(history, [=] { Expects(history->lastMessageKnown()); deleteHistory(peer, justClear, revoke); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index f7bddf0af..a3691df2b 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -170,17 +170,10 @@ public: rpl::producer dialogsLoadMayBlockByDate() const; rpl::producer dialogsLoadBlockedByDate() const; - void requestDialogEntry(not_null folder); - void requestDialogEntry( - not_null history, - Fn callback = nullptr); - void dialogEntryApplied(not_null history); //void applyFeedSources(const MTPDchannels_feedSources &data); // #feed //void setFeedChannels( // not_null feed, // const std::vector> &channels); - void changeDialogUnreadMark(not_null history, bool unread); - //void changeDialogUnreadMark(not_null feed, bool unread); // #feed void requestFakeChatListMessage(not_null history); void requestWallPaper( @@ -532,7 +525,6 @@ private: QVector collectMessageIds(const MessageDataRequests &requests); MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false); - void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs); void gotChatFull( not_null peer, @@ -682,8 +674,6 @@ private: not_null channel); void migrateFail(not_null peer, const RPCError &error); - void sendDialogRequests(); - not_null _session; base::flat_map _modifyRequests; @@ -753,13 +743,6 @@ private: mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0; - base::flat_set> _dialogFolderRequests; - base::flat_map< - not_null, - std::vector>> _dialogRequests; - base::flat_map< - not_null, - std::vector>> _dialogRequestsPending; base::flat_set> _fakeChatListRequests; base::flat_map, mtpRequestId> _unreadMentionsRequests; diff --git a/Telegram/SourceFiles/boxes/mute_settings_box.cpp b/Telegram/SourceFiles/boxes/mute_settings_box.cpp index fb8b67b09..7fd659c9b 100644 --- a/Telegram/SourceFiles/boxes/mute_settings_box.cpp +++ b/Telegram/SourceFiles/boxes/mute_settings_box.cpp @@ -76,7 +76,7 @@ void MuteSettingsBox::prepare() { _save = [=] { const auto muteForSeconds = group->value() * 3600; - _peer->session().data().updateNotifySettings( + _peer->owner().updateNotifySettings( _peer, muteForSeconds); closeBox(); diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 38c5c5c06..f81a767cc 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_folder.h" #include "data/data_location.h" +#include "data/data_histories.h" #include "base/unixtime.h" #include "history/history.h" #include "observer_peer.h" @@ -688,13 +689,14 @@ void ApplyChannelUpdate( const auto folder = folderId ? channel->owner().folderLoaded(folderId) : nullptr; + auto &histories = channel->owner().histories(); if (folder && history->folder() != folder) { // If history folder is unknown or not synced, request both. - channel->session().api().requestDialogEntry(history); - channel->session().api().requestDialogEntry(folder); + histories.requestDialogEntry(history); + histories.requestDialogEntry(folder); } else if (!history->folderKnown() || channel->pts() != update.vpts().v) { - channel->session().api().requestDialogEntry(history); + histories.requestDialogEntry(history); } else { history->applyDialogFields( history->folder(), diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 7aeb0d124..56b6d5ff6 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -569,7 +569,7 @@ void DocumentData::validateLottieSticker() { void DocumentData::setDataAndCache(const QByteArray &data) { setData(data); if (saveToCache() && data.size() <= Storage::kMaxFileInMemory) { - session().data().cache().put( + owner().cache().put( cacheKey(), Storage::Cache::Database::TaggedValue( base::duplicate(data), diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp index b42ac116c..5229de94b 100644 --- a/Telegram/SourceFiles/data/data_folder.cpp +++ b/Telegram/SourceFiles/data/data_folder.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_channel.h" +#include "data/data_histories.h" #include "dialogs/dialogs_key.h" #include "history/history.h" #include "history/history_item.h" @@ -108,7 +109,7 @@ void Folder::registerOne(not_null history) { if (_chatsList.indexed()->size() == 1) { updateChatListSortPosition(); if (!_cloudUnread.known) { - session().api().requestDialogEntry(this); + owner().histories().requestDialogEntry(this); } } else { updateChatListEntry(); @@ -323,7 +324,7 @@ uint32 Folder::chatListViewVersion() const { void Folder::requestChatListMessage() { if (!chatListMessageKnown()) { - session().api().requestDialogEntry(this); + owner().histories().requestDialogEntry(this); } } diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index efe4c3200..283dc97d8 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -9,10 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_channel.h" +#include "data/data_folder.h" #include "main/main_session.h" #include "history/history.h" #include "history/history_item.h" #include "history/view/history_view_element.h" +#include "core/application.h" #include "apiwrap.h" namespace Data { @@ -77,7 +79,7 @@ void Histories::readInbox(not_null history) { return; } } - session().api().requestDialogEntry(history, [=] { + requestDialogEntry(history, [=] { Expects(history->lastServerMessageKnown()); const auto last = history->lastServerMessage(); @@ -190,6 +192,134 @@ void Histories::readClientSideMessage(not_null item) { } } +void Histories::requestDialogEntry(not_null folder) { + if (_dialogFolderRequests.contains(folder)) { + return; + } + _dialogFolderRequests.emplace(folder); + + auto peers = QVector( + 1, + MTP_inputDialogPeerFolder(MTP_int(folder->id()))); + session().api().request(MTPmessages_GetPeerDialogs( + MTP_vector(std::move(peers)) + )).done([=](const MTPmessages_PeerDialogs &result) { + applyPeerDialogs(result); + _dialogFolderRequests.remove(folder); + }).fail([=](const RPCError &error) { + _dialogFolderRequests.remove(folder); + }).send(); +} + +void Histories::requestDialogEntry( + not_null history, + Fn callback) { + const auto i = _dialogRequests.find(history); + if (i != end(_dialogRequests)) { + if (callback) { + i->second.push_back(std::move(callback)); + } + return; + } + + const auto [j, ok] = _dialogRequestsPending.try_emplace(history); + if (callback) { + j->second.push_back(std::move(callback)); + } + if (!ok) { + return; + } + if (_dialogRequestsPending.size() > 1) { + return; + } + Core::App().postponeCall(crl::guard(&session(), [=] { + sendDialogRequests(); + })); +} + +void Histories::sendDialogRequests() { + if (_dialogRequestsPending.empty()) { + return; + } + auto histories = std::vector>(); + ranges::transform( + _dialogRequestsPending, + ranges::back_inserter(histories), + [](const auto &pair) { return pair.first; }); + auto peers = QVector(); + const auto dialogPeer = [](not_null history) { + return MTP_inputDialogPeer(history->peer->input); + }; + ranges::transform( + histories, + ranges::back_inserter(peers), + dialogPeer); + for (auto &[history, callbacks] : base::take(_dialogRequestsPending)) { + _dialogRequests.emplace(history, std::move(callbacks)); + } + + const auto finalize = [=] { + for (const auto history : histories) { + dialogEntryApplied(history); + history->updateChatListExistence(); + } + }; + session().api().request(MTPmessages_GetPeerDialogs( + MTP_vector(std::move(peers)) + )).done([=](const MTPmessages_PeerDialogs &result) { + applyPeerDialogs(result); + finalize(); + }).fail([=](const RPCError &error) { + finalize(); + }).send(); +} + +void Histories::dialogEntryApplied(not_null history) { + history->dialogEntryApplied(); + if (const auto callbacks = _dialogRequestsPending.take(history)) { + for (const auto &callback : *callbacks) { + callback(); + } + } + if (const auto callbacks = _dialogRequests.take(history)) { + for (const auto &callback : *callbacks) { + callback(); + } + } +} + +void Histories::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) { + Expects(dialogs.type() == mtpc_messages_peerDialogs); + + const auto &data = dialogs.c_messages_peerDialogs(); + _owner->processUsers(data.vusers()); + _owner->processChats(data.vchats()); + _owner->processMessages(data.vmessages(), NewMessageType::Last); + for (const auto &dialog : data.vdialogs().v) { + dialog.match([&](const MTPDdialog &data) { + if (const auto peerId = peerFromMTP(data.vpeer())) { + _owner->history(peerId)->applyDialog(nullptr, data); + } + }, [&](const MTPDdialogFolder &data) { + const auto folder = _owner->processFolder(data.vfolder()); + folder->applyDialog(data); + }); + } + _owner->sendHistoryChangeNotifications(); +} + +void Histories::changeDialogUnreadMark( + not_null history, + bool unread) { + history->setUnreadMark(unread); + + using Flag = MTPmessages_MarkDialogUnread::Flag; + session().api().request(MTPmessages_MarkDialogUnread( + MTP_flags(unread ? Flag::f_unread : Flag(0)), + MTP_inputDialogPeer(history->peer->input) + )).send(); +} + void Histories::sendPendingReadInbox(not_null history) { if (const auto state = lookup(history)) { if (state->readTill @@ -233,7 +363,7 @@ void Histories::sendReadRequest(not_null history, State &state) { Assert(state->readTill >= tillId); if (history->unreadCountRefreshNeeded(tillId)) { - session().api().requestDialogEntry(history); + requestDialogEntry(history); } if (state->readWhen == kReadRequestSent) { state->readWhen = 0; @@ -295,7 +425,7 @@ int Histories::sendRequest( type }); if (base::take(state.thenRequestEntry)) { - session().api().requestDialogEntry(history); + requestDialogEntry(history); } } else if (action == Action::Postpone) { state.postponed.emplace( @@ -322,7 +452,7 @@ void Histories::checkPostponed(not_null history, int requestId) { postponed.type }); if (base::take(state->thenRequestEntry)) { - session().api().requestDialogEntry(history); + requestDialogEntry(history); } } else { Assert(action == Action::Postpone); diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index 42a9641ce..59f02542e 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -19,6 +19,7 @@ class Session; namespace Data { class Session; +class Folder; class Histories final { public: @@ -40,6 +41,14 @@ public: void readClientSideMessage(not_null item); void sendPendingReadInbox(not_null history); + void requestDialogEntry(not_null folder); + void requestDialogEntry( + not_null history, + Fn callback = nullptr); + void dialogEntryApplied(not_null history); + void changeDialogUnreadMark(not_null history, bool unread); + //void changeDialogUnreadMark(not_null feed, bool unread); // #feed + private: enum class RequestType : uchar { None, @@ -85,12 +94,23 @@ private: RequestType type, bool fromPostponed = false) const; + void sendDialogRequests(); + void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs); + const not_null _owner; std::unordered_map> _map; base::flat_map, State> _states; base::Timer _readRequestsTimer; + base::flat_set> _dialogFolderRequests; + base::flat_map< + not_null, + std::vector>> _dialogRequests; + base::flat_map< + not_null, + std::vector>> _dialogRequestsPending; + }; } // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 8ccfa500b..1044fcc3c 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_folder.h" #include "data/data_session.h" #include "data/data_file_origin.h" +#include "data/data_histories.h" #include "base/unixtime.h" #include "base/crc32hash.h" #include "lang/lang_keys.h" @@ -457,7 +458,7 @@ void PeerData::checkFolder(FolderId folderId) { : nullptr; if (const auto history = owner().historyLoaded(this)) { if (folder && history->folder() != folder) { - session().api().requestDialogEntry(history); + owner().histories().requestDialogEntry(history); } } } diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index dc19add6e..7fa9f0a06 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1530,7 +1530,7 @@ void Session::applyDialog( return; } - const auto history = session().data().history(peerId); + const auto history = this->history(peerId); history->applyDialog(requestFolder, data); setPinnedFromDialog(history, data.is_pinned()); @@ -3597,7 +3597,7 @@ void Session::serviceNotification( } const auto history = this->history(PeerData::kServiceNotificationsId); if (!history->folderKnown()) { - _session->api().requestDialogEntry(history, [=] { + histories().requestDialogEntry(history, [=] { insertCheckedServiceNotification(message, media, date); }); } else { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index d80fb8762..5af51519d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_user.h" #include "data/data_peer_values.h" +#include "data/data_histories.h" #include "base/unixtime.h" #include "lang/lang_keys.h" #include "mainwindow.h" @@ -2040,7 +2041,7 @@ bool InnerWidget::searchReceived( _searchInChat, item)); if (uniquePeers && !history->unreadCountKnown()) { - history->session().api().requestDialogEntry(history); + history->owner().histories().requestDialogEntry(history); } } lastDateFound = lastDate; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 78fe529a4..80a17e2be 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -685,7 +685,7 @@ not_null History::addNewItem( not_null item, bool unread) { if (item->isScheduled()) { - session().data().scheduledMessages().appendSending(item); + owner().scheduledMessages().appendSending(item); return item; } else if (!item->isHistoryEntry()) { return item; @@ -1285,7 +1285,7 @@ void History::newItemAdded(not_null item) { if (unreadCountKnown()) { setUnreadCount(unreadCount() + 1); } else { - session().api().requestDialogEntry(this); + owner().histories().requestDialogEntry(this); } } } @@ -1298,7 +1298,7 @@ void History::newItemAdded(not_null item) { outboxRead(item); } if (!folderKnown()) { - session().api().requestDialogEntry(this); + owner().histories().requestDialogEntry(this); } } @@ -1619,7 +1619,7 @@ bool History::readInboxTillNeedsRequest(MsgId tillId) { readClientSideMessages(); if (unreadMark()) { - session().api().changeDialogUnreadMark(this, false); + owner().histories().changeDialogUnreadMark(this, false); } return IsServerMsgId(tillId) && (_inboxReadBefore.value_or(1) <= tillId); } @@ -1691,8 +1691,8 @@ void History::applyInboxReadUpdate( const auto folder = folderId ? owner().folderLoaded(folderId) : nullptr; if (folder && this->folder() != folder) { // If history folder is unknown or not synced, request both. - session().api().requestDialogEntry(this); - session().api().requestDialogEntry(folder); + owner().histories().requestDialogEntry(this); + owner().histories().requestDialogEntry(folder); } if (_inboxReadBefore.value_or(1) <= upTo) { if (!peer->isChannel() || peer->asChannel()->pts() == channelPts) { @@ -1712,7 +1712,7 @@ void History::inboxRead(MsgId upTo, std::optional stillUnread) { } else if (const auto still = countStillUnreadLocal(upTo)) { setUnreadCount(*still); } else { - session().api().requestDialogEntry(this); + owner().histories().requestDialogEntry(this); } setInboxReadTill(upTo); updateChatListEntry(); @@ -2463,7 +2463,7 @@ void History::setChatListMessageUnknown() { void History::requestChatListMessage() { if (!lastMessageKnown()) { - session().api().requestDialogEntry(this, [=] { + owner().histories().requestDialogEntry(this, [=] { requestChatListMessage(); }); return; @@ -2556,7 +2556,7 @@ void History::updateChatListExistence() { // // After ungrouping from a feed we need to load dialog. // requestChatListMessage(); // if (!unreadCountKnown()) { - // session().api().requestDialogEntry(this); + // owner().histories().requestDialogEntry(this); // } // } //} @@ -2608,7 +2608,7 @@ bool History::toImportant() const { void History::unknownMessageDeleted(MsgId messageId) { if (_inboxReadBefore && messageId >= *_inboxReadBefore) { - session().api().requestDialogEntry(this); + owner().histories().requestDialogEntry(this); } } @@ -2660,7 +2660,7 @@ void History::applyDialog( if (draft && draft->type() == mtpc_draftMessage) { Data::applyPeerCloudDraft(peer->id, draft->c_draftMessage()); } - session().api().dialogEntryApplied(this); + owner().histories().dialogEntryApplied(this); } void History::dialogEntryApplied() { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index f70e5fa8d..15deb8f4f 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1878,9 +1878,13 @@ void HistoryWidget::showHistory( } } if (_history->chatListUnreadMark()) { - session().api().changeDialogUnreadMark(_history, false); + _history->owner().histories().changeDialogUnreadMark( + _history, + false); if (_migrated) { - session().api().changeDialogUnreadMark(_migrated, false); + _migrated->owner().histories().changeDialogUnreadMark( + _migrated, + false); } // Must be done before unreadCountUpdated(), or we auto-close. diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index ec105b29b..b5a8dcfa9 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user.h" #include "data/data_scheduled_messages.h" #include "data/data_file_origin.h" +#include "data/data_histories.h" #include "api/api_text_entities.h" #include "ui/special_buttons.h" #include "ui/widgets/buttons.h" @@ -4027,7 +4028,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // d.vunread_count()->v, // d.vunread_muted_count()->v); // } else { - // session().api().requestDialogEntry(feed); + // session().data().histories().requestDialogEntry(feed); // } // } //} break; @@ -4403,7 +4404,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { session().api().requestPinnedDialogs(folder); } if (!loaded) { - session().api().requestDialogEntry(folder); + session().data().histories().requestDialogEntry(folder); } } break; @@ -4461,12 +4462,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { //if (const auto feed = channel->feed()) { // #feed // feed->requestChatListMessage(); // if (!feed->unreadCountKnown()) { - // feed->session().api().requestDialogEntry(feed); + // feed->owner().histories().requestDialogEntry(feed); // } //} else { history->requestChatListMessage(); if (!history->unreadCountKnown()) { - history->session().api().requestDialogEntry(history); + history->owner().histories().requestDialogEntry(history); } //} if (!channel->amCreator()) { diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 64220b5a2..fa85d2984 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -304,9 +304,9 @@ void Filler::addToggleUnreadMark() { const auto markAsRead = isUnread(peer); const auto handle = [&](not_null history) { if (markAsRead) { - peer->session().data().histories().readInbox(history); + peer->owner().histories().readInbox(history); } else { - peer->session().api().changeDialogUnreadMark( + peer->owner().histories().changeDialogUnreadMark( history, !markAsRead); } From 147e8cc4670c4dbc1e060276d0aa4586d51562ce Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 13:22:01 +0400 Subject: [PATCH 068/140] Prepare for syncing read / write requests. --- Telegram/SourceFiles/data/data_histories.cpp | 211 +++++++++---------- Telegram/SourceFiles/data/data_histories.h | 48 ++--- 2 files changed, 127 insertions(+), 132 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 283dc97d8..571927435 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -241,11 +241,21 @@ void Histories::sendDialogRequests() { if (_dialogRequestsPending.empty()) { return; } - auto histories = std::vector>(); - ranges::transform( - _dialogRequestsPending, - ranges::back_inserter(histories), - [](const auto &pair) { return pair.first; }); + const auto histories = ranges::view::all( + _dialogRequestsPending + ) | ranges::view::transform([](const auto &pair) { + return pair.first; + }) | ranges::view::filter([&](not_null history) { + const auto state = lookup(history); + if (!state) { + return true; + } else if (!postponeEntryRequest(*state)) { + return true; + } + state->postponedRequestEntry = true; + return false; + }) | ranges::to_vector; + auto peers = QVector(); const auto dialogPeer = [](not_null history) { return MTP_inputDialogPeer(history->peer->input); @@ -260,8 +270,11 @@ void Histories::sendDialogRequests() { const auto finalize = [=] { for (const auto history : histories) { - dialogEntryApplied(history); - history->updateChatListExistence(); + const auto state = lookup(history); + if (!state || !state->postponedRequestEntry) { + dialogEntryApplied(history); + history->updateChatListExistence(); + } } }; session().api().request(MTPmessages_GetPeerDialogs( @@ -401,6 +414,7 @@ void Histories::sendReadRequest(not_null history, State &state) { void Histories::checkEmptyState(not_null history) { const auto empty = [](const State &state) { return state.postponed.empty() + && !state.postponedRequestEntry && state.sent.empty() && (state.readTill == 0); }; @@ -410,6 +424,21 @@ void Histories::checkEmptyState(not_null history) { } } +bool Histories::postponeHistoryRequest(const State &state) const { + const auto proj = [](const auto &pair) { + return pair.second.type; + }; + const auto i = ranges::find(state.sent, RequestType::Delete, proj); + return (i != end(state.sent)); +} + +bool Histories::postponeEntryRequest(const State &state) const { + const auto i = ranges::find_if(state.sent, [](const auto &pair) { + return pair.second.type != RequestType::History; + }); + return (i != end(state.sent)); +} + int Histories::sendRequest( not_null history, RequestType type, @@ -418,119 +447,85 @@ int Histories::sendRequest( auto &state = _states[history]; const auto id = ++state.autoincrement; - const auto action = chooseAction(state, type); - if (action == Action::Send) { - state.sent.emplace(id, SentRequest{ - generator([=] { checkPostponed(history, id); }), - type - }); - if (base::take(state.thenRequestEntry)) { - requestDialogEntry(history); - } - } else if (action == Action::Postpone) { + if (type == RequestType::History && postponeHistoryRequest(state)) { state.postponed.emplace( id, - PostponedRequest{ std::move(generator), type }); + PostponedHistoryRequest{ std::move(generator) }); + return id; + } + const auto requestId = generator([=] { checkPostponed(history, id); }); + state.sent.emplace(id, SentRequest{ + std::move(generator), + requestId, + type + }); + if (!state.postponedRequestEntry + && postponeEntryRequest(state) + && _dialogRequests.contains(history)) { + state.postponedRequestEntry = true; + } + if (postponeHistoryRequest(state)) { + const auto resendHistoryRequest = [&](auto &pair) { + auto &[id, sent] = pair; + if (sent.type != RequestType::History) { + return false; + } + state.postponed.emplace( + id, + PostponedHistoryRequest{ std::move(sent.generator) }); + session().api().request(sent.id).cancel(); + return true; + }; + state.sent.erase( + ranges::remove_if(state.sent, resendHistoryRequest), + end(state.sent)); } return id; } -void Histories::checkPostponed(not_null history, int requestId) { +void Histories::checkPostponed(not_null history, int id) { const auto state = lookup(history); Assert(state != nullptr); - state->sent.remove(requestId); - if (!state->postponed.empty()) { - auto &entry = state->postponed.front(); - const auto action = chooseAction(*state, entry.second.type, true); - if (action == Action::Send) { - const auto id = entry.first; - const auto postponed = std::move(entry.second); - state->postponed.remove(id); - state->sent.emplace(id, SentRequest{ - postponed.generator([=] { checkPostponed(history, id); }), - postponed.type - }); - if (base::take(state->thenRequestEntry)) { - requestDialogEntry(history); - } - } else { - Assert(action == Action::Postpone); - } - } - checkEmptyState(history); + finishSentRequest(history, state, id); } -Histories::Action Histories::chooseAction( - State &state, - RequestType type, - bool fromPostponed) const { - switch (type) { - case RequestType::ReadInbox: - for (const auto &[_, sent] : state.sent) { - if (sent.type == RequestType::ReadInbox - || sent.type == RequestType::DialogsEntry - || sent.type == RequestType::Delete) { - if (!fromPostponed) { - auto &postponed = state.postponed; - for (auto i = begin(postponed); i != end(postponed);) { - if (i->second.type == RequestType::ReadInbox) { - i = postponed.erase(i); - } else { - ++i; - } - } - } - return Action::Postpone; - } - } - return Action::Send; - - case RequestType::DialogsEntry: - for (const auto &[_, sent] : state.sent) { - if (sent.type == RequestType::DialogsEntry) { - return Action::Skip; - } - if (sent.type == RequestType::ReadInbox - || sent.type == RequestType::Delete) { - if (!fromPostponed) { - auto &postponed = state.postponed; - for (const auto &[_, postponed] : state.postponed) { - if (postponed.type == RequestType::DialogsEntry) { - return Action::Skip; - } - } - } - return Action::Postpone; - } - } - return Action::Send; - - case RequestType::History: - for (const auto &[_, sent] : state.sent) { - if (sent.type == RequestType::Delete) { - return Action::Postpone; - } - } - return Action::Send; - - case RequestType::Delete: - for (const auto &[_, sent] : state.sent) { - if (sent.type == RequestType::History - || sent.type == RequestType::ReadInbox) { - return Action::Postpone; - } - } - for (auto i = begin(state.sent); i != end(state.sent);) { - if (i->second.type == RequestType::DialogsEntry) { - session().api().request(i->second.id).cancel(); - i = state.sent.erase(i); - state.thenRequestEntry = true; - } - } - return Action::Send; +void Histories::cancelRequest(not_null history, int id) { + const auto state = lookup(history); + if (!state) { + return; } - Unexpected("Request type in Histories::chooseAction."); + state->postponed.remove(id); + finishSentRequest(history, state, id); +} + +void Histories::finishSentRequest( + not_null history, + not_null state, + int id) { + state->sent.remove(id); + if (!state->postponed.empty() && !postponeHistoryRequest(*state)) { + for (auto &[id, postponed] : base::take(state->postponed)) { + const auto requestId = postponed.generator([=] { + checkPostponed(history, id); + }); + state->sent.emplace(id, SentRequest{ + std::move(postponed.generator), + requestId, + RequestType::History + }); + } + } + if (state->postponedRequestEntry && !postponeEntryRequest(*state)) { + const auto i = _dialogRequests.find(history); + Assert(i != end(_dialogRequests)); + const auto [j, ok] = _dialogRequestsPending.emplace( + history, + std::move(i->second)); + Assert(ok); + state->postponedRequestEntry = false; + } + checkEmptyState(history); } Histories::State *Histories::lookup(not_null history) { diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index 59f02542e..af62439b3 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -23,6 +23,14 @@ class Folder; class Histories final { public: + enum class RequestType : uchar { + None, + History, + ReadInbox, + Delete, + Send, + }; + explicit Histories(not_null owner); [[nodiscard]] Session &owner() const; @@ -49,34 +57,28 @@ public: void changeDialogUnreadMark(not_null history, bool unread); //void changeDialogUnreadMark(not_null feed, bool unread); // #feed + int sendRequest( + not_null history, + RequestType type, + Fn done)> generator); + void cancelRequest(not_null history, int id); + private: - enum class RequestType : uchar { - None, - DialogsEntry, - History, - ReadInbox, - Delete, - }; - enum class Action : uchar { - Send, - Postpone, - Skip, - }; - struct PostponedRequest { + struct PostponedHistoryRequest { Fn done)> generator; - RequestType type = RequestType::None; }; struct SentRequest { + Fn done)> generator; mtpRequestId id = 0; RequestType type = RequestType::None; }; struct State { - base::flat_map postponed; + base::flat_map postponed; base::flat_map sent; crl::time readWhen = 0; MsgId readTill = 0; int autoincrement = 0; - bool thenRequestEntry = false; + bool postponedRequestEntry = false; }; void readInboxTill(not_null history, MsgId tillId, bool force); @@ -84,15 +86,13 @@ private: void sendReadRequest(not_null history, State &state); [[nodiscard]] State *lookup(not_null history); void checkEmptyState(not_null history); - int sendRequest( + void checkPostponed(not_null history, int id); + void finishSentRequest( not_null history, - RequestType type, - Fn done)> generator); - void checkPostponed(not_null history, int requestId); - [[nodiscard]] Action chooseAction( - State &state, - RequestType type, - bool fromPostponed = false) const; + not_null state, + int id); + [[nodiscard]] bool postponeHistoryRequest(const State &state) const; + [[nodiscard]] bool postponeEntryRequest(const State &state) const; void sendDialogRequests(); void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs); From 818f5cd0049dfc4cee6935663afc0a930b6ec9cc Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 14:29:48 +0400 Subject: [PATCH 069/140] Send and delete messages through Histories. --- Telegram/SourceFiles/api/api_sending.cpp | 42 ++- Telegram/SourceFiles/apiwrap.cpp | 353 +++++++++--------- Telegram/SourceFiles/apiwrap.h | 14 +- Telegram/SourceFiles/boxes/confirm_box.cpp | 9 +- .../boxes/peer_list_controllers.cpp | 58 +-- Telegram/SourceFiles/data/data_histories.cpp | 77 +++- Telegram/SourceFiles/data/data_histories.h | 16 +- .../SourceFiles/history/history_message.cpp | 52 +-- 8 files changed, 363 insertions(+), 258 deletions(-) diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index bc6788818..082826664 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user.h" // UserData::name #include "data/data_session.h" #include "data/data_file_origin.h" +#include "data/data_histories.h" #include "history/history.h" #include "history/history_message.h" // NewMessageFlags. #include "chat_helpers/message_field.h" // ConvertTextTagsToEntities. @@ -110,23 +111,30 @@ void SendExistingMedia( auto failHandler = std::make_shared>(); auto performRequest = [=] { - const auto usedFileReference = media->fileReference(); - history->sendRequestId = api->request(MTPmessages_SendMedia( - MTP_flags(sendFlags), - peer->input, - MTP_int(replyTo), - inputMedia(), - MTP_string(captionText), - MTP_long(randomId), - MTPReplyMarkup(), - sentEntities, - MTP_int(message.action.options.scheduled) - )).done([=](const MTPUpdates &result) { - api->applyUpdates(result, randomId); - }).fail([=](const RPCError &error) { - (*failHandler)(error, usedFileReference); - }).afterRequest(history->sendRequestId - ).send(); + auto &histories = history->owner().histories(); + const auto requestType = Data::Histories::RequestType::Send; + histories.sendRequest(history, requestType, [=](Fn finish) { + const auto usedFileReference = media->fileReference(); + history->sendRequestId = api->request(MTPmessages_SendMedia( + MTP_flags(sendFlags), + peer->input, + MTP_int(replyTo), + inputMedia(), + MTP_string(captionText), + MTP_long(randomId), + MTPReplyMarkup(), + sentEntities, + MTP_int(message.action.options.scheduled) + )).done([=](const MTPUpdates &result) { + api->applyUpdates(result, randomId); + finish(); + }).fail([=](const RPCError &error) { + (*failHandler)(error, usedFileReference); + finish(); + }).afterRequest(history->sendRequestId + ).send(); + return history->sendRequestId; + }); }; *failHandler = [=](const RPCError &error, QByteArray usedFileReference) { if (error.code() == 400 diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index ff5c309a3..c462dfeb4 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2319,8 +2319,8 @@ void ApiWrap::deleteHistory( bool justClear, bool revoke) { auto deleteTillId = MsgId(0); - const auto history = _session->data().historyLoaded(peer); - if (history && justClear) { + const auto history = _session->data().history(peer); + if (justClear) { // In case of clear history we need to know the last server message. while (history->lastMessageKnown()) { const auto last = history->lastMessage(); @@ -2350,30 +2350,22 @@ void ApiWrap::deleteHistory( leaveChannel(channel); } else { if (const auto migrated = peer->migrateFrom()) { - clearHistory(migrated, revoke); + deleteHistory(migrated, justClear, revoke); } if (IsServerMsgId(deleteTillId)) { - request(MTPchannels_DeleteHistory( - channel->inputChannel, - MTP_int(deleteTillId) - )).send(); + history->owner().histories().deleteAllMessages( + history, + deleteTillId, + justClear, + revoke); } } } else { - using Flag = MTPmessages_DeleteHistory::Flag; - const auto flags = Flag(0) - | (justClear ? Flag::f_just_clear : Flag(0)) - | ((peer->isUser() && revoke) ? Flag::f_revoke : Flag(0)); - request(MTPmessages_DeleteHistory( - MTP_flags(flags), - peer->input, - MTP_int(0) - )).done([=](const MTPmessages_AffectedHistory &result) { - const auto offset = applyAffectedHistory(peer, result); - if (offset > 0) { - deleteHistory(peer, justClear, revoke); - } - }).send(); + history->owner().histories().deleteAllMessages( + history, + deleteTillId, + justClear, + revoke); } if (!justClear) { _session->data().deleteConversationLocally(peer); @@ -2411,30 +2403,6 @@ void ApiWrap::applyAffectedMessages( App::main()->ptsUpdateAndApply(data.vpts().v, data.vpts_count().v); } -void ApiWrap::deleteMessages( - not_null peer, - const QVector &ids, - bool revoke) { - const auto done = [=](const MTPmessages_AffectedMessages & result) { - applyAffectedMessages(peer, result); - if (const auto history = peer->owner().historyLoaded(peer)) { - history->requestChatListMessage(); - } - }; - if (const auto channel = peer->asChannel()) { - request(MTPchannels_DeleteMessages( - channel->inputChannel, - MTP_vector(ids) - )).done(done).send(); - } else { - using Flag = MTPmessages_DeleteMessages::Flag; - request(MTPmessages_DeleteMessages( - MTP_flags(revoke ? Flag::f_revoke : Flag(0)), - MTP_vector(ids) - )).done(done).send(); - } -} - void ApiWrap::saveDraftsToCloud() { for (auto i = _draftsSaveRequestIds.begin(), e = _draftsSaveRequestIds.end(); i != e; ++i) { if (i->second) continue; // sent already @@ -4326,6 +4294,8 @@ void ApiWrap::forwardMessages( FnMut &&successCallback) { Expects(!items.empty()); + auto &histories = session().data().histories(); + struct SharedCallback { int requestsLeft = 0; FnMut callback; @@ -4342,7 +4312,7 @@ void ApiWrap::forwardMessages( const auto history = action.history; const auto peer = history->peer; - session().data().histories().readInbox(history); + histories.readInbox(history); const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto silentPost = action.options.silent @@ -4374,7 +4344,7 @@ void ApiWrap::forwardMessages( auto currentGroupId = items.front()->groupId(); auto ids = QVector(); auto randomIds = QVector(); - auto localIds = std::unique_ptr>(); + auto localIds = std::shared_ptr>(); const auto sendAccumulated = [&] { if (shared) { @@ -4384,30 +4354,36 @@ void ApiWrap::forwardMessages( | (currentGroupId == MessageGroupId() ? MTPmessages_ForwardMessages::Flag(0) : MTPmessages_ForwardMessages::Flag::f_grouped); - history->sendRequestId = request(MTPmessages_ForwardMessages( - MTP_flags(finalFlags), - forwardFrom->input, - MTP_vector(ids), - MTP_vector(randomIds), - peer->input, - MTP_int(action.options.scheduled) - )).done([=, callback = std::move(successCallback)]( - const MTPUpdates &updates) { - applyUpdates(updates); - if (shared && !--shared->requestsLeft) { - shared->callback(); - } - }).fail([=, ids = std::move(localIds)](const RPCError &error) { - if (ids) { - for (const auto &[randomId, itemId] : *ids) { - sendMessageFail(error, peer, randomId, itemId); + const auto requestType = Data::Histories::RequestType::Send; + histories.sendRequest(history, requestType, [=](Fn finish) { + history->sendRequestId = request(MTPmessages_ForwardMessages( + MTP_flags(finalFlags), + forwardFrom->input, + MTP_vector(ids), + MTP_vector(randomIds), + peer->input, + MTP_int(action.options.scheduled) + )).done([=]( + const MTPUpdates &updates) { + applyUpdates(updates); + if (shared && !--shared->requestsLeft) { + shared->callback(); } - } else { - sendMessageFail(error, peer); - } - }).afterRequest( - history->sendRequestId - ).send(); + finish(); + }).fail([=, ids = localIds](const RPCError &error) { + if (ids) { + for (const auto &[randomId, itemId] : *ids) { + sendMessageFail(error, peer, randomId, itemId); + } + } else { + sendMessageFail(error, peer); + } + finish(); + }).afterRequest( + history->sendRequestId + ).send(); + return history->sendRequestId; + }); ids.resize(0); randomIds.resize(0); @@ -4440,7 +4416,7 @@ void ApiWrap::forwardMessages( message); _session->data().registerMessageRandomId(randomId, newId); if (!localIds) { - localIds = std::make_unique>(); + localIds = std::make_shared>(); } localIds->emplace(randomId, newId); } @@ -4855,6 +4831,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) { HistoryItem *lastMessage = nullptr; + auto &histories = history->owner().histories(); + const auto requestType = Data::Histories::RequestType::Send; + while (TextUtilities::CutPart(sending, left, MaxMessageSize)) { auto newId = FullMsgId( peerToChannel(peer->id), @@ -4945,27 +4924,32 @@ void ApiWrap::sendMessage(MessageToSend &&message) { MTPVector()), clientFlags, NewMessageType::Unread); - history->sendRequestId = request(MTPmessages_SendMessage( - MTP_flags(sendFlags), - peer->input, - MTP_int(action.replyTo), - msgText, - MTP_long(randomId), - MTPReplyMarkup(), - sentEntities, - MTP_int(action.options.scheduled) - )).done([=](const MTPUpdates &result) { - applyUpdates(result, randomId); - history->clearSentDraftText(QString()); - }).fail([=](const RPCError &error) { - if (error.type() == qstr("MESSAGE_EMPTY")) { - lastMessage->destroy(); - } else { - sendMessageFail(error, peer, randomId, newId); - } - history->clearSentDraftText(QString()); - }).afterRequest(history->sendRequestId - ).send(); + histories.sendRequest(history, requestType, [=](Fn finish) { + history->sendRequestId = request(MTPmessages_SendMessage( + MTP_flags(sendFlags), + peer->input, + MTP_int(action.replyTo), + msgText, + MTP_long(randomId), + MTPReplyMarkup(), + sentEntities, + MTP_int(action.options.scheduled) + )).done([=](const MTPUpdates &result) { + applyUpdates(result, randomId); + history->clearSentDraftText(QString()); + finish(); + }).fail([=](const RPCError &error) { + if (error.type() == qstr("MESSAGE_EMPTY")) { + lastMessage->destroy(); + } else { + sendMessageFail(error, peer, randomId, newId); + } + history->clearSentDraftText(QString()); + finish(); + }).afterRequest(history->sendRequestId + ).send(); + return history->sendRequestId; + }); } if (const auto main = App::main()) { @@ -5071,23 +5055,29 @@ void ApiWrap::sendInlineResult( history->clearCloudDraft(); history->setSentDraftText(QString()); - history->sendRequestId = request(MTPmessages_SendInlineBotResult( - MTP_flags(sendFlags), - peer->input, - MTP_int(action.replyTo), - MTP_long(randomId), - MTP_long(data->getQueryId()), - MTP_string(data->getId()), - MTP_int(action.options.scheduled) - )).done([=](const MTPUpdates &result) { - applyUpdates(result, randomId); - history->clearSentDraftText(QString()); - }).fail([=](const RPCError &error) { - sendMessageFail(error, peer, randomId, newId); - history->clearSentDraftText(QString()); - }).afterRequest(history->sendRequestId - ).send(); - + auto &histories = history->owner().histories(); + const auto requestType = Data::Histories::RequestType::Send; + histories.sendRequest(history, requestType, [=](Fn finish) { + history->sendRequestId = request(MTPmessages_SendInlineBotResult( + MTP_flags(sendFlags), + peer->input, + MTP_int(action.replyTo), + MTP_long(randomId), + MTP_long(data->getQueryId()), + MTP_string(data->getId()), + MTP_int(action.options.scheduled) + )).done([=](const MTPUpdates &result) { + applyUpdates(result, randomId); + history->clearSentDraftText(QString()); + finish(); + }).fail([=](const RPCError &error) { + sendMessageFail(error, peer, randomId, newId); + history->clearSentDraftText(QString()); + finish(); + }).afterRequest(history->sendRequestId + ).send(); + return history->sendRequestId; + }); if (const auto main = App::main()) { main->finishForwarding(action); } @@ -5206,25 +5196,32 @@ void ApiWrap::sendMediaWithRandomId( ? MTPmessages_SendMedia::Flag::f_schedule_date : MTPmessages_SendMedia::Flag(0)); - const auto peer = history->peer; - const auto itemId = item->fullId(); - history->sendRequestId = request(MTPmessages_SendMedia( - MTP_flags(flags), - peer->input, - MTP_int(replyTo), - media, - MTP_string(caption.text), - MTP_long(randomId), - MTPReplyMarkup(), - sentEntities, - MTP_int(options.scheduled) - )).done([=](const MTPUpdates &result) { - applyUpdates(result); - }).fail([=](const RPCError &error) { - sendMessageFail(error, peer, randomId, itemId); - }).afterRequest( - history->sendRequestId - ).send(); + auto &histories = history->owner().histories(); + const auto requestType = Data::Histories::RequestType::Send; + histories.sendRequest(history, requestType, [=](Fn finish) { + const auto peer = history->peer; + const auto itemId = item->fullId(); + history->sendRequestId = request(MTPmessages_SendMedia( + MTP_flags(flags), + peer->input, + MTP_int(replyTo), + media, + MTP_string(caption.text), + MTP_long(randomId), + MTPReplyMarkup(), + sentEntities, + MTP_int(options.scheduled) + )).done([=](const MTPUpdates &result) { + applyUpdates(result); + finish(); + }).fail([=](const RPCError &error) { + sendMessageFail(error, peer, randomId, itemId); + finish(); + }).afterRequest( + history->sendRequestId + ).send(); + return history->sendRequestId; + }); } void ApiWrap::sendAlbumWithUploaded( @@ -5302,27 +5299,34 @@ void ApiWrap::sendAlbumIfReady(not_null album) { | (album->options.scheduled ? MTPmessages_SendMultiMedia::Flag::f_schedule_date : MTPmessages_SendMultiMedia::Flag(0)); - const auto peer = history->peer; - history->sendRequestId = request(MTPmessages_SendMultiMedia( - MTP_flags(flags), - peer->input, - MTP_int(replyTo), - MTP_vector(medias), - MTP_int(album->options.scheduled) - )).done([=](const MTPUpdates &result) { - _sendingAlbums.remove(groupId); - applyUpdates(result); - }).fail([=](const RPCError &error) { - if (const auto album = _sendingAlbums.take(groupId)) { - for (const auto &item : (*album)->items) { - sendMessageFail(error, peer, item.randomId, item.msgId); + auto &histories = history->owner().histories(); + const auto requestType = Data::Histories::RequestType::Send; + histories.sendRequest(history, requestType, [=](Fn finish) { + const auto peer = history->peer; + history->sendRequestId = request(MTPmessages_SendMultiMedia( + MTP_flags(flags), + peer->input, + MTP_int(replyTo), + MTP_vector(medias), + MTP_int(album->options.scheduled) + )).done([=](const MTPUpdates &result) { + _sendingAlbums.remove(groupId); + applyUpdates(result); + finish(); + }).fail([=](const RPCError &error) { + if (const auto album = _sendingAlbums.take(groupId)) { + for (const auto &item : (*album)->items) { + sendMessageFail(error, peer, item.randomId, item.msgId); + } + } else { + sendMessageFail(error, peer); } - } else { - sendMessageFail(error, peer); - } - }).afterRequest( - history->sendRequestId - ).send(); + finish(); + }).afterRequest( + history->sendRequestId + ).send(); + return history->sendRequestId; + }); } FileLoadTo ApiWrap::fileLoadTaskOptions(const SendAction &action) const { @@ -5719,8 +5723,8 @@ Api::SensitiveContent &ApiWrap::sensitiveContent() { void ApiWrap::createPoll( const PollData &data, const SendAction &action, - FnMut done, - FnMut fail) { + Fn done, + Fn fail) { sendAction(action); const auto history = action.history; @@ -5753,27 +5757,34 @@ void ApiWrap::createPoll( correct.push_back(MTP_bytes(answer.option)); } } - const auto replyTo = action.replyTo; - history->sendRequestId = request(MTPmessages_SendMedia( - MTP_flags(sendFlags), - peer->input, - MTP_int(replyTo), - MTP_inputMediaPoll( - MTP_flags(inputFlags), - PollDataToMTP(&data), - MTP_vector(correct)), - MTP_string(), - MTP_long(rand_value()), - MTPReplyMarkup(), - MTPVector(), - MTP_int(action.options.scheduled) - )).done([=, done = std::move(done)](const MTPUpdates &result) mutable { - applyUpdates(result); - done(); - }).fail([=, fail = std::move(fail)](const RPCError &error) mutable { - fail(error); - }).afterRequest(history->sendRequestId - ).send(); + auto &histories = history->owner().histories(); + const auto requestType = Data::Histories::RequestType::Send; + histories.sendRequest(history, requestType, [=](Fn finish) { + const auto replyTo = action.replyTo; + history->sendRequestId = request(MTPmessages_SendMedia( + MTP_flags(sendFlags), + peer->input, + MTP_int(replyTo), + MTP_inputMediaPoll( + MTP_flags(inputFlags), + PollDataToMTP(&data), + MTP_vector(correct)), + MTP_string(), + MTP_long(rand_value()), + MTPReplyMarkup(), + MTPVector(), + MTP_int(action.options.scheduled) + )).done([=](const MTPUpdates &result) mutable { + applyUpdates(result); + done(); + finish(); + }).fail([=](const RPCError &error) mutable { + fail(error); + finish(); + }).afterRequest(history->sendRequestId + ).send(); + return history->sendRequestId; + }); } void ApiWrap::sendPollVotes( diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index a3691df2b..8f46aa7d7 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -141,6 +141,9 @@ public: void applyUpdates( const MTPUpdates &updates, uint64 sentMessageRandomId = 0); + int applyAffectedHistory( + not_null peer, + const MTPmessages_AffectedHistory &result); void registerModifyRequest(const QString &key, mtpRequestId requestId); void clearModifyRequest(const QString &key); @@ -298,10 +301,6 @@ public: void clearHistory(not_null peer, bool revoke); void deleteConversation(not_null peer, bool revoke); - void deleteMessages( - not_null peer, - const QVector &ids, - bool revoke); base::Observable &fullPeerUpdated() { return _fullPeerUpdated; @@ -469,8 +468,8 @@ public: void createPoll( const PollData &data, const SendAction &action, - FnMut done, - FnMut fail); + Fn done, + Fn fail); void sendPollVotes( FullMsgId itemId, const std::vector &options); @@ -616,9 +615,6 @@ private: not_null peer, bool justClear, bool revoke); - int applyAffectedHistory( - not_null peer, - const MTPmessages_AffectedHistory &result); void applyAffectedMessages(const MTPmessages_AffectedMessages &result); void deleteAllFromUserSend( diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index 70cc1f954..c580d3716 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_user.h" #include "data/data_file_origin.h" +#include "data/data_histories.h" #include "base/unixtime.h" #include "main/main_session.h" #include "observer_peer.h" @@ -787,7 +788,7 @@ void DeleteMessagesBox::deleteAndClear() { auto remove = std::vector>(); remove.reserve(_ids.size()); - base::flat_map, QVector> idsByPeer; + base::flat_map, QVector> idsByPeer; base::flat_map, QVector> scheduledIdsByPeer; for (const auto itemId : _ids) { if (const auto item = _session->data().message(itemId)) { @@ -805,13 +806,13 @@ void DeleteMessagesBox::deleteAndClear() { } remove.push_back(item); if (IsServerMsgId(item->id)) { - idsByPeer[history->peer].push_back(MTP_int(itemId.msg)); + idsByPeer[history].push_back(MTP_int(itemId.msg)); } } } - for (const auto &[peer, ids] : idsByPeer) { - peer->session().api().deleteMessages(peer, ids, revoke); + for (const auto &[history, ids] : idsByPeer) { + history->owner().histories().deleteMessages(history, ids, revoke); } for (const auto &[peer, ids] : scheduledIdsByPeer) { peer->session().api().request(MTPmessages_DeleteScheduledMessages( diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 606ecc4f4..5fab61356 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_user.h" #include "data/data_folder.h" +#include "data/data_histories.h" #include "apiwrap.h" #include "mainwidget.h" #include "lang/lang_keys.h" @@ -30,33 +31,36 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { void ShareBotGame(not_null bot, not_null chat) { - const auto history = chat->owner().historyLoaded(chat); - const auto randomId = rand_value(); - const auto api = &chat->session().api(); - const auto requestId = api->request(MTPmessages_SendMedia( - MTP_flags(0), - chat->input, - MTP_int(0), - MTP_inputMediaGame( - MTP_inputGameShortName( - bot->inputUser, - MTP_string(bot->botInfo->shareGameShortName))), - MTP_string(), - MTP_long(randomId), - MTPReplyMarkup(), - MTPVector(), - MTP_int(0) // schedule_date - )).done([=](const MTPUpdates &result) { - api->applyUpdates(result, randomId); - }).fail([=](const RPCError &error) { - api->sendMessageFail(error, chat); - }).afterRequest( - history ? history->sendRequestId : 0 - ).send(); - - if (history) { - history->sendRequestId = requestId; - } + const auto history = chat->owner().history(chat); + auto &histories = history->owner().histories(); + const auto requestType = Data::Histories::RequestType::Send; + histories.sendRequest(history, requestType, [=](Fn finish) { + const auto randomId = rand_value(); + const auto api = &chat->session().api(); + history->sendRequestId = api->request(MTPmessages_SendMedia( + MTP_flags(0), + chat->input, + MTP_int(0), + MTP_inputMediaGame( + MTP_inputGameShortName( + bot->inputUser, + MTP_string(bot->botInfo->shareGameShortName))), + MTP_string(), + MTP_long(randomId), + MTPReplyMarkup(), + MTPVector(), + MTP_int(0) // schedule_date + )).done([=](const MTPUpdates &result) { + api->applyUpdates(result, randomId); + finish(); + }).fail([=](const RPCError &error) { + api->sendMessageFail(error, chat); + finish(); + }).afterRequest( + history->sendRequestId + ).send(); + return history->sendRequestId; + }); Ui::hideLayer(); Ui::showPeerHistory(chat, ShowAtUnreadMsgId); } diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 571927435..7d87d1a8e 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -369,7 +369,7 @@ void Histories::sendReadRequests() { void Histories::sendReadRequest(not_null history, State &state) { const auto tillId = state.readTill; state.readWhen = kReadRequestSent; - sendRequest(history, RequestType::ReadInbox, [=](Fn done) { + sendRequest(history, RequestType::ReadInbox, [=](Fn finish) { const auto finished = [=] { const auto state = lookup(history); Assert(state != nullptr); @@ -386,7 +386,7 @@ void Histories::sendReadRequest(not_null history, State &state) { sendReadRequests(); } } - done(); + finish(); }; if (const auto channel = history->peer->asChannel()) { return session().api().request(MTPchannels_ReadHistory( @@ -439,10 +439,81 @@ bool Histories::postponeEntryRequest(const State &state) const { return (i != end(state.sent)); } +void Histories::deleteMessages( + not_null history, + const QVector &ids, + bool revoke) { + sendRequest(history, RequestType::Delete, [=](Fn finish) { + const auto done = [=](const MTPmessages_AffectedMessages &result) { + session().api().applyAffectedMessages(history->peer, result); + finish(); + history->requestChatListMessage(); + }; + const auto fail = [=](const RPCError &error) { + finish(); + }; + if (const auto channel = history->peer->asChannel()) { + return session().api().request(MTPchannels_DeleteMessages( + channel->inputChannel, + MTP_vector(ids) + )).done(done).fail(fail).send(); + } else { + using Flag = MTPmessages_DeleteMessages::Flag; + return session().api().request(MTPmessages_DeleteMessages( + MTP_flags(revoke ? Flag::f_revoke : Flag(0)), + MTP_vector(ids) + )).done(done).fail(fail).send(); + } + }); +} + +void Histories::deleteAllMessages( + not_null history, + MsgId deleteTillId, + bool justClear, + bool revoke) { + sendRequest(history, RequestType::Delete, [=](Fn finish) { + const auto peer = history->peer; + const auto fail = [=](const RPCError &error) { + finish(); + }; + if (const auto channel = peer->asChannel()) { + return session().api().request(MTPchannels_DeleteHistory( + channel->inputChannel, + MTP_int(deleteTillId) + )).done([=](const MTPBool &result) { + finish(); + }).fail(fail).send(); + } else { + using Flag = MTPmessages_DeleteHistory::Flag; + const auto flags = Flag(0) + | (justClear ? Flag::f_just_clear : Flag(0)) + | ((peer->isUser() && revoke) ? Flag::f_revoke : Flag(0)); + return session().api().request(MTPmessages_DeleteHistory( + MTP_flags(flags), + peer->input, + MTP_int(0) + )).done([=](const MTPmessages_AffectedHistory &result) { + const auto offset = session().api().applyAffectedHistory( + peer, + result); + if (offset > 0) { + deleteAllMessages( + history, + deleteTillId, + justClear, + revoke); + } + finish(); + }).fail(fail).send(); + } + }); +} + int Histories::sendRequest( not_null history, RequestType type, - Fn done)> generator) { + Fn finish)> generator) { Expects(type != RequestType::None); auto &state = _states[history]; diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index af62439b3..0cbae7539 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -57,18 +57,28 @@ public: void changeDialogUnreadMark(not_null history, bool unread); //void changeDialogUnreadMark(not_null feed, bool unread); // #feed + void deleteMessages( + not_null history, + const QVector &ids, + bool revoke); + void deleteAllMessages( + not_null history, + MsgId deleteTillId, + bool justClear, + bool revoke); + int sendRequest( not_null history, RequestType type, - Fn done)> generator); + Fn finish)> generator); void cancelRequest(not_null history, int id); private: struct PostponedHistoryRequest { - Fn done)> generator; + Fn finish)> generator; }; struct SentRequest { - Fn done)> generator; + Fn finish)> generator; mtpRequestId id = 0; RequestType type = RequestType::None; }; diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 0c9ee4d34..7e2974d66 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_media_types.h" #include "data/data_channel.h" #include "data/data_user.h" +#include "data/data_histories.h" #include "facades.h" #include "app.h" #include "styles/style_dialogs.h" @@ -265,15 +266,6 @@ void FastShareMessage(not_null item) { return; } - auto doneCallback = [=](const MTPUpdates &updates, mtpRequestId requestId) { - history->session().api().applyUpdates(updates); - data->requests.remove(requestId); - if (data->requests.empty()) { - Ui::Toast::Show(tr::lng_share_done(tr::now)); - Ui::hideLayer(); - } - }; - const auto sendFlags = MTPmessages_ForwardMessages::Flag(0) | MTPmessages_ForwardMessages::Flag::f_with_my_score | (isGroup @@ -297,28 +289,40 @@ void FastShareMessage(not_null item) { } return result; }; + auto &api = owner->session().api(); + auto &histories = owner->histories(); + const auto requestType = Data::Histories::RequestType::Send; for (const auto peer : result) { - const auto history = peer->owner().history(peer); + const auto history = owner->history(peer); if (!comment.text.isEmpty()) { auto message = ApiWrap::MessageToSend(history); message.textWithTags = comment; message.action.options = options; message.action.clearDraft = false; - history->session().api().sendMessage(std::move(message)); + api.sendMessage(std::move(message)); } - history->sendRequestId = MTP::send( - MTPmessages_ForwardMessages( - MTP_flags(sendFlags), - data->peer->input, - MTP_vector(msgIds), - MTP_vector(generateRandom()), - peer->input, - MTP_int(options.scheduled)), - rpcDone(base::duplicate(doneCallback)), - nullptr, - 0, - 0, - history->sendRequestId); + histories.sendRequest(history, requestType, [=](Fn finish) { + auto &api = history->session().api(); + history->sendRequestId = api.request(MTPmessages_ForwardMessages( + MTP_flags(sendFlags), + data->peer->input, + MTP_vector(msgIds), + MTP_vector(generateRandom()), + peer->input, + MTP_int(options.scheduled) + )).done([=](const MTPUpdates &updates, mtpRequestId requestId) { + history->session().api().applyUpdates(updates); + data->requests.remove(requestId); + if (data->requests.empty()) { + Ui::Toast::Show(tr::lng_share_done(tr::now)); + Ui::hideLayer(); + } + finish(); + }).fail([=](const RPCError &error) { + finish(); + }).afterRequest(history->sendRequestId).send(); + return history->sendRequestId; + }); data->requests.insert(history->sendRequestId); } }; From 6f672ecdc345b00f1b7a550a0e0b4b0f9cfc6ea9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 15:51:37 +0400 Subject: [PATCH 070/140] Request history parts through Histories. --- Telegram/SourceFiles/apiwrap.cpp | 60 ++---- Telegram/SourceFiles/apiwrap.h | 6 +- .../SourceFiles/calls/calls_box_controller.h | 2 +- Telegram/SourceFiles/data/data_histories.cpp | 32 ++++ Telegram/SourceFiles/data/data_histories.h | 3 + .../data/data_search_controller.cpp | 45 +++-- .../SourceFiles/data/data_search_controller.h | 1 + .../SourceFiles/dialogs/dialogs_widget.cpp | 139 +++++++------- Telegram/SourceFiles/history/history.cpp | 2 +- .../SourceFiles/history/history_widget.cpp | 175 ++++++++++++------ Telegram/SourceFiles/history/history_widget.h | 12 +- 11 files changed, 282 insertions(+), 195 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index c462dfeb4..a0feaa15b 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -1012,34 +1012,6 @@ rpl::producer ApiWrap::dialogsLoadBlockedByDate() const { return _dialogsLoadBlockedByDate.value(); } -void ApiWrap::requestFakeChatListMessage( - not_null history) { - if (_fakeChatListRequests.contains(history)) { - return; - } - - _fakeChatListRequests.emplace(history); - request(MTPmessages_GetHistory( - history->peer->input, - MTP_int(0), // offset_id - MTP_int(0), // offset_date - MTP_int(0), // add_offset - MTP_int(2), // limit - MTP_int(0), // max_id - MTP_int(0), // min_id - MTP_int(0) - )).done([=](const MTPmessages_Messages &result) { - _fakeChatListRequests.erase(history); - history->setFakeChatListMessageFrom(result); - }).fail([=](const RPCError &error) { - _fakeChatListRequests.erase(history); - history->setFakeChatListMessageFrom(MTP_messages_messages( - MTP_vector(0), - MTP_vector(0), - MTP_vector(0))); - }).send(); -} - void ApiWrap::requestWallPaper( const QString &slug, Fn done, @@ -3908,12 +3880,12 @@ void ApiWrap::requestSharedMedia( SharedMediaType type, MsgId messageId, SliceType slice) { - auto key = std::make_tuple(peer, type, messageId, slice); + const auto key = std::make_tuple(peer, type, messageId, slice); if (_sharedMediaRequests.contains(key)) { return; } - auto prepared = Api::PrepareSearchRequest( + const auto prepared = Api::PrepareSearchRequest( peer, type, QString(), @@ -3923,17 +3895,23 @@ void ApiWrap::requestSharedMedia( return; } - auto requestId = request( - std::move(*prepared) - ).done([this, peer, type, messageId, slice]( - const MTPmessages_Messages &result) { - auto key = std::make_tuple(peer, type, messageId, slice); - _sharedMediaRequests.remove(key); - sharedMediaDone(peer, type, messageId, slice, result); - }).fail([this, key](const RPCError &error) { - _sharedMediaRequests.remove(key); - }).send(); - _sharedMediaRequests.emplace(key, requestId); + const auto history = session().data().history(peer); + auto &histories = history->owner().histories(); + const auto requestType = Data::Histories::RequestType::History; + histories.sendRequest(history, requestType, [=](Fn finish) { + return request( + std::move(*prepared) + ).done([=](const MTPmessages_Messages &result) { + const auto key = std::make_tuple(peer, type, messageId, slice); + _sharedMediaRequests.remove(key); + sharedMediaDone(peer, type, messageId, slice, result); + finish(); + }).fail([=](const RPCError &error) { + _sharedMediaRequests.remove(key); + finish(); + }).send(); + }); + _sharedMediaRequests.emplace(key); } void ApiWrap::sharedMediaDone( diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 8f46aa7d7..c48ef2b01 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -177,7 +177,6 @@ public: //void setFeedChannels( // not_null feed, // const std::vector> &channels); - void requestFakeChatListMessage(not_null history); void requestWallPaper( const QString &slug, @@ -739,15 +738,14 @@ private: mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0; - base::flat_set> _fakeChatListRequests; base::flat_map, mtpRequestId> _unreadMentionsRequests; - base::flat_map, SharedMediaType, MsgId, - SliceType>, mtpRequestId> _sharedMediaRequests; + SliceType>> _sharedMediaRequests; base::flat_map, mtpRequestId> _userPhotosRequests; diff --git a/Telegram/SourceFiles/calls/calls_box_controller.h b/Telegram/SourceFiles/calls/calls_box_controller.h index d67e22c04..ae5894df4 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.h +++ b/Telegram/SourceFiles/calls/calls_box_controller.h @@ -44,7 +44,7 @@ private: MTP::Sender _api; MsgId _offsetId = 0; - mtpRequestId _loadRequestId = 0; + int _loadRequestId = 0; // Not a real mtpRequestId. bool _allLoaded = false; }; diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 7d87d1a8e..3a5df6411 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -333,6 +333,38 @@ void Histories::changeDialogUnreadMark( )).send(); } +void Histories::requestFakeChatListMessage( + not_null history) { + if (_fakeChatListRequests.contains(history)) { + return; + } + + _fakeChatListRequests.emplace(history); + sendRequest(history, RequestType::History, [=](Fn finish) { + return session().api().request(MTPmessages_GetHistory( + history->peer->input, + MTP_int(0), // offset_id + MTP_int(0), // offset_date + MTP_int(0), // add_offset + MTP_int(2), // limit + MTP_int(0), // max_id + MTP_int(0), // min_id + MTP_int(0) + )).done([=](const MTPmessages_Messages &result) { + _fakeChatListRequests.erase(history); + history->setFakeChatListMessageFrom(result); + finish(); + }).fail([=](const RPCError &error) { + _fakeChatListRequests.erase(history); + history->setFakeChatListMessageFrom(MTP_messages_messages( + MTP_vector(0), + MTP_vector(0), + MTP_vector(0))); + finish(); + }).send(); + }); +} + void Histories::sendPendingReadInbox(not_null history) { if (const auto state = lookup(history)) { if (state->readTill diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index 0cbae7539..bcc068229 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -56,6 +56,7 @@ public: void dialogEntryApplied(not_null history); void changeDialogUnreadMark(not_null history, bool unread); //void changeDialogUnreadMark(not_null feed, bool unread); // #feed + void requestFakeChatListMessage(not_null history); void deleteMessages( not_null history, @@ -121,6 +122,8 @@ private: not_null, std::vector>> _dialogRequestsPending; + base::flat_set> _fakeChatListRequests; + }; } // namespace Data diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp index 243654287..6ae67371f 100644 --- a/Telegram/SourceFiles/data/data_search_controller.cpp +++ b/Telegram/SourceFiles/data/data_search_controller.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_messages.h" #include "data/data_channel.h" +#include "data/data_histories.h" #include "history/history.h" #include "history/history_item.h" #include "apiwrap.h" @@ -193,7 +194,8 @@ SearchController::CacheEntry::CacheEntry(const Query &query) } SearchController::SearchController(not_null session) -: _api(session->api().instance()) { +: _session(session) +, _api(session->api().instance()) { } bool SearchController::hasInCache(const Query &query) const { @@ -366,23 +368,32 @@ void SearchController::requestMore( if (!prepared) { return; } - auto requestId = _api.request( - std::move(*prepared) - ).done([=](const MTPmessages_Messages &result) { - listData->requests.remove(key); - auto parsed = ParseSearchResult( - listData->peer, - query.type, - key.aroundId, - key.direction, - result); - listData->list.addSlice( - std::move(parsed.messageIds), - parsed.noSkipRange, - parsed.fullCount); - }).send(); + auto &histories = _session->data().histories(); + const auto type = Histories::RequestType::History; + const auto history = _session->data().history(listData->peer); + auto requestId = histories.sendRequest(history, type, [=](Fn finish) { + return _api.request( + std::move(*prepared) + ).done([=](const MTPmessages_Messages &result) { + listData->requests.remove(key); + auto parsed = ParseSearchResult( + listData->peer, + query.type, + key.aroundId, + key.direction, + result); + listData->list.addSlice( + std::move(parsed.messageIds), + parsed.noSkipRange, + parsed.fullCount); + finish(); + }).fail([=](const RPCError &error) { + finish(); + }).send(); + }); listData->requests.emplace(key, [=] { - _api.request(requestId).cancel(); + auto &histories = _session->data().histories(); + histories.cancelRequest(history, requestId); }); } diff --git a/Telegram/SourceFiles/data/data_search_controller.h b/Telegram/SourceFiles/data/data_search_controller.h index fcc2b8853..a439bb38e 100644 --- a/Telegram/SourceFiles/data/data_search_controller.h +++ b/Telegram/SourceFiles/data/data_search_controller.h @@ -129,6 +129,7 @@ private: const Query &query, Data *listData); + const not_null _session; MTP::Sender _api; Cache _cache; Cache::iterator _current = _cache.end(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 8fbf57622..ab1c85d3e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1015,94 +1015,95 @@ void Widget::searchReceived( ? *_singleMessageSearch.lookup(_searchQuery) : nullptr; - if (_searchRequest == requestId) { - switch (result.type()) { - case mtpc_messages_messages: { - auto &d = result.c_messages_messages(); - if (_searchRequest != 0) { - // Don't apply cached data! - session().data().processUsers(d.vusers()); - session().data().processChats(d.vchats()); - } - auto &msgs = d.vmessages().v; - _inner->searchReceived(msgs, inject, type, msgs.size()); + if (_searchRequest != requestId) { + return; + } + switch (result.type()) { + case mtpc_messages_messages: { + auto &d = result.c_messages_messages(); + if (_searchRequest != 0) { + // Don't apply cached data! + session().data().processUsers(d.vusers()); + session().data().processChats(d.vchats()); + } + auto &msgs = d.vmessages().v; + _inner->searchReceived(msgs, inject, type, msgs.size()); + if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { + _searchFullMigrated = true; + } else { + _searchFull = true; + } + } break; + + case mtpc_messages_messagesSlice: { + auto &d = result.c_messages_messagesSlice(); + if (_searchRequest != 0) { + // Don't apply cached data! + session().data().processUsers(d.vusers()); + session().data().processChats(d.vchats()); + } + auto &msgs = d.vmessages().v; + const auto someAdded = _inner->searchReceived(msgs, inject, type, d.vcount().v); + const auto nextRate = d.vnext_rate(); + const auto rateUpdated = nextRate && (nextRate->v != _searchNextRate); + const auto finished = (type == SearchRequestType::FromStart || type == SearchRequestType::FromOffset) + ? !rateUpdated + : !someAdded; + if (rateUpdated) { + _searchNextRate = nextRate->v; + } + if (finished) { if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { _searchFullMigrated = true; } else { _searchFull = true; } - } break; + } + } break; - case mtpc_messages_messagesSlice: { - auto &d = result.c_messages_messagesSlice(); - if (_searchRequest != 0) { - // Don't apply cached data! - session().data().processUsers(d.vusers()); - session().data().processChats(d.vchats()); - } - auto &msgs = d.vmessages().v; - const auto someAdded = _inner->searchReceived(msgs, inject, type, d.vcount().v); - const auto nextRate = d.vnext_rate(); - const auto rateUpdated = nextRate && (nextRate->v != _searchNextRate); - const auto finished = (type == SearchRequestType::FromStart || type == SearchRequestType::FromOffset) - ? !rateUpdated - : !someAdded; - if (rateUpdated) { - _searchNextRate = nextRate->v; - } - if (finished) { - if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { - _searchFullMigrated = true; - } else { - _searchFull = true; - } - } - } break; - - case mtpc_messages_channelMessages: { - auto &d = result.c_messages_channelMessages(); - if (const auto peer = _searchInChat.peer()) { - if (const auto channel = peer->asChannel()) { - channel->ptsReceived(d.vpts().v); - } else { - LOG(("API Error: " - "received messages.channelMessages when no channel " - "was passed! (Widget::searchReceived)")); - } + case mtpc_messages_channelMessages: { + auto &d = result.c_messages_channelMessages(); + if (const auto peer = _searchInChat.peer()) { + if (const auto channel = peer->asChannel()) { + channel->ptsReceived(d.vpts().v); } else { LOG(("API Error: " "received messages.channelMessages when no channel " "was passed! (Widget::searchReceived)")); } - if (_searchRequest != 0) { - // Don't apply cached data! - session().data().processUsers(d.vusers()); - session().data().processChats(d.vchats()); - } - auto &msgs = d.vmessages().v; - if (!_inner->searchReceived(msgs, inject, type, d.vcount().v)) { - if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { - _searchFullMigrated = true; - } else { - _searchFull = true; - } - } - } break; - - case mtpc_messages_messagesNotModified: { - LOG(("API Error: received messages.messagesNotModified! (Widget::searchReceived)")); + } else { + LOG(("API Error: " + "received messages.channelMessages when no channel " + "was passed! (Widget::searchReceived)")); + } + if (_searchRequest != 0) { + // Don't apply cached data! + session().data().processUsers(d.vusers()); + session().data().processChats(d.vchats()); + } + auto &msgs = d.vmessages().v; + if (!_inner->searchReceived(msgs, inject, type, d.vcount().v)) { if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { _searchFullMigrated = true; } else { _searchFull = true; } - } break; } + } break; - _searchRequest = 0; - onListScroll(); - update(); + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (Widget::searchReceived)")); + if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { + _searchFullMigrated = true; + } else { + _searchFull = true; + } + } break; } + + _searchRequest = 0; + onListScroll(); + update(); } void Widget::peerSearchReceived( diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 80a17e2be..bbe4cbd93 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -2480,7 +2480,7 @@ void History::setFakeChatListMessage() { if (const auto chat = peer->asChat()) { // In chats we try to take the item before the 'last', which // is the empty-displayed migration message. - session().api().requestFakeChatListMessage(this); + owner().histories().requestFakeChatListMessage(this); } else if (const auto from = migrateFrom()) { // In megagroups we just try to use // the message from the original group. diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 15deb8f4f..78c364636 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1716,9 +1716,8 @@ void HistoryWidget::showHistory( session().data().stopPlayingVideoFiles(); clearReplyReturns(); - clearAllLoadRequests(); - if (_history) { + clearAllLoadRequests(); if (Ui::InFocusChain(_list)) { // Removing focus from list clears selected and updates top bar. setFocus(); @@ -1917,19 +1916,34 @@ void HistoryWidget::showHistory( } void HistoryWidget::clearDelayedShowAt() { + Expects(_history != nullptr); + _delayedShowAtMsgId = -1; if (_delayedShowAtRequest) { - MTP::cancel(_delayedShowAtRequest); + _history->owner().histories().cancelRequest( + _history, + _delayedShowAtRequest); _delayedShowAtRequest = 0; } } void HistoryWidget::clearAllLoadRequests() { + Expects(_history != nullptr); + + auto &histories = _history->owner().histories(); clearDelayedShowAt(); - if (_firstLoadRequest) MTP::cancel(_firstLoadRequest); - if (_preloadRequest) MTP::cancel(_preloadRequest); - if (_preloadDownRequest) MTP::cancel(_preloadDownRequest); - _preloadRequest = _preloadDownRequest = _firstLoadRequest = 0; + if (_firstLoadRequest) { + histories.cancelRequest(_history, _firstLoadRequest); + _firstLoadRequest = 0; + } + if (_preloadRequest) { + histories.cancelRequest(_history, _preloadRequest); + _preloadRequest = 0; + } + if (_preloadDownRequest) { + histories.cancelRequest(_history, _preloadDownRequest); + _preloadDownRequest = 0; + } } void HistoryWidget::updateFieldSubmitSettings() { @@ -2330,8 +2344,10 @@ void HistoryWidget::unreadCountUpdated() { } } -bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId) { - if (MTP::isDefaultHandledError(error)) return false; +bool HistoryWidget::messagesFailed(const RPCError &error, int requestId) { + if (MTP::isDefaultHandledError(error)) { + return false; + } if (error.type() == qstr("CHANNEL_PRIVATE") || error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA") @@ -2356,15 +2372,20 @@ bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId return true; } -void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages &messages, mtpRequestId requestId) { - if (!_history) { - _preloadRequest = _preloadDownRequest = _firstLoadRequest = _delayedShowAtRequest = 0; - return; - } +void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages &messages, int requestId) { + Expects(_history != nullptr); bool toMigrated = (peer == _peer->migrateFrom()); if (peer != _peer && !toMigrated) { - _preloadRequest = _preloadDownRequest = _firstLoadRequest = _delayedShowAtRequest = 0; + if (_preloadRequest == requestId) { + _preloadRequest = 0; + } else if (_preloadDownRequest == requestId) { + _preloadDownRequest = 0; + } else if (_firstLoadRequest == requestId) { + _firstLoadRequest = 0; + } else if (_delayedShowAtRequest == requestId) { + _delayedShowAtRequest = 0; + } return; } @@ -2456,10 +2477,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages _delayedShowAtRequest = 0; _history->getReadyFor(_delayedShowAtMsgId); if (_history->isEmpty()) { - if (_preloadRequest) MTP::cancel(_preloadRequest); - if (_preloadDownRequest) MTP::cancel(_preloadDownRequest); - if (_firstLoadRequest) MTP::cancel(_firstLoadRequest); - _preloadRequest = _preloadDownRequest = 0; + clearAllLoadRequests(); _firstLoadRequest = -1; // hack - don't updateListSize yet addMessagesToFront(peer, *histList); _firstLoadRequest = 0; @@ -2520,14 +2538,14 @@ void HistoryWidget::firstLoadMessages() { return; } - auto from = _peer; + auto from = _history; auto offsetId = 0; auto offset = 0; auto loadCount = kMessagesPerPage; if (_showAtMsgId == ShowAtUnreadMsgId) { if (const auto around = _migrated ? _migrated->loadAroundId() : 0) { _history->getReadyFor(_showAtMsgId); - from = _migrated->peer; + from = _migrated; offset = -loadCount / 2; offsetId = around; } else if (const auto around = _history->loadAroundId()) { @@ -2547,7 +2565,7 @@ void HistoryWidget::firstLoadMessages() { } else if (_showAtMsgId < 0 && _history->isChannel()) { if (_showAtMsgId < 0 && -_showAtMsgId < ServerMaxMsgId && _migrated) { _history->getReadyFor(_showAtMsgId); - from = _migrated->peer; + from = _migrated; offset = -loadCount / 2; offsetId = -_showAtMsgId; } else if (_showAtMsgId == SwitchAtTopMsgId) { @@ -2560,18 +2578,27 @@ void HistoryWidget::firstLoadMessages() { auto minId = 0; auto historyHash = 0; - _firstLoadRequest = MTP::send( - MTPmessages_GetHistory( - from->input, + const auto history = from; + const auto type = Data::Histories::RequestType::History; + auto &histories = history->owner().histories(); + _firstLoadRequest = histories.sendRequest(history, type, [=](Fn finish) { + return history->session().api().request(MTPmessages_GetHistory( + history->peer->input, MTP_int(offsetId), MTP_int(offsetDate), MTP_int(offset), MTP_int(loadCount), MTP_int(maxId), MTP_int(minId), - MTP_int(historyHash)), - rpcDone(&HistoryWidget::messagesReceived, from), - rpcFail(&HistoryWidget::messagesFailed)); + MTP_int(historyHash) + )).done([=](const MTPmessages_Messages &result) { + messagesReceived(history->peer, result, _firstLoadRequest); + finish(); + }).fail([=](const RPCError &error) { + messagesFailed(error, _firstLoadRequest); + finish(); + }).send(); + }); } void HistoryWidget::loadMessages() { @@ -2602,18 +2629,27 @@ void HistoryWidget::loadMessages() { auto minId = 0; auto historyHash = 0; - _preloadRequest = MTP::send( - MTPmessages_GetHistory( - from->peer->input, + const auto history = from; + const auto type = Data::Histories::RequestType::History; + auto &histories = history->owner().histories(); + _preloadRequest = histories.sendRequest(history, type, [=](Fn finish) { + return history->session().api().request(MTPmessages_GetHistory( + history->peer->input, MTP_int(offsetId), MTP_int(offsetDate), MTP_int(addOffset), MTP_int(loadCount), MTP_int(maxId), MTP_int(minId), - MTP_int(historyHash)), - rpcDone(&HistoryWidget::messagesReceived, from->peer.get()), - rpcFail(&HistoryWidget::messagesFailed)); + MTP_int(historyHash) + )).done([=](const MTPmessages_Messages &result) { + messagesReceived(history->peer, result, _preloadRequest); + finish(); + }).fail([=](const RPCError &error) { + messagesFailed(error, _preloadRequest); + finish(); + }).send(); + }); } void HistoryWidget::loadMessagesDown() { @@ -2644,18 +2680,27 @@ void HistoryWidget::loadMessagesDown() { auto minId = 0; auto historyHash = 0; - _preloadDownRequest = MTP::send( - MTPmessages_GetHistory( - from->peer->input, + const auto history = from; + const auto type = Data::Histories::RequestType::History; + auto &histories = history->owner().histories(); + _preloadDownRequest = histories.sendRequest(history, type, [=](Fn finish) { + return history->session().api().request(MTPmessages_GetHistory( + history->peer->input, MTP_int(offsetId + 1), MTP_int(offsetDate), MTP_int(addOffset), MTP_int(loadCount), MTP_int(maxId), MTP_int(minId), - MTP_int(historyHash)), - rpcDone(&HistoryWidget::messagesReceived, from->peer.get()), - rpcFail(&HistoryWidget::messagesFailed)); + MTP_int(historyHash) + )).done([=](const MTPmessages_Messages &result) { + messagesReceived(history->peer, result, _preloadDownRequest); + finish(); + }).fail([=](const RPCError &error) { + messagesFailed(error, _preloadDownRequest); + finish(); + }).send(); + }); } void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { @@ -2667,13 +2712,13 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { clearDelayedShowAt(); _delayedShowAtMsgId = showAtMsgId; - auto from = _peer; + auto from = _history; auto offsetId = 0; auto offset = 0; auto loadCount = kMessagesPerPage; if (_delayedShowAtMsgId == ShowAtUnreadMsgId) { if (const auto around = _migrated ? _migrated->loadAroundId() : 0) { - from = _migrated->peer; + from = _migrated; offset = -loadCount / 2; offsetId = around; } else if (const auto around = _history->loadAroundId()) { @@ -2689,7 +2734,7 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { offsetId = _delayedShowAtMsgId; } else if (_delayedShowAtMsgId < 0 && _history->isChannel()) { if (_delayedShowAtMsgId < 0 && -_delayedShowAtMsgId < ServerMaxMsgId && _migrated) { - from = _migrated->peer; + from = _migrated; offset = -loadCount / 2; offsetId = -_delayedShowAtMsgId; } @@ -2699,18 +2744,27 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { auto minId = 0; auto historyHash = 0; - _delayedShowAtRequest = MTP::send( - MTPmessages_GetHistory( - from->input, + const auto history = from; + const auto type = Data::Histories::RequestType::History; + auto &histories = history->owner().histories(); + _delayedShowAtRequest = histories.sendRequest(history, type, [=](Fn finish) { + return history->session().api().request(MTPmessages_GetHistory( + history->peer->input, MTP_int(offsetId), MTP_int(offsetDate), MTP_int(offset), MTP_int(loadCount), MTP_int(maxId), MTP_int(minId), - MTP_int(historyHash)), - rpcDone(&HistoryWidget::messagesReceived, from), - rpcFail(&HistoryWidget::messagesFailed)); + MTP_int(historyHash) + )).done([=](const MTPmessages_Messages &result) { + messagesReceived(history->peer, result, _delayedShowAtRequest); + finish(); + }).fail([=](const RPCError &error) { + messagesFailed(error, _delayedShowAtRequest); + finish(); + }).send(); + }); } void HistoryWidget::onScroll() { @@ -2884,7 +2938,8 @@ void HistoryWidget::saveEditMsg() { sendFlags |= MTPmessages_EditMessage::Flag::f_entities; } - _saveEditMsgRequestId = MTP::send( + const auto history = _history; + _saveEditMsgRequestId = history->session().api().request( MTPmessages_EditMessage( MTP_flags(sendFlags), _history->peer->input, @@ -2893,9 +2948,12 @@ void HistoryWidget::saveEditMsg() { MTPInputMedia(), MTPReplyMarkup(), sentEntities, - MTP_int(0)), // schedule_date - rpcDone(&HistoryWidget::saveEditMsgDone, _history), - rpcFail(&HistoryWidget::saveEditMsgFail, _history)); + MTP_int(0) + )).done([=](const MTPUpdates &result, mtpRequestId requestId) { + saveEditMsgDone(history, result, requestId); + }).fail([=](const RPCError &error, mtpRequestId requestId) { + saveEditMsgFail(history, error, requestId); + }).send(); } void HistoryWidget::saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req) { @@ -2913,7 +2971,9 @@ void HistoryWidget::saveEditMsgDone(History *history, const MTPUpdates &updates, } bool HistoryWidget::saveEditMsgFail(History *history, const RPCError &error, mtpRequestId req) { - if (MTP::isDefaultHandledError(error)) return false; + if (MTP::isDefaultHandledError(error)) { + return false; + } if (req == _saveEditMsgRequestId) { _saveEditMsgRequestId = 0; } @@ -3733,7 +3793,9 @@ void HistoryWidget::inlineBotResolveDone( } bool HistoryWidget::inlineBotResolveFail(QString name, const RPCError &error) { - if (MTP::isDefaultHandledError(error)) return false; + if (MTP::isDefaultHandledError(error)) { + return false; + } _inlineBotResolveRequestId = 0; // Notify::inlineBotRequesting(false); @@ -6085,7 +6147,7 @@ void HistoryWidget::cancelEdit() { applyDraft(); if (_saveEditMsgRequestId) { - MTP::cancel(_saveEditMsgRequestId); + _history->session().api().request(_saveEditMsgRequestId).cancel(); _saveEditMsgRequestId = 0; } @@ -6970,5 +7032,6 @@ void HistoryWidget::synteticScrollToY(int y) { } HistoryWidget::~HistoryWidget() { + clearAllLoadRequests(); setTabbedPanel(nullptr); } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index f8b720792..f672559e1 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -105,7 +105,6 @@ public: void start(); - void messagesReceived(PeerData *peer, const MTPmessages_Messages &messages, mtpRequestId requestId); void historyLoaded(); void windowShown(); @@ -569,7 +568,8 @@ private: void checkPreview(); void requestPreview(); void gotPreview(QString links, const MTPMessageMedia &media, mtpRequestId req); - bool messagesFailed(const RPCError &error, mtpRequestId requestId); + void messagesReceived(PeerData *peer, const MTPmessages_Messages &messages, int requestId); + bool messagesFailed(const RPCError &error, int requestId); void addMessagesToFront(PeerData *peer, const QVector &messages); void addMessagesToBack(PeerData *peer, const QVector &messages); @@ -681,12 +681,12 @@ private: bool _canSendMessages = false; MsgId _showAtMsgId = ShowAtUnreadMsgId; - mtpRequestId _firstLoadRequest = 0; - mtpRequestId _preloadRequest = 0; - mtpRequestId _preloadDownRequest = 0; + int _firstLoadRequest = 0; // Not real mtpRequestId. + int _preloadRequest = 0; // Not real mtpRequestId. + int _preloadDownRequest = 0; // Not real mtpRequestId. MsgId _delayedShowAtMsgId = -1; - mtpRequestId _delayedShowAtRequest = 0; + int _delayedShowAtRequest = 0; // Not real mtpRequestId. object_ptr _topBar; object_ptr _scroll; From ec7a2dce2f2e0507bab7e6fb5b84bbfb651c5425 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 16:57:06 +0400 Subject: [PATCH 071/140] Search through Histories. --- Telegram/SourceFiles/data/data_histories.cpp | 15 +- Telegram/SourceFiles/data/data_histories.h | 5 +- .../data/data_search_controller.cpp | 5 +- .../SourceFiles/dialogs/dialogs_widget.cpp | 237 +++++++++++------- Telegram/SourceFiles/dialogs/dialogs_widget.h | 2 + .../SourceFiles/history/history_widget.cpp | 14 +- 6 files changed, 168 insertions(+), 110 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 3a5df6411..169615fdc 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -549,7 +549,8 @@ int Histories::sendRequest( Expects(type != RequestType::None); auto &state = _states[history]; - const auto id = ++state.autoincrement; + const auto id = ++_requestAutoincrement; + _historyByRequest.emplace(id, history); if (type == RequestType::History && postponeHistoryRequest(state)) { state.postponed.emplace( id, @@ -593,19 +594,24 @@ void Histories::checkPostponed(not_null history, int id) { finishSentRequest(history, state, id); } -void Histories::cancelRequest(not_null history, int id) { - const auto state = lookup(history); +void Histories::cancelRequest(int id) { + const auto history = _historyByRequest.take(id); + if (!history) { + return; + } + const auto state = lookup(*history); if (!state) { return; } state->postponed.remove(id); - finishSentRequest(history, state, id); + finishSentRequest(*history, state, id); } void Histories::finishSentRequest( not_null history, not_null state, int id) { + _historyByRequest.remove(id); state->sent.remove(id); if (!state->postponed.empty() && !postponeHistoryRequest(*state)) { for (auto &[id, postponed] : base::take(state->postponed)) { @@ -626,6 +632,7 @@ void Histories::finishSentRequest( history, std::move(i->second)); Assert(ok); + _dialogRequests.erase(i); state->postponedRequestEntry = false; } checkEmptyState(history); diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index bcc068229..21e4efa5e 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -72,7 +72,7 @@ public: not_null history, RequestType type, Fn finish)> generator); - void cancelRequest(not_null history, int id); + void cancelRequest(int id); private: struct PostponedHistoryRequest { @@ -88,7 +88,6 @@ private: base::flat_map sent; crl::time readWhen = 0; MsgId readTill = 0; - int autoincrement = 0; bool postponedRequestEntry = false; }; @@ -112,6 +111,8 @@ private: std::unordered_map> _map; base::flat_map, State> _states; + base::flat_map> _historyByRequest; + int _requestAutoincrement = 0; base::Timer _readRequestsTimer; base::flat_set> _dialogFolderRequests; diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp index 6ae67371f..08541b13d 100644 --- a/Telegram/SourceFiles/data/data_search_controller.cpp +++ b/Telegram/SourceFiles/data/data_search_controller.cpp @@ -369,7 +369,7 @@ void SearchController::requestMore( return; } auto &histories = _session->data().histories(); - const auto type = Histories::RequestType::History; + const auto type = ::Data::Histories::RequestType::History; const auto history = _session->data().history(listData->peer); auto requestId = histories.sendRequest(history, type, [=](Fn finish) { return _api.request( @@ -392,8 +392,7 @@ void SearchController::requestMore( }).send(); }); listData->requests.emplace(key, [=] { - auto &histories = _session->data().histories(); - histories.cancelRequest(history, requestId); + _session->data().histories().cancelRequest(requestId); }); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index ab1c85d3e..211f01b0d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_user.h" #include "data/data_folder.h" +#include "data/data_histories.h" #include "facades.h" #include "app.h" #include "styles/style_dialogs.h" @@ -392,6 +393,7 @@ void Widget::fullSearchRefreshOn(rpl::producer<> events) { _searchQueries.clear(); _searchQuery = QString(); _scroll->scrollToY(0); + cancelSearchRequest(); onSearchMessages(); }, lifetime()); } @@ -736,7 +738,7 @@ bool Widget::onSearchMessages(bool searchCache) { auto result = false; auto q = _filter->getLastText().trimmed(); if (q.isEmpty() && !_searchFromUser) { - MTP::cancel(base::take(_searchRequest)); + cancelSearchRequest(); MTP::cancel(base::take(_peerSearchRequest)); return true; } @@ -753,7 +755,7 @@ bool Widget::onSearchMessages(bool searchCache) { _searchQueryFrom = _searchFromUser; _searchNextRate = 0; _searchFull = _searchFullMigrated = false; - MTP::cancel(base::take(_searchRequest)); + cancelSearchRequest(); searchReceived( _searchInChat ? SearchRequestType::PeerFromStart @@ -767,19 +769,23 @@ bool Widget::onSearchMessages(bool searchCache) { _searchQueryFrom = _searchFromUser; _searchNextRate = 0; _searchFull = _searchFullMigrated = false; - MTP::cancel(base::take(_searchRequest)); + cancelSearchRequest(); if (const auto peer = _searchInChat.peer()) { - const auto flags = _searchQueryFrom - ? MTP_flags(MTPmessages_Search::Flag::f_from_id) - : MTP_flags(0); - _searchRequest = MTP::send( - MTPmessages_Search( + auto &histories = session().data().histories(); + const auto type = Data::Histories::RequestType::History; + const auto history = session().data().history(peer); + _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn finish) { + const auto type = SearchRequestType::PeerFromStart; + const auto flags = _searchQueryFrom + ? MTP_flags(MTPmessages_Search::Flag::f_from_id) + : MTP_flags(0); + _searchRequest = session().api().request(MTPmessages_Search( flags, peer->input, MTP_string(_searchQuery), - _searchQueryFrom + (_searchQueryFrom ? _searchQueryFrom->inputUser - : MTP_inputUserEmpty(), + : MTP_inputUserEmpty()), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), @@ -788,9 +794,17 @@ bool Widget::onSearchMessages(bool searchCache) { MTP_int(SearchPerPage), MTP_int(0), MTP_int(0), - MTP_int(0)), - rpcDone(&Widget::searchReceived, SearchRequestType::PeerFromStart), - rpcFail(&Widget::searchFailed, SearchRequestType::PeerFromStart)); + MTP_int(0) + )).done([=](const MTPmessages_Messages &result) { + searchReceived(type, result, _searchRequest); + finish(); + }).fail([=](const RPCError &error) { + searchFailed(type, error, _searchRequest); + finish(); + }).send(); + _searchQueries.insert(_searchRequest, _searchQuery); + return _searchRequest; + }); //} else if (const auto feed = _searchInChat.feed()) { // #feed // _searchRequest = MTP::send( // MTPchannels_SearchFeed( @@ -802,6 +816,7 @@ bool Widget::onSearchMessages(bool searchCache) { // MTP_int(SearchPerPage)), // rpcDone(&Widget::searchReceived, SearchRequestType::FromStart), // rpcFail(&Widget::searchFailed, SearchRequestType::FromStart)); + // _searchQueries.insert(_searchRequest, _searchQuery); } else { const auto flags = session().settings().skipArchiveInSearch() ? MTPmessages_SearchGlobal::Flag::f_folder_id @@ -818,8 +833,8 @@ bool Widget::onSearchMessages(bool searchCache) { MTP_int(SearchPerPage)), rpcDone(&Widget::searchReceived, SearchRequestType::FromStart), rpcFail(&Widget::searchFailed, SearchRequestType::FromStart)); + _searchQueries.insert(_searchRequest, _searchQuery); } - _searchQueries.insert(_searchRequest, _searchQuery); } const auto query = Api::ConvertPeerSearchQuery(q); if (searchForPeersRequired(query)) { @@ -906,93 +921,122 @@ void Widget::searchMessages( } void Widget::onSearchMore() { - if (!_searchRequest) { - if (!_searchFull) { - auto offsetPeer = _inner->lastSearchPeer(); - auto offsetId = _inner->lastSearchId(); - if (const auto peer = _searchInChat.peer()) { + if (_searchRequest || _searchInHistoryRequest) { + return; + } + if (!_searchFull) { + auto offsetPeer = _inner->lastSearchPeer(); + auto offsetId = _inner->lastSearchId(); + if (const auto peer = _searchInChat.peer()) { + auto &histories = session().data().histories(); + const auto type = Data::Histories::RequestType::History; + const auto history = session().data().history(peer); + _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn finish) { + const auto type = offsetId + ? SearchRequestType::PeerFromOffset + : SearchRequestType::PeerFromStart; auto flags = _searchQueryFrom ? MTP_flags(MTPmessages_Search::Flag::f_from_id) : MTP_flags(0); - _searchRequest = MTP::send( - MTPmessages_Search( - flags, - peer->input, - MTP_string(_searchQuery), - _searchQueryFrom - ? _searchQueryFrom->inputUser - : MTP_inputUserEmpty(), - MTP_inputMessagesFilterEmpty(), - MTP_int(0), - MTP_int(0), - MTP_int(offsetId), - MTP_int(0), - MTP_int(SearchPerPage), - MTP_int(0), - MTP_int(0), - MTP_int(0)), - rpcDone(&Widget::searchReceived, offsetId ? SearchRequestType::PeerFromOffset : SearchRequestType::PeerFromStart), - rpcFail(&Widget::searchFailed, offsetId ? SearchRequestType::PeerFromOffset : SearchRequestType::PeerFromStart)); - //} else if (const auto feed = _searchInChat.feed()) { // #feed - // _searchRequest = MTP::send( - // MTPchannels_SearchFeed( - // MTP_int(feed->id()), - // MTP_string(_searchQuery), - // MTP_int(offsetDate), - // offsetPeer - // ? offsetPeer->input - // : MTP_inputPeerEmpty(), - // MTP_int(offsetId), - // MTP_int(SearchPerPage)), - // rpcDone(&Widget::searchReceived, offsetId ? SearchRequestType::FromOffset : SearchRequestType::FromStart), - // rpcFail(&Widget::searchFailed, offsetId ? SearchRequestType::FromOffset : SearchRequestType::FromStart)); - } else { - const auto flags = session().settings().skipArchiveInSearch() - ? MTPmessages_SearchGlobal::Flag::f_folder_id - : MTPmessages_SearchGlobal::Flag(0); - const auto folderId = 0; - _searchRequest = MTP::send( - MTPmessages_SearchGlobal( - MTP_flags(flags), - MTP_int(folderId), - MTP_string(_searchQuery), - MTP_int(_searchNextRate), - offsetPeer - ? offsetPeer->input - : MTP_inputPeerEmpty(), - MTP_int(offsetId), - MTP_int(SearchPerPage)), - rpcDone(&Widget::searchReceived, offsetId ? SearchRequestType::FromOffset : SearchRequestType::FromStart), - rpcFail(&Widget::searchFailed, offsetId ? SearchRequestType::FromOffset : SearchRequestType::FromStart)); - } - if (!offsetId) { - _searchQueries.insert(_searchRequest, _searchQuery); - } - } else if (_searchInMigrated && !_searchFullMigrated) { - auto offsetMigratedId = _inner->lastSearchMigratedId(); - auto flags = _searchQueryFrom - ? MTP_flags(MTPmessages_Search::Flag::f_from_id) - : MTP_flags(0); - _searchRequest = MTP::send( - MTPmessages_Search( + _searchRequest = session().api().request(MTPmessages_Search( flags, - _searchInMigrated->peer->input, + peer->input, MTP_string(_searchQuery), - _searchQueryFrom + (_searchQueryFrom ? _searchQueryFrom->inputUser - : MTP_inputUserEmpty(), + : MTP_inputUserEmpty()), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), - MTP_int(offsetMigratedId), + MTP_int(offsetId), MTP_int(0), MTP_int(SearchPerPage), MTP_int(0), MTP_int(0), - MTP_int(0)), - rpcDone(&Widget::searchReceived, offsetMigratedId ? SearchRequestType::MigratedFromOffset : SearchRequestType::MigratedFromStart), - rpcFail(&Widget::searchFailed, offsetMigratedId ? SearchRequestType::MigratedFromOffset : SearchRequestType::MigratedFromStart)); + MTP_int(0) + )).done([=](const MTPmessages_Messages &result) { + searchReceived(type, result, _searchRequest); + }).fail([=](const RPCError &error) { + searchFailed(type, error, _searchRequest); + }).send(); + if (!offsetId) { + _searchQueries.insert(_searchRequest, _searchQuery); + } + return _searchRequest; + }); + //} else if (const auto feed = _searchInChat.feed()) { // #feed + // _searchRequest = MTP::send( + // MTPchannels_SearchFeed( + // MTP_int(feed->id()), + // MTP_string(_searchQuery), + // MTP_int(offsetDate), + // offsetPeer + // ? offsetPeer->input + // : MTP_inputPeerEmpty(), + // MTP_int(offsetId), + // MTP_int(SearchPerPage)), + // rpcDone(&Widget::searchReceived, offsetId ? SearchRequestType::FromOffset : SearchRequestType::FromStart), + // rpcFail(&Widget::searchFailed, offsetId ? SearchRequestType::FromOffset : SearchRequestType::FromStart)); + // if (!offsetId) { + // _searchQueries.insert(_searchRequest, _searchQuery); + // } + } else { + const auto flags = session().settings().skipArchiveInSearch() + ? MTPmessages_SearchGlobal::Flag::f_folder_id + : MTPmessages_SearchGlobal::Flag(0); + const auto folderId = 0; + _searchRequest = MTP::send( + MTPmessages_SearchGlobal( + MTP_flags(flags), + MTP_int(folderId), + MTP_string(_searchQuery), + MTP_int(_searchNextRate), + offsetPeer + ? offsetPeer->input + : MTP_inputPeerEmpty(), + MTP_int(offsetId), + MTP_int(SearchPerPage)), + rpcDone(&Widget::searchReceived, offsetId ? SearchRequestType::FromOffset : SearchRequestType::FromStart), + rpcFail(&Widget::searchFailed, offsetId ? SearchRequestType::FromOffset : SearchRequestType::FromStart)); + if (!offsetId) { + _searchQueries.insert(_searchRequest, _searchQuery); + } } + } else if (_searchInMigrated && !_searchFullMigrated) { + auto offsetMigratedId = _inner->lastSearchMigratedId(); + auto &histories = session().data().histories(); + const auto type = Data::Histories::RequestType::History; + const auto history = _searchInMigrated; + _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn finish) { + const auto type = offsetMigratedId + ? SearchRequestType::MigratedFromOffset + : SearchRequestType::MigratedFromStart; + const auto flags = _searchQueryFrom + ? MTP_flags(MTPmessages_Search::Flag::f_from_id) + : MTP_flags(0); + _searchRequest = session().api().request(MTPmessages_Search( + flags, + _searchInMigrated->peer->input, + MTP_string(_searchQuery), + (_searchQueryFrom + ? _searchQueryFrom->inputUser + : MTP_inputUserEmpty()), + MTP_inputMessagesFilterEmpty(), + MTP_int(0), + MTP_int(0), + MTP_int(offsetMigratedId), + MTP_int(0), + MTP_int(SearchPerPage), + MTP_int(0), + MTP_int(0), + MTP_int(0) + )).done([=](const MTPmessages_Messages &result) { + searchReceived(type, result, _searchRequest); + }).fail([=](const RPCError &error) { + searchFailed(type, error, _searchRequest); + }).send(); + return _searchRequest; + }); } } @@ -1319,7 +1363,7 @@ void Widget::clearSearchCache() { _searchQueries.clear(); _searchQuery = QString(); _searchQueryFrom = nullptr; - MTP::cancel(base::take(_searchRequest)); + cancelSearchRequest(); } void Widget::showJumpToDate() { @@ -1615,12 +1659,20 @@ void Widget::removeDialog(Key key) { _inner->removeDialog(key); } -bool Widget::onCancelSearch() { - bool clearing = !_filter->getLastText().isEmpty(); +void Widget::cancelSearchRequest() { if (_searchRequest) { MTP::cancel(_searchRequest); _searchRequest = 0; } + if (_searchInHistoryRequest) { + session().data().histories().cancelRequest(_searchInHistoryRequest); + _searchInHistoryRequest = 0; + } +} + +bool Widget::onCancelSearch() { + bool clearing = !_filter->getLastText().isEmpty(); + cancelSearchRequest(); if (_searchInChat && !clearing) { if (Adaptive::OneColumn()) { if (const auto peer = _searchInChat.peer()) { @@ -1642,10 +1694,7 @@ bool Widget::onCancelSearch() { } void Widget::onCancelSearchInChat() { - if (_searchRequest) { - MTP::cancel(_searchRequest); - _searchRequest = 0; - } + cancelSearchRequest(); if (_searchInChat) { if (Adaptive::OneColumn() && !App::main()->selectingPeer()) { if (const auto peer = _searchInChat.peer()) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 42799d2dd..710f32c66 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -136,6 +136,7 @@ private: const MTPcontacts_Found &result, mtpRequestId requestId); void escape(); + void cancelSearchRequest(); void setupSupportMode(); void setupConnectingWidget(); @@ -219,6 +220,7 @@ private: int32 _searchNextRate = 0; bool _searchFull = false; bool _searchFullMigrated = false; + int _searchInHistoryRequest = 0; // Not real mtpRequestId. mtpRequestId _searchRequest = 0; QMap _searchCache; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 78c364636..043476576 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1920,9 +1920,7 @@ void HistoryWidget::clearDelayedShowAt() { _delayedShowAtMsgId = -1; if (_delayedShowAtRequest) { - _history->owner().histories().cancelRequest( - _history, - _delayedShowAtRequest); + _history->owner().histories().cancelRequest(_delayedShowAtRequest); _delayedShowAtRequest = 0; } } @@ -1933,15 +1931,15 @@ void HistoryWidget::clearAllLoadRequests() { auto &histories = _history->owner().histories(); clearDelayedShowAt(); if (_firstLoadRequest) { - histories.cancelRequest(_history, _firstLoadRequest); + histories.cancelRequest(_firstLoadRequest); _firstLoadRequest = 0; } if (_preloadRequest) { - histories.cancelRequest(_history, _preloadRequest); + histories.cancelRequest(_preloadRequest); _preloadRequest = 0; } if (_preloadDownRequest) { - histories.cancelRequest(_history, _preloadDownRequest); + histories.cancelRequest(_preloadDownRequest); _preloadDownRequest = 0; } } @@ -7032,6 +7030,8 @@ void HistoryWidget::synteticScrollToY(int y) { } HistoryWidget::~HistoryWidget() { - clearAllLoadRequests(); + if (_history) { + clearAllLoadRequests(); + } setTabbedPanel(nullptr); } From f9d02740aa3c6a66e52d339ae4b008beb91c05f4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 17:03:03 +0400 Subject: [PATCH 072/140] Don't send same read request more than once. --- Telegram/SourceFiles/data/data_histories.cpp | 11 ++++++++++- Telegram/SourceFiles/data/data_histories.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 169615fdc..f2326b313 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -154,6 +154,11 @@ void Histories::readInboxTill( return; } auto &state = _states[history]; + if (state.readTillSent >= tillId) { + return; + } else { + state.readTillSent = 0; + } const auto wasReadTill = state.readTill; state.readTill = tillId; if (force || !stillUnread || !*stillUnread) { @@ -401,6 +406,7 @@ void Histories::sendReadRequests() { void Histories::sendReadRequest(not_null history, State &state) { const auto tillId = state.readTill; state.readWhen = kReadRequestSent; + state.readTillSent = tillId; sendRequest(history, RequestType::ReadInbox, [=](Fn finish) { const auto finished = [=] { const auto state = lookup(history); @@ -409,6 +415,8 @@ void Histories::sendReadRequest(not_null history, State &state) { if (history->unreadCountRefreshNeeded(tillId)) { requestDialogEntry(history); + } else if (state->readTillSent == tillId) { + state->readTillSent = 0; } if (state->readWhen == kReadRequestSent) { state->readWhen = 0; @@ -448,7 +456,8 @@ void Histories::checkEmptyState(not_null history) { return state.postponed.empty() && !state.postponedRequestEntry && state.sent.empty() - && (state.readTill == 0); + && (state.readTill == 0) + && (state.readTillSent == 0); }; const auto i = _states.find(history); if (i != end(_states) && empty(i->second)) { diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index 21e4efa5e..a6973d639 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -88,6 +88,7 @@ private: base::flat_map sent; crl::time readWhen = 0; MsgId readTill = 0; + MsgId readTillSent = 0; bool postponedRequestEntry = false; }; From 7f77db8c7f562e6179a200692e86de5ebd2b4e48 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 17:36:49 +0400 Subject: [PATCH 073/140] Fix request cancel in Histories. --- Telegram/SourceFiles/data/data_histories.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index f2326b313..25a9dfe35 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -621,7 +621,11 @@ void Histories::finishSentRequest( not_null state, int id) { _historyByRequest.remove(id); - state->sent.remove(id); + const auto i = state->sent.find(id); + if (i != end(state->sent)) { + session().api().request(i->second.id).cancel(); + state->sent.erase(i); + } if (!state->postponed.empty() && !postponeHistoryRequest(*state)) { for (auto &[id, postponed] : base::take(state->postponed)) { const auto requestId = postponed.generator([=] { From 28032e5e0d9f84ab665d7ce1fa9f4eebc48d1077 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 18:02:13 +0400 Subject: [PATCH 074/140] Fix jump to a specific message. --- Telegram/SourceFiles/data/data_histories.cpp | 7 ++- .../SourceFiles/history/history_widget.cpp | 49 +++++++++++++------ Telegram/SourceFiles/history/history_widget.h | 3 +- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 25a9dfe35..449f900ee 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -597,10 +597,9 @@ int Histories::sendRequest( } void Histories::checkPostponed(not_null history, int id) { - const auto state = lookup(history); - Assert(state != nullptr); - - finishSentRequest(history, state, id); + if (const auto state = lookup(history)) { + finishSentRequest(history, state, id); + } } void Histories::cancelRequest(int id) { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 043476576..715f9fdf9 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1916,9 +1916,13 @@ void HistoryWidget::showHistory( } void HistoryWidget::clearDelayedShowAt() { + _delayedShowAtMsgId = -1; + clearDelayedShowAtRequest(); +} + +void HistoryWidget::clearDelayedShowAtRequest() { Expects(_history != nullptr); - _delayedShowAtMsgId = -1; if (_delayedShowAtRequest) { _history->owner().histories().cancelRequest(_delayedShowAtRequest); _delayedShowAtRequest = 0; @@ -1929,7 +1933,7 @@ void HistoryWidget::clearAllLoadRequests() { Expects(_history != nullptr); auto &histories = _history->owner().histories(); - clearDelayedShowAt(); + clearDelayedShowAtRequest(); if (_firstLoadRequest) { histories.cancelRequest(_firstLoadRequest); _firstLoadRequest = 0; @@ -2472,19 +2476,19 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages _migrated->clear(History::ClearType::Unload); } - _delayedShowAtRequest = 0; + clearAllLoadRequests(); + _firstLoadRequest = -1; // hack - don't updateListSize yet _history->getReadyFor(_delayedShowAtMsgId); if (_history->isEmpty()) { - clearAllLoadRequests(); - _firstLoadRequest = -1; // hack - don't updateListSize yet addMessagesToFront(peer, *histList); - _firstLoadRequest = 0; - if (_history->loadedAtTop() - && _history->isEmpty() - && count > 0) { - firstLoadMessages(); - return; - } + } + _firstLoadRequest = 0; + + if (_history->loadedAtTop() + && _history->isEmpty() + && count > 0) { + firstLoadMessages(); + return; } while (_replyReturn) { if (_replyReturn->history() == _history @@ -2498,6 +2502,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages } } + _delayedShowAtRequest = 0; setMsgId(_delayedShowAtMsgId); historyLoaded(); } @@ -2521,6 +2526,7 @@ bool HistoryWidget::doWeReadMentions() const { && _list && _historyInited && !_firstLoadRequest + && !_delayedShowAtRequest && !_a_show.animating() && App::wnd()->doWeMarkAsRead(); } @@ -2707,7 +2713,7 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { return; } - clearDelayedShowAt(); + clearAllLoadRequests(); _delayedShowAtMsgId = showAtMsgId; auto from = _history; @@ -2799,7 +2805,11 @@ void HistoryWidget::visibleAreaUpdated() { } void HistoryWidget::preloadHistoryIfNeeded() { - if (_firstLoadRequest || _scroll->isHidden() || !_peer) { + if (_firstLoadRequest + || _delayedShowAtRequest + || _scroll->isHidden() + || !_peer + || !_historyInited) { return; } @@ -2818,7 +2828,11 @@ void HistoryWidget::preloadHistoryIfNeeded() { } void HistoryWidget::preloadHistoryByScroll() { - if (_firstLoadRequest || _scroll->isHidden() || !_peer) { + if (_firstLoadRequest + || _delayedShowAtRequest + || _scroll->isHidden() + || !_peer + || !_historyInited) { return; } @@ -2834,7 +2848,10 @@ void HistoryWidget::preloadHistoryByScroll() { } void HistoryWidget::checkReplyReturns() { - if (_firstLoadRequest || _scroll->isHidden() || !_peer) { + if (_firstLoadRequest + || _scroll->isHidden() + || !_peer + || !_historyInited) { return; } auto scrollTop = _scroll->scrollTop(); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index f672559e1..3b6ccafa2 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -213,8 +213,9 @@ public: void applyDraft( FieldHistoryAction fieldHistoryAction = FieldHistoryAction::Clear); void showHistory(const PeerId &peer, MsgId showAtMsgId, bool reload = false); - void clearDelayedShowAt(); void clearAllLoadRequests(); + void clearDelayedShowAtRequest(); + void clearDelayedShowAt(); void saveFieldToHistoryLocalDraft(); void applyCloudDraft(History *history); From d83cf0e5603408561cc315f5594d596653830dba Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 18:02:43 +0400 Subject: [PATCH 075/140] Fix build with Clang. --- Telegram/SourceFiles/data/data_histories.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 449f900ee..c35c24105 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -627,7 +627,7 @@ void Histories::finishSentRequest( } if (!state->postponed.empty() && !postponeHistoryRequest(*state)) { for (auto &[id, postponed] : base::take(state->postponed)) { - const auto requestId = postponed.generator([=] { + const auto requestId = postponed.generator([=, id=id] { checkPostponed(history, id); }); state->sent.emplace(id, SentRequest{ From c207a7c0d3fad14143f73bcb32fb7b343fe0c6ad Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 19:05:57 +0400 Subject: [PATCH 076/140] Fix simultaneous read history requests. --- Telegram/SourceFiles/data/data_histories.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index c35c24105..bcd3cdfe9 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -388,7 +388,7 @@ void Histories::sendReadRequests() { const auto now = crl::now(); auto next = std::optional(); for (auto &[history, state] : _states) { - if (!state.readTill) { + if (!state.readTill || state.readWhen == kReadRequestSent) { continue; } else if (state.readWhen <= now) { sendReadRequest(history, state); From 0743e71ab6b928d2ee5bae1aed991849b1e2b291 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Feb 2020 21:33:32 +0400 Subject: [PATCH 077/140] Beta version 1.9.15. - Mark new messages as read while scrolling down through them. - Bug fixes and other minor improvements. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 6 +++--- Telegram/build/version | 10 +++++----- changelog.txt | 5 +++++ 6 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 63028397b..a80961461 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.15.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 345ef0176..adf6bd3f8 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,14,0 - PRODUCTVERSION 1,9,14,0 + FILEVERSION 1,9,15,0 + PRODUCTVERSION 1,9,15,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.14.0" + VALUE "FileVersion", "1.9.15.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.14.0" + VALUE "ProductVersion", "1.9.15.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index fd3ccd378..d809b940b 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,14,0 - PRODUCTVERSION 1,9,14,0 + FILEVERSION 1,9,15,0 + PRODUCTVERSION 1,9,15,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.14.0" + VALUE "FileVersion", "1.9.15.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.14.0" + VALUE "ProductVersion", "1.9.15.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 79766c78c..1f5568a25 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009014; -constexpr auto AppVersionStr = "1.9.14"; -constexpr auto AppBetaVersion = false; +constexpr auto AppVersion = 1009015; +constexpr auto AppVersionStr = "1.9.15"; +constexpr auto AppBetaVersion = true; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 1ce9141a3..0d5c2af02 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009014 +AppVersion 1009015 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.14 -AppVersionStr 1.9.14 -BetaChannel 0 +AppVersionStrSmall 1.9.15 +AppVersionStr 1.9.15 +BetaChannel 1 AlphaVersion 0 -AppVersionOriginal 1.9.14 +AppVersionOriginal 1.9.15.beta diff --git a/changelog.txt b/changelog.txt index 0d4d83a23..a47e41097 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,8 @@ +1.9.15 (21.02.20) + +- Mark new messages as read while scrolling down through them. +- Bug fixes and other minor improvements. + 1.9.14 (17.02.20) - Bug fixes and other minor improvements. From 50bf4dad36eed56839c85f1cf3558c5c2e672d13 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 22 Feb 2020 14:47:30 +0400 Subject: [PATCH 078/140] Add local changelog for 1.9.15. --- Telegram/SourceFiles/core/changelogs.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Telegram/SourceFiles/core/changelogs.cpp b/Telegram/SourceFiles/core/changelogs.cpp index c2613ca46..bd338c5a4 100644 --- a/Telegram/SourceFiles/core/changelogs.cpp +++ b/Telegram/SourceFiles/core/changelogs.cpp @@ -55,6 +55,13 @@ std::map BetaLogs() { "\xE2\x80\xA2 Rotate photos and videos in the media viewer " "using the rotate button in the bottom right corner.\n" + }, + { + 1009015, + "\xE2\x80\xA2 Mark new messages as read " + "while scrolling down through them.\n" + + "\xE2\x80\xA2 Bug fixes and other minor improvements." } }; }; From 496faef0b3f47d77848b5b11016f487a82af6ba6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 23 Feb 2020 11:54:15 +0400 Subject: [PATCH 079/140] Fix crashes in fast simultaneous readings. Fixes #7264, fixes #7259. --- Telegram/SourceFiles/data/data_histories.cpp | 85 ++++++++++---------- Telegram/SourceFiles/data/data_histories.h | 7 +- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index bcd3cdfe9..8eb8284f5 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -21,7 +21,6 @@ namespace Data { namespace { constexpr auto kReadRequestTimeout = 3 * crl::time(1000); -constexpr auto kReadRequestSent = std::numeric_limits::max(); } // namespace @@ -135,15 +134,23 @@ void Histories::readInboxTill( bool force) { Expects(IsServerMsgId(tillId) || (!tillId && !force)); - if (!history->readInboxTillNeedsRequest(tillId) && !force) { + const auto needsRequest = history->readInboxTillNeedsRequest(tillId); + if (!needsRequest && !force) { return; } else if (!history->trackUnreadMessages()) { return; - } else if (!force) { - const auto maybeState = lookup(history); - if (maybeState && maybeState->readTill >= tillId) { - return; + } + const auto maybeState = lookup(history); + if (maybeState && maybeState->sentReadTill >= tillId) { + return; + } else if (maybeState && maybeState->willReadTill >= tillId) { + if (force) { + sendPendingReadInbox(history); } + return; + } else if (!needsRequest + && (!maybeState || !maybeState->willReadTill)) { + return; } const auto stillUnread = history->countStillUnreadLocal(tillId); if (!force @@ -153,22 +160,16 @@ void Histories::readInboxTill( history->setInboxReadTill(tillId); return; } - auto &state = _states[history]; - if (state.readTillSent >= tillId) { - return; - } else { - state.readTillSent = 0; - } - const auto wasReadTill = state.readTill; - state.readTill = tillId; + auto &state = maybeState ? *maybeState : _states[history]; + state.willReadTill = tillId; if (force || !stillUnread || !*stillUnread) { - state.readWhen = 0; + state.willReadWhen = 0; sendReadRequests(); if (!stillUnread) { return; } - } else if (!wasReadTill) { - state.readWhen = crl::now() + kReadRequestTimeout; + } else if (!state.willReadWhen) { + state.willReadWhen = crl::now() + kReadRequestTimeout; if (!_readRequestsTimer.isActive()) { _readRequestsTimer.callOnce(kReadRequestTimeout); } @@ -304,6 +305,12 @@ void Histories::dialogEntryApplied(not_null history) { callback(); } } + if (const auto state = lookup(history)) { + if (state->sentReadTill && state->sentReadDone) { + history->setInboxReadTill(base::take(state->sentReadTill)); + checkEmptyState(history); + } + } } void Histories::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) { @@ -372,10 +379,8 @@ void Histories::requestFakeChatListMessage( void Histories::sendPendingReadInbox(not_null history) { if (const auto state = lookup(history)) { - if (state->readTill - && state->readWhen - && state->readWhen != kReadRequestSent) { - state->readWhen = 0; + if (state->willReadTill && state->willReadWhen) { + state->willReadWhen = 0; sendReadRequests(); } } @@ -388,12 +393,12 @@ void Histories::sendReadRequests() { const auto now = crl::now(); auto next = std::optional(); for (auto &[history, state] : _states) { - if (!state.readTill || state.readWhen == kReadRequestSent) { + if (!state.willReadTill) { continue; - } else if (state.readWhen <= now) { + } else if (state.willReadWhen <= now) { sendReadRequest(history, state); - } else if (!next || *next > state.readWhen) { - next = state.readWhen; + } else if (!next || *next > state.willReadWhen) { + next = state.willReadWhen; } } if (next.has_value()) { @@ -404,28 +409,26 @@ void Histories::sendReadRequests() { } void Histories::sendReadRequest(not_null history, State &state) { - const auto tillId = state.readTill; - state.readWhen = kReadRequestSent; - state.readTillSent = tillId; + Expects(state.willReadTill > state.sentReadTill); + + const auto tillId = state.sentReadTill = base::take(state.willReadTill); + state.willReadWhen = 0; + state.sentReadDone = false; sendRequest(history, RequestType::ReadInbox, [=](Fn finish) { const auto finished = [=] { const auto state = lookup(history); Assert(state != nullptr); - Assert(state->readTill >= tillId); + Assert(state->sentReadTill >= tillId); - if (history->unreadCountRefreshNeeded(tillId)) { - requestDialogEntry(history); - } else if (state->readTillSent == tillId) { - state->readTillSent = 0; - } - if (state->readWhen == kReadRequestSent) { - state->readWhen = 0; - if (state->readTill == tillId) { - state->readTill = 0; + if (state->sentReadTill == tillId) { + state->sentReadDone = true; + if (history->unreadCountRefreshNeeded(tillId)) { + requestDialogEntry(history); } else { - sendReadRequests(); + state->sentReadTill = 0; } } + sendReadRequests(); finish(); }; if (const auto channel = history->peer->asChannel()) { @@ -456,8 +459,8 @@ void Histories::checkEmptyState(not_null history) { return state.postponed.empty() && !state.postponedRequestEntry && state.sent.empty() - && (state.readTill == 0) - && (state.readTillSent == 0); + && (state.willReadTill == 0) + && (state.sentReadTill == 0); }; const auto i = _states.find(history); if (i != end(_states) && empty(i->second)) { diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index a6973d639..6cd6e9db5 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -86,9 +86,10 @@ private: struct State { base::flat_map postponed; base::flat_map sent; - crl::time readWhen = 0; - MsgId readTill = 0; - MsgId readTillSent = 0; + MsgId willReadTill = 0; + MsgId sentReadTill = 0; + crl::time willReadWhen = 0; + bool sentReadDone = false; bool postponedRequestEntry = false; }; From f7144a55e2297768910366105cab56b2fad34a9e Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 23 Feb 2020 12:48:39 +0400 Subject: [PATCH 080/140] Always clear history notifications when marking as read. --- Telegram/SourceFiles/data/data_histories.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 8eb8284f5..b9bcb750d 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_folder.h" #include "main/main_session.h" +#include "window/notifications_manager.h" #include "history/history.h" #include "history/history_item.h" #include "history/view/history_view_element.h" @@ -134,6 +135,8 @@ void Histories::readInboxTill( bool force) { Expects(IsServerMsgId(tillId) || (!tillId && !force)); + history->session().notifications().clearIncomingFromHistory(history); + const auto needsRequest = history->readInboxTillNeedsRequest(tillId); if (!needsRequest && !force) { return; From a84c7e0b066d10c8a3e74eb1703290b356a86ae7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 23 Feb 2020 12:56:33 +0400 Subject: [PATCH 081/140] Don't apply entry from dialogs if postponed. --- Telegram/SourceFiles/data/data_histories.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index b9bcb750d..aaff7acca 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -297,6 +297,10 @@ void Histories::sendDialogRequests() { } void Histories::dialogEntryApplied(not_null history) { + const auto state = lookup(history); + if (state->postponedRequestEntry) { + return; + } history->dialogEntryApplied(); if (const auto callbacks = _dialogRequestsPending.take(history)) { for (const auto &callback : *callbacks) { @@ -308,11 +312,9 @@ void Histories::dialogEntryApplied(not_null history) { callback(); } } - if (const auto state = lookup(history)) { - if (state->sentReadTill && state->sentReadDone) { - history->setInboxReadTill(base::take(state->sentReadTill)); - checkEmptyState(history); - } + if (state && state->sentReadTill && state->sentReadDone) { + history->setInboxReadTill(base::take(state->sentReadTill)); + checkEmptyState(history); } } From e2f037537fcd523342c244ef3fedf809ceedd16d Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 23 Feb 2020 12:58:45 +0400 Subject: [PATCH 082/140] Beta version 1.9.16. - Bug fixes and other minor improvements. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 4 ++-- Telegram/build/version | 8 ++++---- changelog.txt | 6 +++++- 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index a80961461..a52637355 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.16.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index adf6bd3f8..fcf1da23d 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,15,0 - PRODUCTVERSION 1,9,15,0 + FILEVERSION 1,9,16,0 + PRODUCTVERSION 1,9,16,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.15.0" + VALUE "FileVersion", "1.9.16.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.15.0" + VALUE "ProductVersion", "1.9.16.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index d809b940b..628a74f5f 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,15,0 - PRODUCTVERSION 1,9,15,0 + FILEVERSION 1,9,16,0 + PRODUCTVERSION 1,9,16,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.15.0" + VALUE "FileVersion", "1.9.16.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.15.0" + VALUE "ProductVersion", "1.9.16.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 1f5568a25..f32867215 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009015; -constexpr auto AppVersionStr = "1.9.15"; +constexpr auto AppVersion = 1009016; +constexpr auto AppVersionStr = "1.9.16"; constexpr auto AppBetaVersion = true; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 0d5c2af02..01132d36c 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009015 +AppVersion 1009016 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.15 -AppVersionStr 1.9.15 +AppVersionStrSmall 1.9.16 +AppVersionStr 1.9.16 BetaChannel 1 AlphaVersion 0 -AppVersionOriginal 1.9.15.beta +AppVersionOriginal 1.9.16.beta diff --git a/changelog.txt b/changelog.txt index a47e41097..bf90681ee 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,8 @@ -1.9.15 (21.02.20) +1.9.16 beta (23.02.20) + +- Bug fixes and other minor improvements. + +1.9.15 beta (21.02.20) - Mark new messages as read while scrolling down through them. - Bug fixes and other minor improvements. From b84b1e71f7cab93d456e5f27c5ef21c5ec4abd0c Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 23 Feb 2020 15:13:23 +0400 Subject: [PATCH 083/140] Beta version 1.9.16: Crash fix. --- Telegram/SourceFiles/data/data_histories.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index aaff7acca..7b4aa17ca 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -298,7 +298,7 @@ void Histories::sendDialogRequests() { void Histories::dialogEntryApplied(not_null history) { const auto state = lookup(history); - if (state->postponedRequestEntry) { + if (state && state->postponedRequestEntry) { return; } history->dialogEntryApplied(); From 23d958e457adf4f1a3367c6267be50781fde5636 Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 22 Feb 2020 08:45:09 +0300 Subject: [PATCH 084/140] Save build place on Linux workflow * This tries to avoid "No space left on device" error. * Remove unneeded build cache directories. * Whenever possible, checkout only one Git commit. --- .github/workflows/linux.yml | 49 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 1f8e4abd0..3fd97931b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -122,9 +122,8 @@ jobs: run: | cd $LibrariesPath - git clone $GIT/xiph/opus + git clone -b v1.3 --depth=1 $GIT/xiph/opus cd opus - git checkout v1.3 ./autogen.sh ./configure make -j$(nproc) @@ -142,16 +141,20 @@ jobs: ./autogen.sh --enable-static make -j$(nproc) sudo make install + cd .. + rm -rf libva - name: Libvdpau. run: | cd $LibrariesPath - git clone https://gitlab.freedesktop.org/vdpau/libvdpau.git --depth=1 -b libvdpau-1.2 + git clone -b libvdpau-1.2 --depth=1 https://gitlab.freedesktop.org/vdpau/libvdpau.git cd libvdpau ./autogen.sh --enable-static make -j$(nproc) sudo make install + cd .. + rm -rf libvdpau - name: FFmpeg cache. id: cache-ffmpeg @@ -267,6 +270,8 @@ jobs: make -j$(nproc) sudo make install + cd .. + rm -rf ffmpeg - name: FFmpeg install. run: | cd $LibrariesPath @@ -293,18 +298,20 @@ jobs: ./configure make -j$(nproc) sudo make install + cd .. + rm -rf portaudio - name: OpenAL Soft. run: | cd $LibrariesPath - git clone $GIT/kcat/openal-soft.git - cd openal-soft - git checkout openal-soft-1.19.1 - cd build + git clone -b openal-soft-1.19.1 --depth=1 $GIT/kcat/openal-soft.git + cd openal-soft/build cmake -D LIBTYPE:STRING=STATIC .. make -j$(nproc) sudo make install + cd - + rm -rf openal-soft - name: OpenSSL cache. id: cache-openssl @@ -317,12 +324,14 @@ jobs: run: | cd $LibrariesPath - git clone $GIT/openssl/openssl openssl_$OPENSSL_VER - cd openssl_$OPENSSL_VER - git checkout OpenSSL_1_1_1-stable + git clone -b OpenSSL_${OPENSSL_VER}-stable --depth=1 \ + $GIT/openssl/openssl openssl_${OPENSSL_VER} + cd openssl_${OPENSSL_VER} ./config --prefix=$LibrariesPath/openssl-cache make -j$(nproc) sudo make install + cd .. + rm -rf openssl_${OPENSSL_VER} - name: OpenSSL install. run: | cd $LibrariesPath @@ -333,12 +342,13 @@ jobs: run: | cd $LibrariesPath - git clone $GIT/xkbcommon/libxkbcommon.git + git clone -b xkbcommon-0.8.4 --depth=1 $GIT/xkbcommon/libxkbcommon.git cd libxkbcommon - git checkout xkbcommon-0.8.4 ./autogen.sh make -j$(nproc) sudo make install + cd .. + rm -rf libxkbcommon - name: Qt 5.12.5 cache. id: cache-qt @@ -351,15 +361,12 @@ jobs: run: | cd $LibrariesPath - git clone git://code.qt.io/qt/qt5.git qt_$QT - cd qt_$QT + git clone -b v5.12.5 --depth=1 git://code.qt.io/qt/qt5.git qt_${QT} + cd qt_${QT} perl init-repository --module-subset=qtbase,qtimageformats,qtsvg - git checkout v5.12.5 - git submodule update qtbase - git submodule update qtimageformats - git submodule update qtsvg + git submodule update qtbase qtimageformats qtsvg cd qtbase - git apply ../../patches/qtbase_$QT.diff + git apply ../../patches/qtbase_${QT}.diff cd src/plugins/platforminputcontexts git clone $GIT/desktop-app/fcitx.git git clone $GIT/desktop-app/hime.git @@ -390,6 +397,8 @@ jobs: make -j$(nproc) sudo make install + cd .. + rm -rf qt_${QT} - name: Qt 5.12.5 install. run: | cd $LibrariesPath @@ -440,6 +449,8 @@ jobs: make -j$(nproc) dump_syms mv dump_syms $BreakpadCache/ + cd .. + rm -rf gyp breakpad - name: Breakpad install. run: | cd $LibrariesPath From f1c2d4fe3d3d75e79e85156e4364aac6ab6e56b1 Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 22 Feb 2020 09:09:35 +0300 Subject: [PATCH 085/140] Fix CMake version for snap build * With CMake 1.17.0-rc1, Python package is broken. --- snap/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 8e87c1b10..cb1d604ea 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -170,7 +170,7 @@ parts: cmake: source: "https://gitlab.kitware.com/cmake/cmake.git" source-depth: 1 - source-branch: master + source-tag: v3.16.4 source-type: git plugin: make override-build: | From 91a6632a1b70e100dc5c36905ca4315f896a427d Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 12:57:24 +0400 Subject: [PATCH 086/140] Fix state assertion in reading requets. --- Telegram/SourceFiles/data/data_histories.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 7b4aa17ca..b486639eb 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -423,7 +423,6 @@ void Histories::sendReadRequest(not_null history, State &state) { const auto finished = [=] { const auto state = lookup(history); Assert(state != nullptr); - Assert(state->sentReadTill >= tillId); if (state->sentReadTill == tillId) { state->sentReadDone = true; @@ -432,6 +431,8 @@ void Histories::sendReadRequest(not_null history, State &state) { } else { state->sentReadTill = 0; } + } else { + Assert(!state->sentReadTill || state->sentReadTill > tillId); } sendReadRequests(); finish(); From 6ded5b74d09acc1a38c09710cd68d049da95ddfc Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 13:13:48 +0400 Subject: [PATCH 087/140] Fix load requests cancel on history change. --- Telegram/SourceFiles/history/history_widget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 715f9fdf9..68bf3bed4 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1717,7 +1717,6 @@ void HistoryWidget::showHistory( clearReplyReturns(); if (_history) { - clearAllLoadRequests(); if (Ui::InFocusChain(_list)) { // Removing focus from list clears selected and updates top bar. setFocus(); @@ -1736,6 +1735,8 @@ void HistoryWidget::showHistory( destroyPinnedBar(); _membersDropdown.destroy(); _scrollToAnimation.stop(); + + clearAllLoadRequests(); _history = _migrated = nullptr; _list = nullptr; _peer = nullptr; From 91fb9917bc2743fbd7f98a59b7b0b24367c405e1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 13:14:29 +0400 Subject: [PATCH 088/140] Fix search in chat results loading. --- Telegram/SourceFiles/dialogs/dialogs_widget.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 211f01b0d..957baa25e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -797,9 +797,11 @@ bool Widget::onSearchMessages(bool searchCache) { MTP_int(0) )).done([=](const MTPmessages_Messages &result) { searchReceived(type, result, _searchRequest); + _searchInHistoryRequest = 0; finish(); }).fail([=](const RPCError &error) { searchFailed(type, error, _searchRequest); + _searchInHistoryRequest = 0; finish(); }).send(); _searchQueries.insert(_searchRequest, _searchQuery); @@ -956,8 +958,12 @@ void Widget::onSearchMore() { MTP_int(0) )).done([=](const MTPmessages_Messages &result) { searchReceived(type, result, _searchRequest); + _searchInHistoryRequest = 0; + finish(); }).fail([=](const RPCError &error) { searchFailed(type, error, _searchRequest); + _searchInHistoryRequest = 0; + finish(); }).send(); if (!offsetId) { _searchQueries.insert(_searchRequest, _searchQuery); @@ -1032,8 +1038,12 @@ void Widget::onSearchMore() { MTP_int(0) )).done([=](const MTPmessages_Messages &result) { searchReceived(type, result, _searchRequest); + _searchInHistoryRequest = 0; + finish(); }).fail([=](const RPCError &error) { searchFailed(type, error, _searchRequest); + _searchInHistoryRequest = 0; + finish(); }).send(); return _searchRequest; }); From f2ef10994089c746d084f89ed4ad185c64203339 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 14:40:02 +0400 Subject: [PATCH 089/140] Make sure we request pending dialog entries. --- Telegram/SourceFiles/data/data_histories.cpp | 5 +++++ Telegram/SourceFiles/data/data_histories.h | 1 + 2 files changed, 6 insertions(+) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index b486639eb..434a8b33f 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -238,6 +238,10 @@ void Histories::requestDialogEntry( if (!ok) { return; } + postponeRequestDialogEntries(); +} + +void Histories::postponeRequestDialogEntries() { if (_dialogRequestsPending.size() > 1) { return; } @@ -655,6 +659,7 @@ void Histories::finishSentRequest( Assert(ok); _dialogRequests.erase(i); state->postponedRequestEntry = false; + postponeRequestDialogEntries(); } checkEmptyState(history); } diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index 6cd6e9db5..61079634d 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -105,6 +105,7 @@ private: int id); [[nodiscard]] bool postponeHistoryRequest(const State &state) const; [[nodiscard]] bool postponeEntryRequest(const State &state) const; + void postponeRequestDialogEntries(); void sendDialogRequests(); void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs); From c3463dec63eb17081ddaba71910fbdd2c9026354 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 14:53:38 +0400 Subject: [PATCH 090/140] Force zero unread count if read till end. --- Telegram/SourceFiles/data/data_histories.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 434a8b33f..ee3da9421 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -135,6 +135,17 @@ void Histories::readInboxTill( bool force) { Expects(IsServerMsgId(tillId) || (!tillId && !force)); + const auto syncGuard = gsl::finally([&] { + if (history->unreadCount() > 0) { + if (const auto last = history->lastServerMessage()) { + if (last->id == tillId) { + history->setUnreadCount(0); + history->updateChatListEntry(); + } + } + } + }); + history->session().notifications().clearIncomingFromHistory(history); const auto needsRequest = history->readInboxTillNeedsRequest(tillId); From 8e222d35013040e6006441743bab9e2594109c80 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 15:31:28 +0400 Subject: [PATCH 091/140] Fix closing of fullscreen GIFs by click. --- Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 22c661655..df5e243b4 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -3688,7 +3688,7 @@ void OverlayWidget::updateOver(QPoint pos) { } else if (documentContentShown() && contentRect().contains(pos)) { if ((_doc->isVideoFile() || _doc->isVideoMessage()) && _streamed) { updateOverState(OverVideo); - } else if (!_doc->loaded()) { + } else if (!_streamed && !_doc->loaded()) { updateOverState(OverIcon); } else if (_over != OverNone) { updateOverState(OverNone); From 5937b24799fbe1d764225e521321e1ae02d71f92 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 16:35:13 +0400 Subject: [PATCH 092/140] Request dialog entry for unknown chat. --- Telegram/SourceFiles/history/history_widget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 68bf3bed4..0abfd9ddd 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1877,6 +1877,9 @@ void HistoryWidget::showHistory( } } } + if (!_history->folderKnown()) { + session().data().histories().requestDialogEntry(_history); + } if (_history->chatListUnreadMark()) { _history->owner().histories().changeDialogUnreadMark( _history, From c2f58d3ab5a59c2ddd432ff8f4a9d6dc3657db2c Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 17:48:23 +0400 Subject: [PATCH 093/140] Fix GIFs with alpha display. --- .../streaming/media_streaming_utility.cpp | 37 +++++++++++++------ .../media/streaming/media_streaming_utility.h | 1 + .../streaming/media_streaming_video_track.cpp | 9 ++++- .../streaming/media_streaming_video_track.h | 2 + .../SourceFiles/media/view/media_view_pip.cpp | 1 + 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp index 297475c95..44fe63b8a 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp @@ -212,6 +212,7 @@ void PaintFrameInner( QPainter &p, QRect to, const QImage &original, + bool alpha, int rotation) { const auto rotated = [](QRect rect, int rotation) { switch (rotation) { @@ -239,22 +240,32 @@ void PaintFrameInner( if (rotation) { p.rotate(rotation); } - p.drawImage(rotated(to, rotation), original); + const auto rect = rotated(to, rotation); + if (alpha) { + p.fillRect(rect, Qt::white); + } + p.drawImage(rect, original); } void PaintFrameContent( QPainter &p, const QImage &original, + bool alpha, int rotation, const FrameRequest &request) { - const auto full = request.outer; + const auto full = request.outer.isEmpty() + ? original.size() + : request.outer; + const auto size = request.resize.isEmpty() + ? original.size() + : request.resize; const auto to = QRect( - (full.width() - request.resize.width()) / 2, - (full.height() - request.resize.height()) / 2, - request.resize.width(), - request.resize.height()); + (full.width() - size.width()) / 2, + (full.height() - size.height()) / 2, + size.width(), + size.height()); PaintFrameOuter(p, to, full); - PaintFrameInner(p, to, original, rotation); + PaintFrameInner(p, to, original, alpha, rotation); } void ApplyFrameRounding(QImage &storage, const FrameRequest &request) { @@ -267,17 +278,21 @@ void ApplyFrameRounding(QImage &storage, const FrameRequest &request) { QImage PrepareByRequest( const QImage &original, + bool alpha, int rotation, const FrameRequest &request, QImage storage) { - Expects(!request.outer.isEmpty()); + Expects(!request.outer.isEmpty() || alpha); - if (!FFmpeg::GoodStorageForFrame(storage, request.outer)) { - storage = FFmpeg::CreateFrameStorage(request.outer); + const auto outer = request.outer.isEmpty() + ? original.size() + : request.outer; + if (!FFmpeg::GoodStorageForFrame(storage, outer)) { + storage = FFmpeg::CreateFrameStorage(outer); } QPainter p(&storage); - PaintFrameContent(p, original, rotation, request); + PaintFrameContent(p, original, alpha, rotation, request); p.end(); ApplyFrameRounding(storage, request); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_utility.h b/Telegram/SourceFiles/media/streaming/media_streaming_utility.h index 0b28584e2..3a39eb7f9 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_utility.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_utility.h @@ -60,6 +60,7 @@ struct Stream { QImage storage); [[nodiscard]] QImage PrepareByRequest( const QImage &original, + bool alpha, int rotation, const FrameRequest &request, QImage storage); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp index 1feaa6852..b2cc6ff00 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp @@ -361,6 +361,7 @@ void VideoTrackObject::presentFrameIfNeeded() { Expects(frame->position != kFinishedPosition); fillRequests(frame); + frame->alpha = (frame->decoded->format == AV_PIX_FMT_BGRA); frame->original = ConvertFrame( _stream, frame->decoded.get(), @@ -982,7 +983,8 @@ QImage VideoTrack::frame( unwrapped.updateFrameRequest(instance, useRequest); }); } - if (GoodForRequest(frame->original, _streamRotation, useRequest)) { + if (!frame->alpha + && GoodForRequest(frame->original, _streamRotation, useRequest)) { return frame->original; } else if (changed || none || i->second.image.isNull()) { const auto j = none @@ -1002,6 +1004,7 @@ QImage VideoTrack::frame( } j->second.image = PrepareByRequest( frame->original, + frame->alpha, _streamRotation, useRequest, std::move(j->second.image)); @@ -1025,7 +1028,8 @@ void VideoTrack::PrepareFrameByRequests( const auto end = frame->prepared.end(); for (auto i = begin; i != end; ++i) { auto &prepared = i->second; - if (!GoodForRequest(frame->original, rotation, prepared.request)) { + if (frame->alpha + || !GoodForRequest(frame->original, rotation, prepared.request)) { auto j = begin; for (; j != i; ++j) { if (j->second.request == prepared.request) { @@ -1036,6 +1040,7 @@ void VideoTrack::PrepareFrameByRequests( if (j == i) { prepared.image = PrepareByRequest( frame->original, + frame->alpha, rotation, prepared.request, std::move(prepared.image)); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h index 434e061ee..e92ddc566 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h @@ -83,6 +83,8 @@ private: crl::time display = kTimeUnknown; base::flat_map prepared; + + bool alpha = false; }; class Shared { diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp index cba1ecf92..639f47f37 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp @@ -1391,6 +1391,7 @@ QImage Pip::videoFrame(const FrameRequest &request) const { if (state == ThumbState::Cover) { _preparedCoverStorage = Streaming::PrepareByRequest( _instance.info().video.cover, + false, _instance.info().video.rotation, request, std::move(_preparedCoverStorage)); From 60612635ef844525ab683249963d86409e8f5490 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 18:54:16 +0400 Subject: [PATCH 094/140] Use QSaveFile to write sensitive settings / data. --- Telegram/SourceFiles/storage/localstorage.cpp | 99 ++++++++++--------- 1 file changed, 55 insertions(+), 44 deletions(-) diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 0ac58bec4..8d83f7bf1 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -41,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "facades.h" #include +#include #include #include @@ -118,10 +119,18 @@ inline constexpr auto is_flag_type(FileOption) { return true; }; bool keyAlreadyUsed(QString &name, FileOptions options = FileOption::User | FileOption::Safe) { name += '0'; - if (QFileInfo(name).exists()) return true; + if (QFileInfo(name).exists()) { + return true; + } if (options & (FileOption::Safe)) { name[name.size() - 1] = '1'; - return QFileInfo(name).exists(); + if (QFileInfo(name).exists()) { + return true; + } + name[name.size() - 1] = 's'; + if (QFileInfo(name).exists()) { + return true; + } } return false; } @@ -160,6 +169,8 @@ void clearKey(const FileKey &key, FileOptions options = FileOption::User | FileO if (options & FileOption::Safe) { name[name.size() - 1] = '1'; QFile::remove(name); + name[name.size() - 1] = 's'; + QFile::remove(name); } } @@ -240,10 +251,12 @@ struct EncryptedDescriptor { }; struct FileWriteDescriptor { - FileWriteDescriptor(const FileKey &key, FileOptions options = FileOption::User | FileOption::Safe) { + FileWriteDescriptor(const FileKey &key, FileOptions options = FileOption::User | FileOption::Safe) + : file((options & FileOption::Safe) ? (QFileDevice&)saveFile : plainFile) { init(toFilePart(key), options); } - FileWriteDescriptor(const QString &name, FileOptions options = FileOption::User | FileOption::Safe) { + FileWriteDescriptor(const QString &name, FileOptions options = FileOption::User | FileOption::Safe) + : file((options & FileOption::Safe) ? (QFileDevice&)saveFile : plainFile) { init(name, options); } void init(const QString &name, FileOptions options) { @@ -253,29 +266,13 @@ struct FileWriteDescriptor { if (!_working()) return; } - // detect order of read attempts and file version - QString toWrite[2]; - toWrite[0] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '0'; + const auto base = ((options & FileOption::User) ? _userBasePath : _basePath) + name; if (options & FileOption::Safe) { - toWrite[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; - QFileInfo toWrite0(toWrite[0]); - QFileInfo toWrite1(toWrite[1]); - if (toWrite0.exists()) { - if (toWrite1.exists()) { - QDateTime mod0 = toWrite0.lastModified(), mod1 = toWrite1.lastModified(); - if (mod0 > mod1) { - qSwap(toWrite[0], toWrite[1]); - } - } else { - qSwap(toWrite[0], toWrite[1]); - } - toDelete = toWrite[1]; - } else if (toWrite1.exists()) { - toDelete = toWrite[1]; - } + toDelete = base; + saveFile.setFileName(base + 's'); + } else { + plainFile.setFileName(base + '0'); } - - file.setFileName(toWrite[0]); if (file.open(QIODevice::WriteOnly)) { file.write(tdfMagic, tdfMagicLen); qint32 version = AppVersion; @@ -330,17 +327,21 @@ struct FileWriteDescriptor { md5.feed(&version, sizeof(version)); md5.feed(tdfMagic, tdfMagicLen); file.write((const char*)md5.result(), 0x10); - file.flush(); -#ifndef Q_OS_WIN - fsync(file.handle()); -#endif // Q_OS_WIN - file.close(); + + if (saveFile.isOpen()) { + saveFile.commit(); + } else { + plainFile.close(); + } if (!toDelete.isEmpty()) { - QFile::remove(toDelete); + QFile::remove(toDelete + '0'); + QFile::remove(toDelete + '1'); } } - QFile file; + QFile plainFile; + QSaveFile saveFile; + QFileDevice &file; QDataStream stream; QString toDelete; @@ -360,25 +361,35 @@ bool readFile(FileReadDescriptor &result, const QString &name, FileOptions optio if (!_working()) return false; } + const auto base = ((options & FileOption::User) ? _userBasePath : _basePath) + name; + // detect order of read attempts QString toTry[2]; - toTry[0] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '0'; if (options & FileOption::Safe) { - QFileInfo toTry0(toTry[0]); - if (toTry0.exists()) { - toTry[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; - QFileInfo toTry1(toTry[1]); - if (toTry1.exists()) { - QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified(); - if (mod0 < mod1) { - qSwap(toTry[0], toTry[1]); + const auto modern = base + 's'; + if (QFileInfo(modern).exists()) { + toTry[0] = modern; + } else { + // Legacy way. + toTry[0] = base + '0'; + QFileInfo toTry0(toTry[0]); + if (toTry0.exists()) { + toTry[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; + QFileInfo toTry1(toTry[1]); + if (toTry1.exists()) { + QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified(); + if (mod0 < mod1) { + qSwap(toTry[0], toTry[1]); + } + } else { + toTry[1] = QString(); } } else { - toTry[1] = QString(); + toTry[0][toTry[0].size() - 1] = '1'; } - } else { - toTry[0][toTry[0].size() - 1] = '1'; } + } else { + toTry[0] = base + '0'; } for (int32 i = 0; i < 2; ++i) { QString fname(toTry[i]); From da14588235039b1934cb55e3f3a2adb00efbc72a Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Tue, 11 Feb 2020 19:10:07 +0400 Subject: [PATCH 095/140] Enable native Wayland support --- .github/workflows/linux.yml | 25 ++++++++++++++++------ Telegram/SourceFiles/qt_static_plugins.cpp | 12 +++++++++++ Telegram/SourceFiles/stdafx.h | 6 +++--- docs/building-cmake.md | 17 ++++++++++----- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3fd97931b..e97ffe76f 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,7 +31,7 @@ jobs: CMAKE_VER: "3.16.3" UPLOAD_ARTIFACT: "false" ONLY_CACHE: "false" - MANUAL_CACHING: "5" + MANUAL_CACHING: "6" DOC_PATH: "docs/building-cmake.md" steps: @@ -55,13 +55,13 @@ jobs: sudo apt-get install software-properties-common -y && \ sudo apt-get install git libexif-dev liblzma-dev libz-dev libssl-dev \ libgtk2.0-dev libice-dev libsm-dev libicu-dev libdrm-dev dh-autoreconf \ - autoconf automake build-essential libass-dev libfreetype6-dev \ + autoconf automake build-essential libxml2-dev libass-dev libfreetype6-dev \ libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev \ libvorbis-dev libenchant-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \ libxcb-xfixes0-dev libxcb-keysyms1-dev libxcb-icccm4-dev libatspi2.0-dev \ libxcb-render-util0-dev libxcb-util0-dev libxcb-xkb-dev libxrender-dev \ - libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev bison \ - libx11-xcb-dev libffi-dev libncurses5-dev pkg-config texi2html yasm \ + libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev libegl1-mesa-dev \ + libx11-xcb-dev libffi-dev libncurses5-dev pkg-config texi2html bison yasm \ zlib1g-dev xutils-dev python-xcbgen chrpath gperf wget -y --force-yes && \ sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ sudo apt-get update && \ @@ -350,6 +350,18 @@ jobs: cd .. rm -rf libxkbcommon + - name: Libwayland. + run: | + cd $LibrariesPath + + git clone -b 1.16 https://gitlab.freedesktop.org/wayland/wayland + cd wayland + ./autogen.sh --enable-static --disable-documentation + make -j$(nproc) + sudo make install + cd .. + rm -rf wayland + - name: Qt 5.12.5 cache. id: cache-qt uses: actions/cache@v1 @@ -363,8 +375,8 @@ jobs: git clone -b v5.12.5 --depth=1 git://code.qt.io/qt/qt5.git qt_${QT} cd qt_${QT} - perl init-repository --module-subset=qtbase,qtimageformats,qtsvg - git submodule update qtbase qtimageformats qtsvg + perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg + git submodule update qtbase qtwayland qtimageformats qtsvg cd qtbase git apply ../../patches/qtbase_${QT}.diff cd src/plugins/platforminputcontexts @@ -386,7 +398,6 @@ jobs: -qt-xcb \ -system-freetype \ -fontconfig \ - -no-opengl \ -no-gtk \ -static \ -dbus-runtime \ diff --git a/Telegram/SourceFiles/qt_static_plugins.cpp b/Telegram/SourceFiles/qt_static_plugins.cpp index 8d3e03633..6cfb24559 100644 --- a/Telegram/SourceFiles/qt_static_plugins.cpp +++ b/Telegram/SourceFiles/qt_static_plugins.cpp @@ -20,7 +20,19 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin) Q_IMPORT_PLUGIN(QGenericEnginePlugin) #elif defined Q_OS_LINUX // Q_OS_WIN | Q_OS_MAC +Q_IMPORT_PLUGIN(ShmServerBufferPlugin) +Q_IMPORT_PLUGIN(DmaBufServerBufferPlugin) +Q_IMPORT_PLUGIN(DrmEglServerBufferPlugin) +Q_IMPORT_PLUGIN(QWaylandEglClientBufferPlugin) +Q_IMPORT_PLUGIN(QWaylandIviShellIntegrationPlugin) +Q_IMPORT_PLUGIN(QWaylandWlShellIntegrationPlugin) +Q_IMPORT_PLUGIN(QWaylandXdgShellV5IntegrationPlugin) +Q_IMPORT_PLUGIN(QWaylandXdgShellV6IntegrationPlugin) +Q_IMPORT_PLUGIN(QWaylandXdgShellIntegrationPlugin) +Q_IMPORT_PLUGIN(QWaylandBradientDecorationPlugin) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) +Q_IMPORT_PLUGIN(QWaylandIntegrationPlugin) +Q_IMPORT_PLUGIN(QWaylandEglPlatformIntegrationPlugin) Q_IMPORT_PLUGIN(QGenericEnginePlugin) Q_IMPORT_PLUGIN(QComposePlatformInputContextPlugin) Q_IMPORT_PLUGIN(QSvgIconPlugin) diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index ccba4b9bc..5e5d6ead2 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -78,10 +78,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #endif // OS_MAC_OLD -// Fix Google Breakpad build for Mac App Store version -#ifdef Q_OS_MAC +// Fix Google Breakpad build for Mac App Store and Linux version +#if defined Q_OS_MAC || defined Q_OS_LINUX #define __STDC_FORMAT_MACROS -#endif // Q_OS_MAC +#endif // Q_OS_MAC || Q_OS_LINUX #include #include diff --git a/docs/building-cmake.md b/docs/building-cmake.md index 32661ef66..af59c2d30 100644 --- a/docs/building-cmake.md +++ b/docs/building-cmake.md @@ -15,13 +15,13 @@ You will need GCC 8 installed. To install them and all the required dependencies sudo apt-get install software-properties-common -y && \ sudo apt-get install git libexif-dev liblzma-dev libz-dev libssl-dev \ libgtk2.0-dev libice-dev libsm-dev libicu-dev libdrm-dev dh-autoreconf \ - autoconf automake build-essential libass-dev libfreetype6-dev \ + autoconf automake build-essential libxml2-dev libass-dev libfreetype6-dev \ libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev \ libvorbis-dev libenchant-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \ libxcb-xfixes0-dev libxcb-keysyms1-dev libxcb-icccm4-dev libatspi2.0-dev \ libxcb-render-util0-dev libxcb-util0-dev libxcb-xkb-dev libxrender-dev \ - libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev bison \ - libx11-xcb-dev libffi-dev libncurses5-dev pkg-config texi2html yasm \ + libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev libegl1-mesa-dev \ + libx11-xcb-dev libffi-dev libncurses5-dev pkg-config texi2html bison yasm \ zlib1g-dev xutils-dev python-xcbgen chrpath gperf -y --force-yes && \ sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ sudo apt-get update && \ @@ -225,11 +225,19 @@ Go to ***BuildPath*** and run sudo make install cd .. + git clone -b 1.16 https://gitlab.freedesktop.org/wayland/wayland + cd wayland + ./autogen.sh --enable-static --disable-documentation + make -j$(nproc) + sudo make install + cd .. + git clone git://code.qt.io/qt/qt5.git qt_5_12_5 cd qt_5_12_5 - perl init-repository --module-subset=qtbase,qtimageformats,qtsvg + perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg git checkout v5.12.5 git submodule update qtbase + git submodule update qtwayland git submodule update qtimageformats git submodule update qtsvg cd qtbase @@ -254,7 +262,6 @@ Go to ***BuildPath*** and run -qt-xcb \ -system-freetype \ -fontconfig \ - -no-opengl \ -no-gtk \ -static \ -dbus-runtime \ From 2b2ac2e48fa7bd28d930af4b351ddcf5421284a8 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Feb 2020 16:48:02 +0300 Subject: [PATCH 096/140] Decreased packages installation time for Linux workflow. --- .github/workflows/linux.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index e97ffe76f..23d21c244 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -43,6 +43,18 @@ jobs: with: submodules: recursive + - name: Disable man for further package installs. + run: | + cfgFile="/etc/dpkg/dpkg.cfg.d/no_man" + sudo touch $cfgFile + p() { + sudo echo "path-exclude=/usr/share/$1/*" >> $cfgFile + } + + p man + p locale + p doc + - name: First set up. run: | cd .. From 1ca096e7ce71940c6201d55215b7e9eb430522b7 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Feb 2020 16:51:53 +0300 Subject: [PATCH 097/140] Added auto caching for Github CI. --- .github/workflows/linux.yml | 6 ++++++ .github/workflows/mac.yml | 6 ++++++ .github/workflows/win.yml | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 23d21c244..a083df13a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -33,6 +33,7 @@ jobs: ONLY_CACHE: "false" MANUAL_CACHING: "6" DOC_PATH: "docs/building-cmake.md" + AUTO_CACHING: "1" steps: - name: Get repository name. @@ -56,6 +57,7 @@ jobs: p doc - name: First set up. + shell: bash run: | cd .. mv $REPO_NAME temp @@ -87,6 +89,10 @@ jobs: gcc --version > CACHE_KEY.txt echo $MANUAL_CACHING >> CACHE_KEY.txt + if [ "$AUTO_CACHING" == "1" ]; then + thisFile=$REPO_NAME/.github/workflows/linux.yml + echo `md5sum $thisFile | cut -c -32` >> CACHE_KEY.txt + fi md5cache=$(md5sum CACHE_KEY.txt | cut -c -32) echo ::set-env name=CACHE_KEY::$md5cache diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 9aa29942c..9e29fb255 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -35,6 +35,8 @@ jobs: ONLY_CACHE: "false" MANUAL_CACHING: "2" DOC_PATH: "docs/building-xcode.md" + AUTO_CACHING: "1" + steps: - name: Get repository name. run: echo ::set-env name=REPO_NAME::${GITHUB_REPOSITORY##*/} @@ -61,6 +63,10 @@ jobs: echo $MIN_MAC >> CACHE_KEY.txt echo $PREFIX >> CACHE_KEY.txt echo $MANUAL_CACHING >> CACHE_KEY.txt + if [ "$AUTO_CACHING" == "1" ]; then + thisFile=$REPO_NAME/.github/workflows/mac.yml + echo `md5 -q $thisFile` >> CACHE_KEY.txt + fi echo ::set-env name=CACHE_KEY::`md5 -q CACHE_KEY.txt` echo ::add-path::$PWD/Libraries/depot_tools diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml index 815b9b68c..6118a4c86 100644 --- a/.github/workflows/win.yml +++ b/.github/workflows/win.yml @@ -30,6 +30,8 @@ jobs: ONLY_CACHE: "false" MANUAL_CACHING: "2" DOC_PATH: "docs/building-msvc.md" + AUTO_CACHING: "1" + steps: - name: Get repository name. shell: bash @@ -69,6 +71,10 @@ jobs: - name: Generate cache key. shell: bash run: | + if [ "$AUTO_CACHING" == "1" ]; then + thisFile=$REPO_NAME/.github/workflows/win.yml + echo `md5sum $thisFile | awk '{ print $1 }'` >> CACHE_KEY.txt + fi echo ::set-env name=CACHE_KEY::`md5sum CACHE_KEY.txt | awk '{ print $1 }'` - name: Choco installs. From fcb5292a4f3dd1acc49db7d9b5aaa266a3ef938e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 27 Jan 2020 14:05:00 +0300 Subject: [PATCH 098/140] Added external_hunspell to CMake build. --- .gitmodules | 3 +++ Telegram/CMakeLists.txt | 4 ++++ Telegram/ThirdParty/hunspell | 1 + cmake | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) create mode 160000 Telegram/ThirdParty/hunspell diff --git a/.gitmodules b/.gitmodules index b96eac1b5..9b02ad897 100644 --- a/.gitmodules +++ b/.gitmodules @@ -64,3 +64,6 @@ [submodule "Telegram/ThirdParty/libdbusmenu-qt"] path = Telegram/ThirdParty/libdbusmenu-qt url = https://github.com/desktop-app/libdbusmenu-qt.git +[submodule "Telegram/ThirdParty/hunspell"] + path = Telegram/ThirdParty/hunspell + url = https://github.com/hunspell/hunspell diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 98c142c95..5ed03a652 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -85,6 +85,10 @@ if (LINUX AND NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION) ) endif() +if (add_hunspell_library) + target_link_libraries(Telegram PRIVATE desktop-app::external_hunspell) +endif() + target_link_libraries(Telegram PRIVATE tdesktop::lib_mtproto diff --git a/Telegram/ThirdParty/hunspell b/Telegram/ThirdParty/hunspell new file mode 160000 index 000000000..8c773334f --- /dev/null +++ b/Telegram/ThirdParty/hunspell @@ -0,0 +1 @@ +Subproject commit 8c773334f314201b79bd8a6d40369ada9d7056d4 diff --git a/cmake b/cmake index 99278254e..6dd044ae1 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 99278254e352029ce36dc7b597b346b245d9860c +Subproject commit 6dd044ae163bc67a7f0f0dbf6a2fa28b633b5fdf From 4cc46f1ffa59d02df65a020f354da5ed373754ef Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2020 23:38:23 +0300 Subject: [PATCH 099/140] Added vector of enabled dictionaries to Main::Settings. --- Telegram/SourceFiles/main/main_settings.cpp | 17 +++++++++++++++++ Telegram/SourceFiles/main/main_settings.h | 13 +++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Telegram/SourceFiles/main/main_settings.cpp b/Telegram/SourceFiles/main/main_settings.cpp index 83975e9f5..95beb2bd9 100644 --- a/Telegram/SourceFiles/main/main_settings.cpp +++ b/Telegram/SourceFiles/main/main_settings.cpp @@ -118,6 +118,10 @@ QByteArray Settings::serialize() const { } stream << qint32(SerializePlaybackSpeed(_variables.videoPlaybackSpeed.current())); stream << _variables.videoPipGeometry; + stream << qint32(_variables.dictionariesEnabled.current().size()); + for (const auto i : _variables.dictionariesEnabled.current()) { + stream << quint64(i); + } } return result; } @@ -170,6 +174,7 @@ void Settings::constructFromSerialized(const QByteArray &serialized) { std::vector> mediaLastPlaybackPosition; qint32 videoPlaybackSpeed = SerializePlaybackSpeed(_variables.videoPlaybackSpeed.current()); QByteArray videoPipGeometry = _variables.videoPipGeometry; + std::vector dictionariesEnabled; stream >> versionTag; if (versionTag == kVersionTag) { @@ -296,6 +301,17 @@ void Settings::constructFromSerialized(const QByteArray &serialized) { if (!stream.atEnd()) { stream >> videoPipGeometry; } + if (!stream.atEnd()) { + auto count = qint32(0); + stream >> count; + if (stream.status() == QDataStream::Ok) { + for (auto i = 0; i != count; ++i) { + qint64 langId; + stream >> langId; + dictionariesEnabled.emplace_back(langId); + } + } + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Main::Settings::constructFromSerialized()")); @@ -385,6 +401,7 @@ void Settings::constructFromSerialized(const QByteArray &serialized) { _variables.mediaLastPlaybackPosition = std::move(mediaLastPlaybackPosition); _variables.videoPlaybackSpeed = DeserializePlaybackSpeed(videoPlaybackSpeed); _variables.videoPipGeometry = videoPipGeometry; + _variables.dictionariesEnabled = std::move(dictionariesEnabled); } void Settings::setSupportChatsTimeSlice(int slice) { diff --git a/Telegram/SourceFiles/main/main_settings.h b/Telegram/SourceFiles/main/main_settings.h index 020a8fc97..ba0d8b9c4 100644 --- a/Telegram/SourceFiles/main/main_settings.h +++ b/Telegram/SourceFiles/main/main_settings.h @@ -241,6 +241,18 @@ public: return _variables.spellcheckerEnabled.changes(); } + void setDictionariesEnabled(std::vector dictionaries) { + _variables.dictionariesEnabled = std::move(dictionaries); + } + + std::vector dictionariesEnabled() const { + return _variables.dictionariesEnabled.current(); + } + + rpl::producer> dictionariesEnabledChanges() const { + return _variables.dictionariesEnabled.changes(); + } + [[nodiscard]] float64 videoPlaybackSpeed() const { return _variables.videoPlaybackSpeed.current(); } @@ -298,6 +310,7 @@ private: std::vector> mediaLastPlaybackPosition; rpl::variable videoPlaybackSpeed = 1.; QByteArray videoPipGeometry; + rpl::variable> dictionariesEnabled; static constexpr auto kDefaultSupportChatsLimitSlice = 7 * 24 * 60 * 60; From 26a45885ffc4ec9be1d48324fe8f3191c9cecc4e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 31 Jan 2020 01:58:08 +0300 Subject: [PATCH 100/140] Added updating of spell highlighter when enabled languages are changed. --- .../chat_helpers/message_field.cpp | 19 +++++++++++++++++++ .../SourceFiles/chat_helpers/message_field.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 1b2d53083..142568285 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -283,15 +283,34 @@ void InitSpellchecker( if (!Platform::Spellchecker::IsAvailable()) { return; } + + Spellchecker::SetWorkingDirPath(Spellchecker::DictionariesPath()); + const auto s = Ui::CreateChild( field.get(), session->settings().spellcheckerEnabledValue()); + + const auto applyDictionaries = [=] { + crl::async([=] { + Platform::Spellchecker::UpdateLanguages( + session->settings().dictionariesEnabled()); + crl::on_main([=] { + s->checkCurrentText(); + }); + }); + }; + session->settings().dictionariesChanges( + ) | rpl::start_with_next(applyDictionaries, field->lifetime()); + Spellchecker::SetPhrases({ { { &ph::lng_spellchecker_add, tr::lng_spellchecker_add() }, { &ph::lng_spellchecker_remove, tr::lng_spellchecker_remove() }, { &ph::lng_spellchecker_ignore, tr::lng_spellchecker_ignore() }, } }); + field->setExtendedContextMenu(s->contextMenuCreated()); + + applyDictionaries(); #endif // TDESKTOP_DISABLE_SPELLCHECK } diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h index 8f95a9323..49c4ec8fb 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.h +++ b/Telegram/SourceFiles/chat_helpers/message_field.h @@ -12,7 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/qt_connection.h" #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "boxes/dictionaries_manager.h" #include "spellcheck/spelling_highlighter.h" +#include "spellcheck/spellcheck_value.h" #endif // TDESKTOP_DISABLE_SPELLCHECK #include From 65a7f2e7d8576ebae7329dc8bab8d2157eea2a71 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 02:50:29 +0300 Subject: [PATCH 101/140] Added dictionary management box. --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/langs/lang.strings | 2 + .../boxes/dictionaries_manager.cpp | 433 ++++++++++++++++++ .../SourceFiles/boxes/dictionaries_manager.h | 36 ++ Telegram/SourceFiles/settings/settings.style | 4 + 5 files changed, 477 insertions(+) create mode 100644 Telegram/SourceFiles/boxes/dictionaries_manager.cpp create mode 100644 Telegram/SourceFiles/boxes/dictionaries_manager.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 5ed03a652..6877ea1cb 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -189,6 +189,8 @@ PRIVATE boxes/connection_box.h boxes/create_poll_box.cpp boxes/create_poll_box.h + boxes/dictionaries_manager.cpp + boxes/dictionaries_manager.h boxes/download_path_box.cpp boxes/download_path_box.h boxes/edit_caption_box.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b15250cf7..ab50a4318 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -422,6 +422,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_spellchecker" = "Spell checker"; "lng_settings_system_spellchecker" = "Use system spell checker"; +"lng_settings_manage_dictionaries" = "Manage dictionaries"; +"lng_settings_manage_enabled_dictionary" = "Dictionary is enabled"; "lng_backgrounds_header" = "Choose your new chat background"; "lng_theme_sure_keep" = "Keep this theme?"; diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp new file mode 100644 index 000000000..8b6d062f9 --- /dev/null +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -0,0 +1,433 @@ +/* +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 +*/ +#include "boxes/dictionaries_manager.h" + +#ifndef TDESKTOP_DISABLE_SPELLCHECK + +#include "mtproto/dedicated_file_loader.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/wrap/fade_wrap.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/labels.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/effects/animations.h" +#include "ui/effects/radial_animation.h" +#include "lang/lang_keys.h" +#include "base/zlib_help.h" +#include "layout.h" +#include "core/application.h" +#include "main/main_account.h" +#include "main/main_session.h" +#include "mainwidget.h" +#include "app.h" +#include "styles/style_layers.h" +#include "styles/style_settings.h" +#include "styles/style_boxes.h" +#include "styles/style_chat_helpers.h" + +#include "chat_helpers/spellchecker_common.h" + +#include + +namespace Ui { +namespace { + +using Dictionaries = std::vector; + +struct Available { + int size = 0; + + inline bool operator<(const Available &other) const { + return size < other.size; + } + inline bool operator==(const Available &other) const { + return size == other.size; + } +}; +struct Ready { + inline bool operator<(const Ready &other) const { + return false; + } + inline bool operator==(const Ready &other) const { + return true; + } +}; +struct Active { + inline bool operator<(const Active &other) const { + return false; + } + inline bool operator==(const Active &other) const { + return true; + } +}; +using Loading = MTP::DedicatedLoader::Progress; +struct Failed { + inline bool operator<(const Failed &other) const { + return false; + } + inline bool operator==(const Failed &other) const { + return true; + } +}; +using SetState = base::variant< + Available, + Ready, + Active, + Loading, + Failed>; + +class Loader : public QObject { +public: + Loader(QObject *parent, int id); + + int id() const; + + rpl::producer state() const; + void destroy(); + +private: + void setImplementation(std::unique_ptr loader); + void unpack(const QString &path); + void finalize(const QString &path); + void fail(); + + int _id = 0; + int _size = 0; + rpl::variable _state; + + MTP::WeakInstance _mtproto; + std::unique_ptr _implementation; + +}; + +class Inner : public Ui::RpWidget { +public: + Inner(QWidget *parent, Dictionaries enabledDictionaries); + + Dictionaries enabledRows() const; + +private: + void setupContent(Dictionaries enabledDictionaries); + + Dictionaries _enabledRows; + +}; + +base::unique_qptr GlobalLoader; +rpl::event_stream GlobalLoaderValues; + +QLocale LocaleFromLangId(int langId) { + if (langId > 1000) { + const auto l = langId / 1000; + const auto lang = static_cast(l); + const auto country = static_cast(langId - l * 1000); + return QLocale(lang, country); + } + return QLocale(static_cast(langId)); +} + +void SetGlobalLoader(base::unique_qptr loader) { + GlobalLoader = std::move(loader); + GlobalLoaderValues.fire(GlobalLoader.get()); +} + +int GetDownloadSize(int id) { + const auto sets = Spellchecker::Dictionaries(); + return ranges::find(sets, id, &Spellchecker::Dict::id)->size; +} + +MTP::DedicatedLoader::Location GetDownloadLocation(int id) { + constexpr auto kUsername = "tdhbcfiles"; + const auto sets = Spellchecker::Dictionaries(); + const auto i = ranges::find(sets, id, &Spellchecker::Dict::id); + return MTP::DedicatedLoader::Location{ kUsername, i->postId }; +} + +SetState ComputeState(int id) { + // if (id == CurrentSetId()) { + // return Active(); + if (Spellchecker::DictionaryExists(id)) { + return Ready(); + } + return Available{ GetDownloadSize(id) }; +} + +QString StateDescription(const SetState &state) { + return state.match([](const Available &data) { + return tr::lng_emoji_set_download(tr::now, lt_size, formatSizeText(data.size)); + }, [](const Ready &data) -> QString { + return tr::lng_emoji_set_ready(tr::now); + }, [](const Active &data) -> QString { + return tr::lng_settings_manage_enabled_dictionary(tr::now); + // return tr::lng_emoji_set_active(tr::now); + }, [](const Loading &data) { + const auto percent = (data.size > 0) + ? snap((data.already * 100) / float64(data.size), 0., 100.) + : 0.; + return tr::lng_emoji_set_loading( + tr::now, + lt_percent, + QString::number(int(std::round(percent))) + '%', + lt_progress, + formatDownloadText(data.already, data.size)); + }, [](const Failed &data) { + return tr::lng_attach_failed(tr::now); + }); +} + +Loader::Loader(QObject *parent, int id) +: QObject(parent) +, _id(id) +, _size(GetDownloadSize(_id)) +, _state(Loading{ 0, _size }) +, _mtproto(Core::App().activeAccount().mtp()) { + const auto ready = [=](std::unique_ptr loader) { + if (loader) { + setImplementation(std::move(loader)); + } else { + fail(); + } + }; + const auto location = GetDownloadLocation(id); + const auto folder = Spellchecker::DictPathByLangId(id); + MTP::StartDedicatedLoader(&_mtproto, location, folder, ready); +} + +int Loader::id() const { + return _id; +} + +rpl::producer Loader::state() const { + return _state.value(); +} + +void Loader::setImplementation( + std::unique_ptr loader) { + _implementation = std::move(loader); + auto convert = [](auto value) { + return SetState(value); + }; + _state = _implementation->progress( + ) | rpl::map([](const Loading &state) { + return SetState(state); + }); + _implementation->failed( + ) | rpl::start_with_next([=] { + fail(); + }, _implementation->lifetime()); + + _implementation->ready( + ) | rpl::start_with_next([=](const QString &filepath) { + unpack(filepath); + }, _implementation->lifetime()); + + QDir(Spellchecker::DictPathByLangId(_id)).removeRecursively(); + _implementation->start(); +} + +void Loader::unpack(const QString &path) { + const auto weak = Ui::MakeWeak(this); + crl::async([=] { + if (Spellchecker::UnpackDictionary(path, _id)) { + QFile(path).remove(); + crl::on_main(weak, [=] { + destroy(); + }); + } else { + crl::on_main(weak, [=] { + fail(); + }); + } + }); +} + +void Loader::finalize(const QString &path) { +} + +void Loader::fail() { + _state = Failed(); +} + +void Loader::destroy() { + Expects(GlobalLoader == this); + + SetGlobalLoader(nullptr); +} + +Inner::Inner( + QWidget *parent, + Dictionaries enabledDictionaries) : RpWidget(parent) { + setupContent(std::move(enabledDictionaries)); +} + +Dictionaries Inner::enabledRows() const { + return _enabledRows; +} + +auto AddButtonWithLoader( + not_null content, + const Spellchecker::Dict &set, + bool buttonEnabled) { + const auto id = set.id; + + const auto button = content->add( + object_ptr>( + content, + object_ptr( + content, + rpl::single(set.name), + st::dictionariesSectionButton + ) + ) + )->entity(); + + const auto buttonState = button->lifetime() + .make_state>(); + + const auto label = Ui::CreateChild( + button, + buttonState->value() | rpl::map(StateDescription), + st::settingsUpdateState); + label->setAttribute(Qt::WA_TransparentForMouseEvents); + + rpl::combine( + button->widthValue(), + label->widthValue() + ) | rpl::start_with_next([=] { + label->moveToLeft( + st::settingsUpdateStatePosition.x(), + st::settingsUpdateStatePosition.y()); + }, label->lifetime()); + + buttonState->value( + ) | rpl::start_with_next([=](const SetState &state) { + const auto isToggledSet = state.is(); + const auto toggled = isToggledSet ? 1. : 0.; + const auto over = !button->isDisabled() + && (button->isDown() || button->isOver()); + + if (toggled == 0. && !over) { + label->setTextColorOverride(std::nullopt); + } else { + label->setTextColorOverride(anim::color( + over ? st::contactsStatusFgOver : st::contactsStatusFg, + st::contactsStatusFgOnline, + toggled)); + } + }, label->lifetime()); + + button->toggleOn( + rpl::single( + buttonEnabled + ) | rpl::then( + buttonState->value( + ) | rpl::filter([](const SetState &state) { + return state.is(); + }) | rpl::map([](const SetState &state) { + return false; + }) + ) + ); + + *buttonState = GlobalLoaderValues.events_starting_with( + GlobalLoader.get() + ) | rpl::map([=](Loader *loader) { + return (loader && loader->id() == id) + ? loader->state() + : rpl::single( + buttonEnabled + ) | rpl::then( + button->toggledValue() + ) | rpl::map([=](auto enabled) { + const auto &state = buttonState->current(); + if (enabled && state.is()) { + return SetState(Active()); + } + if (!enabled && state.is()) { + return SetState(Ready()); + } + return ComputeState(id); + }); + }) | rpl::flatten_latest( + ) | rpl::filter([=](const SetState &state) { + return !buttonState->current().is() || !state.is(); + }); + + button->toggledValue( + ) | rpl::start_with_next([=](bool toggled) { + const auto &state = buttonState->current(); + if (toggled && (state.is() || state.is())) { + SetGlobalLoader(base::make_unique_q(App::main(), id)); + } else if (!toggled && state.is()) { + if (GlobalLoader && GlobalLoader->id() == id) { + GlobalLoader->destroy(); + } + } + }, button->lifetime()); + + return button; +} + +void Inner::setupContent(Dictionaries enabledDictionaries) { + const auto content = Ui::CreateChild(this); + + const auto sets = Spellchecker::Dictionaries(); + for (const auto &set : sets) { + const auto row = AddButtonWithLoader( + content, + set, + ranges::contains(enabledDictionaries, set.id)); + row->toggledValue( + ) | rpl::start_with_next([=](auto enabled) { + if (enabled && Spellchecker::DictionaryExists(set.id)) { + _enabledRows.push_back(set.id); + } else { + auto &rows = _enabledRows; + rows.erase(ranges::remove(rows, set.id), end(rows)); + } + }, row->lifetime()); + } + + content->resizeToWidth(st::boxWidth); + Ui::ResizeFitChild(this, content); +} + +} // namespace + +ManageDictionariesBox::ManageDictionariesBox( + QWidget*, + not_null session) +: _session(session) { +} + +void ManageDictionariesBox::prepare() { + const auto inner = setInnerWidget(object_ptr( + this, + _session->settings().dictionariesEnabled())); + + setTitle(tr::lng_settings_manage_dictionaries()); + + addButton(tr::lng_settings_save(), [=] { + _session->settings().setDictionariesEnabled(inner->enabledRows()); + _session->saveSettingsDelayed(); + closeBox(); + }); + addButton(tr::lng_close(), [=] { closeBox(); }); + + setDimensionsToContent(st::boxWidth, inner); + + inner->heightValue( + ) | rpl::start_with_next([=](int height) { + using std::min; + setDimensions(st::boxWidth, min(height, st::boxMaxListHeight)); + }, inner->lifetime()); +} + +} // namespace Ui + +#endif // !TDESKTOP_DISABLE_SPELLCHECK diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.h b/Telegram/SourceFiles/boxes/dictionaries_manager.h new file mode 100644 index 000000000..f819e140d --- /dev/null +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.h @@ -0,0 +1,36 @@ +/* +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 +*/ +#pragma once + +#ifndef TDESKTOP_DISABLE_SPELLCHECK + +#include "boxes/abstract_box.h" + +namespace Main { +class Session; +} // namespace Main + +namespace Ui { + +class ManageDictionariesBox : public Ui::BoxContent { +public: + ManageDictionariesBox( + QWidget*, + not_null session); + +protected: + void prepare() override; + +private: + const not_null _session; + +}; + +} // namespace Ui + +#endif // !TDESKTOP_DISABLE_SPELLCHECK diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 9d1040125..0500f2808 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -215,3 +215,7 @@ settingsForwardPrivacyTooltipPadding: margins(8px, 6px, 8px, 6px); settingsAccentColorSize: 24px; settingsAccentColorSkip: 4px; settingsAccentColorLine: 3px; + +dictionariesSectionButton: SettingsButton(settingsUpdateToggle) { + font: font(14px semibold); +} From 4b684a492648312dc80a3aa90aadeb9375fe6e34 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 03:03:54 +0300 Subject: [PATCH 102/140] Added spellchecker helper for common purposes. --- Telegram/CMakeLists.txt | 2 + .../SourceFiles/chat_helpers/message_field.h | 2 +- .../chat_helpers/spellchecker_common.cpp | 197 ++++++++++++++++++ .../chat_helpers/spellchecker_common.h | 32 +++ 4 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp create mode 100644 Telegram/SourceFiles/chat_helpers/spellchecker_common.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 6877ea1cb..5c59b357b 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -263,6 +263,8 @@ PRIVATE chat_helpers/gifs_list_widget.h chat_helpers/message_field.cpp chat_helpers/message_field.h + chat_helpers/spellchecker_common.cpp + chat_helpers/spellchecker_common.h chat_helpers/stickers.cpp chat_helpers/stickers.h chat_helpers/stickers_emoji_pack.cpp diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h index 49c4ec8fb..102daca00 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.h +++ b/Telegram/SourceFiles/chat_helpers/message_field.h @@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/qt_connection.h" #ifndef TDESKTOP_DISABLE_SPELLCHECK -#include "boxes/dictionaries_manager.h" +#include "chat_helpers/spellchecker_common.h" #include "spellcheck/spelling_highlighter.h" #include "spellcheck/spellcheck_value.h" #endif // TDESKTOP_DISABLE_SPELLCHECK diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp new file mode 100644 index 000000000..cf149b577 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -0,0 +1,197 @@ +/* +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 +*/ +#include "chat_helpers/spellchecker_common.h" + +#ifndef TDESKTOP_DISABLE_SPELLCHECK + +#include "base/zlib_help.h" + +namespace Spellchecker { + +namespace { + +// Language With Country. +inline auto LWC(QLocale::Country country) { + const auto l = QLocale::matchingLocales( + QLocale::AnyLanguage, + QLocale::AnyScript, + country)[0]; + return (l.language() * 1000) + country; +} + +const auto kDictionaries = { + Dict{ QLocale::Bulgarian, 12, 229'658, "\xd0\x91\xd1\x8a\xd0\xbb\xd0\xb3\xd0\xb0\xd1\x80\xd1\x81\xd0\xba\xd0\xb8" }, + Dict{ QLocale::Catalan, 13, 417'611, "\x43\x61\x74\x61\x6c\xc3\xa0" }, + Dict{ QLocale::Czech, 14, 860'286, "\xc4\x8c\x65\xc5\xa1\x74\x69\x6e\x61" }, + Dict{ QLocale::Welsh, 15, 177'305, "\x43\x79\x6d\x72\x61\x65\x67" }, + Dict{ QLocale::Danish, 16, 345'874, "\x44\x61\x6e\x73\x6b" }, + Dict{ QLocale::German, 17, 2'412'780, "\x44\x65\x75\x74\x73\x63\x68" }, + Dict{ QLocale::Greek, 18, 1'389'160, "\xce\x95\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac" }, + Dict{ LWC(QLocale::Australia), 19, 175'266, "English (Australia)" }, + Dict{ LWC(QLocale::Canada), 20, 174'295, "English (Canada)" }, + Dict{ LWC(QLocale::UnitedKingdom), 21, 174'433, "English (United Kingdom)" }, + Dict{ QLocale::English, 22, 174'516, "English" }, + Dict{ QLocale::Spanish, 23, 264'717, "\x45\x73\x70\x61\xc3\xb1\x6f\x6c" }, + Dict{ QLocale::Estonian, 24, 757'394, "\x45\x65\x73\x74\x69" }, + Dict{ QLocale::Persian, 25, 333'911, "\xd9\x81\xd8\xa7\xd8\xb1\xd8\xb3\xdb\x8c" }, + Dict{ QLocale::French, 26, 321'391, "\x46\x72\x61\x6e\xc3\xa7\x61\x69\x73" }, + Dict{ QLocale::Hebrew, 27, 622'550, "\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa" }, + Dict{ QLocale::Hindi, 28, 56'105, "\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80" }, + Dict{ QLocale::Croatian, 29, 668'876, "\x48\x72\x76\x61\x74\x73\x6b\x69" }, + Dict{ QLocale::Hungarian, 30, 660'402, "\x4d\x61\x67\x79\x61\x72" }, + Dict{ QLocale::Armenian, 31, 928'746, "\xd5\x80\xd5\xa1\xd5\xb5\xd5\xa5\xd6\x80\xd5\xa5\xd5\xb6" }, + Dict{ QLocale::Indonesian, 32, 100'134, "\x49\x6e\x64\x6f\x6e\x65\x73\x69\x61" }, + Dict{ QLocale::Italian, 33, 324'613, "\x49\x74\x61\x6c\x69\x61\x6e\x6f" }, + Dict{ QLocale::Korean, 34, 1'256'987, "\xed\x95\x9c\xea\xb5\xad\xec\x96\xb4" }, + Dict{ QLocale::Lithuanian, 35, 267'427, "\x4c\x69\x65\x74\x75\x76\x69\xc5\xb3" }, + Dict{ QLocale::Latvian, 36, 641'602, "\x4c\x61\x74\x76\x69\x65\xc5\xa1\x75" }, + Dict{ QLocale::Norwegian, 37, 588'650, "\x4e\x6f\x72\x73\x6b" }, + Dict{ QLocale::Dutch, 38, 743'406, "\x4e\x65\x64\x65\x72\x6c\x61\x6e\x64\x73" }, + Dict{ QLocale::Polish, 39, 1'015'747, "\x50\x6f\x6c\x73\x6b\x69" }, + Dict{ LWC(QLocale::Brazil), 40, 1'231'999, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73 (Brazil)" }, + Dict{ QLocale::Portugal, 41, 138'571, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73" }, + Dict{ QLocale::Romanian, 42, 455'643, "\x52\x6f\x6d\xc3\xa2\x6e\xc4\x83" }, + Dict{ QLocale::Russian, 43, 463'194, "\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9" }, + Dict{ QLocale::Slovak, 44, 525'328, "\x53\x6c\x6f\x76\x65\x6e\xc4\x8d\x69\x6e\x61" }, + Dict{ QLocale::Slovenian, 45, 1'143'710, "\x53\x6c\x6f\x76\x65\x6e\xc5\xa1\xc4\x8d\x69\x6e\x61" }, + Dict{ QLocale::Albanian, 46, 583'412, "\x53\x68\x71\x69\x70" }, + Dict{ QLocale::Swedish, 47, 593'877, "\x53\x76\x65\x6e\x73\x6b\x61" }, + Dict{ QLocale::Tamil, 48, 323'193, "\xe0\xae\xa4\xe0\xae\xae\xe0\xae\xbf\xe0\xae\xb4\xe0\xaf\x8d" }, + Dict{ QLocale::Tajik, 49, 369'931, "\xd0\xa2\xd0\xbe\xd2\xb7\xd0\xb8\xd0\xba\xd3\xa3" }, + Dict{ QLocale::Turkish, 50, 4'301'099, "\x54\xc3\xbc\x72\x6b\xc3\xa7\x65" }, + Dict{ QLocale::Ukrainian, 51, 445'711, "\xd0\xa3\xd0\xba\xd1\x80\xd0\xb0\xd1\x97\xd0\xbd\xd1\x81\xd1\x8c\xd0\xba\xd0\xb0" }, + Dict{ QLocale::Vietnamese, 52, 12'949, "\x54\x69\xe1\xba\xbf\x6e\x67\x20\x56\x69\xe1\xbb\x87\x74" }, +}; + +QLocale LocaleFromLangId(int langId) { + if (langId > 1000) { + const auto l = langId / 1000; + const auto lang = static_cast(l); + const auto country = static_cast(langId - l * 1000); + return QLocale(lang, country); + } + return QLocale(static_cast(langId)); +} + +void EnsurePath() { + if (!QDir::current().mkpath(Spellchecker::DictionariesPath())) { + LOG(("App Error: Could not create dictionaries path.")); + } +} + +QByteArray ReadFinalFile(const QString &path) { + constexpr auto kMaxZipSize = 10 * 1024 * 1024; //12 + auto file = QFile(path); + if (file.size() > kMaxZipSize || !file.open(QIODevice::ReadOnly)) { + return QByteArray(); + } + return file.readAll(); +} + +bool ExtractZipFile(zlib::FileToRead &zip, const QString path) { + constexpr auto kMaxSize = 10 * 1024 * 1024; + const auto content = zip.readCurrentFileContent(kMaxSize); + if (content.isEmpty() || zip.error() != UNZ_OK) { + return false; + } + auto file = QFile(path); + return file.open(QIODevice::WriteOnly) + && (file.write(content) == content.size()); +} + +} // namespace + +std::initializer_list Dictionaries() { + return kDictionaries; +} + +bool IsGoodPartName(const QString &name) { + return name.endsWith(qsl(".dic")) + || name.endsWith(qsl(".aff")); +} + +QString DictPathByLangId(int langId) { + EnsurePath(); + return qsl("%1/%2") + .arg(DictionariesPath()) + .arg(LocaleFromLangId(langId).name()); +} + +QString DictionariesPath() { + return cWorkingDir() + qsl("tdata/dictionaries"); +} + +bool UnpackDictionary(const QString &path, int langId) { + const auto folder = DictPathByLangId(langId); + const auto bytes = ReadFinalFile(path); + if (bytes.isEmpty()) { + return false; + } + auto zip = zlib::FileToRead(bytes); + if (zip.goToFirstFile() != UNZ_OK) { + return false; + } + do { + const auto name = zip.getCurrentFileName(); + const auto path = folder + '/' + name; + if (IsGoodPartName(name) && !ExtractZipFile(zip, path)) { + return false; + } + + const auto jump = zip.goToNextFile(); + if (jump == UNZ_END_OF_LIST_OF_FILE) { + break; + } else if (jump != UNZ_OK) { + return false; + } + } while (true); + return true; +} + +bool DictionaryExists(int langId) { + if (!langId) { + return true; + } + const auto folder = DictPathByLangId(langId) + '/'; + const auto exts = { "dic", "aff" }; + const auto bad = ranges::find_if(exts, [&](const QString &ext) { + const auto name = LocaleFromLangId(langId).name(); + return !QFile(folder + name + '.' + ext).exists(); + }); + return (bad == exts.end()); +} + +bool WriteDefaultDictionary() { + // This is an unused function. + const auto en = QLocale::English; + if (DictionaryExists(en)) { + return false; + } + const auto fileName = QLocale(en).name(); + const auto folder = qsl("%1/%2/") + .arg(DictionariesPath()) + .arg(fileName); + QDir(folder).removeRecursively(); + + const auto path = folder + fileName; + QDir().mkpath(folder); + auto input = QFile(qsl(":/misc/en_US_dictionary")); + auto output = QFile(path); + if (input.open(QIODevice::ReadOnly) + && output.open(QIODevice::WriteOnly)) { + output.write(input.readAll()); + const auto result = Spellchecker::UnpackDictionary(path, en); + output.remove(); + return result; + } + return false; +} + +} // namespace Spellchecker + +#endif // !TDESKTOP_DISABLE_SPELLCHECK diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h new file mode 100644 index 000000000..ec0de1e56 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -0,0 +1,32 @@ +/* +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 +*/ +#pragma once + +#ifndef TDESKTOP_DISABLE_SPELLCHECK + +namespace Spellchecker { + +struct Dict { + int id = 0; + int postId = 0; + int size = 0; + QString name; +}; + +[[nodiscard]] QString DictionariesPath(); +[[nodiscard]] QString DictPathByLangId(int langId); +[[nodiscard]] bool IsGoodPartName(const QString &name); +bool UnpackDictionary(const QString &path, int langId); +[[nodiscard]] bool DictionaryExists(int langId); + +bool WriteDefaultDictionary(); +std::initializer_list Dictionaries(); + +} // namespace Spellchecker + +#endif // !TDESKTOP_DISABLE_SPELLCHECK From 08cd7450ffb3f27a13dab87588f3b4f342ba9872 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 13:29:27 +0300 Subject: [PATCH 103/140] Added storage/storage_cloud_blob. - This file is needed to store same code parts related to management of dictionaries and emoji sets. - Moved extracting of zip files to storage_cloud_blob. --- Telegram/CMakeLists.txt | 2 + .../chat_helpers/emoji_sets_manager.cpp | 46 +------------ .../chat_helpers/spellchecker_common.cpp | 46 +------------ .../storage/storage_cloud_blob.cpp | 67 +++++++++++++++++++ .../SourceFiles/storage/storage_cloud_blob.h | 17 +++++ 5 files changed, 91 insertions(+), 87 deletions(-) create mode 100644 Telegram/SourceFiles/storage/storage_cloud_blob.cpp create mode 100644 Telegram/SourceFiles/storage/storage_cloud_blob.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 5c59b357b..2125bd45a 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -856,6 +856,8 @@ PRIVATE storage/serialize_common.h storage/serialize_document.cpp storage/serialize_document.h + storage/storage_cloud_blob.cpp + storage/storage_cloud_blob.h storage/storage_facade.cpp storage/storage_facade.h # storage/storage_feed_messages.cpp diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index 03af31483..eb2d55526 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_account.h" #include "mainwidget.h" #include "app.h" +#include "storage/storage_cloud_blob.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" @@ -197,26 +198,6 @@ QString StateDescription(const SetState &state) { }); } -QByteArray ReadFinalFile(const QString &path) { - constexpr auto kMaxZipSize = 10 * 1024 * 1024; - auto file = QFile(path); - if (file.size() > kMaxZipSize || !file.open(QIODevice::ReadOnly)) { - return QByteArray(); - } - return file.readAll(); -} - -bool ExtractZipFile(zlib::FileToRead &zip, const QString path) { - constexpr auto kMaxSize = 10 * 1024 * 1024; - const auto content = zip.readCurrentFileContent(kMaxSize); - if (content.isEmpty() || zip.error() != UNZ_OK) { - return false; - } - auto file = QFile(path); - return file.open(QIODevice::WriteOnly) - && (file.write(content) == content.size()); -} - bool GoodSetPartName(const QString &name) { return (name == qstr("config.json")) || (name.startsWith(qstr("emoji_")) @@ -224,30 +205,7 @@ bool GoodSetPartName(const QString &name) { } bool UnpackSet(const QString &path, const QString &folder) { - const auto bytes = ReadFinalFile(path); - if (bytes.isEmpty()) { - return false; - } - - auto zip = zlib::FileToRead(bytes); - if (zip.goToFirstFile() != UNZ_OK) { - return false; - } - do { - const auto name = zip.getCurrentFileName(); - const auto path = folder + '/' + name; - if (GoodSetPartName(name) && !ExtractZipFile(zip, path)) { - return false; - } - - const auto jump = zip.goToNextFile(); - if (jump == UNZ_END_OF_LIST_OF_FILE) { - break; - } else if (jump != UNZ_OK) { - return false; - } - } while (true); - return true; + return Storage::UnpackBlob(path, folder, GoodSetPartName); } Loader::Loader(QObject *parent, int id) diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index cf149b577..fce0a12d9 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "storage/storage_cloud_blob.h" + #include "base/zlib_help.h" namespace Spellchecker { @@ -84,26 +86,6 @@ void EnsurePath() { } } -QByteArray ReadFinalFile(const QString &path) { - constexpr auto kMaxZipSize = 10 * 1024 * 1024; //12 - auto file = QFile(path); - if (file.size() > kMaxZipSize || !file.open(QIODevice::ReadOnly)) { - return QByteArray(); - } - return file.readAll(); -} - -bool ExtractZipFile(zlib::FileToRead &zip, const QString path) { - constexpr auto kMaxSize = 10 * 1024 * 1024; - const auto content = zip.readCurrentFileContent(kMaxSize); - if (content.isEmpty() || zip.error() != UNZ_OK) { - return false; - } - auto file = QFile(path); - return file.open(QIODevice::WriteOnly) - && (file.write(content) == content.size()); -} - } // namespace std::initializer_list Dictionaries() { @@ -128,29 +110,7 @@ QString DictionariesPath() { bool UnpackDictionary(const QString &path, int langId) { const auto folder = DictPathByLangId(langId); - const auto bytes = ReadFinalFile(path); - if (bytes.isEmpty()) { - return false; - } - auto zip = zlib::FileToRead(bytes); - if (zip.goToFirstFile() != UNZ_OK) { - return false; - } - do { - const auto name = zip.getCurrentFileName(); - const auto path = folder + '/' + name; - if (IsGoodPartName(name) && !ExtractZipFile(zip, path)) { - return false; - } - - const auto jump = zip.goToNextFile(); - if (jump == UNZ_END_OF_LIST_OF_FILE) { - break; - } else if (jump != UNZ_OK) { - return false; - } - } while (true); - return true; + return Storage::UnpackBlob(path, folder, IsGoodPartName); } bool DictionaryExists(int langId) { diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp new file mode 100644 index 000000000..c394271bb --- /dev/null +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp @@ -0,0 +1,67 @@ +/* +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 +*/ +#include "storage/storage_cloud_blob.h" + +#include "base/zlib_help.h" + +namespace Storage { + +namespace { + +QByteArray ReadFinalFile(const QString &path) { + constexpr auto kMaxZipSize = 10 * 1024 * 1024; + auto file = QFile(path); + if (file.size() > kMaxZipSize || !file.open(QIODevice::ReadOnly)) { + return QByteArray(); + } + return file.readAll(); +} + +bool ExtractZipFile(zlib::FileToRead &zip, const QString path) { + constexpr auto kMaxSize = 25 * 1024 * 1024; + const auto content = zip.readCurrentFileContent(kMaxSize); + if (content.isEmpty() || zip.error() != UNZ_OK) { + return false; + } + auto file = QFile(path); + return file.open(QIODevice::WriteOnly) + && (file.write(content) == content.size()); +} + +} // namespace + +bool UnpackBlob( + const QString &path, + const QString &folder, + Fn checkNameCallback) { + const auto bytes = ReadFinalFile(path); + if (bytes.isEmpty()) { + return false; + } + auto zip = zlib::FileToRead(bytes); + if (zip.goToFirstFile() != UNZ_OK) { + return false; + } + do { + const auto name = zip.getCurrentFileName(); + const auto path = folder + '/' + name; + if (checkNameCallback(name) && !ExtractZipFile(zip, path)) { + return false; + } + + const auto jump = zip.goToNextFile(); + if (jump == UNZ_END_OF_LIST_OF_FILE) { + break; + } else if (jump != UNZ_OK) { + return false; + } + } while (true); + return true; +} + +} // namespace Storage diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.h b/Telegram/SourceFiles/storage/storage_cloud_blob.h new file mode 100644 index 000000000..5728803d1 --- /dev/null +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.h @@ -0,0 +1,17 @@ +/* +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 +*/ +#pragma once + +namespace Storage { + +bool UnpackBlob( + const QString &path, + const QString &folder, + Fn checkNameCallback); + +} // namespace Storage From 9f4d05b04c255d9f3d74e5ee7a5ecf6a3878153c Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 13:59:07 +0300 Subject: [PATCH 104/140] Moved emoji sets from lib_ui. Added parent struct to storage_cloud_blob. --- .../chat_helpers/emoji_sets_manager.cpp | 19 +++++ .../chat_helpers/spellchecker_common.cpp | 84 +++++++++---------- .../chat_helpers/spellchecker_common.h | 8 +- .../SourceFiles/storage/storage_cloud_blob.h | 7 ++ Telegram/lib_ui | 2 +- 5 files changed, 71 insertions(+), 49 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index eb2d55526..c7fbb5116 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -31,6 +31,25 @@ namespace Ui { namespace Emoji { namespace { +struct Set : public Storage::Blob { + QString previewPath; +}; + +inline auto PreviewPath(int i) { + return qsl(":/gui/emoji/set%1_preview.webp").arg(i); +} + +const auto kSets = { + Set{ {0, 0, 0, "Mac"}, PreviewPath(0) }, + Set{ {1, 246, 7'336'383, "Android"}, PreviewPath(1) }, + Set{ {2, 206, 5'038'738, "Twemoji"}, PreviewPath(2) }, + Set{ {3, 238, 6'992'260, "JoyPixels"}, PreviewPath(3) }, +}; + +auto Sets() { + return kSets; +} + struct Available { int size = 0; diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index fce0a12d9..38ca1d0b7 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -9,8 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK -#include "storage/storage_cloud_blob.h" - #include "base/zlib_help.h" namespace Spellchecker { @@ -27,47 +25,47 @@ inline auto LWC(QLocale::Country country) { } const auto kDictionaries = { - Dict{ QLocale::Bulgarian, 12, 229'658, "\xd0\x91\xd1\x8a\xd0\xbb\xd0\xb3\xd0\xb0\xd1\x80\xd1\x81\xd0\xba\xd0\xb8" }, - Dict{ QLocale::Catalan, 13, 417'611, "\x43\x61\x74\x61\x6c\xc3\xa0" }, - Dict{ QLocale::Czech, 14, 860'286, "\xc4\x8c\x65\xc5\xa1\x74\x69\x6e\x61" }, - Dict{ QLocale::Welsh, 15, 177'305, "\x43\x79\x6d\x72\x61\x65\x67" }, - Dict{ QLocale::Danish, 16, 345'874, "\x44\x61\x6e\x73\x6b" }, - Dict{ QLocale::German, 17, 2'412'780, "\x44\x65\x75\x74\x73\x63\x68" }, - Dict{ QLocale::Greek, 18, 1'389'160, "\xce\x95\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac" }, - Dict{ LWC(QLocale::Australia), 19, 175'266, "English (Australia)" }, - Dict{ LWC(QLocale::Canada), 20, 174'295, "English (Canada)" }, - Dict{ LWC(QLocale::UnitedKingdom), 21, 174'433, "English (United Kingdom)" }, - Dict{ QLocale::English, 22, 174'516, "English" }, - Dict{ QLocale::Spanish, 23, 264'717, "\x45\x73\x70\x61\xc3\xb1\x6f\x6c" }, - Dict{ QLocale::Estonian, 24, 757'394, "\x45\x65\x73\x74\x69" }, - Dict{ QLocale::Persian, 25, 333'911, "\xd9\x81\xd8\xa7\xd8\xb1\xd8\xb3\xdb\x8c" }, - Dict{ QLocale::French, 26, 321'391, "\x46\x72\x61\x6e\xc3\xa7\x61\x69\x73" }, - Dict{ QLocale::Hebrew, 27, 622'550, "\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa" }, - Dict{ QLocale::Hindi, 28, 56'105, "\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80" }, - Dict{ QLocale::Croatian, 29, 668'876, "\x48\x72\x76\x61\x74\x73\x6b\x69" }, - Dict{ QLocale::Hungarian, 30, 660'402, "\x4d\x61\x67\x79\x61\x72" }, - Dict{ QLocale::Armenian, 31, 928'746, "\xd5\x80\xd5\xa1\xd5\xb5\xd5\xa5\xd6\x80\xd5\xa5\xd5\xb6" }, - Dict{ QLocale::Indonesian, 32, 100'134, "\x49\x6e\x64\x6f\x6e\x65\x73\x69\x61" }, - Dict{ QLocale::Italian, 33, 324'613, "\x49\x74\x61\x6c\x69\x61\x6e\x6f" }, - Dict{ QLocale::Korean, 34, 1'256'987, "\xed\x95\x9c\xea\xb5\xad\xec\x96\xb4" }, - Dict{ QLocale::Lithuanian, 35, 267'427, "\x4c\x69\x65\x74\x75\x76\x69\xc5\xb3" }, - Dict{ QLocale::Latvian, 36, 641'602, "\x4c\x61\x74\x76\x69\x65\xc5\xa1\x75" }, - Dict{ QLocale::Norwegian, 37, 588'650, "\x4e\x6f\x72\x73\x6b" }, - Dict{ QLocale::Dutch, 38, 743'406, "\x4e\x65\x64\x65\x72\x6c\x61\x6e\x64\x73" }, - Dict{ QLocale::Polish, 39, 1'015'747, "\x50\x6f\x6c\x73\x6b\x69" }, - Dict{ LWC(QLocale::Brazil), 40, 1'231'999, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73 (Brazil)" }, - Dict{ QLocale::Portugal, 41, 138'571, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73" }, - Dict{ QLocale::Romanian, 42, 455'643, "\x52\x6f\x6d\xc3\xa2\x6e\xc4\x83" }, - Dict{ QLocale::Russian, 43, 463'194, "\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9" }, - Dict{ QLocale::Slovak, 44, 525'328, "\x53\x6c\x6f\x76\x65\x6e\xc4\x8d\x69\x6e\x61" }, - Dict{ QLocale::Slovenian, 45, 1'143'710, "\x53\x6c\x6f\x76\x65\x6e\xc5\xa1\xc4\x8d\x69\x6e\x61" }, - Dict{ QLocale::Albanian, 46, 583'412, "\x53\x68\x71\x69\x70" }, - Dict{ QLocale::Swedish, 47, 593'877, "\x53\x76\x65\x6e\x73\x6b\x61" }, - Dict{ QLocale::Tamil, 48, 323'193, "\xe0\xae\xa4\xe0\xae\xae\xe0\xae\xbf\xe0\xae\xb4\xe0\xaf\x8d" }, - Dict{ QLocale::Tajik, 49, 369'931, "\xd0\xa2\xd0\xbe\xd2\xb7\xd0\xb8\xd0\xba\xd3\xa3" }, - Dict{ QLocale::Turkish, 50, 4'301'099, "\x54\xc3\xbc\x72\x6b\xc3\xa7\x65" }, - Dict{ QLocale::Ukrainian, 51, 445'711, "\xd0\xa3\xd0\xba\xd1\x80\xd0\xb0\xd1\x97\xd0\xbd\xd1\x81\xd1\x8c\xd0\xba\xd0\xb0" }, - Dict{ QLocale::Vietnamese, 52, 12'949, "\x54\x69\xe1\xba\xbf\x6e\x67\x20\x56\x69\xe1\xbb\x87\x74" }, + Dict{{ QLocale::Bulgarian, 12, 229'658, "\xd0\x91\xd1\x8a\xd0\xbb\xd0\xb3\xd0\xb0\xd1\x80\xd1\x81\xd0\xba\xd0\xb8" }}, + Dict{{ QLocale::Catalan, 13, 417'611, "\x43\x61\x74\x61\x6c\xc3\xa0" }}, + Dict{{ QLocale::Czech, 14, 860'286, "\xc4\x8c\x65\xc5\xa1\x74\x69\x6e\x61" }}, + Dict{{ QLocale::Welsh, 15, 177'305, "\x43\x79\x6d\x72\x61\x65\x67" }}, + Dict{{ QLocale::Danish, 16, 345'874, "\x44\x61\x6e\x73\x6b" }}, + Dict{{ QLocale::German, 17, 2'412'780, "\x44\x65\x75\x74\x73\x63\x68" }}, + Dict{{ QLocale::Greek, 18, 1'389'160, "\xce\x95\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac" }}, + Dict{{ LWC(QLocale::Australia), 19, 175'266, "English (Australia)" }}, + Dict{{ LWC(QLocale::Canada), 20, 174'295, "English (Canada)" }}, + Dict{{ LWC(QLocale::UnitedKingdom), 21, 174'433, "English (United Kingdom)" }}, + Dict{{ QLocale::English, 22, 174'516, "English" }}, + Dict{{ QLocale::Spanish, 23, 264'717, "\x45\x73\x70\x61\xc3\xb1\x6f\x6c" }}, + Dict{{ QLocale::Estonian, 24, 757'394, "\x45\x65\x73\x74\x69" }}, + Dict{{ QLocale::Persian, 25, 333'911, "\xd9\x81\xd8\xa7\xd8\xb1\xd8\xb3\xdb\x8c" }}, + Dict{{ QLocale::French, 26, 321'391, "\x46\x72\x61\x6e\xc3\xa7\x61\x69\x73" }}, + Dict{{ QLocale::Hebrew, 27, 622'550, "\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa" }}, + Dict{{ QLocale::Hindi, 28, 56'105, "\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80" }}, + Dict{{ QLocale::Croatian, 29, 668'876, "\x48\x72\x76\x61\x74\x73\x6b\x69" }}, + Dict{{ QLocale::Hungarian, 30, 660'402, "\x4d\x61\x67\x79\x61\x72" }}, + Dict{{ QLocale::Armenian, 31, 928'746, "\xd5\x80\xd5\xa1\xd5\xb5\xd5\xa5\xd6\x80\xd5\xa5\xd5\xb6" }}, + Dict{{ QLocale::Indonesian, 32, 100'134, "\x49\x6e\x64\x6f\x6e\x65\x73\x69\x61" }}, + Dict{{ QLocale::Italian, 33, 324'613, "\x49\x74\x61\x6c\x69\x61\x6e\x6f" }}, + Dict{{ QLocale::Korean, 34, 1'256'987, "\xed\x95\x9c\xea\xb5\xad\xec\x96\xb4" }}, + Dict{{ QLocale::Lithuanian, 35, 267'427, "\x4c\x69\x65\x74\x75\x76\x69\xc5\xb3" }}, + Dict{{ QLocale::Latvian, 36, 641'602, "\x4c\x61\x74\x76\x69\x65\xc5\xa1\x75" }}, + Dict{{ QLocale::Norwegian, 37, 588'650, "\x4e\x6f\x72\x73\x6b" }}, + Dict{{ QLocale::Dutch, 38, 743'406, "\x4e\x65\x64\x65\x72\x6c\x61\x6e\x64\x73" }}, + Dict{{ QLocale::Polish, 39, 1'015'747, "\x50\x6f\x6c\x73\x6b\x69" }}, + Dict{{ LWC(QLocale::Brazil), 40, 1'231'999, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73 (Brazil)" }}, + Dict{{ QLocale::Portugal, 41, 138'571, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73" }}, + Dict{{ QLocale::Romanian, 42, 455'643, "\x52\x6f\x6d\xc3\xa2\x6e\xc4\x83" }}, + Dict{{ QLocale::Russian, 43, 463'194, "\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9" }}, + Dict{{ QLocale::Slovak, 44, 525'328, "\x53\x6c\x6f\x76\x65\x6e\xc4\x8d\x69\x6e\x61" }}, + Dict{{ QLocale::Slovenian, 45, 1'143'710, "\x53\x6c\x6f\x76\x65\x6e\xc5\xa1\xc4\x8d\x69\x6e\x61" }}, + Dict{{ QLocale::Albanian, 46, 583'412, "\x53\x68\x71\x69\x70" }}, + Dict{{ QLocale::Swedish, 47, 593'877, "\x53\x76\x65\x6e\x73\x6b\x61" }}, + Dict{{ QLocale::Tamil, 48, 323'193, "\xe0\xae\xa4\xe0\xae\xae\xe0\xae\xbf\xe0\xae\xb4\xe0\xaf\x8d" }}, + Dict{{ QLocale::Tajik, 49, 369'931, "\xd0\xa2\xd0\xbe\xd2\xb7\xd0\xb8\xd0\xba\xd3\xa3" }}, + Dict{{ QLocale::Turkish, 50, 4'301'099, "\x54\xc3\xbc\x72\x6b\xc3\xa7\x65" }}, + Dict{{ QLocale::Ukrainian, 51, 445'711, "\xd0\xa3\xd0\xba\xd1\x80\xd0\xb0\xd1\x97\xd0\xbd\xd1\x81\xd1\x8c\xd0\xba\xd0\xb0" }}, + Dict{{ QLocale::Vietnamese, 52, 12'949, "\x54\x69\xe1\xba\xbf\x6e\x67\x20\x56\x69\xe1\xbb\x87\x74" }}, }; QLocale LocaleFromLangId(int langId) { diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h index ec0de1e56..5f08db09b 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -9,13 +9,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "storage/storage_cloud_blob.h" + namespace Spellchecker { -struct Dict { - int id = 0; - int postId = 0; - int size = 0; - QString name; +struct Dict : public Storage::Blob { }; [[nodiscard]] QString DictionariesPath(); diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.h b/Telegram/SourceFiles/storage/storage_cloud_blob.h index 5728803d1..064b0cd1a 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_blob.h +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.h @@ -9,6 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Storage { +struct Blob { + int id = 0; + int postId = 0; + int size = 0; + QString name; +}; + bool UnpackBlob( const QString &path, const QString &folder, diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 44c463368..be5ed0053 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 44c46336847a8d8ece3fb00301875af58ca69bf4 +Subproject commit be5ed0053adddfa70a739bf19b8d84e540e7e0f8 From 704dcc8d656c314e71015bad9777fd5b88e928db Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 16:06:38 +0300 Subject: [PATCH 105/140] Moved emoji sets and dictionaries loader states to CloudBlob. - Moved CloudBlob to second namespace. --- .../boxes/dictionaries_manager.cpp | 69 +++++-------------- .../chat_helpers/emoji_sets_manager.cpp | 40 ++--------- .../chat_helpers/spellchecker_common.cpp | 4 +- .../chat_helpers/spellchecker_common.h | 2 +- .../storage/storage_cloud_blob.cpp | 4 +- .../SourceFiles/storage/storage_cloud_blob.h | 39 ++++++++++- 6 files changed, 65 insertions(+), 93 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 8b6d062f9..4beab9046 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -38,48 +38,15 @@ namespace Ui { namespace { using Dictionaries = std::vector; +using namespace Storage::CloudBlob; -struct Available { - int size = 0; - - inline bool operator<(const Available &other) const { - return size < other.size; - } - inline bool operator==(const Available &other) const { - return size == other.size; - } -}; -struct Ready { - inline bool operator<(const Ready &other) const { - return false; - } - inline bool operator==(const Ready &other) const { - return true; - } -}; -struct Active { - inline bool operator<(const Active &other) const { - return false; - } - inline bool operator==(const Active &other) const { - return true; - } -}; using Loading = MTP::DedicatedLoader::Progress; -struct Failed { - inline bool operator<(const Failed &other) const { - return false; - } - inline bool operator==(const Failed &other) const { - return true; - } -}; -using SetState = base::variant< +using DictState = base::variant< Available, Ready, Active, - Loading, - Failed>; + Failed, + Loading>; class Loader : public QObject { public: @@ -87,7 +54,7 @@ public: int id() const; - rpl::producer state() const; + rpl::producer state() const; void destroy(); private: @@ -98,7 +65,7 @@ private: int _id = 0; int _size = 0; - rpl::variable _state; + rpl::variable _state; MTP::WeakInstance _mtproto; std::unique_ptr _implementation; @@ -148,7 +115,7 @@ MTP::DedicatedLoader::Location GetDownloadLocation(int id) { return MTP::DedicatedLoader::Location{ kUsername, i->postId }; } -SetState ComputeState(int id) { +DictState ComputeState(int id) { // if (id == CurrentSetId()) { // return Active(); if (Spellchecker::DictionaryExists(id)) { @@ -157,7 +124,7 @@ SetState ComputeState(int id) { return Available{ GetDownloadSize(id) }; } -QString StateDescription(const SetState &state) { +QString StateDescription(const DictState &state) { return state.match([](const Available &data) { return tr::lng_emoji_set_download(tr::now, lt_size, formatSizeText(data.size)); }, [](const Ready &data) -> QString { @@ -202,7 +169,7 @@ int Loader::id() const { return _id; } -rpl::producer Loader::state() const { +rpl::producer Loader::state() const { return _state.value(); } @@ -210,11 +177,11 @@ void Loader::setImplementation( std::unique_ptr loader) { _implementation = std::move(loader); auto convert = [](auto value) { - return SetState(value); + return DictState(value); }; _state = _implementation->progress( ) | rpl::map([](const Loading &state) { - return SetState(state); + return DictState(state); }); _implementation->failed( ) | rpl::start_with_next([=] { @@ -287,7 +254,7 @@ auto AddButtonWithLoader( )->entity(); const auto buttonState = button->lifetime() - .make_state>(); + .make_state>(); const auto label = Ui::CreateChild( button, @@ -305,7 +272,7 @@ auto AddButtonWithLoader( }, label->lifetime()); buttonState->value( - ) | rpl::start_with_next([=](const SetState &state) { + ) | rpl::start_with_next([=](const DictState &state) { const auto isToggledSet = state.is(); const auto toggled = isToggledSet ? 1. : 0.; const auto over = !button->isDisabled() @@ -326,9 +293,9 @@ auto AddButtonWithLoader( buttonEnabled ) | rpl::then( buttonState->value( - ) | rpl::filter([](const SetState &state) { + ) | rpl::filter([](const DictState &state) { return state.is(); - }) | rpl::map([](const SetState &state) { + }) | rpl::map([](const auto &state) { return false; }) ) @@ -346,15 +313,15 @@ auto AddButtonWithLoader( ) | rpl::map([=](auto enabled) { const auto &state = buttonState->current(); if (enabled && state.is()) { - return SetState(Active()); + return DictState(Active()); } if (!enabled && state.is()) { - return SetState(Ready()); + return DictState(Ready()); } return ComputeState(id); }); }) | rpl::flatten_latest( - ) | rpl::filter([=](const SetState &state) { + ) | rpl::filter([=](const DictState &state) { return !buttonState->current().is() || !state.is(); }); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index c7fbb5116..190c7fbc4 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -31,7 +31,9 @@ namespace Ui { namespace Emoji { namespace { -struct Set : public Storage::Blob { +using namespace Storage::CloudBlob; + +struct Set : public Blob { QString previewPath; }; @@ -50,41 +52,7 @@ auto Sets() { return kSets; } -struct Available { - int size = 0; - - inline bool operator<(const Available &other) const { - return size < other.size; - } - inline bool operator==(const Available &other) const { - return size == other.size; - } -}; -struct Ready { - inline bool operator<(const Ready &other) const { - return false; - } - inline bool operator==(const Ready &other) const { - return true; - } -}; -struct Active { - inline bool operator<(const Active &other) const { - return false; - } - inline bool operator==(const Active &other) const { - return true; - } -}; using Loading = MTP::DedicatedLoader::Progress; -struct Failed { - inline bool operator<(const Failed &other) const { - return false; - } - inline bool operator==(const Failed &other) const { - return true; - } -}; using SetState = base::variant< Available, Ready, @@ -224,7 +192,7 @@ bool GoodSetPartName(const QString &name) { } bool UnpackSet(const QString &path, const QString &folder) { - return Storage::UnpackBlob(path, folder, GoodSetPartName); + return UnpackBlob(path, folder, GoodSetPartName); } Loader::Loader(QObject *parent, int id) diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index 38ca1d0b7..fc8cd3bb8 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -15,6 +15,8 @@ namespace Spellchecker { namespace { +using namespace Storage::CloudBlob; + // Language With Country. inline auto LWC(QLocale::Country country) { const auto l = QLocale::matchingLocales( @@ -108,7 +110,7 @@ QString DictionariesPath() { bool UnpackDictionary(const QString &path, int langId) { const auto folder = DictPathByLangId(langId); - return Storage::UnpackBlob(path, folder, IsGoodPartName); + return UnpackBlob(path, folder, IsGoodPartName); } bool DictionaryExists(int langId) { diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h index 5f08db09b..c33e81095 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Spellchecker { -struct Dict : public Storage::Blob { +struct Dict : public Storage::CloudBlob::Blob { }; [[nodiscard]] QString DictionariesPath(); diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp index c394271bb..a90635462 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp @@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/zlib_help.h" -namespace Storage { +namespace Storage::CloudBlob { namespace { @@ -64,4 +64,4 @@ bool UnpackBlob( return true; } -} // namespace Storage +} // namespace Storage::CloudBlob diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.h b/Telegram/SourceFiles/storage/storage_cloud_blob.h index 064b0cd1a..e34705f2c 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_blob.h +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.h @@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -namespace Storage { +namespace Storage::CloudBlob { struct Blob { int id = 0; @@ -16,9 +16,44 @@ struct Blob { QString name; }; +struct Available { + int size = 0; + + inline bool operator<(const Available &other) const { + return size < other.size; + } + inline bool operator==(const Available &other) const { + return size == other.size; + } +}; +struct Ready { + inline bool operator<(const Ready &other) const { + return false; + } + inline bool operator==(const Ready &other) const { + return true; + } +}; +struct Active { + inline bool operator<(const Active &other) const { + return false; + } + inline bool operator==(const Active &other) const { + return true; + } +}; +struct Failed { + inline bool operator<(const Failed &other) const { + return false; + } + inline bool operator==(const Failed &other) const { + return true; + } +}; + bool UnpackBlob( const QString &path, const QString &folder, Fn checkNameCallback); -} // namespace Storage +} // namespace Storage::CloudBlob From 8ca0b614d7dc63a9986940646dc598f7f076fbfa Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 17:13:12 +0300 Subject: [PATCH 106/140] Moved loader of emoji sets and dictionaries to CloudBlob. --- .../boxes/dictionaries_manager.cpp | 109 ++++------------- .../chat_helpers/emoji_sets_manager.cpp | 111 ++++-------------- .../storage/storage_cloud_blob.cpp | 59 ++++++++++ .../SourceFiles/storage/storage_cloud_blob.h | 43 +++++++ 4 files changed, 153 insertions(+), 169 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 4beab9046..46f809fe1 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -41,34 +41,19 @@ using Dictionaries = std::vector; using namespace Storage::CloudBlob; using Loading = MTP::DedicatedLoader::Progress; -using DictState = base::variant< - Available, - Ready, - Active, - Failed, - Loading>; +using DictState = BlobState; -class Loader : public QObject { +class Loader : public BlobLoader { public: - Loader(QObject *parent, int id); + Loader( + QObject *parent, + int id, + MTP::DedicatedLoader::Location location, + const QString &folder, + int size); - int id() const; - - rpl::producer state() const; - void destroy(); - -private: - void setImplementation(std::unique_ptr loader); - void unpack(const QString &path); - void finalize(const QString &path); - void fail(); - - int _id = 0; - int _size = 0; - rpl::variable _state; - - MTP::WeakInstance _mtproto; - std::unique_ptr _implementation; + void destroy() override; + void unpack(const QString &path) override; }; @@ -109,10 +94,10 @@ int GetDownloadSize(int id) { } MTP::DedicatedLoader::Location GetDownloadLocation(int id) { - constexpr auto kUsername = "tdhbcfiles"; + const auto username = kCloudLocationUsername.utf16(); const auto sets = Spellchecker::Dictionaries(); const auto i = ranges::find(sets, id, &Spellchecker::Dict::id); - return MTP::DedicatedLoader::Location{ kUsername, i->postId }; + return MTP::DedicatedLoader::Location{ username, i->postId }; } DictState ComputeState(int id) { @@ -147,60 +132,18 @@ QString StateDescription(const DictState &state) { }); } -Loader::Loader(QObject *parent, int id) -: QObject(parent) -, _id(id) -, _size(GetDownloadSize(_id)) -, _state(Loading{ 0, _size }) -, _mtproto(Core::App().activeAccount().mtp()) { - const auto ready = [=](std::unique_ptr loader) { - if (loader) { - setImplementation(std::move(loader)); - } else { - fail(); - } - }; - const auto location = GetDownloadLocation(id); - const auto folder = Spellchecker::DictPathByLangId(id); - MTP::StartDedicatedLoader(&_mtproto, location, folder, ready); -} - -int Loader::id() const { - return _id; -} - -rpl::producer Loader::state() const { - return _state.value(); -} - -void Loader::setImplementation( - std::unique_ptr loader) { - _implementation = std::move(loader); - auto convert = [](auto value) { - return DictState(value); - }; - _state = _implementation->progress( - ) | rpl::map([](const Loading &state) { - return DictState(state); - }); - _implementation->failed( - ) | rpl::start_with_next([=] { - fail(); - }, _implementation->lifetime()); - - _implementation->ready( - ) | rpl::start_with_next([=](const QString &filepath) { - unpack(filepath); - }, _implementation->lifetime()); - - QDir(Spellchecker::DictPathByLangId(_id)).removeRecursively(); - _implementation->start(); +Loader::Loader( + QObject *parent, + int id, + MTP::DedicatedLoader::Location location, + const QString &folder, + int size) : BlobLoader(parent, id, location, folder, size) { } void Loader::unpack(const QString &path) { const auto weak = Ui::MakeWeak(this); crl::async([=] { - if (Spellchecker::UnpackDictionary(path, _id)) { + if (Spellchecker::UnpackDictionary(path, id())) { QFile(path).remove(); crl::on_main(weak, [=] { destroy(); @@ -213,13 +156,6 @@ void Loader::unpack(const QString &path) { }); } -void Loader::finalize(const QString &path) { -} - -void Loader::fail() { - _state = Failed(); -} - void Loader::destroy() { Expects(GlobalLoader == this); @@ -329,7 +265,12 @@ auto AddButtonWithLoader( ) | rpl::start_with_next([=](bool toggled) { const auto &state = buttonState->current(); if (toggled && (state.is() || state.is())) { - SetGlobalLoader(base::make_unique_q(App::main(), id)); + SetGlobalLoader(base::make_unique_q( + App::main(), + id, + GetDownloadLocation(id), + Spellchecker::DictPathByLangId(id), + GetDownloadSize(id))); } else if (!toggled && state.is()) { if (GlobalLoader && GlobalLoader->id() == id) { GlobalLoader->destroy(); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index 190c7fbc4..c41fac066 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -53,34 +53,19 @@ auto Sets() { } using Loading = MTP::DedicatedLoader::Progress; -using SetState = base::variant< - Available, - Ready, - Active, - Loading, - Failed>; +using SetState = BlobState; -class Loader : public QObject { +class Loader : public BlobLoader { public: - Loader(QObject *parent, int id); + Loader( + QObject *parent, + int id, + MTP::DedicatedLoader::Location location, + const QString &folder, + int size); - int id() const; - - rpl::producer state() const; - void destroy(); - -private: - void setImplementation(std::unique_ptr loader); - void unpack(const QString &path); - void finalize(const QString &path); - void fail(); - - int _id = 0; - int _size = 0; - rpl::variable _state; - - MTP::WeakInstance _mtproto; - std::unique_ptr _implementation; + void destroy() override; + void unpack(const QString &path) override; }; @@ -148,10 +133,10 @@ int GetDownloadSize(int id) { } MTP::DedicatedLoader::Location GetDownloadLocation(int id) { - constexpr auto kUsername = "tdhbcfiles"; + const auto username = kCloudLocationUsername.utf16(); const auto sets = Sets(); const auto i = ranges::find(sets, id, &Set::id); - return MTP::DedicatedLoader::Location{ kUsername, i->postId }; + return MTP::DedicatedLoader::Location{ username, i->postId }; } SetState ComputeState(int id) { @@ -195,63 +180,21 @@ bool UnpackSet(const QString &path, const QString &folder) { return UnpackBlob(path, folder, GoodSetPartName); } -Loader::Loader(QObject *parent, int id) -: QObject(parent) -, _id(id) -, _size(GetDownloadSize(_id)) -, _state(Loading{ 0, _size }) -, _mtproto(Core::App().activeAccount().mtp()) { - const auto ready = [=](std::unique_ptr loader) { - if (loader) { - setImplementation(std::move(loader)); - } else { - fail(); - } - }; - const auto location = GetDownloadLocation(id); - const auto folder = internal::SetDataPath(id); - MTP::StartDedicatedLoader(&_mtproto, location, folder, ready); -} - -int Loader::id() const { - return _id; -} - -rpl::producer Loader::state() const { - return _state.value(); -} - -void Loader::setImplementation( - std::unique_ptr loader) { - _implementation = std::move(loader); - auto convert = [](auto value) { - return SetState(value); - }; - _state = _implementation->progress( - ) | rpl::map([](const Loading &state) { - return SetState(state); - }); - _implementation->failed( - ) | rpl::start_with_next([=] { - fail(); - }, _implementation->lifetime()); - - _implementation->ready( - ) | rpl::start_with_next([=](const QString &filepath) { - unpack(filepath); - }, _implementation->lifetime()); - - QDir(internal::SetDataPath(_id)).removeRecursively(); - _implementation->start(); +Loader::Loader( + QObject *parent, + int id, + MTP::DedicatedLoader::Location location, + const QString &folder, + int size) : BlobLoader(parent, id, location, folder, size) { } void Loader::unpack(const QString &path) { - const auto folder = internal::SetDataPath(_id); + const auto folder = internal::SetDataPath(id()); const auto weak = Ui::MakeWeak(this); crl::async([=] { if (UnpackSet(path, folder)) { QFile(path).remove(); - SwitchToSet(_id, crl::guard(weak, [=](bool success) { + SwitchToSet(id(), crl::guard(weak, [=](bool success) { if (success) { destroy(); } else { @@ -266,13 +209,6 @@ void Loader::unpack(const QString &path) { }); } -void Loader::finalize(const QString &path) { -} - -void Loader::fail() { - _state = Failed(); -} - void Loader::destroy() { Expects(GlobalLoader == this); @@ -491,7 +427,12 @@ void Row::setupHandler() { } void Row::load() { - SetGlobalLoader(base::make_unique_q(App::main(), _id)); + SetGlobalLoader(base::make_unique_q( + App::main(), + _id, + GetDownloadLocation(_id), + internal::SetDataPath(_id), + GetDownloadSize(_id))); } void Row::setupLabels(const Set &set) { diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp index a90635462..3707cc8cb 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp @@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/storage_cloud_blob.h" #include "base/zlib_help.h" +#include "core/application.h" +#include "main/main_account.h" namespace Storage::CloudBlob { @@ -64,4 +66,61 @@ bool UnpackBlob( return true; } +BlobLoader::BlobLoader( + QObject *parent, + int id, + MTP::DedicatedLoader::Location location, + const QString &folder, + int size) +: QObject(parent) +, _folder(folder) +, _id(id) +, _state(Loading{ 0, size }) +, _mtproto(Core::App().activeAccount().mtp()) { + const auto ready = [=](std::unique_ptr loader) { + if (loader) { + setImplementation(std::move(loader)); + } else { + fail(); + } + }; + MTP::StartDedicatedLoader(&_mtproto, location, _folder, ready); +} + +int BlobLoader::id() const { + return _id; +} + +rpl::producer BlobLoader::state() const { + return _state.value(); +} + +void BlobLoader::setImplementation( + std::unique_ptr loader) { + _implementation = std::move(loader); + auto convert = [](auto value) { + return BlobState(value); + }; + _state = _implementation->progress( + ) | rpl::map([](const Loading &state) { + return BlobState(state); + }); + _implementation->failed( + ) | rpl::start_with_next([=] { + fail(); + }, _implementation->lifetime()); + + _implementation->ready( + ) | rpl::start_with_next([=](const QString &filepath) { + unpack(filepath); + }, _implementation->lifetime()); + + QDir(_folder).removeRecursively(); + _implementation->start(); +} + +void BlobLoader::fail() { + _state = Failed(); +} + } // namespace Storage::CloudBlob diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.h b/Telegram/SourceFiles/storage/storage_cloud_blob.h index e34705f2c..a0533eee7 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_blob.h +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.h @@ -7,8 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "mtproto/dedicated_file_loader.h" + namespace Storage::CloudBlob { +constexpr auto kCloudLocationUsername = "tdhbcfiles"_cs; + struct Blob { int id = 0; int postId = 0; @@ -51,9 +55,48 @@ struct Failed { } }; +using Loading = MTP::DedicatedLoader::Progress; +using BlobState = base::variant< + Available, + Ready, + Active, + Failed, + Loading>; + bool UnpackBlob( const QString &path, const QString &folder, Fn checkNameCallback); +class BlobLoader : public QObject { +public: + BlobLoader( + QObject *parent, + int id, + MTP::DedicatedLoader::Location location, + const QString &folder, + int size); + + int id() const; + + rpl::producer state() const; + virtual void destroy() = 0; + virtual void unpack(const QString &path) = 0; + +protected: + void fail(); + + const QString _folder; + +private: + void setImplementation(std::unique_ptr loader); + + int _id = 0; + rpl::variable _state; + + MTP::WeakInstance _mtproto; + std::unique_ptr _implementation; + +}; + } // namespace Storage::CloudBlob From efdf5f176717b5f9f1035dbec9c41c3446251324 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 17:28:22 +0300 Subject: [PATCH 107/140] Moved producer of state description to CloudBlob. --- .../boxes/dictionaries_manager.cpp | 24 +++-------------- .../chat_helpers/emoji_sets_manager.cpp | 23 +++------------- .../storage/storage_cloud_blob.cpp | 27 +++++++++++++++++++ .../SourceFiles/storage/storage_cloud_blob.h | 7 +++++ 4 files changed, 40 insertions(+), 41 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 46f809fe1..9d9fc461c 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -19,7 +19,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/radial_animation.h" #include "lang/lang_keys.h" #include "base/zlib_help.h" -#include "layout.h" #include "core/application.h" #include "main/main_account.h" #include "main/main_session.h" @@ -110,26 +109,9 @@ DictState ComputeState(int id) { } QString StateDescription(const DictState &state) { - return state.match([](const Available &data) { - return tr::lng_emoji_set_download(tr::now, lt_size, formatSizeText(data.size)); - }, [](const Ready &data) -> QString { - return tr::lng_emoji_set_ready(tr::now); - }, [](const Active &data) -> QString { - return tr::lng_settings_manage_enabled_dictionary(tr::now); - // return tr::lng_emoji_set_active(tr::now); - }, [](const Loading &data) { - const auto percent = (data.size > 0) - ? snap((data.already * 100) / float64(data.size), 0., 100.) - : 0.; - return tr::lng_emoji_set_loading( - tr::now, - lt_percent, - QString::number(int(std::round(percent))) + '%', - lt_progress, - formatDownloadText(data.already, data.size)); - }, [](const Failed &data) { - return tr::lng_attach_failed(tr::now); - }); + return StateDescription( + state, + tr::lng_settings_manage_enabled_dictionary); } Loader::Loader( diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index c41fac066..50c52c215 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -17,7 +17,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/emoji_config.h" #include "lang/lang_keys.h" #include "base/zlib_help.h" -#include "layout.h" #include "core/application.h" #include "main/main_account.h" #include "mainwidget.h" @@ -149,25 +148,9 @@ SetState ComputeState(int id) { } QString StateDescription(const SetState &state) { - return state.match([](const Available &data) { - return tr::lng_emoji_set_download(tr::now, lt_size, formatSizeText(data.size)); - }, [](const Ready &data) -> QString { - return tr::lng_emoji_set_ready(tr::now); - }, [](const Active &data) -> QString { - return tr::lng_emoji_set_active(tr::now); - }, [](const Loading &data) { - const auto percent = (data.size > 0) - ? snap((data.already * 100) / float64(data.size), 0., 100.) - : 0.; - return tr::lng_emoji_set_loading( - tr::now, - lt_percent, - QString::number(int(std::round(percent))) + '%', - lt_progress, - formatDownloadText(data.already, data.size)); - }, [](const Failed &data) { - return tr::lng_attach_failed(tr::now); - }); + return StateDescription( + state, + tr::lng_emoji_set_active); } bool GoodSetPartName(const QString &name) { diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp index 3707cc8cb..41d7d1c9d 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp @@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/zlib_help.h" #include "core/application.h" +#include "lang/lang_keys.h" +#include "layout.h" #include "main/main_account.h" namespace Storage::CloudBlob { @@ -66,6 +68,31 @@ bool UnpackBlob( return true; } +QString StateDescription(const BlobState &state, tr::phrase<> activeText) { + return state.match([](const Available &data) { + return tr::lng_emoji_set_download( + tr::now, + lt_size, + formatSizeText(data.size)); + }, [](const Ready &data) -> QString { + return tr::lng_emoji_set_ready(tr::now); + }, [&](const Active &data) -> QString { + return activeText(tr::now); + }, [](const Loading &data) { + const auto percent = (data.size > 0) + ? snap((data.already * 100) / float64(data.size), 0., 100.) + : 0.; + return tr::lng_emoji_set_loading( + tr::now, + lt_percent, + QString::number(int(std::round(percent))) + '%', + lt_progress, + formatDownloadText(data.already, data.size)); + }, [](const Failed &data) { + return tr::lng_attach_failed(tr::now); + }); +} + BlobLoader::BlobLoader( QObject *parent, int id, diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.h b/Telegram/SourceFiles/storage/storage_cloud_blob.h index a0533eee7..4a1b485bc 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_blob.h +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.h @@ -9,6 +9,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/dedicated_file_loader.h" +namespace tr { +template +struct phrase; +} // namespace tr + namespace Storage::CloudBlob { constexpr auto kCloudLocationUsername = "tdhbcfiles"_cs; @@ -68,6 +73,8 @@ bool UnpackBlob( const QString &folder, Fn checkNameCallback); +QString StateDescription(const BlobState &state, tr::phrase<> activeText); + class BlobLoader : public QObject { public: BlobLoader( From 9d98682089300772750f538917f471f0d9d02113 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 17:54:52 +0300 Subject: [PATCH 108/140] Removed unnecessary includes from emoji sets and dictionaries managers. --- .../boxes/dictionaries_manager.cpp | 23 ++++++------------- .../chat_helpers/emoji_sets_manager.cpp | 2 -- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 9d9fc461c..9afbf9c86 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -9,29 +9,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK -#include "mtproto/dedicated_file_loader.h" -#include "ui/wrap/vertical_layout.h" -#include "ui/wrap/fade_wrap.h" -#include "ui/widgets/buttons.h" -#include "ui/widgets/labels.h" -#include "ui/wrap/slide_wrap.h" -#include "ui/effects/animations.h" -#include "ui/effects/radial_animation.h" -#include "lang/lang_keys.h" -#include "base/zlib_help.h" +#include "chat_helpers/spellchecker_common.h" #include "core/application.h" #include "main/main_account.h" #include "main/main_session.h" #include "mainwidget.h" -#include "app.h" +#include "mtproto/dedicated_file_loader.h" #include "styles/style_layers.h" #include "styles/style_settings.h" #include "styles/style_boxes.h" -#include "styles/style_chat_helpers.h" - -#include "chat_helpers/spellchecker_common.h" - -#include +#include "ui/wrap/vertical_layout.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/labels.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/effects/animations.h" namespace Ui { namespace { diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index 50c52c215..13709bc51 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -15,8 +15,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/animations.h" #include "ui/effects/radial_animation.h" #include "ui/emoji_config.h" -#include "lang/lang_keys.h" -#include "base/zlib_help.h" #include "core/application.h" #include "main/main_account.h" #include "mainwidget.h" From f377ac54fd4d3a9f88b224c3a389d0f4e60b6598 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 5 Feb 2020 18:59:52 +0300 Subject: [PATCH 109/140] Slightly refactored spellchecker_common.cpp. - Moved LocaleFromLangId to lib_spellcheck. --- .../boxes/dictionaries_manager.cpp | 10 ------- .../chat_helpers/spellchecker_common.cpp | 27 +++++++------------ 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 9afbf9c86..2ab0dbe7a 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -63,16 +63,6 @@ private: base::unique_qptr GlobalLoader; rpl::event_stream GlobalLoaderValues; -QLocale LocaleFromLangId(int langId) { - if (langId > 1000) { - const auto l = langId / 1000; - const auto lang = static_cast(l); - const auto country = static_cast(langId - l * 1000); - return QLocale(lang, country); - } - return QLocale(static_cast(langId)); -} - void SetGlobalLoader(base::unique_qptr loader) { GlobalLoader = std::move(loader); GlobalLoaderValues.fire(GlobalLoader.get()); diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index fc8cd3bb8..81d87500e 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "spellcheck/spellcheck_utils.h" #include "base/zlib_help.h" namespace Spellchecker { @@ -17,6 +18,8 @@ namespace { using namespace Storage::CloudBlob; +constexpr auto kDictExtensions = { "dic", "aff" }; + // Language With Country. inline auto LWC(QLocale::Country country) { const auto l = QLocale::matchingLocales( @@ -70,16 +73,6 @@ const auto kDictionaries = { Dict{{ QLocale::Vietnamese, 52, 12'949, "\x54\x69\xe1\xba\xbf\x6e\x67\x20\x56\x69\xe1\xbb\x87\x74" }}, }; -QLocale LocaleFromLangId(int langId) { - if (langId > 1000) { - const auto l = langId / 1000; - const auto lang = static_cast(l); - const auto country = static_cast(langId - l * 1000); - return QLocale(lang, country); - } - return QLocale(static_cast(langId)); -} - void EnsurePath() { if (!QDir::current().mkpath(Spellchecker::DictionariesPath())) { LOG(("App Error: Could not create dictionaries path.")); @@ -93,15 +86,16 @@ std::initializer_list Dictionaries() { } bool IsGoodPartName(const QString &name) { - return name.endsWith(qsl(".dic")) - || name.endsWith(qsl(".aff")); + return ranges::find_if(kDictExtensions, [&](const auto &ext) { + return name.endsWith(ext); + }) != end(kDictExtensions); } QString DictPathByLangId(int langId) { EnsurePath(); return qsl("%1/%2") .arg(DictionariesPath()) - .arg(LocaleFromLangId(langId).name()); + .arg(Spellchecker::LocaleFromLangId(langId).name()); } QString DictionariesPath() { @@ -118,12 +112,11 @@ bool DictionaryExists(int langId) { return true; } const auto folder = DictPathByLangId(langId) + '/'; - const auto exts = { "dic", "aff" }; - const auto bad = ranges::find_if(exts, [&](const QString &ext) { - const auto name = LocaleFromLangId(langId).name(); + const auto bad = ranges::find_if(kDictExtensions, [&](const auto &ext) { + const auto name = Spellchecker::LocaleFromLangId(langId).name(); return !QFile(folder + name + '.' + ext).exists(); }); - return (bad == exts.end()); + return (bad == end(kDictExtensions)); } bool WriteDefaultDictionary() { From 62e0ced6a6afc41fd5ade0436ad5a43cfcb37fe2 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 6 Feb 2020 00:39:58 +0300 Subject: [PATCH 110/140] Imporved computing state of buttons in dictionaries manager. --- .../boxes/dictionaries_manager.cpp | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 2ab0dbe7a..3d1cc444b 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -80,11 +80,14 @@ MTP::DedicatedLoader::Location GetDownloadLocation(int id) { return MTP::DedicatedLoader::Location{ username, i->postId }; } -DictState ComputeState(int id) { - // if (id == CurrentSetId()) { - // return Active(); - if (Spellchecker::DictionaryExists(id)) { - return Ready(); +inline auto DictExists(int langId) { + return Spellchecker::DictionaryExists(langId); +} + +DictState ComputeState(int id, bool enabled) { + const auto result = enabled ? DictState(Active()) : DictState(Ready()); + if (DictExists(id)) { + return result; } return Available{ GetDownloadSize(id) }; } @@ -210,14 +213,7 @@ auto AddButtonWithLoader( ) | rpl::then( button->toggledValue() ) | rpl::map([=](auto enabled) { - const auto &state = buttonState->current(); - if (enabled && state.is()) { - return DictState(Active()); - } - if (!enabled && state.is()) { - return DictState(Ready()); - } - return ComputeState(id); + return ComputeState(id, enabled); }); }) | rpl::flatten_latest( ) | rpl::filter([=](const DictState &state) { @@ -255,7 +251,7 @@ void Inner::setupContent(Dictionaries enabledDictionaries) { ranges::contains(enabledDictionaries, set.id)); row->toggledValue( ) | rpl::start_with_next([=](auto enabled) { - if (enabled && Spellchecker::DictionaryExists(set.id)) { + if (enabled && DictExists(set.id)) { _enabledRows.push_back(set.id); } else { auto &rows = _enabledRows; From 039ed17683845bcaa4c6602a0deb9787bc750c36 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 6 Feb 2020 16:58:19 +0300 Subject: [PATCH 111/140] Fixed saving of not loaded dictionaries. --- Telegram/SourceFiles/boxes/dictionaries_manager.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 3d1cc444b..a2deaee2a 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -251,7 +251,7 @@ void Inner::setupContent(Dictionaries enabledDictionaries) { ranges::contains(enabledDictionaries, set.id)); row->toggledValue( ) | rpl::start_with_next([=](auto enabled) { - if (enabled && DictExists(set.id)) { + if (enabled) { _enabledRows.push_back(set.id); } else { auto &rows = _enabledRows; @@ -280,7 +280,11 @@ void ManageDictionariesBox::prepare() { setTitle(tr::lng_settings_manage_dictionaries()); addButton(tr::lng_settings_save(), [=] { - _session->settings().setDictionariesEnabled(inner->enabledRows()); + auto enabledRows = inner->enabledRows(); + _session->settings().setDictionariesEnabled( + enabledRows | ranges::views::filter( + DictExists + ) | ranges::to_vector); _session->saveSettingsDelayed(); closeBox(); }); From f598bf0b426c9685161f0876aac916c7b24e147f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 6 Feb 2020 18:27:35 +0300 Subject: [PATCH 112/140] Replaced fake dictionary ids with real values. --- .../boxes/dictionaries_manager.cpp | 36 ++---- .../chat_helpers/spellchecker_common.cpp | 105 ++++++++++-------- .../chat_helpers/spellchecker_common.h | 6 +- 3 files changed, 74 insertions(+), 73 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index a2deaee2a..1a09a6ad4 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -68,18 +68,6 @@ void SetGlobalLoader(base::unique_qptr loader) { GlobalLoaderValues.fire(GlobalLoader.get()); } -int GetDownloadSize(int id) { - const auto sets = Spellchecker::Dictionaries(); - return ranges::find(sets, id, &Spellchecker::Dict::id)->size; -} - -MTP::DedicatedLoader::Location GetDownloadLocation(int id) { - const auto username = kCloudLocationUsername.utf16(); - const auto sets = Spellchecker::Dictionaries(); - const auto i = ranges::find(sets, id, &Spellchecker::Dict::id); - return MTP::DedicatedLoader::Location{ username, i->postId }; -} - inline auto DictExists(int langId) { return Spellchecker::DictionaryExists(langId); } @@ -89,7 +77,7 @@ DictState ComputeState(int id, bool enabled) { if (DictExists(id)) { return result; } - return Available{ GetDownloadSize(id) }; + return Available{ Spellchecker::GetDownloadSize(id) }; } QString StateDescription(const DictState &state) { @@ -140,16 +128,16 @@ Dictionaries Inner::enabledRows() const { auto AddButtonWithLoader( not_null content, - const Spellchecker::Dict &set, + const Spellchecker::Dict &dict, bool buttonEnabled) { - const auto id = set.id; + const auto id = dict.id; const auto button = content->add( object_ptr>( content, object_ptr( content, - rpl::single(set.name), + rpl::single(dict.name), st::dictionariesSectionButton ) ) @@ -227,9 +215,9 @@ auto AddButtonWithLoader( SetGlobalLoader(base::make_unique_q( App::main(), id, - GetDownloadLocation(id), + Spellchecker::GetDownloadLocation(id), Spellchecker::DictPathByLangId(id), - GetDownloadSize(id))); + Spellchecker::GetDownloadSize(id))); } else if (!toggled && state.is()) { if (GlobalLoader && GlobalLoader->id() == id) { GlobalLoader->destroy(); @@ -243,19 +231,19 @@ auto AddButtonWithLoader( void Inner::setupContent(Dictionaries enabledDictionaries) { const auto content = Ui::CreateChild(this); - const auto sets = Spellchecker::Dictionaries(); - for (const auto &set : sets) { + for (const auto &dict : Spellchecker::Dictionaries()) { + const auto id = dict.id; const auto row = AddButtonWithLoader( content, - set, - ranges::contains(enabledDictionaries, set.id)); + dict, + ranges::contains(enabledDictionaries, id)); row->toggledValue( ) | rpl::start_with_next([=](auto enabled) { if (enabled) { - _enabledRows.push_back(set.id); + _enabledRows.push_back(id); } else { auto &rows = _enabledRows; - rows.erase(ranges::remove(rows, set.id), end(rows)); + rows.erase(ranges::remove(rows, id), end(rows)); } }, row->lifetime()); } diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index 81d87500e..07ab7275b 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -30,47 +30,48 @@ inline auto LWC(QLocale::Country country) { } const auto kDictionaries = { - Dict{{ QLocale::Bulgarian, 12, 229'658, "\xd0\x91\xd1\x8a\xd0\xbb\xd0\xb3\xd0\xb0\xd1\x80\xd1\x81\xd0\xba\xd0\xb8" }}, - Dict{{ QLocale::Catalan, 13, 417'611, "\x43\x61\x74\x61\x6c\xc3\xa0" }}, - Dict{{ QLocale::Czech, 14, 860'286, "\xc4\x8c\x65\xc5\xa1\x74\x69\x6e\x61" }}, - Dict{{ QLocale::Welsh, 15, 177'305, "\x43\x79\x6d\x72\x61\x65\x67" }}, - Dict{{ QLocale::Danish, 16, 345'874, "\x44\x61\x6e\x73\x6b" }}, - Dict{{ QLocale::German, 17, 2'412'780, "\x44\x65\x75\x74\x73\x63\x68" }}, - Dict{{ QLocale::Greek, 18, 1'389'160, "\xce\x95\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac" }}, - Dict{{ LWC(QLocale::Australia), 19, 175'266, "English (Australia)" }}, - Dict{{ LWC(QLocale::Canada), 20, 174'295, "English (Canada)" }}, - Dict{{ LWC(QLocale::UnitedKingdom), 21, 174'433, "English (United Kingdom)" }}, - Dict{{ QLocale::English, 22, 174'516, "English" }}, - Dict{{ QLocale::Spanish, 23, 264'717, "\x45\x73\x70\x61\xc3\xb1\x6f\x6c" }}, - Dict{{ QLocale::Estonian, 24, 757'394, "\x45\x65\x73\x74\x69" }}, - Dict{{ QLocale::Persian, 25, 333'911, "\xd9\x81\xd8\xa7\xd8\xb1\xd8\xb3\xdb\x8c" }}, - Dict{{ QLocale::French, 26, 321'391, "\x46\x72\x61\x6e\xc3\xa7\x61\x69\x73" }}, - Dict{{ QLocale::Hebrew, 27, 622'550, "\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa" }}, - Dict{{ QLocale::Hindi, 28, 56'105, "\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80" }}, - Dict{{ QLocale::Croatian, 29, 668'876, "\x48\x72\x76\x61\x74\x73\x6b\x69" }}, - Dict{{ QLocale::Hungarian, 30, 660'402, "\x4d\x61\x67\x79\x61\x72" }}, - Dict{{ QLocale::Armenian, 31, 928'746, "\xd5\x80\xd5\xa1\xd5\xb5\xd5\xa5\xd6\x80\xd5\xa5\xd5\xb6" }}, - Dict{{ QLocale::Indonesian, 32, 100'134, "\x49\x6e\x64\x6f\x6e\x65\x73\x69\x61" }}, - Dict{{ QLocale::Italian, 33, 324'613, "\x49\x74\x61\x6c\x69\x61\x6e\x6f" }}, - Dict{{ QLocale::Korean, 34, 1'256'987, "\xed\x95\x9c\xea\xb5\xad\xec\x96\xb4" }}, - Dict{{ QLocale::Lithuanian, 35, 267'427, "\x4c\x69\x65\x74\x75\x76\x69\xc5\xb3" }}, - Dict{{ QLocale::Latvian, 36, 641'602, "\x4c\x61\x74\x76\x69\x65\xc5\xa1\x75" }}, - Dict{{ QLocale::Norwegian, 37, 588'650, "\x4e\x6f\x72\x73\x6b" }}, - Dict{{ QLocale::Dutch, 38, 743'406, "\x4e\x65\x64\x65\x72\x6c\x61\x6e\x64\x73" }}, - Dict{{ QLocale::Polish, 39, 1'015'747, "\x50\x6f\x6c\x73\x6b\x69" }}, - Dict{{ LWC(QLocale::Brazil), 40, 1'231'999, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73 (Brazil)" }}, - Dict{{ QLocale::Portugal, 41, 138'571, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73" }}, - Dict{{ QLocale::Romanian, 42, 455'643, "\x52\x6f\x6d\xc3\xa2\x6e\xc4\x83" }}, - Dict{{ QLocale::Russian, 43, 463'194, "\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9" }}, - Dict{{ QLocale::Slovak, 44, 525'328, "\x53\x6c\x6f\x76\x65\x6e\xc4\x8d\x69\x6e\x61" }}, - Dict{{ QLocale::Slovenian, 45, 1'143'710, "\x53\x6c\x6f\x76\x65\x6e\xc5\xa1\xc4\x8d\x69\x6e\x61" }}, - Dict{{ QLocale::Albanian, 46, 583'412, "\x53\x68\x71\x69\x70" }}, - Dict{{ QLocale::Swedish, 47, 593'877, "\x53\x76\x65\x6e\x73\x6b\x61" }}, - Dict{{ QLocale::Tamil, 48, 323'193, "\xe0\xae\xa4\xe0\xae\xae\xe0\xae\xbf\xe0\xae\xb4\xe0\xaf\x8d" }}, - Dict{{ QLocale::Tajik, 49, 369'931, "\xd0\xa2\xd0\xbe\xd2\xb7\xd0\xb8\xd0\xba\xd3\xa3" }}, - Dict{{ QLocale::Turkish, 50, 4'301'099, "\x54\xc3\xbc\x72\x6b\xc3\xa7\x65" }}, - Dict{{ QLocale::Ukrainian, 51, 445'711, "\xd0\xa3\xd0\xba\xd1\x80\xd0\xb0\xd1\x97\xd0\xbd\xd1\x81\xd1\x8c\xd0\xba\xd0\xb0" }}, - Dict{{ QLocale::Vietnamese, 52, 12'949, "\x54\x69\xe1\xba\xbf\x6e\x67\x20\x56\x69\xe1\xbb\x87\x74" }}, + Dict{{ QLocale::English, 649, 174'516, "English" }}, // en_US + Dict{{ QLocale::Bulgarian, 594, 229'658, "\xd0\x91\xd1\x8a\xd0\xbb\xd0\xb3\xd0\xb0\xd1\x80\xd1\x81\xd0\xba\xd0\xb8" }}, // bg_BG + Dict{{ QLocale::Catalan, 595, 417'611, "\x43\x61\x74\x61\x6c\xc3\xa0" }}, // ca_ES + Dict{{ QLocale::Czech, 596, 860'286, "\xc4\x8c\x65\xc5\xa1\x74\x69\x6e\x61" }}, // cs_CZ + Dict{{ QLocale::Welsh, 597, 177'305, "\x43\x79\x6d\x72\x61\x65\x67" }}, // cy_GB + Dict{{ QLocale::Danish, 598, 345'874, "\x44\x61\x6e\x73\x6b" }}, // da_DK + Dict{{ QLocale::German, 599, 2'412'780, "\x44\x65\x75\x74\x73\x63\x68" }}, // de_DE + Dict{{ QLocale::Greek, 600, 1'389'160, "\xce\x95\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac" }}, // el_GR + Dict{{ LWC(QLocale::Australia), 601, 175'266, "English (Australia)" }}, // en_AU + Dict{{ LWC(QLocale::Canada), 602, 174'295, "English (Canada)" }}, // en_CA + Dict{{ LWC(QLocale::UnitedKingdom), 603, 174'433, "English (United Kingdom)" }}, // en_GB + Dict{{ QLocale::Spanish, 604, 264'717, "\x45\x73\x70\x61\xc3\xb1\x6f\x6c" }}, // es_ES + Dict{{ QLocale::Estonian, 605, 757'394, "\x45\x65\x73\x74\x69" }}, // et_EE + Dict{{ QLocale::Persian, 606, 333'911, "\xd9\x81\xd8\xa7\xd8\xb1\xd8\xb3\xdb\x8c" }}, // fa_IR + Dict{{ QLocale::French, 607, 321'391, "\x46\x72\x61\x6e\xc3\xa7\x61\x69\x73" }}, // fr_FR + Dict{{ QLocale::Hebrew, 608, 622'550, "\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa" }}, // he_IL + Dict{{ QLocale::Hindi, 609, 56'105, "\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80" }}, // hi_IN + Dict{{ QLocale::Croatian, 610, 668'876, "\x48\x72\x76\x61\x74\x73\x6b\x69" }}, // hr_HR + Dict{{ QLocale::Hungarian, 611, 660'402, "\x4d\x61\x67\x79\x61\x72" }}, // hu_HU + Dict{{ QLocale::Armenian, 612, 928'746, "\xd5\x80\xd5\xa1\xd5\xb5\xd5\xa5\xd6\x80\xd5\xa5\xd5\xb6" }}, // hy_AM + Dict{{ QLocale::Indonesian, 613, 100'134, "\x49\x6e\x64\x6f\x6e\x65\x73\x69\x61" }}, // id_ID + Dict{{ QLocale::Italian, 614, 324'613, "\x49\x74\x61\x6c\x69\x61\x6e\x6f" }}, // it_IT + Dict{{ QLocale::Korean, 615, 1'256'987, "\xed\x95\x9c\xea\xb5\xad\xec\x96\xb4" }}, // ko_KR + Dict{{ QLocale::Lithuanian, 616, 267'427, "\x4c\x69\x65\x74\x75\x76\x69\xc5\xb3" }}, // lt_LT + Dict{{ QLocale::Latvian, 617, 641'602, "\x4c\x61\x74\x76\x69\x65\xc5\xa1\x75" }}, // lv_LV + Dict{{ QLocale::Norwegian, 618, 588'650, "\x4e\x6f\x72\x73\x6b" }}, // nb_NO + Dict{{ QLocale::Dutch, 619, 743'406, "\x4e\x65\x64\x65\x72\x6c\x61\x6e\x64\x73" }}, // nl_NL + Dict{{ QLocale::Polish, 620, 1'015'747, "\x50\x6f\x6c\x73\x6b\x69" }}, // pl_PL + Dict{{ QLocale::Portuguese, 621, 1'231'999, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73 (Brazil)" }}, // pt_BR + Dict{{ LWC(QLocale::Portugal), 622, 138'571, "\x50\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73" }}, // pt_PT + Dict{{ QLocale::Romanian, 623, 455'643, "\x52\x6f\x6d\xc3\xa2\x6e\xc4\x83" }}, // ro_RO + Dict{{ QLocale::Russian, 624, 463'194, "\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9" }}, // ru_RU + Dict{{ QLocale::Slovak, 625, 525'328, "\x53\x6c\x6f\x76\x65\x6e\xc4\x8d\x69\x6e\x61" }}, // sk_SK + Dict{{ QLocale::Slovenian, 626, 1'143'710, "\x53\x6c\x6f\x76\x65\x6e\xc5\xa1\xc4\x8d\x69\x6e\x61" }}, // sl_SI + Dict{{ QLocale::Albanian, 627, 583'412, "\x53\x68\x71\x69\x70" }}, // sq_AL + Dict{{ QLocale::Swedish, 628, 593'877, "\x53\x76\x65\x6e\x73\x6b\x61" }}, // sv_SE + Dict{{ QLocale::Tamil, 629, 323'193, "\xe0\xae\xa4\xe0\xae\xae\xe0\xae\xbf\xe0\xae\xb4\xe0\xaf\x8d" }}, // ta_IN + Dict{{ QLocale::Tajik, 630, 369'931, "\xd0\xa2\xd0\xbe\xd2\xb7\xd0\xb8\xd0\xba\xd3\xa3" }}, // tg_TG + Dict{{ QLocale::Turkish, 631, 4'301'099, "\x54\xc3\xbc\x72\x6b\xc3\xa7\x65" }}, // tr_TR + Dict{{ QLocale::Ukrainian, 632, 445'711, "\xd0\xa3\xd0\xba\xd1\x80\xd0\xb0\xd1\x97\xd0\xbd\xd1\x81\xd1\x8c\xd0\xba\xd0\xb0" }}, // uk_UA + Dict{{ QLocale::Vietnamese, 633, 12'949, "\x54\x69\xe1\xba\xbf\x6e\x67\x20\x56\x69\xe1\xbb\x87\x74" }}, // vi_VN + // The Tajik code is 'tg_TG' in Chromium, but QT has only 'tg_TJ'. }; void EnsurePath() { @@ -79,18 +80,28 @@ void EnsurePath() { } } -} // namespace - -std::initializer_list Dictionaries() { - return kDictionaries; -} - bool IsGoodPartName(const QString &name) { return ranges::find_if(kDictExtensions, [&](const auto &ext) { return name.endsWith(ext); }) != end(kDictExtensions); } +} // namespace + +std::vector Dictionaries() { + return kDictionaries | ranges::to_vector; +} + +int GetDownloadSize(int id) { + return ranges::find(kDictionaries, id, &Spellchecker::Dict::id)->size; +} + +MTP::DedicatedLoader::Location GetDownloadLocation(int id) { + const auto username = kCloudLocationUsername.utf16(); + const auto i = ranges::find(kDictionaries, id, &Spellchecker::Dict::id); + return MTP::DedicatedLoader::Location{ username, i->postId }; +} + QString DictPathByLangId(int langId) { EnsurePath(); return qsl("%1/%2") diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h index c33e81095..dad2be732 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -16,14 +16,16 @@ namespace Spellchecker { struct Dict : public Storage::CloudBlob::Blob { }; +int GetDownloadSize(int id); +MTP::DedicatedLoader::Location GetDownloadLocation(int id); + [[nodiscard]] QString DictionariesPath(); [[nodiscard]] QString DictPathByLangId(int langId); -[[nodiscard]] bool IsGoodPartName(const QString &name); bool UnpackDictionary(const QString &path, int langId); [[nodiscard]] bool DictionaryExists(int langId); bool WriteDefaultDictionary(); -std::initializer_list Dictionaries(); +std::vector Dictionaries(); } // namespace Spellchecker From 783269e256df8457d3f3869c650548a4b86b6307 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 6 Feb 2020 18:32:02 +0300 Subject: [PATCH 113/140] Removed unnecessary Sets() function. --- .../SourceFiles/chat_helpers/emoji_sets_manager.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index 13709bc51..a59a2a2e9 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -45,10 +45,6 @@ const auto kSets = { Set{ {3, 238, 6'992'260, "JoyPixels"}, PreviewPath(3) }, }; -auto Sets() { - return kSets; -} - using Loading = MTP::DedicatedLoader::Progress; using SetState = BlobState; @@ -119,8 +115,7 @@ void SetGlobalLoader(base::unique_qptr loader) { } int GetDownloadSize(int id) { - const auto sets = Sets(); - return ranges::find(sets, id, &Set::id)->size; + return ranges::find(kSets, id, &Set::id)->size; } [[nodiscard]] float64 CountProgress(not_null loading) { @@ -131,8 +126,7 @@ int GetDownloadSize(int id) { MTP::DedicatedLoader::Location GetDownloadLocation(int id) { const auto username = kCloudLocationUsername.utf16(); - const auto sets = Sets(); - const auto i = ranges::find(sets, id, &Set::id); + const auto i = ranges::find(kSets, id, &Set::id); return MTP::DedicatedLoader::Location{ username, i->postId }; } @@ -203,8 +197,7 @@ Inner::Inner(QWidget *parent) : RpWidget(parent) { void Inner::setupContent() { const auto content = Ui::CreateChild(this); - const auto sets = Sets(); - for (const auto &set : sets) { + for (const auto &set : kSets) { content->add(object_ptr(content, set)); } From 9dee4e2d25a2e14a1aee361c147fd6647292baec Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 7 Feb 2020 21:13:06 +0300 Subject: [PATCH 114/140] Added ability to download more than one dictionary at same time. --- .../boxes/dictionaries_manager.cpp | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 1a09a6ad4..23e6e1957 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -40,11 +40,15 @@ public: int id, MTP::DedicatedLoader::Location location, const QString &folder, - int size); + int size, + Fn destroyCallback); void destroy() override; void unpack(const QString &path) override; +private: + Fn _destroyCallback; + }; class Inner : public Ui::RpWidget { @@ -60,14 +64,6 @@ private: }; -base::unique_qptr GlobalLoader; -rpl::event_stream GlobalLoaderValues; - -void SetGlobalLoader(base::unique_qptr loader) { - GlobalLoader = std::move(loader); - GlobalLoaderValues.fire(GlobalLoader.get()); -} - inline auto DictExists(int langId) { return Spellchecker::DictionaryExists(langId); } @@ -91,29 +87,24 @@ Loader::Loader( int id, MTP::DedicatedLoader::Location location, const QString &folder, - int size) : BlobLoader(parent, id, location, folder, size) { + int size, + Fn destroyCallback) +: BlobLoader(parent, id, location, folder, size) +, _destroyCallback(std::move(destroyCallback)) { } void Loader::unpack(const QString &path) { - const auto weak = Ui::MakeWeak(this); + Expects(_destroyCallback); crl::async([=] { - if (Spellchecker::UnpackDictionary(path, id())) { + const auto success = Spellchecker::UnpackDictionary(path, id()); + if (success) { QFile(path).remove(); - crl::on_main(weak, [=] { - destroy(); - }); - } else { - crl::on_main(weak, [=] { - fail(); - }); } + crl::on_main(success ? _destroyCallback : [=] { fail(); }); }); } void Loader::destroy() { - Expects(GlobalLoader == this); - - SetGlobalLoader(nullptr); } Inner::Inner( @@ -143,6 +134,20 @@ auto AddButtonWithLoader( ) )->entity(); + + const auto localLoader = button->lifetime() + .make_state>(); + const auto localLoaderValues = button->lifetime() + .make_state>(); + const auto setLocalLoader = [=](base::unique_qptr loader) { + *localLoader = std::move(loader); + localLoaderValues->fire(localLoader->get()); + }; + const auto destroyLocalLoader = [=] { + setLocalLoader(nullptr); + }; + + const auto buttonState = button->lifetime() .make_state>(); @@ -191,9 +196,9 @@ auto AddButtonWithLoader( ) ); - *buttonState = GlobalLoaderValues.events_starting_with( - GlobalLoader.get() - ) | rpl::map([=](Loader *loader) { + *buttonState = localLoaderValues->events_starting_with( + localLoader->get() + ) | rpl::map([=](Loader *loader) { return (loader && loader->id() == id) ? loader->state() : rpl::single( @@ -212,15 +217,17 @@ auto AddButtonWithLoader( ) | rpl::start_with_next([=](bool toggled) { const auto &state = buttonState->current(); if (toggled && (state.is() || state.is())) { - SetGlobalLoader(base::make_unique_q( + const auto weak = Ui::MakeWeak(button); + setLocalLoader(base::make_unique_q( App::main(), id, Spellchecker::GetDownloadLocation(id), Spellchecker::DictPathByLangId(id), - Spellchecker::GetDownloadSize(id))); + Spellchecker::GetDownloadSize(id), + crl::guard(weak, destroyLocalLoader))); } else if (!toggled && state.is()) { - if (GlobalLoader && GlobalLoader->id() == id) { - GlobalLoader->destroy(); + if (localLoader && localLoader->get()->id() == id) { + destroyLocalLoader(); } } }, button->lifetime()); From 9d1b93fe506e79716cd875ad84b556193be23055 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 8 Feb 2020 01:42:01 +0300 Subject: [PATCH 115/140] Moved spellchecker work from message_field to Spellchecker::Start. --- .../chat_helpers/message_field.cpp | 27 -------------- .../SourceFiles/chat_helpers/message_field.h | 2 -- .../chat_helpers/spellchecker_common.cpp | 35 ++++++++++++++++++- .../chat_helpers/spellchecker_common.h | 6 ++++ Telegram/SourceFiles/main/main_session.cpp | 8 +++++ 5 files changed, 48 insertions(+), 30 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 142568285..1bd0b447b 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -280,37 +280,10 @@ void InitSpellchecker( not_null session, not_null field) { #ifndef TDESKTOP_DISABLE_SPELLCHECK - if (!Platform::Spellchecker::IsAvailable()) { - return; - } - - Spellchecker::SetWorkingDirPath(Spellchecker::DictionariesPath()); - const auto s = Ui::CreateChild( field.get(), session->settings().spellcheckerEnabledValue()); - - const auto applyDictionaries = [=] { - crl::async([=] { - Platform::Spellchecker::UpdateLanguages( - session->settings().dictionariesEnabled()); - crl::on_main([=] { - s->checkCurrentText(); - }); - }); - }; - session->settings().dictionariesChanges( - ) | rpl::start_with_next(applyDictionaries, field->lifetime()); - - Spellchecker::SetPhrases({ { - { &ph::lng_spellchecker_add, tr::lng_spellchecker_add() }, - { &ph::lng_spellchecker_remove, tr::lng_spellchecker_remove() }, - { &ph::lng_spellchecker_ignore, tr::lng_spellchecker_ignore() }, - } }); - field->setExtendedContextMenu(s->contextMenuCreated()); - - applyDictionaries(); #endif // TDESKTOP_DISABLE_SPELLCHECK } diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h index 102daca00..8f95a9323 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.h +++ b/Telegram/SourceFiles/chat_helpers/message_field.h @@ -12,9 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/qt_connection.h" #ifndef TDESKTOP_DISABLE_SPELLCHECK -#include "chat_helpers/spellchecker_common.h" #include "spellcheck/spelling_highlighter.h" -#include "spellcheck/spellcheck_value.h" #endif // TDESKTOP_DISABLE_SPELLCHECK #include diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index 07ab7275b..a589f39c3 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -9,8 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK -#include "spellcheck/spellcheck_utils.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" #include "base/zlib_help.h" +#include "spellcheck/platform/platform_spellcheck.h" +#include "spellcheck/spellcheck_utils.h" +#include "spellcheck/spellcheck_value.h" namespace Spellchecker { @@ -156,6 +160,35 @@ bool WriteDefaultDictionary() { return false; } +void Start(not_null session) { + Spellchecker::SetPhrases({ { + { &ph::lng_spellchecker_add, tr::lng_spellchecker_add() }, + { &ph::lng_spellchecker_remove, tr::lng_spellchecker_remove() }, + { &ph::lng_spellchecker_ignore, tr::lng_spellchecker_ignore() }, + } }); + + if (!Platform::Spellchecker::IsSystemSpellchecker()) { + Spellchecker::SetWorkingDirPath(DictionariesPath()); + + session->settings().dictionariesEnabledChanges( + ) | rpl::start_with_next([](auto dictionaries) { + Platform::Spellchecker::UpdateLanguages(dictionaries); + }, session->lifetime()); + + session->settings().spellcheckerEnabledChanges( + ) | rpl::start_with_next([=](auto enabled) { + Platform::Spellchecker::UpdateLanguages( + enabled + ? session->settings().dictionariesEnabled() + : std::vector()); + }, session->lifetime()); + } + if (session->settings().spellcheckerEnabled()) { + Platform::Spellchecker::UpdateLanguages( + session->settings().dictionariesEnabled()); + } +} + } // namespace Spellchecker #endif // !TDESKTOP_DISABLE_SPELLCHECK diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h index dad2be732..0c3a09c4d 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/storage_cloud_blob.h" +namespace Main { +class Session; +} // namespace Main + namespace Spellchecker { struct Dict : public Storage::CloudBlob::Blob { @@ -27,6 +31,8 @@ bool UnpackDictionary(const QString &path, int langId); bool WriteDefaultDictionary(); std::vector Dictionaries(); +void Start(not_null session); + } // namespace Spellchecker #endif // !TDESKTOP_DISABLE_SPELLCHECK diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 39fb80754..90de3897d 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -27,6 +27,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "observer_peer.h" #include "facades.h" +#ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "chat_helpers/spellchecker_common.h" +#endif // TDESKTOP_DISABLE_SPELLCHECK + namespace Main { namespace { @@ -97,6 +101,10 @@ Session::Session( }); Window::Theme::Background()->start(); + +#ifndef TDESKTOP_DISABLE_SPELLCHECK + Spellchecker::Start(this); +#endif // TDESKTOP_DISABLE_SPELLCHECK } Session::~Session() { From 4bd34b35aedcd3a0493e32a13abbc2608245bbad Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 8 Feb 2020 13:28:13 +0300 Subject: [PATCH 116/140] Added button to advanced settings for dictionary management box. --- Telegram/Resources/langs/lang.strings | 1 + .../settings/settings_advanced.cpp | 39 ++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index ab50a4318..2d6126197 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -422,6 +422,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_spellchecker" = "Spell checker"; "lng_settings_system_spellchecker" = "Use system spell checker"; +"lng_settings_custom_spellchecker" = "Use spell checker"; "lng_settings_manage_dictionaries" = "Manage dictionaries"; "lng_settings_manage_enabled_dictionary" = "Dictionary is enabled"; diff --git a/Telegram/SourceFiles/settings/settings_advanced.cpp b/Telegram/SourceFiles/settings/settings_advanced.cpp index 3e613ee5a..d2e61809d 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced.cpp @@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_settings.h" #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "boxes/dictionaries_manager.h" #include "spellcheck/platform/platform_spellcheck.h" #endif // !TDESKTOP_DISABLE_SPELLCHECK @@ -250,28 +251,56 @@ void SetupUpdate(not_null container) { bool HasSystemSpellchecker() { #ifdef TDESKTOP_DISABLE_SPELLCHECK return false; -#else - return Platform::Spellchecker::IsAvailable(); #endif // TDESKTOP_DISABLE_SPELLCHECK + return true; } void SetupSpellchecker( not_null controller, not_null container) { +#ifndef TDESKTOP_DISABLE_SPELLCHECK const auto session = &controller->session(); - AddButton( + const auto isSystem = Platform::Spellchecker::IsSystemSpellchecker(); + const auto button = AddButton( container, - tr::lng_settings_system_spellchecker(), + isSystem + ? tr::lng_settings_system_spellchecker() + : tr::lng_settings_custom_spellchecker(), st::settingsButton )->toggleOn( rpl::single(session->settings().spellcheckerEnabled()) - )->toggledValue( + ); + + button->toggledValue( ) | rpl::filter([=](bool enabled) { return (enabled != session->settings().spellcheckerEnabled()); }) | rpl::start_with_next([=](bool enabled) { session->settings().setSpellcheckerEnabled(enabled); session->saveSettingsDelayed(); }, container->lifetime()); + + if (isSystem) { + return; + } + + const auto sliding = container->add( + object_ptr>( + container, + object_ptr(container))); + + AddButton( + sliding->entity(), + tr::lng_settings_manage_dictionaries(), + st::settingsButton + )->addClickHandler([=] { + Ui::show(Box(session)); + }); + + button->toggledValue( + ) | rpl::start_with_next([=](bool enabled) { + sliding->toggle(enabled, anim::type::normal); + }, container->lifetime()); +#endif // !TDESKTOP_DISABLE_SPELLCHECK } bool HasTray() { From e9e9ea2d6920aa97809f49964ebc1f8d1aef9beb Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 8 Feb 2020 14:50:20 +0300 Subject: [PATCH 117/140] Added filter for removed dictionaries when dictionary box is closed. --- Telegram/SourceFiles/boxes/dictionaries_manager.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 23e6e1957..98ba77e1a 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -122,6 +122,7 @@ auto AddButtonWithLoader( const Spellchecker::Dict &dict, bool buttonEnabled) { const auto id = dict.id; + buttonEnabled &= DictExists(id); const auto button = content->add( object_ptr>( @@ -272,6 +273,11 @@ void ManageDictionariesBox::prepare() { this, _session->settings().dictionariesEnabled())); + // The initial list of enabled rows may differ from the list of languages + // in settings, so we should store it when box opens + // and save it when box closes (don't do it when "Save" was pressed). + const auto initialEnabledRows = inner->enabledRows(); + setTitle(tr::lng_settings_manage_dictionaries()); addButton(tr::lng_settings_save(), [=] { @@ -281,10 +287,17 @@ void ManageDictionariesBox::prepare() { DictExists ) | ranges::to_vector); _session->saveSettingsDelayed(); + // Ignore boxClosing() when the Save button was pressed. + lifetime().destroy(); closeBox(); }); addButton(tr::lng_close(), [=] { closeBox(); }); + boxClosing() | rpl::start_with_next([=] { + _session->settings().setDictionariesEnabled(initialEnabledRows); + _session->saveSettingsDelayed(); + }, lifetime()); + setDimensionsToContent(st::boxWidth, inner); inner->heightValue( From a0f995b134a49fb58bb7fb37ae6fb5235909f60b Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 8 Feb 2020 16:57:43 +0300 Subject: [PATCH 118/140] Added ability to remove dictionary from context menu. --- Telegram/Resources/langs/lang.strings | 1 + .../boxes/dictionaries_manager.cpp | 62 ++++++++++++++++--- .../chat_helpers/spellchecker_common.cpp | 11 ++++ .../chat_helpers/spellchecker_common.h | 2 + 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 2d6126197..db08ef19f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -425,6 +425,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_custom_spellchecker" = "Use spell checker"; "lng_settings_manage_dictionaries" = "Manage dictionaries"; "lng_settings_manage_enabled_dictionary" = "Dictionary is enabled"; +"lng_settings_manage_remove_dictionary" = "Remove Dictionary"; "lng_backgrounds_header" = "Choose your new chat background"; "lng_theme_sure_keep" = "Keep this theme?"; diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 98ba77e1a..cd8957ce5 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "base/event_filter.h" #include "chat_helpers/spellchecker_common.h" #include "core/application.h" #include "main/main_account.h" @@ -21,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/vertical_layout.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" +#include "ui/widgets/popup_menu.h" #include "ui/wrap/slide_wrap.h" #include "ui/effects/animations.h" @@ -68,6 +70,12 @@ inline auto DictExists(int langId) { return Spellchecker::DictionaryExists(langId); } +inline auto FilterEnabledDict(Dictionaries dicts) { + return dicts | ranges::views::filter( + DictExists + ) | ranges::to_vector; +} + DictState ComputeState(int id, bool enabled) { const auto result = enabled ? DictState(Active()) : DictState(Ready()); if (DictExists(id)) { @@ -151,6 +159,8 @@ auto AddButtonWithLoader( const auto buttonState = button->lifetime() .make_state>(); + const auto dictionaryRemoved = button->lifetime() + .make_state>(); const auto label = Ui::CreateChild( button, @@ -188,10 +198,15 @@ auto AddButtonWithLoader( rpl::single( buttonEnabled ) | rpl::then( - buttonState->value( - ) | rpl::filter([](const DictState &state) { - return state.is(); - }) | rpl::map([](const auto &state) { + rpl::merge( + dictionaryRemoved->events(), + buttonState->value( + ) | rpl::filter([](const DictState &state) { + return state.is(); + }) | rpl::map([] { + return rpl::empty_value(); + }) + ) | rpl::map([]() { return false; }) ) @@ -205,7 +220,13 @@ auto AddButtonWithLoader( : rpl::single( buttonEnabled ) | rpl::then( - button->toggledValue() + rpl::merge( + dictionaryRemoved->events( + ) | rpl::map([] { + return false; + }), + button->toggledValue() + ) ) | rpl::map([=](auto enabled) { return ComputeState(id, enabled); }); @@ -233,6 +254,29 @@ auto AddButtonWithLoader( } }, button->lifetime()); + const auto contextMenu = button->lifetime() + .make_state>(); + const auto showMenu = [=] { + if (!DictExists(id)) { + return false; + } + *contextMenu = base::make_unique_q(button); + contextMenu->get()->addAction( + tr::lng_settings_manage_remove_dictionary(tr::now), [=] { + Spellchecker::RemoveDictionary(id); + dictionaryRemoved->fire({}); + }); + contextMenu->get()->popup(QCursor::pos()); + return true; + }; + + base::install_event_filter(button, [=](not_null e) { + if (e->type() == QEvent::ContextMenu && showMenu()) { + return base::EventFilterResult::Cancel; + } + return base::EventFilterResult::Continue; + }); + return button; } @@ -281,11 +325,8 @@ void ManageDictionariesBox::prepare() { setTitle(tr::lng_settings_manage_dictionaries()); addButton(tr::lng_settings_save(), [=] { - auto enabledRows = inner->enabledRows(); _session->settings().setDictionariesEnabled( - enabledRows | ranges::views::filter( - DictExists - ) | ranges::to_vector); + FilterEnabledDict(inner->enabledRows())); _session->saveSettingsDelayed(); // Ignore boxClosing() when the Save button was pressed. lifetime().destroy(); @@ -294,7 +335,8 @@ void ManageDictionariesBox::prepare() { addButton(tr::lng_close(), [=] { closeBox(); }); boxClosing() | rpl::start_with_next([=] { - _session->settings().setDictionariesEnabled(initialEnabledRows); + _session->settings().setDictionariesEnabled( + FilterEnabledDict(initialEnabledRows)); _session->saveSettingsDelayed(); }, lifetime()); diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index a589f39c3..07e6ef012 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -134,6 +134,17 @@ bool DictionaryExists(int langId) { return (bad == end(kDictExtensions)); } +bool RemoveDictionary(int langId) { + if (!langId) { + return true; + } + const auto fileName = Spellchecker::LocaleFromLangId(langId).name(); + const auto folder = qsl("%1/%2/") + .arg(DictionariesPath()) + .arg(fileName); + return QDir(folder).removeRecursively(); +} + bool WriteDefaultDictionary() { // This is an unused function. const auto en = QLocale::English; diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h index 0c3a09c4d..db486ebde 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -27,6 +27,8 @@ MTP::DedicatedLoader::Location GetDownloadLocation(int id); [[nodiscard]] QString DictPathByLangId(int langId); bool UnpackDictionary(const QString &path, int langId); [[nodiscard]] bool DictionaryExists(int langId); +bool RemoveDictionary(int langId); +[[nodiscard]] bool IsEn(int langId); bool WriteDefaultDictionary(); std::vector Dictionaries(); From 311678af806027643199b0137aa42468d354db15 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 9 Feb 2020 02:22:39 +0300 Subject: [PATCH 119/140] Added ability to filter languages in dictionaries manager. --- .../boxes/dictionaries_manager.cpp | 94 +++++++++++++++++-- .../SourceFiles/boxes/dictionaries_manager.h | 2 + 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index cd8957ce5..e5e99cbd3 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -16,12 +16,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "mainwidget.h" #include "mtproto/dedicated_file_loader.h" +#include "spellcheck/spellcheck_utils.h" #include "styles/style_layers.h" #include "styles/style_settings.h" #include "styles/style_boxes.h" #include "ui/wrap/vertical_layout.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" +#include "ui/widgets/multi_select.h" #include "ui/widgets/popup_menu.h" #include "ui/wrap/slide_wrap.h" #include "ui/effects/animations.h" @@ -34,6 +36,13 @@ using namespace Storage::CloudBlob; using Loading = MTP::DedicatedLoader::Progress; using DictState = BlobState; +using QueryCallback = Fn; +constexpr auto kMaxQueryLength = 15; + +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) +#define OLD_QT +using QStringView = QString; +#endif class Loader : public BlobLoader { public: @@ -58,11 +67,13 @@ public: Inner(QWidget *parent, Dictionaries enabledDictionaries); Dictionaries enabledRows() const; + QueryCallback queryCallback() const; private: void setupContent(Dictionaries enabledDictionaries); Dictionaries _enabledRows; + QueryCallback _queryCallback; }; @@ -115,12 +126,27 @@ void Loader::unpack(const QString &path) { void Loader::destroy() { } +auto CreateMultiSelect(QWidget *parent) { + const auto result = Ui::CreateChild( + parent, + st::contactsMultiSelect, + tr::lng_participant_filter()); + + result->resizeToWidth(st::boxWidth); + result->moveToLeft(0, 0); + return result; +} + Inner::Inner( QWidget *parent, Dictionaries enabledDictionaries) : RpWidget(parent) { setupContent(std::move(enabledDictionaries)); } +QueryCallback Inner::queryCallback() const { + return _queryCallback; +} + Dictionaries Inner::enabledRows() const { return _enabledRows; } @@ -128,11 +154,19 @@ Dictionaries Inner::enabledRows() const { auto AddButtonWithLoader( not_null content, const Spellchecker::Dict &dict, - bool buttonEnabled) { + bool buttonEnabled, + rpl::producer query) { const auto id = dict.id; buttonEnabled &= DictExists(id); - const auto button = content->add( + const auto locale = Spellchecker::LocaleFromLangId(id); + const std::vector indexList = { + dict.name, + QLocale::languageToString(locale.language()), + QLocale::countryToString(locale.country()) + }; + + const auto wrap = content->add( object_ptr>( content, object_ptr( @@ -141,8 +175,18 @@ auto AddButtonWithLoader( st::dictionariesSectionButton ) ) - )->entity(); + ); + const auto button = wrap->entity(); + std::move( + query + ) | rpl::start_with_next([=](auto string) { + wrap->toggle( + ranges::any_of(indexList, [&](const QString &s) { + return s.startsWith(string, Qt::CaseInsensitive); + }), + anim::type::instant); + }, button->lifetime()); const auto localLoader = button->lifetime() .make_state>(); @@ -283,12 +327,16 @@ auto AddButtonWithLoader( void Inner::setupContent(Dictionaries enabledDictionaries) { const auto content = Ui::CreateChild(this); + const auto queryStream = content->lifetime() + .make_state>(); + for (const auto &dict : Spellchecker::Dictionaries()) { const auto id = dict.id; const auto row = AddButtonWithLoader( content, dict, - ranges::contains(enabledDictionaries, id)); + ranges::contains(enabledDictionaries, id), + queryStream->events()); row->toggledValue( ) | rpl::start_with_next([=](auto enabled) { if (enabled) { @@ -300,6 +348,13 @@ void Inner::setupContent(Dictionaries enabledDictionaries) { }, row->lifetime()); } + _queryCallback = [=](const QString &query) { + if (query.size() >= kMaxQueryLength) { + return; + } + queryStream->fire_copy(query); + }; + content->resizeToWidth(st::boxWidth); Ui::ResizeFitChild(this, content); } @@ -312,10 +367,25 @@ ManageDictionariesBox::ManageDictionariesBox( : _session(session) { } +void ManageDictionariesBox::setInnerFocus() { + _setInnerFocus(); +} + void ManageDictionariesBox::prepare() { - const auto inner = setInnerWidget(object_ptr( - this, - _session->settings().dictionariesEnabled())); + const auto multiSelect = CreateMultiSelect(this); + + const auto inner = setInnerWidget( + object_ptr( + this, + _session->settings().dictionariesEnabled()), + st::boxScroll, + multiSelect->height() + ); + + multiSelect->setQueryChangedCallback(inner->queryCallback()); + _setInnerFocus = [=] { + multiSelect->setInnerFocus(); + }; // The initial list of enabled rows may differ from the list of languages // in settings, so we should store it when box opens @@ -342,10 +412,16 @@ void ManageDictionariesBox::prepare() { setDimensionsToContent(st::boxWidth, inner); - inner->heightValue( + using namespace rpl::mappers; + const auto max = lifetime().make_state(0); + rpl::combine( + inner->heightValue(), + multiSelect->heightValue(), + _1 + _2 ) | rpl::start_with_next([=](int height) { using std::min; - setDimensions(st::boxWidth, min(height, st::boxMaxListHeight)); + accumulate_max(*max, height); + setDimensions(st::boxWidth, min(*max, st::boxMaxListHeight), true); }, inner->lifetime()); } diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.h b/Telegram/SourceFiles/boxes/dictionaries_manager.h index f819e140d..f137a76ca 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.h +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.h @@ -25,9 +25,11 @@ public: protected: void prepare() override; + void setInnerFocus() override; private: const not_null _session; + Fn _setInnerFocus; }; From 9daf362df6ca723788c24a035339f671e11a8c84 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 11 Feb 2020 12:11:09 +0300 Subject: [PATCH 120/140] Added label with state to "Manage dictionaries" button. --- .../chat_helpers/spellchecker_common.cpp | 38 +++++++++++++++++++ .../chat_helpers/spellchecker_common.h | 2 + .../settings/settings_advanced.cpp | 4 +- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index 07e6ef012..05fd9837a 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -171,6 +171,44 @@ bool WriteDefaultDictionary() { return false; } +rpl::producer ButtonManageDictsState( + not_null session) { + if (Platform::Spellchecker::IsSystemSpellchecker()) { + return rpl::single(QString()); + } + const auto computeString = [=] { + if (!session->settings().spellcheckerEnabled()) { + return QString(); + } + if (!session->settings().dictionariesEnabled().size()) { + return QString(); + } + const auto dicts = session->settings().dictionariesEnabled(); + const auto filtered = ranges::view::all( + dicts + ) | ranges::views::filter( + DictionaryExists + ) | ranges::to_vector; + const auto active = Platform::Spellchecker::ActiveLanguages(); + + return (active.size() == filtered.size()) + ? QString::number(filtered.size()) + : tr::lng_contacts_loading(tr::now); + }; + const auto emptyValue = [] { return rpl::empty_value(); }; + return rpl::single( + computeString() + ) | rpl::then( + rpl::merge( + Spellchecker::SupportedScriptsChanged(), + session->settings().dictionariesEnabledChanges( + ) | rpl::map(emptyValue), + session->settings().spellcheckerEnabledChanges( + ) | rpl::map(emptyValue) + ) | rpl::map(computeString) + ); +} + void Start(not_null session) { Spellchecker::SetPhrases({ { { &ph::lng_spellchecker_add, tr::lng_spellchecker_add() }, diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h index db486ebde..e7c560923 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -34,6 +34,8 @@ bool WriteDefaultDictionary(); std::vector Dictionaries(); void Start(not_null session); +[[nodiscard]] rpl::producer ButtonManageDictsState( + not_null session); } // namespace Spellchecker diff --git a/Telegram/SourceFiles/settings/settings_advanced.cpp b/Telegram/SourceFiles/settings/settings_advanced.cpp index d2e61809d..3b250a21f 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced.cpp @@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK #include "boxes/dictionaries_manager.h" +#include "chat_helpers/spellchecker_common.h" #include "spellcheck/platform/platform_spellcheck.h" #endif // !TDESKTOP_DISABLE_SPELLCHECK @@ -288,9 +289,10 @@ void SetupSpellchecker( container, object_ptr(container))); - AddButton( + AddButtonWithLabel( sliding->entity(), tr::lng_settings_manage_dictionaries(), + Spellchecker::ButtonManageDictsState(session), st::settingsButton )->addClickHandler([=] { Ui::show(Box(session)); From bb8aead078f23b994dfdf702600d103f7f4cfd92 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 21 Feb 2020 21:55:11 +0300 Subject: [PATCH 121/140] Added sequential background dictionary loader. - Moved the Loader from the dictionaries manager to the spellchecker common space as a DictLoader. --- .../boxes/dictionaries_manager.cpp | 120 ++++++++------- .../chat_helpers/spellchecker_common.cpp | 141 +++++++++++++++++- .../chat_helpers/spellchecker_common.h | 32 ++++ .../SourceFiles/storage/storage_cloud_blob.h | 2 +- 4 files changed, 239 insertions(+), 56 deletions(-) diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index e5e99cbd3..1d8940251 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -44,24 +44,6 @@ constexpr auto kMaxQueryLength = 15; using QStringView = QString; #endif -class Loader : public BlobLoader { -public: - Loader( - QObject *parent, - int id, - MTP::DedicatedLoader::Location location, - const QString &folder, - int size, - Fn destroyCallback); - - void destroy() override; - void unpack(const QString &path) override; - -private: - Fn _destroyCallback; - -}; - class Inner : public Ui::RpWidget { public: Inner(QWidget *parent, Dictionaries enabledDictionaries); @@ -101,31 +83,6 @@ QString StateDescription(const DictState &state) { tr::lng_settings_manage_enabled_dictionary); } -Loader::Loader( - QObject *parent, - int id, - MTP::DedicatedLoader::Location location, - const QString &folder, - int size, - Fn destroyCallback) -: BlobLoader(parent, id, location, folder, size) -, _destroyCallback(std::move(destroyCallback)) { -} - -void Loader::unpack(const QString &path) { - Expects(_destroyCallback); - crl::async([=] { - const auto success = Spellchecker::UnpackDictionary(path, id()); - if (success) { - QFile(path).remove(); - } - crl::on_main(success ? _destroyCallback : [=] { fail(); }); - }); -} - -void Loader::destroy() { -} - auto CreateMultiSelect(QWidget *parent) { const auto result = Ui::CreateChild( parent, @@ -188,6 +145,9 @@ auto AddButtonWithLoader( anim::type::instant); }, button->lifetime()); + using Loader = Spellchecker::DictLoader; + using GlobalLoaderPtr = std::shared_ptr>; + const auto localLoader = button->lifetime() .make_state>(); const auto localLoaderValues = button->lifetime() @@ -200,11 +160,45 @@ auto AddButtonWithLoader( setLocalLoader(nullptr); }; - const auto buttonState = button->lifetime() .make_state>(); const auto dictionaryRemoved = button->lifetime() .make_state>(); + const auto dictionaryFromGlobalLoader = button->lifetime() + .make_state>(); + + const auto globalLoader = button->lifetime() + .make_state(); + + const auto rawGlobalLoaderPtr = [=]() -> Loader* { + if (!globalLoader || !*globalLoader || !*globalLoader->get()) { + return nullptr; + } + return globalLoader->get()->get(); + }; + + const auto setGlobalLoaderPtr = [=](GlobalLoaderPtr loader) { + if (localLoader->get()) { + if (loader && loader->get()) { + loader->get()->destroy(); + } + return; + } + *globalLoader = std::move(loader); + localLoaderValues->fire(rawGlobalLoaderPtr()); + if (rawGlobalLoaderPtr()) { + dictionaryFromGlobalLoader->fire({}); + } + }; + + Spellchecker::GlobalLoaderChanged( + ) | rpl::start_with_next([=](int langId) { + if (!langId && rawGlobalLoaderPtr()) { + setGlobalLoaderPtr(nullptr); + } else if (langId == id) { + setGlobalLoaderPtr(Spellchecker::GlobalLoader()); + } + }, button->lifetime()); const auto label = Ui::CreateChild( button, @@ -243,21 +237,29 @@ auto AddButtonWithLoader( buttonEnabled ) | rpl::then( rpl::merge( - dictionaryRemoved->events(), - buttonState->value( - ) | rpl::filter([](const DictState &state) { - return state.is(); - }) | rpl::map([] { - return rpl::empty_value(); + // Events to toggle on. + dictionaryFromGlobalLoader->events( + ) | rpl::map([] { + return true; + }), + // Events to toggle off. + rpl::merge( + dictionaryRemoved->events(), + buttonState->value( + ) | rpl::filter([](const DictState &state) { + return state.is(); + }) | rpl::map([] { + return rpl::empty_value(); + }) + ) | rpl::map([] { + return false; }) - ) | rpl::map([]() { - return false; - }) + ) ) ); *buttonState = localLoaderValues->events_starting_with( - localLoader->get() + rawGlobalLoaderPtr() ? rawGlobalLoaderPtr() : localLoader->get() ) | rpl::map([=](Loader *loader) { return (loader && loader->id() == id) ? loader->state() @@ -292,6 +294,10 @@ auto AddButtonWithLoader( Spellchecker::GetDownloadSize(id), crl::guard(weak, destroyLocalLoader))); } else if (!toggled && state.is()) { + if (const auto g = rawGlobalLoaderPtr()) { + g->destroy(); + return; + } if (localLoader && localLoader->get()->id() == id) { destroyLocalLoader(); } @@ -321,6 +327,12 @@ auto AddButtonWithLoader( return base::EventFilterResult::Continue; }); + if (const auto g = Spellchecker::GlobalLoader()) { + if (g.get() && g->get()->id() == id) { + setGlobalLoaderPtr(g); + } + } + return button; } diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index 05fd9837a..cf580ae53 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -9,13 +9,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "base/platform/base_platform_info.h" +#include "base/zlib_help.h" +#include "data/data_session.h" +#include "lang/lang_instance.h" #include "lang/lang_keys.h" #include "main/main_session.h" -#include "base/zlib_help.h" +#include "mainwidget.h" #include "spellcheck/platform/platform_spellcheck.h" #include "spellcheck/spellcheck_utils.h" #include "spellcheck/spellcheck_value.h" +#include + namespace Spellchecker { namespace { @@ -24,12 +30,20 @@ using namespace Storage::CloudBlob; constexpr auto kDictExtensions = { "dic", "aff" }; +// 31 - QLocale::English, 91 - QLocale::Portuguese. +constexpr auto kLangsForLWC = { 31, 91 }; +// 225 - QLocale::UnitesStates, 30 - QLocale::Brazil. +constexpr auto kDefaultCountries = { 225, 30 }; + // Language With Country. inline auto LWC(QLocale::Country country) { const auto l = QLocale::matchingLocales( QLocale::AnyLanguage, QLocale::AnyScript, country)[0]; + if (ranges::contains(kDefaultCountries, country)) { + return int(l.language()); + } return (l.language() * 1000) + country; } @@ -90,8 +104,104 @@ bool IsGoodPartName(const QString &name) { }) != end(kDictExtensions); } +using DictLoaderPtr = std::shared_ptr>; + +DictLoaderPtr BackgroundLoader; +rpl::event_stream BackgroundLoaderChanged; + +void SetBackgroundLoader(DictLoaderPtr loader) { + BackgroundLoader = std::move(loader); +} + +void DownloadDictionaryInBackground( + not_null session, + int counter, + std::vector langs) { + const auto id = langs[counter]; + counter++; + const auto destroyer = [=] { + // This is a temporary workaround. + const auto copyId = id; + const auto copyLangs = langs; + const auto copySession = session; + const auto copyCounter = counter; + BackgroundLoader = nullptr; + BackgroundLoaderChanged.fire(0); + + if (DictionaryExists(copyId)) { + auto dicts = copySession->settings().dictionariesEnabled(); + if (!ranges::contains(dicts, copyId)) { + dicts.push_back(copyId); + copySession->settings().setDictionariesEnabled(std::move(dicts)); + copySession->saveSettingsDelayed(); + } + } + + if (copyCounter >= copyLangs.size()) { + return; + } + DownloadDictionaryInBackground(copySession, copyCounter, copyLangs); + }; + if (DictionaryExists(id)) { + destroyer(); + return; + } + + auto sharedLoader = std::make_shared>(); + *sharedLoader = base::make_unique_q( + App::main(), + id, + GetDownloadLocation(id), + DictPathByLangId(id), + GetDownloadSize(id), + crl::guard(session, destroyer)); + SetBackgroundLoader(std::move(sharedLoader)); + BackgroundLoaderChanged.fire_copy(id); +} + } // namespace +DictLoaderPtr GlobalLoader() { + return BackgroundLoader; +} + +rpl::producer GlobalLoaderChanged() { + return BackgroundLoaderChanged.events(); +} + +DictLoader::DictLoader( + QObject *parent, + int id, + MTP::DedicatedLoader::Location location, + const QString &folder, + int size, + Fn destroyCallback) +: BlobLoader(parent, id, location, folder, size) +, _destroyCallback(std::move(destroyCallback)) { +} + +void DictLoader::unpack(const QString &path) { + Expects(_destroyCallback); + crl::async([=] { + const auto success = Spellchecker::UnpackDictionary(path, id()); + if (success) { + QFile(path).remove(); + } + crl::on_main(success ? _destroyCallback : [=] { fail(); }); + }); +} + +void DictLoader::destroy() { + Expects(_destroyCallback); + + _destroyCallback(); +} + +void DictLoader::fail() { + BlobLoader::fail(); + destroy(); +} + std::vector Dictionaries() { return kDictionaries | ranges::to_vector; } @@ -209,6 +319,24 @@ rpl::producer ButtonManageDictsState( ); } +std::vector DefaultLanguages() { + std::vector langs; + + const auto method = QGuiApplication::inputMethod(); + langs.reserve(method ? 3 : 2); + if (method) { + const auto loc = method->locale(); + const auto locLang = int(loc.language()); + langs.push_back(ranges::contains(kLangsForLWC, locLang) + ? LWC(loc.country()) + : locLang); + } + langs.push_back(QLocale(Platform::SystemLanguage()).language()); + langs.push_back(QLocale(Lang::Current().id()).language()); + + return langs; +} + void Start(not_null session) { Spellchecker::SetPhrases({ { { &ph::lng_spellchecker_add, tr::lng_spellchecker_add() }, @@ -231,6 +359,17 @@ void Start(not_null session) { ? session->settings().dictionariesEnabled() : std::vector()); }, session->lifetime()); + + session->data().contactsLoaded().changes( + ) | rpl::start_with_next([=](bool loaded) { + if (!loaded) { + return; + } + + DownloadDictionaryInBackground(session, 0, DefaultLanguages()); + }, session->lifetime()); + + } if (session->settings().spellcheckerEnabled()) { Platform::Spellchecker::UpdateLanguages( diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h index e7c560923..203c4e047 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK #include "storage/storage_cloud_blob.h" +#include "base/unique_qptr.h" namespace Main { class Session; @@ -37,6 +38,37 @@ void Start(not_null session); [[nodiscard]] rpl::producer ButtonManageDictsState( not_null session); +std::vector DefaultLanguages(); + +class DictLoader : public Storage::CloudBlob::BlobLoader { +public: + DictLoader( + QObject *parent, + int id, + MTP::DedicatedLoader::Location location, + const QString &folder, + int size, + Fn destroyCallback); + + void destroy() override; + + rpl::lifetime &lifetime() { + return _lifetime; + } + +private: + void unpack(const QString &path) override; + void fail() override; + + Fn _destroyCallback; + + rpl::lifetime _lifetime; + +}; + +std::shared_ptr> GlobalLoader(); +rpl::producer GlobalLoaderChanged(); + } // namespace Spellchecker #endif // !TDESKTOP_DISABLE_SPELLCHECK diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.h b/Telegram/SourceFiles/storage/storage_cloud_blob.h index 4a1b485bc..af6301ca0 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_blob.h +++ b/Telegram/SourceFiles/storage/storage_cloud_blob.h @@ -91,7 +91,7 @@ public: virtual void unpack(const QString &path) = 0; protected: - void fail(); + virtual void fail(); const QString _folder; From bc6e1e7a0d06e2945eb3ba55c0e27e8f00130f34 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 20 Feb 2020 22:27:21 +0300 Subject: [PATCH 122/140] Added new setting for automatic dictionaries download. --- Telegram/Resources/langs/lang.strings | 1 + .../chat_helpers/spellchecker_common.cpp | 28 ++++++++++--------- Telegram/SourceFiles/main/main_settings.cpp | 6 ++++ Telegram/SourceFiles/main/main_settings.h | 14 ++++++++++ .../settings/settings_advanced.cpp | 21 ++++++++++++-- 5 files changed, 54 insertions(+), 16 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index db08ef19f..9899731a2 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -423,6 +423,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_spellchecker" = "Spell checker"; "lng_settings_system_spellchecker" = "Use system spell checker"; "lng_settings_custom_spellchecker" = "Use spell checker"; +"lng_settings_auto_download_dictionaries" = "Automatic dictionaries download"; "lng_settings_manage_dictionaries" = "Manage dictionaries"; "lng_settings_manage_enabled_dictionary" = "Dictionary is enabled"; "lng_settings_manage_remove_dictionary" = "Remove Dictionary"; diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index cf580ae53..7beca4351 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -343,37 +343,39 @@ void Start(not_null session) { { &ph::lng_spellchecker_remove, tr::lng_spellchecker_remove() }, { &ph::lng_spellchecker_ignore, tr::lng_spellchecker_ignore() }, } }); + const auto settings = &session->settings(); if (!Platform::Spellchecker::IsSystemSpellchecker()) { Spellchecker::SetWorkingDirPath(DictionariesPath()); - session->settings().dictionariesEnabledChanges( + settings->dictionariesEnabledChanges( ) | rpl::start_with_next([](auto dictionaries) { Platform::Spellchecker::UpdateLanguages(dictionaries); }, session->lifetime()); - session->settings().spellcheckerEnabledChanges( + settings->spellcheckerEnabledChanges( ) | rpl::start_with_next([=](auto enabled) { Platform::Spellchecker::UpdateLanguages( enabled - ? session->settings().dictionariesEnabled() + ? settings->dictionariesEnabled() : std::vector()); }, session->lifetime()); - session->data().contactsLoaded().changes( - ) | rpl::start_with_next([=](bool loaded) { - if (!loaded) { - return; - } - - DownloadDictionaryInBackground(session, 0, DefaultLanguages()); - }, session->lifetime()); + if (settings->autoDownloadDictionaries()) { + session->data().contactsLoaded().changes( + ) | rpl::start_with_next([=](bool loaded) { + if (!loaded) { + return; + } + DownloadDictionaryInBackground(session, 0, DefaultLanguages()); + }, session->lifetime()); + } } - if (session->settings().spellcheckerEnabled()) { + if (settings->spellcheckerEnabled()) { Platform::Spellchecker::UpdateLanguages( - session->settings().dictionariesEnabled()); + settings->dictionariesEnabled()); } } diff --git a/Telegram/SourceFiles/main/main_settings.cpp b/Telegram/SourceFiles/main/main_settings.cpp index 95beb2bd9..b9f1f07b1 100644 --- a/Telegram/SourceFiles/main/main_settings.cpp +++ b/Telegram/SourceFiles/main/main_settings.cpp @@ -122,6 +122,7 @@ QByteArray Settings::serialize() const { for (const auto i : _variables.dictionariesEnabled.current()) { stream << quint64(i); } + stream << qint32(_variables.autoDownloadDictionaries.current() ? 1 : 0); } return result; } @@ -175,6 +176,7 @@ void Settings::constructFromSerialized(const QByteArray &serialized) { qint32 videoPlaybackSpeed = SerializePlaybackSpeed(_variables.videoPlaybackSpeed.current()); QByteArray videoPipGeometry = _variables.videoPipGeometry; std::vector dictionariesEnabled; + qint32 autoDownloadDictionaries = _variables.autoDownloadDictionaries.current() ? 1 : 0; stream >> versionTag; if (versionTag == kVersionTag) { @@ -312,6 +314,9 @@ void Settings::constructFromSerialized(const QByteArray &serialized) { } } } + if (!stream.atEnd()) { + stream >> autoDownloadDictionaries; + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Main::Settings::constructFromSerialized()")); @@ -402,6 +407,7 @@ void Settings::constructFromSerialized(const QByteArray &serialized) { _variables.videoPlaybackSpeed = DeserializePlaybackSpeed(videoPlaybackSpeed); _variables.videoPipGeometry = videoPipGeometry; _variables.dictionariesEnabled = std::move(dictionariesEnabled); + _variables.autoDownloadDictionaries = (autoDownloadDictionaries == 1); } void Settings::setSupportChatsTimeSlice(int slice) { diff --git a/Telegram/SourceFiles/main/main_settings.h b/Telegram/SourceFiles/main/main_settings.h index ba0d8b9c4..264f51f05 100644 --- a/Telegram/SourceFiles/main/main_settings.h +++ b/Telegram/SourceFiles/main/main_settings.h @@ -253,6 +253,19 @@ public: return _variables.dictionariesEnabled.changes(); } + void setAutoDownloadDictionaries(bool value) { + _variables.autoDownloadDictionaries = value; + } + bool autoDownloadDictionaries() const { + return _variables.autoDownloadDictionaries.current(); + } + rpl::producer autoDownloadDictionariesValue() const { + return _variables.autoDownloadDictionaries.value(); + } + rpl::producer autoDownloadDictionariesChanges() const { + return _variables.autoDownloadDictionaries.changes(); + } + [[nodiscard]] float64 videoPlaybackSpeed() const { return _variables.videoPlaybackSpeed.current(); } @@ -311,6 +324,7 @@ private: rpl::variable videoPlaybackSpeed = 1.; QByteArray videoPipGeometry; rpl::variable> dictionariesEnabled; + rpl::variable autoDownloadDictionaries = true; static constexpr auto kDefaultSupportChatsLimitSlice = 7 * 24 * 60 * 60; diff --git a/Telegram/SourceFiles/settings/settings_advanced.cpp b/Telegram/SourceFiles/settings/settings_advanced.cpp index 3b250a21f..95c9f369e 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced.cpp @@ -261,6 +261,7 @@ void SetupSpellchecker( not_null container) { #ifndef TDESKTOP_DISABLE_SPELLCHECK const auto session = &controller->session(); + const auto settings = &session->settings(); const auto isSystem = Platform::Spellchecker::IsSystemSpellchecker(); const auto button = AddButton( container, @@ -269,14 +270,14 @@ void SetupSpellchecker( : tr::lng_settings_custom_spellchecker(), st::settingsButton )->toggleOn( - rpl::single(session->settings().spellcheckerEnabled()) + rpl::single(settings->spellcheckerEnabled()) ); button->toggledValue( ) | rpl::filter([=](bool enabled) { - return (enabled != session->settings().spellcheckerEnabled()); + return (enabled != settings->spellcheckerEnabled()); }) | rpl::start_with_next([=](bool enabled) { - session->settings().setSpellcheckerEnabled(enabled); + settings->setSpellcheckerEnabled(enabled); session->saveSettingsDelayed(); }, container->lifetime()); @@ -289,6 +290,20 @@ void SetupSpellchecker( container, object_ptr(container))); + AddButton( + sliding->entity(), + tr::lng_settings_auto_download_dictionaries(), + st::settingsButton + )->toggleOn( + rpl::single(settings->autoDownloadDictionaries()) + )->toggledValue( + ) | rpl::filter([=](bool enabled) { + return (enabled != settings->autoDownloadDictionaries()); + }) | rpl::start_with_next([=](bool enabled) { + settings->setAutoDownloadDictionaries(enabled); + session->saveSettingsDelayed(); + }, sliding->entity()->lifetime()); + AddButtonWithLabel( sliding->entity(), tr::lng_settings_manage_dictionaries(), From 8734ebe4c48228c080a1f42da034890809a1d811 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 21 Feb 2020 00:44:25 +0300 Subject: [PATCH 123/140] Added auto download of new dictionary when input locale is changed. --- .../chat_helpers/spellchecker_common.cpp | 128 +++++++++++++----- 1 file changed, 95 insertions(+), 33 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index 7beca4351..70f5aac44 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "spellcheck/spellcheck_value.h" #include +#include namespace Spellchecker { @@ -47,6 +48,14 @@ inline auto LWC(QLocale::Country country) { return (l.language() * 1000) + country; } +inline auto LanguageFromLocale(QLocale loc) { + const auto locLang = int(loc.language()); + return (ranges::contains(kLangsForLWC, locLang) + && (loc.country() != QLocale::AnyCountry)) + ? LWC(loc.country()) + : locLang; +} + const auto kDictionaries = { Dict{{ QLocale::English, 649, 174'516, "English" }}, // en_US Dict{{ QLocale::Bulgarian, 594, 229'658, "\xd0\x91\xd1\x8a\xd0\xbb\xd0\xb3\xd0\xb0\xd1\x80\xd1\x81\xd0\xba\xd0\xb8" }}, // bg_BG @@ -92,6 +101,10 @@ const auto kDictionaries = { // The Tajik code is 'tg_TG' in Chromium, but QT has only 'tg_TJ'. }; +inline auto IsSupportedLang(int lang) { + return ranges::contains(kDictionaries, lang, &Dict::id); +} + void EnsurePath() { if (!QDir::current().mkpath(Spellchecker::DictionariesPath())) { LOG(("App Error: Could not create dictionaries path.")); @@ -322,17 +335,20 @@ rpl::producer ButtonManageDictsState( std::vector DefaultLanguages() { std::vector langs; + const auto append = [&](const auto loc) { + const auto l = LanguageFromLocale(loc); + if (!ranges::contains(langs, l) && IsSupportedLang(l)) { + langs.push_back(l); + } + }; + const auto method = QGuiApplication::inputMethod(); langs.reserve(method ? 3 : 2); if (method) { - const auto loc = method->locale(); - const auto locLang = int(loc.language()); - langs.push_back(ranges::contains(kLangsForLWC, locLang) - ? LWC(loc.country()) - : locLang); + append(method->locale()); } - langs.push_back(QLocale(Platform::SystemLanguage()).language()); - langs.push_back(QLocale(Lang::Current().id()).language()); + append(QLocale(Platform::SystemLanguage())); + append(QLocale(Lang::LanguageIdOrDefault(Lang::Current().id()))); return langs; } @@ -345,38 +361,84 @@ void Start(not_null session) { } }); const auto settings = &session->settings(); - if (!Platform::Spellchecker::IsSystemSpellchecker()) { - Spellchecker::SetWorkingDirPath(DictionariesPath()); - - settings->dictionariesEnabledChanges( - ) | rpl::start_with_next([](auto dictionaries) { - Platform::Spellchecker::UpdateLanguages(dictionaries); - }, session->lifetime()); - - settings->spellcheckerEnabledChanges( - ) | rpl::start_with_next([=](auto enabled) { + const auto guard = gsl::finally([=]{ + if (settings->spellcheckerEnabled()) { Platform::Spellchecker::UpdateLanguages( - enabled - ? settings->dictionariesEnabled() - : std::vector()); + settings->dictionariesEnabled()); + } + }); + + if (Platform::Spellchecker::IsSystemSpellchecker()) { + return; + } + + Spellchecker::SetWorkingDirPath(DictionariesPath()); + + settings->dictionariesEnabledChanges( + ) | rpl::start_with_next([](auto dictionaries) { + Platform::Spellchecker::UpdateLanguages(dictionaries); + }, session->lifetime()); + + settings->spellcheckerEnabledChanges( + ) | rpl::start_with_next([=](auto enabled) { + Platform::Spellchecker::UpdateLanguages( + enabled + ? settings->dictionariesEnabled() + : std::vector()); + }, session->lifetime()); + + const auto method = QGuiApplication::inputMethod(); + + const auto connectInput = [=] { + if (!method || !settings->spellcheckerEnabled()) { + return; + } + auto callback = [=] { + if (BackgroundLoader) { + return; + } + const auto l = LanguageFromLocale(method->locale()); + if (!IsSupportedLang(l) || DictionaryExists(l)) { + return; + } + crl::on_main(session, [=] { + DownloadDictionaryInBackground(session, 0, { l }); + }); + }; + QObject::connect( + method, + &QInputMethod::localeChanged, + std::move(callback)); + }; + + if (settings->autoDownloadDictionaries()) { + session->data().contactsLoaded().changes( + ) | rpl::start_with_next([=](bool loaded) { + if (!loaded) { + return; + } + + DownloadDictionaryInBackground(session, 0, DefaultLanguages()); }, session->lifetime()); - if (settings->autoDownloadDictionaries()) { - session->data().contactsLoaded().changes( - ) | rpl::start_with_next([=](bool loaded) { - if (!loaded) { - return; - } + connectInput(); + } - DownloadDictionaryInBackground(session, 0, DefaultLanguages()); - }, session->lifetime()); + rpl::combine( + settings->spellcheckerEnabledValue(), + settings->autoDownloadDictionariesValue() + ) | rpl::start_with_next([=](bool spell, bool download) { + if (spell && download) { + connectInput(); + return; } + QObject::disconnect( + method, + &QInputMethod::localeChanged, + nullptr, + nullptr); + }, session->lifetime()); - } - if (settings->spellcheckerEnabled()) { - Platform::Spellchecker::UpdateLanguages( - settings->dictionariesEnabled()); - } } } // namespace Spellchecker From 0ca09300666db000e3d77dbb9151545bf19b88df Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 21 Feb 2020 12:48:24 +0300 Subject: [PATCH 124/140] Updated context menu for spellchecker. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/chat_helpers/message_field.cpp | 6 +++++- Telegram/SourceFiles/chat_helpers/message_field.h | 1 + Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 9899731a2..02c23cbb8 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1616,6 +1616,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_formatting_link_url" = "URL"; "lng_formatting_link_create" = "Create"; +"lng_spellchecker_submenu" = "Spelling"; "lng_spellchecker_add" = "Add to Dictionary"; "lng_spellchecker_remove" = "Remove from Dictionary"; "lng_spellchecker_ignore" = "Ignore word"; diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 1bd0b447b..215932831 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -282,7 +282,11 @@ void InitSpellchecker( #ifndef TDESKTOP_DISABLE_SPELLCHECK const auto s = Ui::CreateChild( field.get(), - session->settings().spellcheckerEnabledValue()); + session->settings().spellcheckerEnabledValue(), + Spellchecker::SpellingHighlighter::CustomContextMenuItem{ + tr::lng_settings_manage_dictionaries(tr::now), + [=] { Ui::show(Box(session)); } + }); field->setExtendedContextMenu(s->contextMenuCreated()); #endif // TDESKTOP_DISABLE_SPELLCHECK } diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h index 8f95a9323..812ca859b 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.h +++ b/Telegram/SourceFiles/chat_helpers/message_field.h @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/qt_connection.h" #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "boxes/dictionaries_manager.h" #include "spellcheck/spelling_highlighter.h" #endif // TDESKTOP_DISABLE_SPELLCHECK diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index 70f5aac44..ee4b0d7c6 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -355,6 +355,7 @@ std::vector DefaultLanguages() { void Start(not_null session) { Spellchecker::SetPhrases({ { + { &ph::lng_spellchecker_submenu, tr::lng_spellchecker_submenu() }, { &ph::lng_spellchecker_add, tr::lng_spellchecker_add() }, { &ph::lng_spellchecker_remove, tr::lng_spellchecker_remove() }, { &ph::lng_spellchecker_ignore, tr::lng_spellchecker_ignore() }, From 9fe64deea047c69841f53a433dd18510122b869f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 21 Feb 2020 13:04:46 +0300 Subject: [PATCH 125/140] Updated lib_spellcheck. --- Telegram/lib_spellcheck | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_spellcheck b/Telegram/lib_spellcheck index 691cda5b2..b7a057562 160000 --- a/Telegram/lib_spellcheck +++ b/Telegram/lib_spellcheck @@ -1 +1 @@ -Subproject commit 691cda5b223133396a53246c14f613ff04542628 +Subproject commit b7a057562c7a080e1ba92501c34551f16c2230e2 From 530b212f55560dbe77b3cb24f3e669c22eea1e28 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 19:55:48 +0400 Subject: [PATCH 126/140] Remove _USING_V110_SDK71_ on Windows. --- cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake b/cmake index 6dd044ae1..4c6923433 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 6dd044ae163bc67a7f0f0dbf6a2fa28b633b5fdf +Subproject commit 4c69234334eeb32f35da08307d0de1467fbce575 From 9979c220ce968f147656814d2aef2b026917dede Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Fri, 21 Feb 2020 19:35:22 +0400 Subject: [PATCH 127/140] Multiple sizes for linux tray icon --- .../platform/linux/main_window_linux.cpp | 227 ++++++++++-------- .../platform/linux/main_window_linux.h | 3 +- 2 files changed, 131 insertions(+), 99 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index fe5e75355..bd3f656ff 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -38,11 +38,11 @@ constexpr auto kAttentionPanelTrayIconName = "telegram-attention-panel"_cs; constexpr auto kSNIWatcherService = "org.kde.StatusNotifierWatcher"_cs; constexpr auto kTrayIconFilename = "tdesktop-trayicon-XXXXXX.png"_cs; -int32 _trayIconSize = 22; -bool _trayIconMuted = true; -int32 _trayIconCount = 0; -QImage _trayIconImageBack, _trayIconImage; -QString _trayIconThemeName, _trayIconName; +bool TrayIconMuted = true; +int32 TrayIconCount = 0; +base::flat_map TrayIconImageBack; +QIcon TrayIcon; +QString TrayIconThemeName, TrayIconName; QString GetPanelIconName() { const auto counter = Core::App().unreadBadge(); @@ -73,92 +73,133 @@ QString GetTrayIconName() { return QString(); } -QImage TrayIconImageGen() { +QIcon TrayIconGen() { + const auto iconThemeName = QIcon::themeName(); + const auto iconName = GetTrayIconName(); + + if (qEnvironmentVariableIsSet(kDisableTrayCounter.utf8()) + && !iconName.isEmpty()) { + if (TrayIcon.isNull() + || iconThemeName != TrayIconThemeName + || iconName != TrayIconName) { + TrayIcon = QIcon::fromTheme(iconName); + TrayIconThemeName = iconThemeName; + TrayIconName = iconName; + } + + return TrayIcon; + } + const auto counter = Core::App().unreadBadge(); const auto muted = Core::App().unreadBadgeMuted(); const auto counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter; - const auto iconThemeName = QIcon::themeName(); - const auto iconName = GetTrayIconName(); - const auto desiredSize = QSize(_trayIconSize, _trayIconSize); + if (TrayIcon.isNull() + || iconThemeName != TrayIconThemeName + || iconName != TrayIconName + || muted != TrayIconMuted + || counterSlice != TrayIconCount) { + QIcon result; + QIcon systemIcon; - if (_trayIconImage.isNull() - || _trayIconImage.size() != desiredSize - || iconThemeName != _trayIconThemeName - || iconName != _trayIconName - || muted != _trayIconMuted - || counterSlice != _trayIconCount) { - if (_trayIconImageBack.isNull() - || _trayIconImageBack.size() != desiredSize - || iconThemeName != _trayIconThemeName - || iconName != _trayIconName) { - if (!iconName.isEmpty()) { - const auto systemIcon = QIcon::fromTheme(iconName); + const auto iconSizes = { + 16, + 22, + 24, + 32, + 48, + 64 + }; - if (systemIcon.actualSize(desiredSize) == desiredSize) { - _trayIconImageBack = systemIcon - .pixmap(desiredSize) - .toImage(); + for (const auto iconSize : iconSizes) { + auto ¤tImageBack = TrayIconImageBack[iconSize]; + const auto desiredSize = QSize(iconSize, iconSize); + + if (currentImageBack.isNull() + || iconThemeName != TrayIconThemeName + || iconName != TrayIconName) { + if (!iconName.isEmpty()) { + if(systemIcon.isNull()) { + systemIcon = QIcon::fromTheme(iconName); + } + + if (systemIcon.actualSize(desiredSize) == desiredSize) { + currentImageBack = systemIcon + .pixmap(desiredSize) + .toImage(); + } else { + const auto availableSizes = systemIcon + .availableSizes(); + + const auto biggestSize = ranges::max_element( + availableSizes, + std::less<>(), + &QSize::width); + + currentImageBack = systemIcon + .pixmap(*biggestSize) + .toImage(); + } } else { - const auto biggestSize = systemIcon - .availableSizes() - .last(); - - _trayIconImageBack = systemIcon - .pixmap(biggestSize) - .toImage(); + currentImageBack = Core::App().logo(); + } + + if (currentImageBack.size() != desiredSize) { + currentImageBack = currentImageBack.scaled( + desiredSize, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); } - } else { - _trayIconImageBack = Core::App().logo(); } - if (_trayIconImageBack.size() != desiredSize) { - _trayIconImageBack = _trayIconImageBack.scaled( - desiredSize, - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation); + auto iconImage = currentImageBack; + TrayIconMuted = muted; + TrayIconCount = counterSlice; + TrayIconThemeName = iconThemeName; + TrayIconName = iconName; + + if (!qEnvironmentVariableIsSet(kDisableTrayCounter.utf8()) + && counter > 0) { + QPainter p(&iconImage); + int32 layerSize = -16; + + if (iconSize >= 48) { + layerSize = -32; + } else if (iconSize >= 36) { + layerSize = -24; + } else if (iconSize >= 32) { + layerSize = -20; + } + + auto &bg = muted + ? st::trayCounterBgMute + : st::trayCounterBg; + + auto &fg = st::trayCounterFg; + + auto layer = App::wnd()->iconWithCounter( + layerSize, + counter, + bg, + fg, + false); + + p.drawImage( + iconImage.width() - layer.width() - 1, + iconImage.height() - layer.height() - 1, + layer); } + + result.addPixmap(App::pixmapFromImageInPlace( + std::move(iconImage))); } - _trayIconImage = _trayIconImageBack; - _trayIconMuted = muted; - _trayIconCount = counterSlice; - _trayIconThemeName = iconThemeName; - _trayIconName = iconName; - - if (!qEnvironmentVariableIsSet(kDisableTrayCounter.utf8()) - && counter > 0) { - QPainter p(&_trayIconImage); - int32 layerSize = -16; - - if (_trayIconSize >= 48) { - layerSize = -32; - } else if (_trayIconSize >= 36) { - layerSize = -24; - } else if (_trayIconSize >= 32) { - layerSize = -20; - } - - auto &bg = (muted ? st::trayCounterBgMute : st::trayCounterBg); - auto &fg = st::trayCounterFg; - - auto layer = App::wnd()->iconWithCounter( - layerSize, - counter, - bg, - fg, - false); - - p.drawImage( - _trayIconImage.width() - layer.width() - 1, - _trayIconImage.height() - layer.height() - 1, - layer); - } + TrayIcon = result; } - return _trayIconImage; + return TrayIcon; } bool IsAppIndicator() { @@ -182,10 +223,7 @@ bool IsAppIndicator() { static bool NeedTrayIconFile() { // Hack for indicator-application, which doesn't handle icons sent across D-Bus: // save the icon to a temp file and set the icon name to that filename. - static const auto TrayIconFileNeeded = IsAppIndicator() - // Ubuntu's tray extension doesn't zoom image data, but zooms image file - || DesktopEnvironment::IsGnome(); - + static const auto TrayIconFileNeeded = IsAppIndicator(); return TrayIconFileNeeded; } @@ -196,12 +234,14 @@ static inline QString TrayIconFileTemplate() { } std::unique_ptr TrayIconFile( - const QImage &icon, QObject *parent) { + const QIcon &icon, + int size, + QObject *parent) { auto ret = std::make_unique( TrayIconFileTemplate(), parent); ret->open(); - icon.save(ret.get()); + icon.pixmap(size).save(ret.get()); ret->close(); return ret; } @@ -279,8 +319,7 @@ void MainWindow::psTrayMenuUpdated() { } #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION -void MainWindow::setSNITrayIcon( - const QIcon &icon, const QImage &iconImage) { +void MainWindow::setSNITrayIcon(const QIcon &icon) { const auto iconName = GetTrayIconName(); if (qEnvironmentVariableIsSet(kDisableTrayCounter.utf8()) @@ -288,11 +327,13 @@ void MainWindow::setSNITrayIcon( _sniTrayIcon->setIconByName(iconName); _sniTrayIcon->setToolTipIconByName(iconName); } else if (NeedTrayIconFile()) { - _trayIconFile = TrayIconFile(iconImage, this); + _trayIconFile = TrayIconFile(icon, 22, this); + _trayToolTipIconFile = TrayIconFile(icon, 48, this); if (_trayIconFile) { _sniTrayIcon->setIconByName(_trayIconFile->fileName()); - _sniTrayIcon->setToolTipIconByName(_trayIconFile->fileName()); + _sniTrayIcon->setToolTipIconByName( + _trayToolTipIconFile->fileName()); } } else { _sniTrayIcon->setIconByPixmap(icon); @@ -323,9 +364,6 @@ void MainWindow::attachToSNITrayIcon() { #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION void MainWindow::psSetupTrayIcon() { - const auto iconImage = TrayIconImageGen(); - const auto icon = QIcon(QPixmap::fromImage(iconImage)); - if (IsSNIAvailable()) { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION LOG(("Using SNI tray icon.")); @@ -335,7 +373,7 @@ void MainWindow::psSetupTrayIcon() { this); _sniTrayIcon->setTitle(AppName.utf16()); - setSNITrayIcon(icon, iconImage); + setSNITrayIcon(TrayIconGen()); attachToSNITrayIcon(); } @@ -351,7 +389,7 @@ void MainWindow::psSetupTrayIcon() { if (!trayIcon) { trayIcon = new QSystemTrayIcon(this); - trayIcon->setIcon(icon); + trayIcon->setIcon(TrayIconGen()); attachToTrayIcon(trayIcon); } @@ -420,17 +458,14 @@ void MainWindow::updateIconCounters() { } #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - const auto iconImage = TrayIconImageGen(); - const auto icon = QIcon(QPixmap::fromImage(iconImage)); - if (IsSNIAvailable()) { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION if (_sniTrayIcon) { - setSNITrayIcon(icon, iconImage); + setSNITrayIcon(TrayIconGen()); } #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION } else if (trayIcon) { - trayIcon->setIcon(icon); + trayIcon->setIcon(TrayIconGen()); } } @@ -440,10 +475,6 @@ void MainWindow::LibsLoaded() { qDBusRegisterMetaType(); qDBusRegisterMetaType(); #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - - if (DesktopEnvironment::IsKDE()) { - _trayIconSize = 48; - } } void MainWindow::initTrayMenuHook() { diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index 104e8e5b6..f6eadc5d1 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -68,8 +68,9 @@ private: #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION StatusNotifierItem *_sniTrayIcon = nullptr; std::unique_ptr _trayIconFile = nullptr; + std::unique_ptr _trayToolTipIconFile = nullptr; - void setSNITrayIcon(const QIcon &icon, const QImage &iconImage); + void setSNITrayIcon(const QIcon &icon); void attachToSNITrayIcon(); #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION From 2b0e62dafea066f14c7b7d97bc50d2745681c67a Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 22 Feb 2020 20:36:01 +0400 Subject: [PATCH 128/140] Follow hidding reply setting in native notifications on Linux, use system icon --- .../linux/notifications_manager_linux.cpp | 35 ++++++++++++------- .../linux/notifications_manager_linux.h | 16 ++++++--- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index f7fd5debc..7f77c0235 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -88,8 +88,12 @@ QVersionNumber ParseSpecificationVersion( NotificationData::NotificationData( const std::shared_ptr ¬ificationInterface, const base::weak_ptr &manager, - const QString &title, const QString &subtitle, - const QString &msg, PeerId peerId, MsgId msgId) + const QString &title, + const QString &subtitle, + const QString &msg, + PeerId peerId, + MsgId msgId, + bool hideReplyButton) : _notificationInterface(notificationInterface) , _manager(manager) , _title(title) @@ -120,7 +124,7 @@ NotificationData::NotificationData( this, SLOT(notificationClicked(uint,QString))); - if (capabilities.contains(qsl("inline-reply"))) { + if (capabilities.contains(qsl("inline-reply")) && !hideReplyButton) { _actions << qsl("inline-reply") << tr::lng_notification_reply(tr::now); @@ -169,12 +173,14 @@ NotificationData::NotificationData( SLOT(notificationClosed(uint))); } -bool NotificationData::show() { +bool NotificationData::show(bool hideNameAndPhoto) { const QDBusReply notifyReply = _notificationInterface->call( qsl("Notify"), AppName.utf16(), uint(0), - QString(), + hideNameAndPhoto + ? qsl("telegram") + : QString(), _title, _body, _actions, @@ -285,7 +291,8 @@ void NotificationData::notificationReplied(uint id, const QString &text) { } } -QDBusArgument &operator<<(QDBusArgument &argument, +QDBusArgument &operator<<( + QDBusArgument &argument, const NotificationData::ImageData &imageData) { argument.beginStructure(); argument << imageData.width @@ -299,7 +306,8 @@ QDBusArgument &operator<<(QDBusArgument &argument, return argument; } -const QDBusArgument &operator>>(const QDBusArgument &argument, +const QDBusArgument &operator>>( + const QDBusArgument &argument, NotificationData::ImageData &imageData) { argument.beginStructure(); argument >> imageData.width @@ -380,12 +388,13 @@ void Manager::Private::showNotification( subtitle, msg, peer->id, - msgId); + msgId, + hideReplyButton); - const auto key = hideNameAndPhoto - ? InMemoryKey() - : peer->userpicUniqueKey(); - notification->setImage(_cachedUserpics.get(key, peer)); + if (!hideNameAndPhoto) { + const auto key = peer->userpicUniqueKey(); + notification->setImage(_cachedUserpics.get(key, peer)); + } auto i = _notifications.find(peer->id); if (i != _notifications.cend()) { @@ -401,7 +410,7 @@ void Manager::Private::showNotification( i = _notifications.insert(peer->id, QMap()); } _notifications[peer->id].insert(msgId, notification); - if (!notification->show()) { + if (!notification->show(hideNameAndPhoto)) { i = _notifications.find(peer->id); if (i != _notifications.cend()) { i->remove(msgId); diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h index 4ac937216..ef641b4a9 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h @@ -38,15 +38,19 @@ public: NotificationData( const std::shared_ptr ¬ificationInterface, const base::weak_ptr &manager, - const QString &title, const QString &subtitle, - const QString &msg, PeerId peerId, MsgId msgId); + const QString &title, + const QString &subtitle, + const QString &msg, + PeerId peerId, + MsgId msgId, + bool hideReplyButton); NotificationData(const NotificationData &other) = delete; NotificationData &operator=(const NotificationData &other) = delete; NotificationData(NotificationData &&other) = delete; NotificationData &operator=(NotificationData &&other) = delete; - bool show(); + bool show(bool hideNameAndPhoto); bool close(); void setImage(const QString &imagePath); @@ -78,10 +82,12 @@ private slots: using Notification = std::shared_ptr; -QDBusArgument &operator<<(QDBusArgument &argument, +QDBusArgument &operator<<( + QDBusArgument &argument, const NotificationData::ImageData &imageData); -const QDBusArgument &operator>>(const QDBusArgument &argument, +const QDBusArgument &operator>>( + const QDBusArgument &argument, NotificationData::ImageData &imageData); class Manager From ddf483012b2d3c19d2267ecdf20a7d80e85e6273 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Feb 2020 19:58:34 +0400 Subject: [PATCH 129/140] Beta version 1.9.17. - Spell checker on Windows 7. - Bug fixes and other minor improvements. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/changelogs.cpp | 7 +++++++ Telegram/SourceFiles/core/version.h | 4 ++-- Telegram/build/version | 8 ++++---- changelog.txt | 5 +++++ cmake | 2 +- 8 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index a52637355..d600fc7ce 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.17.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index fcf1da23d..c067af099 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,16,0 - PRODUCTVERSION 1,9,16,0 + FILEVERSION 1,9,17,0 + PRODUCTVERSION 1,9,17,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.16.0" + VALUE "FileVersion", "1.9.17.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.16.0" + VALUE "ProductVersion", "1.9.17.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 628a74f5f..49e361f23 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,16,0 - PRODUCTVERSION 1,9,16,0 + FILEVERSION 1,9,17,0 + PRODUCTVERSION 1,9,17,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.16.0" + VALUE "FileVersion", "1.9.17.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.16.0" + VALUE "ProductVersion", "1.9.17.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/changelogs.cpp b/Telegram/SourceFiles/core/changelogs.cpp index bd338c5a4..1ea716f18 100644 --- a/Telegram/SourceFiles/core/changelogs.cpp +++ b/Telegram/SourceFiles/core/changelogs.cpp @@ -61,6 +61,13 @@ std::map BetaLogs() { "\xE2\x80\xA2 Mark new messages as read " "while scrolling down through them.\n" + "\xE2\x80\xA2 Bug fixes and other minor improvements." + }, + + { + 1009017, + "\xE2\x80\xA2 Spell checker on Windows 7.\n" + "\xE2\x80\xA2 Bug fixes and other minor improvements." } }; diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index f32867215..e8a2cde4f 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009016; -constexpr auto AppVersionStr = "1.9.16"; +constexpr auto AppVersion = 1009017; +constexpr auto AppVersionStr = "1.9.17"; constexpr auto AppBetaVersion = true; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 01132d36c..e7903d3de 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009016 +AppVersion 1009017 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.16 -AppVersionStr 1.9.16 +AppVersionStrSmall 1.9.17 +AppVersionStr 1.9.17 BetaChannel 1 AlphaVersion 0 -AppVersionOriginal 1.9.16.beta +AppVersionOriginal 1.9.17.beta diff --git a/changelog.txt b/changelog.txt index bf90681ee..fd51761a2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,8 @@ +1.9.17 beta (24.02.20) + +- Spell checker on Windows 7. +- Bug fixes and other minor improvements. + 1.9.16 beta (23.02.20) - Bug fixes and other minor improvements. diff --git a/cmake b/cmake index 4c6923433..0c4fe1750 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 4c69234334eeb32f35da08307d0de1467fbce575 +Subproject commit 0c4fe1750f232805f604048340d64bd1a6a18a74 From 6f1c1fd070908f25dbb80894a7ca1c70403e49d7 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Mon, 24 Feb 2020 21:14:19 +0400 Subject: [PATCH 130/140] Fix packaged build --- Telegram/CMakeLists.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 2125bd45a..a760408dd 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -66,17 +66,6 @@ generate_numbers(Telegram ${res_loc}/numbers.txt) set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON) -if (DESKTOP_APP_USE_PACKAGED) - set(CMAKE_THREAD_PREFER_PTHREAD TRUE) - find_package(Threads) - - target_link_libraries(Telegram - PRIVATE - ${CMAKE_DL_LIBS} - Threads::Threads - ) -endif() - if (LINUX AND NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION) target_link_libraries(Telegram PRIVATE @@ -128,6 +117,17 @@ if (NOT HAVE_LONG_ATOMIC_WITHOUT_LIB) target_link_libraries(Telegram PRIVATE atomic) endif() +if (DESKTOP_APP_USE_PACKAGED) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + find_package(Threads) + + target_link_libraries(Telegram + PRIVATE + ${CMAKE_DL_LIBS} + Threads::Threads + ) +endif() + target_precompile_headers(Telegram PRIVATE ${src_loc}/stdafx.h) nice_target_sources(Telegram ${src_loc} PRIVATE From 6fbd0d7deb0ae2815d502b43c8606b1f307cd7f4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 07:58:29 +0400 Subject: [PATCH 131/140] Fix logout on second relaunch. Fixes #7279. --- Telegram/SourceFiles/storage/localstorage.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 8d83f7bf1..cac8a7bb3 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -2896,7 +2896,7 @@ base::flat_set CollectGoodNames() { _exportSettingsKey, _trustedBotsKey }; - auto result = base::flat_set{ "map0", "map1" }; + auto result = base::flat_set{ "map0", "map1", "maps" }; const auto push = [&](FileKey key) { if (!key) { return; @@ -2905,6 +2905,8 @@ base::flat_set CollectGoodNames() { result.emplace(name); name[name.size() - 1] = '1'; result.emplace(name); + name[name.size() - 1] = 's'; + result.emplace(name); }; for (const auto &value : _draftsMap) { push(value); @@ -5120,7 +5122,7 @@ void ClearManager::onStart() { if (!QDir(di.filePath()).removeRecursively()) result = false; } else { QString path = di.filePath(); - if (!path.endsWith(qstr("map0")) && !path.endsWith(qstr("map1"))) { + if (!path.endsWith(qstr("map0")) && !path.endsWith(qstr("map1")) && !path.endsWith(qstr("maps"))) { if (!QFile::remove(di.filePath())) result = false; } } From 0c8125476a044342d631997ef325164f6cc1092f Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 08:02:54 +0400 Subject: [PATCH 132/140] Beta version 1.9.18. - Bug fixes and other minor improvements. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 4 ++-- Telegram/build/version | 8 ++++---- changelog.txt | 4 ++++ 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index d600fc7ce..f63307106 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.18.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index c067af099..611a1fac8 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,17,0 - PRODUCTVERSION 1,9,17,0 + FILEVERSION 1,9,18,0 + PRODUCTVERSION 1,9,18,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.17.0" + VALUE "FileVersion", "1.9.18.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.17.0" + VALUE "ProductVersion", "1.9.18.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 49e361f23..7a6133f86 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,17,0 - PRODUCTVERSION 1,9,17,0 + FILEVERSION 1,9,18,0 + PRODUCTVERSION 1,9,18,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.17.0" + VALUE "FileVersion", "1.9.18.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.17.0" + VALUE "ProductVersion", "1.9.18.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index e8a2cde4f..111ac1e42 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009017; -constexpr auto AppVersionStr = "1.9.17"; +constexpr auto AppVersion = 1009018; +constexpr auto AppVersionStr = "1.9.18"; constexpr auto AppBetaVersion = true; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index e7903d3de..3a0e27ee4 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009017 +AppVersion 1009018 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.17 -AppVersionStr 1.9.17 +AppVersionStrSmall 1.9.18 +AppVersionStr 1.9.18 BetaChannel 1 AlphaVersion 0 -AppVersionOriginal 1.9.17.beta +AppVersionOriginal 1.9.18.beta diff --git a/changelog.txt b/changelog.txt index fd51761a2..9a903c49a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +1.9.18 beta (25.02.20) + +- Bug fixes and other minor improvements. + 1.9.17 beta (24.02.20) - Spell checker on Windows 7. From d27dd512c58262ce9a480075709de4768f927696 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Tue, 25 Feb 2020 01:20:54 +0400 Subject: [PATCH 133/140] Update snap to hunspell --- .github/workflows/snap.yml | 19 ++----------------- cmake | 2 +- snap/snapcraft.yaml | 35 ++--------------------------------- 3 files changed, 5 insertions(+), 51 deletions(-) diff --git a/.github/workflows/snap.yml b/.github/workflows/snap.yml index ed4fe99d8..53ff92d93 100644 --- a/.github/workflows/snap.yml +++ b/.github/workflows/snap.yml @@ -47,10 +47,6 @@ jobs: md5cache=$(md5sum CMAKE_CACHE_KEY.txt | cut -c -32) echo ::set-env name=CMAKE_CACHE_KEY::$md5cache - awk -v RS="" -v ORS="\n\n" '/^ enchant:/' snap/snapcraft.yaml > ENCHANT_CACHE_KEY.txt - md5cache=$(md5sum ENCHANT_CACHE_KEY.txt | cut -c -32) - echo ::set-env name=ENCHANT_CACHE_KEY::$md5cache - - name: CMake cache. id: cache-cmake uses: actions/cache@v1 @@ -62,17 +58,6 @@ jobs: if: steps.cache-cmake.outputs.cache-hit != 'true' run: snapcraft build --destructive-mode cmake - - name: Enchant cache. - id: cache-enchant - uses: actions/cache@v1 - with: - path: parts/enchant - key: ${{ runner.OS }}-enchant-${{ env.CACHE_KEY }}-${{ env.ENCHANT_CACHE_KEY }} - - - name: Enchant build. - if: steps.cache-enchant.outputs.cache-hit != 'true' - run: snapcraft build --destructive-mode enchant - - name: Telegram Desktop snap build. if: env.ONLY_CACHE == 'false' run: snapcraft --destructive-mode @@ -95,5 +80,5 @@ jobs: - name: Remove unneeded directories for cache. run: | - rm -rf parts/{cmake,enchant}/{build,src,ubuntu} - rm -rf parts/{cmake,enchant}/state/{stage,prime} + rm -rf parts/cmake/{build,src,ubuntu} + rm -rf parts/cmake/state/{stage,prime} diff --git a/cmake b/cmake index 0c4fe1750..81e27ccc0 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 0c4fe1750f232805f604048340d64bd1a6a18a74 +Subproject commit 81e27ccc0e7bf27405569ce98582860dfc9ea9bb diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index cb1d604ea..62a4f41c6 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -62,6 +62,7 @@ parts: - libswscale-dev - libswresample-dev - libdbusmenu-qt5-dev + - libhunspell-dev - liblz4-dev - liblzma-dev - libminizip-dev @@ -79,6 +80,7 @@ parts: - libswscale4 - libswresample2 - libdbusmenu-qt5-2 + - libhunspell-1.6-0 - liblz4-1 - liblzma5 - libminizip1 @@ -117,26 +119,9 @@ parts: after: - cmake - desktop-qt5 - - enchant - range-v3 - xxhash - spellchecking: - plugin: nil - stage-packages: - - hunspell-de-de - - hunspell-en-au - - hunspell-en-ca - - hunspell-en-gb - - hunspell-en-us - - hunspell-en-za - - hunspell-fr-classical - - hunspell-it - - hunspell-pl - - hunspell-es - - hunspell-pt-br - - hunspell-pt-pt - desktop-qt5: source: https://github.com/ubuntu/snapcraft-desktop-helpers.git source-subdir: qt @@ -191,22 +176,6 @@ parts: - libtinfo5 prime: [-./*] - enchant: - source: https://github.com/AbiWord/enchant.git - source-depth: 1 - source-tag: v2.2.7 - plugin: autotools - build-packages: - - libltdl-dev - - libglib2.0-dev - - libhunspell-dev - stage-packages: - - libglib2.0-0 - - libhunspell-1.6-0 - configflags: - - --enable-relocatable - prime: [-./bin/*] - range-v3: source: https://github.com/ericniebler/range-v3.git source-depth: 1 From 5838e320aef55ed3788b955066a4ef8517c6046e Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 12:58:13 +0400 Subject: [PATCH 134/140] Fix possible crash in sticker inline results. --- .../SourceFiles/inline_bots/inline_bot_layout_internal.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 960ec1078..a29cadc62 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -482,8 +482,9 @@ void Sticker::setupLottie(not_null document) const { void Sticker::prepareThumbnail() const { if (const auto document = getShownDocument()) { - if (document->sticker()->animated - && !_lottie + if (!_lottie + && document->sticker() + && document->sticker()->animated && document->loaded()) { setupLottie(document); } From 06689260e5ae0bfff4a7718a738e0d230406496d Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 13:18:31 +0400 Subject: [PATCH 135/140] Fix crash in shared images rounding. --- Telegram/lib_ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_ui b/Telegram/lib_ui index be5ed0053..ccc12ce3d 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit be5ed0053adddfa70a739bf19b8d84e540e7e0f8 +Subproject commit ccc12ce3da8f9ac30f30228c225585f732f74d5f From b2aac8006cefc0ab340573ac208154f60e7d1d10 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 13:38:58 +0400 Subject: [PATCH 136/140] Fix crash on Windows 7. --- Telegram/lib_spellcheck | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_spellcheck b/Telegram/lib_spellcheck index b7a057562..dbb92ddbe 160000 --- a/Telegram/lib_spellcheck +++ b/Telegram/lib_spellcheck @@ -1 +1 @@ -Subproject commit b7a057562c7a080e1ba92501c34551f16c2230e2 +Subproject commit dbb92ddbef82988d426ef7a0ffa40a698cdc3fd3 From 3e3696298fa95f414febd999c2da56f90c1384dd Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 13:40:09 +0400 Subject: [PATCH 137/140] Fix possible use-after-free in test connections. --- Telegram/SourceFiles/mtproto/session_private.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/mtproto/session_private.cpp b/Telegram/SourceFiles/mtproto/session_private.cpp index f71439f90..e35a4959d 100644 --- a/Telegram/SourceFiles/mtproto/session_private.cpp +++ b/Telegram/SourceFiles/mtproto/session_private.cpp @@ -189,8 +189,9 @@ void SessionPrivate::appendTestConnection( }); }); + const auto protocolDcId = getProtocolDcId(); InvokeQueued(_testConnections.back().data, [=] { - weak->connectToServer(ip, port, protocolSecret, getProtocolDcId()); + weak->connectToServer(ip, port, protocolSecret, protocolDcId); }); } From b5ad3e7724d2c33935ff50622c020f13bd17a241 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 11:59:08 +0400 Subject: [PATCH 138/140] Fix unread badges for new dialogs. --- Telegram/SourceFiles/history/history.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index bbe4cbd93..7b0767027 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -2731,7 +2731,7 @@ void History::applyDialogFields( clearFolder(); } if (!skipUnreadUpdate() - && maxInboxRead >= _inboxReadBefore.value_or(1)) { + && maxInboxRead + 1 >= _inboxReadBefore.value_or(1)) { setUnreadCount(unreadCount); setInboxReadTill(maxInboxRead); } From cc95117e9bf15318c99b8d016ccb064b6327d057 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 14:03:08 +0400 Subject: [PATCH 139/140] Beta version 1.9.19. - Bug fixes and other minor improvements. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 4 ++-- Telegram/build/version | 8 ++++---- changelog.txt | 4 ++++ 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index f63307106..474eae12b 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.9.19.0" /> Telegram Desktop Telegram FZ-LLC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 611a1fac8..c33e6deb8 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,18,0 - PRODUCTVERSION 1,9,18,0 + FILEVERSION 1,9,19,0 + PRODUCTVERSION 1,9,19,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.9.18.0" + VALUE "FileVersion", "1.9.19.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.18.0" + VALUE "ProductVersion", "1.9.19.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 7a6133f86..7cc7ae53e 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,18,0 - PRODUCTVERSION 1,9,18,0 + FILEVERSION 1,9,19,0 + PRODUCTVERSION 1,9,19,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,10 +42,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.9.18.0" + VALUE "FileVersion", "1.9.19.0" VALUE "LegalCopyright", "Copyright (C) 2014-2020" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.9.18.0" + VALUE "ProductVersion", "1.9.19.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 111ac1e42..fedd6ea8f 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 1009018; -constexpr auto AppVersionStr = "1.9.18"; +constexpr auto AppVersion = 1009019; +constexpr auto AppVersionStr = "1.9.19"; constexpr auto AppBetaVersion = true; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 3a0e27ee4..37dc9a595 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 1009018 +AppVersion 1009019 AppVersionStrMajor 1.9 -AppVersionStrSmall 1.9.18 -AppVersionStr 1.9.18 +AppVersionStrSmall 1.9.19 +AppVersionStr 1.9.19 BetaChannel 1 AlphaVersion 0 -AppVersionOriginal 1.9.18.beta +AppVersionOriginal 1.9.19.beta diff --git a/changelog.txt b/changelog.txt index 9a903c49a..990ae6a71 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +1.9.19 beta (25.02.20) + +- Bug fixes and other minor improvements. + 1.9.18 beta (25.02.20) - Bug fixes and other minor improvements. From 844e9b60ddf01712082e7ff87cfe74bb20d97297 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Feb 2020 16:12:04 +0400 Subject: [PATCH 140/140] Fix crash in SearchController. Data::Histories cancels request in Main::Session::api(), so the request must be sent using this global api(), not custom MTP::Sender. --- Telegram/SourceFiles/data/data_search_controller.cpp | 5 ++--- Telegram/SourceFiles/data/data_search_controller.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp index 08541b13d..90fbd3676 100644 --- a/Telegram/SourceFiles/data/data_search_controller.cpp +++ b/Telegram/SourceFiles/data/data_search_controller.cpp @@ -194,8 +194,7 @@ SearchController::CacheEntry::CacheEntry(const Query &query) } SearchController::SearchController(not_null session) -: _session(session) -, _api(session->api().instance()) { +: _session(session) { } bool SearchController::hasInCache(const Query &query) const { @@ -372,7 +371,7 @@ void SearchController::requestMore( const auto type = ::Data::Histories::RequestType::History; const auto history = _session->data().history(listData->peer); auto requestId = histories.sendRequest(history, type, [=](Fn finish) { - return _api.request( + return _session->api().request( std::move(*prepared) ).done([=](const MTPmessages_Messages &result) { listData->requests.remove(key); diff --git a/Telegram/SourceFiles/data/data_search_controller.h b/Telegram/SourceFiles/data/data_search_controller.h index a439bb38e..f9341ac4d 100644 --- a/Telegram/SourceFiles/data/data_search_controller.h +++ b/Telegram/SourceFiles/data/data_search_controller.h @@ -130,7 +130,6 @@ private: Data *listData); const not_null _session; - MTP::Sender _api; Cache _cache; Cache::iterator _current = _cache.end();