From 100e875530a512d156240bdd1c27c9b66caae732 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 22 Jul 2023 22:27:45 +0400 Subject: [PATCH 01/60] Short launcher access in Logs::start --- Telegram/SourceFiles/logs.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp index 03cfe4c49..f645db99d 100644 --- a/Telegram/SourceFiles/logs.cpp +++ b/Telegram/SourceFiles/logs.cpp @@ -346,7 +346,8 @@ bool WritingEntry() { void start() { Assert(LogsData == nullptr); - if (!Core::Launcher::Instance().checkPortableVersionFolder()) { + auto &launcher = Core::Launcher::Instance(); + if (!launcher.checkPortableVersionFolder()) { return; } @@ -414,7 +415,7 @@ void start() { QDir().mkpath(cWorkingDir() + u"tdata"_q); - Core::Launcher::Instance().workingFolderReady(); + launcher.workingFolderReady(); CrashReports::StartCatching(); if (!LogsData->openMain()) { @@ -430,7 +431,7 @@ void start() { LOG(("Executable dir: %1, name: %2").arg(cExeDir(), cExeName())); LOG(("Initial working dir: %1").arg(initialWorkingDir)); LOG(("Working dir: %1").arg(cWorkingDir())); - LOG(("Command line: %1").arg(Core::Launcher::Instance().arguments().join(' '))); + LOG(("Command line: %1").arg(launcher.arguments().join(' '))); if (!LogsData) { LOG(("FATAL: Could not open '%1' for writing log!" From cd7539c001495d5daa63375307b5c56417a31a3d Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 22 Jul 2023 01:07:22 +0400 Subject: [PATCH 02/60] Detect when -workdir value is not really custom --- Telegram/SourceFiles/core/launcher.cpp | 20 ++++++++++++++++---- Telegram/SourceFiles/core/launcher.h | 3 ++- Telegram/SourceFiles/logs.cpp | 7 +++++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Telegram/SourceFiles/core/launcher.cpp b/Telegram/SourceFiles/core/launcher.cpp index 52ebbd7c7..35b168d9a 100644 --- a/Telegram/SourceFiles/core/launcher.cpp +++ b/Telegram/SourceFiles/core/launcher.cpp @@ -394,6 +394,18 @@ int Launcher::exec() { return result; } +bool Launcher::validateCustomWorkingDir() { + if (customWorkingDir()) { + if (_customWorkingDir == cWorkingDir()) { + _customWorkingDir = {}; + return false; + } + cForceWorkingDir(_customWorkingDir); + return true; + } + return false; +} + void Launcher::workingFolderReady() { srand((unsigned int)time(nullptr)); @@ -435,7 +447,7 @@ const QStringList &Launcher::arguments() const { } bool Launcher::customWorkingDir() const { - return _customWorkingDir; + return !_customWorkingDir.isEmpty(); } void Launcher::prepareSettings() { @@ -534,9 +546,9 @@ void Launcher::processArguments() { gStartInTray = parseResult.contains("-startintray"); gQuit = parseResult.contains("-quit"); gSendPaths = parseResult.value("-sendpath", {}); - cForceWorkingDir(parseResult.value("-workdir", {}).join(QString())); - if (!gWorkingDir.isEmpty()) { - _customWorkingDir = true; + _customWorkingDir = parseResult.value("-workdir", {}).join(QString()); + if (!_customWorkingDir.isEmpty()) { + _customWorkingDir = QDir(_customWorkingDir).absolutePath() + '/'; } gStartUrl = parseResult.value("--", {}).join(QString()); diff --git a/Telegram/SourceFiles/core/launcher.h b/Telegram/SourceFiles/core/launcher.h index 264085f20..a5e5117a5 100644 --- a/Telegram/SourceFiles/core/launcher.h +++ b/Telegram/SourceFiles/core/launcher.h @@ -34,6 +34,7 @@ public: uint64 installationTag() const; bool checkPortableVersionFolder(); + bool validateCustomWorkingDir(); void workingFolderReady(); void writeDebugModeSetting(); void writeInstallBetaVersionsSetting(); @@ -83,7 +84,7 @@ private: QStringList _arguments; BaseIntegration _baseIntegration; - bool _customWorkingDir = false; + QString _customWorkingDir; }; diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp index f645db99d..b8bd88d6c 100644 --- a/Telegram/SourceFiles/logs.cpp +++ b/Telegram/SourceFiles/logs.cpp @@ -363,7 +363,6 @@ void start() { if (!cWorkingDir().isEmpty()) { // This value must come from TelegramForcePortable - // or from the "-workdir" command line argument. cForceWorkingDir(cWorkingDir()); workingDirChosen = true; } else { @@ -391,7 +390,6 @@ void start() { if (!cWorkingDir().isEmpty()) { // This value must come from TelegramForcePortable - // or from the "-workdir" command line argument. cForceWorkingDir(cWorkingDir()); workingDirChosen = true; } @@ -408,6 +406,11 @@ void start() { } } + if (launcher.validateCustomWorkingDir()) { + delete LogsData; + LogsData = new LogsDataFields(); + } + // WinRT build requires the working dir to stay the same for plugin loading. #ifndef Q_OS_WINRT QDir().setCurrent(cWorkingDir()); From 272d2da04af1e5a98b63cdebae52ea0e5a060407 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 22 Jul 2023 01:07:47 +0400 Subject: [PATCH 03/60] Stabilize app id on Linux when -workdir is set to the default workdir Currently the app id hash is generated from workdir path only when it's set explicitly and that's for a good reason: the default workdir could be changed (e.g. by creating a TelegramForcePortable) and app id would change what would result in a duplicate .desktop created. The current code has the possibility of having duplicate .desktop files, too, as it happened, but by specifying -workdir to the same directory as the default one. There's now a check that ensures the specified workdir is really custom so those duplicate launchers could be removed what should really stabilize the hash. --- .../platform/linux/specific_linux.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index e53ac78b0..81ff88729 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -309,6 +309,10 @@ bool GenerateDesktopFile( hashMd5Hex(d.constData(), d.size(), md5Hash); if (!Core::Launcher::Instance().customWorkingDir()) { + QFile::remove(u"%1org.telegram.desktop._%2.desktop"_q.arg( + targetPath, + md5Hash)); + const auto exePath = QFile::encodeName( cExeDir() + cExeName()); hashMd5Hex(exePath.constData(), exePath.size(), md5Hash); @@ -335,7 +339,7 @@ bool GenerateServiceFile(bool silent = false) { + QGuiApplication::desktopFileName() + u".service"_q; - DEBUG_LOG(("App Info: placing .service file to %1").arg(targetPath)); + DEBUG_LOG(("App Info: placing D-Bus service file to %1").arg(targetPath)); if (!QDir(targetPath).exists()) QDir().mkpath(targetPath); const auto target = Glib::KeyFile::create(); @@ -366,6 +370,18 @@ bool GenerateServiceFile(bool silent = false) { return false; } + if (!Core::UpdaterDisabled() && !Core::Launcher::Instance().customWorkingDir()) { + DEBUG_LOG(("App Info: removing old D-Bus service files")); + + char md5Hash[33] = { 0 }; + const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath()); + hashMd5Hex(d.constData(), d.size(), md5Hash); + + QFile::remove(u"%1org.telegram.desktop._%2.service"_q.arg( + targetPath, + md5Hash)); + } + QProcess::execute(u"systemctl"_q, { u"--user"_q, u"reload"_q, From 727bfd1059bff2859721aad83e8a9d79c8c666ad Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Jul 2023 10:43:55 +0400 Subject: [PATCH 04/60] Fix incorrect state of ElasticScroll. --- Telegram/lib_ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 079d966e4..ad852f0f4 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 079d966e45922f90de297fc9f7435cbf8b127b09 +Subproject commit ad852f0f4ab271de4db799d01fa8b7032eb33b11 From 0b1b996e3348bfe0d8c32b3f5f7b5a4926892ebf Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Jul 2023 10:44:36 +0400 Subject: [PATCH 05/60] Fix build with MSVC. --- Telegram/SourceFiles/core/launcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/core/launcher.cpp b/Telegram/SourceFiles/core/launcher.cpp index 35b168d9a..b18f0b541 100644 --- a/Telegram/SourceFiles/core/launcher.cpp +++ b/Telegram/SourceFiles/core/launcher.cpp @@ -397,7 +397,7 @@ int Launcher::exec() { bool Launcher::validateCustomWorkingDir() { if (customWorkingDir()) { if (_customWorkingDir == cWorkingDir()) { - _customWorkingDir = {}; + _customWorkingDir = QString(); return false; } cForceWorkingDir(_customWorkingDir); From fb4e05405e7c95d6593ef53810b9c36e07d0a0d3 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Jul 2023 11:43:20 +0400 Subject: [PATCH 06/60] Support and use share comment in stories. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/calls/calls.style | 5 ++++ .../SourceFiles/data/data_media_types.cpp | 21 +++------------ .../history/view/history_view_element.cpp | 8 ++++-- .../history/view/media/history_view_gif.cpp | 22 +++++++-------- .../history/view/media/history_view_gif.h | 2 +- .../history/view/media/history_view_photo.cpp | 25 ++++++++--------- .../history/view/media/history_view_photo.h | 2 +- .../media/stories/media_stories_share.cpp | 27 ++++++++++++------- 9 files changed, 57 insertions(+), 56 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index ce176c6d1..8ebc76005 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1710,6 +1710,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_forwarded" = "Forwarded from {user}"; "lng_forwarded_story" = "Story from {user}"; +"lng_forwarded_story_expired" = "This story has expired."; "lng_forwarded_date" = "Original: {date}"; "lng_forwarded_channel" = "Forwarded from {channel}"; "lng_forwarded_psa_default" = "Forwarded from {channel}"; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 28b5f90a6..c8f287328 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -744,6 +744,11 @@ groupCallShareBoxComment: InputField(groupCallField) { } groupCallShareBoxList: PeerList(groupCallMembersList) { item: PeerListItem(groupCallMembersListItem) { + nameStyle: TextStyle(defaultTextStyle) { + font: font(11px); + linkFont: font(11px); + linkFontOver: font(11px); + } checkbox: RoundImageCheckbox(groupCallMembersListCheckbox) { imageRadius: 28px; imageSmallRadius: 24px; diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 19d89c500..e623df3a5 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -1995,18 +1995,11 @@ MediaStory::MediaStory( owner->registerStoryItem(storyId, parent); const auto stories = &owner->stories(); - if (const auto maybeStory = stories->lookup(storyId)) { - if (!_mention) { - parent->setText((*maybeStory)->caption()); - } - } else { + const auto maybeStory = stories->lookup(storyId); + if (!maybeStory) { if (maybeStory.error() == NoStory::Unknown) { stories->resolve(storyId, crl::guard(this, [=] { - if (const auto maybeStory = stories->lookup(storyId)) { - if (!_mention) { - parent->setText((*maybeStory)->caption()); - } - } else { + if (!stories->lookup(storyId)) { _expired = true; } if (_mention) { @@ -2058,9 +2051,7 @@ TextWithEntities MediaStory::notificationText() const { && maybeStory.error() == Data::NoStory::Deleted)) ? tr::lng_in_dlg_story_expired : tr::lng_in_dlg_story)(tr::now), - (maybeStory - ? (*maybeStory)->caption() - : TextWithEntities())); + parent()->originalText()); } QString MediaStory::pinnedTextSubstring() const { @@ -2100,9 +2091,6 @@ std::unique_ptr MediaStory::createView( const auto stories = &parent()->history()->owner().stories(); const auto maybeStory = stories->lookup(_storyId); if (!maybeStory) { - if (!_mention) { - realParent->setText(TextWithEntities()); - } if (maybeStory.error() == Data::NoStory::Deleted) { _expired = true; return nullptr; @@ -2124,7 +2112,6 @@ std::unique_ptr MediaStory::createView( message, std::make_unique(message, story)); } else { - realParent->setText(story->caption()); if (const auto photo = story->photo()) { return std::make_unique( message, diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index f20499bb9..f86159d38 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -846,8 +846,12 @@ void Element::validateText() { _media = nullptr; if (!storyMention) { if (_text.isEmpty()) { - setTextWithLinks( - Ui::Text::Italic(u"This story has expired"_q)); + auto now = Ui::Text::Italic( + tr::lng_forwarded_story_expired(tr::now)); + if (!text.empty()) { + now.append(u"\n\n"_q).append(text); + } + setTextWithLinks(std::move(now)); } return; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index d3040ce07..0bee2fbf0 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -88,14 +88,13 @@ Gif::Gif( bool spoiler) : File(parent, realParent) , _data(document) -, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) +, _storyId(realParent->media() + ? realParent->media()->storyId() + : FullStoryId()) +, _caption( + st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) , _spoiler(spoiler ? std::make_unique() : nullptr) , _downloadSize(Ui::FormatSizeText(_data->size)) { - if (const auto media = realParent->media()) { - if (media->storyId()) { - _story = true; - } - } setDocumentLinks(_data, realParent, [=] { if (!_data->createMediaView()->canBePlayed(realParent) || !_data->isAnimation() @@ -1438,15 +1437,14 @@ void Gif::dataMediaCreated() const { } void Gif::togglePollingStory(bool enabled) const { - if (!_story || _pollingStory == enabled) { + if (!_storyId || _pollingStory == enabled) { return; } const auto polling = Data::Stories::Polling::Chat; - const auto media = _parent->data()->media(); - const auto id = media ? media->storyId() : FullStoryId(); if (!enabled) { - _data->owner().stories().unregisterPolling(id, polling); - } else if (!_data->owner().stories().registerPolling(id, polling)) { + _data->owner().stories().unregisterPolling(_storyId, polling); + } else if ( + !_data->owner().stories().registerPolling(_storyId, polling)) { return; } _pollingStory = enabled; @@ -1464,7 +1462,7 @@ void Gif::hideSpoilers() { } bool Gif::needsBubble() const { - if (_story) { + if (_storyId) { return true; } else if (_data->isVideoMessage()) { return false; diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index 50c5583ac..c737d2391 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -211,6 +211,7 @@ private: void togglePollingStory(bool enabled) const; const not_null _data; + const FullStoryId _storyId; Ui::Text::String _caption; std::unique_ptr _streamed; const std::unique_ptr _spoiler; @@ -223,7 +224,6 @@ private: mutable std::optional _thumbCacheRounding; mutable bool _thumbCacheBlurred : 1 = false; mutable bool _thumbIsEllipse : 1 = false; - mutable bool _story : 1 = false; mutable bool _pollingStory : 1 = false; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index ed5c49ac9..a5cf0f41c 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -69,13 +69,11 @@ Photo::Photo( bool spoiler) : File(parent, realParent) , _data(photo) +, _storyId(realParent->media() + ? realParent->media()->storyId() + : FullStoryId()) , _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) , _spoiler(spoiler ? std::make_unique() : nullptr) { - if (const auto media = realParent->media()) { - if (media->storyId()) { - _story = 1; - } - } _caption = createCaption(realParent); create(realParent->fullId()); } @@ -168,15 +166,14 @@ void Photo::unloadHeavyPart() { void Photo::togglePollingStory(bool enabled) const { const auto pollingStory = (enabled ? 1 : 0); - if (!_story || _pollingStory == pollingStory) { + if (!_storyId || _pollingStory == pollingStory) { return; } const auto polling = Data::Stories::Polling::Chat; - const auto media = _parent->data()->media(); - const auto id = media ? media->storyId() : FullStoryId(); if (!enabled) { - _data->owner().stories().unregisterPolling(id, polling); - } else if (!_data->owner().stories().registerPolling(id, polling)) { + _data->owner().stories().unregisterPolling(_storyId, polling); + } else if ( + !_data->owner().stories().registerPolling(_storyId, polling)) { return; } _pollingStory = pollingStory; @@ -285,7 +282,7 @@ int Photo::adjustHeightForLessCrop(QSize dimensions, QSize current) const { void Photo::draw(Painter &p, const PaintContext &context) const { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return; - } else if (_story && _data->isNull()) { + } else if (_storyId && _data->isNull()) { return; } @@ -623,7 +620,7 @@ void Photo::paintUserpicFrame( } QSize Photo::photoSize() const { - if (_story) { + if (_storyId) { return { kStoryWidth, kStoryHeight }; } return QSize(_data->width(), _data->height()); @@ -634,7 +631,7 @@ TextState Photo::textState(QPoint point, StateRequest request) const { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; - } else if (_story && _data->isNull()) { + } else if (_storyId && _data->isNull()) { return result; } auto paintx = 0, painty = 0, paintw = width(), painth = height(); @@ -1054,7 +1051,7 @@ void Photo::hideSpoilers() { } bool Photo::needsBubble() const { - if (_story || !_caption.isEmpty()) { + if (_storyId || !_caption.isEmpty()) { return true; } const auto item = _parent->data(); diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index 94404ddbe..cfe9e9627 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -163,6 +163,7 @@ private: void togglePollingStory(bool enabled) const; const not_null _data; + const FullStoryId _storyId; Ui::Text::String _caption; mutable std::shared_ptr _dataMedia; mutable std::unique_ptr _streamed; @@ -172,7 +173,6 @@ private: uint32 _serviceWidth : 28 = 0; mutable uint32 _imageCacheForum : 1 = 0; mutable uint32 _imageCacheBlurred : 1 = 0; - mutable uint32 _story : 1 = 0; mutable uint32 _pollingStory : 1 = 0; }; diff --git a/Telegram/SourceFiles/media/stories/media_stories_share.cpp b/Telegram/SourceFiles/media/stories/media_stories_share.cpp index 413fbf3d1..d6fe67adc 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_share.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_share.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/stories/media_stories_share.h" #include "api/api_common.h" +#include "api/api_text_entities.h" #include "apiwrap.h" #include "base/random.h" #include "boxes/share_box.h" @@ -86,7 +87,7 @@ namespace Media::Stories { for (const auto thread : result) { const auto error = GetErrorTextForSending( thread, - { .story = story, .text = &comment }); + { .story = story }); if (!error.isEmpty()) { return std::make_pair(error, thread); } @@ -105,16 +106,21 @@ namespace Media::Stories { return; } + auto caption = TextWithEntities{ + comment.text, + TextUtilities::ConvertTextTagsToEntities(comment.tags) + }; + TextUtilities::Trim(caption); + auto sentEntities = Api::EntitiesToMTP( + session, + caption.entities, + Api::ConvertOption::SkipLocal); + const auto captionText = caption.text; + const auto api = &story->owner().session().api(); auto &histories = story->owner().histories(); for (const auto thread : result) { const auto action = Api::SendAction(thread, options); - if (!comment.text.isEmpty()) { - auto message = Api::MessageToSend(action); - message.textWithTags = comment; - message.action.clearDraft = false; - api->sendMessage(std::move(message)); - } const auto peer = thread->peer(); const auto threadHistory = thread->owningHistory(); const auto randomId = base::RandomValue(); @@ -126,6 +132,9 @@ namespace Media::Stories { if (silentPost) { sendFlags |= MTPmessages_SendMedia::Flag::f_silent; } + if (!sentEntities.v.isEmpty()) { + sendFlags |= MTPmessages_SendMedia::Flag::f_entities; + } const auto done = [=] { if (!--state->requests) { if (show->valid()) { @@ -145,10 +154,10 @@ namespace Media::Stories { MTP_inputMediaStory( user->inputUser, MTP_int(id.story)), - MTPstring(), + MTP_string(captionText), MTP_long(randomId), MTPReplyMarkup(), - MTPVector(), + sentEntities, MTP_int(action.options.scheduled), MTP_inputPeerEmpty() ), [=](const MTPUpdates &result, const MTP::Response &response) { From 88a165d6761c4289c40ea8363d42822826589041 Mon Sep 17 00:00:00 2001 From: Avimitin Date: Mon, 24 Jul 2023 16:53:09 +0800 Subject: [PATCH 07/60] Use absolute executable path for dbus service After the v4.8.7 release, I cannot launch telegram desktop because of the recent dbus support introduced in https://github.com/telegramdesktop/tdesktop/commit/2dfe85832717ccfd9268a5b767f03eb4e8665b8f. And it was fixed after I changed the value of the Exec field to absolute path to the telegram-desktop executable. In dbus specification they don't mention that they will find executable from PATH variable, so this is a UB. After this commit, cmake will use the full install path to generate the correct service file and fix the above issue. Signed-off-by: Avimitin --- Telegram/CMakeLists.txt | 3 ++- lib/xdg/org.telegram.desktop.service | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 329e16226..8fb9e62d1 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1758,6 +1758,7 @@ endif() if (LINUX AND DESKTOP_APP_USE_PACKAGED) include(GNUInstallDirs) + configure_file("../lib/xdg/org.telegram.desktop.service" "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.service" @ONLY) configure_file("../lib/xdg/org.telegram.desktop.metainfo.xml" "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.metainfo.xml" @ONLY) generate_appdata_changelog(Telegram "${CMAKE_SOURCE_DIR}/changelog.txt" "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.metainfo.xml") install(TARGETS Telegram RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}") @@ -1769,6 +1770,6 @@ if (LINUX AND DESKTOP_APP_USE_PACKAGED) install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "telegram.png") install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "telegram.png") install(FILES "../lib/xdg/org.telegram.desktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") - install(FILES "../lib/xdg/org.telegram.desktop.service" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/dbus-1/services") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.service" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/dbus-1/services") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.telegram.desktop.metainfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo") endif() diff --git a/lib/xdg/org.telegram.desktop.service b/lib/xdg/org.telegram.desktop.service index 0f9caabbc..525cac208 100644 --- a/lib/xdg/org.telegram.desktop.service +++ b/lib/xdg/org.telegram.desktop.service @@ -1,3 +1,3 @@ [D-BUS Service] Name=org.telegram.desktop -Exec=telegram-desktop +Exec=@CMAKE_INSTALL_FULL_BINDIR@/telegram-desktop From 320db83155ff5f3afb67bc1a2e6e979a98c69869 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Jul 2023 15:31:43 +0400 Subject: [PATCH 08/60] Fix build with GCC. --- Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index 1a1a395d3..c3a9ddda3 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -332,11 +332,7 @@ void List::paint( bool layered) { const auto &st = _st.small; const auto &full = _st.full; - const auto ratio = layout.ratio; const auto expandRatio = layout.expandRatio; - const auto lerp = [&](float64 a, float64 b) { - return a + (b - a) * ratio; - }; const auto elerp = [&](float64 a, float64 b) { return a + (b - a) * expandRatio; }; From 2323aef899df81a66645ad443f423d5d98ce4311 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Jul 2023 17:01:13 +0400 Subject: [PATCH 09/60] Show nice tooltips about story privacy / silence. --- Telegram/Resources/langs/lang.strings | 10 + .../stories/media_stories_controller.cpp | 17 +- .../media/stories/media_stories_controller.h | 1 + .../media/stories/media_stories_header.cpp | 204 +++++++++++++++--- .../media/stories/media_stories_header.h | 16 ++ .../SourceFiles/media/view/media_view.style | 15 ++ Telegram/lib_ui | 2 +- 7 files changed, 233 insertions(+), 32 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 8ebc76005..85149cb42 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3833,6 +3833,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_stories_no_views" = "No views"; "lng_stories_unsupported" = "This story is not supported\nby your version of Telegram."; "lng_stories_cant_reply" = "You can't reply to this story."; +"lng_stories_about_silent" = "This video has no sound."; +"lng_stories_about_close_friends" = "You're seeing this story because {user} added you to their list of **Close Friends**."; +"lng_stories_about_contacts" = "Only {user}'s contacts can view this story."; +"lng_stories_about_selected_contacts" = "Only some contacts {user} selected can view this story."; +"lng_stories_about_close_friends_my" = "Only your list of **Close Friends** can view this story."; +"lng_stories_about_contacts_my" = "Only your contacts can view this story."; +"lng_stories_about_selected_contacts_my" = "Only some contacts you selected can view this story."; +"lng_stories_click_to_view" = "Click here to view updates from {users}."; +"lng_stories_click_to_view_and_one" = "{accumulated}, {user}"; +"lng_stories_click_to_view_and_last" = "{accumulated} and {user}"; "lng_stories_my_title" = "Saved Stories"; "lng_stories_archive_button" = "Stories Archive"; diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 2c2efc7d6..a5cf70746 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -322,8 +322,18 @@ Controller::Controller(not_null delegate) _delegate->storiesLayerShown( ) | rpl::start_with_next([=](bool shown) { - _layerShown = shown; - updatePlayingAllowed(); + if (_layerShown != shown) { + _layerShown = shown; + updatePlayingAllowed(); + } + }, _lifetime); + + _header->tooltipShownValue( + ) | rpl::start_with_next([=](bool shown) { + if (_tooltipShown != shown) { + _tooltipShown = shown; + updatePlayingAllowed(); + } }, _lifetime); const auto window = _wrap->window()->windowHandle(); @@ -961,7 +971,8 @@ void Controller::updatePlayingAllowed() { && !_captionFullView && !_captionExpanded && !_layerShown - && !_menuShown); + && !_menuShown + && !_tooltipShown); } void Controller::setPlayingAllowed(bool allowed) { diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.h b/Telegram/SourceFiles/media/stories/media_stories_controller.h index 760835a81..3aa3a49a2 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.h +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.h @@ -257,6 +257,7 @@ private: bool _hasSendText = false; bool _layerShown = false; bool _menuShown = false; + bool _tooltipShown = false; bool _paused = false; FullStoryId _shown; diff --git a/Telegram/SourceFiles/media/stories/media_stories_header.cpp b/Telegram/SourceFiles/media/stories/media_stories_header.cpp index 5dc7f6b15..8da578b9b 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_header.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_header.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/continuous_sliders.h" #include "ui/widgets/labels.h" +#include "ui/widgets/tooltip.h" #include "ui/wrap/fade_wrap.h" #include "ui/painter.h" #include "ui/rp_widget.h" @@ -50,10 +51,9 @@ struct PrivacyBadge { class UserpicBadge final : public Ui::RpWidget { public: - UserpicBadge( - not_null userpic, - PrivacyBadge badge, - Fn clicked); + UserpicBadge(not_null userpic, PrivacyBadge badge); + + [[nodiscard]] QRect badgeGeometry() const; private: bool eventFilter(QObject *o, QEvent *e) override; @@ -63,7 +63,6 @@ private: const not_null _userpic; const PrivacyBadge _badgeData; - const std::unique_ptr _clickable; QRect _badge; QImage _layer; bool _grabbing = false; @@ -95,15 +94,10 @@ private: return {}; } -UserpicBadge::UserpicBadge( - not_null userpic, - PrivacyBadge badge, - Fn clicked) +UserpicBadge::UserpicBadge(not_null userpic, PrivacyBadge badge) : RpWidget(userpic->parentWidget()) , _userpic(userpic) -, _badgeData(badge) -, _clickable(std::make_unique(parentWidget())) { - _clickable->setClickedCallback(std::move(clicked)); +, _badgeData(badge) { userpic->installEventFilter(this); updateGeometry(); setAttribute(Qt::WA_TransparentForMouseEvents); @@ -113,6 +107,10 @@ UserpicBadge::UserpicBadge( show(); } +QRect UserpicBadge::badgeGeometry() const { + return _badge; +} + bool UserpicBadge::eventFilter(QObject *o, QEvent *e) { if (o != _userpic) { return false; @@ -173,22 +171,27 @@ void UserpicBadge::updateGeometry() { _badge = QRect( QPoint(width - badge.width(), height - badge.height()), badge); - _clickable->setGeometry(_badge.translated(pos())); update(); } -[[nodiscard]] std::unique_ptr MakePrivacyBadge( +struct MadePrivacyBadge { + std::unique_ptr widget; + QRect geometry; +}; + +[[nodiscard]] MadePrivacyBadge MakePrivacyBadge( not_null userpic, - Data::StoryPrivacy privacy, - Fn clicked) { + Data::StoryPrivacy privacy) { const auto badge = LookupPrivacyBadge(privacy); if (!badge.icon) { - return nullptr; + return {}; } - return std::make_unique( - userpic, - badge, - std::move(clicked)); + auto widget = std::make_unique(userpic, badge); + const auto geometry = widget->badgeGeometry(); + return { + .widget = std::move(widget), + .geometry = geometry, + }; } [[nodiscard]] Timestamp ComposeTimestamp(TimeId when, TimeId now) { @@ -277,6 +280,8 @@ void Header::show(HeaderData data) { _info->setGeometry({ 0, 0, r, _widget->height() }); } }; + _tooltip = nullptr; + _tooltipShown = false; if (userChanged) { _volume = nullptr; _date = nullptr; @@ -328,6 +333,8 @@ void Header::show(HeaderData data) { _controller->layoutValue( ) | rpl::start_with_next([=](const Layout &layout) { raw->setGeometry(layout.header); + _contentGeometry = layout.content; + updateTooltipGeometry(); }, raw->lifetime()); } auto timestamp = ComposeDetails(data, base::unixtime::now()); @@ -357,8 +364,29 @@ void Header::show(HeaderData data) { _counter = nullptr; } - _privacy = MakePrivacyBadge(_userpic.get(), data.privacy, [=] { - }); + auto made = MakePrivacyBadge(_userpic.get(), data.privacy); + _privacy = std::move(made.widget); + _privacyBadgeOver = false; + _privacyBadgeGeometry = _privacy + ? Ui::MapFrom(_info.get(), _privacy.get(), made.geometry) + : QRect(); + if (_privacy) { + _info->setMouseTracking(true); + _info->events( + ) | rpl::filter([=](not_null e) { + const auto type = e->type(); + if (type != QEvent::Leave && type != QEvent::MouseMove) { + return false; + } + const auto over = (type == QEvent::MouseMove) + && _privacyBadgeGeometry.contains( + static_cast(e.get())->pos()); + return (_privacyBadgeOver != over); + }) | rpl::start_with_next([=] { + _privacyBadgeOver = !_privacyBadgeOver; + toggleTooltip(Tooltip::Privacy, _privacyBadgeOver); + }, _privacy->lifetime()); + } if (data.video) { createPlayPause(); @@ -369,6 +397,7 @@ void Header::show(HeaderData data) { _playPause->moveToRight(playPause.x(), playPause.y(), width); const auto volume = st::storiesVolumeButtonPosition; _volumeToggle->moveToRight(volume.x(), volume.y(), width); + updateTooltipGeometry(); }, _playPause->lifetime()); _pauseState = _controller->pauseState(); @@ -496,15 +525,14 @@ void Header::createVolumeToggle() { _volumeToggle->events( ) | rpl::start_with_next([=](not_null e) { - if (state->silent) { - return; - } const auto type = e->type(); if (type == QEvent::Enter || type == QEvent::Leave) { const auto over = (e->type() == QEvent::Enter); if (state->over != over) { state->over = over; - if (over) { + if (state->silent) { + toggleTooltip(Tooltip::SilentVideo, over); + } else if (over) { state->hideTimer.cancel(); _volume->toggle(true, anim::type::normal); } else if (!state->dropdownOver) { @@ -565,6 +593,123 @@ void Header::createVolumeToggle() { } } +void Header::toggleTooltip(Tooltip type, bool show) { + const auto guard = gsl::finally([&] { + _tooltipShown = (_tooltip != nullptr); + }); + if (const auto was = _tooltip.release()) { + was->toggleAnimated(false); + } + if (!show) { + return; + } + const auto text = [&]() -> TextWithEntities { + using Privacy = Data::StoryPrivacy; + const auto boldName = Ui::Text::Bold(_data->user->shortName()); + const auto self = _data->user->isSelf(); + switch (type) { + case Tooltip::SilentVideo: + return { tr::lng_stories_about_silent(tr::now) }; + case Tooltip::Privacy: switch (_data->privacy) { + case Privacy::CloseFriends: + return self + ? tr::lng_stories_about_close_friends_my( + tr::now, + Ui::Text::RichLangValue) + : tr::lng_stories_about_close_friends( + tr::now, + lt_user, + boldName, + Ui::Text::RichLangValue); + case Privacy::Contacts: + return self + ? tr::lng_stories_about_contacts_my( + tr::now, + Ui::Text::RichLangValue) + : tr::lng_stories_about_contacts( + tr::now, + lt_user, + boldName, + Ui::Text::RichLangValue); + case Privacy::SelectedContacts: + return self + ? tr::lng_stories_about_selected_contacts_my( + tr::now, + Ui::Text::RichLangValue) + : tr::lng_stories_about_selected_contacts( + tr::now, + lt_user, + boldName, + Ui::Text::RichLangValue); + } + } + return {}; + }(); + if (text.empty()) { + return; + } + _tooltipType = type; + _tooltip = std::make_unique( + _widget->parentWidget(), + Ui::MakeNiceTooltipLabel( + _widget.get(), + rpl::single(text), + st::storiesInfoTooltipMaxWidth, + st::storiesInfoTooltipLabel), + st::storiesInfoTooltip); + const auto tooltip = _tooltip.get(); + const auto weak = QPointer(tooltip); + const auto destroy = [=] { + delete weak.data(); + }; + tooltip->setAttribute(Qt::WA_TransparentForMouseEvents); + tooltip->setHiddenCallback(destroy); + updateTooltipGeometry(); + tooltip->toggleAnimated(true); +} + +void Header::updateTooltipGeometry() { + if (!_tooltip) { + return; + } + const auto geometry = [&] { + switch (_tooltipType) { + case Tooltip::SilentVideo: + return Ui::MapFrom( + _widget->parentWidget(), + _volumeToggle.get(), + _volumeToggle->rect()); + case Tooltip::Privacy: + return Ui::MapFrom( + _widget->parentWidget(), + _info.get(), + _privacyBadgeGeometry.marginsAdded( + st::storiesInfoTooltip.padding)); + } + return QRect(); + }(); + if (geometry.isEmpty()) { + toggleTooltip(Tooltip::None, false); + return; + } + const auto weak = QPointer(_tooltip.get()); + const auto countPosition = [=](QSize size) { + const auto result = geometry.bottomLeft() + - QPoint(size.width() / 2, 0); + const auto inner = _contentGeometry.marginsRemoved( + st::storiesInfoTooltip.padding); + if (size.width() > inner.width()) { + return QPoint( + inner.x() + (inner.width() - size.width()) / 2, + result.y()); + } else if (result.x() < inner.x()) { + return QPoint(inner.x(), result.y()); + } + return result; + }; + _tooltip->pointAt(geometry, RectPart::Bottom, countPosition); +} + void Header::rebuildVolumeControls( not_null dropdown, bool horizontal) { @@ -682,11 +827,14 @@ void Header::raise() { } } - bool Header::ignoreWindowMove(QPoint position) const { return _ignoreWindowMove; } +rpl::producer Header::tooltipShownValue() const { + return _tooltipShown.value(); +} + void Header::updateDateText() { if (!_date || !_data || !_data->date) { return; diff --git a/Telegram/SourceFiles/media/stories/media_stories_header.h b/Telegram/SourceFiles/media/stories/media_stories_header.h index 12a66b1a1..4c67526e2 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_header.h +++ b/Telegram/SourceFiles/media/stories/media_stories_header.h @@ -20,6 +20,7 @@ class FlatLabel; class IconButton; class AbstractButton; class UserpicButton; +class ImportantTooltip; template class FadeWrap; } // namespace Ui @@ -55,8 +56,15 @@ public: void raise(); [[nodiscard]] bool ignoreWindowMove(QPoint position) const; + [[nodiscard]] rpl::producer tooltipShownValue() const; private: + enum class Tooltip { + None, + SilentVideo, + Privacy, + }; + void updateDateText(); void applyPauseState(); void createPlayPause(); @@ -64,6 +72,8 @@ private: void rebuildVolumeControls( not_null dropdown, bool horizontal); + void toggleTooltip(Tooltip type, bool show); + void updateTooltipGeometry(); const not_null _controller; @@ -81,9 +91,15 @@ private: std::unique_ptr> _volume; rpl::variable _volumeIcon; std::unique_ptr _privacy; + QRect _privacyBadgeGeometry; std::optional _data; + std::unique_ptr _tooltip = { nullptr }; + rpl::variable _tooltipShown = false; + QRect _contentGeometry; + Tooltip _tooltipType = {}; base::Timer _dateUpdateTimer; bool _ignoreWindowMove = false; + bool _privacyBadgeOver = false; }; diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index d463e8adc..2a855721c 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -891,3 +891,18 @@ storiesVolumeSlider: MediaSlider { seekSize: size(12px, 12px); duration: mediaviewOverDuration; } +storiesInfoTooltipLabel: FlatLabel(defaultImportantTooltipLabel) { + style: TextStyle(defaultTextStyle) { + font: font(11px); + linkFont: font(11px); + linkFontOver: font(11px underline); + } + minWidth: 36px; +} +storiesInfoTooltip: ImportantTooltip(defaultImportantTooltip) { + bg: importantTooltipBg; + padding: margins(10px, 3px, 10px, 5px); + radius: 4px; + arrow: 4px; +} +storiesInfoTooltipMaxWidth: 360px; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index ad852f0f4..bd1e8f7c4 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit ad852f0f4ab271de4db799d01fa8b7032eb33b11 +Subproject commit bd1e8f7c47c3e99493adf9653d684c86a0a51941 From 4e109e0517facc06f00af1d70e6c2df83d58bc7b Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 01:15:32 +0300 Subject: [PATCH 10/60] Added support build of dav1d on arm machines. --- Telegram/build/prepare/prepare.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index 8b8bfd1d3..a8f611a8c 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -520,7 +520,7 @@ mac: """) stage('mozjpeg', """ - git clone -b v4.0.3 https://github.com/mozilla/mozjpeg.git + git clone -b v4.1.3 https://github.com/mozilla/mozjpeg.git cd mozjpeg win: cmake . ^ @@ -675,13 +675,31 @@ stage('dav1d', """ win: git clone -b 1.2.1 --depth 1 https://code.videolan.org/videolan/dav1d.git cd dav1d + + if "%X8664%" equ "x64" ( + SET "TARGET=x86_64" + ) else ( + SET "TARGET=x86" + ) + set FILE=cross-file.txt + echo [binaries] > %FILE% + echo c = 'cl' >> %FILE% + echo cpp = 'cl' >> %FILE% + echo ar = 'lib' >> %FILE% + echo windres = 'rc' >> %FILE% + echo [host_machine] >> %FILE% + echo system = 'windows' >> %FILE% + echo cpu_family = '%TARGET%' >> %FILE% + echo cpu = '%TARGET%' >> %FILE% + echo endian = 'little'>> %FILE% + depends:python/Scripts/activate.bat %THIRDPARTY_DIR%\\python\\Scripts\\activate.bat - meson setup --prefix %LIBS_DIR%/local --default-library=static --buildtype=debug -Denable_tools=false -Denable_tests=false -Db_vscrt=mtd builddir-debug + meson setup --cross-file %FILE% --prefix %LIBS_DIR%/local --default-library=static --buildtype=debug -Denable_tools=false -Denable_tests=false -Db_vscrt=mtd builddir-debug meson compile -C builddir-debug meson install -C builddir-debug release: - meson setup --prefix %LIBS_DIR%/local --default-library=static --buildtype=release -Denable_tools=false -Denable_tests=false -Db_vscrt=mt builddir-release + meson setup --cross-file %FILE% --prefix %LIBS_DIR%/local --default-library=static --buildtype=release -Denable_tools=false -Denable_tests=false -Db_vscrt=mt builddir-release meson compile -C builddir-release meson install -C builddir-release win: From 39f494eaddef588d47072d64a5b205a3498bb626 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 17:14:15 +0300 Subject: [PATCH 11/60] Removed display of right buttons in message field while editing message. --- .../SourceFiles/history/history_widget.cpp | 34 +++++++++++++------ .../view/controls/history_view_ttl_button.cpp | 8 +++++ .../view/controls/history_view_ttl_button.h | 2 ++ 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 25abe7428..321c1227c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2852,10 +2852,10 @@ void HistoryWidget::updateControlsVisibility() { _silent->setVisible(!_editMsgId); } if (_scheduled) { - _scheduled->show(); + _scheduled->setVisible(!_editMsgId); } if (_ttlInfo) { - _ttlInfo->show(); + _ttlInfo->setVisible(!_editMsgId); } if (_sendAs) { _sendAs->show(); @@ -5010,19 +5010,33 @@ void HistoryWidget::moveFieldControls() { } void HistoryWidget::updateFieldSize() { - auto kbShowShown = _history && !_kbShown && _keyboard->hasMarkup(); + const auto kbShowShown = _history && !_kbShown && _keyboard->hasMarkup(); auto fieldWidth = width() - _attachToggle->width() - st::historySendRight - _send->width() - _tabbedSelectorToggle->width(); - if (_botMenuButton) fieldWidth -= st::historyBotMenuSkip + _botMenuButton->width(); - if (_sendAs) fieldWidth -= _sendAs->width(); - if (kbShowShown) fieldWidth -= _botKeyboardShow->width(); - if (_cmdStartShown) fieldWidth -= _botCommandStart->width(); - if (_silent && !_silent->isHidden()) fieldWidth -= _silent->width(); - if (_scheduled) fieldWidth -= _scheduled->width(); - if (_ttlInfo) fieldWidth -= _ttlInfo->width(); + if (_botMenuButton) { + fieldWidth -= st::historyBotMenuSkip + _botMenuButton->width(); + } + if (_sendAs) { + fieldWidth -= _sendAs->width(); + } + if (kbShowShown) { + fieldWidth -= _botKeyboardShow->width(); + } + if (_cmdStartShown) { + fieldWidth -= _botCommandStart->width(); + } + if (_silent && _silent->isVisible()) { + fieldWidth -= _silent->width(); + } + if (_scheduled && _scheduled->isVisible()) { + fieldWidth -= _scheduled->width(); + } + if (_ttlInfo && _ttlInfo->isVisible()) { + fieldWidth -= _ttlInfo->width(); + } if (_fieldDisabled) { _fieldDisabled->resize(fieldWidth, fieldHeight()); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_ttl_button.cpp b/Telegram/SourceFiles/history/view/controls/history_view_ttl_button.cpp index 945253ec6..f7e15f5e5 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_ttl_button.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_ttl_button.cpp @@ -50,6 +50,14 @@ void TTLButton::hide() { _button.hide(); } +void TTLButton::setVisible(bool visible) { + _button.setVisible(visible); +} + +bool TTLButton::isVisible() const { + return _button.isVisible(); +} + void TTLButton::move(int x, int y) { _button.move(x, y); } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_ttl_button.h b/Telegram/SourceFiles/history/view/controls/history_view_ttl_button.h index dbdc50a9f..16098aa6e 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_ttl_button.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_ttl_button.h @@ -28,6 +28,8 @@ public: void show(); void hide(); + void setVisible(bool visible); + [[nodiscard]] bool isVisible() const; void move(int x, int y); [[nodiscard]] int width() const; From 6d69a78a0572181348474f5cd905d4239eec09f2 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 17:51:22 +0300 Subject: [PATCH 12/60] Fixed width updating of message field with hidden right buttons. --- .../SourceFiles/history/history_widget.cpp | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 321c1227c..cc9e0d0e4 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2848,14 +2848,35 @@ void HistoryWidget::updateControlsVisibility() { if (_botMenuButton) { _botMenuButton->show(); } - if (_silent) { - _silent->setVisible(!_editMsgId); - } - if (_scheduled) { - _scheduled->setVisible(!_editMsgId); - } - if (_ttlInfo) { - _ttlInfo->setVisible(!_editMsgId); + { + auto rightButtonsChanged = false; + if (_silent) { + const auto was = _silent->isVisible(); + const auto now = (!_editMsgId); + if (was != now) { + _silent->setVisible(now); + rightButtonsChanged = true; + } + } + if (_scheduled) { + const auto was = _scheduled->isVisible(); + const auto now = (!_editMsgId); + if (was != now) { + _scheduled->setVisible(now); + rightButtonsChanged = true; + } + } + if (_ttlInfo) { + const auto was = _ttlInfo->isVisible(); + const auto now = (!_editMsgId); + if (was != now) { + _ttlInfo->setVisible(now); + rightButtonsChanged = true; + } + } + if (rightButtonsChanged) { + updateFieldSize(); + } } if (_sendAs) { _sendAs->show(); From 3a472d1b900c4eb56127c800b60983781ca22fca Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 18:38:08 +0300 Subject: [PATCH 13/60] Removed first animation from radio button in premium graphics. --- Telegram/SourceFiles/boxes/gift_premium_box.cpp | 7 ++++--- Telegram/SourceFiles/settings/settings_premium.cpp | 7 ++++--- Telegram/SourceFiles/ui/effects/premium_graphics.cpp | 4 ++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index 199ee4cad..6720339c2 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -156,14 +156,15 @@ void GiftBox( // List. const auto group = std::make_shared(); - group->setChangedCallback([=](int value) { + const auto groupValueChangedCallback = [=](int value) { Expects(value < options.size() && value >= 0); auto text = tr::lng_premium_gift_button( tr::now, lt_cost, options[value].costTotal); state->buttonText.fire(std::move(text)); - }); + }; + group->setChangedCallback(groupValueChangedCallback); Ui::Premium::AddGiftOptions( buttonsParent, group, @@ -215,7 +216,7 @@ void GiftBox( }); box->addButton(std::move(button)); - group->setValue(0); + groupValueChangedCallback(0); Data::PeerPremiumValue( user diff --git a/Telegram/SourceFiles/settings/settings_premium.cpp b/Telegram/SourceFiles/settings/settings_premium.cpp index 82d4e4801..2b359b984 100644 --- a/Telegram/SourceFiles/settings/settings_premium.cpp +++ b/Telegram/SourceFiles/settings/settings_premium.cpp @@ -1653,7 +1653,7 @@ QPointer Premium::createPinnedToBottom( } else { #endif { - _radioGroup->setChangedCallback([=](int value) { + const auto callback = [=](int value) { const auto options = _controller->session().api().premium().subscriptionOptions(); if (options.empty()) { @@ -1665,8 +1665,9 @@ QPointer Premium::createPinnedToBottom( lt_cost, options[value].costPerMonth); _buttonText = std::move(text); - }); - _radioGroup->setValue(0); + }; + _radioGroup->setChangedCallback(callback); + callback(0); } _showFinished.events( diff --git a/Telegram/SourceFiles/ui/effects/premium_graphics.cpp b/Telegram/SourceFiles/ui/effects/premium_graphics.cpp index 2e9972257..a7ce3f922 100644 --- a/Telegram/SourceFiles/ui/effects/premium_graphics.cpp +++ b/Telegram/SourceFiles/ui/effects/premium_graphics.cpp @@ -1138,6 +1138,10 @@ void AddGiftOptions( stCheckbox, std::move(radioView)); radio->setAttribute(Qt::WA_TransparentForMouseEvents); + { // Paint the last frame instantly for the layer animation. + group->setValue(0); + radio->finishAnimating(); + } row->sizeValue( ) | rpl::start_with_next([=, margins = stCheckbox.margin]( From 65a344be76dc23ef77e649d1bc523f4e610ed34e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 20:02:46 +0300 Subject: [PATCH 14/60] Added phrase for personal photo to short info box. --- Telegram/Resources/langs/lang.strings | 1 + .../boxes/peers/peer_short_info_box.cpp | 51 +++++++++++++++---- .../boxes/peers/peer_short_info_box.h | 4 ++ .../boxes/peers/prepare_short_info_box.cpp | 5 ++ 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 85149cb42..cb98565ea 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1143,6 +1143,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_profile_shared_links#other" = "{count} shared links"; "lng_profile_copy_phone" = "Copy Phone Number"; "lng_profile_copy_fullname" = "Copy Name"; +"lng_profile_photo_by_you" = "photo set by you"; "lng_via_link_group_one" = "**{user}** restricts adding them to groups.\nYou can send them an invite link as message instead."; "lng_via_link_group_many#one" = "**{count} user** restricts adding them to groups.\nYou can send them an invite link as message instead."; diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp index 1bf236db1..5d8e93901 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp @@ -105,6 +105,7 @@ PeerShortInfoCover::PeerShortInfoCover( userpic ) | rpl::start_with_next([=](PeerShortInfoUserpic &&value) { applyUserpic(std::move(value)); + applyAdditionalStatus(value.additionalStatus); }, lifetime()); style::PaletteChanged( @@ -136,16 +137,7 @@ PeerShortInfoCover::PeerShortInfoCover( return base::EventFilterResult::Cancel; }); - _name->moveToLeft( - _st.namePosition.x(), - _st.size - _st.namePosition.y() - _name->height(), - _st.size); - _status->moveToLeft( - _st.statusPosition.x(), - (_st.size - - _st.statusPosition.y() - - _status->height()), - _st.size); + refreshLabelsGeometry(); _roundedTopImage = QImage( QSize(_st.size, _st.radius) * style::DevicePixelRatio(), @@ -415,6 +407,23 @@ QImage PeerShortInfoCover::currentVideoFrame() const { : QImage(); } +void PeerShortInfoCover::applyAdditionalStatus(const QString &status) { + if (status.isEmpty()) { + if (_additionalStatus) { + _additionalStatus.destroy(); + refreshLabelsGeometry(); + } + return; + } + if (_additionalStatus) { + _additionalStatus->setText(status); + } else { + _additionalStatus.create(_widget.get(), status, _statusStyle->st); + _additionalStatus->show(); + refreshLabelsGeometry(); + } +} + void PeerShortInfoCover::applyUserpic(PeerShortInfoUserpic &&value) { if (_index != value.index) { _index = value.index; @@ -593,6 +602,28 @@ void PeerShortInfoCover::refreshBarImages() { _barLarge = makeBar(_largeWidth); } +void PeerShortInfoCover::refreshLabelsGeometry() { + const auto statusTop = _st.size + - _st.statusPosition.y() + - _status->height(); + const auto diff = _st.namePosition.y() + - _name->height() + - _st.statusPosition.y(); + if (_additionalStatus) { + _additionalStatus->moveToLeft( + _status->x(), + statusTop - diff - _additionalStatus->height()); + } + _name->moveToLeft( + _st.namePosition.x(), + _st.size + - _st.namePosition.y() + - _name->height() + - (_additionalStatus ? (diff + _additionalStatus->height()) : 0), + _st.size); + _status->moveToLeft(_st.statusPosition.x(), statusTop, _st.size); +} + QRect PeerShortInfoCover::radialRect() const { const auto cover = _widget->rect(); const auto size = st::boxLoadingSize; diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h index 07e60132a..0e130562d 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h @@ -50,6 +50,7 @@ struct PeerShortInfoUserpic { float64 photoLoadingProgress = 0.; std::shared_ptr videoDocument; crl::time videoStartPosition = 0; + QString additionalStatus; }; class PeerShortInfoCover final { @@ -87,6 +88,7 @@ private: [[nodiscard]] QImage currentVideoFrame() const; void applyUserpic(PeerShortInfoUserpic &&value); + void applyAdditionalStatus(const QString &status); [[nodiscard]] QRect radialRect() const; void videoWaiting(); @@ -99,6 +101,7 @@ private: void updateRadialState(); void refreshCoverCursor(); void refreshBarImages(); + void refreshLabelsGeometry(); const style::ShortInfoCover &_st; @@ -108,6 +111,7 @@ private: object_ptr _name; std::unique_ptr _statusStyle; object_ptr _status; + object_ptr _additionalStatus = { nullptr }; std::array _roundMask; QImage _userpicImage; diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp index 8baf378b5..9965e8810 100644 --- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp @@ -335,6 +335,11 @@ bool ProcessCurrent( : state->photoView ? state->photoView->owner().get() : nullptr; + state->current.additionalStatus = ((state->photoId == userpicPhotoId) + && peer->isUser() + && peer->asUser()->hasPersonalPhoto()) + ? tr::lng_profile_photo_by_you(tr::now) + : QString(); state->waitingLoad = false; if (!changedPhotoId && (state->current.index > 0 || !changedUserpic) From fce8bc62013edb37422ef28cce327f544dbb8675 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 24 Jul 2023 21:42:13 +0400 Subject: [PATCH 15/60] Add stories-above-chats-list tooltip. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/calls/calls.style | 8 +- Telegram/SourceFiles/core/core_settings.cpp | 12 +- Telegram/SourceFiles/core/core_settings.h | 7 + Telegram/SourceFiles/dialogs/dialogs.style | 3 + .../SourceFiles/dialogs/dialogs_widget.cpp | 9 + .../dialogs/ui/dialogs_stories_list.cpp | 209 +++++++++++++++++- .../dialogs/ui/dialogs_stories_list.h | 17 ++ .../media/stories/media_stories_header.cpp | 2 +- .../media/stories/media_stories_header.h | 2 +- .../SourceFiles/media/view/media_view.style | 16 +- Telegram/lib_ui | 2 +- 12 files changed, 256 insertions(+), 32 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index cb98565ea..5e7f85bc6 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3841,6 +3841,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_stories_about_close_friends_my" = "Only your list of **Close Friends** can view this story."; "lng_stories_about_contacts_my" = "Only your contacts can view this story."; "lng_stories_about_selected_contacts_my" = "Only some contacts you selected can view this story."; +"lng_stories_click_to_view_mine" = "Click here to view your story."; "lng_stories_click_to_view" = "Click here to view updates from {users}."; "lng_stories_click_to_view_and_one" = "{accumulated}, {user}"; "lng_stories_click_to_view_and_last" = "{accumulated} and {user}"; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index c8f287328..2791724dd 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -1338,13 +1338,7 @@ groupCallNiceTooltip: ImportantTooltip(defaultImportantTooltip) { radius: 4px; arrow: 4px; } -groupCallNiceTooltipLabel: FlatLabel(defaultImportantTooltipLabel) { - style: TextStyle(defaultTextStyle) { - font: font(11px); - linkFont: font(11px); - linkFontOver: font(11px underline); - } -} +groupCallNiceTooltipLabel: defaultImportantTooltipLabel; groupCallStickedTooltip: ImportantTooltip(groupCallNiceTooltip) { padding: margins(10px, 1px, 6px, 3px); } diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index d1e9bfb5a..cef0bd2e8 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -200,7 +200,8 @@ QByteArray Settings::serialize() const { + sizeof(qint32) * 3 + Serialize::bytearraySize(mediaViewPosition) + sizeof(qint32) - + sizeof(quint64); + + sizeof(quint64) + + sizeof(qint32); auto result = QByteArray(); result.reserve(size); @@ -334,7 +335,8 @@ QByteArray Settings::serialize() const { << qint32(_windowTitleContent.current().hideTotalUnread ? 1 : 0) << mediaViewPosition << qint32(_ignoreBatterySaving.current() ? 1 : 0) - << quint64(_macRoundIconDigest.value_or(0)); + << quint64(_macRoundIconDigest.value_or(0)) + << qint32(_storiesClickTooltipHidden.current() ? 1 : 0); } return result; } @@ -440,6 +442,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { QByteArray mediaViewPosition; qint32 ignoreBatterySaving = _ignoreBatterySaving.current() ? 1 : 0; quint64 macRoundIconDigest = _macRoundIconDigest.value_or(0); + qint32 storiesClickTooltipHidden = _storiesClickTooltipHidden.current() ? 1 : 0; stream >> themesAccentColors; if (!stream.atEnd()) { @@ -674,6 +677,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) { if (!stream.atEnd()) { stream >> macRoundIconDigest; } + if (!stream.atEnd()) { + stream >> storiesClickTooltipHidden; + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Core::Settings::constructFromSerialized()")); @@ -865,6 +871,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { } _ignoreBatterySaving = (ignoreBatterySaving == 1); _macRoundIconDigest = macRoundIconDigest ? macRoundIconDigest : std::optional(); + _storiesClickTooltipHidden = (storiesClickTooltipHidden == 1); } QString Settings::getSoundPath(const QString &key) const { @@ -1155,6 +1162,7 @@ void Settings::resetOnLastLogout() { _tabbedReplacedWithInfo = false; // per-window _systemDarkModeEnabled = false; _hiddenGroupCallTooltips = 0; + _storiesClickTooltipHidden = 0; _recentEmojiPreload.clear(); _recentEmoji.clear(); diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index 111bf6c80..aec34560c 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -802,6 +802,12 @@ public: [[nodiscard]] std::optional macRoundIconDigest() const { return _macRoundIconDigest; } + [[nodiscard]] rpl::producer storiesClickTooltipHiddenValue() const { + return _storiesClickTooltipHidden.value(); + } + void setStoriesClickTooltipHidden(bool value) { + _storiesClickTooltipHidden = value; + } [[nodiscard]] static bool ThirdColumnByDefault(); [[nodiscard]] static float64 DefaultDialogsWidthRatio(); @@ -923,6 +929,7 @@ private: WindowPosition _mediaViewPosition = { .maximized = 2 }; rpl::variable _ignoreBatterySaving = false; std::optional _macRoundIconDigest; + rpl::variable _storiesClickTooltipHidden = false; bool _tabbedReplacedWithInfo = false; // per-window rpl::event_stream _tabbedReplacedWithInfoValue; // per-window diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index c824b8219..0e877db81 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -562,3 +562,6 @@ dialogsStoriesListInfo: DialogsStoriesList(dialogsStoriesList) { dialogsStoriesListMine: DialogsStoriesList(dialogsStoriesListInfo) { readOpacity: 1.; } +dialogsStoriesTooltip: defaultImportantTooltip; +dialogsStoriesTooltipLabel: defaultImportantTooltipLabel; +dialogsStoriesTooltipMaxWidth: 200px; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 1b696ae8d..e2fb50534 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -798,6 +798,15 @@ void Widget::setupStories() { _scroll->viewportEvent(e); }, _stories->lifetime()); + const auto hideTooltip = [=] { + Core::App().settings().setStoriesClickTooltipHidden(true); + Core::App().saveSettingsDelayed(); + }; + _stories->setShowTooltip( + Core::App().settings().storiesClickTooltipHiddenValue( + ) | rpl::map(!rpl::mappers::_1), + hideTooltip); + _storiesContents.fire(Stories::ContentForSession( &controller()->session(), Data::StorySourcesList::NotHidden)); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index c3a9ddda3..da710848b 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -7,14 +7,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "dialogs/ui/dialogs_stories_list.h" +#include "base/event_filter.h" +#include "base/qt_signal_producer.h" #include "lang/lang_keys.h" #include "ui/effects/outline_segments.h" +#include "ui/text/text_utilities.h" #include "ui/widgets/menu/menu_add_action_callback_factory.h" +#include "ui/widgets/labels.h" #include "ui/widgets/popup_menu.h" +#include "ui/widgets/tooltip.h" #include "ui/painter.h" #include "styles/style_dialogs.h" #include +#include #include "base/debug_log.h" @@ -27,6 +33,7 @@ constexpr auto kExpandAfterRatio = 0.72; constexpr auto kCollapseAfterRatio = 0.68; constexpr auto kFrictionRatio = 0.15; constexpr auto kExpandCatchUpDuration = crl::time(200); +constexpr auto kMaxTooltipNames = 3; [[nodiscard]] int AvailableNameWidth(const style::DialogsStoriesList &st) { const auto &full = st.full; @@ -112,6 +119,7 @@ void List::showContent(Content &&content) { _data.items.emplace_back(Item{ .element = element }); } } + _lastCollapsedGeometry = {}; if (int(_data.items.size()) != wasCount) { updateGeometry(); } @@ -120,6 +128,8 @@ void List::showContent(Content &&content) { if (!wasCount) { _empty = false; } + _tooltipText = computeTooltipText(); + updateTooltipGeometry(); } void List::updateScrollMax() { @@ -162,10 +172,16 @@ void List::requestExpanded(bool expanded) { const auto from = _expanded ? 0. : 1.; const auto till = _expanded ? 2. : 0.; const auto duration = (_expanded ? 2 : 1) * st::slideWrapDuration; + if (!isHidden() && _expanded) { + toggleTooltip(false); + } _expandedAnimation.start([=] { checkForFullState(); update(); _collapsedGeometryChanged.fire({}); + if (!isHidden() && !_expandedAnimation.animating()) { + toggleTooltip(false); + } }, from, till, duration, anim::sineInOut); } _toggleExpandedRequests.fire_copy(_expanded); @@ -179,6 +195,12 @@ void List::resizeEvent(QResizeEvent *e) { updateScrollMax(); } +void List::updateExpanding() { + updateExpanding( + _lastExpandedHeight * _expandCatchUpAnimation.value(1.), + _st.full.height); +} + void List::updateExpanding(int expandingHeight, int expandedHeight) { Expects(!expandingHeight || expandedHeight > 0); @@ -196,12 +218,10 @@ void List::updateExpanding(int expandingHeight, int expandedHeight) { if (change) { requestExpanded(!_expanded); } + updateTooltipGeometry(); } List::Layout List::computeLayout() { - updateExpanding( - _lastExpandedHeight * _expandCatchUpAnimation.value(1.), - _st.full.height); return computeLayout(_expandedAnimation.value(_expanded ? 2. : 0.)); } @@ -678,6 +698,9 @@ void List::mousePressEvent(QMouseEvent *e) { return; } else if (_state == State::Small) { requestExpanded(true); + if (const auto onstack = _tooltipHide) { + onstack(); + } return; } else if (_state != State::Full) { return; @@ -757,6 +780,7 @@ void List::setExpandedHeight(int height, bool momentum) { } else if (!momentum && _expandIgnored && height > 0) { _expandIgnored = false; _expandCatchUpAnimation.start([=] { + updateExpanding(); update(); checkForFullState(); }, 0., 1., kExpandCatchUpDuration); @@ -764,6 +788,7 @@ void List::setExpandedHeight(int height, bool momentum) { _expandCatchUpAnimation.stop(); } _lastExpandedHeight = height; + updateExpanding(); if (!checkForFullState()) { setState(!height ? State::Small : State::Changing); } @@ -784,17 +809,177 @@ void List::setLayoutConstraints( QPoint positionSmall, style::align alignSmall, QRect geometryFull) { + if (_positionSmall == positionSmall + && _alignSmall == alignSmall + && _geometryFull == geometryFull) { + return; + } _positionSmall = positionSmall; _alignSmall = alignSmall; _geometryFull = geometryFull; + _lastCollapsedGeometry = {}; updateGeometry(); update(); } +TextWithEntities List::computeTooltipText() const { + const auto &list = _data.items; + if (list.empty()) { + return {}; + } else if (list.size() == 1 && list.front().element.skipSmall) { + return { tr::lng_stories_click_to_view_mine(tr::now) }; + } + auto names = QStringList(); + for (const auto &item : list) { + if (item.element.skipSmall) { + continue; + } + names.append(item.element.name); + if (names.size() >= kMaxTooltipNames) { + break; + } + } + auto sequence = Ui::Text::Bold(names.front()); + if (names.size() > 1) { + for (auto i = 1; i + 1 != names.size(); ++i) { + sequence = tr::lng_stories_click_to_view_and_one( + tr::now, + lt_accumulated, + sequence, + lt_user, + Ui::Text::Bold(names[i]), + Ui::Text::WithEntities); + } + sequence = tr::lng_stories_click_to_view_and_last( + tr::now, + lt_accumulated, + sequence, + lt_user, + Ui::Text::Bold(names.back()), + Ui::Text::WithEntities); + } + return tr::lng_stories_click_to_view( + tr::now, + lt_users, + sequence, + Ui::Text::WithEntities); +} + +void List::setShowTooltip(rpl::producer shown, Fn hide) { + _tooltip = nullptr; + _tooltipHide = std::move(hide); + _tooltipNotHidden = std::move(shown); + _tooltipText = computeTooltipText(); + const auto window = this->window(); + const auto notEmpty = [](const TextWithEntities &text) { + return !text.empty(); + }; + _tooltip = std::make_unique( + window, + Ui::MakeNiceTooltipLabel( + window, + _tooltipText.value() | rpl::filter(notEmpty), + st::dialogsStoriesTooltipMaxWidth, + st::dialogsStoriesTooltipLabel), + st::dialogsStoriesTooltip); + const auto tooltip = _tooltip.get(); + const auto weak = QPointer(tooltip); + tooltip->setAttribute(Qt::WA_TransparentForMouseEvents); + tooltip->toggleFast(false); + updateTooltipGeometry(); + + const auto handle = window->windowHandle(); + auto windowActive = rpl::single( + handle->isActive() + ) | rpl::then(base::qt_signal_producer( + handle, + &QWindow::activeChanged + ) | rpl::map([=] { + return handle->isActive(); + })) | rpl::distinct_until_changed(); + + for (auto parent = parentWidget() + ; parent != window + ; parent = parent->parentWidget()) { + using namespace base; + install_event_filter(parent, tooltip, [=](not_null e) { + if (e->type() == QEvent::Move) { + updateTooltipGeometry(); + } + return EventFilterResult::Continue; + }); + } + + rpl::combine( + _tooltipNotHidden.value(), + _tooltipText.value() | rpl::map( + notEmpty + ) | rpl::distinct_until_changed(), + std::move(windowActive) + ) | rpl::start_with_next([=](bool, bool, bool active) { + _tooltipWindowActive = active; + if (!isHidden()) { + toggleTooltip(false); + } + }, tooltip->lifetime()); + + shownValue( + ) | rpl::skip(1) | rpl::start_with_next([=](bool shown) { + toggleTooltip(true); + }, tooltip->lifetime()); +} + +void List::toggleTooltip(bool fast) { + const auto shown = !_expanded + && !_expandedAnimation.animating() + && !isHidden() + && _tooltipNotHidden.current() + && !_tooltipText.current().empty() + && window()->windowHandle()->isActive(); + if (shown) { + updateTooltipGeometry(); + } + if (fast) { + _tooltip->toggleFast(shown); + } else { + _tooltip->toggleAnimated(shown); + } +} + +void List::updateTooltipGeometry() { + if (!_tooltip || _expanded || _expandedAnimation.animating()) { + return; + } + const auto collapsed = collapsedGeometryCurrent(); + if (collapsed.geometry.isEmpty()) { + int a = 0; + } + const auto geometry = Ui::MapFrom( + window(), + parentWidget(), + QRect( + collapsed.geometry.x(), + collapsed.geometry.y(), + int(std::ceil(collapsed.singleWidth)), + collapsed.geometry.height())); + const auto weak = QPointer(_tooltip.get()); + const auto countPosition = [=](QSize size) { + return QPoint( + geometry.x() + (geometry.width() - size.width()) / 2, + geometry.y() + geometry.height()); + }; + _tooltip->pointAt(geometry, RectPart::Bottom, countPosition); +} + List::CollapsedGeometry List::collapsedGeometryCurrent() const { const auto expanded = _expandedAnimation.value(_expanded ? 2. : 0.); if (expanded >= 1.) { - return { QRect(), 1. }; + const auto single = 2 * _st.full.photoLeft + _st.full.photo; + return { QRect(), 1., float64(single) }; + } else if (_lastCollapsedRatio == _lastRatio + && _lastCollapsedGeometry.expanded == expanded + && !_lastCollapsedGeometry.geometry.isEmpty()) { + return _lastCollapsedGeometry; } const auto layout = computeLayout(0.); const auto small = countSmallGeometry(); @@ -803,10 +988,21 @@ List::CollapsedGeometry List::collapsedGeometryCurrent() const { const auto left = int(base::SafeRound( shift + layout.left + layout.single * index)); const auto width = small.x() + small.width() - left; - return { - QRect(left, small.y(), width, small.height()), + const auto photoTopSmall = _st.small.photoTop; + const auto photoTop = photoTopSmall + + (_st.full.photoTop - photoTopSmall) * layout.expandedRatio; + const auto ySmall = photoTopSmall + + ((photoTop - photoTopSmall) * kSmallThumbsShown / 0.5); + const auto photo = _st.small.photo + + (_st.full.photo - _st.small.photo) * layout.ratio; + const auto top = y() + layout.geometryShift.y(); + _lastCollapsedRatio = _lastRatio; + _lastCollapsedGeometry = { + QRect(left, top, width, ySmall + photo + _st.full.photoTop), expanded, + layout.photoLeft * 2 + photo, }; + return _lastCollapsedGeometry; } rpl::producer<> List::collapsedGeometryChanged() const { @@ -822,6 +1018,7 @@ void List::updateGeometry() { } break; case State::Full: setGeometry(_geometryFull); } + updateTooltipGeometry(); update(); } diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h index 3182d7229..9ecf28394 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h @@ -23,6 +23,7 @@ struct DialogsStoriesList; namespace Ui { class PopupMenu; struct OutlineSegment; +class ImportantTooltip; } // namespace Ui namespace Dialogs::Stories { @@ -72,9 +73,11 @@ public: QPoint positionSmall, style::align alignSmall, QRect geometryFull = QRect()); + void setShowTooltip(rpl::producer shown, Fn hide); struct CollapsedGeometry { QRect geometry; float64 expanded = 0.; + float64 singleWidth = 0.; }; [[nodiscard]] CollapsedGeometry collapsedGeometryCurrent() const; [[nodiscard]] rpl::producer<> collapsedGeometryChanged() const; @@ -142,10 +145,15 @@ private: void checkLoadMore(); void requestExpanded(bool expanded); + void updateTooltipGeometry(); + [[nodiscard]] TextWithEntities computeTooltipText() const; + void toggleTooltip(bool fast); + bool checkForFullState(); void setState(State state); void updateGeometry(); [[nodiscard]] QRect countSmallGeometry() const; + void updateExpanding(); void updateExpanding(int expandingHeight, int expandedHeight); void validateSegments( not_null item, @@ -189,11 +197,20 @@ private: bool _expandIgnored : 1 = false; bool _expanded : 1 = false; + mutable CollapsedGeometry _lastCollapsedGeometry; + mutable float64 _lastCollapsedRatio = 0.; + int _selected = -1; int _pressed = -1; rpl::event_stream> _verticalScrollEvents; + rpl::variable _tooltipText; + rpl::variable _tooltipNotHidden; + Fn _tooltipHide; + std::unique_ptr _tooltip; + bool _tooltipWindowActive = false; + base::unique_qptr _menu; base::has_weak_ptr _menuGuard; diff --git a/Telegram/SourceFiles/media/stories/media_stories_header.cpp b/Telegram/SourceFiles/media/stories/media_stories_header.cpp index 8da578b9b..ac85729ee 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_header.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_header.cpp @@ -315,7 +315,7 @@ void Header::show(HeaderData data) { raw, rpl::single(data.user->isSelf() ? tr::lng_stories_my_name(tr::now) - : data.user->shortName()), + : data.user->name()), st::storiesHeaderName); _name->setAttribute(Qt::WA_TransparentForMouseEvents); _name->setOpacity(kNameOpacity); diff --git a/Telegram/SourceFiles/media/stories/media_stories_header.h b/Telegram/SourceFiles/media/stories/media_stories_header.h index 4c67526e2..c10df3ec2 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_header.h +++ b/Telegram/SourceFiles/media/stories/media_stories_header.h @@ -93,7 +93,7 @@ private: std::unique_ptr _privacy; QRect _privacyBadgeGeometry; std::optional _data; - std::unique_ptr _tooltip = { nullptr }; + std::unique_ptr _tooltip; rpl::variable _tooltipShown = false; QRect _contentGeometry; Tooltip _tooltipType = {}; diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 2a855721c..49eefe127 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -891,18 +891,6 @@ storiesVolumeSlider: MediaSlider { seekSize: size(12px, 12px); duration: mediaviewOverDuration; } -storiesInfoTooltipLabel: FlatLabel(defaultImportantTooltipLabel) { - style: TextStyle(defaultTextStyle) { - font: font(11px); - linkFont: font(11px); - linkFontOver: font(11px underline); - } - minWidth: 36px; -} -storiesInfoTooltip: ImportantTooltip(defaultImportantTooltip) { - bg: importantTooltipBg; - padding: margins(10px, 3px, 10px, 5px); - radius: 4px; - arrow: 4px; -} +storiesInfoTooltipLabel: defaultImportantTooltipLabel; +storiesInfoTooltip: defaultImportantTooltip; storiesInfoTooltipMaxWidth: 360px; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index bd1e8f7c4..8314fc9b3 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit bd1e8f7c47c3e99493adf9653d684c86a0a51941 +Subproject commit 8314fc9b3f292dd9921ef2bfa1c30bcfd2ed05ed From 16117e56bb91c6775a224042322d832aab080c75 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 22:10:21 +0300 Subject: [PATCH 16/60] Added phrase for public photo to short info box. --- Telegram/Resources/langs/lang.strings | 1 + .../SourceFiles/boxes/peers/prepare_short_info_box.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 5e7f85bc6..15c8eff5f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1144,6 +1144,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_profile_copy_phone" = "Copy Phone Number"; "lng_profile_copy_fullname" = "Copy Name"; "lng_profile_photo_by_you" = "photo set by you"; +"lng_profile_public_photo" = "public photo"; "lng_via_link_group_one" = "**{user}** restricts adding them to groups.\nYou can send them an invite link as message instead."; "lng_via_link_group_many#one" = "**{count} user** restricts adding them to groups.\nYou can send them an invite link as message instead."; diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp index 9965e8810..dfe8bdf72 100644 --- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp @@ -335,10 +335,14 @@ bool ProcessCurrent( : state->photoView ? state->photoView->owner().get() : nullptr; - state->current.additionalStatus = ((state->photoId == userpicPhotoId) - && peer->isUser() + state->current.additionalStatus = (!peer->isUser()) + ? QString() + : ((state->photoId == userpicPhotoId) && peer->asUser()->hasPersonalPhoto()) ? tr::lng_profile_photo_by_you(tr::now) + : ((state->current.index == (state->current.count - 1)) + && SyncUserFallbackPhotoViewer(peer->asUser())) + ? tr::lng_profile_public_photo(tr::now) : QString(); state->waitingLoad = false; if (!changedPhotoId From 9a72b0511758e1a7e7706cf6be43a5191f3c2842 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 22:15:51 +0300 Subject: [PATCH 17/60] Removed left button from short info box with self. --- .../boxes/peers/peer_short_info_box.cpp | 16 ++++++++++------ .../boxes/peers/peer_short_info_box.h | 1 + .../boxes/peers/prepare_short_info_box.cpp | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp index 5d8e93901..bc07210f6 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp @@ -685,12 +685,16 @@ rpl::producer PeerShortInfoBox::moveRequests() const { void PeerShortInfoBox::prepare() { addButton(tr::lng_close(), [=] { closeBox(); }); - // Perhaps a new lang key should be added for opening a group. - addLeftButton((_type == PeerShortInfoType::User) - ? tr::lng_profile_send_message() - : (_type == PeerShortInfoType::Group) - ? tr::lng_view_button_group() - : tr::lng_profile_view_channel(), [=] { _openRequests.fire({}); }); + if (_type != PeerShortInfoType::Self) { + // Perhaps a new lang key should be added for opening a group. + addLeftButton( + (_type == PeerShortInfoType::User) + ? tr::lng_profile_send_message() + : (_type == PeerShortInfoType::Group) + ? tr::lng_view_button_group() + : tr::lng_profile_view_channel(), + [=] { _openRequests.fire({}); }); + } prepareRows(); diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h index 0e130562d..bf59ff7aa 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h @@ -28,6 +28,7 @@ class RpWidget; } // namespace Ui enum class PeerShortInfoType { + Self, User, Group, Channel, diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp index dfe8bdf72..d71645316 100644 --- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp @@ -431,7 +431,9 @@ object_ptr PrepareShortInfoBox( Fn open, Fn videoPaused, const style::ShortInfoBox *stOverride) { - const auto type = peer->isUser() + const auto type = peer->isSelf() + ? PeerShortInfoType::Self + : peer->isUser() ? PeerShortInfoType::User : peer->isBroadcast() ? PeerShortInfoType::Channel From fd33fb4e7a0b234830aeb17a0f903bf66b0453af Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 23:09:11 +0300 Subject: [PATCH 18/60] Fixed style of input field in boxes from compose controls in media view. --- .../SourceFiles/chat_helpers/chat_helpers.style | 2 ++ .../controls/history_view_compose_controls.cpp | 2 ++ Telegram/SourceFiles/media/view/media_view.style | 14 ++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 5c72090e0..b1b3583ac 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -204,6 +204,7 @@ ComposeControls { record: RecordBar; files: ComposeFiles; premium: PremiumLimits; + boxField: InputField; } ReportBox { @@ -1148,6 +1149,7 @@ defaultComposeControls: ComposeControls { record: defaultRecordBar; files: defaultComposeFiles; premium: defaultPremiumLimits; + boxField: defaultInputField; } moreChatsBarHeight: 48px; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 86d412b2a..93550ba66 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -1663,6 +1663,8 @@ void ComposeControls::initField() { } return false; }); + _field->setEditLinkCallback( + DefaultEditLinkCallback(_show, _field, &_st.boxField)); initAutocomplete(); const auto allow = [=](const auto &) { return _history && Data::AllowEmojiWithoutPremium(_history->peer); diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 49eefe127..dc74d145f 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -752,6 +752,20 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { statusFg: storiesComposeGrayText; } premium: storiesComposePremium; + boxField: InputField(defaultInputField) { + textBg: transparent; + textFg: groupCallMembersFg; + + placeholderFg: groupCallMemberNotJoinedStatus; + placeholderFgActive: groupCallMemberNotJoinedStatus; + placeholderFgError: groupCallMemberNotJoinedStatus; + + borderFg: inputBorderFg; + borderFgActive: groupCallMemberInactiveStatus; + borderFgError: activeLineFgError; + + menu: storiesPopupMenu; + } } storiesViewsMenu: PopupMenu(storiesPopupMenuWithIcons) { scrollPadding: margins(0px, 6px, 0px, 4px); From 921aeb308372e372631418158b2a2c8fa62f2b3d Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 24 Jul 2023 23:33:37 +0300 Subject: [PATCH 19/60] Removed display of all layers in media view on open story. --- Telegram/SourceFiles/media/stories/media_stories_controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index a5cf70746..b77eeafa3 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -833,6 +833,7 @@ void Controller::show( .video = (document != nullptr), .silent = (document && document->isSilentVideo()), }); + uiShow()->hideLayer(anim::type::instant); if (!changeShown(story)) { return; } From 065eb8e63cbd3ea365dbbca5036d095d91f7d75a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 25 Jul 2023 02:10:44 +0300 Subject: [PATCH 20/60] Removed tabbing navigation from short info box. --- Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp | 3 +++ Telegram/lib_base | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp index bc07210f6..b1d6ab7b0 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp @@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/streaming/media_streaming_instance.h" #include "media/streaming/media_streaming_player.h" #include "base/event_filter.h" +#include "base/qt/qt_tab_key.h" #include "lang/lang_keys.h" #include "styles/style_boxes.h" #include "styles/style_layers.h" @@ -670,6 +671,8 @@ PeerShortInfoBox::PeerShortInfoBox( ) | rpl::start_with_next([=] { _cover.setScrollTop(_scroll->scrollTop()); }, _cover.lifetime()); + + base::DisableTabKey(this); } PeerShortInfoBox::~PeerShortInfoBox() = default; diff --git a/Telegram/lib_base b/Telegram/lib_base index 2669a0457..77a89e3c8 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 2669a04579069942b6208a18abe93c26adfddf2a +Subproject commit 77a89e3c857353acac83817e6ff354b962edb45c From 57fc9f71acec646efd4f56d1c31ee0cf4940590c Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 10:45:08 +0400 Subject: [PATCH 21/60] Fix some stories tooltip edge cases. --- Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp | 3 --- Telegram/SourceFiles/dialogs/dialogs_widget.cpp | 6 ++++-- Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp | 9 +++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp index b1d6ab7b0..bc07210f6 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp @@ -20,7 +20,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/streaming/media_streaming_instance.h" #include "media/streaming/media_streaming_player.h" #include "base/event_filter.h" -#include "base/qt/qt_tab_key.h" #include "lang/lang_keys.h" #include "styles/style_boxes.h" #include "styles/style_layers.h" @@ -671,8 +670,6 @@ PeerShortInfoBox::PeerShortInfoBox( ) | rpl::start_with_next([=] { _cover.setScrollTop(_scroll->scrollTop()); }, _cover.lifetime()); - - base::DisableTabKey(this); } PeerShortInfoBox::~PeerShortInfoBox() = default; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index e2fb50534..f6b506d0d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -803,8 +803,10 @@ void Widget::setupStories() { Core::App().saveSettingsDelayed(); }; _stories->setShowTooltip( - Core::App().settings().storiesClickTooltipHiddenValue( - ) | rpl::map(!rpl::mappers::_1), + rpl::combine( + Core::App().settings().storiesClickTooltipHiddenValue(), + shownValue(), + !rpl::mappers::_1 && rpl::mappers::_2), hideTooltip); _storiesContents.fire(Stories::ContentForSession( diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index da710848b..83b73ec7d 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -951,9 +951,6 @@ void List::updateTooltipGeometry() { return; } const auto collapsed = collapsedGeometryCurrent(); - if (collapsed.geometry.isEmpty()) { - int a = 0; - } const auto geometry = Ui::MapFrom( window(), parentWidget(), @@ -964,8 +961,12 @@ void List::updateTooltipGeometry() { collapsed.geometry.height())); const auto weak = QPointer(_tooltip.get()); const auto countPosition = [=](QSize size) { + const auto left = geometry.x() + + (geometry.width() - size.width()) / 2; + const auto right = window()->width() + - st::dialogsStoriesTooltip.padding.right(); return QPoint( - geometry.x() + (geometry.width() - size.width()) / 2, + std::max(std::min(left, right - size.width()), 0), geometry.y() + geometry.height()); }; _tooltip->pointAt(geometry, RectPart::Bottom, countPosition); From b7ea9a283790199c84a21ee46e52eb6e0dd99bf9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 10:45:17 +0400 Subject: [PATCH 22/60] Block tab-focus inside a layer widget. --- Telegram/lib_base | 2 +- Telegram/lib_ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Telegram/lib_base b/Telegram/lib_base index 77a89e3c8..efd052594 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 77a89e3c857353acac83817e6ff354b962edb45c +Subproject commit efd052594db9f3d85a2fbcba76db6fdecf226597 diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 8314fc9b3..2f0ac3822 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 8314fc9b3f292dd9921ef2bfa1c30bcfd2ed05ed +Subproject commit 2f0ac382289d0584002c007bdf2b3e4464f75b58 From 8cc90c3373811549c4bb50f8d1239c7d00f5f3f0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 12:30:52 +0400 Subject: [PATCH 23/60] Fix media viewer with MacBook top notch. --- .../stories/media_stories_controller.cpp | 5 +- .../media/stories/media_stories_delegate.h | 1 + .../media/view/media_view_overlay_opengl.cpp | 27 ++++- .../media/view/media_view_overlay_raster.cpp | 10 +- .../media/view/media_view_overlay_widget.cpp | 101 ++++++++++++++---- .../media/view/media_view_overlay_widget.h | 5 + .../platform/mac/overlay_widget_mac.h | 1 + .../platform/mac/overlay_widget_mac.mm | 8 ++ .../platform/platform_overlay_widget.h | 3 + 9 files changed, 135 insertions(+), 26 deletions(-) diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index b77eeafa3..384770741 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -388,6 +388,8 @@ void Controller::initLayout() { _layout = _wrap->sizeValue( ) | rpl::map([=](QSize size) { + const auto topNotchSkip = _delegate->storiesTopNotchSkip(); + size = QSize( std::max(size.width(), st::mediaviewMinWidth), std::max(size.height(), st::mediaviewMinHeight)); @@ -397,7 +399,8 @@ void Controller::initLayout() { ? HeaderLayout::Outside : HeaderLayout::Normal; - const auto topSkip = st::storiesFieldMargin.bottom() + const auto topSkip = topNotchSkip + + st::storiesFieldMargin.bottom() + (layout.headerLayout == HeaderLayout::Outside ? outsideHeaderHeight : 0); diff --git a/Telegram/SourceFiles/media/stories/media_stories_delegate.h b/Telegram/SourceFiles/media/stories/media_stories_delegate.h index ca663e69c..d1a06a52e 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_delegate.h +++ b/Telegram/SourceFiles/media/stories/media_stories_delegate.h @@ -64,6 +64,7 @@ public: virtual void storiesVolumeToggle() = 0; virtual void storiesVolumeChanged(float64 volume) = 0; virtual void storiesVolumeChangeFinished() = 0; + [[nodiscard]] virtual int storiesTopNotchSkip() = 0; }; } // namespace Media::Stories diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp index 7174aef59..b3b26aeed 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp @@ -21,7 +21,8 @@ namespace { using namespace Ui::GL; -constexpr auto kRadialLoadingOffset = 4; +constexpr auto kNotchOffset = 4; +constexpr auto kRadialLoadingOffset = kNotchOffset + 4; constexpr auto kThemePreviewOffset = kRadialLoadingOffset + 4; constexpr auto kDocumentBubbleOffset = kThemePreviewOffset + 4; constexpr auto kSaveMsgOffset = kDocumentBubbleOffset + 4; @@ -129,7 +130,7 @@ OverlayWidget::RendererGL::RendererGL(not_null owner) void OverlayWidget::RendererGL::init( not_null widget, QOpenGLFunctions &f) { - constexpr auto kQuads = 8; + constexpr auto kQuads = 9; constexpr auto kQuadVertices = kQuads * 4; constexpr auto kQuadValues = kQuadVertices * 4; constexpr auto kControlsValues = kControlsCount * kControlValues; @@ -291,6 +292,28 @@ bool OverlayWidget::RendererGL::handleHideWorkaround(QOpenGLFunctions &f) { void OverlayWidget::RendererGL::paintBackground() { _contentBuffer->bind(); + if (const auto notch = _owner->topNotchSkip()) { + const auto top = transformRect(QRect(0, 0, _owner->width(), notch)); + const GLfloat coords[] = { + top.left(), top.top(), + top.right(), top.top(), + top.right(), top.bottom(), + top.left(), top.bottom(), + }; + const auto offset = kNotchOffset; + _contentBuffer->write( + offset * 4 * sizeof(GLfloat), + coords, + sizeof(coords)); + + _fillProgram->bind(); + _fillProgram->setUniformValue("viewport", _uniformViewport); + FillRectangle( + *_f, + &*_fillProgram, + offset, + QColor(0, 0, 0)); + } } void OverlayWidget::RendererGL::paintTransformedVideoFrame( diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp index 277d39d96..4ca702d39 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp @@ -45,6 +45,12 @@ void OverlayWidget::RendererSW::paintBackground() { for (const auto &rect : region) { _p->fillRect(rect, bg); } + if (const auto notch = _owner->topNotchSkip()) { + const auto top = QRect(0, 0, _owner->width(), notch); + if (const auto black = top.intersected(_clipOuter); !black.isEmpty()) { + _p->fillRect(black, Qt::black); + } + } _p->setCompositionMode(m); } @@ -101,8 +107,8 @@ void OverlayWidget::RendererSW::paintTransformedStaticContent( } void OverlayWidget::RendererSW::paintControlsFade( - QRect content, - const ContentGeometry &geometry) { + QRect content, + const ContentGeometry &geometry) { auto opacity = geometry.controlsOpacity; if (geometry.fade > 0.) { _p->setOpacity(geometry.fade); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 0a8be2dc6..aa225a91f 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -587,6 +587,16 @@ OverlayWidget::OverlayWidget() update(); }, lifetime()); + _helper->topNotchSkipValue( + ) | rpl::start_with_next([=](int notch) { + if (_topNotchSize != notch) { + _topNotchSize = notch; + if (_fullscreen) { + updateControlsGeometry(); + } + } + }, lifetime()); + _window->setTitle(tr::lng_mediaview_title(tr::now)); _window->setTitleStyle(st::mediaviewTitle); @@ -673,7 +683,11 @@ void OverlayWidget::showSaveMsgToastWith( const auto h = st::mediaviewSaveMsgStyle.font->height + st::mediaviewSaveMsgPadding.top() + st::mediaviewSaveMsgPadding.bottom(); - _saveMsg = QRect((width() - w) / 2, (height() - h) / 2, w, h); + _saveMsg = QRect( + (width() - w) / 2, + _minUsedTop + (_maxUsedHeight - h) / 2, + w, + h); const auto callback = [=](float64 value) { updateSaveMsg(); if (!_saveMsgAnimation.animating()) { @@ -703,7 +717,7 @@ void OverlayWidget::setupWindow() { && _streamed->controls && _streamed->controls->dragging())) { return Flag::None | Flag(0); - } else if ((_w > _widget->width() || _h > _widget->height()) + } else if ((_w > _widget->width() || _h > _maxUsedHeight) && (widgetPoint.y() > st::mediaviewHeaderTop) && QRect(_x, _y, _w, _h).contains(widgetPoint)) { return Flag::None | Flag(0); @@ -940,8 +954,14 @@ void OverlayWidget::updateGeometryToScreen(bool inMove) { void OverlayWidget::updateControlsGeometry() { updateNavigationControlsGeometry(); - _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); - _photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize); + _saveMsg.moveTo( + (width() - _saveMsg.width()) / 2, + _minUsedTop + (_maxUsedHeight - _saveMsg.height()) / 2); + _photoRadialRect = QRect( + QPoint( + (width() - st::radialSize.width()) / 2, + _minUsedTop + (_maxUsedHeight - st::radialSize.height()) / 2), + st::radialSize); const auto bottom = st::mediaviewShadowBottom.height(); const auto top = st::mediaviewShadowTop.size(); @@ -960,6 +980,9 @@ void OverlayWidget::updateControlsGeometry() { } void OverlayWidget::updateNavigationControlsGeometry() { + _minUsedTop = topNotchSkip(); + _maxUsedHeight = height() - _minUsedTop; + const auto overRect = QRect( QPoint(), QSize(st::mediaviewIconOver, st::mediaviewIconOver)); @@ -969,14 +992,22 @@ void OverlayWidget::updateNavigationControlsGeometry() { const auto navSkip = st::mediaviewHeaderTop; const auto xLeft = _stories ? (_x - navSize) : 0; const auto xRight = _stories ? (_x + _w) : (width() - navSize); - _leftNav = QRect(xLeft, navSkip, navSize, height() - 2 * navSkip); + _leftNav = QRect( + xLeft, + _minUsedTop + navSkip, + navSize, + _maxUsedHeight - 2 * navSkip); _leftNavOver = _stories ? QRect() : style::centerrect(_leftNav, overRect); _leftNavIcon = style::centerrect( _leftNav, _stories ? st::storiesLeft : st::mediaviewLeft); - _rightNav = QRect(xRight, navSkip, navSize, height() - 2 * navSkip); + _rightNav = QRect( + xRight, + _minUsedTop + navSkip, + navSize, + _maxUsedHeight - 2 * navSkip); _rightNavOver = _stories ? QRect() : style::centerrect(_rightNav, overRect); @@ -1213,7 +1244,7 @@ void OverlayWidget::updateControls() { if (_document && documentBubbleShown()) { _docRect = QRect( (width() - st::mediaviewFileSize.width()) / 2, - (height() - st::mediaviewFileSize.height()) / 2, + _minUsedTop + (_maxUsedHeight - st::mediaviewFileSize.height()) / 2, st::mediaviewFileSize.width(), st::mediaviewFileSize.height()); _docIconRect = QRect( @@ -1244,7 +1275,7 @@ void OverlayWidget::updateControls() { } else { _docIconRect = QRect( (width() - st::mediaviewFileIconSize) / 2, - (height() - st::mediaviewFileIconSize) / 2, + _minUsedTop + (_maxUsedHeight - st::mediaviewFileIconSize) / 2, st::mediaviewFileIconSize, st::mediaviewFileIconSize); _docDownload->hide(); @@ -1263,7 +1294,8 @@ void OverlayWidget::updateControls() { _shareVisible = story && story->canShare(); _rotateVisible = !_themePreviewShown && !story; const auto navRect = [&](int i) { - return QRect(width() - st::mediaviewIconSize.width() * i, + return QRect( + width() - st::mediaviewIconSize.width() * i, height() - st::mediaviewIconSize.height(), st::mediaviewIconSize.width(), st::mediaviewIconSize.height()); @@ -1302,12 +1334,27 @@ void OverlayWidget::updateControls() { }(); _dateText = d.isValid() ? Ui::FormatDateTime(d) : QString(); if (!_fromName.isEmpty()) { - _fromNameLabel.setText(st::mediaviewTextStyle, _fromName, Ui::NameTextOptions()); - _nameNav = QRect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, qMin(_fromNameLabel.maxWidth(), width() / 3), st::mediaviewFont->height); - _dateNav = QRect(st::mediaviewTextLeft + _nameNav.width() + st::mediaviewTextSkip, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height); + _fromNameLabel.setText( + st::mediaviewTextStyle, + _fromName, + Ui::NameTextOptions()); + _nameNav = QRect( + st::mediaviewTextLeft, + height() - st::mediaviewTextTop, + qMin(_fromNameLabel.maxWidth(), width() / 3), + st::mediaviewFont->height); + _dateNav = QRect( + st::mediaviewTextLeft + _nameNav.width() + st::mediaviewTextSkip, + height() - st::mediaviewTextTop, + st::mediaviewFont->width(_dateText), + st::mediaviewFont->height); } else { _nameNav = QRect(); - _dateNav = QRect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height); + _dateNav = QRect( + st::mediaviewTextLeft, + height() - st::mediaviewTextTop, + st::mediaviewFont->width(_dateText), + st::mediaviewFont->height); } updateHeader(); refreshNavVisibility(); @@ -1363,9 +1410,9 @@ void OverlayWidget::refreshCaptionGeometry() { _caption.maxWidth()); const auto maxExpandedOuterHeight = (_stories ? (_h - st::storiesShadowTop.height()) - : height()); + : _maxUsedHeight); const auto maxCollapsedOuterHeight = !_stories - ? (height() / 4) + ? (_maxUsedHeight / 4) : (_h / 3); const auto maxExpandedHeight = maxExpandedOuterHeight - st::mediaviewCaptionPadding.top() @@ -1777,7 +1824,7 @@ void OverlayWidget::recountSkipTop() { ? height() : (_streamed->controls->y() - st::mediaviewCaptionPadding.bottom()); const auto skipHeightBottom = (height() - bottom); - _skipTop = std::min( + _skipTop = _minUsedTop + std::min( std::max( st::mediaviewCaptionMargin.height(), height() - _height - skipHeightBottom), @@ -1785,7 +1832,7 @@ void OverlayWidget::recountSkipTop() { _availableHeight = height() - skipHeightBottom - _skipTop; if (_fullScreenVideo && skipHeightBottom > 0 && _width > 0) { const auto h = width() * _height / _width; - const auto topAllFit = height() - skipHeightBottom - h; + const auto topAllFit = _maxUsedHeight - skipHeightBottom - h; if (_skipTop > topAllFit) { _skipTop = std::max(topAllFit, 0); } @@ -1818,12 +1865,12 @@ void OverlayWidget::resizeContentByScreenSize() { }; if (_width > 0 && _height > 0) { _zoomToDefault = countZoomFor(availableWidth, _availableHeight); - _zoomToScreen = countZoomFor(width(), height()); + _zoomToScreen = countZoomFor(width(), _maxUsedHeight); } else { _zoomToDefault = _zoomToScreen = 0; } const auto usew = _fullScreenVideo ? width() : availableWidth; - const auto useh = _fullScreenVideo ? height() : _availableHeight; + const auto useh = _fullScreenVideo ? _maxUsedHeight : _availableHeight; if ((_width > usew) || (_height > useh) || _fullScreenVideo) { const auto use = _fullScreenVideo ? _zoomToScreen : _zoomToDefault; _zoom = kZoomToScreenLevel; @@ -3156,6 +3203,10 @@ void OverlayWidget::show(OpenRequest request) { } } } + if (isHidden() || isMinimized()) { + // Count top notch on macOS before counting geometry. + _helper->beforeShow(_fullscreen); + } if (photo) { if (contextItem && contextPeer) { return; @@ -4240,6 +4291,14 @@ void OverlayWidget::storiesVolumeChangeFinished() { playbackControlsVolumeChangeFinished(); } +int OverlayWidget::topNotchSkip() const { + return _fullscreen ? _topNotchSize : 0; +} + +int OverlayWidget::storiesTopNotchSkip() { + return topNotchSkip(); +} + void OverlayWidget::playbackToggleFullScreen() { Expects(_streamed != nullptr); @@ -5366,7 +5425,7 @@ bool OverlayWidget::handleDoubleClick( void OverlayWidget::snapXY() { auto xmin = width() - _w, xmax = 0; - auto ymin = height() - _h, ymax = 0; + auto ymin = height() - _h, ymax = _minUsedTop; accumulate_min(xmin, (width() - _w) / 2); accumulate_max(xmax, (width() - _w) / 2); accumulate_min(ymin, _skipTop + (_availableHeight - _h) / 2); @@ -5390,7 +5449,7 @@ void OverlayWidget::handleMouseMove(QPoint position) { >= QApplication::startDragDistance())) { _dragging = QRect(_x, _y, _w, _h).contains(_mStart) ? 1 : -1; if (_dragging > 0) { - if (_w > width() || _h > height()) { + if (_w > width() || _h > _maxUsedHeight) { setCursor(style::cur_sizeall); } else { setCursor(style::cur_default); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index b0feb4f1d..b4a243f84 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -243,6 +243,7 @@ private: void playbackResumeOnCall(); void playbackPauseMusic(); void switchToPip(); + [[nodiscard]] int topNotchSkip() const; not_null storiesWrap() override; std::shared_ptr storiesShow() override; @@ -264,6 +265,7 @@ private: void storiesVolumeToggle() override; void storiesVolumeChanged(float64 volume) override; void storiesVolumeChangeFinished() override; + int storiesTopNotchSkip() override; void hideControls(bool force = false); void subscribeToScreenGeometry(); @@ -589,10 +591,13 @@ private: bool _captionFitsIfExpanded = false; bool _captionExpanded = false; + int _topNotchSize = 0; int _width = 0; int _height = 0; int _skipTop = 0; int _availableHeight = 0; + int _minUsedTop = 0; // Geometry without top notch on macOS. + int _maxUsedHeight = 0; int _x = 0, _y = 0, _w = 0, _h = 0; int _xStart = 0, _yStart = 0; int _zoom = 0; // < 0 - out, 0 - none, > 0 - in diff --git a/Telegram/SourceFiles/platform/mac/overlay_widget_mac.h b/Telegram/SourceFiles/platform/mac/overlay_widget_mac.h index 1e292891f..2c83b5612 100644 --- a/Telegram/SourceFiles/platform/mac/overlay_widget_mac.h +++ b/Telegram/SourceFiles/platform/mac/overlay_widget_mac.h @@ -36,6 +36,7 @@ public: void clearState() override; void setControlsOpacity(float64 opacity) override; rpl::producer controlsSideRightValue() override; + rpl::producer topNotchSkipValue() override; private: using Control = Ui::Platform::TitleControl; diff --git a/Telegram/SourceFiles/platform/mac/overlay_widget_mac.mm b/Telegram/SourceFiles/platform/mac/overlay_widget_mac.mm index 4f9160e7a..ef544803e 100644 --- a/Telegram/SourceFiles/platform/mac/overlay_widget_mac.mm +++ b/Telegram/SourceFiles/platform/mac/overlay_widget_mac.mm @@ -35,6 +35,7 @@ struct MacOverlayWidgetHelper::Data { rpl::event_stream<> clearStateRequests; bool anyOver = false; NSWindow * __weak native = nil; + rpl::variable topNotchSkip; }; MacOverlayWidgetHelper::MacOverlayWidgetHelper( @@ -96,6 +97,9 @@ void MacOverlayWidgetHelper::updateStyles(bool fullscreen) { [window setTitleVisibility:NSWindowTitleHidden]; [window setTitlebarAppearsTransparent:YES]; [window setStyleMask:[window styleMask] | NSWindowStyleMaskFullSizeContentView]; + if (@available(macOS 12.0, *)) { + _data->topNotchSkip = [[window screen] safeAreaInsets].top; + } } void MacOverlayWidgetHelper::refreshButtons(bool fullscreen) { @@ -153,6 +157,10 @@ rpl::producer MacOverlayWidgetHelper::controlsSideRightValue() { return rpl::single(false); } +rpl::producer MacOverlayWidgetHelper::topNotchSkipValue() { + return _data->topNotchSkip.value(); +} + object_ptr MacOverlayWidgetHelper::create( not_null parent, Control control) { diff --git a/Telegram/SourceFiles/platform/platform_overlay_widget.h b/Telegram/SourceFiles/platform/platform_overlay_widget.h index 97b6ef7ef..2de3687d0 100644 --- a/Telegram/SourceFiles/platform/platform_overlay_widget.h +++ b/Telegram/SourceFiles/platform/platform_overlay_widget.h @@ -58,6 +58,9 @@ public: -> rpl::producer> { return rpl::never>(); } + [[nodiscard]] virtual rpl::producer topNotchSkipValue() { + return rpl::single(0); + } }; [[nodiscard]] std::unique_ptr CreateOverlayWidgetHelper( From 5aa610290367bfb8b9c7238114f02b9a7f074080 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 17:37:56 +0400 Subject: [PATCH 24/60] Implement nice expandable story caption viewer. --- Telegram/Resources/langs/lang.strings | 1 + .../SourceFiles/core/click_handler_types.cpp | 1 + .../media_stories_caption_full_view.cpp | 189 +++++++++++++----- .../stories/media_stories_caption_full_view.h | 41 ++-- .../stories/media_stories_controller.cpp | 45 +++-- .../media/stories/media_stories_controller.h | 5 +- .../media/stories/media_stories_view.cpp | 4 +- .../media/stories/media_stories_view.h | 5 +- .../SourceFiles/media/view/media_view.style | 6 +- .../media/view/media_view_overlay_widget.cpp | 94 +++++---- .../media/view/media_view_overlay_widget.h | 5 +- 11 files changed, 259 insertions(+), 137 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 15c8eff5f..e966fe52d 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3846,6 +3846,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_stories_click_to_view" = "Click here to view updates from {users}."; "lng_stories_click_to_view_and_one" = "{accumulated}, {user}"; "lng_stories_click_to_view_and_last" = "{accumulated} and {user}"; +"lng_stories_show_more" = "Show more"; "lng_stories_my_title" = "Saved Stories"; "lng_stories_archive_button" = "Stories Archive"; diff --git a/Telegram/SourceFiles/core/click_handler_types.cpp b/Telegram/SourceFiles/core/click_handler_types.cpp index 02472e437..e3bbba7d1 100644 --- a/Telegram/SourceFiles/core/click_handler_types.cpp +++ b/Telegram/SourceFiles/core/click_handler_types.cpp @@ -147,6 +147,7 @@ void HiddenUrlClickHandler::Open(QString url, QVariant context) { my.show->showBox(std::move(box)); } else if (use) { use->show(std::move(box)); + use->activate(); } } else { open(); diff --git a/Telegram/SourceFiles/media/stories/media_stories_caption_full_view.cpp b/Telegram/SourceFiles/media/stories/media_stories_caption_full_view.cpp index 6506dd62c..25687468f 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_caption_full_view.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_caption_full_view.cpp @@ -7,79 +7,168 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "media/stories/media_stories_caption_full_view.h" +#include "base/event_filter.h" #include "core/ui_integration.h" -#include "ui/widgets/scroll_area.h" +#include "chat_helpers/compose/compose_show.h" +#include "media/stories/media_stories_controller.h" +#include "media/stories/media_stories_view.h" +#include "ui/widgets/elastic_scroll.h" #include "ui/widgets/labels.h" +#include "ui/click_handler.h" #include "styles/style_media_view.h" namespace Media::Stories { -CaptionFullView::CaptionFullView( - not_null parent, - not_null session, - const TextWithEntities &text, - Fn close) -: RpWidget(parent) -, _scroll(std::make_unique((RpWidget*)this)) -, _text(_scroll->setOwnedWidget( +CaptionFullView::CaptionFullView(not_null controller) +: _controller(controller) +, _scroll(std::make_unique(controller->wrap())) +, _wrap(_scroll->setOwnedWidget( object_ptr>( _scroll.get(), object_ptr(_scroll.get(), st::storiesCaptionFull), - st::mediaviewCaptionPadding))->entity()) -, _close(std::move(close)) -, _background(st::storiesRadius, st::mediaviewCaptionBg) { - _text->setMarkedText(text, Core::MarkedTextContext{ - .session = session, + st::mediaviewCaptionPadding))) +, _text(_wrap->entity()) { + _text->setMarkedText(controller->captionText(), Core::MarkedTextContext{ + .session = &controller->uiShow()->session(), .customEmojiRepaint = [=] { _text->update(); }, }); - parent->sizeValue() | rpl::start_with_next([=](QSize size) { - setGeometry(QRect(QPoint(), size)); - }, lifetime()); + startAnimation(); + _controller->layoutValue( + ) | rpl::start_with_next([=](const Layout &layout) { + if (_outer != layout.content) { + const auto skip = layout.header.y() + + layout.header.height() + - layout.content.y(); + _outer = layout.content.marginsRemoved({ 0, skip, 0, 0 }); + updateGeometry(); + } + }, _scroll->lifetime()); - show(); - setFocus(); + const auto filter = [=](not_null e) { + const auto mouse = [&] { + return static_cast(e.get()); + }; + const auto type = e->type(); + if (type == QEvent::MouseButtonPress + && mouse()->button() == Qt::LeftButton + && !ClickHandler::getActive()) { + _down = true; + } else if (type == QEvent::MouseButtonRelease && _down) { + _down = false; + if (!ClickHandler::getPressed()) { + close(); + } + } else if (type == QEvent::KeyPress + && static_cast(e.get())->key() == Qt::Key_Escape) { + close(); + return base::EventFilterResult::Cancel; + } + return base::EventFilterResult::Continue; + }; + base::install_event_filter(_text.get(), filter); + base::install_event_filter(_wrap.get(), filter); + + using Type = Ui::ElasticScroll::OverscrollType; + + rpl::combine( + _scroll->positionValue(), + _scroll->movementValue() + ) | rpl::filter([=] { + return !_closing; + }) | rpl::start_with_next([=]( + Ui::ElasticScrollPosition position, + Ui::ElasticScrollMovement movement) { + const auto overscrollTop = std::max(-position.overscroll, 0); + using Phase = Ui::ElasticScrollMovement; + if (movement == Phase::Progress) { + if (overscrollTop > 0) { + _pulling = true; + } else { + _pulling = false; + } + } else if (_pulling + && (movement == Phase::Momentum + || movement == Phase::Returning)) { + _pulling = false; + if (overscrollTop > st::storiesCaptionPullThreshold) { + _closingTopAdded = overscrollTop; + _scroll->setOverscrollTypes(Type::None, Type::Real); + close(); + updateGeometry(); + } + } + }, _scroll->lifetime()); + + _scroll->show(); + _scroll->setOverscrollBg(QColor(0, 0, 0, 0)); + _scroll->setOverscrollTypes(Type::Real, Type::Real); + _text->show(); + _text->setFocus(); } CaptionFullView::~CaptionFullView() = default; -void CaptionFullView::paintEvent(QPaintEvent *e) { - auto p = QPainter(this); - _background.paint(p, _scroll->geometry()); - _background.paint(p, _scroll->geometry()); +bool CaptionFullView::closing() const { + return _closing; } -void CaptionFullView::resizeEvent(QResizeEvent *e) { - const auto wanted = _text->naturalWidth(); +bool CaptionFullView::focused() const { + return Ui::InFocusChain(_scroll.get()); +} + +void CaptionFullView::close() { + if (_closing) { + return; + } + _closing = true; + _controller->captionClosing(); + startAnimation(); +} + +void CaptionFullView::updateGeometry() { + if (_outer.isEmpty()) { + return; + } + const auto lineHeight = st::mediaviewCaptionStyle.font->height; const auto padding = st::mediaviewCaptionPadding; - const auto margin = st::mediaviewCaptionMargin * 2; - const auto available = (rect() - padding).width() - - (margin.width() * 2); - const auto use = std::min(wanted, available); - _text->resizeToWidth(use); - const auto fullw = use + padding.left() + padding.right(); - const auto fullh = std::min( - _text->height() + padding.top() + padding.bottom(), - height() - (margin.height() * 2)); - const auto left = (width() - fullw) / 2; - const auto top = (height() - fullh) / 2; - _scroll->setGeometry(left, top, fullw, fullh); -} - -void CaptionFullView::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Escape) { - if (const auto onstack = _close) { - onstack(); - } + _text->resizeToWidth(_outer.width() - padding.left() - padding.right()); + const auto add = padding.top() + padding.bottom(); + const auto maxShownHeight = lineHeight * kMaxShownCaptionLines; + const auto shownHeight = (_text->height() > maxShownHeight) + ? (lineHeight * kCollapsedCaptionLines) + : _text->height(); + const auto collapsedHeight = shownHeight + add; + const auto addedToBottom = lineHeight; + const auto expandedHeight = _text->height() + add + addedToBottom; + const auto fullHeight = std::min(expandedHeight, _outer.height()); + const auto shown = _animation.value(_closing ? 0. : 1.); + const auto height = (_closing || _animation.animating()) + ? anim::interpolate(collapsedHeight, fullHeight, shown) + : _outer.height(); + const auto added = anim::interpolate(0, _closingTopAdded, shown); + const auto bottomPadding = anim::interpolate(0, addedToBottom, shown); + const auto use = padding + ((_closing || _animation.animating()) + ? QMargins(0, 0, 0, bottomPadding) + : QMargins(0, height - fullHeight, 0, bottomPadding)); + _wrap->setPadding(use); + _scroll->setGeometry( + _outer.x(), + added + _outer.y() + _outer.height() - height, + _outer.width(), + std::max(height - added, 0)); + if (_closing && !_animation.animating()) { + _controller->captionClosed(); } } -void CaptionFullView::mousePressEvent(QMouseEvent *e) { - if (e->button() == Qt::LeftButton) { - if (const auto onstack = _close) { - onstack(); - } - } +void CaptionFullView::startAnimation() { + _animation.start( + [=] { updateGeometry(); }, + _closing ? 1. : 0., + _closing ? 0. : 1., + st::fadeWrapDuration, + anim::sineInOut); } } // namespace Media::Stories diff --git a/Telegram/SourceFiles/media/stories/media_stories_caption_full_view.h b/Telegram/SourceFiles/media/stories/media_stories_caption_full_view.h index 94b6e2cff..b51ccb0d9 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_caption_full_view.h +++ b/Telegram/SourceFiles/media/stories/media_stories_caption_full_view.h @@ -7,8 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "ui/rp_widget.h" -#include "ui/round_rect.h" +#include "ui/effects/animations.h" namespace Main { class Session; @@ -16,30 +15,38 @@ class Session; namespace Ui { class FlatLabel; -class ScrollArea; +class ElasticScroll; +template +class PaddingWrap; } // namespace Ui namespace Media::Stories { -class CaptionFullView final : private Ui::RpWidget { +class Controller; + +class CaptionFullView final { public: - CaptionFullView( - not_null parent, - not_null session, - const TextWithEntities &text, - Fn close); + explicit CaptionFullView(not_null controller); ~CaptionFullView(); -private: - void paintEvent(QPaintEvent *e) override; - void resizeEvent(QResizeEvent *e) override; - void keyPressEvent(QKeyEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; + void close(); + [[nodiscard]] bool closing() const; + [[nodiscard]] bool focused() const; - std::unique_ptr _scroll; +private: + void updateGeometry(); + void startAnimation(); + + const not_null _controller; + const std::unique_ptr _scroll; + const not_null*> _wrap; const not_null _text; - Fn _close; - Ui::RoundRect _background; + Ui::Animations::Simple _animation; + QRect _outer; + int _closingTopAdded = 0; + bool _pulling = false; + bool _closing = false; + bool _down = false; }; diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 384770741..b94484a59 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -280,9 +280,6 @@ Controller::Controller(not_null delegate) _1 || _2 ) | rpl::distinct_until_changed( ) | rpl::start_with_next([=](bool active) { - if (active) { - _captionFullView = nullptr; - } _replyActive = active; updateContentFaded(); }, _lifetime); @@ -355,7 +352,8 @@ Controller::~Controller() { } void Controller::updateContentFaded() { - const auto faded = _replyActive || _captionFullView || _captionExpanded; + const auto faded = _replyActive + || (_captionFullView && !_captionFullView->closing()); if (_contentFaded == faded) { return; } @@ -584,26 +582,31 @@ TextWithEntities Controller::captionText() const { return _captionText; } -void Controller::setCaptionExpanded(bool expanded) { - if (_captionExpanded == expanded) { - return; - } - _captionExpanded = expanded; - updateContentFaded(); +bool Controller::skipCaption() const { + return _captionFullView != nullptr; } void Controller::showFullCaption() { if (_captionText.empty()) { return; } - _captionFullView = std::make_unique( - wrap(), - &_delegate->storiesShow()->session(), - _captionText, - [=] { _captionFullView = nullptr; updateContentFaded(); }); + _captionFullView = std::make_unique(this); updateContentFaded(); } +void Controller::captionClosing() { + updateContentFaded(); +} + +void Controller::captionClosed() { + if (!_captionFullView) { + return; + } else if (_captionFullView->focused()) { + _wrap->setFocus(); + } + _captionFullView = nullptr; +} + std::shared_ptr Controller::uiShow() const { return _delegate->storiesShow(); } @@ -820,9 +823,8 @@ void Controller::show( _slider->raise(); } + captionClosed(); _captionText = story->caption(); - _captionFullView = nullptr; - _captionExpanded = false; _contentFaded = false; _contentFadeAnimation.stop(); const auto document = story->document(); @@ -972,17 +974,13 @@ void Controller::updatePlayingAllowed() { && _windowActive && !_paused && !_replyActive - && !_captionFullView - && !_captionExpanded + && (!_captionFullView || _captionFullView->closing()) && !_layerShown && !_menuShown && !_tooltipShown); } void Controller::setPlayingAllowed(bool allowed) { - if (allowed) { - _captionFullView = nullptr; - } if (_photoPlayback) { _photoPlayback->togglePaused(!allowed); } else { @@ -1192,6 +1190,9 @@ void Controller::togglePaused(bool paused) { void Controller::contentPressed(bool pressed) { togglePaused(pressed); + if (_captionFullView) { + _captionFullView->close(); + } if (pressed) { _reactions->collapse(); } diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.h b/Telegram/SourceFiles/media/stories/media_stories_controller.h index 3aa3a49a2..35d82c9b0 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.h +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.h @@ -122,8 +122,10 @@ public: [[nodiscard]] bool closeByClickAt(QPoint position) const; [[nodiscard]] Data::FileOrigin fileOrigin() const; [[nodiscard]] TextWithEntities captionText() const; - void setCaptionExpanded(bool expanded); + [[nodiscard]] bool skipCaption() const; void showFullCaption(); + void captionClosing(); + void captionClosed(); [[nodiscard]] std::shared_ptr uiShow() const; [[nodiscard]] auto stickerOrEmojiChosen() const @@ -250,7 +252,6 @@ private: Ui::Animations::Simple _contentFadeAnimation; bool _contentFaded = false; - bool _captionExpanded = false; bool _windowActive = false; bool _replyFocused = false; bool _replyActive = false; diff --git a/Telegram/SourceFiles/media/stories/media_stories_view.cpp b/Telegram/SourceFiles/media/stories/media_stories_view.cpp index 159999281..dfbab352b 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_view.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_view.cpp @@ -123,8 +123,8 @@ TextWithEntities View::captionText() const { return _controller->captionText(); } -void View::setCaptionExpanded(bool expanded) { - _controller->setCaptionExpanded(expanded); +bool View::skipCaption() const { + return _controller->skipCaption(); } void View::showFullCaption() { diff --git a/Telegram/SourceFiles/media/stories/media_stories_view.h b/Telegram/SourceFiles/media/stories/media_stories_view.h index 57e38e70b..08fe4cf1b 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_view.h +++ b/Telegram/SourceFiles/media/stories/media_stories_view.h @@ -48,6 +48,9 @@ struct SiblingView { } }; +inline constexpr auto kCollapsedCaptionLines = 2; +inline constexpr auto kMaxShownCaptionLines = 4; + class View final { public: explicit View(not_null delegate); @@ -64,7 +67,7 @@ public: [[nodiscard]] SiblingView sibling(SiblingType type) const; [[nodiscard]] Data::FileOrigin fileOrigin() const; [[nodiscard]] TextWithEntities captionText() const; - void setCaptionExpanded(bool expanded); + [[nodiscard]] bool skipCaption() const; void showFullCaption(); void updatePlayback(const Player::TrackState &state); diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index dc74d145f..c15460c9e 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -445,7 +445,8 @@ storiesSideSkip: 145px; storiesCaptionFull: FlatLabel(defaultFlatLabel) { style: mediaviewCaptionStyle; textFg: mediaviewCaptionFg; - minWidth: 360px; + palette: mediaviewTextPalette; + minWidth: 36px; } storiesComposeBg: groupCallMembersBg; storiesComposeBgOver: groupCallMembersBgOver; @@ -908,3 +909,6 @@ storiesVolumeSlider: MediaSlider { storiesInfoTooltipLabel: defaultImportantTooltipLabel; storiesInfoTooltip: defaultImportantTooltip; storiesInfoTooltipMaxWidth: 360px; +storiesCaptionPullThreshold: 50px; +storiesShowMorePadding: margins(6px, 4px, 6px, 4px); +storiesShowMoreFont: semiboldFont; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index aa225a91f..a5f00bc3d 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1383,6 +1383,10 @@ void OverlayWidget::resizeCenteredControls() { } void OverlayWidget::refreshCaptionGeometry() { + _caption.updateSkipBlock(0, 0); + _captionShowMoreWidth = 0; + _captionSkipBlockWidth = 0; + if (_caption.isEmpty()) { _captionRect = QRect(); return; @@ -1408,32 +1412,28 @@ void OverlayWidget::refreshCaptionGeometry() { - st::mediaviewCaptionPadding.left() - st::mediaviewCaptionPadding.right()), _caption.maxWidth()); - const auto maxExpandedOuterHeight = (_stories - ? (_h - st::storiesShadowTop.height()) - : _maxUsedHeight); - const auto maxCollapsedOuterHeight = !_stories - ? (_maxUsedHeight / 4) - : (_h / 3); - const auto maxExpandedHeight = maxExpandedOuterHeight - - st::mediaviewCaptionPadding.top() - - st::mediaviewCaptionPadding.bottom(); - const auto maxCollapsedHeight = maxCollapsedOuterHeight - - st::mediaviewCaptionPadding.top() - - st::mediaviewCaptionPadding.bottom(); const auto lineHeight = st::mediaviewCaptionStyle.font->height; const auto wantedHeight = _caption.countHeight(captionWidth); - const auto maxHeight = _captionExpanded - ? maxExpandedHeight - : maxCollapsedHeight; + const auto maxHeight = !_stories + ? (_maxUsedHeight / 4) + : (wantedHeight > lineHeight * Stories::kMaxShownCaptionLines) + ? (lineHeight * Stories::kCollapsedCaptionLines) + : wantedHeight; const auto captionHeight = std::min( wantedHeight, (maxHeight / lineHeight) * lineHeight); - _captionFitsIfExpanded = _stories - && (wantedHeight <= maxExpandedHeight); - _captionShownFull = (wantedHeight <= maxCollapsedHeight); - if (_captionShownFull && _captionExpanded && _stories) { - _captionExpanded = false; - _stories->setCaptionExpanded(false); + if (_stories && captionHeight < wantedHeight) { + const auto padding = st::storiesShowMorePadding; + _captionShowMoreWidth = st::storiesShowMoreFont->width( + tr::lng_stories_show_more(tr::now)); + _captionSkipBlockWidth = _captionShowMoreWidth + + padding.left() + + padding.right() + - st::mediaviewCaptionPadding.right(); + const auto skiph = st::storiesShowMoreFont->height + + padding.bottom() + - st::mediaviewCaptionPadding.bottom(); + _caption.updateSkipBlock(_captionSkipBlockWidth, skiph); } _captionRect = QRect( (width() - captionWidth) / 2, @@ -3495,7 +3495,6 @@ void OverlayWidget::updateThemePreviewGeometry() { } void OverlayWidget::displayFinished(anim::activation activation) { - _captionExpanded = _captionFitsIfExpanded = _captionShownFull = false; updateControls(); if (isHidden()) { _helper->beforeShow(_fullscreen); @@ -4502,7 +4501,8 @@ void OverlayWidget::paint(not_null renderer) { if (!_stories) { renderer->paintFooter(footerGeometry(), opacity); } - if (!_caption.isEmpty()) { + if (!_caption.isEmpty() + && (!_stories || !_stories->skipCaption())) { renderer->paintCaption(captionGeometry(), opacity); } if (_groupThumbs) { @@ -4912,6 +4912,7 @@ void OverlayWidget::paintCaptionContent( } if (inner.intersects(clip)) { p.setPen(st::mediaviewCaptionFg); + const auto lineHeight = st::mediaviewCaptionStyle.font->height; _caption.draw(p, { .position = inner.topLeft(), .availableWidth = inner.width(), @@ -4919,8 +4920,31 @@ void OverlayWidget::paintCaptionContent( .spoiler = Ui::Text::DefaultSpoilerCache(), .pausedEmoji = On(PowerSaving::kEmojiChat), .pausedSpoiler = On(PowerSaving::kChatSpoiler), - .elisionLines = inner.height() / st::mediaviewCaptionStyle.font->height, + .elisionLines = inner.height() / lineHeight, + .elisionRemoveFromEnd = _captionSkipBlockWidth, }); + + if (_captionShowMoreWidth > 0) { + const auto padding = st::storiesShowMorePadding; + const auto showMoreLeft = outer.x() + + outer.width() + - padding.right() + - _captionShowMoreWidth; + const auto showMoreTop = outer.y() + + outer.height() + - padding.bottom() + - st::storiesShowMoreFont->height; + const auto underline = _captionExpandLink + && ClickHandler::showAsActive(_captionExpandLink); + p.setFont(underline + ? st::storiesShowMoreFont->underline() + : st::storiesShowMoreFont); + p.drawTextLeft( + showMoreLeft, + showMoreTop, + width(), + tr::lng_stories_show_more(tr::now)); + } } } @@ -5545,9 +5569,13 @@ void OverlayWidget::updateOver(QPoint pos) { lnk = textState.link; lnkhost = this; } else if (_captionRect.contains(pos)) { - auto textState = _caption.getState(pos - _captionRect.topLeft(), _captionRect.width()); + auto request = Ui::Text::StateRequestElided(); + const auto lineHeight = st::mediaviewCaptionStyle.font->height; + request.lines = _captionRect.height() / lineHeight; + request.removeFromEnd = _captionSkipBlockWidth; + auto textState = _caption.getStateElided(pos - _captionRect.topLeft(), _captionRect.width(), request); lnk = textState.link; - if (_stories && !_captionShownFull && !lnk) { + if (_stories && !lnk) { lnk = ensureCaptionExpandLink(); } lnkhost = this; @@ -5626,19 +5654,7 @@ void OverlayWidget::updateOver(QPoint pos) { ClickHandlerPtr OverlayWidget::ensureCaptionExpandLink() { if (!_captionExpandLink) { const auto toggle = crl::guard(_widget, [=] { - if (!_stories) { - return; - } else if (_captionExpanded) { - _captionExpanded = false; - _stories->setCaptionExpanded(false); - refreshCaptionGeometry(); - update(); - } else if (_captionFitsIfExpanded) { - _captionExpanded = true; - _stories->setCaptionExpanded(true); - refreshCaptionGeometry(); - update(); - } else { + if (_stories) { _stories->showFullCaption(); } }); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index b4a243f84..49727bb5d 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -587,9 +587,8 @@ private: Ui::Text::String _caption; QRect _captionRect; ClickHandlerPtr _captionExpandLink; - bool _captionShownFull = false; - bool _captionFitsIfExpanded = false; - bool _captionExpanded = false; + int _captionShowMoreWidth = 0; + int _captionSkipBlockWidth = 0; int _topNotchSize = 0; int _width = 0; From 0f2e8d9a794ed152d866979a1711ff854f0dc290 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 17:59:53 +0400 Subject: [PATCH 25/60] Add a small scale for stories siblings. --- .../media/stories/media_stories_sibling.cpp | 2 ++ .../media/stories/media_stories_view.h | 2 ++ .../media/view/media_view_overlay_opengl.cpp | 17 ++++++++++++++++- .../media/view/media_view_overlay_opengl.h | 3 +++ .../media/view/media_view_overlay_widget.cpp | 6 ++++-- .../media/view/media_view_overlay_widget.h | 4 +++- 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp b/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp index 1024edadb..791c8235f 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp @@ -32,6 +32,7 @@ constexpr auto kSiblingFade = 0.5; constexpr auto kSiblingFadeOver = 0.4; constexpr auto kSiblingNameOpacity = 0.8; constexpr auto kSiblingNameOpacityOver = 1.; +constexpr auto kSiblingScaleOver = 0.05; [[nodiscard]] StoryId LookupShownId( const Data::StoriesSource &source, @@ -325,6 +326,7 @@ SiblingView Sibling::view(const SiblingLayout &layout, float64 over) { .namePosition = namePosition(layout, name), .nameOpacity = (kSiblingNameOpacity * (1 - over) + kSiblingNameOpacityOver * over), + .scale = 1. + (over * kSiblingScaleOver), }; } diff --git a/Telegram/SourceFiles/media/stories/media_stories_view.h b/Telegram/SourceFiles/media/stories/media_stories_view.h index 08fe4cf1b..4d6cdac1e 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_view.h +++ b/Telegram/SourceFiles/media/stories/media_stories_view.h @@ -25,6 +25,7 @@ class Controller; struct ContentLayout { QRect geometry; float64 fade = 0.; + float64 scale = 1.; int radius = 0; bool headerOutside = false; }; @@ -39,6 +40,7 @@ struct SiblingView { QImage name; QPoint namePosition; float64 nameOpacity = 0.; + float64 scale = 1.; [[nodiscard]] bool valid() const { return !image.isNull(); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp index b3b26aeed..7851ed7f9 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp @@ -488,7 +488,9 @@ void OverlayWidget::RendererGL::paintTransformedContent( not_null program, ContentGeometry geometry, bool fillTransparentBackground) { - const auto rect = transformRect(geometry.rect); + const auto rect = scaleRect( + transformRect(geometry.rect), + geometry.scale); const auto centerx = rect.x() + rect.width() / 2; const auto centery = rect.y() + rect.height() / 2; const auto rsin = float(std::sin(geometry.rotation * M_PI / 180.)); @@ -1066,4 +1068,17 @@ Rect OverlayWidget::RendererGL::transformRect(const QRect &raster) const { return TransformRect(Rect(raster), _viewport, _factor); } +Rect OverlayWidget::RendererGL::scaleRect( + const Rect &unscaled, + float64 scale) const { + const auto added = scale - 1.; + const auto addw = unscaled.width() * added; + const auto addh = unscaled.height() * added; + return Rect( + unscaled.x() - addw / 2, + unscaled.y() - addh / 2, + unscaled.width() + addw, + unscaled.height() + addh); +} + } // namespace Media::View diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h index 4f769ce7b..a0342518a 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h @@ -97,6 +97,9 @@ private: [[nodiscard]] Ui::GL::Rect transformRect(const QRectF &raster) const; [[nodiscard]] Ui::GL::Rect transformRect( const Ui::GL::Rect &raster) const; + [[nodiscard]] Ui::GL::Rect scaleRect( + const Ui::GL::Rect &unscaled, + float64 scale) const; void uploadTexture( GLint internalformat, diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index a5f00bc3d..30dc08c71 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1795,11 +1795,13 @@ OverlayWidget::ContentGeometry OverlayWidget::contentGeometry() const { } OverlayWidget::ContentGeometry OverlayWidget::storiesContentGeometry( - const Stories::ContentLayout &layout) const { + const Stories::ContentLayout &layout, + float64 scale) const { return { .rect = QRectF(layout.geometry), .controlsOpacity = kStoriesControlsOpacity, .fade = layout.fade, + .scale = scale, .roundRadius = layout.radius, .topShadowShown = !layout.headerOutside, }; @@ -4458,7 +4460,7 @@ void OverlayWidget::paint(not_null renderer) { const auto paint = [&](const SiblingView &view, int index) { renderer->paintTransformedStaticContent( view.image, - storiesContentGeometry(view.layout), + storiesContentGeometry(view.layout, view.scale), false, // semi-transparent false, // fill transparent background index); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 49727bb5d..06d0c0468 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -180,6 +180,7 @@ private: // Stories. qreal fade = 0.; + qreal scale = 1.; int bottomShadowSkip = 0; int roundRadius = 0; bool topShadowShown = false; @@ -421,7 +422,8 @@ private: [[nodiscard]] QRect finalContentRect() const; [[nodiscard]] ContentGeometry contentGeometry() const; [[nodiscard]] ContentGeometry storiesContentGeometry( - const Stories::ContentLayout &layout) const; + const Stories::ContentLayout &layout, + float64 scale = 1.) const; void updateContentRect(); void contentSizeChanged(); From 6098e5ac33270a7d0591b13b9020cf996f9221b1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 18:03:02 +0400 Subject: [PATCH 26/60] Close stories on Key_Right press on last one. --- Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp | 4 +++- 1 file changed, 3 insertions(+), 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 30dc08c71..535beeb2a 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -5045,7 +5045,9 @@ void OverlayWidget::handleKeyPress(not_null e) { if (_controlsHideTimer.isActive()) { activateControls(); } - moveToNext(1); + if (!moveToNext(1) && _stories) { + storiesClose(); + } } else if (ctrl) { if (key == Qt::Key_Plus || key == Qt::Key_Equal From a85f33f7d36adbcd435b007a52e70175be3f39fa Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 20:08:26 +0400 Subject: [PATCH 27/60] Fix reactions strip glitch in story reply sending. --- Telegram/SourceFiles/media/stories/media_stories_reply.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp index 9df6d290f..7ea8ce8b7 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp @@ -186,8 +186,8 @@ void ReplyArea::send( session().api().sendMessage(std::move(message)); - _controls->clear(); finishSending(skipToast); + _controls->clear(); } void ReplyArea::sendVoice(VoiceToSend &&data) { @@ -276,8 +276,6 @@ void ReplyArea::sendInlineResult( action.generateLocal = true; session().api().sendInlineResult(bot, result, action, localMessageId); - _controls->clear(); - auto &bots = cRefRecentInlineBots(); const auto index = bots.indexOf(bot); if (index) { @@ -290,11 +288,12 @@ void ReplyArea::sendInlineResult( bot->session().local().writeRecentHashtagsAndBots(); } finishSending(); + _controls->clear(); } void ReplyArea::finishSending(bool skipToast) { _controls->hidePanelsAnimated(); - _controller->wrap()->setFocus(); + _controller->unfocusReply(); if (!skipToast) { _controller->uiShow()->showToast( tr::lng_stories_reply_sent(tr::now)); From 35f0f87f730fc16af5ae6fd5c90d35721c8c7a7d Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 20:24:13 +0400 Subject: [PATCH 28/60] Fix possible crash in story deletion. Fixes #26571. --- .../SourceFiles/media/stories/media_stories_controller.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index b94484a59..42cf67c5a 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -872,9 +872,10 @@ bool Controller::changeShown(Data::Story *story) { if (_shown == id && !sessionChanged) { return false; } - if (const auto now = this->story()) { - now->owner().stories().unregisterPolling( - now, + if (_shown) { + Assert(_session != nullptr); + _session->data().stories().unregisterPolling( + _shown, Data::Stories::Polling::Viewer); } if (sessionChanged) { From 30334b6c74d1eb53cd82a1d2d2ea35cb515f21e7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 20:50:21 +0400 Subject: [PATCH 29/60] Attempt to fix crash in story preloading. --- Telegram/SourceFiles/data/data_document.cpp | 3 ++- Telegram/SourceFiles/data/data_stories.h | 2 +- Telegram/SourceFiles/data/data_story.cpp | 2 ++ Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp | 3 ++- Telegram/SourceFiles/info/stories/info_stories_provider.cpp | 3 ++- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index c9e66759b..5852a9606 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { constexpr auto kDefaultCoverThumbnailSize = 100; +constexpr auto kMaxAllowedPreloadPrefix = 6 * 1024 * 1024; const auto kLottieStickerDimensions = QSize( kStickerSideSize, @@ -393,7 +394,7 @@ void DocumentData::setattributes( if (data.is_round_message()) { _additional = std::make_unique(); } else if (const auto size = data.vpreload_prefix_size()) { - if (size->v > 0) { + if (size->v > 0 && size->v < kMaxAllowedPreloadPrefix) { _videoPreloadPrefix = size->v; } } diff --git a/Telegram/SourceFiles/data/data_stories.h b/Telegram/SourceFiles/data/data_stories.h index c4d55a129..48ea79688 100644 --- a/Telegram/SourceFiles/data/data_stories.h +++ b/Telegram/SourceFiles/data/data_stories.h @@ -217,7 +217,7 @@ public: void registerPolling(not_null story, Polling polling); void unregisterPolling(not_null story, Polling polling); - bool registerPolling(FullStoryId id, Polling polling); + [[nodiscard]] bool registerPolling(FullStoryId id, Polling polling); void unregisterPolling(FullStoryId id, Polling polling); void requestUserStories( not_null user, diff --git a/Telegram/SourceFiles/data/data_story.cpp b/Telegram/SourceFiles/data/data_story.cpp index 2a139de87..fbc678581 100644 --- a/Telegram/SourceFiles/data/data_story.cpp +++ b/Telegram/SourceFiles/data/data_story.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "media/streaming/media_streaming_reader.h" #include "storage/download_manager_mtproto.h" +#include "storage/file_download.h" // kMaxFileInMemory #include "ui/text/text_utilities.h" namespace Data { @@ -574,6 +575,7 @@ void StoryPreload::load() { } _task = std::make_unique(id(), video, [=](QByteArray data) { if (!data.isEmpty()) { + Assert(data.size() < Storage::kMaxFileInMemory); _story->owner().cacheBigFile().putIfEmpty( key, Storage::Cache::Database::TaggedValue(std::move(data), 0)); diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp index ffedf1f50..b9f34f030 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lottie/lottie_frame_generator.h" #include "ffmpeg/ffmpeg_frame_generator.h" #include "chat_helpers/stickers_lottie.h" +#include "storage/file_download.h" // kMaxFileInMemory #include "ui/widgets/input_fields.h" #include "ui/text/text_custom_emoji.h" #include "ui/text/text_utilities.h" @@ -345,7 +346,7 @@ void CustomEmojiLoader::check() { }; auto put = [=, key = cacheKey(document)](QByteArray value) { const auto size = value.size(); - if (size <= Storage::Cache::Database::Settings().maxDataSize) { + if (size <= Storage::kMaxFileInMemory) { document->owner().cacheBigFile().put(key, std::move(value)); } else { LOG(("Data Error: Cached emoji size too big: %1.").arg(size)); diff --git a/Telegram/SourceFiles/info/stories/info_stories_provider.cpp b/Telegram/SourceFiles/info/stories/info_stories_provider.cpp index e582f9ce7..82f0ca5f2 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_provider.cpp +++ b/Telegram/SourceFiles/info/stories/info_stories_provider.cpp @@ -283,9 +283,10 @@ BaseLayout *Provider::getLayout( if (auto layout = createLayout(id, delegate)) { layout->initDimensions(); it = _layouts.emplace(id, std::move(layout)).first; - _peer->owner().stories().registerPolling( + const auto ok = _peer->owner().stories().registerPolling( { _peer->id, id }, Data::Stories::Polling::Chat); + Assert(ok); } else { return nullptr; } From 885a8b3161ee702276256c3da18193e04da4ab38 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 21:33:32 +0400 Subject: [PATCH 30/60] Attempt to fix a crash in pinned message translations. --- Telegram/SourceFiles/history/history_widget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index cc9e0d0e4..d69117441 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6564,6 +6564,8 @@ void HistoryWidget::checkPinnedBarState() { _list->setShownPinned( session().data().message( _pinnedTracker->currentMessageId().message)); + } else { + _list->setShownPinned(nullptr); } return std::move(content); })); From 642c5a37c59c7fb2aacf07180e8208d8f8bd9e9c Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 Jul 2023 21:34:40 +0400 Subject: [PATCH 31/60] Version 4.8.8. - Several crash fixes and story viewer 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 898e980a2..2d99765a2 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="4.8.8.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 8f8652e9e..207ce5673 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,8,7,0 - PRODUCTVERSION 4,8,7,0 + FILEVERSION 4,8,8,0 + PRODUCTVERSION 4,8,8,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "4.8.7.0" + VALUE "FileVersion", "4.8.8.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.8.7.0" + VALUE "ProductVersion", "4.8.8.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index c1a090788..65a32e4a7 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,8,7,0 - PRODUCTVERSION 4,8,7,0 + FILEVERSION 4,8,8,0 + PRODUCTVERSION 4,8,8,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -53,10 +53,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "4.8.7.0" + VALUE "FileVersion", "4.8.8.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.8.7.0" + VALUE "ProductVersion", "4.8.8.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 71ea8719a..630dfd075 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 = 4008007; -constexpr auto AppVersionStr = "4.8.7"; +constexpr auto AppVersion = 4008008; +constexpr auto AppVersionStr = "4.8.8"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 1322ed7d7..a0acebbbd 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 4008007 +AppVersion 4008008 AppVersionStrMajor 4.8 -AppVersionStrSmall 4.8.7 -AppVersionStr 4.8.7 +AppVersionStrSmall 4.8.8 +AppVersionStr 4.8.8 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 4.8.7 +AppVersionOriginal 4.8.8 diff --git a/changelog.txt b/changelog.txt index 314f815c6..0e476e2f1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +4.8.8 (25.07.23) + +- Several crash fixes and story viewer improvements. + 4.8.7 (21.07.23) - Several crash fixes and small stories improvements. From 2d31704bdee53a3bdba4582ad6da363c6672e384 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 09:45:06 +0400 Subject: [PATCH 32/60] Fix lock/unlock button visibility. --- Telegram/SourceFiles/dialogs/dialogs_widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index f6b506d0d..8fe35aba2 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1458,6 +1458,7 @@ void Widget::stopWidthAnimation() { } void Widget::updateStoriesVisibility() { + updateLockUnlockVisibility(); if (!_stories) { return; } @@ -1487,7 +1488,6 @@ void Widget::updateStoriesVisibility() { if (_aboveScrollAdded > 0 && _updateScrollGeometryCached) { _updateScrollGeometryCached(); } - updateLockUnlockVisibility(); updateLockUnlockPosition(); } } From e71f614f4dfe376e0a91f44b78bb9680ce91e098 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 09:48:44 +0400 Subject: [PATCH 33/60] Fix a possible crash in messages list. --- Telegram/SourceFiles/history/view/history_view_list_widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 9ca933844..5903fa94b 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -933,7 +933,7 @@ Element *ListWidget::viewByPosition(Data::MessagePosition position) const { const auto result = (index < 0) ? nullptr : _items[index].get(); return (position == Data::MinMessagePosition || position == Data::MaxMessagePosition - || result->data()->position() == position) + || (result && result->data()->position() == position)) ? result : nullptr; } From 37ab65d952262d947fba10887992fd742c4f0603 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 10:47:19 +0400 Subject: [PATCH 34/60] Allow editing photos in messages in ComposeControls. --- .../history_view_compose_controls.cpp | 207 +++++++++++++++--- 1 file changed, 173 insertions(+), 34 deletions(-) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 93550ba66..4901c3bf9 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -347,7 +347,7 @@ public: void setHistory(const SetHistoryArgs &args); void init(); - void editMessage(FullMsgId id); + void editMessage(FullMsgId id, bool photoEditAllowed = false); void replyToMessage(FullMsgId id); void updateForwarding( Data::Thread *thread, @@ -363,8 +363,10 @@ public: [[nodiscard]] bool readyToForward() const; [[nodiscard]] const HistoryItemsList &forwardItems() const; [[nodiscard]] FullMsgId replyingToMessage() const; - [[nodiscard]] rpl::producer editMsgId() const; + [[nodiscard]] FullMsgId editMsgId() const; + [[nodiscard]] rpl::producer editMsgIdValue() const; [[nodiscard]] rpl::producer scrollToItemRequests() const; + [[nodiscard]] rpl::producer<> editPhotoRequests() const; [[nodiscard]] MessageToEdit queryToEdit(); [[nodiscard]] WebPageId webPageId() const; @@ -425,16 +427,24 @@ private: HistoryItem *_shownMessage = nullptr; Ui::Text::String _shownMessageName; Ui::Text::String _shownMessageText; + std::unique_ptr _shownPreviewSpoiler; + Ui::Animations::Simple _inPhotoEditOver; int _shownMessageNameVersion = -1; - bool _repaintScheduled = false; + bool _shownMessageHasPreview : 1 = false; + bool _inPhotoEdit : 1 = false; + bool _photoEditAllowed : 1 = false; + bool _repaintScheduled : 1 = false; + bool _inClickable : 1 = false; const not_null _data; const not_null _cancel; QRect _clickableRect; + QRect _shownMessagePreviewRect; rpl::event_stream _visibleChanged; rpl::event_stream _scrollToItemRequests; + rpl::event_stream<> _editPhotoRequests; }; @@ -554,26 +564,45 @@ void FieldHeader::init() { }, lifetime()); setMouseTracking(true); - const auto inClickable = lifetime().make_state(false); events( ) | rpl::filter([=](not_null event) { - return ranges::contains(kMouseEvents, event->type()) + const auto type = event->type(); + const auto leaving = (type == QEvent::Leave); + return (ranges::contains(kMouseEvents, type) || leaving) && (isEditingMessage() || readyToForward() || replyingToMessage()); }) | rpl::start_with_next([=](not_null event) { - const auto type = event->type(); - const auto e = static_cast(event.get()); - const auto pos = e ? e->pos() : mapFromGlobal(QCursor::pos()); - const auto inPreviewRect = _clickableRect.contains(pos); - - if (type == QEvent::MouseMove) { - if (inPreviewRect != *inClickable) { - *inClickable = inPreviewRect; - setCursor(*inClickable + const auto updateOver = [&](bool inClickable, bool inPhotoEdit) { + if (_inClickable != inClickable) { + _inClickable = inClickable; + setCursor(_inClickable ? style::cur_pointer : style::cur_default); } + if (_inPhotoEdit != inPhotoEdit) { + _inPhotoEdit = inPhotoEdit; + _inPhotoEditOver.start( + [=] { update(); }, + _inPhotoEdit ? 0. : 1., + _inPhotoEdit ? 1. : 0., + st::defaultMessageBar.duration); + } + }; + const auto type = event->type(); + if (type == QEvent::Leave) { + updateOver(false, false); + return; + } + const auto e = static_cast(event.get()); + const auto pos = e ? e->pos() : mapFromGlobal(QCursor::pos()); + const auto inPreviewRect = _clickableRect.contains(pos); + const auto inPhotoEdit = _shownMessageHasPreview + && _photoEditAllowed + && _shownMessagePreviewRect.contains(pos); + + if (type == QEvent::MouseMove) { + updateOver(inPreviewRect, inPhotoEdit); return; } const auto isLeftIcon = (pos.x() < st::historyReplySkip); @@ -582,6 +611,8 @@ void FieldHeader::init() { if (isLeftButton && isLeftIcon) { *leftIconPressed = true; update(); + } else if (isLeftButton && inPhotoEdit) { + _editPhotoRequests.fire({}); } else if (isLeftButton && inPreviewRect) { if (!isEditingMessage() && readyToForward()) { _forwardPanel->editOptions(_show); @@ -794,20 +825,74 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) { } } + const auto media = _shownMessage->media(); + _shownMessageHasPreview = media && media->hasReplyPreview(); + const auto preview = _shownMessageHasPreview + ? media->replyPreview() + : nullptr; + const auto spoilered = preview && media->hasSpoiler(); + if (!spoilered) { + _shownPreviewSpoiler = nullptr; + } else if (!_shownPreviewSpoiler) { + _shownPreviewSpoiler = std::make_unique([=] { + update(); + }); + } + const auto previewSkipValue = st::msgReplyBarSize.height() + + st::msgReplyBarSkip + - st::msgReplyBarSize.width() + - st::msgReplyBarPos.x(); + const auto previewSkip = _shownMessageHasPreview ? previewSkipValue : 0; + const auto textLeft = replySkip + previewSkip; + const auto textAvailableWidth = availableWidth - previewSkip; + if (preview) { + const auto overEdit = _photoEditAllowed + ? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.) + : 0.; + const auto to = QRect( + replySkip, + st::msgReplyPadding.top(), + st::msgReplyBarSize.height(), + st::msgReplyBarSize.height()); + p.drawPixmap(to.x(), to.y(), preview->pixSingle( + preview->size() / style::DevicePixelRatio(), + { + .options = Images::Option::RoundSmall, + .outer = to.size(), + })); + if (_shownPreviewSpoiler) { + if (overEdit > 0.) { + p.setOpacity(1. - overEdit); + } + Ui::FillSpoilerRect( + p, + to, + Ui::DefaultImageSpoiler().frame( + _shownPreviewSpoiler->index(crl::now(), p.inactive()))); + } + if (overEdit > 0.) { + p.setOpacity(overEdit); + p.fillRect(to, st::historyEditMediaBg); + st::historyEditMedia.paintInCenter(p, to); + p.setOpacity(1.); + } + + } + p.setPen(st::historyReplyNameFg); p.setFont(st::msgServiceNameFont); _shownMessageName.drawElided( p, - replySkip, + textLeft, st::msgReplyPadding.top(), - availableWidth); + textAvailableWidth); p.setPen(st::historyComposeAreaFg); _shownMessageText.draw(p, { .position = QPoint( - replySkip, + textLeft, st::msgReplyPadding.top() + st::msgServiceNameFont->height), - .availableWidth = availableWidth, + .availableWidth = textAvailableWidth, .palette = &st::historyComposeAreaPalette, .spoiler = Ui::Text::DefaultSpoilerCache(), .now = crl::now(), @@ -848,6 +933,10 @@ bool FieldHeader::isEditingMessage() const { return !!_editMsgId.current(); } +FullMsgId FieldHeader::editMsgId() const { + return _editMsgId.current(); +} + bool FieldHeader::readyToForward() const { return !_forwardPanel->empty(); } @@ -879,10 +968,21 @@ void FieldHeader::updateControlsGeometry(QSize size) { 0, width() - st::historyReplySkip - _cancel->width(), height()); + _shownMessagePreviewRect = QRect( + st::historyReplySkip, + st::msgReplyPadding.top(), + st::msgReplyBarSize.height(), + st::msgReplyBarSize.height()); } -void FieldHeader::editMessage(FullMsgId id) { +void FieldHeader::editMessage(FullMsgId id, bool photoEditAllowed) { + _photoEditAllowed = photoEditAllowed; _editMsgId = id; + if (!photoEditAllowed) { + _inPhotoEdit = false; + _inPhotoEditOver.stop(); + } + update(); } void FieldHeader::replyToMessage(FullMsgId id) { @@ -898,7 +998,7 @@ void FieldHeader::updateForwarding( } } -rpl::producer FieldHeader::editMsgId() const { +rpl::producer FieldHeader::editMsgIdValue() const { return _editMsgId.value(); } @@ -906,6 +1006,10 @@ rpl::producer FieldHeader::scrollToItemRequests() const { return _scrollToItemRequests.events(); } +rpl::producer<> FieldHeader::editPhotoRequests() const { + return _editPhotoRequests.events(); +} + MessageToEdit FieldHeader::queryToEdit() { const auto item = _data->message(_editMsgId.current()); if (!isEditingMessage() || !item) { @@ -1470,7 +1574,7 @@ void ComposeControls::init() { paintBackground(clip); }, _wrap->lifetime()); - _header->editMsgId( + _header->editMsgIdValue( ) | rpl::start_with_next([=](const auto &id) { unregisterDraftSources(); updateSendButtonType(); @@ -1482,6 +1586,16 @@ void ComposeControls::init() { registerDraftSource(); }, _wrap->lifetime()); + _header->editPhotoRequests( + ) | rpl::start_with_next([=] { + EditCaptionBox::StartPhotoEdit( + _regularWindow, + _photoEditMedia, + _editingId, + _field->getTextWithTags(), + crl::guard(_wrap.get(), [=] { cancelEditMessage(); })); + }, _wrap->lifetime()); + _header->previewCancelled( ) | rpl::start_with_next([=] { if (_preview) { @@ -1521,7 +1635,7 @@ void ComposeControls::init() { _voiceRecordBar->requestToSendWithOptions(options); }, _wrap->lifetime()); - _header->editMsgId( + _header->editMsgIdValue( ) | rpl::start_with_next([=](const auto &id) { _editingId = id; }, _wrap->lifetime()); @@ -2051,7 +2165,43 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) { } if (draft == editDraft) { - _header->editMessage(editingId); + const auto resolve = [=] { + if (const auto item = _history->owner().message(editingId)) { + const auto media = item->media(); + _canReplaceMedia = media && media->allowsEditMedia(); + _photoEditMedia = (_canReplaceMedia + && _regularWindow + && media->photo() + && !media->photo()->isNull()) + ? media->photo()->createMediaView() + : nullptr; + if (_photoEditMedia) { + _photoEditMedia->wanted( + Data::PhotoSize::Large, + item->fullId()); + } + _header->editMessage(editingId, _photoEditMedia != nullptr); + return true; + } + _canReplaceMedia = false; + _photoEditMedia = nullptr; + _header->editMessage(editingId, false); + return false; + }; + if (!resolve()) { + const auto callback = crl::guard(_header.get(), [=] { + if (_header->editMsgId() == editingId + && resolve() + && updateReplaceMediaButton()) { + updateControlsVisibility(); + updateControlsGeometry(_wrap->size()); + } + }); + _history->session().api().requestMessageData( + _history->peer, + editingId.msg, + callback); + } _header->replyToMessage({}); } else { _canReplaceMedia = false; @@ -2710,17 +2860,6 @@ void ComposeControls::editMessage(not_null item) { cursor, previewState)); applyDraft(); - - const auto media = item->media(); - _canReplaceMedia = media && media->allowsEditMedia(); - _photoEditMedia = (_canReplaceMedia - && media->photo() - && !media->photo()->isNull()) - ? media->photo()->createMediaView() - : nullptr; - if (_photoEditMedia) { - _photoEditMedia->wanted(Data::PhotoSize::Large, item->fullId()); - } if (updateReplaceMediaButton()) { updateControlsVisibility(); updateControlsGeometry(_wrap->size()); From 5dc35bc75f95a935c5b9981a3433cc6cd0b133ea Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 12:00:43 +0400 Subject: [PATCH 35/60] Fix userpics in "Who Read" menu. --- .../ui/controls/who_reacted_context_action.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/ui/controls/who_reacted_context_action.cpp b/Telegram/SourceFiles/ui/controls/who_reacted_context_action.cpp index ae9acc05d..4a7dcb337 100644 --- a/Telegram/SourceFiles/ui/controls/who_reacted_context_action.cpp +++ b/Telegram/SourceFiles/ui/controls/who_reacted_context_action.cpp @@ -165,8 +165,9 @@ Action::Action( + _st.itemStyle.font->height + st::defaultWhoRead.itemPadding.bottom()) { const auto parent = parentMenu->menu(); - const auto checkAppeared = [=, now = crl::now()] { - _appeared = (crl::now() - now) >= parentMenu->st().duration; + const auto delay = anim::Disabled() ? 0 : parentMenu->st().duration; + const auto checkAppeared = [=, now = crl::now()](bool force = false) { + _appeared = force || ((crl::now() - now) >= delay); }; setAcceptBoth(true); @@ -224,8 +225,10 @@ Action::Action( enableMouseSelecting(); base::call_delayed(parentMenu->st().duration, this, [=] { - checkAppeared(); - updateUserpicsFromContent(); + if (!_appeared) { + checkAppeared(true); + updateUserpicsFromContent(); + } }); } From 3654c197a9b2de0e92b30a4890abfdefb20c647b Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 12:00:57 +0400 Subject: [PATCH 36/60] Fix DirectManipulation scroll events in media viewer. --- .../SourceFiles/media/view/media_view_overlay_widget.cpp | 6 ++++-- Telegram/lib_ui | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 535beeb2a..75faf2be5 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -5065,20 +5065,22 @@ void OverlayWidget::handleKeyPress(not_null e) { void OverlayWidget::handleWheelEvent(not_null e) { constexpr auto step = int(QWheelEvent::DefaultDeltasPerStep); + const auto acceptForJump = (e->source() == Qt::MouseEventNotSynthesized) + || (e->source() == Qt::MouseEventSynthesizedBySystem); _verticalWheelDelta += e->angleDelta().y(); while (qAbs(_verticalWheelDelta) >= step) { if (_verticalWheelDelta < 0) { _verticalWheelDelta += step; if (e->modifiers().testFlag(Qt::ControlModifier)) { zoomOut(); - } else if (e->source() == Qt::MouseEventNotSynthesized) { + } else if (acceptForJump) { moveToNext(1); } } else { _verticalWheelDelta -= step; if (e->modifiers().testFlag(Qt::ControlModifier)) { zoomIn(); - } else if (e->source() == Qt::MouseEventNotSynthesized) { + } else if (acceptForJump) { moveToNext(-1); } } diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 2f0ac3822..91d43ea4b 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 2f0ac382289d0584002c007bdf2b3e4464f75b58 +Subproject commit 91d43ea4b50ef1e7df810ab1f14c49e044570734 From ce39431beb14eb658082d447d0d37c0b16088e32 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 12:01:53 +0400 Subject: [PATCH 37/60] Don't jump by scroll events in stories viewer. --- .../SourceFiles/media/view/media_view_overlay_widget.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 75faf2be5..2f2cf164c 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -5065,8 +5065,9 @@ void OverlayWidget::handleKeyPress(not_null e) { void OverlayWidget::handleWheelEvent(not_null e) { constexpr auto step = int(QWheelEvent::DefaultDeltasPerStep); - const auto acceptForJump = (e->source() == Qt::MouseEventNotSynthesized) - || (e->source() == Qt::MouseEventSynthesizedBySystem); + const auto acceptForJump = !_stories + && ((e->source() == Qt::MouseEventNotSynthesized) + || (e->source() == Qt::MouseEventSynthesizedBySystem)); _verticalWheelDelta += e->angleDelta().y(); while (qAbs(_verticalWheelDelta) >= step) { if (_verticalWheelDelta < 0) { From 16820139dd6e46ee5d8af73122b2bc6ed34a93f7 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 26 Jul 2023 03:25:01 +0300 Subject: [PATCH 38/60] Improved style of stickers settings box. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/boxes/stickers_box.cpp | 181 +++++++++++------- .../chat_helpers/chat_helpers.style | 6 + 3 files changed, 115 insertions(+), 73 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index e966fe52d..3a6b93532 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1926,6 +1926,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_switch_gifs" = "GIFs"; "lng_switch_masks" = "Masks"; "lng_stickers_featured_add" = "Add"; +"lng_stickers_featured_installed" = "Added"; "lng_emoji_featured_unlock" = "Unlock"; "lng_emoji_premium_restore" = "Restore"; "lng_gifs_search" = "Search GIFs"; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 29a16c78e..32295cf08 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -211,7 +211,7 @@ private: void setActionDown(int newActionDown); void setPressed(SelectedRow pressed); void setup(); - QRect relativeButtonRect(bool removeButton) const; + QRect relativeButtonRect(bool removeButton, bool installedSet) const; void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton); bool shiftingAnimationCallback(crl::time now); @@ -234,7 +234,7 @@ private: void readVisibleSets(); void updateControlsGeometry(); - void rebuildAppendSet(not_null set, int maxNameWidth); + void rebuildAppendSet(not_null set); void fillSetCover(not_null set, DocumentData **outSticker, int *outWidth, int *outHeight) const; int fillSetCount(not_null set) const; [[nodiscard]] QString fillSetTitle( @@ -247,7 +247,7 @@ private: void handleMegagroupSetAddressChange(); void setMegagroupSelectedSet(const StickerSetIdentifier &set); - int countMaxNameWidth() const; + int countMaxNameWidth(bool installedSet) const; [[nodiscard]] bool skipPremium() const; const std::shared_ptr _show; @@ -255,9 +255,9 @@ private: MTP::Sender _api; const Section _section; - const bool _isInstalled; + const bool _isInstalledTab; - Ui::RoundRect _buttonBgOver, _buttonBg; + Ui::RoundRect _buttonBgOver, _buttonBg, _inactiveButtonBg; int32 _rowHeight = 0; @@ -282,6 +282,8 @@ private: int _addWidth = 0; QString _undoText; int _undoWidth = 0; + QString _installedText; + int _installedWidth = 0; QPoint _mouse; bool _inDragArea = false; @@ -678,19 +680,19 @@ void StickersBox::refreshTabs() { _tabIndices.clear(); auto sections = std::vector(); if (_installed.widget()) { - sections.push_back(tr::lng_stickers_installed_tab(tr::now).toUpper()); + sections.push_back(tr::lng_stickers_installed_tab(tr::now)); _tabIndices.push_back(Section::Installed); } if (_masks.widget()) { - sections.push_back(tr::lng_stickers_masks_tab(tr::now).toUpper()); + sections.push_back(tr::lng_stickers_masks_tab(tr::now)); _tabIndices.push_back(Section::Masks); } if (!stickers.featuredSetsOrder().isEmpty() && _featured.widget()) { - sections.push_back(tr::lng_stickers_featured_tab(tr::now).toUpper()); + sections.push_back(tr::lng_stickers_featured_tab(tr::now)); _tabIndices.push_back(Section::Featured); } if (!archivedSetsOrder().isEmpty() && _archived.widget()) { - sections.push_back(tr::lng_stickers_archived_tab(tr::now).toUpper()); + sections.push_back(tr::lng_stickers_archived_tab(tr::now)); _tabIndices.push_back(Section::Archived); } _tabs->setSections(sections); @@ -771,7 +773,7 @@ void StickersBox::updateTabsGeometry() { auto featuredLeft = width() / maxTabs; auto featuredRight = 2 * width() / maxTabs; - auto featuredTextWidth = st::stickersTabs.labelStyle.font->width(tr::lng_stickers_featured_tab(tr::now).toUpper()); + auto featuredTextWidth = st::stickersTabs.labelStyle.font->width(tr::lng_stickers_featured_tab(tr::now)); auto featuredTextRight = featuredLeft + (featuredRight - featuredLeft - featuredTextWidth) / 2 + featuredTextWidth; auto unreadBadgeLeft = featuredTextRight - st::stickersFeaturedBadgeSkip; auto unreadBadgeTop = st::stickersFeaturedBadgeTop; @@ -1133,26 +1135,32 @@ StickersBox::Inner::Inner( , _session(&_show->session()) , _api(&_session->mtp()) , _section(section) -, _isInstalled(_section == Section::Installed || _section == Section::Masks) +, _isInstalledTab(_section == Section::Installed + || _section == Section::Masks) , _buttonBgOver( - ImageRoundRadius::Small, - (_isInstalled + ImageRoundRadius::Large, + (_isInstalledTab ? st::stickersUndoRemove : st::stickersTrendingAdd).textBgOver) , _buttonBg( - ImageRoundRadius::Small, - (_isInstalled + ImageRoundRadius::Large, + (_isInstalledTab ? st::stickersUndoRemove : st::stickersTrendingAdd).textBg) +, _inactiveButtonBg( + ImageRoundRadius::Large, + st::stickersTrendingInstalled.textBg) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _shiftingAnimation([=](crl::time now) { return shiftingAnimationCallback(now); }) , _itemsTop(st::membersMarginTop) -, _addText(tr::lng_stickers_featured_add(tr::now).toUpper()) +, _addText(tr::lng_stickers_featured_add(tr::now)) , _addWidth(st::stickersTrendingAdd.font->width(_addText)) -, _undoText(tr::lng_stickers_return(tr::now).toUpper()) -, _undoWidth(st::stickersUndoRemove.font->width(_undoText)) { +, _undoText(tr::lng_stickers_return(tr::now)) +, _undoWidth(st::stickersUndoRemove.font->width(_undoText)) +, _installedText(tr::lng_stickers_featured_installed(tr::now)) +, _installedWidth(st::stickersTrendingInstalled.font->width(_installedText)) { setup(); } @@ -1165,17 +1173,21 @@ StickersBox::Inner::Inner( , _session(&_show->session()) , _api(&_session->mtp()) , _section(StickersBox::Section::Installed) -, _isInstalled(_section == Section::Installed || _section == Section::Masks) +, _isInstalledTab(_section == Section::Installed + || _section == Section::Masks) , _buttonBgOver( - ImageRoundRadius::Small, - (_isInstalled + ImageRoundRadius::Large, + (_isInstalledTab ? st::stickersUndoRemove : st::stickersTrendingAdd).textBgOver) , _buttonBg( - ImageRoundRadius::Small, - (_isInstalled + ImageRoundRadius::Large, + (_isInstalledTab ? st::stickersUndoRemove : st::stickersTrendingAdd).textBg) +, _inactiveButtonBg( + ImageRoundRadius::Large, + st::stickersTrendingInstalled.textBg) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _shiftingAnimation([=](crl::time now) { return shiftingAnimationCallback(now); @@ -1295,15 +1307,23 @@ void StickersBox::Inner::updateControlsGeometry() { } } -QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const { +QRect StickersBox::Inner::relativeButtonRect( + bool removeButton, + bool installedSet) const { auto buttonw = st::stickersRemove.width; auto buttonh = st::stickersRemove.height; auto buttonshift = st::stickersRemoveSkip; if (!removeButton) { - const auto &st = _isInstalled + const auto &st = installedSet + ? st::stickersTrendingInstalled + : _isInstalledTab ? st::stickersUndoRemove : st::stickersTrendingAdd; - const auto textWidth = _isInstalled ? _undoWidth : _addWidth; + const auto textWidth = installedSet + ? _installedWidth + : _isInstalledTab + ? _undoWidth + : _addWidth; buttonw = textWidth - st.width; buttonh = st.height; buttonshift = 0; @@ -1332,7 +1352,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null row, int index) { } } - if (_isInstalled) { + if (_isInstalledTab) { if (index >= 0 && index == _above) { auto current = _aboveShadowFadeOpacity.current(); if (_started >= 0) { @@ -1359,13 +1379,13 @@ void StickersBox::Inner::paintRow(Painter &p, not_null row, int index) { paintFakeButton(p, row, index); } - if (row->removed && _isInstalled) { + if (row->removed && _isInstalledTab) { p.setOpacity(st::stickersRowDisabledOpacity); } auto stickerx = st::contactsPadding.left(); - if (!_megagroupSet && _isInstalled) { + if (!_megagroupSet && _isInstalledTab) { stickerx += st::stickersReorderIcon.width() + st::stickersReorderSkip; if (!row->isRecentSet()) { st::stickersReorderIcon.paint(p, st::contactsPadding.left(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width()); @@ -1553,7 +1573,7 @@ void StickersBox::Inner::updateRowThumbnail(not_null row) { Unexpected("StickersBox::Inner::updateRowThumbnail: row not found"); }(); const auto left = st::contactsPadding.left() - + ((!_megagroupSet && _isInstalled) + + ((!_megagroupSet && _isInstalledTab) ? st::stickersReorderIcon.width() + st::stickersReorderSkip : 0); update( @@ -1564,14 +1584,19 @@ void StickersBox::Inner::updateRowThumbnail(not_null row) { } void StickersBox::Inner::paintFakeButton(Painter &p, not_null row, int index) { - auto removeButton = (_isInstalled && !row->removed); - auto rect = relativeButtonRect(removeButton); - if (!_isInstalled && row->isInstalled() && !row->isArchived() && !row->removed) { - // Checkbox after installed from Trending or Archived. - int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (rect.width() + st::stickersFeaturedInstalled.width()) / 2); - int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2; - st::stickersFeaturedInstalled.paint(p, QPoint(checkx, checky), width()); + const auto removeButton = (_isInstalledTab && !row->removed); + if (!_isInstalledTab && row->isInstalled() && !row->isArchived() && !row->removed) { + // Round button "Added" after installed from Trending or Archived. + const auto rect = relativeButtonRect(removeButton, true); + const auto &st = st::stickersTrendingInstalled; + const auto textWidth = _installedWidth; + const auto &text = _installedText; + _inactiveButtonBg.paint(p, myrtlrect(rect)); + p.setFont(st.font); + p.setPen(st.textFg); + p.drawTextLeft(rect.x() - (st.width / 2), rect.y() + st.textTop, width(), text, textWidth); } else { + const auto rect = relativeButtonRect(removeButton, false); auto selected = (index == _actionSel && _actionDown < 0) || (index == _actionDown); if (removeButton) { // Trash icon button when not disabled in Installed. @@ -1589,11 +1614,11 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null row, int ind } else { // Round button ADD when not installed from Trending or Archived. // Or round button UNDO after disabled from Installed. - const auto &st = _isInstalled + const auto &st = _isInstalledTab ? st::stickersUndoRemove : st::stickersTrendingAdd; - const auto textWidth = _isInstalled ? _undoWidth : _addWidth; - const auto &text = _isInstalled ? _undoText : _addText; + const auto textWidth = _isInstalledTab ? _undoWidth : _addWidth; + const auto &text = _isInstalledTab ? _undoText : _addText; (selected ? _buttonBgOver : _buttonBg).paint(p, myrtlrect(rect)); if (row->ripple) { row->ripple->paint(p, rect.x(), rect.y(), width()); @@ -1618,7 +1643,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) { setActionDown(_actionSel); update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); } else if (auto selectedIndex = std::get_if(&_selected)) { - if (_isInstalled && !_rows[*selectedIndex]->isRecentSet() && _inDragArea) { + if (_isInstalledTab && !_rows[*selectedIndex]->isRecentSet() && _inDragArea) { _above = _dragging = _started = *selectedIndex; _dragStart = mapFromGlobal(_mouse); } @@ -1640,12 +1665,12 @@ void StickersBox::Inner::setActionDown(int newActionDown) { if (_actionDown >= 0 && _actionDown < _rows.size()) { update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight); const auto row = _rows[_actionDown].get(); - auto removeButton = (_isInstalled && !row->removed); + auto removeButton = (_isInstalledTab && !row->removed); if (!row->ripple) { - if (_isInstalled) { + if (_isInstalledTab) { if (row->removed) { auto rippleSize = QSize(_undoWidth - st::stickersUndoRemove.width, st::stickersUndoRemove.height); - auto rippleMask = Ui::RippleAnimation::RoundRectMask(rippleSize, st::roundRadiusSmall); + auto rippleMask = Ui::RippleAnimation::RoundRectMask(rippleSize, st::roundRadiusLarge); ensureRipple(st::stickersUndoRemove.ripple, std::move(rippleMask), removeButton); } else { auto rippleSize = st::stickersRemove.rippleAreaSize; @@ -1654,12 +1679,12 @@ void StickersBox::Inner::setActionDown(int newActionDown) { } } else if (!row->isInstalled() || row->isArchived() || row->removed) { auto rippleSize = QSize(_addWidth - st::stickersTrendingAdd.width, st::stickersTrendingAdd.height); - auto rippleMask = Ui::RippleAnimation::RoundRectMask(rippleSize, st::roundRadiusSmall); + auto rippleMask = Ui::RippleAnimation::RoundRectMask(rippleSize, st::roundRadiusLarge); ensureRipple(st::stickersTrendingAdd.ripple, std::move(rippleMask), removeButton); } } if (row->ripple) { - auto rect = relativeButtonRect(removeButton); + auto rect = relativeButtonRect(removeButton, false); row->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(myrtlrect(rect).x(), _itemsTop + _actionDown * _rowHeight + rect.y())); } } @@ -1722,7 +1747,7 @@ void StickersBox::Inner::setPressed(SelectedRow pressed) { void StickersBox::Inner::ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton) { _rows[_actionDown]->ripple = std::make_unique(st, std::move(mask), [this, index = _actionDown, removeButton] { - update(myrtlrect(relativeButtonRect(removeButton).translated(0, _itemsTop + index * _rowHeight))); + update(myrtlrect(relativeButtonRect(removeButton, false).translated(0, _itemsTop + index * _rowHeight))); }); } @@ -1785,14 +1810,14 @@ void StickersBox::Inner::updateSelected() { selected = selectedIndex; local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight); const auto row = _rows[selectedIndex].get(); - if (!_megagroupSet && (_isInstalled || !row->isInstalled() || row->isArchived() || row->removed)) { - auto removeButton = (_isInstalled && !row->removed); - auto rect = myrtlrect(relativeButtonRect(removeButton)); + if (!_megagroupSet && (_isInstalledTab || !row->isInstalled() || row->isArchived() || row->removed)) { + auto removeButton = (_isInstalledTab && !row->removed); + auto rect = myrtlrect(relativeButtonRect(removeButton, false)); actionSel = rect.contains(local) ? selectedIndex : -1; } else { actionSel = -1; } - if (!_megagroupSet && _isInstalled && !row->isRecentSet()) { + if (!_megagroupSet && _isInstalledTab && !row->isRecentSet()) { auto dragAreaWidth = st::contactsPadding.left() + st::stickersReorderIcon.width() + st::stickersReorderSkip; auto dragArea = myrtlrect(0, 0, dragAreaWidth, _rowHeight); inDragArea = dragArea.contains(local); @@ -1816,7 +1841,7 @@ void StickersBox::Inner::updateSelected() { void StickersBox::Inner::updateCursor() { setCursor(_inDragArea ? style::cur_sizeall - : (!_megagroupSet && _isInstalled) + : (!_megagroupSet && _isInstalledTab) ? ((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel)) ? style::cur_pointer : style::cur_default) @@ -1841,7 +1866,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) { _mouse = e->globalPos(); updateSelected(); if (_actionDown == _actionSel && _actionSel >= 0) { - if (_isInstalled) { + if (_isInstalledTab) { setRowRemoved(_actionDown, !_rows[_actionDown]->removed); } else if (_installSetCallback) { _installSetCallback(_rows[_actionDown]->set->id); @@ -2079,15 +2104,15 @@ void StickersBox::Inner::rebuildMegagroupSet() { } const auto set = it->second.get(); - auto maxNameWidth = countMaxNameWidth(); - auto titleWidth = 0; - auto title = fillSetTitle(set, maxNameWidth, &titleWidth); auto count = fillSetCount(set); auto sticker = (DocumentData*)nullptr; auto pixw = 0, pixh = 0; fillSetCover(set, &sticker, &pixw, &pixh); auto flagsOverride = SetFlag::Installed; auto removed = false; + auto maxNameWidth = countMaxNameWidth(!_isInstalledTab); + auto titleWidth = 0; + auto title = fillSetTitle(set, maxNameWidth, &titleWidth); if (!_megagroupSelectedSet || _megagroupSelectedSet->set->id != set->id) { _megagroupSetField->setText(set->shortName); @@ -2125,8 +2150,6 @@ void StickersBox::Inner::rebuild(bool masks) { rebuildMegagroupSet(); } - auto maxNameWidth = countMaxNameWidth(); - _oldRows = std::move(_rows); clear(); const auto &order = ([&]() -> const StickersSetsOrder & { @@ -2155,12 +2178,12 @@ void StickersBox::Inner::rebuild(bool masks) { ? tr::lng_stickers_group_from_featured(tr::now) : tr::lng_stickers_group_from_your(tr::now)); updateControlsGeometry(); - } else if (_isInstalled) { + } else if (_isInstalledTab) { const auto cloudIt = sets.find((_section == Section::Masks) ? Data::Stickers::CloudRecentAttachedSetId : Data::Stickers::CloudRecentSetId); // Section::Installed. if (cloudIt != sets.cend() && !cloudIt->second->stickers.isEmpty()) { - rebuildAppendSet(cloudIt->second.get(), maxNameWidth); + rebuildAppendSet(cloudIt->second.get()); } } for (const auto setId : order) { @@ -2170,7 +2193,7 @@ void StickersBox::Inner::rebuild(bool masks) { } const auto set = it->second.get(); - rebuildAppendSet(set, maxNameWidth); + rebuildAppendSet(set); if (set->stickers.isEmpty() || (set->flags & SetFlag::NotLoaded)) { @@ -2205,7 +2228,8 @@ void StickersBox::Inner::updateSize(int newWidth) { } void StickersBox::Inner::updateRows() { - int maxNameWidth = countMaxNameWidth(); + const auto maxNameWidth = countMaxNameWidth(false); + const auto maxNameWidthInstalled = countMaxNameWidth(true); const auto &sets = session().data().stickers().sets(); for (const auto &row : _rows) { const auto it = sets.find(row->set->id); @@ -2231,7 +2255,7 @@ void StickersBox::Inner::updateRows() { auto wasInstalled = row->isInstalled(); auto wasArchived = row->isArchived(); row->flagsOverride = fillSetFlags(set); - if (_isInstalled) { + if (_isInstalledTab) { row->flagsOverride &= ~SetFlag::Archived; } if (row->isInstalled() != wasInstalled @@ -2239,7 +2263,14 @@ void StickersBox::Inner::updateRows() { row->ripple.reset(); } } - row->title = fillSetTitle(set, maxNameWidth, &row->titleWidth); + const auto installedSet = (!_isInstalledTab + && row->isInstalled() + && !row->isArchived() + && !row->removed); + row->title = fillSetTitle( + set, + installedSet ? maxNameWidthInstalled : maxNameWidth, + &row->titleWidth); row->count = fillSetCount(set); } update(); @@ -2251,7 +2282,7 @@ bool StickersBox::Inner::appendSet(not_null set) { return false; } } - rebuildAppendSet(set, countMaxNameWidth()); + rebuildAppendSet(set); return true; } @@ -2259,18 +2290,20 @@ bool StickersBox::Inner::skipPremium() const { return !_session->premiumPossible(); } -int StickersBox::Inner::countMaxNameWidth() const { +int StickersBox::Inner::countMaxNameWidth(bool installedSet) const { int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); - if (!_megagroupSet && _isInstalled) { + if (!_megagroupSet && _isInstalledTab) { namex += st::stickersReorderIcon.width() + st::stickersReorderSkip; } int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); - if (_isInstalled) { + if (_isInstalledTab) { if (!_megagroupSet) { namew -= _undoWidth - st::stickersUndoRemove.width; } } else { - namew -= _addWidth - st::stickersTrendingAdd.width; + namew -= installedSet + ? (_installedWidth - st::stickersTrendingInstalled.width) + : (_addWidth - st::stickersTrendingAdd.width); if (_section == Section::Featured) { namew -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; } @@ -2278,14 +2311,12 @@ int StickersBox::Inner::countMaxNameWidth() const { return namew; } -void StickersBox::Inner::rebuildAppendSet( - not_null set, - int maxNameWidth) { +void StickersBox::Inner::rebuildAppendSet(not_null set) { auto flagsOverride = (set->id != Data::Stickers::CloudRecentSetId) ? fillSetFlags(set) : SetFlag::Installed; auto removed = false; - if (_isInstalled && (flagsOverride & SetFlag::Archived)) { + if (_isInstalledTab && (flagsOverride & SetFlag::Archived)) { return; } @@ -2293,6 +2324,10 @@ void StickersBox::Inner::rebuildAppendSet( int pixw = 0, pixh = 0; fillSetCover(set, &sticker, &pixw, &pixh); + const auto maxNameWidth = countMaxNameWidth(!_isInstalledTab + && (flagsOverride & SetFlag::Installed) + && !(flagsOverride & SetFlag::Archived) + && !removed); int titleWidth = 0; QString title = fillSetTitle(set, maxNameWidth, &titleWidth); int count = fillSetCount(set); diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index b1b3583ac..cf5961705 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -288,6 +288,12 @@ stickersTrendingAdd: RoundButton(defaultActiveButton) { height: 26px; textTop: 4px; } +stickersTrendingInstalled: RoundButton(stickersTrendingAdd) { + textFg: activeButtonBg; + textFgOver: activeButtonBgOver; + textBg: activeButtonSecondaryFg; + textBgOver: activeButtonSecondaryFgOver; +} stickersRemove: IconButton(defaultIconButton) { width: 40px; height: 40px; From 16e5792f3af481a6309cb76ac823ac304674e5d6 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 26 Jul 2023 04:23:14 +0300 Subject: [PATCH 39/60] Improved style of buttons in stickers search results. --- .../chat_helpers/chat_helpers.style | 3 - .../chat_helpers/stickers_list_widget.cpp | 81 ++++++++++++------- .../chat_helpers/stickers_list_widget.h | 8 +- .../SourceFiles/media/view/media_view.style | 1 - 4 files changed, 58 insertions(+), 35 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index cf5961705..e791a7a35 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -105,7 +105,6 @@ EmojiPan { trendingHeaderFg: color; trendingSubheaderFg: color; trendingUnreadFg: color; - trendingInstalled: icon; overBg: color; pathBg: color; pathFg: color; @@ -330,7 +329,6 @@ stickersFeaturedUnreadBg: msgFileInBg; stickersFeaturedUnreadSize: 5px; stickersFeaturedUnreadSkip: 5px; stickersFeaturedUnreadTop: 7px; -stickersFeaturedInstalled: icon {{ "chat/input_save", lightButtonFg }}; stickersMaxHeight: 320px; stickersPadding: margins(19px, 13px, 19px, 13px); @@ -597,7 +595,6 @@ defaultEmojiPan: EmojiPan { trendingHeaderFg: stickersTrendingHeaderFg; trendingSubheaderFg: stickersTrendingSubheaderFg; trendingUnreadFg: stickersFeaturedUnreadBg; - trendingInstalled: stickersFeaturedInstalled; overBg: emojiPanHover; pathBg: windowBgRipple; pathFg: windowBgOver; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index afee47efd..3675c0483 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -186,7 +186,7 @@ StickersListWidget::StickersListWidget( , _mode(descriptor.mode) , _show(std::move(descriptor.show)) , _features(descriptor.features) -, _overBg(st::roundRadiusSmall, st().overBg) +, _overBg(st::roundRadiusLarge, st().overBg) , _api(&session().mtp()) , _localSetsManager(std::make_unique(&session())) , _section(Section::Stickers) @@ -194,22 +194,27 @@ StickersListWidget::StickersListWidget( , _updateItemsTimer([=] { updateItems(); }) , _updateSetsTimer([=] { updateSets(); }) , _trendingAddBgOver( - ImageRoundRadius::Small, + ImageRoundRadius::Large, st::stickersTrendingAdd.textBgOver) -, _trendingAddBg(ImageRoundRadius::Small, st::stickersTrendingAdd.textBg) +, _trendingAddBg(ImageRoundRadius::Large, st::stickersTrendingAdd.textBg) +, _inactiveButtonBg( + ImageRoundRadius::Large, + st::stickersTrendingInstalled.textBg) , _groupCategoryAddBgOver( - ImageRoundRadius::Small, + ImageRoundRadius::Large, st::stickerGroupCategoryAdd.textBgOver) , _groupCategoryAddBg( - ImageRoundRadius::Small, + ImageRoundRadius::Large, st::stickerGroupCategoryAdd.textBg) , _pathGradient(std::make_unique( st().pathBg, st().pathFg, [=] { update(); })) , _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st().headerLeft) -, _addText(tr::lng_stickers_featured_add(tr::now).toUpper()) +, _addText(tr::lng_stickers_featured_add(tr::now)) , _addWidth(st::stickersTrendingAdd.font->width(_addText)) +, _installedText(tr::lng_stickers_featured_installed(tr::now)) +, _installedWidth(st::stickersTrendingInstalled.font->width(_installedText)) , _settings(this, tr::lng_stickers_you_have(tr::now)) , _previewTimer([=] { showPreview(); }) , _premiumMark(std::make_unique(&session())) @@ -896,26 +901,40 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { : loadedCount; auto widthForTitle = stickersRight() - (st().headerLeft - st().margin.left()); - if (featuredHasAddButton(info.section)) { - auto add = featuredAddRect(info); - auto selected = selectedButton ? (selectedButton->section == info.section) : false; - (selected ? _trendingAddBgOver : _trendingAddBg).paint(p, myrtlrect(add)); + { + const auto installedSet = !featuredHasAddButton(info.section); + const auto add = featuredAddRect(info, installedSet); + const auto selected = selectedButton + ? (selectedButton->section == info.section) + : false; + (installedSet + ? _inactiveButtonBg + : selected + ? _trendingAddBgOver + : _trendingAddBg).paint(p, myrtlrect(add)); if (set.ripple) { set.ripple->paint(p, add.x(), add.y(), width()); if (set.ripple->empty()) { set.ripple.reset(); } } - p.setFont(st::stickersTrendingAdd.font); - p.setPen(selected ? st::stickersTrendingAdd.textFgOver : st::stickersTrendingAdd.textFg); - p.drawTextLeft(add.x() - (st::stickersTrendingAdd.width / 2), add.y() + st::stickersTrendingAdd.textTop, width(), _addText, _addWidth); + const auto &text = installedSet ? _installedText : _addText; + const auto textWidth = installedSet + ? _installedWidth + : _addWidth; + const auto &st = installedSet + ? st::stickersTrendingInstalled + : st::stickersTrendingAdd; + p.setFont(st.font); + p.setPen(selected ? st.textFgOver : st.textFg); + p.drawTextLeft( + add.x() - (st.width / 2), + add.y() + st.textTop, + width(), + text, + textWidth); - widthForTitle -= add.width() - (st::stickersTrendingAdd.width / 2); - } else { - auto add = featuredAddRect(info); - int checkx = add.left() + (add.width() - st::stickersFeaturedInstalled.width()) / 2; - int checky = add.top() + (add.height() - st::stickersFeaturedInstalled.height()) / 2; - st().trendingInstalled.paint(p, QPoint(checkx, checky), width()); + widthForTitle -= add.width() - (st.width / 2); } if (set.flags & SetFlag::Unread) { widthForTitle -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; @@ -1453,14 +1472,17 @@ bool StickersListWidget::featuredHasAddButton(int index) const { } QRect StickersListWidget::featuredAddRect(int index) const { - return featuredAddRect(sectionInfo(index)); + return featuredAddRect(sectionInfo(index), false); } -QRect StickersListWidget::featuredAddRect(const SectionInfo &info) const { - auto addw = _addWidth - st::stickersTrendingAdd.width; - auto addh = st::stickersTrendingAdd.height; - auto addx = stickersRight() - addw; - auto addy = info.top + st::stickersTrendingAddTop; +QRect StickersListWidget::featuredAddRect( + const SectionInfo &info, + bool installedSet) const { + const auto addw = (installedSet ? _installedWidth : _addWidth) + - st::stickersTrendingAdd.width; + const auto addh = st::stickersTrendingAdd.height; + const auto addx = stickersRight() - addw; + const auto addy = info.top + st::stickersTrendingAddTop; return QRect(addx, addy, addw, addh); } @@ -1536,7 +1558,7 @@ void StickersListWidget::setPressed(OverState newPressed) { } else if (std::get_if(&_pressed)) { if (!_megagroupSetButtonRipple) { auto maskSize = _megagroupSetButtonRect.size(); - auto mask = Ui::RippleAnimation::RoundRectMask(maskSize, st::roundRadiusSmall); + auto mask = Ui::RippleAnimation::RoundRectMask(maskSize, st::roundRadiusLarge); _megagroupSetButtonRipple = std::make_unique(st::stickerGroupCategoryAdd.ripple, std::move(mask), [this] { rtlupdate(megagroupSetButtonRectFinal()); }); @@ -1564,7 +1586,7 @@ std::unique_ptr StickersListWidget::createButtonRipple(int if (shownSets()[section].externalLayout) { auto maskSize = QSize(_addWidth - st::stickersTrendingAdd.width, st::stickersTrendingAdd.height); - auto mask = Ui::RippleAnimation::RoundRectMask(maskSize, st::roundRadiusSmall); + auto mask = Ui::RippleAnimation::RoundRectMask(maskSize, st::roundRadiusLarge); return std::make_unique( st::stickersTrendingAdd.ripple, std::move(mask), @@ -1740,6 +1762,7 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) { Assert(button->section >= 0 && button->section < sets.size()); if (sets[button->section].externalLayout) { _localSetsManager->install(sets[button->section].id); + update(); } else { removeSet(sets[button->section].id); } @@ -2354,7 +2377,7 @@ void StickersListWidget::updateSelected() { if (p.y() >= info.top && p.y() < info.rowsTop) { if (hasRemoveButton(section) && myrtlrect(removeButtonRect(info)).contains(p.x(), p.y())) { newSelected = OverButton{ section }; - } else if (featuredHasAddButton(section) && myrtlrect(featuredAddRect(info)).contains(p.x(), p.y())) { + } else if (featuredHasAddButton(section) && myrtlrect(featuredAddRect(info, false)).contains(p.x(), p.y())) { newSelected = OverButton{ section }; } else if (_features.openStickerSets && !(sets[section].flags & SetFlag::Special)) { @@ -2557,7 +2580,7 @@ void StickersListWidget::showMegagroupSet(ChannelData *megagroup) { _megagroupSetAbout.setText( st::stickerGroupCategoryAbout, tr::lng_group_stickers_description(tr::now)); - _megagroupSetButtonText = tr::lng_group_stickers_add(tr::now).toUpper(); + _megagroupSetButtonText = tr::lng_group_stickers_add(tr::now); refreshMegagroupSetGeometry(); } _megagroupSetButtonRipple.reset(); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index 6e2c2fa04..2e1ef9c1c 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -302,7 +302,9 @@ private: [[nodiscard]] int stickersRight() const; [[nodiscard]] bool featuredHasAddButton(int index) const; [[nodiscard]] QRect featuredAddRect(int index) const; - [[nodiscard]] QRect featuredAddRect(const SectionInfo &info) const; + [[nodiscard]] QRect featuredAddRect( + const SectionInfo &info, + bool installedSet) const; [[nodiscard]] bool hasRemoveButton(int index) const; [[nodiscard]] QRect removeButtonRect(int index) const; [[nodiscard]] QRect removeButtonRect(const SectionInfo &info) const; @@ -392,7 +394,7 @@ private: OverState _pressed; QPoint _lastMousePosition; - Ui::RoundRect _trendingAddBgOver, _trendingAddBg; + Ui::RoundRect _trendingAddBgOver, _trendingAddBg, _inactiveButtonBg; Ui::RoundRect _groupCategoryAddBgOver, _groupCategoryAddBg; const std::unique_ptr _pathGradient; @@ -405,6 +407,8 @@ private: QString _addText; int _addWidth; + QString _installedText; + int _installedWidth; object_ptr _settings; diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index c15460c9e..adf770688 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -571,7 +571,6 @@ storiesEmojiPan: EmojiPan(defaultEmojiPan) { trendingHeaderFg: storiesComposeWhiteText; trendingSubheaderFg: storiesComposeGrayText; trendingUnreadFg: storiesComposeBlue; - trendingInstalled: icon {{ "chat/input_save", storiesComposeBlue }}; overBg: storiesComposeBgOver; pathBg: storiesComposeBgRipple; pathFg: storiesComposeBgOver; From b6e2360f5121830caecf42d11beacb6bb5845055 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 12:37:10 +0400 Subject: [PATCH 40/60] Version 4.8.9. - 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 2d99765a2..a0e82f806 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="4.8.9.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 207ce5673..1253b7043 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,8,8,0 - PRODUCTVERSION 4,8,8,0 + FILEVERSION 4,8,9,0 + PRODUCTVERSION 4,8,9,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "4.8.8.0" + VALUE "FileVersion", "4.8.9.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.8.8.0" + VALUE "ProductVersion", "4.8.9.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 65a32e4a7..cb1aed9eb 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,8,8,0 - PRODUCTVERSION 4,8,8,0 + FILEVERSION 4,8,9,0 + PRODUCTVERSION 4,8,9,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -53,10 +53,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "4.8.8.0" + VALUE "FileVersion", "4.8.9.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.8.8.0" + VALUE "ProductVersion", "4.8.9.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 630dfd075..4f1c6194a 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 = 4008008; -constexpr auto AppVersionStr = "4.8.8"; +constexpr auto AppVersion = 4008009; +constexpr auto AppVersionStr = "4.8.9"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index a0acebbbd..3bbc47084 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 4008008 +AppVersion 4008009 AppVersionStrMajor 4.8 -AppVersionStrSmall 4.8.8 -AppVersionStr 4.8.8 +AppVersionStrSmall 4.8.9 +AppVersionStr 4.8.9 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 4.8.8 +AppVersionOriginal 4.8.9 diff --git a/changelog.txt b/changelog.txt index 0e476e2f1..4c503803a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +4.8.9 (26.07.23) + +- Bug fixes and other minor improvements. + 4.8.8 (25.07.23) - Several crash fixes and story viewer improvements. From 770880b74bef0763708501d8a70b0eab9a7f7233 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 12:32:55 +0400 Subject: [PATCH 41/60] Version 4.8.9: Add hiding X button to stories tooltip. --- Telegram/SourceFiles/dialogs/dialogs.style | 5 +- .../dialogs/ui/dialogs_stories_list.cpp | 58 +++++++++++++++++-- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 0e877db81..88e1239be 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -562,6 +562,9 @@ dialogsStoriesListInfo: DialogsStoriesList(dialogsStoriesList) { dialogsStoriesListMine: DialogsStoriesList(dialogsStoriesListInfo) { readOpacity: 1.; } -dialogsStoriesTooltip: defaultImportantTooltip; +dialogsStoriesTooltip: ImportantTooltip(defaultImportantTooltip) { + padding: margins(0px, 0px, 0px, 0px); +} dialogsStoriesTooltipLabel: defaultImportantTooltipLabel; dialogsStoriesTooltipMaxWidth: 200px; +dialogsStoriesTooltipHide: size(14px, 14px); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index 83b73ec7d..d71e8663d 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -16,11 +16,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/labels.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/tooltip.h" +#include "ui/abstract_button.h" #include "ui/painter.h" #include "styles/style_dialogs.h" #include #include +#include #include "base/debug_log.h" @@ -34,6 +36,7 @@ constexpr auto kCollapseAfterRatio = 0.68; constexpr auto kFrictionRatio = 0.15; constexpr auto kExpandCatchUpDuration = crl::time(200); constexpr auto kMaxTooltipNames = 3; +constexpr auto kStoriesTooltipHideBgOpacity = 0.2; [[nodiscard]] int AvailableNameWidth(const style::DialogsStoriesList &st) { const auto &full = st.full; @@ -42,6 +45,55 @@ constexpr auto kMaxTooltipNames = 3; return full.photoLeft * 2 + full.photo - 2 * skip; } +[[nodiscard]] object_ptr MakeTooltipContent( + not_null parent, + rpl::producer text, + Fn hide) { + const auto size = st::dialogsStoriesTooltipHide; + const auto buttonw = size.width(); + const auto skip = st::defaultImportantTooltip.padding.right(); + auto result = object_ptr>( + parent, + Ui::MakeNiceTooltipLabel( + parent, + std::move(text), + st::dialogsStoriesTooltipMaxWidth, + st::dialogsStoriesTooltipLabel), + (st::defaultImportantTooltip.padding + + QMargins(0, 0, skip + buttonw, 0))); + const auto button = Ui::CreateChild(result.data()); + result->sizeValue( + ) | rpl::start_with_next([=](QSize size) { + const auto buttonh = button->height(); + button->resize(skip * 2 + buttonw, size.height()); + button->moveToRight(0, 0, size.width()); + }, button->lifetime()); + button->setClickedCallback(std::move(hide)); + button->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(button); + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(st::importantTooltipFg); + p.setOpacity(kStoriesTooltipHideBgOpacity); + const auto rect = style::centerrect( + button->rect(), + QRect(QPoint(), size)); + const auto center = QRectF(rect).center(); + const auto half = QSizeF(rect.size()) / 6.; + const auto phalf = QPointF(half.width(), half.height()); + const auto mhalf = QPointF(-half.width(), half.height()); + p.drawEllipse(rect); + p.setOpacity(1.); + auto pen = st::importantTooltipFg->p; + pen.setWidthF(style::ConvertScaleExact(sqrtf(2.))); + p.setPen(pen); + p.drawLine(center - phalf, center + phalf); + p.drawLine(center - mhalf, center + mhalf); + }, button->lifetime()); + return result; +} + } // namespace struct List::Layout { @@ -876,15 +928,13 @@ void List::setShowTooltip(rpl::producer shown, Fn hide) { }; _tooltip = std::make_unique( window, - Ui::MakeNiceTooltipLabel( + MakeTooltipContent( window, _tooltipText.value() | rpl::filter(notEmpty), - st::dialogsStoriesTooltipMaxWidth, - st::dialogsStoriesTooltipLabel), + _tooltipHide), st::dialogsStoriesTooltip); const auto tooltip = _tooltip.get(); const auto weak = QPointer(tooltip); - tooltip->setAttribute(Qt::WA_TransparentForMouseEvents); tooltip->toggleFast(false); updateTooltipGeometry(); From e6a80927c62dabb49b82717fac94d9472b5c058c Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Jul 2023 13:46:58 +0400 Subject: [PATCH 42/60] Version 4.8.9: Fix build with GCC. --- Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index d71e8663d..eaa5c89dd 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -64,7 +64,6 @@ constexpr auto kStoriesTooltipHideBgOpacity = 0.2; const auto button = Ui::CreateChild(result.data()); result->sizeValue( ) | rpl::start_with_next([=](QSize size) { - const auto buttonh = button->height(); button->resize(skip * 2 + buttonw, size.height()); button->moveToRight(0, 0, size.width()); }, button->lifetime()); From ebbef70d420a6713858f5d3ec6e929fc70eeedc2 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 26 Jul 2023 18:40:02 +0300 Subject: [PATCH 43/60] Removed self from contacts list. --- .../SourceFiles/boxes/peer_list_controllers.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 5831ec0b5..335531fc9 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -59,7 +59,20 @@ constexpr auto kSearchPerPage = 50; object_ptr PrepareContactsBox( not_null sessionController) { using Mode = ContactsBoxController::SortMode; - auto controller = std::make_unique( + class Controller final : public ContactsBoxController { + public: + using ContactsBoxController::ContactsBoxController; + + protected: + std::unique_ptr createRow( + not_null user) override { + return !user->isSelf() + ? ContactsBoxController::createRow(user) + : nullptr; + } + + }; + auto controller = std::make_unique( &sessionController->session()); controller->setStyleOverrides(&st::contactsWithStories); controller->setStoriesShown(true); From 73373e373ffb38566da0c4ac9f7bc20488943e2a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 26 Jul 2023 22:23:45 +0300 Subject: [PATCH 44/60] Moved important tooltip for stories in dialogs to MainWidget. --- Telegram/SourceFiles/core/core_settings.h | 3 ++ .../SourceFiles/dialogs/dialogs_widget.cpp | 25 +++++---- .../dialogs/ui/dialogs_stories_list.cpp | 53 ++++++++++++------- .../dialogs/ui/dialogs_stories_list.h | 5 +- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index aec34560c..72468e755 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -802,6 +802,9 @@ public: [[nodiscard]] std::optional macRoundIconDigest() const { return _macRoundIconDigest; } + [[nodiscard]] bool storiesClickTooltipHidden() const { + return _storiesClickTooltipHidden.current(); + } [[nodiscard]] rpl::producer storiesClickTooltipHiddenValue() const { return _storiesClickTooltipHidden.value(); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 8fe35aba2..7a147a3c6 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -798,16 +798,21 @@ void Widget::setupStories() { _scroll->viewportEvent(e); }, _stories->lifetime()); - const auto hideTooltip = [=] { - Core::App().settings().setStoriesClickTooltipHidden(true); - Core::App().saveSettingsDelayed(); - }; - _stories->setShowTooltip( - rpl::combine( - Core::App().settings().storiesClickTooltipHiddenValue(), - shownValue(), - !rpl::mappers::_1 && rpl::mappers::_2), - hideTooltip); + if (!Core::App().settings().storiesClickTooltipHidden()) { + // Don't create tooltip + // until storiesClickTooltipHidden can be returned to false. + const auto hideTooltip = [=] { + Core::App().settings().setStoriesClickTooltipHidden(true); + Core::App().saveSettingsDelayed(); + }; + _stories->setShowTooltip( + parentWidget(), + rpl::combine( + Core::App().settings().storiesClickTooltipHiddenValue(), + shownValue(), + !rpl::mappers::_1 && rpl::mappers::_2), + hideTooltip); + } _storiesContents.fire(Stories::ContentForSession( &controller()->session(), diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index eaa5c89dd..4fed6d154 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -916,19 +916,21 @@ TextWithEntities List::computeTooltipText() const { Ui::Text::WithEntities); } -void List::setShowTooltip(rpl::producer shown, Fn hide) { +void List::setShowTooltip( + not_null tooltipParent, + rpl::producer shown, + Fn hide) { _tooltip = nullptr; _tooltipHide = std::move(hide); _tooltipNotHidden = std::move(shown); _tooltipText = computeTooltipText(); - const auto window = this->window(); const auto notEmpty = [](const TextWithEntities &text) { return !text.empty(); }; _tooltip = std::make_unique( - window, + tooltipParent, MakeTooltipContent( - window, + tooltipParent, _tooltipText.value() | rpl::filter(notEmpty), _tooltipHide), st::dialogsStoriesTooltip); @@ -937,7 +939,7 @@ void List::setShowTooltip(rpl::producer shown, Fn hide) { tooltip->toggleFast(false); updateTooltipGeometry(); - const auto handle = window->windowHandle(); + const auto handle = tooltipParent->window()->windowHandle(); auto windowActive = rpl::single( handle->isActive() ) | rpl::then(base::qt_signal_producer( @@ -947,16 +949,29 @@ void List::setShowTooltip(rpl::producer shown, Fn hide) { return handle->isActive(); })) | rpl::distinct_until_changed(); - for (auto parent = parentWidget() - ; parent != window - ; parent = parent->parentWidget()) { + { + const auto recompute = [=] { + updateTooltipGeometry(); + tooltip->raise(); + }; using namespace base; - install_event_filter(parent, tooltip, [=](not_null e) { - if (e->type() == QEvent::Move) { - updateTooltipGeometry(); + using Event = not_null; + install_event_filter(tooltip, tooltipParent, [=](Event e) { + if ((e->type() == QEvent::Move) + || (e->type() == QEvent::ChildAdded) + || (e->type() == QEvent::ChildRemoved)) { + recompute(); } return EventFilterResult::Continue; }); + for (const auto &child : tooltipParent->children()) { + install_event_filter(tooltip, child, [=](Event e) { + if (e->type() == QEvent::ZOrderChange) { + recompute(); + } + return EventFilterResult::Continue; + }); + } } rpl::combine( @@ -985,14 +1000,16 @@ void List::toggleTooltip(bool fast) { && _tooltipNotHidden.current() && !_tooltipText.current().empty() && window()->windowHandle()->isActive(); + if (_tooltip) { + if (fast) { + _tooltip->toggleFast(shown); + } else { + _tooltip->toggleAnimated(shown); + } + } if (shown) { updateTooltipGeometry(); } - if (fast) { - _tooltip->toggleFast(shown); - } else { - _tooltip->toggleAnimated(shown); - } } void List::updateTooltipGeometry() { @@ -1001,7 +1018,7 @@ void List::updateTooltipGeometry() { } const auto collapsed = collapsedGeometryCurrent(); const auto geometry = Ui::MapFrom( - window(), + _tooltip->parentWidget(), parentWidget(), QRect( collapsed.geometry.x(), @@ -1012,7 +1029,7 @@ void List::updateTooltipGeometry() { const auto countPosition = [=](QSize size) { const auto left = geometry.x() + (geometry.width() - size.width()) / 2; - const auto right = window()->width() + const auto right = _tooltip->parentWidget()->width() - st::dialogsStoriesTooltip.padding.right(); return QPoint( std::max(std::min(left, right - size.width()), 0), diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h index 9ecf28394..ea2f2f36c 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h @@ -73,7 +73,10 @@ public: QPoint positionSmall, style::align alignSmall, QRect geometryFull = QRect()); - void setShowTooltip(rpl::producer shown, Fn hide); + void setShowTooltip( + not_null tooltipParent, + rpl::producer shown, + Fn hide); struct CollapsedGeometry { QRect geometry; float64 expanded = 0.; From 4017d8db7c3a6ea0d88ea9243782a1a77ad90fac Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 28 Jul 2023 02:44:20 +0300 Subject: [PATCH 45/60] Removed Save button from box for bot username editing. --- Telegram/Resources/langs/lang.strings | 2 +- Telegram/SourceFiles/boxes/username_box.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 3a6b93532..acfe54a1d 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -433,7 +433,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_channel_usernames_deactivate_description" = "Do you want to hide this link from the channel info page?"; "lng_channel_usernames_description" = "Drag and drop links to change the order in which they will be displayed on the channel info page."; -"lng_bot_username_title" = "Username"; +"lng_bot_username_title" = "Public Link"; "lng_bot_username_description1" = "This link cannot be edited. You can acquire additional usernames on {link}."; "lng_bot_username_description1_link" = "Fragment"; "lng_bot_usernames_activate_description" = "Do you want to show this link on the bot info page?"; diff --git a/Telegram/SourceFiles/boxes/username_box.cpp b/Telegram/SourceFiles/boxes/username_box.cpp index 8e7ccd244..ded98183a 100644 --- a/Telegram/SourceFiles/boxes/username_box.cpp +++ b/Telegram/SourceFiles/boxes/username_box.cpp @@ -393,8 +393,12 @@ void UsernamesBox( editor->submitted( ) | rpl::start_with_next(finish, editor->lifetime()); - box->addButton(tr::lng_settings_save(), finish); - box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); + if (isBot) { + box->addButton(tr::lng_close(), [=] { box->closeBox(); }); + } else { + box->addButton(tr::lng_settings_save(), finish); + box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); + } } void AddUsernameCheckLabel( From 19ba685cc3e125de7546af4d4ae3b4102ef718b3 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 28 Jul 2023 03:28:29 +0300 Subject: [PATCH 46/60] Added ability to mark as read all chats from menu of filter button. --- .../window/window_filters_menu.cpp | 68 +++++++++++++------ .../SourceFiles/window/window_peer_menu.cpp | 7 +- .../SourceFiles/window/window_peer_menu.h | 4 +- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/Telegram/SourceFiles/window/window_filters_menu.cpp b/Telegram/SourceFiles/window/window_filters_menu.cpp index 657e0165d..b606be053 100644 --- a/Telegram/SourceFiles/window/window_filters_menu.cpp +++ b/Telegram/SourceFiles/window/window_filters_menu.cpp @@ -40,6 +40,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Window { namespace { +[[nodiscard]] Dialogs::UnreadState MainListMapUnreadState( + not_null session, + const Dialogs::UnreadState &state) { + const auto folderId = Data::Folder::kId; + if (const auto folder = session->data().folderLoaded(folderId)) { + return state - folder->chatsList()->unreadState(); + } + return state; +} + [[nodiscard]] rpl::producer MainListUnreadState( not_null list) { return rpl::single(rpl::empty) | rpl::then( @@ -59,11 +69,7 @@ namespace { return MainListUnreadState( session->data().chatsList() ) | rpl::map([=](const Dialogs::UnreadState &state) { - const auto folderId = Data::Folder::kId; - if (const auto folder = session->data().folderLoaded(folderId)) { - return state - folder->chatsList()->unreadState(); - } - return state; + return MainListMapUnreadState(session, state); }); } @@ -331,7 +337,7 @@ base::unique_qptr FiltersMenu::prepareButton( raw->setAcceptDrops(true); raw->events( ) | rpl::filter([=](not_null e) { - return ((e->type() == QEvent::ContextMenu) && (id > 0)) + return ((e->type() == QEvent::ContextMenu) && (id >= 0)) || e->type() == QEvent::DragEnter || e->type() == QEvent::DragMove || e->type() == QEvent::DragLeave; @@ -368,7 +374,7 @@ void FiltersMenu::showMenu(QPoint position, FilterId id) { return; } const auto i = _filters.find(id); - if (i == end(_filters)) { + if ((i == end(_filters)) && id) { return; } _popupMenu = base::make_unique_q( @@ -382,23 +388,41 @@ void FiltersMenu::showMenu(QPoint position, FilterId id) { args.icon); }); - addAction( - tr::lng_filters_context_edit(tr::now), - [=] { showEditBox(id); }, - &st::menuIconEdit); + if (id) { + addAction( + tr::lng_filters_context_edit(tr::now), + [=] { showEditBox(id); }, + &st::menuIconEdit); - auto filteredChats = [=] { - return _session->session().data().chatsFilters().chatsList(id); - }; - Window::MenuAddMarkAsReadChatListAction( - _session, - std::move(filteredChats), - addAction); + auto filteredChats = [=] { + return _session->session().data().chatsFilters().chatsList(id); + }; + Window::MenuAddMarkAsReadChatListAction( + _session, + std::move(filteredChats), + addAction); - addAction( - tr::lng_filters_context_remove(tr::now), - [=] { showRemoveBox(id); }, - &st::menuIconDelete); + addAction( + tr::lng_filters_context_remove(tr::now), + [=] { showRemoveBox(id); }, + &st::menuIconDelete); + } else { + auto customUnreadState = [=] { + const auto session = &_session->session(); + return MainListMapUnreadState( + session, + session->data().chatsList()->unreadState()); + }; + Window::MenuAddMarkAsReadChatListAction( + _session, + [=] { return _session->session().data().chatsList(); }, + addAction, + std::move(customUnreadState)); + } + if (_popupMenu->empty()) { + _popupMenu = nullptr; + return; + } _popupMenu->popup(position); } diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 7b908dc47..9098b9112 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -2299,9 +2299,12 @@ void MenuAddMarkAsReadAllChatsAction( void MenuAddMarkAsReadChatListAction( not_null controller, Fn()> &&list, - const PeerMenuCallback &addAction) { + const PeerMenuCallback &addAction, + Fn customUnreadState) { // There is no async to make weak from controller. - const auto unreadState = list()->unreadState(); + const auto unreadState = customUnreadState + ? customUnreadState() + : list()->unreadState(); if (!unreadState.messages && !unreadState.marks && !unreadState.chats) { return; } diff --git a/Telegram/SourceFiles/window/window_peer_menu.h b/Telegram/SourceFiles/window/window_peer_menu.h index 7fde1f407..d5808fbf5 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.h +++ b/Telegram/SourceFiles/window/window_peer_menu.h @@ -32,6 +32,7 @@ class Thread; namespace Dialogs { class MainList; struct EntryState; +struct UnreadState; } // namespace Dialogs namespace ChatHelpers { @@ -69,7 +70,8 @@ void MenuAddMarkAsReadAllChatsAction( void MenuAddMarkAsReadChatListAction( not_null controller, Fn()> &&list, - const PeerMenuCallback &addAction); + const PeerMenuCallback &addAction, + Fn customUnreadState = nullptr); void PeerMenuExportChat(not_null peer); void PeerMenuDeleteContact( From a08e42fb97fde33ddab3456724df448e6e7e3d0c Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 28 Jul 2023 03:56:38 +0300 Subject: [PATCH 47/60] Moved edit folders button from folders menu to context menu. --- Telegram/Resources/langs/lang.strings | 1 + .../window/window_filters_menu.cpp | 31 ++++++++++++------- .../SourceFiles/window/window_filters_menu.h | 1 + 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index acfe54a1d..9730225d2 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3587,6 +3587,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_filters_restore" = "Undo"; "lng_filters_new" = "New Folder"; "lng_filters_edit" = "Edit Folder"; +"lng_filters_setup_menu" = "Edit Folders"; "lng_filters_new_name" = "Folder name"; "lng_filters_add_chats" = "Add chats"; "lng_filters_remove_chats" = "Remove chats"; diff --git a/Telegram/SourceFiles/window/window_filters_menu.cpp b/Telegram/SourceFiles/window/window_filters_menu.cpp index b606be053..c6c34a0d9 100644 --- a/Telegram/SourceFiles/window/window_filters_menu.cpp +++ b/Telegram/SourceFiles/window/window_filters_menu.cpp @@ -320,17 +320,7 @@ base::unique_qptr FiltersMenu::prepareButton( } else if (id >= 0) { _session->setActiveChatsFilter(id); } else { - const auto filters = &_session->session().data().chatsFilters(); - if (filters->suggestedLoaded()) { - _session->showSettings(Settings::Folders::Id()); - } else if (!_waitingSuggested) { - _waitingSuggested = true; - filters->requestSuggested(); - filters->suggestedUpdated( - ) | rpl::take(1) | rpl::start_with_next([=] { - _session->showSettings(Settings::Folders::Id()); - }, _outer.lifetime()); - } + openFiltersSettings(); } }); if (id >= 0) { @@ -368,6 +358,20 @@ base::unique_qptr FiltersMenu::prepareButton( return button; } +void FiltersMenu::openFiltersSettings() { + const auto filters = &_session->session().data().chatsFilters(); + if (filters->suggestedLoaded()) { + _session->showSettings(Settings::Folders::Id()); + } else if (!_waitingSuggested) { + _waitingSuggested = true; + filters->requestSuggested(); + filters->suggestedUpdated( + ) | rpl::take(1) | rpl::start_with_next([=] { + _session->showSettings(Settings::Folders::Id()); + }, _outer.lifetime()); + } +} + void FiltersMenu::showMenu(QPoint position, FilterId id) { if (_popupMenu) { _popupMenu = nullptr; @@ -418,6 +422,11 @@ void FiltersMenu::showMenu(QPoint position, FilterId id) { [=] { return _session->session().data().chatsList(); }, addAction, std::move(customUnreadState)); + + addAction( + tr::lng_filters_setup_menu(tr::now), + [=] { openFiltersSettings(); }, + &st::menuIconEdit); } if (_popupMenu->empty()) { _popupMenu = nullptr; diff --git a/Telegram/SourceFiles/window/window_filters_menu.h b/Telegram/SourceFiles/window/window_filters_menu.h index a4084164b..ee71510ea 100644 --- a/Telegram/SourceFiles/window/window_filters_menu.h +++ b/Telegram/SourceFiles/window/window_filters_menu.h @@ -52,6 +52,7 @@ private: void showRemoveBox(FilterId id); void remove(FilterId id, std::vector> leave = {}); void scrollToButton(not_null widget); + void openFiltersSettings(); const not_null _session; const not_null _parent; From 7149119098c3c0b52cccbc67b88b5d632448f901 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 28 Jul 2023 04:11:12 +0300 Subject: [PATCH 48/60] Fixed style of media player controls. --- Telegram/SourceFiles/media/player/media_player.style | 12 ++++++++---- .../SourceFiles/media/player/media_player_widget.cpp | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/media/player/media_player.style b/Telegram/SourceFiles/media/player/media_player.style index 841cc3e5c..5e5a3ec8b 100644 --- a/Telegram/SourceFiles/media/player/media_player.style +++ b/Telegram/SourceFiles/media/player/media_player.style @@ -106,7 +106,7 @@ mediaPlayerRepeatButton: IconButton { icon: icon { { "player/player_repeat", mediaPlayerActiveFg } }; - iconPosition: point(3px, 6px); + iconPosition: point(2px, 5px); rippleAreaPosition: point(2px, 6px); rippleAreaSize: 24px; @@ -135,6 +135,10 @@ mediaPlayerReverseDisabledIconOver: icon { mediaPlayerShuffleIcon: icon { { "player/player_shuffle", mediaPlayerActiveFg } }; +mediaPlayerOrderButton: IconButton(mediaPlayerRepeatButton) { + iconPosition: point(2px, 6px); + rippleAreaPosition: point(2px, 6px); +} mediaPlayerRepeatDisabledRippleBg: windowBgOver; mediaPlayerPlayButton: IconButton(mediaPlayerRepeatButton) { @@ -233,7 +237,7 @@ mediaPlayerVolumeToggle: IconButton(mediaPlayerRepeatButton) { { "player/player_mini_full", mediaPlayerActiveFg }, }; iconPosition: point(5px, 6px); - rippleAreaPosition: point(4px, 5px); + rippleAreaPosition: point(5px, 6px); } mediaPlayerVolumeMargin: 10px; mediaPlayerVolumeSize: size(27px, 100px); @@ -267,9 +271,9 @@ mediaPlayerClose: IconButton(mediaPlayerRepeatButton) { width: 39px; icon: icon {{ "player/panel_close", menuIconFg }}; iconOver: icon {{ "player/panel_close", menuIconFgOver }}; - iconPosition: point(5px, 6px); + iconPosition: point(4px, 6px); - rippleAreaPosition: point(4px, 5px); + rippleAreaPosition: point(4px, 6px); ripple: RippleAnimation(defaultRippleAnimation) { color: windowBgOver; } diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index d9be06b6d..abe1c738c 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -55,7 +55,7 @@ Widget::Widget( , _playPause(this, st::mediaPlayerPlayButton) , _volumeToggle(rightControls(), st::mediaPlayerVolumeToggle) , _repeatToggle(rightControls(), st::mediaPlayerRepeatButton) -, _orderToggle(rightControls(), st::mediaPlayerRepeatButton) +, _orderToggle(rightControls(), st::mediaPlayerOrderButton) , _speedToggle(rightControls(), st::mediaPlayerSpeedButton) , _close(this, st::mediaPlayerClose) , _shadow(this) From b663edff09a772180e09560465e314b29f358292 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 27 Jul 2023 18:26:26 +0400 Subject: [PATCH 49/60] Improve silent stories playback. --- .../SourceFiles/media/view/media_view_overlay_widget.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 2f2cf164c..04d814478 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -3698,6 +3698,7 @@ bool OverlayWidget::createStreamingObjects() { _streamed->instance.setPriority(kOverlayLoaderPriority); _streamed->instance.lockPlayer(); _streamed->withSound = _document + && !_document->isSilentVideo() && (_document->isAudioFile() || _document->isVideoFile() || _document->isVoiceMessage() @@ -4038,12 +4039,14 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) { }; if (!_streamed->withSound) { options.mode = Streaming::Mode::Video; - options.loop = true; + options.loop = !_stories; } else { Assert(_document != nullptr); const auto messageId = _message ? _message->fullId() : FullMsgId(); options.audioId = AudioMsgId(_document, messageId); - options.speed = Core::App().settings().videoPlaybackSpeed(); + options.speed = _stories + ? Core::App().settings().videoPlaybackSpeed() + : 1.; if (_pip) { _pip = nullptr; } @@ -4111,7 +4114,7 @@ void OverlayWidget::playbackControlsSpeedChanged(float64 speed) { Core::App().settings().setVideoPlaybackSpeed(speed); Core::App().saveSettingsDelayed(); } - if (_streamed && _streamed->controls) { + if (_streamed && _streamed->controls && !_stories) { DEBUG_LOG(("Media playback speed: %1 to _streamed.").arg(speed)); _streamed->instance.setSpeed(speed); } From 48687d443fc32beea619c14c9b8ecec383c118cf Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 27 Jul 2023 23:48:41 +0400 Subject: [PATCH 50/60] Use message date instead of file date. --- Telegram/SourceFiles/overview/overview_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 2f8609ace..cae666b37 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -1020,7 +1020,7 @@ Document::Document( , _forceFileLayout(fields.forceFileLayout) , _date(langDateTime(base::unixtime::parse(fields.dateOverride ? fields.dateOverride - : _data->date))) + : parent->date()))) , _ext(_generic.ext) , _datew(st::normalFont->width(_date)) { _name.setMarkedText( From e59e7d9b9745e4ee9d74626974671a7147c90859 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 27 Jul 2023 20:51:53 +0400 Subject: [PATCH 51/60] Correct check for scheduled message ids. --- Telegram/SourceFiles/data/data_shared_media.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_shared_media.cpp b/Telegram/SourceFiles/data/data_shared_media.cpp index e2a69482e..8033fba9c 100644 --- a/Telegram/SourceFiles/data/data_shared_media.cpp +++ b/Telegram/SourceFiles/data/data_shared_media.cpp @@ -185,7 +185,8 @@ rpl::producer SharedScheduledMediaViewer( SharedMediaMergedKey key, int limitBefore, int limitAfter) { - Expects(!IsServerMsgId(key.mergedKey.universalId)); + Expects(!key.mergedKey.universalId + || Data::IsScheduledMsgId(key.mergedKey.universalId)); Expects((key.mergedKey.universalId != 0) || (limitBefore == 0 && limitAfter == 0)); From fcd1062d783582a84c157f017ee4bf9b0ae9a3c2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jul 2023 12:09:51 +0400 Subject: [PATCH 52/60] Use message date instead of file date in voices. --- Telegram/SourceFiles/overview/overview_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index cae666b37..9ac811f19 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -700,7 +700,7 @@ Voice::Voice( updateName(); const auto dateText = Ui::Text::Link( - langDateTime(base::unixtime::parse(_data->date))); // Link 1. + langDateTime(base::unixtime::parse(parent->date()))); // Link 1. _details.setMarkedText( st::defaultTextStyle, tr::lng_date_and_duration( From 7d1725b339ecf1ea6fc483af711cab94a4912c5e Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jul 2023 12:10:01 +0400 Subject: [PATCH 53/60] Simplify ordering of stories tooltip. --- .../SourceFiles/dialogs/dialogs_widget.cpp | 9 +++++++++ Telegram/SourceFiles/dialogs/dialogs_widget.h | 1 + .../dialogs/ui/dialogs_stories_list.cpp | 18 +++++++----------- .../dialogs/ui/dialogs_stories_list.h | 2 ++ Telegram/SourceFiles/mainwidget.cpp | 2 +- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 7a147a3c6..11e7b2f1b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1386,6 +1386,15 @@ void Widget::jumpToTop(bool belowPinned) { } } +void Widget::raiseWithTooltip() { + raise(); + if (_stories) { + Ui::PostponeCall(this, [=] { + _stories->raiseTooltip(); + }); + } +} + void Widget::scrollToDefault(bool verytop) { if (verytop) { //_scroll->verticalScrollBar()->setMinimum(0); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 9473ac348..e1d1a64ef 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -98,6 +98,7 @@ public: void setInnerFocus(); void jumpToTop(bool belowPinned = false); + void raiseWithTooltip(); void startWidthAnimation(); void stopWidthAnimation(); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index 4fed6d154..f99091721 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -957,21 +957,11 @@ void List::setShowTooltip( using namespace base; using Event = not_null; install_event_filter(tooltip, tooltipParent, [=](Event e) { - if ((e->type() == QEvent::Move) - || (e->type() == QEvent::ChildAdded) - || (e->type() == QEvent::ChildRemoved)) { + if (e->type() == QEvent::ChildAdded) { recompute(); } return EventFilterResult::Continue; }); - for (const auto &child : tooltipParent->children()) { - install_event_filter(tooltip, child, [=](Event e) { - if (e->type() == QEvent::ZOrderChange) { - recompute(); - } - return EventFilterResult::Continue; - }); - } } rpl::combine( @@ -993,6 +983,12 @@ void List::setShowTooltip( }, tooltip->lifetime()); } +void List::raiseTooltip() { + if (_tooltip) { + _tooltip->raise(); + } +} + void List::toggleTooltip(bool fast) { const auto shown = !_expanded && !_expandedAnimation.animating() diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h index ea2f2f36c..24468850a 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h @@ -77,6 +77,8 @@ public: not_null tooltipParent, rpl::producer shown, Fn hide); + void raiseTooltip(); + struct CollapsedGeometry { QRect geometry; float64 expanded = 0.; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4b46807d0..8abf9f2d2 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1926,7 +1926,7 @@ void MainWidget::showBackFromStack( void MainWidget::orderWidgets() { if (_dialogs) { - _dialogs->raise(); + _dialogs->raiseWithTooltip(); } if (_player) { _player->raise(); From 815e9d246203a84a814d90bdc21a0dbe94c6c84e Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jul 2023 12:19:14 +0400 Subject: [PATCH 54/60] Call viewMessage only when marking as read. --- Telegram/SourceFiles/history/history_inner_widget.cpp | 5 +++-- .../SourceFiles/history/view/history_view_list_widget.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 5074219da..eedd0b81c 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1052,6 +1052,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { _translateTracker->startBunch(); auto readTill = (HistoryItem*)nullptr; auto readContents = base::flat_set>(); + const auto markingAsViewed = _widget->markingContentsRead(); const auto guard = gsl::finally([&] { if (_pinnedItem) { _translateTracker->add(_pinnedItem); @@ -1060,7 +1061,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { if (readTill && _widget->markingMessagesRead()) { session().data().histories().readInboxTill(readTill); } - if (!readContents.empty() && _widget->markingContentsRead()) { + if (markingAsViewed && !readContents.empty()) { session().api().markContentsRead(readContents); } _userpicsCache.clear(); @@ -1093,7 +1094,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } else if (isUnread) { readTill = item; } - if (item->hasViews()) { + if (markingAsViewed && item->hasViews()) { session().api().views().scheduleIncrement(item); } if (withReaction) { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 5903fa94b..1e2648125 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2059,12 +2059,13 @@ void ListWidget::paintEvent(QPaintEvent *e) { } auto readTill = (HistoryItem*)nullptr; auto readContents = base::flat_set>(); + const auto markingAsViewed = markingMessagesRead(); const auto guard = gsl::finally([&] { if (_translateTracker) { _delegate->listAddTranslatedItems(_translateTracker.get()); _translateTracker->finishBunch(); } - if (readTill && markingMessagesRead()) { + if (markingAsViewed && readTill) { _delegate->listMarkReadTill(readTill); } if (!readContents.empty() && markingContentsRead()) { @@ -2136,7 +2137,7 @@ void ListWidget::paintEvent(QPaintEvent *e) { } else if (isUnread) { readTill = item; } - if (item->hasViews()) { + if (markingAsViewed && item->hasViews()) { session->api().views().scheduleIncrement(item); } if (withReaction) { From f58171b50b5b620d584b4cbc7ed0dcb1950508be Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jul 2023 20:45:04 +0400 Subject: [PATCH 55/60] Fix tooltips in group calls. --- Telegram/SourceFiles/calls/group/calls_group_panel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 8af7d3f0d..a240ce118 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -2060,6 +2060,7 @@ void Panel::showNiceTooltip( (normal ? widget().get() : container), std::move(text), st::groupCallNiceTooltipLabel); + label->resizeToNaturalWidth(label->naturalWidth()); if (normal) { return label; } From 61f4defa4d4872631e827aa604468f564a854296 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jul 2023 21:20:06 +0400 Subject: [PATCH 56/60] Partially revert "Support and use share comment in stories." Send sharing comment as a separate message, like in posts sharing. --- .../SourceFiles/data/data_media_types.cpp | 21 ++++++++++++--- .../history/view/history_view_element.cpp | 8 ++---- .../stories/media_stories_controller.cpp | 2 +- .../media/stories/media_stories_share.cpp | 27 +++++++------------ 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index e623df3a5..19d89c500 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -1995,11 +1995,18 @@ MediaStory::MediaStory( owner->registerStoryItem(storyId, parent); const auto stories = &owner->stories(); - const auto maybeStory = stories->lookup(storyId); - if (!maybeStory) { + if (const auto maybeStory = stories->lookup(storyId)) { + if (!_mention) { + parent->setText((*maybeStory)->caption()); + } + } else { if (maybeStory.error() == NoStory::Unknown) { stories->resolve(storyId, crl::guard(this, [=] { - if (!stories->lookup(storyId)) { + if (const auto maybeStory = stories->lookup(storyId)) { + if (!_mention) { + parent->setText((*maybeStory)->caption()); + } + } else { _expired = true; } if (_mention) { @@ -2051,7 +2058,9 @@ TextWithEntities MediaStory::notificationText() const { && maybeStory.error() == Data::NoStory::Deleted)) ? tr::lng_in_dlg_story_expired : tr::lng_in_dlg_story)(tr::now), - parent()->originalText()); + (maybeStory + ? (*maybeStory)->caption() + : TextWithEntities())); } QString MediaStory::pinnedTextSubstring() const { @@ -2091,6 +2100,9 @@ std::unique_ptr MediaStory::createView( const auto stories = &parent()->history()->owner().stories(); const auto maybeStory = stories->lookup(_storyId); if (!maybeStory) { + if (!_mention) { + realParent->setText(TextWithEntities()); + } if (maybeStory.error() == Data::NoStory::Deleted) { _expired = true; return nullptr; @@ -2112,6 +2124,7 @@ std::unique_ptr MediaStory::createView( message, std::make_unique(message, story)); } else { + realParent->setText(story->caption()); if (const auto photo = story->photo()) { return std::make_unique( message, diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index f86159d38..0503f04ff 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -846,12 +846,8 @@ void Element::validateText() { _media = nullptr; if (!storyMention) { if (_text.isEmpty()) { - auto now = Ui::Text::Italic( - tr::lng_forwarded_story_expired(tr::now)); - if (!text.empty()) { - now.append(u"\n\n"_q).append(text); - } - setTextWithLinks(std::move(now)); + setTextWithLinks(Ui::Text::Italic( + tr::lng_forwarded_story_expired(tr::now))); } return; } diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 42cf67c5a..237401606 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -64,7 +64,7 @@ namespace { constexpr auto kPhotoProgressInterval = crl::time(100); constexpr auto kPhotoDuration = 5 * crl::time(1000); -constexpr auto kFullContentFade = 0.35; +constexpr auto kFullContentFade = 0.6; constexpr auto kSiblingMultiplierDefault = 0.448; constexpr auto kSiblingMultiplierMax = 0.72; constexpr auto kSiblingOutsidePart = 0.24; diff --git a/Telegram/SourceFiles/media/stories/media_stories_share.cpp b/Telegram/SourceFiles/media/stories/media_stories_share.cpp index d6fe67adc..413fbf3d1 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_share.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_share.cpp @@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/stories/media_stories_share.h" #include "api/api_common.h" -#include "api/api_text_entities.h" #include "apiwrap.h" #include "base/random.h" #include "boxes/share_box.h" @@ -87,7 +86,7 @@ namespace Media::Stories { for (const auto thread : result) { const auto error = GetErrorTextForSending( thread, - { .story = story }); + { .story = story, .text = &comment }); if (!error.isEmpty()) { return std::make_pair(error, thread); } @@ -106,21 +105,16 @@ namespace Media::Stories { return; } - auto caption = TextWithEntities{ - comment.text, - TextUtilities::ConvertTextTagsToEntities(comment.tags) - }; - TextUtilities::Trim(caption); - auto sentEntities = Api::EntitiesToMTP( - session, - caption.entities, - Api::ConvertOption::SkipLocal); - const auto captionText = caption.text; - const auto api = &story->owner().session().api(); auto &histories = story->owner().histories(); for (const auto thread : result) { const auto action = Api::SendAction(thread, options); + if (!comment.text.isEmpty()) { + auto message = Api::MessageToSend(action); + message.textWithTags = comment; + message.action.clearDraft = false; + api->sendMessage(std::move(message)); + } const auto peer = thread->peer(); const auto threadHistory = thread->owningHistory(); const auto randomId = base::RandomValue(); @@ -132,9 +126,6 @@ namespace Media::Stories { if (silentPost) { sendFlags |= MTPmessages_SendMedia::Flag::f_silent; } - if (!sentEntities.v.isEmpty()) { - sendFlags |= MTPmessages_SendMedia::Flag::f_entities; - } const auto done = [=] { if (!--state->requests) { if (show->valid()) { @@ -154,10 +145,10 @@ namespace Media::Stories { MTP_inputMediaStory( user->inputUser, MTP_int(id.story)), - MTP_string(captionText), + MTPstring(), MTP_long(randomId), MTPReplyMarkup(), - sentEntities, + MTPVector(), MTP_int(action.options.scheduled), MTP_inputPeerEmpty() ), [=](const MTPUpdates &result, const MTP::Response &response) { From 84ce95cc9538bc140646989e78f03e8273ed2646 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jul 2023 21:37:42 +0400 Subject: [PATCH 57/60] Update toast colors in day-blue / day-custom-base. --- Telegram/Resources/day-blue.tdesktop-theme | Bin 3686 -> 3706 bytes .../Resources/day-custom-base.tdesktop-theme | Bin 14227 -> 14474 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Telegram/Resources/day-blue.tdesktop-theme b/Telegram/Resources/day-blue.tdesktop-theme index 04b07154d9de6376e61e8d284eaa1a3b64c649e2..54d4dfa296af5891df00f28fc14c6869cdb44c7c 100644 GIT binary patch literal 3706 zcmZ{nXEYlQ+r}em?^S!RT2Z34QdKinX-jRj2}MY>Fzw;K*XN&=8TBP@002M_un82fTn9Kh=v-Vz7sYx} z?rt9bJ|RJ&fu10Epw9*~8L>jj{Ne8Ex_Gb;X8?|;hz)kqN|6jP$XID7A$<*R8GqvG zen&w}05v#a`XP*#os2v{*sr`Cy#%oOAE(t%r}qQIme5cZ0H8tz0N}ZB@(6ku6oLRD zJ-rbA$RM~9($_1%E6c$#h}ggx{ilk3k*-mf0R0p};noht1n1s+e>-B-IH~xXU)>MA z@!rtj=+hGCW1NiZ)90lP3oyFy6k`nWcfWWkm*X#>lvk&|( zKuvF-i=;8+?o5zhpB3#BS@vpV9=^M(R&9~H;8O^>}BI#o86(&;<~3N+^Wu6>G%M6E4}4~`k7~=^VEPOUa?-cP_wifcIfjr9`JcsA%HK?2 zYu0+7Ps}p}lLlH1rPuUE2M<62W|@DhuN{Eo9W7rh{6csF_4bm<{Jk&ZCELH%$GZBt#t5^KS+YzJDl#Qqzp;Q3K$6JaGcls_hM*lC_OlWk=$d0LTNT5r z66XfhOJJney^L5X`&&!`oiD?D;4Nt?YbMO<`m0QN9&LFuFyZDF_h^Qq)SVi+MT*3E zQ*yVvnB^PJ;GKh>nA@@o0<%AU30FLjaL6mfN`+&x9)#YlNgZ%wi8Tg7Y&&mmqfQ~8 zR%4B0AD{fe#cCD!88YK658g!vzsnkWmu$j`^8Sf>=IvvW-8@~Xm~NNK?5(YPc{Ei- zoBA;3W64~G(qszfH2IzRaRN{ZLmmZmzk%#<@)z?O4BaiJTWU082y6v6i@_Q1}#=z_8b!@A7w3 z(!j|@6da63F7+rZ$BEUiW%ooZ@@DYQZyHM=J?L?!z!+0#_PwE&oxAK4ca#Aw*eHYW zt_LU6ypYyYbDSXZwJVd*#1WTA^*+-i4^0T+;E{fAEVlu$H`|aA;~QCQr5|hbb_UjR zK)WOm9WT|#l{Q))ZTuC`{{Xa$mx=4^lGl+acRI?;q`rYfy3B_{D$XH7w0#d;KKFfm zYN7C;EP2~&P5{3qKw(qf+Agj_7L1MlO!_v#X<;bdGX?L}(9d_pByE%WWE*PcUJJiX zdNx*Sg-oZrZvKgDmp!l5%lmB6@C5@~Bf*C6$wbc{96g(yW|eO6H9sMUUv$Y>rq-FD zuEZUBx!Db3B6KOI(U}k-Hn=ZwPol?Wp=Ad5TxI}&$DGBfUa*Uzme`F}7$5bf-qX4j zXk>3}@|kBO?e_hr-=F`^W*ff0Rk_0=^k6mV*9h8gGWeHe95CoO;@!869hRRr9AHQZ z?yZ#=@2TbY98Tu*OS~- zz4MjC`kv9-&aK@7Y`DzBrABqg4E>OQL_=0+`0`?VQB~_PnGaeyFKBQmzs*V9y6dy< z(cJsyF2;5KrsP|(#5ZlXpskr;8+4CfE;v~zDrrnOB?P5A|lKDb!>`px(D%LGISw^wZ_j37~NYC5S|fm zwOheME+uUAuR=QtQA)8Te~`tWA|&XPPsN4iD%5;R;OX0ZV>>KsFuVKL+n;v+nb+C8 z)e22=Z-iRM*Z7FZOUd!SwbpMDG-4Fr!CoEuo2hn|z2oK3aA`f3J$xC23)vV+x;!yp zB?VeI2CzAo`})ncU>#x~r+Y>9QatIe7#1ruUMd?HU1oOkKlq8Sxoa=2u4LK*l>ZAr z&`yRniPI2h^6Vn7#F~n)qf7gu=vLAM;kBoF@rnt%B^!*|{vkUHIx4}|u6j)!!2=53 zI#yafSkty{*zH{+-4n;vNTF)R{gNw`VeN_LRgPH>QKWX`b5EP4rRFvB@#~ff7xx6` zd+Z^(OL>dbfh>oIRSJPh9?Jm9<9uT;4R1wCnl>VA>kSveQC?BTNp*)&wlr<}^bx24 zt!+YsUfZ_c$R_LKN#1$8p}O+gVY(YbbsMIlw&ZLe4m#V(%|ogrf2rN0H=KIgrLOvi z{{*wG_-cN^B^tI&e zOu}?{Cw$$3XY{(-_>}*gffUbdt(CMa@D8W2F^xo?oqft}weI!TRAi5OZRlHg(0#pU zwua|r+NvR{W=ZA26|1czaYlQaoT8)=1b%A8j^fhWx!_!bZyeQH0F&+ z$hYqXIy+T!qmQ5CXPYe3rU;I!@v zw&hX{^*CKci@?K)^SDhn)w;>qfIkc<7h&_D#izuT!M)Kkr?kI=Av$;o=KX)JGzdG zT{KR@usJOdkwMtzTRl&xU{+dek&%)r&1wes6{Q<0X=(5DU;#a(8j$?D^B06*7OVL{ z<^GH*-7x+iMW>Fju|vowyWqIVv7gS)O{u1I6;}3MpdutY@dsz~)0PjOO0eRl^WD^X zpS`8%@v5$jHCB_IvUuy#SB-_5F6_hmPr7bzl)Yzbg^tP+vg`V5AU8A&Y1>GC zEi&7xBa(q4F^zCI5vO4Cm6**N5e+=CldIgw#!dM0w*B^z_FU>AX-J3m8A=Jc=e<2X z_#sAJMQ38L2?68u_-eyH|7O)Mvt9LMxFMtMZPUuEAOUyP!aC2Phv@DbVtFS2s+ETZ zf7&w0XPn#cWpuxOhRxk&N~D_N)-LmhxFWv^9+Zu0i&GYjZ3MC*KDtrI@%M9zES9ML zGs@&*J1*q1iUB_hGNU9<-~}23`f4fN-`dMj7qbCwIe6kOo18`z)zPu+NT^{lp@!8MTu_RW3;Pg{ z<2b(}X&jD^#`$Q3uPY;tR;y>lutw%)_U*@|$68h8OAO@NJ8r|-B=wp)1mQ_S1*`4> ze;M_6)h5K_5!R5_xCc|^!#Q!!%};ZYO!x{}?hW!HaTzD!l5{`*)qxCf9yYqckiob> zT1We|Ma^B!!>9ZfMTMB+xTUGvZPHkmI1>^?&|Co2dUl$?vpZ9oxF-aHP2LSvFniLfF literal 3686 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 T-CKX%AOQd74BQ|R^tbyL7hc1% diff --git a/Telegram/Resources/day-custom-base.tdesktop-theme b/Telegram/Resources/day-custom-base.tdesktop-theme index 36f91ef0257d5dd8456abb9ca410a86a8df13524..d10f68c7568edc082b008a7e9f2064b9c31e15d2 100644 GIT binary patch literal 14474 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 bLc;$iu}o109O8ezf&6#<|Fh2=|Kt5H@Anvm literal 14227 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 Oe|z-5+QRlfPX8Cy* Date: Fri, 28 Jul 2023 21:38:59 +0400 Subject: [PATCH 58/60] Use close icon from group calls in stories tooltip. --- Telegram/SourceFiles/dialogs/dialogs.style | 9 ++++- .../dialogs/ui/dialogs_stories_list.cpp | 35 ++++--------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 88e1239be..622016bb8 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -567,4 +567,11 @@ dialogsStoriesTooltip: ImportantTooltip(defaultImportantTooltip) { } dialogsStoriesTooltipLabel: defaultImportantTooltipLabel; dialogsStoriesTooltipMaxWidth: 200px; -dialogsStoriesTooltipHide: size(14px, 14px); +dialogsStoriesTooltipHide: IconButton(defaultIconButton) { + width: 34px; + height: 20px; + iconPosition: point(-1px, -1px); + icon: icon {{ "calls/video_tooltip", importantTooltipFg }}; + iconOver: icon {{ "calls/video_tooltip", importantTooltipFg }}; + ripple: emptyRippleAnimation; +} diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index f99091721..82854b90b 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -13,10 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/outline_segments.h" #include "ui/text/text_utilities.h" #include "ui/widgets/menu/menu_add_action_callback_factory.h" +#include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/tooltip.h" -#include "ui/abstract_button.h" #include "ui/painter.h" #include "styles/style_dialogs.h" @@ -49,8 +49,7 @@ constexpr auto kStoriesTooltipHideBgOpacity = 0.2; not_null parent, rpl::producer text, Fn hide) { - const auto size = st::dialogsStoriesTooltipHide; - const auto buttonw = size.width(); + const auto size = st::dialogsStoriesTooltipHide.width; const auto skip = st::defaultImportantTooltip.padding.right(); auto result = object_ptr>( parent, @@ -60,36 +59,16 @@ constexpr auto kStoriesTooltipHideBgOpacity = 0.2; st::dialogsStoriesTooltipMaxWidth, st::dialogsStoriesTooltipLabel), (st::defaultImportantTooltip.padding - + QMargins(0, 0, skip + buttonw, 0))); - const auto button = Ui::CreateChild(result.data()); + + QMargins(0, 0, skip + size, 0))); + const auto button = Ui::CreateChild( + result.data(), + st::dialogsStoriesTooltipHide); result->sizeValue( ) | rpl::start_with_next([=](QSize size) { - button->resize(skip * 2 + buttonw, size.height()); + button->resize(button->width(), size.height()); button->moveToRight(0, 0, size.width()); }, button->lifetime()); button->setClickedCallback(std::move(hide)); - button->paintRequest( - ) | rpl::start_with_next([=] { - auto p = QPainter(button); - auto hq = PainterHighQualityEnabler(p); - p.setPen(Qt::NoPen); - p.setBrush(st::importantTooltipFg); - p.setOpacity(kStoriesTooltipHideBgOpacity); - const auto rect = style::centerrect( - button->rect(), - QRect(QPoint(), size)); - const auto center = QRectF(rect).center(); - const auto half = QSizeF(rect.size()) / 6.; - const auto phalf = QPointF(half.width(), half.height()); - const auto mhalf = QPointF(-half.width(), half.height()); - p.drawEllipse(rect); - p.setOpacity(1.); - auto pen = st::importantTooltipFg->p; - pen.setWidthF(style::ConvertScaleExact(sqrtf(2.))); - p.setPen(pen); - p.drawLine(center - phalf, center + phalf); - p.drawLine(center - mhalf, center + mhalf); - }, button->lifetime()); return result; } From 81be0ef20b4b52cd8c58f1f7cfdfe931cba29b32 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jul 2023 21:41:24 +0400 Subject: [PATCH 59/60] Version 4.8.10. - Send story sharing comments as separate messages. - Fix stories explanation tooltip ordering. --- 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 | 5 +++++ 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index a0e82f806..9e1d43480 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="4.8.10.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 1253b7043..275685f7c 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,8,9,0 - PRODUCTVERSION 4,8,9,0 + FILEVERSION 4,8,10,0 + PRODUCTVERSION 4,8,10,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "4.8.9.0" + VALUE "FileVersion", "4.8.10.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.8.9.0" + VALUE "ProductVersion", "4.8.10.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index cb1aed9eb..e7bd1d0dc 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,8,9,0 - PRODUCTVERSION 4,8,9,0 + FILEVERSION 4,8,10,0 + PRODUCTVERSION 4,8,10,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -53,10 +53,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "4.8.9.0" + VALUE "FileVersion", "4.8.10.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.8.9.0" + VALUE "ProductVersion", "4.8.10.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 4f1c6194a..6bbf2904d 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 = 4008009; -constexpr auto AppVersionStr = "4.8.9"; +constexpr auto AppVersion = 4008010; +constexpr auto AppVersionStr = "4.8.10"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 3bbc47084..f7062fb28 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 4008009 +AppVersion 4008010 AppVersionStrMajor 4.8 -AppVersionStrSmall 4.8.9 -AppVersionStr 4.8.9 +AppVersionStrSmall 4.8.10 +AppVersionStr 4.8.10 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 4.8.9 +AppVersionOriginal 4.8.10 diff --git a/changelog.txt b/changelog.txt index 4c503803a..28384f4b3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,8 @@ +4.8.10 (28.07.23) + +- Send story sharing comments as separate messages. +- Fix stories explanation tooltip ordering. + 4.8.9 (26.07.23) - Bug fixes and other minor improvements. From 8ec0bdcac935adfdae740c4551db08927be59dd7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jul 2023 21:46:02 +0400 Subject: [PATCH 60/60] Version 4.8.10: Fix build with GCC. --- Telegram/SourceFiles/platform/linux/main_window_linux.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 692c68353..f6d48b3da 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "base/platform/base_platform_info.h" #include "base/event_filter.h" +#include "ui/platform/ui_platform_window_title.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/input_fields.h" #include "ui/ui_utility.h"