From 678527254b07736015d6e21fbb66bd9ab6a87a51 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Tue, 28 Jan 2025 04:22:51 +0000 Subject: [PATCH 01/95] Add development facilities to the CentOS Dockerfile --- .devcontainer.json | 36 +++++++++++++++++++ .gitignore | 1 + Telegram/build/docker/centos_env/Dockerfile | 39 +++++++++++++++------ docs/building-linux.md | 17 +++++++++ 4 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 .devcontainer.json diff --git a/.devcontainer.json b/.devcontainer.json new file mode 100644 index 000000000..27fb3574e --- /dev/null +++ b/.devcontainer.json @@ -0,0 +1,36 @@ +{ + "name": "CentOS", + "image": "tdesktop:centos_env", + "customizations": { + "vscode": { + "settings": { + "C_Cpp.intelliSenseEngine": "disabled", + "clangd.arguments": [ + "--compile-commands-dir=${workspaceFolder}/out" + ], + "cmake.generator": "Ninja Multi-Config", + "cmake.buildDirectory": "${workspaceFolder}/out", + "cmake.configureSettings": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + "extensions": [ + "ms-vscode.cpptools-extension-pack", + "llvm-vs-code-extensions.vscode-clangd", + "TheQtCompany.qt", + "ms-python.python", + "ms-azuretools.vscode-docker", + "mkhl.direnv", + "eamodio.gitlens" + ] + } + }, + "capAdd": [ + "SYS_PTRACE" + ], + "securityOpt": [ + "seccomp=unconfined" + ], + "workspaceMount": "source=${localWorkspaceFolder},target=/usr/src/tdesktop,type=bind,consistency=cached", + "workspaceFolder": "/usr/src/tdesktop" +} diff --git a/.gitignore b/.gitignore index c2896799e..f893d4bad 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ Release/ ipch/ .vs/ .vscode/ +.cache/ /Telegram/log.txt /Telegram/data diff --git a/Telegram/build/docker/centos_env/Dockerfile b/Telegram/build/docker/centos_env/Dockerfile index f36d40a51..b9414dcc7 100644 --- a/Telegram/build/docker/centos_env/Dockerfile +++ b/Telegram/build/docker/centos_env/Dockerfile @@ -1,6 +1,7 @@ {%- set GIT = "https://github.com" -%} {%- set GIT_FREEDESKTOP = GIT ~ "/gitlab-freedesktop-mirrors" -%} {%- set GIT_UPDATE_M4 = "git submodule set-url m4 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 && git config -f .gitmodules submodule.m4.shallow true && git submodule init && git submodule update" -%} +{%- set TOOLSET = "gcc-toolset-12" -%} {%- set QT = "6.8.1" -%} {%- set QT_TAG = "v" ~ QT -%} {%- set CFLAGS_DEBUG = "$CFLAGS -O0 -fno-lto -U_FORTIFY_SOURCE" -%} @@ -14,24 +15,37 @@ ENV LIBRARY_PATH /usr/local/lib64:/usr/local/lib:/lib64:/lib:/usr/lib64:/usr/lib ENV LD_LIBRARY_PATH $LIBRARY_PATH ENV PKG_CONFIG_PATH /usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig +RUN adduser user + RUN dnf -y install epel-release \ && dnf config-manager --set-enabled powertools \ && dnf -y install cmake autoconf automake libtool pkgconfig make patch git \ - python3.11-pip python3.11-devel gperf flex bison clang lld nasm yasm \ - file which perl-open perl-XML-Parser perl-IPC-Cmd xorg-x11-util-macros \ - gcc-toolset-12-gcc gcc-toolset-12-gcc-c++ gcc-toolset-12-binutils \ - gcc-toolset-12-libasan-devel libffi-devel fontconfig-devel freetype-devel \ - libX11-devel alsa-lib-devel pulseaudio-libs-devel mesa-libGL-devel \ - mesa-libEGL-devel mesa-libgbm-devel libdrm-devel vulkan-devel libva-devel \ - libvdpau-devel glib2-devel at-spi2-core-devel gtk3-devel boost1.78-devel fmt-devel \ + python3.11-pip python3.11-devel gperf flex bison clang clang-tools-extra \ + lld nasm yasm file which perl-open perl-XML-Parser perl-IPC-Cmd \ + xorg-x11-util-macros {{ TOOLSET }}-gcc {{ TOOLSET }}-gcc-c++ \ + {{ TOOLSET }}-binutils {{ TOOLSET }}-gdb {{ TOOLSET }}-libasan-devel \ + libffi-devel fontconfig-devel freetype-devel libX11-devel wayland-devel \ + alsa-lib-devel pulseaudio-libs-devel mesa-libGL-devel mesa-libEGL-devel \ + mesa-libgbm-devel libdrm-devel vulkan-devel libva-devel libvdpau-devel \ + glib2-devel at-spi2-core-devel gtk3-devel boost1.78-devel fmt-devel \ && dnf clean all -SHELL [ "bash", "-c", ". /opt/rh/gcc-toolset-12/enable; exec bash -c \"$@\"", "-s"] +SHELL [ "bash", "-c", ". /opt/rh/{{ TOOLSET }}/enable; exec bash -c \"$@\"", "-s"] WORKDIR {{ LibrariesPath }} RUN python3 -m pip install meson ninja +RUN curl -sSL https://github.com/direnv/direnv/releases/download/v2.35.0/direnv.linux-amd64 > /usr/local/bin/direnv \ + && chmod +x /usr/local/bin/direnv \ + && echo 'eval "$(direnv hook bash)"' >> /home/user/.bashrc \ + && mkdir -p /home/user/.config/direnv \ + && echo . /opt/rh/{{ TOOLSET }}/enable > /home/user/.config/direnv/direnvrc \ + && touch /.envrc \ + && su -c "direnv allow /" user + +RUN echo set debuginfod enabled on > /opt/rh/{{ TOOLSET }}/root/etc/gdbinit.d/00-debuginfod.gdb + ENV AR gcc-ar ENV RANLIB gcc-ranlib ENV NM gcc-nm @@ -460,8 +474,10 @@ RUN git clone -b 1.19.0 --depth=1 {{ GIT_FREEDESKTOP }}/wayland.git \ -Ddocumentation=false \ -Ddtd_validation=false \ -Dicon_directory=/usr/share/icons \ - && meson compile -C build \ - && DESTDIR="{{ LibrariesPath }}/wayland-cache" meson install -C build \ + && meson compile -C build src/wayland-scanner \ + && mkdir -p "{{ LibrariesPath }}/wayland-cache/usr/local/bin" "{{ LibrariesPath }}/wayland-cache/usr/local/lib64/pkgconfig" \ + && cp build/src/wayland-scanner "{{ LibrariesPath }}/wayland-cache/usr/local/bin" \ + && sed 's@bindir=${prefix}/bin@bindir=${prefix}/local/bin@;s/1.21.0/1.19.0/' /usr/lib64/pkgconfig/wayland-scanner.pc > "{{ LibrariesPath }}/wayland-cache/usr/local/lib64/pkgconfig/wayland-scanner.pc" \ && cd .. \ && rm -rf wayland @@ -868,6 +884,7 @@ ENV QT {{ QT }} ENV BOOST_INCLUDEDIR /usr/include/boost1.78 ENV BOOST_LIBRARYDIR /usr/lib64/boost1.78 +USER user VOLUME [ "/usr/src/tdesktop" ] -ENTRYPOINT [ "scl", "enable", "gcc-toolset-12", "--" ] +ENTRYPOINT [ "scl", "enable", "{{ TOOLSET }}", "--" ] CMD [ "/usr/src/tdesktop/Telegram/build/docker/centos_env/build.sh" ] diff --git a/docs/building-linux.md b/docs/building-linux.md index e8a0b050b..d177798fe 100644 --- a/docs/building-linux.md +++ b/docs/building-linux.md @@ -38,4 +38,21 @@ Or, to create a debug build, run (also using [your **api_id** and **api_hash**]( The built files will be in the `out` directory. +### Visual Studio Code integration + +Ensure you've followed the instruction up to the [**Clone source code and prepare libraries**](#clone-source-code-and-prepare-libraries) step at least. + +Open the repository in Visual Studio Code, install the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension and add the following to `.vscode/settings.json` (using [your **api_id** and **api_hash**](#obtain-your-api-credentials)): + + { + "cmake.configureSettings": { + "TDESKTOP_API_ID": "YOUR_API_ID", + "TDESKTOP_API_HASH": "YOUR_API_HASH" + } + } + +After that, choose **Reopen in Container** via the menu triggered by the green button in bottom left corner and you're done. + +![Quick actions Status bar item](https://code.visualstudio.com/assets/docs/devcontainers/containers/remote-dev-status-bar.png) + [api_credentials]: api_credentials.md From bbdd5feaa4841b832dfcb6487d17de42e1557b09 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 28 Jan 2025 09:58:42 +0300 Subject: [PATCH 02/95] Fixed display of video userpic in short box on Retina. --- .../SourceFiles/boxes/peers/peer_short_info_box.cpp | 13 ++++++++----- .../SourceFiles/boxes/peers/peer_short_info_box.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp index 0275358f0..12fab358c 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp @@ -106,6 +106,8 @@ PeerShortInfoCover::PeerShortInfoCover( , _statusStyle(std::make_unique(_st.status)) , _status(_widget.get(), std::move(status), _statusStyle->st) , _roundMask(Images::CornersMask(_st.radius)) +, _roundMaskRetina( + Images::CornersMask(_st.radius / style::DevicePixelRatio())) , _videoPaused(std::move(videoPaused)) { _widget->setCursor(_cursor); @@ -190,7 +192,7 @@ void PeerShortInfoCover::paint(QPainter &p) { if (!frame.isNull()) { frame = Images::Round( std::move(frame), - _roundMask, + _roundMaskRetina, RectPart::TopLeft | RectPart::TopRight); } else if (_userpicImage.isNull()) { auto image = QImage( @@ -226,10 +228,11 @@ void PeerShortInfoCover::paintCoverImage(QPainter &p, const QImage &image) { const auto top = _widget->height() - fill; const auto factor = style::DevicePixelRatio(); if (fill > 0) { + const auto t = roundedHeight + _scrollTop; p.drawImage( - QRect(0, top, roundedWidth, fill), + QRect(0, t, roundedWidth * factor, (roundedWidth - t) * factor), image, - QRect(0, top * factor, roundedWidth * factor, fill * factor)); + QRect(0, t, roundedWidth * factor, (roundedWidth - t) * factor)); } if (covered <= 0) { return; @@ -238,9 +241,9 @@ void PeerShortInfoCover::paintCoverImage(QPainter &p, const QImage &image) { const auto from = top - rounded; auto q = QPainter(&_roundedTopImage); q.drawImage( - QRect(0, 0, roundedWidth, rounded), + QRect(0, 0, roundedWidth * factor, rounded * factor), image, - QRect(0, from * factor, roundedWidth * factor, rounded * factor)); + QRect(0, _scrollTop, roundedWidth * factor, rounded * factor)); q.end(); _roundedTopImage = Images::Round( std::move(_roundedTopImage), diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h index 271e1826c..f6baf8c74 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h @@ -123,6 +123,7 @@ private: object_ptr _additionalStatus = { nullptr }; std::array _roundMask; + std::array _roundMaskRetina; QImage _userpicImage; QImage _roundedTopImage; QImage _barSmall; From d6ba6ac41edbd859b1d0cb3b773acfd65d9acca8 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 28 Jan 2025 18:26:47 +0300 Subject: [PATCH 03/95] Added initial ability to open single typed shared media in window. --- .../SourceFiles/info/info_wrap_widget.cpp | 5 +- Telegram/SourceFiles/info/info_wrap_widget.h | 2 + .../info/media/info_media_buttons.h | 5 +- .../profile/info_profile_inner_widget.cpp | 75 +++++++++++++++++++ Telegram/SourceFiles/window/window.style | 2 + .../SourceFiles/window/window_separate_id.cpp | 13 ++++ .../SourceFiles/window/window_separate_id.h | 16 ++++ .../window/window_session_controller.cpp | 27 +++++++ 8 files changed, 143 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index dbef00afb..212e541f4 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -106,6 +106,8 @@ WrapWidget::WrapWidget( Wrap wrap, not_null memento) : SectionWidget(parent, window, rpl::producer()) +, _isSeparatedWindow( + window->windowId().type == Window::SeparateType::SharedMedia) , _wrap(wrap) , _controller(createController(window, memento->content())) , _topShadow(this) @@ -1044,7 +1046,8 @@ const Ui::RoundRect *WrapWidget::bottomSkipRounding() const { } bool WrapWidget::hasBackButton() const { - return (wrap() == Wrap::Narrow || hasStackHistory()); + return !_isSeparatedWindow + && (wrap() == Wrap::Narrow || hasStackHistory()); } bool WrapWidget::willHaveBackButton( diff --git a/Telegram/SourceFiles/info/info_wrap_widget.h b/Telegram/SourceFiles/info/info_wrap_widget.h index 0ece881a0..815765154 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.h +++ b/Telegram/SourceFiles/info/info_wrap_widget.h @@ -208,6 +208,8 @@ private: void addProfileCallsButton(); void showTopBarMenu(bool check); + const bool _isSeparatedWindow = false; + rpl::variable _wrap; std::unique_ptr _controller; object_ptr _content = { nullptr }; diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.h b/Telegram/SourceFiles/info/media/info_media_buttons.h index 4efdb15f9..363a27953 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.h +++ b/Telegram/SourceFiles/info/media/info_media_buttons.h @@ -96,7 +96,10 @@ inline auto AddButton( Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), MediaText(type), tracker)->entity(); - result->addClickHandler([=] { + result->addClickHandler([=](Qt::MouseButton mouse) { + if (mouse == Qt::RightButton) { + return; + } const auto topic = topicRootId ? peer->forumTopicFor(topicRootId) : nullptr; diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 4e9108fc3..8d8a6b599 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/profile/info_profile_inner_widget.h" +#include "base/call_delayed.h" #include "info/info_memento.h" #include "info/info_controller.h" #include "info/profile/info_profile_widget.h" @@ -29,11 +30,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "api/api_peer_photo.h" #include "window/main_window.h" +#include "window/window_separate_id.h" #include "window/window_session_controller.h" #include "storage/storage_shared_media.h" #include "lang/lang_keys.h" #include "ui/widgets/buttons.h" #include "ui/widgets/checkbox.h" +#include "ui/widgets/popup_menu.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/widgets/box_content_divider.h" @@ -44,10 +47,79 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_shared_media.h" #include "styles/style_info.h" #include "styles/style_boxes.h" +#include "styles/style_menu_icons.h" namespace Info { namespace Profile { +namespace { + +Window::SeparateSharedMediaType ToSeparateType( + Storage::SharedMediaType type) { + using Type = Storage::SharedMediaType; + using SeparatedType = Window::SeparateSharedMediaType; + return (type == Type::Photo) + ? SeparatedType::Photos + : (type == Type::Video) + ? SeparatedType::Videos + : (type == Type::File) + ? SeparatedType::Files + : (type == Type::MusicFile) + ? SeparatedType::Audio + : (type == Type::Link) + ? SeparatedType::Links + : (type == Type::RoundVoiceFile) + ? SeparatedType::Voices + : (type == Type::GIF) + ? SeparatedType::GIF + : SeparatedType::None; +} + +Fn SeparateWindowFactory( + not_null controller, + not_null peer, + Storage::SharedMediaType type) { + const auto separateType = ToSeparateType(type); + if (separateType == Window::SeparateSharedMediaType::None) { + return nullptr; + } + return [=] { + controller->showInNewWindow(Window::SeparateId(separateType, peer)); + }; +} + +void AddContextMenu( + not_null button, + not_null controller, + not_null peer, + Storage::SharedMediaType type) { + const auto callback = SeparateWindowFactory(controller, peer, type); + if (!callback) { + return; + } + button->setAcceptBoth(); + struct State final { + base::unique_qptr menu; + }; + const auto state = button->lifetime().make_state(); + button->addClickHandler([=](Qt::MouseButton mouse) { + if (mouse != Qt::RightButton) { + return; + } + state->menu = base::make_unique_q( + button.get(), + st::popupMenuWithIcons); + state->menu->addAction(tr::lng_context_new_window(tr::now), [=] { + base::call_delayed( + st::popupMenuWithIcons.showDuration, + crl::guard(button, callback)); + }, &st::menuIconNewWindow); + state->menu->popup(QCursor::pos()); + }); +} + +} // namespace + InnerWidget::InnerWidget( QWidget *parent, not_null controller, @@ -160,6 +232,9 @@ object_ptr InnerWidget::setupSharedMedia( _migrated, type, tracker); + if (const auto window = _controller->parentController(); !_topic) { + AddContextMenu(result, window, _peer, type); + } object_ptr( result, icon, diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index 30026da2c..acdda3129 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -321,6 +321,8 @@ ivHeightMin: 480px; ivWidthDefault: 600px; ivHeightDefault: 800px; +maxWidthSharedMediaWindow: 419px; + // Windows specific winQuitIcon: icon {{ "win_quit", windowFg }}; diff --git a/Telegram/SourceFiles/window/window_separate_id.cpp b/Telegram/SourceFiles/window/window_separate_id.cpp index f2ed89183..f46d4bce4 100644 --- a/Telegram/SourceFiles/window/window_separate_id.cpp +++ b/Telegram/SourceFiles/window/window_separate_id.cpp @@ -44,6 +44,13 @@ SeparateId::SeparateId(not_null peer) : SeparateId(SeparateType::Chat, peer->owner().history(peer)) { } +SeparateId::SeparateId(SeparateSharedMediaType type, not_null peer) +: type(SeparateType::SharedMedia) +, sharedMedia(type) +, account(&peer->session().account()) +, sharedMediaLocalPeer(peer) { +} + bool SeparateId::primary() const { return (type == SeparateType::Primary); } @@ -74,4 +81,10 @@ bool SeparateId::hasChatsList() const { || (type == SeparateType::Forum); } +PeerData *SeparateId::sharedMediaPeer() const { + return (type == SeparateType::SharedMedia) + ? sharedMediaLocalPeer + : nullptr; +} + } // namespace Window diff --git a/Telegram/SourceFiles/window/window_separate_id.h b/Telegram/SourceFiles/window/window_separate_id.h index bcbe72860..e031e5400 100644 --- a/Telegram/SourceFiles/window/window_separate_id.h +++ b/Telegram/SourceFiles/window/window_separate_id.h @@ -29,6 +29,18 @@ enum class SeparateType { Chat, Forum, SavedSublist, + SharedMedia, +}; + +enum class SeparateSharedMediaType { + None, + Photos, + Videos, + Files, + Audio, + Links, + Voices, + GIF, }; struct SeparateId { @@ -38,10 +50,13 @@ struct SeparateId { SeparateId(SeparateType type, not_null thread); SeparateId(not_null thread); SeparateId(not_null peer); + SeparateId(SeparateSharedMediaType type, not_null peer); SeparateType type = SeparateType::Primary; + SeparateSharedMediaType sharedMedia = SeparateSharedMediaType::None; Main::Account *account = nullptr; Data::Thread *thread = nullptr; // For types except Main and Archive. + PeerData *sharedMediaLocalPeer = nullptr; [[nodiscard]] bool valid() const { return account != nullptr; @@ -55,6 +70,7 @@ struct SeparateId { [[nodiscard]] Data::Forum *forum() const; [[nodiscard]] Data::Folder *folder() const; [[nodiscard]] Data::SavedSublist *sublist() const; + [[nodiscard]] PeerData *sharedMediaPeer() const; [[nodiscard]] bool hasChatsList() const; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 559b60f00..6a82b2b49 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1189,6 +1189,30 @@ void SessionNavigation::showByInitialId( case SeparateType::Chat: showThread(id.thread, msgId, instant); break; + case SeparateType::SharedMedia: { + Assert(id.sharedMedia != SeparateSharedMediaType::None); + clearSectionStack(instant); + const auto type = (id.sharedMedia == SeparateSharedMediaType::Photos) + ? Storage::SharedMediaType::Photo + : (id.sharedMedia == SeparateSharedMediaType::Videos) + ? Storage::SharedMediaType::Video + : (id.sharedMedia == SeparateSharedMediaType::Files) + ? Storage::SharedMediaType::File + : (id.sharedMedia == SeparateSharedMediaType::Audio) + ? Storage::SharedMediaType::MusicFile + : (id.sharedMedia == SeparateSharedMediaType::Links) + ? Storage::SharedMediaType::Link + : (id.sharedMedia == SeparateSharedMediaType::Voices) + ? Storage::SharedMediaType::RoundVoiceFile + : (id.sharedMedia == SeparateSharedMediaType::GIF) + ? Storage::SharedMediaType::GIF + : Storage::SharedMediaType::Photo; + showSection( + std::make_shared(id.sharedMediaPeer(), type), + instant); + parent->widget()->setMaximumWidth(st::maxWidthSharedMediaWindow); + break; + } case SeparateType::SavedSublist: showSection( std::make_shared(id.sublist()), @@ -1782,6 +1806,9 @@ const rpl::variable &SessionController::shownForum() const { } void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) { + if (windowId().type == SeparateType::SharedMedia) { + return; + } const auto was = _activeChatEntry.current().key.history(); const auto now = row.key.history(); if (was && was != now) { From cf1fa718a8cb308d36794c79be590bc2a3973923 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2025 11:00:50 +0300 Subject: [PATCH 04/95] Improved conflict handle between IV shortcuts and Shortcuts. --- Telegram/SourceFiles/dialogs/dialogs_widget.cpp | 1 + Telegram/SourceFiles/history/history_widget.cpp | 1 + Telegram/SourceFiles/info/info_wrap_widget.cpp | 1 + Telegram/SourceFiles/iv/iv_controller.cpp | 16 +++++++++++++++- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index ecabae874..752e431a9 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1214,6 +1214,7 @@ void Widget::setupShortcuts() { }); request->check(Command::ShowChatMenu, 1) && request->handle([=] { if (_inner) { + Window::ActivateWindow(controller()); _inner->showPeerMenu(); } return true; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 67d49cad7..6c337f9c0 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2010,6 +2010,7 @@ void HistoryWidget::setupShortcuts() { return true; }); request->check(Command::ShowChatMenu, 1) && request->handle([=] { + Window::ActivateWindow(controller()); _topBar->showPeerMenu(); return true; }); diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index 212e541f4..3e86ccb36 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -502,6 +502,7 @@ void WrapWidget::addTopBarMenuButton() { using Command = Shortcuts::Command; request->check(Command::ShowChatMenu, 1) && request->handle([=] { + Window::ActivateWindow(_controller->parentController()); showTopBarMenu(false); return true; }); diff --git a/Telegram/SourceFiles/iv/iv_controller.cpp b/Telegram/SourceFiles/iv/iv_controller.cpp index bf699adb7..87befe5bf 100644 --- a/Telegram/SourceFiles/iv/iv_controller.cpp +++ b/Telegram/SourceFiles/iv/iv_controller.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "iv/iv_controller.h" +#include "base/event_filter.h" #include "base/platform/base_platform_info.h" #include "base/qt/qt_key_modifiers.h" #include "base/invoke_queued.h" @@ -679,18 +680,31 @@ void Controller::createWebview(const Webview::StorageId &storageId) { if (event->key() == Qt::Key_Escape) { escape(); } + } + }, window->lifetime()); + + base::install_event_filter(window, qApp, [=](not_null e) { + if (e->type() == QEvent::ShortcutOverride) { + if (!window->isActiveWindow()) { + return base::EventFilterResult::Continue; + } + const auto event = static_cast(e.get()); if (event->modifiers() & Qt::ControlModifier) { if (event->key() == Qt::Key_Plus || event->key() == Qt::Key_Equal) { _delegate->ivSetZoom(_delegate->ivZoom() + kZoomStep); + return base::EventFilterResult::Cancel; } else if (event->key() == Qt::Key_Minus) { _delegate->ivSetZoom(_delegate->ivZoom() - kZoomStep); + return base::EventFilterResult::Cancel; } else if (event->key() == Qt::Key_0) { _delegate->ivSetZoom(kDefaultZoom); + return base::EventFilterResult::Cancel; } } } - }, window->lifetime()); + return base::EventFilterResult::Continue; + }); const auto widget = raw->widget(); if (!widget) { From 0089cad740a23613e1523e5f7a669e23697d17b0 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2025 11:42:12 +0300 Subject: [PATCH 05/95] Replaced default shortcut to open chat menu with Ctrl+\. --- Telegram/SourceFiles/core/shortcuts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp index 3632bcfd3..49f81d1d8 100644 --- a/Telegram/SourceFiles/core/shortcuts.cpp +++ b/Telegram/SourceFiles/core/shortcuts.cpp @@ -440,7 +440,7 @@ void Manager::fillDefaults() { set(u"ctrl+r"_q, Command::ReadChat); - set(u"ctrl+="_q, Command::ShowChatMenu); + set(u"ctrl+\\"_q, Command::ShowChatMenu); } void Manager::writeDefaultFile() { From 7442ea7a1607ac38aac5f9be2f8d87b31a7c0cf5 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2025 12:04:44 +0300 Subject: [PATCH 06/95] Added ability to open single typed shared media in window for topics. --- .../info/profile/info_profile_inner_widget.cpp | 17 +++++++++++------ .../SourceFiles/window/window_separate_id.cpp | 17 ++++++++++++----- .../SourceFiles/window/window_separate_id.h | 12 ++++++++++-- .../window/window_session_controller.cpp | 12 +++++++++++- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 8d8a6b599..5ef8bfd32 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -78,22 +78,26 @@ Window::SeparateSharedMediaType ToSeparateType( Fn SeparateWindowFactory( not_null controller, not_null peer, + MsgId topicRootId, Storage::SharedMediaType type) { const auto separateType = ToSeparateType(type); if (separateType == Window::SeparateSharedMediaType::None) { return nullptr; } return [=] { - controller->showInNewWindow(Window::SeparateId(separateType, peer)); + controller->showInNewWindow({ + Window::SeparateSharedMedia(separateType, peer, topicRootId), + }); }; } void AddContextMenu( not_null button, - not_null controller, + not_null window, not_null peer, + MsgId rootId, Storage::SharedMediaType type) { - const auto callback = SeparateWindowFactory(controller, peer, type); + const auto callback = SeparateWindowFactory(window, peer, rootId, type); if (!callback) { return; } @@ -224,16 +228,17 @@ object_ptr InnerWidget::setupSharedMedia( auto addMediaButton = [&]( MediaType type, const style::icon &icon) { + const auto topicRootId = _topic ? _topic->rootId() : 0; auto result = Media::AddButton( content, _controller, _peer, - _topic ? _topic->rootId() : 0, + topicRootId, _migrated, type, tracker); - if (const auto window = _controller->parentController(); !_topic) { - AddContextMenu(result, window, _peer, type); + if (const auto window = _controller->parentController()) { + AddContextMenu(result, window, _peer, topicRootId, type); } object_ptr( result, diff --git a/Telegram/SourceFiles/window/window_separate_id.cpp b/Telegram/SourceFiles/window/window_separate_id.cpp index f46d4bce4..2b8896896 100644 --- a/Telegram/SourceFiles/window/window_separate_id.cpp +++ b/Telegram/SourceFiles/window/window_separate_id.cpp @@ -44,11 +44,12 @@ SeparateId::SeparateId(not_null peer) : SeparateId(SeparateType::Chat, peer->owner().history(peer)) { } -SeparateId::SeparateId(SeparateSharedMediaType type, not_null peer) +SeparateId::SeparateId(SeparateSharedMedia data) : type(SeparateType::SharedMedia) -, sharedMedia(type) -, account(&peer->session().account()) -, sharedMediaLocalPeer(peer) { +, sharedMedia(data.type) +, account(&data.peer->session().account()) +, sharedMediaDataPeer(data.peer) +, sharedMediaDataTopicRootId(data.topicRootId) { } bool SeparateId::primary() const { @@ -83,8 +84,14 @@ bool SeparateId::hasChatsList() const { PeerData *SeparateId::sharedMediaPeer() const { return (type == SeparateType::SharedMedia) - ? sharedMediaLocalPeer + ? sharedMediaDataPeer : nullptr; } +MsgId SeparateId::sharedMediaTopicRootId() const { + return (type == SeparateType::SharedMedia) + ? sharedMediaDataTopicRootId + : MsgId(); +} + } // namespace Window diff --git a/Telegram/SourceFiles/window/window_separate_id.h b/Telegram/SourceFiles/window/window_separate_id.h index e031e5400..81f417d4f 100644 --- a/Telegram/SourceFiles/window/window_separate_id.h +++ b/Telegram/SourceFiles/window/window_separate_id.h @@ -43,6 +43,12 @@ enum class SeparateSharedMediaType { GIF, }; +struct SeparateSharedMedia { + SeparateSharedMediaType type = SeparateSharedMediaType::None; + not_null peer; + MsgId topicRootId = MsgId(); +}; + struct SeparateId { SeparateId(std::nullptr_t); SeparateId(not_null account); @@ -50,13 +56,14 @@ struct SeparateId { SeparateId(SeparateType type, not_null thread); SeparateId(not_null thread); SeparateId(not_null peer); - SeparateId(SeparateSharedMediaType type, not_null peer); + SeparateId(SeparateSharedMedia data); SeparateType type = SeparateType::Primary; SeparateSharedMediaType sharedMedia = SeparateSharedMediaType::None; Main::Account *account = nullptr; Data::Thread *thread = nullptr; // For types except Main and Archive. - PeerData *sharedMediaLocalPeer = nullptr; + PeerData *sharedMediaDataPeer = nullptr; + MsgId sharedMediaDataTopicRootId = MsgId(); [[nodiscard]] bool valid() const { return account != nullptr; @@ -71,6 +78,7 @@ struct SeparateId { [[nodiscard]] Data::Folder *folder() const; [[nodiscard]] Data::SavedSublist *sublist() const; [[nodiscard]] PeerData *sharedMediaPeer() const; + [[nodiscard]] MsgId sharedMediaTopicRootId() const; [[nodiscard]] bool hasChatsList() const; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 6a82b2b49..5562388d2 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1207,8 +1207,18 @@ void SessionNavigation::showByInitialId( : (id.sharedMedia == SeparateSharedMediaType::GIF) ? Storage::SharedMediaType::GIF : Storage::SharedMediaType::Photo; + const auto topicRootId = id.sharedMediaTopicRootId(); + const auto peer = id.sharedMediaPeer(); + const auto topic = topicRootId + ? peer->forumTopicFor(topicRootId) + : nullptr; + if (topicRootId && !topic) { + break; + } showSection( - std::make_shared(id.sharedMediaPeer(), type), + topicRootId + ? std::make_shared(topic, type) + : std::make_shared(peer, type), instant); parent->widget()->setMaximumWidth(st::maxWidthSharedMediaWindow); break; From a676138745e7824b63ec8cdd29fe9d31c93ae55c Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2025 12:16:31 +0300 Subject: [PATCH 07/95] Added ability to open shared media in window with Ctrl+Click. --- .../info/media/info_media_buttons.h | 8 ++++++- .../info/media/info_media_inner_widget.cpp | 3 ++- .../profile/info_profile_inner_widget.cpp | 23 ++++++++++--------- .../info/saved/info_saved_sublists_widget.cpp | 3 ++- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.h b/Telegram/SourceFiles/info/media/info_media_buttons.h index 363a27953..7d894be0b 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.h +++ b/Telegram/SourceFiles/info/media/info_media_buttons.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include #include "lang/lang_keys.h" +#include "base/qt/qt_key_modifiers.h" #include "data/data_saved_messages.h" #include "data/data_session.h" #include "data/data_stories_ids.h" @@ -90,7 +91,8 @@ inline auto AddButton( MsgId topicRootId, PeerData *migrated, Type type, - Ui::MultiSlideTracker &tracker) { + Ui::MultiSlideTracker &tracker, + Fn openInWindow) { auto result = AddCountedButton( parent, Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), @@ -100,6 +102,10 @@ inline auto AddButton( if (mouse == Qt::RightButton) { return; } + if (openInWindow + && (base::IsCtrlPressed() || mouse == Qt::MiddleButton)) { + return openInWindow(); + } const auto topic = topicRootId ? peer->forumTopicFor(topicRootId) : nullptr; diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp index eed93256b..f0afc716d 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp @@ -92,7 +92,8 @@ void InnerWidget::createTypeButtons() { topicRootId, migrated, buttonType, - tracker); + tracker, + nullptr); object_ptr( result, icon, diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 5ef8bfd32..b4eefed8c 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -93,12 +93,8 @@ Fn SeparateWindowFactory( void AddContextMenu( not_null button, - not_null window, - not_null peer, - MsgId rootId, - Storage::SharedMediaType type) { - const auto callback = SeparateWindowFactory(window, peer, rootId, type); - if (!callback) { + Fn openInWindow) { + if (!openInWindow) { return; } button->setAcceptBoth(); @@ -116,7 +112,7 @@ void AddContextMenu( state->menu->addAction(tr::lng_context_new_window(tr::now), [=] { base::call_delayed( st::popupMenuWithIcons.showDuration, - crl::guard(button, callback)); + crl::guard(button, openInWindow)); }, &st::menuIconNewWindow); state->menu->popup(QCursor::pos()); }); @@ -229,6 +225,12 @@ object_ptr InnerWidget::setupSharedMedia( MediaType type, const style::icon &icon) { const auto topicRootId = _topic ? _topic->rootId() : 0; + const auto window = _controller->parentController(); + const auto openInWindow = SeparateWindowFactory( + window, + _peer, + topicRootId, + type); auto result = Media::AddButton( content, _controller, @@ -236,10 +238,9 @@ object_ptr InnerWidget::setupSharedMedia( topicRootId, _migrated, type, - tracker); - if (const auto window = _controller->parentController()) { - AddContextMenu(result, window, _peer, topicRootId, type); - } + tracker, + openInWindow); + AddContextMenu(result, openInWindow); object_ptr( result, icon, diff --git a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp index 3a3ff46ad..b0b07b961 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp @@ -109,7 +109,8 @@ void SublistsWidget::setupOtherTypes() { MsgId(), // topicRootId nullptr, // migrated buttonType, - tracker); + tracker, + nullptr); object_ptr( result, icon, From ef9f7ab27ad398c10336c60678cc6cfb7b056977 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2025 12:32:22 +0300 Subject: [PATCH 08/95] Moved process of separated window for shared media to correspond file. --- Telegram/CMakeLists.txt | 1 + .../info/media/info_media_buttons.cpp | 87 +++++++++++++++ .../info/media/info_media_buttons.h | 19 +++- .../info/media/info_media_inner_widget.cpp | 3 +- .../profile/info_profile_inner_widget.cpp | 103 +----------------- .../info/saved/info_saved_sublists_widget.cpp | 3 +- 6 files changed, 109 insertions(+), 107 deletions(-) create mode 100644 Telegram/SourceFiles/info/media/info_media_buttons.cpp diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index b2298db22..47081bf7a 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -959,6 +959,7 @@ PRIVATE info/global_media/info_global_media_inner_widget.h info/global_media/info_global_media_provider.cpp info/global_media/info_global_media_provider.h + info/media/info_media_buttons.cpp info/media/info_media_buttons.h info/media/info_media_common.cpp info/media/info_media_common.h diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.cpp b/Telegram/SourceFiles/info/media/info_media_buttons.cpp new file mode 100644 index 000000000..92dd44e16 --- /dev/null +++ b/Telegram/SourceFiles/info/media/info_media_buttons.cpp @@ -0,0 +1,87 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "info/media/info_media_buttons.h" + + +#include "base/call_delayed.h" +#include "ui/widgets/popup_menu.h" +#include "window/window_separate_id.h" +#include "styles/style_menu_icons.h" + +namespace Info { +namespace Media { +namespace { + +Window::SeparateSharedMediaType ToSeparateType( + Storage::SharedMediaType type) { + using Type = Storage::SharedMediaType; + using SeparatedType = Window::SeparateSharedMediaType; + return (type == Type::Photo) + ? SeparatedType::Photos + : (type == Type::Video) + ? SeparatedType::Videos + : (type == Type::File) + ? SeparatedType::Files + : (type == Type::MusicFile) + ? SeparatedType::Audio + : (type == Type::Link) + ? SeparatedType::Links + : (type == Type::RoundVoiceFile) + ? SeparatedType::Voices + : (type == Type::GIF) + ? SeparatedType::GIF + : SeparatedType::None; +} + +} // namespace + +Fn SeparateWindowFactory( + not_null controller, + not_null peer, + MsgId topicRootId, + Storage::SharedMediaType type) { + const auto separateType = ToSeparateType(type); + if (separateType == Window::SeparateSharedMediaType::None) { + return nullptr; + } + return [=] { + controller->showInNewWindow({ + Window::SeparateSharedMedia(separateType, peer, topicRootId), + }); + }; +} + +void AddContextMenuToButton( + not_null button, + Fn openInWindow) { + if (!openInWindow) { + return; + } + button->setAcceptBoth(); + struct State final { + base::unique_qptr menu; + }; + const auto state = button->lifetime().make_state(); + button->addClickHandler([=](Qt::MouseButton mouse) { + if (mouse != Qt::RightButton) { + return; + } + state->menu = base::make_unique_q( + button.get(), + st::popupMenuWithIcons); + state->menu->addAction(tr::lng_context_new_window(tr::now), [=] { + base::call_delayed( + st::popupMenuWithIcons.showDuration, + crl::guard(button, openInWindow)); + }, &st::menuIconNewWindow); + state->menu->popup(QCursor::pos()); + }); +} + +} // namespace Media +} // namespace Info diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.h b/Telegram/SourceFiles/info/media/info_media_buttons.h index 7d894be0b..7023868d6 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.h +++ b/Telegram/SourceFiles/info/media/info_media_buttons.h @@ -84,6 +84,16 @@ inline auto AddCountedButton( return button; }; +Fn SeparateWindowFactory( + not_null controller, + not_null peer, + MsgId topicRootId, + Type type); + +void AddContextMenuToButton( + not_null button, + Fn openInWindow); + inline auto AddButton( Ui::VerticalLayout *parent, not_null navigation, @@ -91,13 +101,18 @@ inline auto AddButton( MsgId topicRootId, PeerData *migrated, Type type, - Ui::MultiSlideTracker &tracker, - Fn openInWindow) { + Ui::MultiSlideTracker &tracker) { auto result = AddCountedButton( parent, Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), MediaText(type), tracker)->entity(); + const auto openInWindow = SeparateWindowFactory( + navigation->parentController(), + peer, + topicRootId, + type); + AddContextMenuToButton(result, openInWindow); result->addClickHandler([=](Qt::MouseButton mouse) { if (mouse == Qt::RightButton) { return; diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp index f0afc716d..eed93256b 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp @@ -92,8 +92,7 @@ void InnerWidget::createTypeButtons() { topicRootId, migrated, buttonType, - tracker, - nullptr); + tracker); object_ptr( result, icon, diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index b4eefed8c..3171fa194 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -7,119 +7,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/profile/info_profile_inner_widget.h" -#include "base/call_delayed.h" -#include "info/info_memento.h" -#include "info/info_controller.h" #include "info/profile/info_profile_widget.h" -#include "info/profile/info_profile_text.h" -#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_cover.h" #include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_members.h" #include "info/profile/info_profile_actions.h" #include "info/media/info_media_buttons.h" -#include "boxes/abstract_box.h" -#include "boxes/add_contact_box.h" #include "data/data_changes.h" #include "data/data_forum_topic.h" #include "data/data_photo.h" #include "data/data_file_origin.h" -#include "ui/boxes/confirm_box.h" -#include "mainwidget.h" #include "main/main_session.h" #include "apiwrap.h" #include "api/api_peer_photo.h" -#include "window/main_window.h" -#include "window/window_separate_id.h" -#include "window/window_session_controller.h" -#include "storage/storage_shared_media.h" #include "lang/lang_keys.h" #include "ui/widgets/buttons.h" #include "ui/widgets/checkbox.h" -#include "ui/widgets/popup_menu.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" -#include "ui/widgets/box_content_divider.h" -#include "ui/wrap/slide_wrap.h" -#include "ui/wrap/vertical_layout.h" #include "ui/ui_utility.h" -#include "data/data_channel.h" -#include "data/data_shared_media.h" -#include "styles/style_info.h" -#include "styles/style_boxes.h" -#include "styles/style_menu_icons.h" namespace Info { namespace Profile { -namespace { - -Window::SeparateSharedMediaType ToSeparateType( - Storage::SharedMediaType type) { - using Type = Storage::SharedMediaType; - using SeparatedType = Window::SeparateSharedMediaType; - return (type == Type::Photo) - ? SeparatedType::Photos - : (type == Type::Video) - ? SeparatedType::Videos - : (type == Type::File) - ? SeparatedType::Files - : (type == Type::MusicFile) - ? SeparatedType::Audio - : (type == Type::Link) - ? SeparatedType::Links - : (type == Type::RoundVoiceFile) - ? SeparatedType::Voices - : (type == Type::GIF) - ? SeparatedType::GIF - : SeparatedType::None; -} - -Fn SeparateWindowFactory( - not_null controller, - not_null peer, - MsgId topicRootId, - Storage::SharedMediaType type) { - const auto separateType = ToSeparateType(type); - if (separateType == Window::SeparateSharedMediaType::None) { - return nullptr; - } - return [=] { - controller->showInNewWindow({ - Window::SeparateSharedMedia(separateType, peer, topicRootId), - }); - }; -} - -void AddContextMenu( - not_null button, - Fn openInWindow) { - if (!openInWindow) { - return; - } - button->setAcceptBoth(); - struct State final { - base::unique_qptr menu; - }; - const auto state = button->lifetime().make_state(); - button->addClickHandler([=](Qt::MouseButton mouse) { - if (mouse != Qt::RightButton) { - return; - } - state->menu = base::make_unique_q( - button.get(), - st::popupMenuWithIcons); - state->menu->addAction(tr::lng_context_new_window(tr::now), [=] { - base::call_delayed( - st::popupMenuWithIcons.showDuration, - crl::guard(button, openInWindow)); - }, &st::menuIconNewWindow); - state->menu->popup(QCursor::pos()); - }); -} - -} // namespace - InnerWidget::InnerWidget( QWidget *parent, not_null controller, @@ -224,23 +134,14 @@ object_ptr InnerWidget::setupSharedMedia( auto addMediaButton = [&]( MediaType type, const style::icon &icon) { - const auto topicRootId = _topic ? _topic->rootId() : 0; - const auto window = _controller->parentController(); - const auto openInWindow = SeparateWindowFactory( - window, - _peer, - topicRootId, - type); auto result = Media::AddButton( content, _controller, _peer, - topicRootId, + _topic ? _topic->rootId() : 0, _migrated, type, - tracker, - openInWindow); - AddContextMenu(result, openInWindow); + tracker); object_ptr( result, icon, diff --git a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp index b0b07b961..3a3ff46ad 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp @@ -109,8 +109,7 @@ void SublistsWidget::setupOtherTypes() { MsgId(), // topicRootId nullptr, // migrated buttonType, - tracker, - nullptr); + tracker); object_ptr( result, icon, From 1d8a7f8fd3b0a910ad4ff7bdadc292c402aa8af3 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2025 13:12:18 +0300 Subject: [PATCH 09/95] Removed redundant template from Info::Media::AddCountedButton. --- .../info/media/info_media_buttons.cpp | 239 ++++++++++++++- .../info/media/info_media_buttons.h | 273 ++++-------------- .../info/media/info_media_inner_widget.cpp | 2 + .../profile/info_profile_inner_widget.cpp | 7 + .../info/saved/info_saved_sublists_widget.cpp | 1 + .../stories/info_stories_inner_widget.cpp | 1 + 6 files changed, 294 insertions(+), 229 deletions(-) diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.cpp b/Telegram/SourceFiles/info/media/info_media_buttons.cpp index 92dd44e16..bc0859881 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.cpp +++ b/Telegram/SourceFiles/info/media/info_media_buttons.cpp @@ -7,14 +7,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/media/info_media_buttons.h" - #include "base/call_delayed.h" +#include "base/qt/qt_key_modifiers.h" +#include "data/data_channel.h" +#include "data/data_saved_messages.h" +#include "data/data_session.h" +#include "data/data_stories_ids.h" +#include "data/data_user.h" +#include "history/view/history_view_sublist_section.h" +#include "info/info_controller.h" +#include "info/info_memento.h" +#include "info/profile/info_profile_values.h" +#include "info/stories/info_stories_widget.h" +#include "ui/widgets/buttons.h" #include "ui/widgets/popup_menu.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" #include "window/window_separate_id.h" +#include "window/window_session_controller.h" +#include "styles/style_info.h" #include "styles/style_menu_icons.h" -namespace Info { -namespace Media { +namespace Info::Media { namespace { Window::SeparateSharedMediaType ToSeparateType( @@ -38,8 +52,6 @@ Window::SeparateSharedMediaType ToSeparateType( : SeparatedType::None; } -} // namespace - Fn SeparateWindowFactory( not_null controller, not_null peer, @@ -83,5 +95,218 @@ void AddContextMenuToButton( }); } -} // namespace Media -} // namespace Info +} // namespace + +tr::phrase MediaTextPhrase(Type type) { + switch (type) { + case Type::Photo: return tr::lng_profile_photos; + case Type::GIF: return tr::lng_profile_gifs; + case Type::Video: return tr::lng_profile_videos; + case Type::File: return tr::lng_profile_files; + case Type::MusicFile: return tr::lng_profile_songs; + case Type::Link: return tr::lng_profile_shared_links; + case Type::RoundVoiceFile: return tr::lng_profile_audios; + } + Unexpected("Type in MediaTextPhrase()"); +}; + +Fn MediaText(Type type) { + return [phrase = MediaTextPhrase(type)](int count) { + return phrase(tr::now, lt_count, count); + }; +} + +not_null*> AddCountedButton( + Ui::VerticalLayout *parent, + rpl::producer &&count, + Fn &&textFromCount, + Ui::MultiSlideTracker &tracker) { + using namespace ::Settings; + auto forked = std::move(count) + | start_spawning(parent->lifetime()); + auto text = rpl::duplicate( + forked + ) | rpl::map([textFromCount](int count) { + return (count > 0) + ? textFromCount(count) + : QString(); + }); + auto button = parent->add(object_ptr>( + parent, + object_ptr( + parent, + std::move(text), + st::infoSharedMediaButton)) + )->setDuration( + st::infoSlideDuration + )->toggleOn( + rpl::duplicate(forked) | rpl::map(rpl::mappers::_1 > 0) + ); + tracker.track(button); + return button; +}; + +Fn SeparateWindowFactory( + not_null controller, + not_null peer, + MsgId topicRootId, + Type type); + +void AddContextMenuToButton( + not_null button, + Fn openInWindow); + +not_null AddButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + MsgId topicRootId, + PeerData *migrated, + Type type, + Ui::MultiSlideTracker &tracker) { + auto result = AddCountedButton( + parent, + Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), + MediaText(type), + tracker)->entity(); + const auto openInWindow = SeparateWindowFactory( + navigation->parentController(), + peer, + topicRootId, + type); + AddContextMenuToButton(result, openInWindow); + result->addClickHandler([=](Qt::MouseButton mouse) { + if (mouse == Qt::RightButton) { + return; + } + if (openInWindow + && (base::IsCtrlPressed() || mouse == Qt::MiddleButton)) { + return openInWindow(); + } + const auto topic = topicRootId + ? peer->forumTopicFor(topicRootId) + : nullptr; + if (topicRootId && !topic) { + return; + } + navigation->showSection(topicRootId + ? std::make_shared(topic, Section(type)) + : std::make_shared(peer, Section(type))); + }); + return result; +}; + +not_null AddCommonGroupsButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null user, + Ui::MultiSlideTracker &tracker) { + auto result = AddCountedButton( + parent, + Profile::CommonGroupsCountValue(user), + [](int count) { + return tr::lng_profile_common_groups(tr::now, lt_count, count); + }, + tracker)->entity(); + result->addClickHandler([=] { + navigation->showSection( + std::make_shared( + user, + Section::Type::CommonGroups)); + }); + return result; +} + +not_null AddSimilarPeersButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + Ui::MultiSlideTracker &tracker) { + auto result = AddCountedButton( + parent, + Profile::SimilarPeersCountValue(peer), + [=](int count) { + return peer->isBroadcast() + ? tr::lng_profile_similar_channels(tr::now, lt_count, count) + : tr::lng_profile_similar_bots(tr::now, lt_count, count); + }, + tracker)->entity(); + result->addClickHandler([=] { + navigation->showSection( + std::make_shared( + peer, + Section::Type::SimilarPeers)); + }); + return result; +} + +not_null AddStoriesButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + Ui::MultiSlideTracker &tracker) { + auto count = rpl::single(0) | rpl::then(Data::SavedStoriesIds( + peer, + ServerMaxStoryId - 1, + 0 + ) | rpl::map([](const Data::StoriesIdsSlice &slice) { + return slice.fullCount().value_or(0); + })); + const auto phrase = peer->isChannel() ? (+[](int count) { + return tr::lng_profile_posts(tr::now, lt_count, count); + }) : (+[](int count) { + return tr::lng_profile_saved_stories(tr::now, lt_count, count); + }); + auto result = AddCountedButton( + parent, + std::move(count), + phrase, + tracker)->entity(); + result->addClickHandler([=] { + navigation->showSection(Info::Stories::Make(peer)); + }); + return result; +} + +not_null AddSavedSublistButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + Ui::MultiSlideTracker &tracker) { + auto result = AddCountedButton( + parent, + Profile::SavedSublistCountValue(peer), + [](int count) { + return tr::lng_profile_saved_messages(tr::now, lt_count, count); + }, + tracker)->entity(); + result->addClickHandler([=] { + navigation->showSection( + std::make_shared( + peer->owner().savedMessages().sublist(peer))); + }); + return result; +} + +not_null AddPeerGiftsButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + Ui::MultiSlideTracker &tracker) { + auto result = AddCountedButton( + parent, + Profile::PeerGiftsCountValue(peer), + [](int count) { + return tr::lng_profile_peer_gifts(tr::now, lt_count, count); + }, + tracker)->entity(); + result->addClickHandler([=] { + navigation->showSection( + std::make_shared( + peer, + Section::Type::PeerGifts)); + }); + return result; +} + +} // namespace Info::Media diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.h b/Telegram/SourceFiles/info/media/info_media_buttons.h index 7023868d6..e8927c097 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.h +++ b/Telegram/SourceFiles/info/media/info_media_buttons.h @@ -7,244 +7,73 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include -#include #include "lang/lang_keys.h" -#include "base/qt/qt_key_modifiers.h" -#include "data/data_saved_messages.h" -#include "data/data_session.h" -#include "data/data_stories_ids.h" #include "storage/storage_shared_media.h" -#include "history/view/history_view_sublist_section.h" -#include "info/info_memento.h" -#include "info/info_controller.h" -#include "info/profile/info_profile_values.h" -#include "info/stories/info_stories_widget.h" -#include "ui/wrap/slide_wrap.h" -#include "ui/wrap/vertical_layout.h" -#include "ui/widgets/buttons.h" -#include "window/window_session_controller.h" -#include "data/data_channel.h" -#include "data/data_user.h" -#include "styles/style_info.h" + +namespace Ui { +class AbstractButton; +class MultiSlideTracker; +class SettingsButton; +class VerticalLayout; +template +class SlideWrap; +} // namespace Ui + +namespace Window { +class SessionNavigation; +} // namespace Window namespace Info::Media { using Type = Storage::SharedMediaType; -inline tr::phrase MediaTextPhrase(Type type) { - switch (type) { - case Type::Photo: return tr::lng_profile_photos; - case Type::GIF: return tr::lng_profile_gifs; - case Type::Video: return tr::lng_profile_videos; - case Type::File: return tr::lng_profile_files; - case Type::MusicFile: return tr::lng_profile_songs; - case Type::Link: return tr::lng_profile_shared_links; - case Type::RoundVoiceFile: return tr::lng_profile_audios; - } - Unexpected("Type in MediaTextPhrase()"); -}; +[[nodiscard]] tr::phrase MediaTextPhrase(Type type); -inline auto MediaText(Type type) { - return [phrase = MediaTextPhrase(type)](int count) { - return phrase(tr::now, lt_count, count); - }; -} +[[nodiscard]] Fn MediaText(Type type); -template -inline auto AddCountedButton( - Ui::VerticalLayout *parent, - Count &&count, - Text &&textFromCount, - Ui::MultiSlideTracker &tracker) { - using namespace rpl::mappers; +[[nodiscard]] not_null*> AddCountedButton( + Ui::VerticalLayout *parent, + rpl::producer &&count, + Fn &&textFromCount, + Ui::MultiSlideTracker &tracker); - using namespace ::Settings; - auto forked = std::move(count) - | start_spawning(parent->lifetime()); - auto text = rpl::duplicate( - forked - ) | rpl::map([textFromCount](int count) { - return (count > 0) - ? textFromCount(count) - : QString(); - }); - auto button = parent->add(object_ptr>( - parent, - object_ptr( - parent, - std::move(text), - st::infoSharedMediaButton)) - )->setDuration( - st::infoSlideDuration - )->toggleOn( - rpl::duplicate(forked) | rpl::map(_1 > 0) - ); - tracker.track(button); - return button; -}; - -Fn SeparateWindowFactory( - not_null controller, +[[nodiscard]] not_null AddButton( + Ui::VerticalLayout *parent, + not_null navigation, not_null peer, MsgId topicRootId, - Type type); + PeerData *migrated, + Type type, + Ui::MultiSlideTracker &tracker); -void AddContextMenuToButton( - not_null button, - Fn openInWindow); +[[nodiscard]] not_null AddCommonGroupsButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null user, + Ui::MultiSlideTracker &tracker); -inline auto AddButton( - Ui::VerticalLayout *parent, - not_null navigation, - not_null peer, - MsgId topicRootId, - PeerData *migrated, - Type type, - Ui::MultiSlideTracker &tracker) { - auto result = AddCountedButton( - parent, - Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), - MediaText(type), - tracker)->entity(); - const auto openInWindow = SeparateWindowFactory( - navigation->parentController(), - peer, - topicRootId, - type); - AddContextMenuToButton(result, openInWindow); - result->addClickHandler([=](Qt::MouseButton mouse) { - if (mouse == Qt::RightButton) { - return; - } - if (openInWindow - && (base::IsCtrlPressed() || mouse == Qt::MiddleButton)) { - return openInWindow(); - } - const auto topic = topicRootId - ? peer->forumTopicFor(topicRootId) - : nullptr; - if (topicRootId && !topic) { - return; - } - navigation->showSection(topicRootId - ? std::make_shared(topic, Section(type)) - : std::make_shared(peer, Section(type))); - }); - return result; -}; +[[nodiscard]] not_null AddSimilarPeersButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + Ui::MultiSlideTracker &tracker); -inline auto AddCommonGroupsButton( - Ui::VerticalLayout *parent, - not_null navigation, - not_null user, - Ui::MultiSlideTracker &tracker) { - auto result = AddCountedButton( - parent, - Profile::CommonGroupsCountValue(user), - [](int count) { - return tr::lng_profile_common_groups(tr::now, lt_count, count); - }, - tracker)->entity(); - result->addClickHandler([=] { - navigation->showSection( - std::make_shared( - user, - Section::Type::CommonGroups)); - }); - return result; -} +[[nodiscard]] not_null AddStoriesButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + Ui::MultiSlideTracker &tracker); -inline auto AddSimilarPeersButton( - Ui::VerticalLayout *parent, - not_null navigation, - not_null peer, - Ui::MultiSlideTracker &tracker) { - auto result = AddCountedButton( - parent, - Profile::SimilarPeersCountValue(peer), - [=](int count) { - return peer->isBroadcast() - ? tr::lng_profile_similar_channels(tr::now, lt_count, count) - : tr::lng_profile_similar_bots(tr::now, lt_count, count); - }, - tracker)->entity(); - result->addClickHandler([=] { - navigation->showSection( - std::make_shared( - peer, - Section::Type::SimilarPeers)); - }); - return result; -} +[[nodiscard]] not_null AddSavedSublistButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + Ui::MultiSlideTracker &tracker); -inline auto AddStoriesButton( - Ui::VerticalLayout *parent, - not_null navigation, - not_null peer, - Ui::MultiSlideTracker &tracker) { - auto count = rpl::single(0) | rpl::then(Data::SavedStoriesIds( - peer, - ServerMaxStoryId - 1, - 0 - ) | rpl::map([](const Data::StoriesIdsSlice &slice) { - return slice.fullCount().value_or(0); - })); - const auto phrase = peer->isChannel() ? (+[](int count) { - return tr::lng_profile_posts(tr::now, lt_count, count); - }) : (+[](int count) { - return tr::lng_profile_saved_stories(tr::now, lt_count, count); - }); - auto result = AddCountedButton( - parent, - std::move(count), - phrase, - tracker)->entity(); - result->addClickHandler([=] { - navigation->showSection(Info::Stories::Make(peer)); - }); - return result; -} - -inline auto AddSavedSublistButton( - Ui::VerticalLayout *parent, - not_null navigation, - not_null peer, - Ui::MultiSlideTracker &tracker) { - auto result = AddCountedButton( - parent, - Profile::SavedSublistCountValue(peer), - [](int count) { - return tr::lng_profile_saved_messages(tr::now, lt_count, count); - }, - tracker)->entity(); - result->addClickHandler([=] { - navigation->showSection( - std::make_shared( - peer->owner().savedMessages().sublist(peer))); - }); - return result; -} - -inline auto AddPeerGiftsButton( - Ui::VerticalLayout *parent, - not_null navigation, - not_null peer, - Ui::MultiSlideTracker &tracker) { - auto result = AddCountedButton( - parent, - Profile::PeerGiftsCountValue(peer), - [](int count) { - return tr::lng_profile_peer_gifts(tr::now, lt_count, count); - }, - tracker)->entity(); - result->addClickHandler([=] { - navigation->showSection( - std::make_shared( - peer, - Section::Type::PeerGifts)); - }); - return result; -} +[[nodiscard]] not_null AddPeerGiftsButton( + Ui::VerticalLayout *parent, + not_null navigation, + not_null peer, + Ui::MultiSlideTracker &tracker); } // namespace Info::Media diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp index eed93256b..6f2bedac4 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp @@ -15,10 +15,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/profile/info_profile_icon.h" #include "info/info_controller.h" #include "data/data_forum_topic.h" +#include "data/data_peer.h" #include "ui/widgets/discrete_sliders.h" #include "ui/widgets/shadow.h" #include "ui/widgets/buttons.h" #include "ui/widgets/box_content_divider.h" +#include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" #include "ui/search_field_controller.h" #include "styles/style_info.h" diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 3171fa194..42594dd01 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/profile/info_profile_inner_widget.h" +#include "info/info_controller.h" #include "info/profile/info_profile_widget.h" #include "info/profile/info_profile_cover.h" #include "info/profile/info_profile_icon.h" @@ -14,9 +15,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/profile/info_profile_actions.h" #include "info/media/info_media_buttons.h" #include "data/data_changes.h" +#include "data/data_channel.h" #include "data/data_forum_topic.h" +#include "data/data_peer.h" #include "data/data_photo.h" #include "data/data_file_origin.h" +#include "data/data_user.h" #include "main/main_session.h" #include "apiwrap.h" #include "api/api_peer_photo.h" @@ -25,7 +29,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/checkbox.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/wrap/slide_wrap.h" #include "ui/ui_utility.h" +#include "styles/style_info.h" namespace Info { namespace Profile { diff --git a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp index 3a3ff46ad..9a070889a 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "lang/lang_keys.h" #include "ui/widgets/box_content_divider.h" +#include "ui/widgets/buttons.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" #include "ui/ui_utility.h" diff --git a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp index c83795cab..d0ab12cb5 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp +++ b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/media/info_media_list_widget.h" #include "info/profile/info_profile_actions.h" #include "info/profile/info_profile_icon.h" +#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_widget.h" #include "info/stories/info_stories_widget.h" #include "info/info_controller.h" From f89bac778187a38a11741dabed603154f09ba57d Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2025 13:25:53 +0300 Subject: [PATCH 10/95] Improved handle of existing separated windows for shared media. --- .../info/media/info_media_buttons.cpp | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.cpp b/Telegram/SourceFiles/info/media/info_media_buttons.cpp index bc0859881..12d7827f4 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.cpp +++ b/Telegram/SourceFiles/info/media/info_media_buttons.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/call_delayed.h" #include "base/qt/qt_key_modifiers.h" +#include "core/application.h" #include "data/data_channel.h" #include "data/data_saved_messages.h" #include "data/data_session.h" @@ -31,7 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Info::Media { namespace { -Window::SeparateSharedMediaType ToSeparateType( +[[nodiscard]] Window::SeparateSharedMediaType ToSeparateType( Storage::SharedMediaType type) { using Type = Storage::SharedMediaType; using SeparatedType = Window::SeparateSharedMediaType; @@ -52,20 +53,18 @@ Window::SeparateSharedMediaType ToSeparateType( : SeparatedType::None; } -Fn SeparateWindowFactory( - not_null controller, +[[nodiscard]] Window::SeparateId SeparateId( not_null peer, MsgId topicRootId, Storage::SharedMediaType type) { + if (peer->isSelf()) { + return { nullptr }; + } const auto separateType = ToSeparateType(type); if (separateType == Window::SeparateSharedMediaType::None) { - return nullptr; + return { nullptr }; } - return [=] { - controller->showInNewWindow({ - Window::SeparateSharedMedia(separateType, peer, topicRootId), - }); - }; + return { Window::SeparateSharedMedia(separateType, peer, topicRootId) }; } void AddContextMenuToButton( @@ -146,16 +145,6 @@ not_null*> AddCountedButton( return button; }; -Fn SeparateWindowFactory( - not_null controller, - not_null peer, - MsgId topicRootId, - Type type); - -void AddContextMenuToButton( - not_null button, - Fn openInWindow); - not_null AddButton( Ui::VerticalLayout *parent, not_null navigation, @@ -169,11 +158,10 @@ not_null AddButton( Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), MediaText(type), tracker)->entity(); - const auto openInWindow = SeparateWindowFactory( - navigation->parentController(), - peer, - topicRootId, - type); + const auto separateId = SeparateId(peer, topicRootId, type); + const auto openInWindow = separateId + ? [=] { navigation->parentController()->showInNewWindow(separateId); } + : Fn(nullptr); AddContextMenuToButton(result, openInWindow); result->addClickHandler([=](Qt::MouseButton mouse) { if (mouse == Qt::RightButton) { @@ -189,9 +177,14 @@ not_null AddButton( if (topicRootId && !topic) { return; } - navigation->showSection(topicRootId - ? std::make_shared(topic, Section(type)) - : std::make_shared(peer, Section(type))); + const auto separateId = SeparateId(peer, topicRootId, type); + if (Core::App().separateWindowFor(separateId) && openInWindow) { + openInWindow(); + } else { + navigation->showSection(topicRootId + ? std::make_shared(topic, Section(type)) + : std::make_shared(peer, Section(type))); + } }); return result; }; From 97c4e79e96d4ae98c11a02d6cd4b59678ef7ddf4 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 30 Jan 2025 13:57:45 +0300 Subject: [PATCH 11/95] Improved title for separated windows with shared media. --- Telegram/SourceFiles/window/main_window.cpp | 49 ++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index c37d41228..f81a5784a 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -87,7 +87,47 @@ base::options::toggle OptionDisableTouchbar({ .restartRequired = true, }); -} // namespace. +[[nodiscard]] QString TitleFromSeparateId( + const Core::WindowTitleContent &settings, + const SeparateId &id) { + if (id.sharedMedia == SeparateSharedMediaType::None + || !id.sharedMediaPeer()) { + return QString(); + } + const auto result = (id.sharedMedia == SeparateSharedMediaType::Photos) + ? tr::lng_media_type_photos(tr::now) + : (id.sharedMedia == SeparateSharedMediaType::Videos) + ? tr::lng_media_type_videos(tr::now) + : (id.sharedMedia == SeparateSharedMediaType::Files) + ? tr::lng_media_type_files(tr::now) + : (id.sharedMedia == SeparateSharedMediaType::Audio) + ? tr::lng_media_type_songs(tr::now) + : (id.sharedMedia == SeparateSharedMediaType::Links) + ? tr::lng_media_type_links(tr::now) + : (id.sharedMedia == SeparateSharedMediaType::GIF) + ? tr::lng_media_type_gifs(tr::now) + : (id.sharedMedia == SeparateSharedMediaType::Voices) + ? tr::lng_media_type_audios(tr::now) + : QString(); + + if (settings.hideChatName) { + return result; + } + const auto peer = id.sharedMediaPeer(); + const auto topicRootId = id.sharedMediaTopicRootId(); + const auto topic = topicRootId + ? peer->forumTopicFor(topicRootId) + : nullptr; + const auto name = topic + ? topic->title() + : peer->isSelf() + ? tr::lng_saved_messages(tr::now) + : peer->name(); + const auto wrapped = st::wrap_rtl(name); + return name + u" @ "_q + result; +} + +} // namespace const char kOptionNewWindowsSizeAsFirst[] = "new-windows-size-as-first"; const char kOptionDisableTouchbar[] = "touchbar-disabled"; @@ -862,6 +902,13 @@ void MainWindow::updateTitle() { && Core::App().domain().accountsAuthedCount() > 1) ? st::wrap_rtl(session->authedName()) : QString(); + const auto separateIdTitle = session + ? TitleFromSeparateId(settings, session->windowId()) + : QString(); + if (!separateIdTitle.isEmpty()) { + setTitle(separateIdTitle); + return; + } const auto key = (session && !settings.hideChatName) ? session->activeChatCurrent() : Dialogs::Key(); From 296df113e367aaabb2170434f919731803f24f19 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Fri, 31 Jan 2025 01:05:23 +0000 Subject: [PATCH 12/95] Implement getting geolocation via geoclue/geocode-glib on Linux --- .../linux/current_geo_location_linux.cpp | 179 +++++++++++++++++- 1 file changed, 177 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/current_geo_location_linux.cpp b/Telegram/SourceFiles/platform/linux/current_geo_location_linux.cpp index f87c343d3..7015af739 100644 --- a/Telegram/SourceFiles/platform/linux/current_geo_location_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/current_geo_location_linux.cpp @@ -8,17 +8,192 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/linux/current_geo_location_linux.h" #include "core/current_geo_location.h" +#include "base/platform/linux/base_linux_library.h" + +#include namespace Platform { +namespace { + +typedef struct _GClueSimple GClueSimple; +typedef struct _GClueLocation GClueLocation; +typedef struct _GeocodeLocation GeocodeLocation; +typedef struct _GeocodeReverse GeocodeReverse; +typedef struct _GeocodePlace GeocodePlace; + +typedef enum { + GCLUE_ACCURACY_LEVEL_NONE = 0, + GCLUE_ACCURACY_LEVEL_COUNTRY = 1, + GCLUE_ACCURACY_LEVEL_CITY = 4, + GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD = 5, + GCLUE_ACCURACY_LEVEL_STREET = 6, + GCLUE_ACCURACY_LEVEL_EXACT = 8, +} GClueAccuracyLevel; + +void (*gclue_simple_new)( + const char *desktop_id, + GClueAccuracyLevel accuracy_level, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GClueSimple *(*gclue_simple_new_finish)(GAsyncResult *result, GError **error); +GClueLocation *(*gclue_simple_get_location)(GClueSimple *simple); + +gdouble (*gclue_location_get_latitude)(GClueLocation *loc); +gdouble (*gclue_location_get_longitude)(GClueLocation *loc); + +GeocodeLocation *(*geocode_location_new)( + gdouble latitude, + gdouble longitude, + gdouble accuracy); + +GeocodeReverse *(*geocode_reverse_new_for_location)( + GeocodeLocation *location); + +void (*geocode_reverse_resolve_async)( + GeocodeReverse *object, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GeocodePlace *(*geocode_reverse_resolve_finish)( + GeocodeReverse *object, + GAsyncResult *res, + GError **error); + +const char *(*geocode_place_get_street_address)(GeocodePlace *place); +const char *(*geocode_place_get_town)(GeocodePlace *place); +const char *(*geocode_place_get_country)(GeocodePlace *place); + +} // namespace void ResolveCurrentExactLocation(Fn callback) { - callback({}); + static const auto Inited = [] { + const auto lib = base::Platform::LoadLibrary( + "libgeoclue-2.so.0", + RTLD_NODELETE); + return lib + && LOAD_LIBRARY_SYMBOL(lib, gclue_simple_new) + && LOAD_LIBRARY_SYMBOL(lib, gclue_simple_new_finish) + && LOAD_LIBRARY_SYMBOL(lib, gclue_simple_get_location) + && LOAD_LIBRARY_SYMBOL(lib, gclue_location_get_latitude) + && LOAD_LIBRARY_SYMBOL(lib, gclue_location_get_longitude); + }(); + + if (!Inited) { + callback({}); + return; + } + + gclue_simple_new( + QGuiApplication::desktopFileName().toUtf8().constData(), + GCLUE_ACCURACY_LEVEL_EXACT, + nullptr, + GAsyncReadyCallback(+[]( + GObject *object, + GAsyncResult* res, + Fn *callback) { + const auto callbackGuard = gsl::finally([&] { + delete callback; + }); + + const auto simple = gclue_simple_new_finish(res, nullptr); + if (!simple) { + (*callback)({}); + return; + } + + const auto simpleGuard = gsl::finally([&] { + g_object_unref(simple); + }); + + const auto location = gclue_simple_get_location(simple); + + (*callback)({ + .point = { + gclue_location_get_latitude(location), + gclue_location_get_longitude(location), + }, + .accuracy = Core::GeoLocationAccuracy::Exact, + }); + }), + new Fn(callback)); } + void ResolveLocationAddress( const Core::GeoLocation &location, const QString &language, Fn callback) { - callback({}); + static const auto Inited = [] { + const auto lib = base::Platform::LoadLibrary( + "libgeocode-glib-2.so.0", + RTLD_NODELETE) ?: base::Platform::LoadLibrary( + "libgeocode-glib.so.0", + RTLD_NODELETE); + return lib + && LOAD_LIBRARY_SYMBOL(lib, geocode_location_new) + && LOAD_LIBRARY_SYMBOL(lib, geocode_reverse_new_for_location) + && LOAD_LIBRARY_SYMBOL(lib, geocode_reverse_resolve_async) + && LOAD_LIBRARY_SYMBOL(lib, geocode_reverse_resolve_finish) + && LOAD_LIBRARY_SYMBOL(lib, geocode_place_get_street_address) + && LOAD_LIBRARY_SYMBOL(lib, geocode_place_get_town) + && LOAD_LIBRARY_SYMBOL(lib, geocode_place_get_country); + }(); + + if (!Inited) { + callback({}); + return; + } + + geocode_reverse_resolve_async( + geocode_reverse_new_for_location(geocode_location_new( + location.point.x(), + location.point.y(), + -1)), + nullptr, + GAsyncReadyCallback(+[]( + GeocodeReverse *reverse, + GAsyncResult* res, + Fn *callback) { + const auto argsGuard = gsl::finally([&] { + delete callback; + g_object_unref(reverse); + }); + + const auto place = geocode_reverse_resolve_finish( + reverse, + res, + nullptr); + + if (!place) { + (*callback)({}); + return; + } + + const auto placeGuard = gsl::finally([&] { + g_object_unref(place); + }); + + const auto values = { + geocode_place_get_street_address(place), + geocode_place_get_town(place), + geocode_place_get_country(place), + }; + + QStringList checked; + for (const auto &value : values) { + if (value) { + const auto qt = QString::fromUtf8(value); + if (!qt.isEmpty()) { + checked.push_back(qt); + } + } + } + + (*callback)({ .name = checked.join(u", "_q) }); + }), + new Fn(callback)); } } // namespace Platform From a8d23489c4a6b6a5ce0030a35bede9e8f0b6ea21 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 1 Feb 2025 11:33:08 +0400 Subject: [PATCH 13/95] Set up gcc toolset environment manually --- .devcontainer.json | 1 - Telegram/build/docker/centos_env/Dockerfile | 25 +++++---------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/.devcontainer.json b/.devcontainer.json index 27fb3574e..30bff840d 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -20,7 +20,6 @@ "TheQtCompany.qt", "ms-python.python", "ms-azuretools.vscode-docker", - "mkhl.direnv", "eamodio.gitlens" ] } diff --git a/Telegram/build/docker/centos_env/Dockerfile b/Telegram/build/docker/centos_env/Dockerfile index b9414dcc7..d8cd53512 100644 --- a/Telegram/build/docker/centos_env/Dockerfile +++ b/Telegram/build/docker/centos_env/Dockerfile @@ -11,11 +11,10 @@ FROM rockylinux:8 AS builder ENV LANG C.UTF-8 -ENV LIBRARY_PATH /usr/local/lib64:/usr/local/lib:/lib64:/lib:/usr/lib64:/usr/lib +ENV PATH /opt/rh/{{ TOOLSET }}/root/usr/bin:$PATH +ENV LIBRARY_PATH /opt/rh/{{ TOOLSET }}/root/usr/lib64:/opt/rh/{{ TOOLSET }}/root/usr/lib:/usr/local/lib64:/usr/local/lib:/lib64:/lib:/usr/lib64:/usr/lib ENV LD_LIBRARY_PATH $LIBRARY_PATH -ENV PKG_CONFIG_PATH /usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig - -RUN adduser user +ENV PKG_CONFIG_PATH /opt/rh/{{ TOOLSET }}/root/usr/lib64/pkgconfig:/opt/rh/{{ TOOLSET }}/root/usr/lib/pkgconfig:/usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig RUN dnf -y install epel-release \ && dnf config-manager --set-enabled powertools \ @@ -30,22 +29,11 @@ RUN dnf -y install epel-release \ glib2-devel at-spi2-core-devel gtk3-devel boost1.78-devel fmt-devel \ && dnf clean all -SHELL [ "bash", "-c", ". /opt/rh/{{ TOOLSET }}/enable; exec bash -c \"$@\"", "-s"] +RUN python3 -m pip install meson ninja +RUN echo set debuginfod enabled on > /opt/rh/{{ TOOLSET }}/root/etc/gdbinit.d/00-debuginfod.gdb +RUN adduser user WORKDIR {{ LibrariesPath }} - -RUN python3 -m pip install meson ninja - -RUN curl -sSL https://github.com/direnv/direnv/releases/download/v2.35.0/direnv.linux-amd64 > /usr/local/bin/direnv \ - && chmod +x /usr/local/bin/direnv \ - && echo 'eval "$(direnv hook bash)"' >> /home/user/.bashrc \ - && mkdir -p /home/user/.config/direnv \ - && echo . /opt/rh/{{ TOOLSET }}/enable > /home/user/.config/direnv/direnvrc \ - && touch /.envrc \ - && su -c "direnv allow /" user - -RUN echo set debuginfod enabled on > /opt/rh/{{ TOOLSET }}/root/etc/gdbinit.d/00-debuginfod.gdb - ENV AR gcc-ar ENV RANLIB gcc-ranlib ENV NM gcc-nm @@ -886,5 +874,4 @@ ENV BOOST_LIBRARYDIR /usr/lib64/boost1.78 USER user VOLUME [ "/usr/src/tdesktop" ] -ENTRYPOINT [ "scl", "enable", "{{ TOOLSET }}", "--" ] CMD [ "/usr/src/tdesktop/Telegram/build/docker/centos_env/build.sh" ] From 709ce3adb8403570ef4af300cc7e0ca18eddcc2e Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 1 Feb 2025 06:27:36 +0400 Subject: [PATCH 14/95] Set UID in docker run --- .github/workflows/linux.yml | 5 +++-- Telegram/build/docker/centos_env/run.sh | 2 +- docs/building-linux.md | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 8eb20a2e5..eae84dc67 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -83,6 +83,7 @@ jobs: fi docker run --rm \ + -u $(id -u) \ -v $PWD:/usr/src/tdesktop \ -e CONFIG=Debug \ tdesktop:centos_env \ @@ -114,8 +115,8 @@ jobs: if: env.UPLOAD_ARTIFACT == 'true' run: | cd $REPO_NAME/out/Debug - sudo mkdir artifact - sudo mv {Telegram,Updater} artifact/ + mkdir artifact + mv {Telegram,Updater} artifact/ - uses: actions/upload-artifact@v4 if: env.UPLOAD_ARTIFACT == 'true' name: Upload artifact. diff --git a/Telegram/build/docker/centos_env/run.sh b/Telegram/build/docker/centos_env/run.sh index 4be3f8f03..eba4ec646 100755 --- a/Telegram/build/docker/centos_env/run.sh +++ b/Telegram/build/docker/centos_env/run.sh @@ -18,4 +18,4 @@ if [ "$Command" == "" ]; then Command="bash" fi -docker run -it --rm --cpus=8 --memory=22g -v $HOME/Telegram/DesktopPrivate:/usr/src/DesktopPrivate -v $HOME/Telegram/tdesktop:/usr/src/tdesktop tdesktop:centos_env $Command +docker run -it --rm --cpus=8 --memory=22g -u $(id -u) -v $HOME/Telegram/DesktopPrivate:/usr/src/DesktopPrivate -v $HOME/Telegram/tdesktop:/usr/src/tdesktop tdesktop:centos_env $Command diff --git a/docs/building-linux.md b/docs/building-linux.md index d177798fe..fbdf25355 100644 --- a/docs/building-linux.md +++ b/docs/building-linux.md @@ -20,6 +20,7 @@ Install [poetry](https://python-poetry.org), go to ***BuildPath*** and run Go to ***BuildPath*/tdesktop** and run (using [your **api_id** and **api_hash**](#obtain-your-api-credentials)) docker run --rm -it \ + -u $(id -u) \ -v "$PWD:/usr/src/tdesktop" \ tdesktop:centos_env \ /usr/src/tdesktop/Telegram/build/docker/centos_env/build.sh \ @@ -29,6 +30,7 @@ Go to ***BuildPath*/tdesktop** and run (using [your **api_id** and **api_hash**] Or, to create a debug build, run (also using [your **api_id** and **api_hash**](#obtain-your-api-credentials)) docker run --rm -it \ + -u $(id -u) \ -v "$PWD:/usr/src/tdesktop" \ -e CONFIG=Debug \ tdesktop:centos_env \ From 026490acc65eb1b7ecd7bd4a61d015494b6ae9f2 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 1 Feb 2025 14:37:20 +0000 Subject: [PATCH 15/95] Add geoclue and geocode-glib to snap --- snap/snapcraft.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index c8cf6510c..37bc92d85 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -112,6 +112,8 @@ parts: - libasound2t64 - libavif16 - libboost-regex1.83.0 + - libgeoclue-2-0 + - libgeocode-glib-2-0 - libglib2.0-0t64 - libheif1 - libopenal1 From 5e624605cff657e9e5d1a8d8538c1ed29b559e74 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 1 Feb 2025 14:39:05 +0000 Subject: [PATCH 16/95] Don't print "Choosing Qt $version" multiple times --- Telegram/build/qt_version.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Telegram/build/qt_version.py b/Telegram/build/qt_version.py index 812288db3..8e3c19d3a 100644 --- a/Telegram/build/qt_version.py +++ b/Telegram/build/qt_version.py @@ -5,10 +5,8 @@ def resolve(arch): os.environ['QT'] = '6.2.9' elif sys.platform == 'win32': if arch == 'arm' or 'qt6' in sys.argv: - print('Choosing Qt 6.') os.environ['QT'] = '6.8.1' elif os.environ.get('QT') is None: - print('Choosing Qt 5.') os.environ['QT'] = '5.15.15' elif os.environ.get('QT') is None: return False From bf48025d12fcbdda60b29c932cd7e22b37c6fd2f Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 1 Feb 2025 14:40:03 +0000 Subject: [PATCH 17/95] Update Qt 6.8.1 -> 6.8.2 --- Telegram/build/docker/centos_env/Dockerfile | 4 ++-- Telegram/build/prepare/prepare.py | 2 +- Telegram/build/qt_version.py | 2 +- snap/snapcraft.yaml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Telegram/build/docker/centos_env/Dockerfile b/Telegram/build/docker/centos_env/Dockerfile index d8cd53512..48c5f3ccd 100644 --- a/Telegram/build/docker/centos_env/Dockerfile +++ b/Telegram/build/docker/centos_env/Dockerfile @@ -2,7 +2,7 @@ {%- set GIT_FREEDESKTOP = GIT ~ "/gitlab-freedesktop-mirrors" -%} {%- set GIT_UPDATE_M4 = "git submodule set-url m4 https://gitlab.freedesktop.org/xorg/util/xcb-util-m4 && git config -f .gitmodules submodule.m4.shallow true && git submodule init && git submodule update" -%} {%- set TOOLSET = "gcc-toolset-12" -%} -{%- set QT = "6.8.1" -%} +{%- set QT = "6.8.2" -%} {%- set QT_TAG = "v" ~ QT -%} {%- set CFLAGS_DEBUG = "$CFLAGS -O0 -fno-lto -U_FORTIFY_SOURCE" -%} {%- set LibrariesPath = "/usr/src/Libraries" -%} @@ -44,7 +44,7 @@ FROM builder AS patches RUN git init patches \ && cd patches \ && git remote add origin {{ GIT }}/desktop-app/patches.git \ - && git fetch --depth=1 origin 140cd1837ed200946d6248e9f4cada52452178c1 \ + && git fetch --depth=1 origin 61bbacab28d377d0a2771cc87e008554e2f23ffb \ && git reset --hard FETCH_HEAD \ && rm -rf .git diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index 76f89424f..b78a14b66 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -457,7 +457,7 @@ if customRunCommand: stage('patches', """ git clone https://github.com/desktop-app/patches.git cd patches - git checkout 8828ed7f66 + git checkout 61bbacab28 """) stage('msys64', """ diff --git a/Telegram/build/qt_version.py b/Telegram/build/qt_version.py index 8e3c19d3a..f5a449d89 100644 --- a/Telegram/build/qt_version.py +++ b/Telegram/build/qt_version.py @@ -5,7 +5,7 @@ def resolve(arch): os.environ['QT'] = '6.2.9' elif sys.platform == 'win32': if arch == 'arm' or 'qt6' in sys.argv: - os.environ['QT'] = '6.8.1' + os.environ['QT'] = '6.8.2' elif os.environ.get('QT') is None: os.environ['QT'] = '5.15.15' elif os.environ.get('QT') is None: diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 37bc92d85..668c2ea8c 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -166,7 +166,7 @@ parts: patches: source: https://github.com/desktop-app/patches.git source-depth: 1 - source-commit: cf3b896e00c288143fce51862dbd9b1c86df1960 + source-commit: 61bbacab28d377d0a2771cc87e008554e2f23ffb plugin: dump override-pull: | craftctl default @@ -376,7 +376,7 @@ parts: - mesa-vulkan-drivers - xkb-data override-pull: | - QT=6.8.1 + QT=6.8.2 git clone -b v${QT} --depth=1 https://github.com/qt/qt5.git . git submodule update --init --recursive --depth=1 qtbase qtdeclarative qtwayland qtimageformats qtsvg qtshadertools From bee41185135cba08d717f8d730f57816e838ce27 Mon Sep 17 00:00:00 2001 From: Anton Ryzhov Date: Sat, 8 Feb 2025 21:38:55 +0100 Subject: [PATCH 18/95] Export media sizes --- Telegram/SourceFiles/export/output/export_output_json.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index 9d40b6009..dee8d1e94 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -385,6 +385,7 @@ QByteArray SerializeMessage( }; const auto pushPhoto = [&](const Image &image) { pushPath(image.file, "photo"); + push("photo_file_size", image.file.size); if (image.width && image.height) { push("width", image.width); push("height", image.height); @@ -696,8 +697,10 @@ QByteArray SerializeMessage( }, [&](const Document &data) { pushPath(data.file, "file"); push("file_name", data.name); + push("file_size", data.file.size); if (data.thumb.width > 0) { pushPath(data.thumb.file, "thumbnail"); + push("thumbnail_file_size", data.thumb.file.size); } const auto pushType = [&](const QByteArray &value) { push("media_type", value); @@ -739,6 +742,7 @@ QByteArray SerializeMessage( })); if (!data.vcard.content.isEmpty()) { pushPath(data.vcard, "contact_vcard"); + push("contact_vcard_file_size", data.vcard.size); } }, [&](const GeoPoint &data) { pushBare( From f2f0c7df92004a290f8d3ee107e58885e8746674 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 3 Feb 2025 22:07:28 +0300 Subject: [PATCH 19/95] Extended context menu for outgoing gifts. --- Telegram/Resources/langs/lang.strings | 1 + .../history/history_inner_widget.cpp | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b282a3270..2500f5715 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3952,6 +3952,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_read_show" = "show when"; "lng_context_edit_shortcut" = "Edit Shortcut"; "lng_context_delete_shortcut" = "Delete Quick Reply"; +"lng_context_gift_send" = "Send Another Gift"; "lng_add_tag_about" = "Tag this message with an emoji for quick search."; "lng_subscribe_tag_about" = "Organize your Saved Messages with tags. {link}"; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 8a3c5e2d6..066e19453 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -55,6 +55,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/about_sponsored_box.h" #include "boxes/delete_messages_box.h" #include "boxes/report_messages_box.h" +#include "boxes/star_gift_box.h" // ShowStarGiftBox #include "boxes/sticker_set_box.h" #include "boxes/translate_box.h" #include "chat_helpers/message_field.h" @@ -2770,6 +2771,29 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _menu->addAction(tr::lng_profile_copy_phone(tr::now), [=] { QGuiApplication::clipboard()->setText(phone); }, &st::menuIconCopy); + } else if (const auto gift = media->gift()) { + const auto peer = item->history()->peer; + const auto user = peer->asUser(); + if (!user + || (!user->isInaccessible() + && !user->isNotificationsUser())) { + const auto controller = _controller; + const auto starGiftUpgrade = gift->upgrade + && (gift->type == Data::GiftType::StarGift); + const auto isGift = gift->slug.isEmpty() + || !gift->channel; + const auto out = item->out(); + const auto outgoingGift = isGift + && (starGiftUpgrade ? !out : out); + if (outgoingGift) { + _menu->addAction( + tr::lng_context_gift_send(tr::now), + [=] { + Ui::ShowStarGiftBox(controller, peer); + }, + &st::menuIconGiftPremium); + } + } } } if (!item->isService() && view && actionText.isEmpty()) { From 049ebf90273c344b149cf4a54d39a3cbd5850e3a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 4 Feb 2025 21:31:39 +0300 Subject: [PATCH 20/95] Fixed display of credits icon in table row from gift box. --- .../SourceFiles/boxes/gift_premium_box.cpp | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index 987538be5..f47a153c5 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/basic_click_handlers.h" // UrlClickHandler::Open. #include "ui/boxes/boost_box.h" // StartFireworks. #include "ui/controls/userpic_button.h" +#include "ui/effects/credits_graphics.h" #include "ui/effects/premium_graphics.h" #include "ui/effects/premium_stars_colored.h" #include "ui/effects/premium_top_bar.h" @@ -405,21 +406,14 @@ void AddTableRow( auto result = object_ptr(table); const auto raw = result.data(); - const auto session = &show->session(); - const auto makeContext = [session](Fn update) { - return Core::MarkedTextContext{ - .session = session, - .customEmojiRepaint = std::move(update), - }; - }; - auto star = session->data().customEmojiManager().creditsEmoji(); + const auto star = Ui::CreateSingleStarWidget( + raw, + table->st().defaultValue.style.font->height); const auto label = Ui::CreateChild( raw, - rpl::single(star.append( - ' ' + Lang::FormatStarsAmountDecimal(entry.credits))), + Lang::FormatStarsAmountDecimal(entry.credits), table->st().defaultValue, - st::defaultPopupMenu, - std::move(makeContext)); + st::defaultPopupMenu); const auto convert = convertToStars ? Ui::CreateChild( @@ -430,7 +424,8 @@ void AddTableRow( table->st().smallButton) : nullptr; if (convert) { - convert->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); + using namespace Ui; + convert->setTextTransform(RoundButton::TextTransform::NoTransform); convert->setClickedCallback(std::move(convertToStars)); } rpl::combine( @@ -440,11 +435,13 @@ void AddTableRow( const auto convertSkip = convertWidth ? (st::normalFont->spacew + convertWidth) : 0; - label->resizeToNaturalWidth(width - convertSkip); - label->moveToLeft(0, 0, width); + const auto labelLeft = rect::right(star) + st::normalFont->spacew; + label->resizeToNaturalWidth(width - convertSkip - labelLeft); + star->moveToLeft(0, 0, width); + label->moveToLeft(labelLeft, 0, width); if (convert) { convert->moveToLeft( - label->width() + st::normalFont->spacew, + rect::right(label) + st::normalFont->spacew, (table->st().defaultValue.style.font->ascent - table->st().smallButton.style.font->ascent), width); From e4af1570cb471707273401fc1e6fb3f42fe1e379 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 4 Feb 2025 21:54:40 +0300 Subject: [PATCH 21/95] Replaced link button for switch of business hours with small round one. --- .../info/profile/info_profile_actions.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index bedf78abf..c0a776cdc 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -534,10 +534,7 @@ base::options::toggle ShowPeerIdBelowAbout({ tr::lng_info_hours_label(), st::infoLabel); label->setAttribute(Qt::WA_TransparentForMouseEvents); - const auto link = Ui::CreateChild( - labelWrap, - QString()); - rpl::combine( + auto linkText = rpl::combine( state->nonTrivial.value(), state->hours.value(), state->mine.value(), @@ -552,10 +549,12 @@ base::options::toggle ShowPeerIdBelowAbout({ : my ? tr::lng_info_hours_my_time() : tr::lng_info_hours_local_time(); - }) | rpl::flatten_latest( - ) | rpl::start_with_next([=](const QString &text) { - link->setText(text); - }, link->lifetime()); + }) | rpl::flatten_latest(); + const auto link = Ui::CreateChild( + labelWrap, + std::move(linkText), + st::defaultTableSmallButton); + link->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); link->setClickedCallback([=] { state->myTimezone = !state->myTimezone.current(); state->expanded = true; From 8df7a45e29cb7fad2d64ff00e024886be9e2b0a9 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 4 Feb 2025 22:32:47 +0300 Subject: [PATCH 22/95] Added animated arrow to toggle of business hours. --- Telegram/SourceFiles/info/info.style | 1 + .../info/profile/info_profile_actions.cpp | 39 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 9709579e9..9c841e39d 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -1164,6 +1164,7 @@ infoHoursOuter: RoundButton(defaultActiveButton) { } infoHoursOuterMargin: margins(8px, 4px, 8px, 4px); infoHoursDaySkip: 6px; +infoHoursArrowSize: 4px; infoSharedMediaScroll: ScrollArea(defaultScrollArea) { round: 1px; diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index c0a776cdc..5893c5c0e 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -69,6 +69,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/boxes/peer_qr_box.h" #include "ui/boxes/report_box_graphics.h" #include "ui/controls/userpic_button.h" +#include "ui/effects/toggle_arrow.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/ui_utility.h" @@ -93,6 +94,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_layers.h" #include "styles/style_menu_icons.h" #include "styles/style_settings.h" // settingsButtonRightSkip. +#include "styles/style_window.h" // mainMenuToggleFourStrokes. #include #include @@ -508,6 +510,8 @@ base::options::toggle ShowPeerIdBelowAbout({ dayHoursTextValue(state->day.value()) ) | rpl::after_next(recount), st::infoHoursValue); + const auto timingArrow = Ui::CreateChild(openedWrap); + timingArrow->resize(Size(timing->st().style.font->height)); timing->setAttribute(Qt::WA_TransparentForMouseEvents); state->opened.value() | rpl::start_with_next([=](bool value) { opened->setTextColorOverride(value @@ -521,7 +525,8 @@ base::options::toggle ShowPeerIdBelowAbout({ timing->sizeValue() ) | rpl::start_with_next([=](int width, int h1, QSize size) { opened->moveToLeft(0, 0, width); - timing->moveToRight(0, 0, width); + timingArrow->moveToRight(0, 0, width); + timing->moveToRight(timingArrow->width(), 0, width); const auto margins = opened->getMargins(); const auto added = margins.top() + margins.bottom(); @@ -578,6 +583,38 @@ base::options::toggle ShowPeerIdBelowAbout({ inner, object_ptr(inner))); other->toggleOn(state->expanded.value(), anim::type::normal); + constexpr auto kSlideDuration = float64(st::slideWrapDuration); + other->setDuration(kSlideDuration); + { + const auto arrowAnimation + = other->lifetime().make_state(); + arrowAnimation->init([=] { + timingArrow->update(); + if (!other->animating()) { + arrowAnimation->stop(); + } + }); + timingArrow->paintRequest() | rpl::start_with_next([=] { + auto p = QPainter(timingArrow); + const auto progress = other->animating() + ? (crl::now() - arrowAnimation->started()) / kSlideDuration + : 1.; + + const auto path = Ui::ToggleUpDownArrowPath( + timingArrow->width() / 2, + timingArrow->height() / 2, + st::infoHoursArrowSize, + st::mainMenuToggleFourStrokes, + other->toggled() ? progress : 1 - progress); + + auto hq = PainterHighQualityEnabler(p); + p.fillPath(path, timing->st().textFg); + }, timingArrow->lifetime()); + state->expanded.value() | rpl::start_with_next([=] { + arrowAnimation->start(); + }, other->lifetime()); + } + other->finishAnimating(); const auto days = other->entity(); From 057f906ca4d3da2dfc0bde514490ebd9ae87f05a Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 28 Jan 2025 10:06:37 +0400 Subject: [PATCH 23/95] Remove bot verification from saved messages. --- Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 13b69c128..729224305 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -438,6 +438,9 @@ void PaintRow( const auto promoted = (history && history->useTopPromotion()) && !context.search; + const auto verifyInfo = (from && !from->isSelf()) + ? from->botVerifyDetails() + : nullptr; if (promoted) { const auto type = history->topPromotionType(); const auto custom = type.isEmpty() @@ -449,10 +452,10 @@ void PaintRow( ? tr::lng_badge_psa_default(tr::now) : custom; PaintRowTopRight(p, text, rectForName, context); - } else if (const auto info = from ? from->botVerifyDetails() : nullptr) { - if (!rowBadge.ready(info)) { + } else if (verifyInfo) { + if (!rowBadge.ready(verifyInfo)) { rowBadge.set( - info, + verifyInfo, from->owner().customEmojiManager().factory(), customEmojiRepaint); } From 958db945f319479b905ceee1c9ff5fdc5c6ac63d Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 29 Jan 2025 09:57:17 +0400 Subject: [PATCH 24/95] Fix bot verify badge position. --- Telegram/lib_ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_ui b/Telegram/lib_ui index c2cc42224..1ea9be9bd 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit c2cc4222445058f39a6a0c1f316ea105557b0e00 +Subproject commit 1ea9be9bd646445deb8a215765bc46da69489207 From d60ce41fa9b1cb448439b587dd3e0255e3984f31 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 29 Jan 2025 10:26:42 +0400 Subject: [PATCH 25/95] Add a gift button to channel bottom. --- .../chat_helpers/chat_helpers.style | 7 ++++++ .../SourceFiles/history/history_widget.cpp | 22 +++++++++++++++++++ Telegram/SourceFiles/history/history_widget.h | 2 ++ 3 files changed, 31 insertions(+) diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 2ad236013..3c1518b37 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -855,6 +855,13 @@ historyComposeButton: FlatButton { color: historyComposeButtonBgRipple; } } +historyGiftToChannel: IconButton(defaultIconButton) { + width: 46px; + height: 46px; + + icon: icon{{ "menu/gift_premium", windowActiveTextFg }}; + iconOver: icon{{ "menu/gift_premium", windowActiveTextFg }}; +} historyUnblock: FlatButton(historyComposeButton) { color: attentionButtonFg; overColor: attentionButtonFgOver; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 6c337f9c0..74f354e8a 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/moderate_messages_box.h" #include "boxes/premium_limits_box.h" #include "boxes/premium_preview_box.h" +#include "boxes/star_gift_box.h" #include "boxes/peers/edit_peer_permissions_box.h" // ShowAboutGigagroup. #include "boxes/peers/edit_peer_requests_box.h" #include "core/file_utilities.h" @@ -377,6 +378,7 @@ HistoryWidget::HistoryWidget( _botStart->addClickHandler([=] { sendBotStartCommand(); }); _joinChannel->addClickHandler([=] { joinChannel(); }); _muteUnmute->addClickHandler([=] { toggleMuteUnmute(); }); + setupGiftToChannelButton(); _reportMessages->addClickHandler([=] { reportSelectedMessages(); }); _field->submits( ) | rpl::start_with_next([=](Qt::KeyboardModifiers modifiers) { @@ -2033,6 +2035,20 @@ void HistoryWidget::setupShortcuts() { }, lifetime()); } +void HistoryWidget::setupGiftToChannelButton() { + _giftToChannel = Ui::CreateChild( + _muteUnmute.data(), + st::historyGiftToChannel); + _muteUnmute->widthValue() | rpl::start_with_next([=](int width) { + _giftToChannel->moveToRight(0, 0); + }, _giftToChannel->lifetime()); + _giftToChannel->setClickedCallback([=] { + if (_peer) { + Ui::ShowStarGiftBox(controller(), _peer); + } + }); +} + void HistoryWidget::pushReplyReturn(not_null item) { if (item->history() != _history && item->history() != _migrated) { return; @@ -2415,6 +2431,8 @@ void HistoryWidget::showHistory( ) | rpl::start_with_next([=] { updateControlsGeometry(); }, _businessBotStatus->bar().lifetime()); + } else if (const auto channel = _peer->asChannel()) { + _giftToChannel->setVisible(channel->stargiftsAvailable()); } orderWidgets(); controller()->tabbedSelector()->setCurrentPeer(_peer); @@ -8358,6 +8376,10 @@ void HistoryWidget::fullInfoUpdated() { if (clearMaybeSendStart() && !_history->isDisplayedEmpty()) { sendBotStartCommand(); } + + if (const auto channel = _peer->asChannel()) { + _giftToChannel->setVisible(channel->stargiftsAvailable()); + } } if (updateCmdStartShown()) { refresh = true; diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 7fa51470f..9bdced55b 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -523,6 +523,7 @@ private: } void setupShortcuts(); + void setupGiftToChannelButton(); void handlePeerMigration(); @@ -785,6 +786,7 @@ private: object_ptr _botStart; object_ptr _joinChannel; object_ptr _muteUnmute; + QPointer _giftToChannel; object_ptr _reportMessages; struct { object_ptr button = { nullptr }; From 2729bcac3bdd6c4c72c9d8ac33fa6713f568c265 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 30 Jan 2025 13:13:09 +0400 Subject: [PATCH 26/95] Fix multi-line description in gift box. --- Telegram/SourceFiles/boxes/star_gift_box.cpp | 4 ++-- Telegram/SourceFiles/ui/effects/credits.style | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index 50011546d..584c5a3b6 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -2371,7 +2371,7 @@ void ShowUniqueGiftWearBox( object_ptr( raw, std::move(text), - st.infoAbout ? *st.infoAbout : st::boxDividerLabel), + st.infoAbout ? *st.infoAbout : st::upgradeGiftSubtext), st::settingsPremiumRowAboutPadding); object_ptr( raw, @@ -2603,7 +2603,7 @@ void UpgradeBox( object_ptr( raw, std::move(text), - st::boxDividerLabel), + st::upgradeGiftSubtext), st::settingsPremiumRowAboutPadding); object_ptr( raw, diff --git a/Telegram/SourceFiles/ui/effects/credits.style b/Telegram/SourceFiles/ui/effects/credits.style index a95eb292a..36a5f24f6 100644 --- a/Telegram/SourceFiles/ui/effects/credits.style +++ b/Telegram/SourceFiles/ui/effects/credits.style @@ -216,6 +216,9 @@ uniqueMenuButton: IconButton(uniqueCloseButton) { upgradeGiftBox: Box(giftBox) { buttonPadding: margins(22px, 3px, 22px, 22px); } +upgradeGiftSubtext: FlatLabel(boxDividerLabel) { + minWidth: 200px; +} darkUpgradeGiftTitle: FlatLabel(uniqueGiftTitle) { textFg: groupCallMembersFg; } @@ -232,6 +235,6 @@ darkUpgradeGiftProof: icon{{ "menu/factcheck", groupCallMembersFg }}; darkUpgradeGiftInfoTitle: FlatLabel(defaultFlatLabel) { textFg: groupCallMembersFg; } -darkUpgradeGiftInfoAbout: FlatLabel(boxDividerLabel) { +darkUpgradeGiftInfoAbout: FlatLabel(upgradeGiftSubtext) { textFg: groupCallMemberNotJoinedStatus; } From e46d5a86d34733d75860da1189afc46be24382a9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 28 Jan 2025 17:59:54 +0400 Subject: [PATCH 27/95] Don't auto-submit /start on non-loaded history. --- Telegram/SourceFiles/history/history_widget.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 74f354e8a..b13600c9b 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -4042,7 +4042,10 @@ void HistoryWidget::preloadHistoryIfNeeded() { preloadHistoryByScroll(); checkReplyReturns(); } - if (clearMaybeSendStart() && !_history->isDisplayedEmpty()) { + const auto hasNonEmpty = _history->findFirstNonEmpty(); + const auto readyForBotStart = hasNonEmpty + || (_history->loadedAtTop() && _history->loadedAtBottom()); + if (readyForBotStart && clearMaybeSendStart() && hasNonEmpty) { sendBotStartCommand(); } } @@ -8373,7 +8376,10 @@ void HistoryWidget::fullInfoUpdated() { handlePeerUpdate(); checkSuggestToGigagroup(); - if (clearMaybeSendStart() && !_history->isDisplayedEmpty()) { + const auto hasNonEmpty = _history->findFirstNonEmpty(); + const auto readyForBotStart = hasNonEmpty + || (_history->loadedAtTop() && _history->loadedAtBottom()); + if (readyForBotStart && clearMaybeSendStart() && hasNonEmpty) { sendBotStartCommand(); } From 33ca5ee39f48cad50011be48d92c85f6b3724d1a Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 31 Jan 2025 12:54:15 +0400 Subject: [PATCH 28/95] Limited before In Stock. --- Telegram/SourceFiles/boxes/star_gift_box.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index 584c5a3b6..c99b64959 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -99,8 +99,8 @@ namespace Ui { namespace { constexpr auto kPriceTabAll = 0; -constexpr auto kPriceTabLimited = -1; -constexpr auto kPriceTabInStock = -2; +constexpr auto kPriceTabLimited = -2; +constexpr auto kPriceTabInStock = -1; constexpr auto kGiftMessageLimit = 255; constexpr auto kSentToastDuration = 3 * crl::time(1000); constexpr auto kSwitchUpgradeCoverInterval = 3 * crl::time(1000); From 1869071ef7d644e5f9018b0af3c96be349282c59 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 31 Jan 2025 12:54:40 +0400 Subject: [PATCH 29/95] Sort/Filter channel gifts by non-admins. --- .../SourceFiles/info/info_wrap_widget.cpp | 3 +- .../peer_gifts/info_peer_gifts_widget.cpp | 36 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index 3e86ccb36..57fc7a478 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -446,8 +446,7 @@ void WrapWidget::setupTopBarMenuToggle() { }, _topBar->lifetime()); } else if (section.type() == Section::Type::PeerGifts && key.peer() - && key.peer()->isChannel() - && key.peer()->canManageGifts()) { + && key.peer()->isChannel()) { addTopBarMenuButton(); } } diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp index 3058bfd0b..f1d81e37c 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp @@ -630,24 +630,26 @@ void Widget::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) { }); }, filter.skipUnique ? nullptr : &st::mediaPlayerMenuCheck); - addAction({ .isSeparator = true }); + if (_inner->peer()->canManageGifts()) { + addAction({ .isSeparator = true }); - addAction(tr::lng_peer_gifts_filter_saved(tr::now), [=] { - change([](Filter &filter) { - filter.skipSaved = !filter.skipSaved; - if (filter.skipSaved && filter.skipUnsaved) { - filter.skipUnsaved = false; - } - }); - }, filter.skipSaved ? nullptr : &st::mediaPlayerMenuCheck); - addAction(tr::lng_peer_gifts_filter_unsaved(tr::now), [=] { - change([](Filter &filter) { - filter.skipUnsaved = !filter.skipUnsaved; - if (filter.skipSaved && filter.skipUnsaved) { - filter.skipSaved = false; - } - }); - }, filter.skipUnsaved ? nullptr : &st::mediaPlayerMenuCheck); + addAction(tr::lng_peer_gifts_filter_saved(tr::now), [=] { + change([](Filter &filter) { + filter.skipSaved = !filter.skipSaved; + if (filter.skipSaved && filter.skipUnsaved) { + filter.skipUnsaved = false; + } + }); + }, filter.skipSaved ? nullptr : &st::mediaPlayerMenuCheck); + addAction(tr::lng_peer_gifts_filter_unsaved(tr::now), [=] { + change([](Filter &filter) { + filter.skipUnsaved = !filter.skipUnsaved; + if (filter.skipSaved && filter.skipUnsaved) { + filter.skipSaved = false; + } + }); + }, filter.skipUnsaved ? nullptr : &st::mediaPlayerMenuCheck); + } } rpl::producer Widget::title() { From 1c8b165a6428db00c004397c94a9f071f0b5161c Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 31 Jan 2025 13:38:04 +0400 Subject: [PATCH 30/95] Show quantity of issued unique gifts. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/boxes/gift_premium_box.cpp | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 2500f5715..6163c0426 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3326,6 +3326,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_unique_backdrop" = "Backdrop"; "lng_gift_unique_symbol" = "Symbol"; "lng_gift_unique_rarity" = "Only {percent} of such collectibles have this attribute."; +"lng_gift_unique_availability_label" = "Quantity"; "lng_gift_unique_availability#one" = "{count} of {amount} issued"; "lng_gift_unique_availability#other" = "{count} of {amount} issued"; "lng_gift_unique_info" = "Gifted to {recipient} on {date}."; diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index f47a153c5..fa70d812e 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -1487,10 +1487,15 @@ void AddStarGiftTable( auto amount = rpl::single(TextWithEntities{ Lang::FormatCountDecimal(entry.limitedCount) }); + const auto count = unique + ? (entry.limitedCount - entry.limitedLeft) + : entry.limitedLeft; AddTableRow( table, - tr::lng_gift_availability(), - ((!unique && !entry.limitedLeft) + (unique + ? tr::lng_gift_unique_availability_label() + : tr::lng_gift_availability()), + ((!unique && !count) ? tr::lng_gift_availability_none( lt_amount, std::move(amount), @@ -1499,7 +1504,7 @@ void AddStarGiftTable( ? tr::lng_gift_unique_availability : tr::lng_gift_availability_left)( lt_count_decimal, - rpl::single(entry.limitedLeft * 1.), + rpl::single(count * 1.), lt_amount, std::move(amount), Ui::Text::WithEntities))); From 428a3cf0cea0cafa23baae1cc6f0ed66b68c4ef1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 31 Jan 2025 14:45:06 +0400 Subject: [PATCH 31/95] Improve phrases for forward-from-saved. --- .../view/controls/history_view_draft_options.cpp | 3 ++- .../view/controls/history_view_forward_panel.cpp | 11 ++++++++++- .../view/controls/history_view_forward_panel.h | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index 212840323..2d03f6dfa 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -947,7 +947,8 @@ void DraftOptionsBox( AddFilledSkip(bottom); - if (!hasOnlyForcedForwardedInfo) { + if (!hasOnlyForcedForwardedInfo + && !HasOnlyDroppedForwardedInfo(items)) { Settings::AddButtonWithIcon( bottom, (dropNames diff --git a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp index 239108e13..022b124ab 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp @@ -153,7 +153,7 @@ void ForwardPanel::updateTexts() { Unexpected("Corrupt forwarded information in message."); } } - if (!keepNames) { + if (!keepNames || HasOnlyDroppedForwardedInfo(_data.items)) { from = tr::lng_forward_sender_names_removed(tr::now); } else if (names.size() > 2) { from = tr::lng_forwarding_from( @@ -445,4 +445,13 @@ bool HasOnlyForcedForwardedInfo(const HistoryItemsList &list) { return true; } +bool HasOnlyDroppedForwardedInfo(const HistoryItemsList &list) { + for (const auto &item : list) { + if (!item->computeDropForwardedInfo()) { + return false; + } + } + return true; +} + } // namespace HistoryView::Controls diff --git a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h index 133292ceb..54624d47d 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h @@ -85,5 +85,6 @@ void EditWebPageOptions( Fn done); [[nodiscard]] bool HasOnlyForcedForwardedInfo(const HistoryItemsList &list); +[[nodiscard]] bool HasOnlyDroppedForwardedInfo(const HistoryItemsList &list); } // namespace HistoryView::Controls From 03aa05e4d2a3afe8ff6532dbb176125dc03b6fb7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 31 Jan 2025 20:36:29 +0400 Subject: [PATCH 32/95] Remove creation of telesco.pe links. --- Telegram/SourceFiles/apiwrap.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index d15a73f49..a75d263c4 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -769,19 +769,6 @@ QString ApiWrap::exportDirectMessageLink( : linkThreadId ? (QString::number(linkThreadId.bare) + '/' + post) : post); - if (linkChannel->hasUsername() - && !forceNonPublicLink - && !linkChannel->isMegagroup() - && !linkCommentId - && !linkThreadId) { - if (const auto media = item->media()) { - if (const auto document = media->document()) { - if (document->isVideoMessage()) { - return u"https://telesco.pe/"_q + query; - } - } - } - } return session().createInternalLinkFull(query); }; if (forceNonPublicLink) { From 4cab699b04b4572f547ba1241f40a58b96943b73 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 3 Feb 2025 12:35:24 +0400 Subject: [PATCH 33/95] Use larger unique gift preview. --- Telegram/SourceFiles/data/data_web_page.cpp | 3 ++- .../history/view/media/history_view_unique_gift.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/data/data_web_page.cpp b/Telegram/SourceFiles/data/data_web_page.cpp index 5ab3f6b2f..9f53503bb 100644 --- a/Telegram/SourceFiles/data/data_web_page.cpp +++ b/Telegram/SourceFiles/data/data_web_page.cpp @@ -382,7 +382,8 @@ bool WebPageData::computeDefaultSmallMedia() const { && description.empty() && author.isEmpty()) { return false; - } else if (!document + } else if (!uniqueGift + && !document && photo && type != WebPageType::Photo && type != WebPageType::Document diff --git a/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp index 744b3bd08..27ca9c545 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp @@ -496,7 +496,9 @@ auto UniqueGiftBg( p.setPen(Qt::NoPen); const auto webpreview = (media.get() != view->media()); const auto thickness = webpreview ? 0 : st::chatUniqueGiftBorder * 2; - const auto radius = st::msgServiceGiftBoxRadius - thickness; + const auto radius = webpreview + ? st::roundRadiusLarge + : (st::msgServiceGiftBoxRadius - thickness); const auto full = QRect(0, 0, media->width(), media->height()); const auto inner = full.marginsRemoved( { thickness, thickness, thickness, thickness }); @@ -519,7 +521,8 @@ auto UniqueGiftBg( const auto width = media->width(); const auto shift = width / 12; const auto doubled = width + 2 * shift; - const auto outer = QRect(-shift, -shift, doubled, doubled); + const auto top = (webpreview ? 2 : 1) * (-shift); + const auto outer = QRect(-shift, top, doubled, doubled); p.setClipRect(inner); Ui::PaintPoints( p, From 7ac849ab12c766149206a84fd2bd150f4dac8538 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 4 Feb 2025 20:16:25 +0400 Subject: [PATCH 34/95] Don't update mouse in non-active window. --- Telegram/SourceFiles/history/history_inner_widget.cpp | 6 +++++- Telegram/SourceFiles/history/history_inner_widget.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 066e19453..d5fbdb639 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1577,6 +1577,7 @@ void HistoryInner::mouseMoveEvent(QMouseEvent *e) { mouseReleaseEvent(e); } if (reallyMoved) { + _mouseActive = true; lastGlobalPosition = e->globalPos(); if (!buttonsPressed || (_scrollDateLink && ClickHandler::getPressed() == _scrollDateLink)) { keepScrollDateForNow(); @@ -1623,6 +1624,7 @@ void HistoryInner::mousePressEvent(QMouseEvent *e) { e->accept(); return; // ignore mouse press, that was hiding context menu } + _mouseActive = true; mouseActionStart(e->globalPos(), e->button()); } @@ -3526,6 +3528,7 @@ void HistoryInner::setShownPinned(HistoryItem *item) { } void HistoryInner::enterEventHook(QEnterEvent *e) { + _mouseActive = true; mouseActionUpdate(QCursor::pos()); return TWidget::enterEventHook(e); } @@ -3542,6 +3545,7 @@ void HistoryInner::leaveEventHook(QEvent *e) { _cursor = style::cur_default; setCursor(_cursor); } + _mouseActive = false; return TWidget::leaveEventHook(e); } @@ -3892,7 +3896,7 @@ auto HistoryInner::reactionButtonParameters( } void HistoryInner::mouseActionUpdate() { - if (hasPendingResizedItems()) { + if (hasPendingResizedItems() || !_mouseActive) { return; } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 356609a26..4c06a0979 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -499,6 +499,7 @@ private: HistoryItem *_dragStateItem = nullptr; CursorState _mouseCursorState = CursorState(); uint16 _mouseTextSymbol = 0; + bool _mouseActive = false; bool _dragStateUserpic = false; bool _pressWasInactive = false; bool _recountedAfterPendingResizedItems = false; From 8912d4d55aa964329181dabb8ff8016db2e55be0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 4 Feb 2025 21:46:26 +0400 Subject: [PATCH 35/95] Fix weather widget in stories. --- .../media/stories/media_stories_reactions.cpp | 17 +++++++++-------- .../SourceFiles/ui/color_int_conversion.cpp | 6 +++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp b/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp index 2ac9d29f3..e65443b42 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp @@ -576,9 +576,10 @@ void WeatherView::setAreaGeometry(QRect geometry, float64 radius) { const auto diagxdiag = (geometry.width() * geometry.width()) + (geometry.height() * geometry.height()); const auto diag = std::sqrt(diagxdiag); + const auto shift = diag * 2 / 3.; const auto topleft = QRectF(geometry).center() - - QPointF(diag / 2., diag / 2.); - const auto bottomright = topleft + QPointF(diag, diag); + - QPointF(shift, shift); + const auto bottomright = topleft + QPointF(shift, shift) * 2; const auto left = int(std::floor(topleft.x())); const auto top = int(std::floor(topleft.y())); const auto right = int(std::ceil(bottomright.x())); @@ -701,7 +702,7 @@ void WeatherView::cacheBackground() { p.translate(-center); const auto format = [](float64 value) { - return QString::number(int(base::SafeRound(value * 10)) / 10.); + return QString::number(int(base::SafeRound(value))); }; const auto text = [&] { const auto celsius = _data.millicelsius / 1000.; @@ -712,11 +713,11 @@ void WeatherView::cacheBackground() { return format(fahrenheit); }().append(QChar(0xb0)).append(_celsius ? "C" : "F"); const auto metrics = QFontMetrics(_font); - const auto textWidth = metrics.horizontalAdvance(text); - _padding = int(_rect.height() / 6); - const auto fullWidth = (_emoji ? _emojiSize : 0) + const auto textWidth = qCeil(metrics.horizontalAdvance(text)); + _padding = int(_rect.height() / 5); + const auto fullWidth = (_emoji ? (_emojiSize - _padding) : 0) + textWidth - + (2 * _padding); + + (4 * _padding); const auto left = _rect.x() + (_rect.width() - fullWidth) / 2; _wrapped = QRect(left, _rect.y(), fullWidth, _rect.height()); @@ -725,7 +726,7 @@ void WeatherView::cacheBackground() { p.setPen(_fg); p.setFont(_font); p.drawText(_wrapped.marginsRemoved( - { _padding + (_emoji ? _emojiSize : 0), 0, _padding, 0 }), + { 2 * _padding + (_emoji ? (_emojiSize - _padding) : 0), 0, 2 * _padding, 0 }), text, style::al_center); } diff --git a/Telegram/SourceFiles/ui/color_int_conversion.cpp b/Telegram/SourceFiles/ui/color_int_conversion.cpp index 5c9c57f07..b5df1c1c5 100644 --- a/Telegram/SourceFiles/ui/color_int_conversion.cpp +++ b/Telegram/SourceFiles/ui/color_int_conversion.cpp @@ -24,10 +24,10 @@ std::optional MaybeColorFromSerialized(quint32 serialized) { QColor Color32FromSerialized(quint32 serialized) { return QColor( - int((serialized >> 24) & 0xFFU), - int((serialized >> 16) & 0xFFU), + int(serialized & 0xFFU), int((serialized >> 8) & 0xFFU), - int(serialized & 0xFFU)); + int((serialized >> 16) & 0xFFU), + int((serialized >> 24) & 0xFFU)); } } // namespace Ui From 7f6e871b260f283320948c38e8bd3d7807ce10f9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 5 Feb 2025 13:50:27 +0400 Subject: [PATCH 36/95] Fix crash in emoji color picker. --- Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index edfa0ff06..51d288234 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -628,6 +628,13 @@ void EmojiListWidget::applyNextSearchQuery() { const auto modeChanged = (_searchMode != searching); clearSelection(); if (modeChanged) { + if (_picker) { + _picker->hideAnimated(); + } + _colorAllRipple = nullptr; + for (auto &set : _custom) { + set.ripple = nullptr; + } _searchMode = searching; } if (!searching) { From 8596b0309e1a9a116611aef98caf439a02805d82 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 5 Feb 2025 14:18:05 +0400 Subject: [PATCH 37/95] Fix bot chat scroll shift on state restore. Fixes #28085. --- Telegram/SourceFiles/history/history_inner_widget.cpp | 4 ++-- Telegram/SourceFiles/history/history_inner_widget.h | 2 +- Telegram/SourceFiles/history/history_widget.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index d5fbdb639..c8192f37a 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -3275,7 +3275,7 @@ void HistoryInner::checkActivation() { session().data().histories().readInboxTill(view->data()); } -void HistoryInner::recountHistoryGeometry() { +void HistoryInner::recountHistoryGeometry(bool initial) { _contentWidth = _scroll->width(); if (_history->hasPendingResizedItems() @@ -3333,7 +3333,7 @@ void HistoryInner::recountHistoryGeometry() { } auto historyPaddingTopDelta = (newHistoryPaddingTop - oldHistoryPaddingTop); - if (historyPaddingTopDelta != 0) { + if (!initial && historyPaddingTopDelta != 0) { if (_history->scrollTopItem) { _history->scrollTopOffset += historyPaddingTopDelta; } else if (_migrated && _migrated->scrollTopItem) { diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 4c06a0979..6b4d350c5 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -121,7 +121,7 @@ public: void setItemsRevealHeight(int revealHeight); void changeItemsRevealHeight(int revealHeight); void checkActivation(); - void recountHistoryGeometry(); + void recountHistoryGeometry(bool initial = false); void updateSize(); void setShownPinned(HistoryItem *item); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b13600c9b..7109b494c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6610,7 +6610,7 @@ void HistoryWidget::startMessageSendingAnimation( void HistoryWidget::updateListSize() { Expects(_list != nullptr); - _list->recountHistoryGeometry(); + _list->recountHistoryGeometry(!_historyInited); auto washidden = _scroll->isHidden(); if (washidden) { _scroll->show(); From 1bf50d60d8ed4b77d9f940c1c9bd12624d12fc75 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 5 Feb 2025 14:29:58 +0400 Subject: [PATCH 38/95] Fix possible crash in stories. --- Telegram/SourceFiles/data/data_stories.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp index bb08bca5d..1aac110c4 100644 --- a/Telegram/SourceFiles/data/data_stories.cpp +++ b/Telegram/SourceFiles/data/data_stories.cpp @@ -312,7 +312,7 @@ void Stories::scheduleExpireTimer() { const auto nearest = _expiring.front().first; const auto now = base::unixtime::now(); const auto delay = (nearest > now) - ? (nearest - now) + ? std::min(nearest - now, 86'400) : 0; _expireTimer.callOnce(delay * crl::time(1000)); } From 23542a1db1bb4d793474fcd5b056ac77a8c865a5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 5 Feb 2025 18:10:13 +0400 Subject: [PATCH 39/95] Fix boost group phrases. --- Telegram/Resources/langs/lang.strings | 8 +++++--- Telegram/SourceFiles/ui/boxes/boost_box.cpp | 7 ++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 6163c0426..0a3820fea 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3000,9 +3000,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_boost_channel_ask" = "Ask your **Premium** subscribers to boost your channel with this link:"; "lng_boost_channel_ask_button" = "Copy Link"; -"lng_boost_channel_or" = "or"; -"lng_boost_channel_gifting" = "Boost your channel by gifting your subscribers Telegram Premium. {link}"; -"lng_boost_channel_gifting_link" = "Get boosts >"; +//"lng_boost_channel_or" = "or"; +//"lng_boost_channel_gifting" = "Boost your channel by gifting your subscribers Telegram Premium. {link}"; +//"lng_boost_channel_gifting_link" = "Get boosts >"; +"lng_boost_group_ask" = "Ask your **Premium** members to boost your group with this link:"; +//"lng_boost_group_gifting" = "Boost your group by gifting your members Telegram Premium. {link}"; "lng_feature_stories#one" = "**{count}** Story Per Day"; "lng_feature_stories#other" = "**{count}** Stories Per Day"; diff --git a/Telegram/SourceFiles/ui/boxes/boost_box.cpp b/Telegram/SourceFiles/ui/boxes/boost_box.cpp index 4260eb05f..c70860189 100644 --- a/Telegram/SourceFiles/ui/boxes/boost_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/boost_box.cpp @@ -689,6 +689,7 @@ void AskBoostBox( }, [](AskBoostWearCollectible) { return tr::lng_boost_channel_title_wear(); }); + auto isGroup = false; auto reasonText = v::match(data.reason.data, [&]( AskBoostChannelColor data) { return tr::lng_boost_channel_needs_level_color( @@ -696,6 +697,7 @@ void AskBoostBox( rpl::single(float64(data.requiredLevel)), Ui::Text::RichLangValue); }, [&](AskBoostWallpaper data) { + isGroup = data.group; return (data.group ? tr::lng_boost_group_needs_level_wallpaper : tr::lng_boost_channel_needs_level_wallpaper)( @@ -703,6 +705,7 @@ void AskBoostBox( rpl::single(float64(data.requiredLevel)), Ui::Text::RichLangValue); }, [&](AskBoostEmojiStatus data) { + isGroup = data.group; return (data.group ? tr::lng_boost_group_needs_level_status : tr::lng_boost_channel_needs_level_status)( @@ -710,6 +713,7 @@ void AskBoostBox( rpl::single(float64(data.requiredLevel)), Ui::Text::RichLangValue); }, [&](AskBoostEmojiPack data) { + isGroup = true; return tr::lng_boost_group_needs_level_emoji( lt_count, rpl::single(float64(data.requiredLevel)), @@ -734,7 +738,8 @@ void AskBoostBox( }); auto text = rpl::combine( std::move(reasonText), - tr::lng_boost_channel_ask(Ui::Text::RichLangValue) + (isGroup ? tr::lng_boost_group_ask : tr::lng_boost_channel_ask)( + Ui::Text::RichLangValue) ) | rpl::map([](TextWithEntities &&text, TextWithEntities &&ask) { return text.append(u"\n\n"_q).append(std::move(ask)); }); From c82fbefcfcc5bc5e4a78fdc37726fcd6a5adcdd9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 5 Feb 2025 18:12:34 +0400 Subject: [PATCH 40/95] Don't show Send a Gift to service users. --- Telegram/SourceFiles/window/window_peer_menu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 8830f8dd6..df3d474c3 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -1236,6 +1236,7 @@ void Filler::addSendGift() { && (user->isInaccessible() || user->isSelf() || user->isBot() + || user->isServiceUser() || user->isNotificationsUser() || user->isRepliesChat() || user->isVerifyCodes() From 0585e72c35c7423e81ed72c0fdd7bd70cd3abef8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 6 Feb 2025 18:22:58 +0400 Subject: [PATCH 41/95] Section for shortcuts editing. --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/langs/lang.strings | 37 ++ Telegram/SourceFiles/core/shortcuts.cpp | 76 +++- Telegram/SourceFiles/core/shortcuts.h | 7 + .../SourceFiles/settings/settings_chat.cpp | 17 +- .../settings/settings_shortcuts.cpp | 406 ++++++++++++++++++ .../SourceFiles/settings/settings_shortcuts.h | 31 ++ 7 files changed, 572 insertions(+), 4 deletions(-) create mode 100644 Telegram/SourceFiles/settings/settings_shortcuts.cpp create mode 100644 Telegram/SourceFiles/settings/settings_shortcuts.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 47081bf7a..5253ebde5 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1474,6 +1474,8 @@ PRIVATE settings/settings_privacy_security.h settings/settings_scale_preview.cpp settings/settings_scale_preview.h + settings/settings_shortcuts.cpp + settings/settings_shortcuts.h settings/settings_type.h settings/settings_websites.cpp settings/settings_websites.h diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 0a3820fea..0c6651782 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -642,6 +642,43 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_chat_quick_action_react" = "Send reaction with double click"; "lng_settings_chat_corner_reaction" = "Reaction button on messages"; +"lng_settings_shortcuts" = "Keyboard shortcuts"; +"lng_shortcuts_reset" = "Reset to default"; +"lng_shortcuts_close" = "Close the window"; +"lng_shortcuts_lock" = "Lock the application"; +"lng_shortcuts_minimize" = "Minimize the window"; +"lng_shortcuts_quit" = "Quit the application"; +"lng_shortcuts_media_play" = "Play the media"; +"lng_shortcuts_media_pause" = "Pause the media"; +"lng_shortcuts_media_play_pause" = "Toggle media playback"; +"lng_shortcuts_media_stop" = "Stop media playback"; +"lng_shortcuts_media_previous" = "Previous track"; +"lng_shortcuts_media_next" = "Next track"; +"lng_shortcuts_search" = "Search messages"; +"lng_shortcuts_chat_previous" = "Previous chat"; +"lng_shortcuts_chat_next" = "Next chat"; +"lng_shortcuts_chat_first" = "First chat"; +"lng_shortcuts_chat_last" = "Last chat"; +"lng_shortcuts_chat_self" = "Saved Messages"; +"lng_shortcuts_chat_pinned_n" = "Pinned chat #{index}"; +"lng_shortcuts_show_account_n" = "Account #{index}"; +"lng_shortcuts_show_all_chats" = "All Chats folder"; +"lng_shortcuts_show_folder_n" = "Folder #{index}"; +"lng_shortcuts_show_folder_last" = "Last folder"; +"lng_shortcuts_folder_next" = "Next folder"; +"lng_shortcuts_folder_previous" = "Previous folder"; +"lng_shortcuts_scheduled" = "Scheduled messages"; +"lng_shortcuts_archive" = "Archived chats"; +"lng_shortcuts_contacts" = "Contacts list"; +"lng_shortcuts_just_send" = "Just send"; +"lng_shortcuts_silent_send" = "Silent send"; +"lng_shortcuts_schedule" = "Schedule"; +"lng_shortcuts_read_chat" = "Mark chat as read"; +"lng_shortcuts_archive_chat" = "Archive chat"; +"lng_shortcuts_media_fullscreen" = "Toggle video fullscreen"; +"lng_shortcuts_show_chat_menu" = "Show chat menu"; +"lng_shortcuts_recording" = "Recording..."; + "lng_settings_chat_reactions_title" = "Quick Reaction"; "lng_settings_chat_reactions_subtitle" = "Choose your favorite reaction"; "lng_settings_chat_message_reply_from" = "Bob Harris"; diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp index 49f81d1d8..687db4d25 100644 --- a/Telegram/SourceFiles/core/shortcuts.cpp +++ b/Telegram/SourceFiles/core/shortcuts.cpp @@ -28,6 +28,7 @@ namespace { constexpr auto kCountLimit = 256; // How many shortcuts can be in json file. rpl::event_stream> RequestsStream; +bool Paused/* = false*/; const auto AutoRepeatCommands = base::flat_set{ Command::MediaPrevious, @@ -175,6 +176,9 @@ public: [[nodiscard]] const QStringList &errors() const; + [[nodiscard]] base::flat_map keysDefaults() const; + [[nodiscard]] base::flat_map keysCurrents() const; + private: void fillDefaults(); void writeDefaultFile(); @@ -189,6 +193,8 @@ private: base::flat_map> _shortcuts; base::flat_multi_map, Command> _commandByObject; + base::flat_map _defaults; + base::flat_set _mediaShortcuts; base::flat_set _supportShortcuts; @@ -278,6 +284,21 @@ const QStringList &Manager::errors() const { return _errors; } +base::flat_map Manager::keysDefaults() const { + return _defaults; +} + +base::flat_map Manager::keysCurrents() const { + auto result = base::flat_map(); + for (const auto &[keys, command] : _shortcuts) { + const auto i = _commandByObject.findFirst(command); + if (i != _commandByObject.end()) { + result.emplace(keys, i->second); + } + } + return result; +} + std::vector Manager::lookup(not_null object) const { auto result = std::vector(); auto i = _commandByObject.findFirst(object); @@ -441,6 +462,8 @@ void Manager::fillDefaults() { set(u"ctrl+r"_q, Command::ReadChat); set(u"ctrl+\\"_q, Command::ShowChatMenu); + + _defaults = keysCurrents(); } void Manager::writeDefaultFile() { @@ -598,7 +621,9 @@ bool Launch(Command command) { } bool Launch(std::vector commands) { - if (auto handler = RequestHandler(std::move(commands))) { + if (Paused) { + return false; + } else if (auto handler = RequestHandler(std::move(commands))) { return handler(); } return false; @@ -630,6 +655,55 @@ void ToggleSupportShortcuts(bool toggled) { Data.toggleSupport(toggled); } +void Pause() { + Paused = true; +} + +void Unpause() { + Paused = false; +} + +base::flat_map KeysDefaults() { + return Data.keysDefaults(); +} + +base::flat_map KeysCurrents() { + return Data.keysCurrents(); +} + +bool AllowWithoutModifiers(int key) { + const auto service = { + Qt::Key_Escape, + Qt::Key_Tab, + Qt::Key_Backtab, + Qt::Key_Backspace, + Qt::Key_Return, + Qt::Key_Enter, + Qt::Key_Insert, + Qt::Key_Delete, + Qt::Key_Pause, + Qt::Key_Print, + Qt::Key_SysReq, + Qt::Key_Clear, + Qt::Key_Home, + Qt::Key_End, + Qt::Key_Left, + Qt::Key_Up, + Qt::Key_Right, + Qt::Key_Down, + Qt::Key_PageUp, + Qt::Key_PageDown, + Qt::Key_Shift, + Qt::Key_Control, + Qt::Key_Meta, + Qt::Key_Alt, + Qt::Key_CapsLock, + Qt::Key_NumLock, + Qt::Key_ScrollLock, + }; + return (key >= 0x80) && !ranges::contains(service, key); +} + void Finish() { Data.clear(); } diff --git a/Telegram/SourceFiles/core/shortcuts.h b/Telegram/SourceFiles/core/shortcuts.h index 5355d1681..53da6e0b4 100644 --- a/Telegram/SourceFiles/core/shortcuts.h +++ b/Telegram/SourceFiles/core/shortcuts.h @@ -139,4 +139,11 @@ void ToggleMediaShortcuts(bool toggled); // have some conflicts with default input shortcuts, like Ctrl+Delete. void ToggleSupportShortcuts(bool toggled); +void Pause(); +void Unpause(); + +[[nodiscard]] base::flat_map KeysDefaults(); +[[nodiscard]] base::flat_map KeysCurrents(); +[[nodiscard]] bool AllowWithoutModifiers(int key); + } // namespace Shortcuts diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index 1dfda764c..32cd54682 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_advanced.h" #include "settings/settings_privacy_security.h" #include "settings/settings_experimental.h" +#include "settings/settings_shortcuts.h" #include "boxes/abstract_box.h" #include "boxes/peers/edit_peer_color_box.h" #include "boxes/connection_box.h" @@ -833,7 +834,8 @@ void SetupStickersEmoji( void SetupMessages( not_null controller, - not_null container) { + not_null container, + Fn showOther) { Ui::AddDivider(container); Ui::AddSkip(container); @@ -1003,7 +1005,16 @@ void SetupMessages( Core::App().saveSettingsDelayed(); }, inner->lifetime()); - Ui::AddSkip(inner, st::settingsCheckboxesSkip); + AddButtonWithIcon( + inner, + tr::lng_settings_shortcuts(), + st::settingsButton, + { &st::menuIconBotCommands } + )->addClickHandler([=] { + showOther(Shortcuts::Id()); + }); + + Ui::AddSkip(inner); } void SetupArchive( @@ -1793,7 +1804,7 @@ void Chat::setupContent(not_null controller) { SetupCloudThemes(controller, content); SetupChatBackground(controller, content); SetupStickersEmoji(controller, content); - SetupMessages(controller, content); + SetupMessages(controller, content, showOtherMethod()); Ui::AddDivider(content); SetupSensitiveContent(controller, content, std::move(updateOnTick)); SetupArchive(controller, content); diff --git a/Telegram/SourceFiles/settings/settings_shortcuts.cpp b/Telegram/SourceFiles/settings/settings_shortcuts.cpp new file mode 100644 index 000000000..f895cfbb0 --- /dev/null +++ b/Telegram/SourceFiles/settings/settings_shortcuts.cpp @@ -0,0 +1,406 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "settings/settings_shortcuts.h" + +#include "base/event_filter.h" +#include "core/application.h" +#include "core/shortcuts.h" +#include "lang/lang_keys.h" +#include "ui/text/text_utilities.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/labels.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/vertical_list.h" +#include "styles/style_settings.h" + +namespace Settings { +namespace { + +namespace S = ::Shortcuts; + +struct Labeled { + S::Command command = {}; + rpl::producer label; +}; + +[[nodiscard]] std::vector Entries() { + using C = S::Command; + const auto pinned = [](int index) { + return tr::lng_shortcuts_chat_pinned_n( + lt_index, + rpl::single(QString::number(index))); + }; + const auto account = [](int index) { + return tr::lng_shortcuts_show_account_n( + lt_index, + rpl::single(QString::number(index))); + }; + const auto folder = [](int index) { + return tr::lng_shortcuts_show_folder_n( + lt_index, + rpl::single(QString::number(index))); + }; + const auto separator = Labeled{ C(), nullptr }; + return { + { C::Close, tr::lng_shortcuts_close() }, + { C::Lock, tr::lng_shortcuts_lock() }, + { C::Minimize, tr::lng_shortcuts_minimize() }, + { C::Quit, tr::lng_shortcuts_quit() }, + separator, + { C::Search, tr::lng_shortcuts_search() }, + separator, + { C::ChatPrevious, tr::lng_shortcuts_chat_previous() }, + { C::ChatNext, tr::lng_shortcuts_chat_next() }, + { C::ChatFirst, tr::lng_shortcuts_chat_first() }, + { C::ChatLast, tr::lng_shortcuts_chat_last() }, + { C::ChatSelf, tr::lng_shortcuts_chat_self() }, + separator, + { C::ChatPinned1, pinned(1) }, + { C::ChatPinned2, pinned(2) }, + { C::ChatPinned3, pinned(3) }, + { C::ChatPinned4, pinned(4) }, + { C::ChatPinned5, pinned(5) }, + { C::ChatPinned6, pinned(6) }, + { C::ChatPinned7, pinned(7) }, + { C::ChatPinned8, pinned(8) }, + separator, + { C::ShowAccount1, account(1) }, + { C::ShowAccount2, account(2) }, + { C::ShowAccount3, account(3) }, + { C::ShowAccount4, account(4) }, + { C::ShowAccount5, account(5) }, + { C::ShowAccount6, account(6) }, + separator, + { C::ShowAllChats, tr::lng_shortcuts_show_all_chats() }, + { C::ShowFolder1, folder(1) }, + { C::ShowFolder2, folder(2) }, + { C::ShowFolder3, folder(3) }, + { C::ShowFolder4, folder(4) }, + { C::ShowFolder5, folder(5) }, + { C::ShowFolder6, folder(6) }, + { C::ShowFolderLast, tr::lng_shortcuts_show_folder_last() }, + { C::FolderNext, tr::lng_shortcuts_folder_next() }, + { C::FolderPrevious, tr::lng_shortcuts_folder_previous() }, + { C::ShowArchive, tr::lng_shortcuts_archive() }, + { C::ShowContacts, tr::lng_shortcuts_contacts() }, + separator, + { C::ReadChat, tr::lng_shortcuts_read_chat() }, + { C::ArchiveChat, tr::lng_shortcuts_archive_chat() }, + { C::ShowScheduled, tr::lng_shortcuts_scheduled() }, + { C::ShowChatMenu, tr::lng_shortcuts_show_chat_menu() }, + separator, + { C::JustSendMessage, tr::lng_shortcuts_just_send() }, + { C::SendSilentMessage, tr::lng_shortcuts_silent_send() }, + { C::ScheduleMessage, tr::lng_shortcuts_schedule() }, + separator, + { C::MediaViewerFullscreen, tr::lng_shortcuts_media_fullscreen() }, + separator, + { C::MediaPlay, tr::lng_shortcuts_media_play() }, + { C::MediaPause, tr::lng_shortcuts_media_pause() }, + { C::MediaPlayPause, tr::lng_shortcuts_media_play_pause() }, + { C::MediaStop, tr::lng_shortcuts_media_stop() }, + { C::MediaPrevious, tr::lng_shortcuts_media_previous() }, + { C::MediaNext, tr::lng_shortcuts_media_next() }, + }; +} + +[[nodiscard]] Fn SetupShortcutsContent( + not_null controller, + not_null content) { + const auto &defaults = S::KeysDefaults(); + const auto ¤ts = S::KeysCurrents(); + + struct Button { + S::Command command; + std::unique_ptr widget; + rpl::variable key; + rpl::variable removed; + }; + struct Entry { + S::Command command; + rpl::producer label; + std::vector original; + std::vector now; + Ui::VerticalLayout *wrap = nullptr; + std::vector> buttons; + }; + struct State { + std::vector entries; + rpl::variable modified; + rpl::variable recording; + rpl::variable lastKey; + }; + const auto state = content->lifetime().make_state(); + const auto labeled = Entries(); + auto &entries = state->entries = ranges::views::all( + labeled + ) | ranges::views::transform([](Labeled labeled) { + return Entry{ labeled.command, std::move(labeled.label) }; + }) | ranges::to_vector; + + for (const auto &[keys, command] : defaults) { + const auto i = ranges::find(entries, command, &Entry::command); + if (i != end(entries)) { + i->original.push_back(keys); + } + } + + for (const auto &[keys, command] : currents) { + const auto i = ranges::find(entries, command, &Entry::command); + if (i != end(entries)) { + i->now.push_back(keys); + } + } + + const auto checkModified = [=] { + for (const auto &entry : state->entries) { + auto original = entry.original; + auto now = entry.now; + ranges::sort(original); + ranges::sort(now); + if (original != now) { + state->modified = true; + return; + } + } + state->modified = false; + }; + checkModified(); + + const auto fill = [=](Entry &entry) { + auto index = 0; + if (entry.original.empty()) { + entry.original.push_back(QKeySequence()); + } + if (entry.now.empty()) { + entry.now.push_back(QKeySequence()); + } + for (const auto &now : entry.now) { + if (index < entry.buttons.size()) { + entry.buttons[index]->key = now; + } else { + auto button = std::make_unique