diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 014b25725..f73fc436f 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,6 +1,6 @@
blank_issues_enabled: false
contact_links:
- - name: API issue
+ - name: Platform-wide issue
url: https://bugs.telegram.org
about: Any bug report or feature request affecting more than only Telegram Desktop.
- name: Issue of other client
diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml
index 257010128..4402a95f0 100644
--- a/.github/workflows/win.yml
+++ b/.github/workflows/win.yml
@@ -61,13 +61,10 @@ jobs:
steps:
- name: Prepare directories.
run: |
- mkdir %userprofile%\TBuild
+ mkdir %userprofile%\TBuild\Libraries
mklink /d %GITHUB_WORKSPACE%\TBuild %userprofile%\TBuild
echo TBUILD=%GITHUB_WORKSPACE%\TBuild>>%GITHUB_ENV%
- mkdir %userprofile%\TBuild Libraries
- mklink /d %userprofile%\TBuild\Libraries %GITHUB_WORKSPACE%\Libraries
-
- name: Get repository name.
shell: bash
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
@@ -101,7 +98,7 @@ jobs:
id: cache-libs
uses: actions/cache@v3.0.11
with:
- path: Libraries
+ path: ${{ env.TBUILD }}\Libraries
key: ${{ runner.OS }}-${{ matrix.arch }}-libs-${{ env.CACHE_KEY }}
restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-libs-
@@ -109,7 +106,9 @@ jobs:
env:
GYP_MSVS_OVERRIDE_PATH: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\'
GYP_MSVS_VERSION: 2022
- run: '%TBUILD%\%REPO_NAME%\Telegram\build\prepare\win.bat skip-release silent'
+ run: |
+ cd %TBUILD%
+ %REPO_NAME%\Telegram\build\prepare\win.bat skip-release silent
- name: Read defines.
shell: bash
@@ -133,6 +132,7 @@ jobs:
- name: Free up some disk space.
run: |
+ cd %TBUILD%
del /S Libraries\*.pdb
del /S Libraries\*.pch
del /S Libraries\*.obj
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2979473c4..7ec62b158 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,9 +19,11 @@ include(cmake/validate_special_target.cmake)
include(cmake/version.cmake)
desktop_app_parse_version(Telegram/build/version)
-set(project_langs ASM C CXX)
+set(project_langs C CXX)
if (APPLE)
list(APPEND project_langs OBJC OBJCXX)
+elseif (LINUX)
+ list(APPEND project_langs ASM)
endif()
project(Telegram
@@ -57,7 +59,7 @@ include(cmake/options.cmake)
if (NOT DESKTOP_APP_USE_PACKAGED)
if (WIN32)
- set(qt_version 5.15.9)
+ set(qt_version 5.15.10)
elseif (APPLE)
set(qt_version 6.3.2)
endif()
diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index 898416cbb..56e22c90c 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -211,6 +211,8 @@ PRIVATE
api/api_user_privacy.h
api/api_views.cpp
api/api_views.h
+ api/api_websites.cpp
+ api/api_websites.h
api/api_who_reacted.cpp
api/api_who_reacted.h
boxes/filters/edit_filter_box.cpp
@@ -1041,6 +1043,8 @@ PRIVATE
media/stories/media_stories_sibling.h
media/stories/media_stories_slider.cpp
media/stories/media_stories_slider.h
+ media/stories/media_stories_stealth.cpp
+ media/stories/media_stories_stealth.h
media/stories/media_stories_view.cpp
media/stories/media_stories_view.h
media/streaming/media_streaming_audio_track.cpp
@@ -1312,6 +1316,8 @@ PRIVATE
settings/settings_scale_preview.cpp
settings/settings_scale_preview.h
settings/settings_type.h
+ settings/settings_websites.cpp
+ settings/settings_websites.h
storage/details/storage_file_utilities.cpp
storage/details/storage_file_utilities.h
storage/details/storage_settings_scheme.cpp
diff --git a/Telegram/Resources/icons/chat/input_like.png b/Telegram/Resources/icons/chat/input_like.png
new file mode 100644
index 000000000..c7ccead7e
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_like.png differ
diff --git a/Telegram/Resources/icons/chat/input_like@2x.png b/Telegram/Resources/icons/chat/input_like@2x.png
new file mode 100644
index 000000000..965ae814b
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_like@2x.png differ
diff --git a/Telegram/Resources/icons/chat/input_like@3x.png b/Telegram/Resources/icons/chat/input_like@3x.png
new file mode 100644
index 000000000..cb2285df9
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_like@3x.png differ
diff --git a/Telegram/Resources/icons/chat/input_liked.png b/Telegram/Resources/icons/chat/input_liked.png
new file mode 100644
index 000000000..5a267ca1d
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_liked.png differ
diff --git a/Telegram/Resources/icons/chat/input_liked@2x.png b/Telegram/Resources/icons/chat/input_liked@2x.png
new file mode 100644
index 000000000..600b472be
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_liked@2x.png differ
diff --git a/Telegram/Resources/icons/chat/input_liked@3x.png b/Telegram/Resources/icons/chat/input_liked@3x.png
new file mode 100644
index 000000000..5d6c546e6
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_liked@3x.png differ
diff --git a/Telegram/Resources/icons/emoji/emoji_skin.png b/Telegram/Resources/icons/emoji/emoji_skin.png
new file mode 100644
index 000000000..776617ebe
Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_skin.png differ
diff --git a/Telegram/Resources/icons/emoji/emoji_skin@2x.png b/Telegram/Resources/icons/emoji/emoji_skin@2x.png
new file mode 100644
index 000000000..a53f5c18e
Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_skin@2x.png differ
diff --git a/Telegram/Resources/icons/emoji/emoji_skin@3x.png b/Telegram/Resources/icons/emoji/emoji_skin@3x.png
new file mode 100644
index 000000000..fd756d0a9
Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_skin@3x.png differ
diff --git a/Telegram/Resources/icons/mediaview/download_locked.png b/Telegram/Resources/icons/mediaview/download_locked.png
new file mode 100644
index 000000000..206d5893d
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/download_locked.png differ
diff --git a/Telegram/Resources/icons/mediaview/download_locked@2x.png b/Telegram/Resources/icons/mediaview/download_locked@2x.png
new file mode 100644
index 000000000..46bac9086
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/download_locked@2x.png differ
diff --git a/Telegram/Resources/icons/mediaview/download_locked@3x.png b/Telegram/Resources/icons/mediaview/download_locked@3x.png
new file mode 100644
index 000000000..57752e830
Binary files /dev/null and b/Telegram/Resources/icons/mediaview/download_locked@3x.png differ
diff --git a/Telegram/Resources/icons/menu/antispam.png b/Telegram/Resources/icons/menu/antispam.png
new file mode 100644
index 000000000..201dd2fbb
Binary files /dev/null and b/Telegram/Resources/icons/menu/antispam.png differ
diff --git a/Telegram/Resources/icons/menu/antispam@2x.png b/Telegram/Resources/icons/menu/antispam@2x.png
new file mode 100644
index 000000000..f465352f2
Binary files /dev/null and b/Telegram/Resources/icons/menu/antispam@2x.png differ
diff --git a/Telegram/Resources/icons/menu/antispam@3x.png b/Telegram/Resources/icons/menu/antispam@3x.png
new file mode 100644
index 000000000..43e7f8778
Binary files /dev/null and b/Telegram/Resources/icons/menu/antispam@3x.png differ
diff --git a/Telegram/Resources/icons/menu/bot_commands.png b/Telegram/Resources/icons/menu/bot_commands.png
new file mode 100644
index 000000000..198b475be
Binary files /dev/null and b/Telegram/Resources/icons/menu/bot_commands.png differ
diff --git a/Telegram/Resources/icons/menu/bot_commands@2x.png b/Telegram/Resources/icons/menu/bot_commands@2x.png
new file mode 100644
index 000000000..2ab6754f8
Binary files /dev/null and b/Telegram/Resources/icons/menu/bot_commands@2x.png differ
diff --git a/Telegram/Resources/icons/menu/bot_commands@3x.png b/Telegram/Resources/icons/menu/bot_commands@3x.png
new file mode 100644
index 000000000..1d0974ca4
Binary files /dev/null and b/Telegram/Resources/icons/menu/bot_commands@3x.png differ
diff --git a/Telegram/Resources/icons/menu/calls_receive.png b/Telegram/Resources/icons/menu/calls_receive.png
new file mode 100644
index 000000000..cfe1f6699
Binary files /dev/null and b/Telegram/Resources/icons/menu/calls_receive.png differ
diff --git a/Telegram/Resources/icons/menu/calls_receive@2x.png b/Telegram/Resources/icons/menu/calls_receive@2x.png
new file mode 100644
index 000000000..83e8e622d
Binary files /dev/null and b/Telegram/Resources/icons/menu/calls_receive@2x.png differ
diff --git a/Telegram/Resources/icons/menu/calls_receive@3x.png b/Telegram/Resources/icons/menu/calls_receive@3x.png
new file mode 100644
index 000000000..a74e596a7
Binary files /dev/null and b/Telegram/Resources/icons/menu/calls_receive@3x.png differ
diff --git a/Telegram/Resources/icons/menu/chat_discuss.png b/Telegram/Resources/icons/menu/chat_discuss.png
new file mode 100644
index 000000000..014033429
Binary files /dev/null and b/Telegram/Resources/icons/menu/chat_discuss.png differ
diff --git a/Telegram/Resources/icons/menu/chat_discuss@2x.png b/Telegram/Resources/icons/menu/chat_discuss@2x.png
new file mode 100644
index 000000000..2b266a33d
Binary files /dev/null and b/Telegram/Resources/icons/menu/chat_discuss@2x.png differ
diff --git a/Telegram/Resources/icons/menu/chat_discuss@3x.png b/Telegram/Resources/icons/menu/chat_discuss@3x.png
new file mode 100644
index 000000000..2a54806d8
Binary files /dev/null and b/Telegram/Resources/icons/menu/chat_discuss@3x.png differ
diff --git a/Telegram/Resources/icons/menu/devices.png b/Telegram/Resources/icons/menu/devices.png
new file mode 100644
index 000000000..192140249
Binary files /dev/null and b/Telegram/Resources/icons/menu/devices.png differ
diff --git a/Telegram/Resources/icons/menu/devices@2x.png b/Telegram/Resources/icons/menu/devices@2x.png
new file mode 100644
index 000000000..6ac88a975
Binary files /dev/null and b/Telegram/Resources/icons/menu/devices@2x.png differ
diff --git a/Telegram/Resources/icons/menu/devices@3x.png b/Telegram/Resources/icons/menu/devices@3x.png
new file mode 100644
index 000000000..a5b443200
Binary files /dev/null and b/Telegram/Resources/icons/menu/devices@3x.png differ
diff --git a/Telegram/Resources/icons/menu/dock_bounce.png b/Telegram/Resources/icons/menu/dock_bounce.png
new file mode 100644
index 000000000..b538f11e0
Binary files /dev/null and b/Telegram/Resources/icons/menu/dock_bounce.png differ
diff --git a/Telegram/Resources/icons/menu/dock_bounce@2x.png b/Telegram/Resources/icons/menu/dock_bounce@2x.png
new file mode 100644
index 000000000..232aaa82c
Binary files /dev/null and b/Telegram/Resources/icons/menu/dock_bounce@2x.png differ
diff --git a/Telegram/Resources/icons/menu/dock_bounce@3x.png b/Telegram/Resources/icons/menu/dock_bounce@3x.png
new file mode 100644
index 000000000..5bc6d3dd3
Binary files /dev/null and b/Telegram/Resources/icons/menu/dock_bounce@3x.png differ
diff --git a/Telegram/Resources/icons/menu/download_locked.png b/Telegram/Resources/icons/menu/download_locked.png
new file mode 100644
index 000000000..824ca3707
Binary files /dev/null and b/Telegram/Resources/icons/menu/download_locked.png differ
diff --git a/Telegram/Resources/icons/menu/download_locked@2x.png b/Telegram/Resources/icons/menu/download_locked@2x.png
new file mode 100644
index 000000000..1e2dde2ce
Binary files /dev/null and b/Telegram/Resources/icons/menu/download_locked@2x.png differ
diff --git a/Telegram/Resources/icons/menu/download_locked@3x.png b/Telegram/Resources/icons/menu/download_locked@3x.png
new file mode 100644
index 000000000..69d05e38d
Binary files /dev/null and b/Telegram/Resources/icons/menu/download_locked@3x.png differ
diff --git a/Telegram/Resources/icons/menu/experimental.png b/Telegram/Resources/icons/menu/experimental.png
new file mode 100644
index 000000000..f84b745a9
Binary files /dev/null and b/Telegram/Resources/icons/menu/experimental.png differ
diff --git a/Telegram/Resources/icons/menu/experimental@2x.png b/Telegram/Resources/icons/menu/experimental@2x.png
new file mode 100644
index 000000000..e56b0c3ed
Binary files /dev/null and b/Telegram/Resources/icons/menu/experimental@2x.png differ
diff --git a/Telegram/Resources/icons/menu/experimental@3x.png b/Telegram/Resources/icons/menu/experimental@3x.png
new file mode 100644
index 000000000..d2c1efdd2
Binary files /dev/null and b/Telegram/Resources/icons/menu/experimental@3x.png differ
diff --git a/Telegram/Resources/icons/menu/faq.png b/Telegram/Resources/icons/menu/faq.png
new file mode 100644
index 000000000..e280515e6
Binary files /dev/null and b/Telegram/Resources/icons/menu/faq.png differ
diff --git a/Telegram/Resources/icons/menu/faq@2x.png b/Telegram/Resources/icons/menu/faq@2x.png
new file mode 100644
index 000000000..c44914078
Binary files /dev/null and b/Telegram/Resources/icons/menu/faq@2x.png differ
diff --git a/Telegram/Resources/icons/menu/faq@3x.png b/Telegram/Resources/icons/menu/faq@3x.png
new file mode 100644
index 000000000..853065e0b
Binary files /dev/null and b/Telegram/Resources/icons/menu/faq@3x.png differ
diff --git a/Telegram/Resources/icons/menu/group_log.png b/Telegram/Resources/icons/menu/group_log.png
new file mode 100644
index 000000000..5452f7975
Binary files /dev/null and b/Telegram/Resources/icons/menu/group_log.png differ
diff --git a/Telegram/Resources/icons/menu/group_log@2x.png b/Telegram/Resources/icons/menu/group_log@2x.png
new file mode 100644
index 000000000..b372a0cf6
Binary files /dev/null and b/Telegram/Resources/icons/menu/group_log@2x.png differ
diff --git a/Telegram/Resources/icons/menu/group_log@3x.png b/Telegram/Resources/icons/menu/group_log@3x.png
new file mode 100644
index 000000000..678b9dc62
Binary files /dev/null and b/Telegram/Resources/icons/menu/group_log@3x.png differ
diff --git a/Telegram/Resources/icons/menu/group_reactions.png b/Telegram/Resources/icons/menu/group_reactions.png
new file mode 100644
index 000000000..c941a5955
Binary files /dev/null and b/Telegram/Resources/icons/menu/group_reactions.png differ
diff --git a/Telegram/Resources/icons/menu/group_reactions@2x.png b/Telegram/Resources/icons/menu/group_reactions@2x.png
new file mode 100644
index 000000000..406d42273
Binary files /dev/null and b/Telegram/Resources/icons/menu/group_reactions@2x.png differ
diff --git a/Telegram/Resources/icons/menu/group_reactions@3x.png b/Telegram/Resources/icons/menu/group_reactions@3x.png
new file mode 100644
index 000000000..caf8ae470
Binary files /dev/null and b/Telegram/Resources/icons/menu/group_reactions@3x.png differ
diff --git a/Telegram/Resources/icons/menu/groups_create.png b/Telegram/Resources/icons/menu/groups_create.png
new file mode 100644
index 000000000..5d6bb4c00
Binary files /dev/null and b/Telegram/Resources/icons/menu/groups_create.png differ
diff --git a/Telegram/Resources/icons/menu/groups_create@2x.png b/Telegram/Resources/icons/menu/groups_create@2x.png
new file mode 100644
index 000000000..cf110c030
Binary files /dev/null and b/Telegram/Resources/icons/menu/groups_create@2x.png differ
diff --git a/Telegram/Resources/icons/menu/groups_create@3x.png b/Telegram/Resources/icons/menu/groups_create@3x.png
new file mode 100644
index 000000000..b45349322
Binary files /dev/null and b/Telegram/Resources/icons/menu/groups_create@3x.png differ
diff --git a/Telegram/Resources/icons/menu/hide_members.png b/Telegram/Resources/icons/menu/hide_members.png
new file mode 100644
index 000000000..5e81f7655
Binary files /dev/null and b/Telegram/Resources/icons/menu/hide_members.png differ
diff --git a/Telegram/Resources/icons/menu/hide_members@2x.png b/Telegram/Resources/icons/menu/hide_members@2x.png
new file mode 100644
index 000000000..e10056514
Binary files /dev/null and b/Telegram/Resources/icons/menu/hide_members@2x.png differ
diff --git a/Telegram/Resources/icons/menu/hide_members@3x.png b/Telegram/Resources/icons/menu/hide_members@3x.png
new file mode 100644
index 000000000..011d3c425
Binary files /dev/null and b/Telegram/Resources/icons/menu/hide_members@3x.png differ
diff --git a/Telegram/Resources/icons/menu/info_notifications.png b/Telegram/Resources/icons/menu/info_notifications.png
new file mode 100644
index 000000000..3686dba72
Binary files /dev/null and b/Telegram/Resources/icons/menu/info_notifications.png differ
diff --git a/Telegram/Resources/icons/menu/info_notifications@2x.png b/Telegram/Resources/icons/menu/info_notifications@2x.png
new file mode 100644
index 000000000..ed724c7f2
Binary files /dev/null and b/Telegram/Resources/icons/menu/info_notifications@2x.png differ
diff --git a/Telegram/Resources/icons/menu/info_notifications@3x.png b/Telegram/Resources/icons/menu/info_notifications@3x.png
new file mode 100644
index 000000000..de98cf241
Binary files /dev/null and b/Telegram/Resources/icons/menu/info_notifications@3x.png differ
diff --git a/Telegram/Resources/icons/menu/ip_address.png b/Telegram/Resources/icons/menu/ip_address.png
new file mode 100644
index 000000000..3aa87b0aa
Binary files /dev/null and b/Telegram/Resources/icons/menu/ip_address.png differ
diff --git a/Telegram/Resources/icons/menu/ip_address@2x.png b/Telegram/Resources/icons/menu/ip_address@2x.png
new file mode 100644
index 000000000..1184e10b0
Binary files /dev/null and b/Telegram/Resources/icons/menu/ip_address@2x.png differ
diff --git a/Telegram/Resources/icons/menu/ip_address@3x.png b/Telegram/Resources/icons/menu/ip_address@3x.png
new file mode 100644
index 000000000..3cee2b09d
Binary files /dev/null and b/Telegram/Resources/icons/menu/ip_address@3x.png differ
diff --git a/Telegram/Resources/icons/menu/links_profile.png b/Telegram/Resources/icons/menu/links_profile.png
new file mode 100644
index 000000000..da8497860
Binary files /dev/null and b/Telegram/Resources/icons/menu/links_profile.png differ
diff --git a/Telegram/Resources/icons/menu/links_profile@2x.png b/Telegram/Resources/icons/menu/links_profile@2x.png
new file mode 100644
index 000000000..26dfa285e
Binary files /dev/null and b/Telegram/Resources/icons/menu/links_profile@2x.png differ
diff --git a/Telegram/Resources/icons/menu/links_profile@3x.png b/Telegram/Resources/icons/menu/links_profile@3x.png
new file mode 100644
index 000000000..fef135b0d
Binary files /dev/null and b/Telegram/Resources/icons/menu/links_profile@3x.png differ
diff --git a/Telegram/Resources/icons/menu/lock.png b/Telegram/Resources/icons/menu/lock.png
new file mode 100644
index 000000000..7e7c58bbb
Binary files /dev/null and b/Telegram/Resources/icons/menu/lock.png differ
diff --git a/Telegram/Resources/icons/menu/lock@2x.png b/Telegram/Resources/icons/menu/lock@2x.png
new file mode 100644
index 000000000..2887113a8
Binary files /dev/null and b/Telegram/Resources/icons/menu/lock@2x.png differ
diff --git a/Telegram/Resources/icons/menu/lock@3x.png b/Telegram/Resources/icons/menu/lock@3x.png
new file mode 100644
index 000000000..f960d6a5d
Binary files /dev/null and b/Telegram/Resources/icons/menu/lock@3x.png differ
diff --git a/Telegram/Resources/icons/menu/network.png b/Telegram/Resources/icons/menu/network.png
new file mode 100644
index 000000000..c1f4b9829
Binary files /dev/null and b/Telegram/Resources/icons/menu/network.png differ
diff --git a/Telegram/Resources/icons/menu/network@2x.png b/Telegram/Resources/icons/menu/network@2x.png
new file mode 100644
index 000000000..76f22a6ae
Binary files /dev/null and b/Telegram/Resources/icons/menu/network@2x.png differ
diff --git a/Telegram/Resources/icons/menu/network@3x.png b/Telegram/Resources/icons/menu/network@3x.png
new file mode 100644
index 000000000..0f0e8a6fa
Binary files /dev/null and b/Telegram/Resources/icons/menu/network@3x.png differ
diff --git a/Telegram/Resources/icons/menu/payment_address.png b/Telegram/Resources/icons/menu/payment_address.png
new file mode 100644
index 000000000..a7cc0eb69
Binary files /dev/null and b/Telegram/Resources/icons/menu/payment_address.png differ
diff --git a/Telegram/Resources/icons/menu/payment_address@2x.png b/Telegram/Resources/icons/menu/payment_address@2x.png
new file mode 100644
index 000000000..12daa492c
Binary files /dev/null and b/Telegram/Resources/icons/menu/payment_address@2x.png differ
diff --git a/Telegram/Resources/icons/menu/payment_address@3x.png b/Telegram/Resources/icons/menu/payment_address@3x.png
new file mode 100644
index 000000000..3172912c6
Binary files /dev/null and b/Telegram/Resources/icons/menu/payment_address@3x.png differ
diff --git a/Telegram/Resources/icons/menu/payment_email.png b/Telegram/Resources/icons/menu/payment_email.png
new file mode 100644
index 000000000..5a1c58863
Binary files /dev/null and b/Telegram/Resources/icons/menu/payment_email.png differ
diff --git a/Telegram/Resources/icons/menu/payment_email@2x.png b/Telegram/Resources/icons/menu/payment_email@2x.png
new file mode 100644
index 000000000..a8af89a41
Binary files /dev/null and b/Telegram/Resources/icons/menu/payment_email@2x.png differ
diff --git a/Telegram/Resources/icons/menu/payment_email@3x.png b/Telegram/Resources/icons/menu/payment_email@3x.png
new file mode 100644
index 000000000..b47586e27
Binary files /dev/null and b/Telegram/Resources/icons/menu/payment_email@3x.png differ
diff --git a/Telegram/Resources/icons/menu/power_usage.png b/Telegram/Resources/icons/menu/power_usage.png
new file mode 100644
index 000000000..a6a8015c6
Binary files /dev/null and b/Telegram/Resources/icons/menu/power_usage.png differ
diff --git a/Telegram/Resources/icons/menu/power_usage@2x.png b/Telegram/Resources/icons/menu/power_usage@2x.png
new file mode 100644
index 000000000..cf2e46f6c
Binary files /dev/null and b/Telegram/Resources/icons/menu/power_usage@2x.png differ
diff --git a/Telegram/Resources/icons/menu/power_usage@3x.png b/Telegram/Resources/icons/menu/power_usage@3x.png
new file mode 100644
index 000000000..cb81ed700
Binary files /dev/null and b/Telegram/Resources/icons/menu/power_usage@3x.png differ
diff --git a/Telegram/Resources/icons/menu/premium.png b/Telegram/Resources/icons/menu/premium.png
new file mode 100644
index 000000000..56e0e0e94
Binary files /dev/null and b/Telegram/Resources/icons/menu/premium.png differ
diff --git a/Telegram/Resources/icons/menu/premium@2x.png b/Telegram/Resources/icons/menu/premium@2x.png
new file mode 100644
index 000000000..64913421b
Binary files /dev/null and b/Telegram/Resources/icons/menu/premium@2x.png differ
diff --git a/Telegram/Resources/icons/menu/premium@3x.png b/Telegram/Resources/icons/menu/premium@3x.png
new file mode 100644
index 000000000..0ba0e8b9f
Binary files /dev/null and b/Telegram/Resources/icons/menu/premium@3x.png differ
diff --git a/Telegram/Resources/icons/menu/recovery_email.png b/Telegram/Resources/icons/menu/recovery_email.png
new file mode 100644
index 000000000..a9d149fed
Binary files /dev/null and b/Telegram/Resources/icons/menu/recovery_email.png differ
diff --git a/Telegram/Resources/icons/menu/recovery_email@2x.png b/Telegram/Resources/icons/menu/recovery_email@2x.png
new file mode 100644
index 000000000..dd378b846
Binary files /dev/null and b/Telegram/Resources/icons/menu/recovery_email@2x.png differ
diff --git a/Telegram/Resources/icons/menu/recovery_email@3x.png b/Telegram/Resources/icons/menu/recovery_email@3x.png
new file mode 100644
index 000000000..1372dd22c
Binary files /dev/null and b/Telegram/Resources/icons/menu/recovery_email@3x.png differ
diff --git a/Telegram/Resources/icons/menu/remove.png b/Telegram/Resources/icons/menu/remove.png
new file mode 100644
index 000000000..e8c9534cd
Binary files /dev/null and b/Telegram/Resources/icons/menu/remove.png differ
diff --git a/Telegram/Resources/icons/menu/remove@2x.png b/Telegram/Resources/icons/menu/remove@2x.png
new file mode 100644
index 000000000..b064e3efe
Binary files /dev/null and b/Telegram/Resources/icons/menu/remove@2x.png differ
diff --git a/Telegram/Resources/icons/menu/remove@3x.png b/Telegram/Resources/icons/menu/remove@3x.png
new file mode 100644
index 000000000..90b1b337d
Binary files /dev/null and b/Telegram/Resources/icons/menu/remove@3x.png differ
diff --git a/Telegram/Resources/icons/menu/signed.png b/Telegram/Resources/icons/menu/signed.png
new file mode 100644
index 000000000..ab59a070d
Binary files /dev/null and b/Telegram/Resources/icons/menu/signed.png differ
diff --git a/Telegram/Resources/icons/menu/signed@2x.png b/Telegram/Resources/icons/menu/signed@2x.png
new file mode 100644
index 000000000..e8a3faaf1
Binary files /dev/null and b/Telegram/Resources/icons/menu/signed@2x.png differ
diff --git a/Telegram/Resources/icons/menu/signed@3x.png b/Telegram/Resources/icons/menu/signed@3x.png
new file mode 100644
index 000000000..2a9e1011f
Binary files /dev/null and b/Telegram/Resources/icons/menu/signed@3x.png differ
diff --git a/Telegram/Resources/icons/menu/stealth.png b/Telegram/Resources/icons/menu/stealth.png
new file mode 100644
index 000000000..af12353a9
Binary files /dev/null and b/Telegram/Resources/icons/menu/stealth.png differ
diff --git a/Telegram/Resources/icons/menu/stealth@2x.png b/Telegram/Resources/icons/menu/stealth@2x.png
new file mode 100644
index 000000000..50706a61f
Binary files /dev/null and b/Telegram/Resources/icons/menu/stealth@2x.png differ
diff --git a/Telegram/Resources/icons/menu/stealth@3x.png b/Telegram/Resources/icons/menu/stealth@3x.png
new file mode 100644
index 000000000..c659d25b8
Binary files /dev/null and b/Telegram/Resources/icons/menu/stealth@3x.png differ
diff --git a/Telegram/Resources/icons/menu/stealth_locked.png b/Telegram/Resources/icons/menu/stealth_locked.png
new file mode 100644
index 000000000..dbc0cb5e3
Binary files /dev/null and b/Telegram/Resources/icons/menu/stealth_locked.png differ
diff --git a/Telegram/Resources/icons/menu/stealth_locked@2x.png b/Telegram/Resources/icons/menu/stealth_locked@2x.png
new file mode 100644
index 000000000..979e23d5c
Binary files /dev/null and b/Telegram/Resources/icons/menu/stealth_locked@2x.png differ
diff --git a/Telegram/Resources/icons/menu/stealth_locked@3x.png b/Telegram/Resources/icons/menu/stealth_locked@3x.png
new file mode 100644
index 000000000..07278760a
Binary files /dev/null and b/Telegram/Resources/icons/menu/stealth_locked@3x.png differ
diff --git a/Telegram/Resources/icons/menu/stop_poll.png b/Telegram/Resources/icons/menu/stop_poll.png
deleted file mode 100644
index 55846def1..000000000
Binary files a/Telegram/Resources/icons/menu/stop_poll.png and /dev/null differ
diff --git a/Telegram/Resources/icons/menu/stop_poll@2x.png b/Telegram/Resources/icons/menu/stop_poll@2x.png
deleted file mode 100644
index 85fb5f827..000000000
Binary files a/Telegram/Resources/icons/menu/stop_poll@2x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/menu/stop_poll@3x.png b/Telegram/Resources/icons/menu/stop_poll@3x.png
deleted file mode 100644
index 179ea1b89..000000000
Binary files a/Telegram/Resources/icons/menu/stop_poll@3x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/menu/storage.png b/Telegram/Resources/icons/menu/storage.png
new file mode 100644
index 000000000..ce6ffd0a3
Binary files /dev/null and b/Telegram/Resources/icons/menu/storage.png differ
diff --git a/Telegram/Resources/icons/menu/storage@2x.png b/Telegram/Resources/icons/menu/storage@2x.png
new file mode 100644
index 000000000..c38320ba7
Binary files /dev/null and b/Telegram/Resources/icons/menu/storage@2x.png differ
diff --git a/Telegram/Resources/icons/menu/storage@3x.png b/Telegram/Resources/icons/menu/storage@3x.png
new file mode 100644
index 000000000..532f2ec0f
Binary files /dev/null and b/Telegram/Resources/icons/menu/storage@3x.png differ
diff --git a/Telegram/Resources/icons/menu/timer.png b/Telegram/Resources/icons/menu/timer.png
new file mode 100644
index 000000000..5fe0383b4
Binary files /dev/null and b/Telegram/Resources/icons/menu/timer.png differ
diff --git a/Telegram/Resources/icons/menu/timer@2x.png b/Telegram/Resources/icons/menu/timer@2x.png
new file mode 100644
index 000000000..28d3d1480
Binary files /dev/null and b/Telegram/Resources/icons/menu/timer@2x.png differ
diff --git a/Telegram/Resources/icons/menu/timer@3x.png b/Telegram/Resources/icons/menu/timer@3x.png
new file mode 100644
index 000000000..173ad913d
Binary files /dev/null and b/Telegram/Resources/icons/menu/timer@3x.png differ
diff --git a/Telegram/Resources/icons/menu/topics.png b/Telegram/Resources/icons/menu/topics.png
new file mode 100644
index 000000000..3e5eed67b
Binary files /dev/null and b/Telegram/Resources/icons/menu/topics.png differ
diff --git a/Telegram/Resources/icons/menu/topics@2x.png b/Telegram/Resources/icons/menu/topics@2x.png
new file mode 100644
index 000000000..789d9cf60
Binary files /dev/null and b/Telegram/Resources/icons/menu/topics@2x.png differ
diff --git a/Telegram/Resources/icons/menu/topics@3x.png b/Telegram/Resources/icons/menu/topics@3x.png
new file mode 100644
index 000000000..f5c03b336
Binary files /dev/null and b/Telegram/Resources/icons/menu/topics@3x.png differ
diff --git a/Telegram/Resources/icons/settings/premium/stories_caption.png b/Telegram/Resources/icons/settings/premium/stories_caption.png
new file mode 100644
index 000000000..d73bc9068
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/stories_caption.png differ
diff --git a/Telegram/Resources/icons/settings/premium/stories_caption@2x.png b/Telegram/Resources/icons/settings/premium/stories_caption@2x.png
new file mode 100644
index 000000000..e67594df0
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/stories_caption@2x.png differ
diff --git a/Telegram/Resources/icons/settings/premium/stories_caption@3x.png b/Telegram/Resources/icons/settings/premium/stories_caption@3x.png
new file mode 100644
index 000000000..373884ace
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/stories_caption@3x.png differ
diff --git a/Telegram/Resources/icons/settings/premium/stories_order.png b/Telegram/Resources/icons/settings/premium/stories_order.png
new file mode 100644
index 000000000..3051561df
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/stories_order.png differ
diff --git a/Telegram/Resources/icons/settings/premium/stories_order@2x.png b/Telegram/Resources/icons/settings/premium/stories_order@2x.png
new file mode 100644
index 000000000..4b4f64ceb
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/stories_order@2x.png differ
diff --git a/Telegram/Resources/icons/settings/premium/stories_order@3x.png b/Telegram/Resources/icons/settings/premium/stories_order@3x.png
new file mode 100644
index 000000000..d550ddcef
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/stories_order@3x.png differ
diff --git a/Telegram/Resources/icons/settings/premium/timer.png b/Telegram/Resources/icons/settings/premium/timer.png
new file mode 100644
index 000000000..5fe0383b4
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/timer.png differ
diff --git a/Telegram/Resources/icons/settings/premium/timer@2x.png b/Telegram/Resources/icons/settings/premium/timer@2x.png
new file mode 100644
index 000000000..28d3d1480
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/timer@2x.png differ
diff --git a/Telegram/Resources/icons/settings/premium/timer@3x.png b/Telegram/Resources/icons/settings/premium/timer@3x.png
new file mode 100644
index 000000000..173ad913d
Binary files /dev/null and b/Telegram/Resources/icons/settings/premium/timer@3x.png differ
diff --git a/Telegram/Resources/icons/mediaview/stories_next.png b/Telegram/Resources/icons/stories/next.png
similarity index 100%
rename from Telegram/Resources/icons/mediaview/stories_next.png
rename to Telegram/Resources/icons/stories/next.png
diff --git a/Telegram/Resources/icons/mediaview/stories_next@2x.png b/Telegram/Resources/icons/stories/next@2x.png
similarity index 100%
rename from Telegram/Resources/icons/mediaview/stories_next@2x.png
rename to Telegram/Resources/icons/stories/next@2x.png
diff --git a/Telegram/Resources/icons/mediaview/stories_next@3x.png b/Telegram/Resources/icons/stories/next@3x.png
similarity index 100%
rename from Telegram/Resources/icons/mediaview/stories_next@3x.png
rename to Telegram/Resources/icons/stories/next@3x.png
diff --git a/Telegram/Resources/icons/stories/stealth_25m.png b/Telegram/Resources/icons/stories/stealth_25m.png
new file mode 100644
index 000000000..77fb7fdbb
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_25m.png differ
diff --git a/Telegram/Resources/icons/stories/stealth_25m@2x.png b/Telegram/Resources/icons/stories/stealth_25m@2x.png
new file mode 100644
index 000000000..6ec9a01f7
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_25m@2x.png differ
diff --git a/Telegram/Resources/icons/stories/stealth_25m@3x.png b/Telegram/Resources/icons/stories/stealth_25m@3x.png
new file mode 100644
index 000000000..e1601cd0e
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_25m@3x.png differ
diff --git a/Telegram/Resources/icons/stories/stealth_5m.png b/Telegram/Resources/icons/stories/stealth_5m.png
new file mode 100644
index 000000000..51f1cdfc3
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_5m.png differ
diff --git a/Telegram/Resources/icons/stories/stealth_5m@2x.png b/Telegram/Resources/icons/stories/stealth_5m@2x.png
new file mode 100644
index 000000000..dd0804fea
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_5m@2x.png differ
diff --git a/Telegram/Resources/icons/stories/stealth_5m@3x.png b/Telegram/Resources/icons/stories/stealth_5m@3x.png
new file mode 100644
index 000000000..c635dec9f
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_5m@3x.png differ
diff --git a/Telegram/Resources/icons/stories/stealth_logo.png b/Telegram/Resources/icons/stories/stealth_logo.png
new file mode 100644
index 000000000..10a249195
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_logo.png differ
diff --git a/Telegram/Resources/icons/stories/stealth_logo@2x.png b/Telegram/Resources/icons/stories/stealth_logo@2x.png
new file mode 100644
index 000000000..4300b18f1
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_logo@2x.png differ
diff --git a/Telegram/Resources/icons/stories/stealth_logo@3x.png b/Telegram/Resources/icons/stories/stealth_logo@3x.png
new file mode 100644
index 000000000..161618d20
Binary files /dev/null and b/Telegram/Resources/icons/stories/stealth_logo@3x.png differ
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index c9de1df7c..de72609e7 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -272,6 +272,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_error_noforwards_channel" = "Sorry, forwarding from this channel is disabled by admins.";
"lng_error_nocopy_group" = "Sorry, copying from this group is disabled by admins.";
"lng_error_nocopy_channel" = "Sorry, copying from this channel is disabled by admins.";
+"lng_error_nocopy_story" = "Sorry, copying of this story is disabled by the author.";
"lng_sure_add_admin_invite" = "This user is not a member of this group. Add them to the group and promote them to admin?";
"lng_sure_add_admin_invite_channel" = "This user is not a subscriber of this channel. Add them to the channel and promote them to admin?";
"lng_sure_add_admin_unremove" = "This user is currently restricted or removed. Are you sure you want to promote them?";
@@ -599,6 +600,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_username_label" = "Username";
"lng_settings_phone_label" = "Phone number";
"lng_settings_username_add" = "Add username";
+"lng_settings_username_about" = "Username lets people contact you on Telegram without needing your phone number.";
+"lng_settings_add_account_about" = "You can add up to four accounts with different phone numbers.";
"lng_settings_peer_to_peer_about" = "Disabling peer-to-peer will relay all calls through Telegram servers to avoid revealing your IP address, but may slightly decrease audio quality.";
"lng_settings_advanced" = "Advanced";
"lng_settings_stickers_emoji" = "Stickers and emoji";
@@ -611,12 +614,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_theme_accent_title" = "Choose accent color";
"lng_settings_data_storage" = "Data and storage";
"lng_settings_information" = "Edit profile";
+"lng_settings_my_account" = "My Account";
"lng_settings_security" = "Security";
"lng_settings_passcode_title" = "Local passcode";
"lng_settings_sessions_title" = "Active sessions";
+"lng_settings_sessions_about" = "Review the list of devices where you are logged into your Telegram account.";
+"lng_settings_archive_title" = "Archive Settings";
"lng_settings_new_unknown" = "New chats from unknown users";
"lng_settings_auto_archive" = "Archive and Mute";
"lng_settings_auto_archive_about" = "Automatically archive and mute new chats, groups and channels from non-contacts.";
+"lng_settings_unmuted_chats" = "Unmuted chats";
+"lng_settings_always_in_archive" = "Always keep archived";
+"lng_settings_unmuted_chats_about" = "Keep archived chats in the Archive even if they are unmuted and get a new message.";
+"lng_settings_chats_from_folders" = "Chats from folders";
+"lng_settings_chats_from_folders_about" = "Keep archived chats from folders in the Archive even if they are unmuted and get a new message.";
"lng_settings_destroy_title" = "Delete my account";
"lng_settings_version_info" = "Version and updates";
"lng_settings_system_integration" = "System integration";
@@ -635,6 +646,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_sensitive_about" = "Display sensitive media in public channels on all your Telegram devices.";
"lng_settings_security_bots" = "Bots and websites";
"lng_settings_clear_payment_info" = "Clear Payment and Shipping Info";
+"lng_settings_logged_in" = "Connected websites";
+"lng_settings_logged_in_title" = "Logged in with Telegram";
+"lng_settings_logged_in_description" = "You can log in on websites that support signing in with Telegram.";
+"lng_settings_disconnect_all" = "Disconnect all websites";
+"lng_settings_disconnect_title" = "Disconnect website";
+"lng_settings_disconnect_sure" = "Are you sure you want to disconnect {domain}?";
+"lng_settings_disconnect_block" = "Block {name}";
+"lng_settings_disconnect_all_title" = "Disconnect websites";
+"lng_settings_disconnect_all_sure" = "Are you sure you want to disconnect all websites where you logged in with Telegram?";
+"lng_settings_disconnect" = "Disconnect";
+"lng_settings_connected_title" = "Connected websites";
"lng_settings_power_menu" = "Battery and Animations";
"lng_settings_power_title" = "Power Usage";
@@ -944,6 +966,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_sessions_terminate" = "Terminate Session";
"lng_sessions_application" = "Application";
"lng_sessions_system" = "System version";
+"lng_sessions_browser" = "Browser";
"lng_sessions_ip" = "IP address";
"lng_sessions_location" = "Location";
"lng_sessions_location_about" = "This location is based only on the IP address and may not always be accurate.";
@@ -1789,6 +1812,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_emoji_set_active" = "Current set";
"lng_emoji_set_download" = "Download {size}";
"lng_emoji_set_loading" = "{percent}, {progress}";
+"lng_emoji_color_all" = "Choose color for all emoji";
+"lng_emoji_copy" = "Copy emoji";
+"lng_emoji_view_pack" = "View pack";
+"lng_emoji_remove_recent" = "Remove from recents";
+"lng_emoji_reset_recent" = "Reset recents";
+"lng_emoji_reset_recent_sure" = "Do you want to reset recent emoji?";
+"lng_emoji_reset_recent_button" = "Reset";
"lng_recent_stickers" = "Frequently used";
"lng_faved_stickers_add" = "Add to Favorites";
@@ -1827,6 +1857,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_summary_subtitle_gift#other" = "{user} has gifted you a {count}-months subscription for Telegram Premium.";
"lng_premium_summary_subtitle_gift_me#one" = "You gifted {user} a {count}-month subscription for Telegram Premium.";
"lng_premium_summary_subtitle_gift_me#other" = "You gifted {user} a {count}-months subscription for Telegram Premium.";
+"lng_premium_summary_subtitle_stories" = "Upgraded Stories";
+"lng_premium_summary_about_stories" = "Priority order, stealth mode, permanent views history and more.";
"lng_premium_summary_subtitle_double_limits" = "Doubled Limits";
"lng_premium_summary_about_double_limits" = "Up to 1000 channels, 20 folders, 10 pins, 20 public links, 4 accounts and more.";
"lng_premium_summary_subtitle_more_upload" = "4Gb Upload Size";
@@ -1857,9 +1889,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_summary_bottom_about" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";
"lng_premium_summary_button" = "Subscribe for {cost} per month";
+"lng_premium_summary_new_badge" = "NEW";
+
"lng_premium_success" = "You've successfully subscribed to Telegram Premium!";
"lng_premium_unavailable" = "This feature requires subscription to **Telegram Premium**.\n\nUnfortunately, **Telegram Premium** is not available in your region.";
+// Upgraded Stories.
+"lng_premium_stories_subtitle_order" = "Priority Order";
+"lng_premium_stories_about_order" = "Get more views as your stories are always displayed first.";
+
+"lng_premium_stories_subtitle_stealth" = "Stealth Mode";
+"lng_premium_stories_about_stealth" = "Hide the fact that you viewed other people's stories.";
+
+"lng_premium_stories_subtitle_views" = "Permanent Views History";
+"lng_premium_stories_about_views" = "Check who opens your stories – even after they expire.";
+
+"lng_premium_stories_subtitle_expiration" = "Expiration Durations*";
+"lng_premium_stories_about_expiration" = "Set custom expiration durations like 6 or 48 hours for your stories.";
+
+"lng_premium_stories_subtitle_download" = "Download Stories";
+"lng_premium_stories_about_download" = "Save other people's unprotected stories to your disk.";
+
+"lng_premium_stories_subtitle_caption" = "Longer Captions*";
+"lng_premium_stories_about_caption" = "Add ten times longer captions to your stories – up to 2048 symbols.";
+
+"lng_premium_stories_subtitle_links" = "Links and Formatting*";
+"lng_premium_stories_about_links" = "Add links and formatting in captions of your stories.";
+
+"lng_premium_stories_about_mobile" = "* Available when posting stories from Telegram apps for iOS and Android.";
+
// Doubled Limits.
"lng_premium_double_limits_subtitle_channels" = "Groups and Channels";
"lng_premium_double_limits_about_channels#one" = "Join up to {count} channels and large groups";
@@ -2249,6 +2307,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_archive_to_menu" = "Move to main menu";
"lng_context_archive_to_list" = "Move to chats list";
"lng_context_archive_to_menu_info" = "Archive moved to the main menu!\nYou can return it from the context menu of the archive button.";
+"lng_context_archive_settings" = "Archive settings";
"lng_context_mute" = "Mute";
"lng_context_unmute" = "Unmute";
@@ -3876,6 +3935,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stories_archive_done" = "This story is hidden from your profile.";
"lng_stories_archive_done_many#one" = "{count} story is hidden from your profile.";
"lng_stories_archive_done_many#other" = "{count} stories are hidden from your profile.";
+"lng_stories_save_promo" = "Subscribe to {link} to download other people's unprotected stories to disk.";
+
+"lng_stealth_mode_menu_item" = "Stealth Mode";
+"lng_stealth_mode_title" = "Stealth Mode";
+"lng_stealth_mode_unlock_about" = "Subscribe to Telegram Premium to hide the fact that you viewed peoples' stories from them.";
+"lng_stealth_mode_about" = "Turn Stealth Mode on to hide the fact that you viewed peoples' stories from them.";
+"lng_stealth_mode_past_title" = "Hide Recent Views";
+"lng_stealth_mode_past_about" = "Hide my views in the last 5 minutes.";
+"lng_stealth_mode_next_title" = "Hide Next Views";
+"lng_stealth_mode_next_about" = "Hide my views in the next 25 minutes.";
+"lng_stealth_mode_unlock" = "Unlock Stealth Mode";
+"lng_stealth_mode_enable" = "Enable Stealth Mode";
+"lng_stealth_mode_cooldown_in" = "Available in {left}";
+"lng_stealth_mode_cooldown_tip" = "Please wait until the **Stealth Mode** is ready to use again.";
+"lng_stealth_mode_enabled_tip_title" = "Stealth Mode On";
+"lng_stealth_mode_enabled_tip" = "The creators of stories you viewed in the last **5 minutes** or will view in the next **25 minutes** won't see you in the viewers' lists.";
+"lng_stealth_mode_countdown" = "Stealth Mode active – {left}";
+"lng_stealth_mode_already_title" = "You are in Stealth Mode";
+"lng_stealth_mode_already_about" = "The creators of stories you will view in the next **{left}** won't see you in the viewers' lists.";
"lng_stories_link_invalid" = "This link is broken or has expired.";
diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml
index 0fabf4cf8..15007bceb 100644
--- a/Telegram/Resources/uwp/AppX/AppxManifest.xml
+++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml
@@ -10,7 +10,7 @@
+ Version="4.9.3.0" />
Telegram Desktop
Telegram Messenger LLP
diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc
index 79fe54aee..f13710dae 100644
--- a/Telegram/Resources/winrc/Telegram.rc
+++ b/Telegram/Resources/winrc/Telegram.rc
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 4,8,11,0
- PRODUCTVERSION 4,8,11,0
+ FILEVERSION 4,9,3,0
+ PRODUCTVERSION 4,9,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
- VALUE "FileVersion", "4.8.11.0"
+ VALUE "FileVersion", "4.9.3.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "4.8.11.0"
+ VALUE "ProductVersion", "4.9.3.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc
index 83e9ddab5..197deffe1 100644
--- a/Telegram/Resources/winrc/Updater.rc
+++ b/Telegram/Resources/winrc/Updater.rc
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 4,8,11,0
- PRODUCTVERSION 4,8,11,0
+ FILEVERSION 4,9,3,0
+ PRODUCTVERSION 4,9,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
- VALUE "FileVersion", "4.8.11.0"
+ VALUE "FileVersion", "4.9.3.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "4.8.11.0"
+ VALUE "ProductVersion", "4.9.3.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/SourceFiles/api/api_authorizations.cpp b/Telegram/SourceFiles/api/api_authorizations.cpp
index 6d82a1d11..78e463c11 100644
--- a/Telegram/SourceFiles/api/api_authorizations.cpp
+++ b/Telegram/SourceFiles/api/api_authorizations.cpp
@@ -72,26 +72,9 @@ Authorizations::Entry ParseEntry(const MTPDauthorization &data) {
appName,
appVer.isEmpty() ? QString() : (' ' + appVer));
result.ip = qs(data.vip());
- if (!result.hash) {
- result.active = tr::lng_status_online(tr::now);
- } else {
- const auto now = QDateTime::currentDateTime();
- const auto lastTime = base::unixtime::parse(result.activeTime);
- const auto nowDate = now.date();
- const auto lastDate = lastTime.date();
- if (lastDate == nowDate) {
- result.active = QLocale().toString(
- lastTime.time(),
- QLocale::ShortFormat);
- } else if (lastDate.year() == nowDate.year()
- && lastDate.weekNumber() == nowDate.weekNumber()) {
- result.active = langDayOfWeek(lastDate);
- } else {
- result.active = QLocale().toString(
- lastDate,
- QLocale::ShortFormat);
- }
- }
+ result.active = result.hash
+ ? Authorizations::ActiveDateString(result.activeTime)
+ : tr::lng_status_online(tr::now);
result.location = country;
return result;
@@ -129,16 +112,15 @@ void Authorizations::reload() {
)).done([=](const MTPaccount_Authorizations &result) {
_requestId = 0;
_lastReceived = crl::now();
- result.match([&](const MTPDaccount_authorizations &auths) {
- _ttlDays = auths.vauthorization_ttl_days().v;
- _list = (
- auths.vauthorizations().v
- ) | ranges::views::transform([](const MTPAuthorization &d) {
- return ParseEntry(d.c_authorization());
- }) | ranges::to;
- refreshCallsDisabledHereFromCloud();
- _listChanges.fire({});
- });
+ const auto &data = result.data();
+ _ttlDays = data.vauthorization_ttl_days().v;
+ _list = ranges::views::all(
+ data.vauthorizations().v
+ ) | ranges::views::transform([](const MTPAuthorization &auth) {
+ return ParseEntry(auth.data());
+ }) | ranges::to;
+ refreshCallsDisabledHereFromCloud();
+ _listChanges.fire({});
}).fail([=] {
_requestId = 0;
}).send();
@@ -190,19 +172,21 @@ Authorizations::List Authorizations::list() const {
return _list;
}
-auto Authorizations::listChanges() const
+auto Authorizations::listValue() const
-> rpl::producer {
return rpl::single(
list()
) | rpl::then(
- _listChanges.events() | rpl::map([=] { return list(); }));
+ _listChanges.events() | rpl::map([=] { return list(); })
+ );
}
-rpl::producer Authorizations::totalChanges() const {
+rpl::producer Authorizations::totalValue() const {
return rpl::single(
total()
) | rpl::then(
- _listChanges.events() | rpl::map([=] { return total(); }));
+ _listChanges.events() | rpl::map([=] { return total(); })
+ );
}
void Authorizations::updateTTL(int days) {
@@ -254,6 +238,19 @@ rpl::producer Authorizations::callsDisabledHereChanges() const {
return _callsDisabledHere.changes();
}
+QString Authorizations::ActiveDateString(TimeId active) {
+ const auto now = QDateTime::currentDateTime();
+ const auto lastTime = base::unixtime::parse(active);
+ const auto nowDate = now.date();
+ const auto lastDate = lastTime.date();
+ return (lastDate == nowDate)
+ ? QLocale().toString(lastTime.time(), QLocale::ShortFormat)
+ : (lastDate.year() == nowDate.year()
+ && lastDate.weekNumber() == nowDate.weekNumber())
+ ? langDayOfWeek(lastDate)
+ : QLocale().toString(lastDate, QLocale::ShortFormat);
+}
+
int Authorizations::total() const {
return ranges::count_if(
_list,
diff --git a/Telegram/SourceFiles/api/api_authorizations.h b/Telegram/SourceFiles/api/api_authorizations.h
index 96819edf1..5e2a41c9f 100644
--- a/Telegram/SourceFiles/api/api_authorizations.h
+++ b/Telegram/SourceFiles/api/api_authorizations.h
@@ -38,9 +38,9 @@ public:
[[nodiscard]] crl::time lastReceivedTime();
[[nodiscard]] List list() const;
- [[nodiscard]] rpl::producer listChanges() const;
+ [[nodiscard]] rpl::producer listValue() const;
[[nodiscard]] int total() const;
- [[nodiscard]] rpl::producer totalChanges() const;
+ [[nodiscard]] rpl::producer totalValue() const;
void updateTTL(int days);
[[nodiscard]] rpl::producer ttlDays() const;
@@ -53,6 +53,8 @@ public:
[[nodiscard]] rpl::producer callsDisabledHereValue() const;
[[nodiscard]] rpl::producer callsDisabledHereChanges() const;
+ [[nodiscard]] static QString ActiveDateString(TimeId active);
+
private:
void refreshCallsDisabledHereFromCloud();
diff --git a/Telegram/SourceFiles/api/api_blocked_peers.cpp b/Telegram/SourceFiles/api/api_blocked_peers.cpp
index bf3a061e8..9dfc886b1 100644
--- a/Telegram/SourceFiles/api/api_blocked_peers.cpp
+++ b/Telegram/SourceFiles/api/api_blocked_peers.cpp
@@ -79,6 +79,7 @@ void BlockedPeers::block(not_null peer) {
Data::PeerUpdate::Flag::IsBlocked);
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
const auto requestId = _api.request(MTPcontacts_Block(
+ MTP_flags(0),
peer->input
)).done([=] {
_blockRequests.erase(peer);
@@ -111,6 +112,7 @@ void BlockedPeers::unblock(
return;
}
const auto requestId = _api.request(MTPcontacts_Unblock(
+ MTP_flags(0),
peer->input
)).done([=] {
_blockRequests.erase(peer);
@@ -163,6 +165,7 @@ void BlockedPeers::request(int offset, Fn onDone) {
return;
}
_requestId = _api.request(MTPcontacts_GetBlocked(
+ MTP_flags(0),
MTP_int(offset),
MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice)
)).done([=](const MTPcontacts_Blocked &result) {
diff --git a/Telegram/SourceFiles/api/api_chat_participants.cpp b/Telegram/SourceFiles/api/api_chat_participants.cpp
index aeb7bd0a6..0ee748f2b 100644
--- a/Telegram/SourceFiles/api/api_chat_participants.cpp
+++ b/Telegram/SourceFiles/api/api_chat_participants.cpp
@@ -439,6 +439,7 @@ void ChatParticipants::requestAdmins(not_null channel) {
MTP_int(channel->session().serverConfig().chatSizeMax),
MTP_long(participantsHash)
)).done([=](const MTPchannels_ChannelParticipants &result) {
+ channel->mgInfo->adminsLoaded = true;
_adminsRequests.remove(channel);
result.match([&](const MTPDchannels_channelParticipants &data) {
channel->owner().processUsers(data.vusers());
@@ -448,6 +449,7 @@ void ChatParticipants::requestAdmins(not_null channel) {
"channels.channelParticipantsNotModified received!"));
});
}).fail([=] {
+ channel->mgInfo->adminsLoaded = true;
_adminsRequests.remove(channel);
}).send();
diff --git a/Telegram/SourceFiles/api/api_global_privacy.cpp b/Telegram/SourceFiles/api/api_global_privacy.cpp
index 89e1d57da..219d335f1 100644
--- a/Telegram/SourceFiles/api/api_global_privacy.cpp
+++ b/Telegram/SourceFiles/api/api_global_privacy.cpp
@@ -84,19 +84,29 @@ void GlobalPrivacy::dismissArchiveAndMuteSuggestion() {
u"AUTOARCHIVE_POPULAR"_q);
}
-void GlobalPrivacy::update(bool archiveAndMute) {
+void GlobalPrivacy::updateArchiveAndMute(bool value) {
+ update(value, unarchiveOnNewMessageCurrent());
+}
+
+void GlobalPrivacy::updateUnarchiveOnNewMessage(
+ UnarchiveOnNewMessage value) {
+ update(archiveAndMuteCurrent(), value);
+}
+
+void GlobalPrivacy::update(
+ bool archiveAndMute,
+ UnarchiveOnNewMessage unarchiveOnNewMessage) {
using Flag = MTPDglobalPrivacySettings::Flag;
- const auto unarchive = unarchiveOnNewMessageCurrent();
_api.request(_requestId).cancel();
const auto flags = Flag()
| (archiveAndMute
? Flag::f_archive_and_mute_new_noncontact_peers
: Flag())
- | (unarchive == UnarchiveOnNewMessage::AnyUnmuted
+ | (unarchiveOnNewMessage == UnarchiveOnNewMessage::None
? Flag::f_keep_archived_unmuted
: Flag())
- | (unarchive != UnarchiveOnNewMessage::None
+ | (unarchiveOnNewMessage != UnarchiveOnNewMessage::AnyUnmuted
? Flag::f_keep_archived_folders
: Flag());
_requestId = _api.request(MTPaccount_SetGlobalPrivacySettings(
@@ -108,16 +118,17 @@ void GlobalPrivacy::update(bool archiveAndMute) {
_requestId = 0;
}).send();
_archiveAndMute = archiveAndMute;
+ _unarchiveOnNewMessage = unarchiveOnNewMessage;
}
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
data.match([&](const MTPDglobalPrivacySettings &data) {
_archiveAndMute = data.is_archive_and_mute_new_noncontact_peers();
_unarchiveOnNewMessage = data.is_keep_archived_unmuted()
- ? UnarchiveOnNewMessage::AnyUnmuted
+ ? UnarchiveOnNewMessage::None
: data.is_keep_archived_folders()
? UnarchiveOnNewMessage::NotInFoldersUnmuted
- : UnarchiveOnNewMessage::None;
+ : UnarchiveOnNewMessage::AnyUnmuted;
});
}
diff --git a/Telegram/SourceFiles/api/api_global_privacy.h b/Telegram/SourceFiles/api/api_global_privacy.h
index f569951ca..9e4b8e121 100644
--- a/Telegram/SourceFiles/api/api_global_privacy.h
+++ b/Telegram/SourceFiles/api/api_global_privacy.h
@@ -28,7 +28,8 @@ public:
explicit GlobalPrivacy(not_null api);
void reload(Fn callback = nullptr);
- void update(bool archiveAndMute);
+ void updateArchiveAndMute(bool value);
+ void updateUnarchiveOnNewMessage(UnarchiveOnNewMessage value);
[[nodiscard]] bool archiveAndMuteCurrent() const;
[[nodiscard]] rpl::producer archiveAndMute() const;
@@ -43,6 +44,10 @@ public:
private:
void apply(const MTPGlobalPrivacySettings &data);
+ void update(
+ bool archiveAndMute,
+ UnarchiveOnNewMessage unarchiveOnNewMessage);
+
const not_null _session;
MTP::Sender _api;
mtpRequestId _requestId = 0;
diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp
index 31462da39..58f5e08f4 100644
--- a/Telegram/SourceFiles/api/api_updates.cpp
+++ b/Telegram/SourceFiles/api/api_updates.cpp
@@ -2017,7 +2017,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
case mtpc_updatePeerBlocked: {
const auto &d = update.c_updatePeerBlocked();
if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer_id()))) {
- peer->setIsBlocked(mtpIsTrue(d.vblocked()));
+ peer->setIsBlocked(d.is_blocked());
}
} break;
@@ -2558,6 +2558,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
_session->data().stories().apply(update.c_updateReadStories());
} break;
+ case mtpc_updateStoriesStealthMode: {
+ const auto &data = update.c_updateStoriesStealthMode();
+ _session->data().stories().apply(data.vstealth_mode());
+ } break;
+
}
}
diff --git a/Telegram/SourceFiles/api/api_websites.cpp b/Telegram/SourceFiles/api/api_websites.cpp
new file mode 100644
index 000000000..855056675
--- /dev/null
+++ b/Telegram/SourceFiles/api/api_websites.cpp
@@ -0,0 +1,138 @@
+/*
+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 "api/api_websites.h"
+
+#include "api/api_authorizations.h"
+#include "api/api_blocked_peers.h"
+#include "apiwrap.h"
+#include "data/data_session.h"
+#include "data/data_user.h"
+#include "main/main_session.h"
+
+namespace Api {
+namespace {
+
+constexpr auto TestApiId = 17349;
+constexpr auto SnapApiId = 611335;
+constexpr auto DesktopApiId = 2040;
+
+Websites::Entry ParseEntry(
+ not_null owner,
+ const MTPDwebAuthorization &data) {
+ auto result = Websites::Entry{
+ .hash = data.vhash().v,
+ .bot = owner->user(data.vbot_id()),
+ .platform = qs(data.vplatform()),
+ .domain = qs(data.vdomain()),
+ .browser = qs(data.vbrowser()),
+ .ip = qs(data.vip()),
+ .location = qs(data.vregion()),
+ };
+ result.activeTime = data.vdate_active().v
+ ? data.vdate_active().v
+ : data.vdate_created().v;
+ result.active = Authorizations::ActiveDateString(result.activeTime);
+ return result;
+}
+
+} // namespace
+
+Websites::Websites(not_null api)
+: _session(&api->session())
+, _api(&api->instance()) {
+}
+
+void Websites::reload() {
+ if (_requestId) {
+ return;
+ }
+
+ _requestId = _api.request(MTPaccount_GetWebAuthorizations(
+ )).done([=](const MTPaccount_WebAuthorizations &result) {
+ _requestId = 0;
+ _lastReceived = crl::now();
+ const auto owner = &_session->data();
+ const auto &data = result.data();
+ owner->processUsers(data.vusers());
+ _list = ranges::views::all(
+ data.vauthorizations().v
+ ) | ranges::views::transform([&](const MTPwebAuthorization &auth) {
+ return ParseEntry(owner, auth.data());
+ }) | ranges::to;
+ _listChanges.fire({});
+ }).fail([=] {
+ _requestId = 0;
+ }).send();
+}
+
+void Websites::cancelCurrentRequest() {
+ _api.request(base::take(_requestId)).cancel();
+}
+
+void Websites::requestTerminate(
+ Fn &&done,
+ Fn &&fail,
+ std::optional hash,
+ UserData *botToBlock) {
+ const auto send = [&](auto request) {
+ _api.request(
+ std::move(request)
+ ).done([=, done = std::move(done)](const MTPBool &result) {
+ done(result);
+ if (hash) {
+ _list.erase(
+ ranges::remove(_list, *hash, &Entry::hash),
+ end(_list));
+ } else {
+ _list.clear();
+ }
+ _listChanges.fire({});
+ }).fail(
+ std::move(fail)
+ ).send();
+ };
+ if (hash) {
+ send(MTPaccount_ResetWebAuthorization(MTP_long(*hash)));
+ if (botToBlock) {
+ botToBlock->session().api().blockedPeers().block(botToBlock);
+ }
+ } else {
+ send(MTPaccount_ResetWebAuthorizations());
+ }
+}
+
+Websites::List Websites::list() const {
+ return _list;
+}
+
+auto Websites::listValue() const
+-> rpl::producer {
+ return rpl::single(
+ list()
+ ) | rpl::then(
+ _listChanges.events() | rpl::map([=] { return list(); })
+ );
+}
+
+rpl::producer Websites::totalValue() const {
+ return rpl::single(
+ total()
+ ) | rpl::then(
+ _listChanges.events() | rpl::map([=] { return total(); })
+ );
+}
+
+int Websites::total() const {
+ return _list.size();
+}
+
+crl::time Websites::lastReceivedTime() {
+ return _lastReceived;
+}
+
+} // namespace Api
diff --git a/Telegram/SourceFiles/api/api_websites.h b/Telegram/SourceFiles/api/api_websites.h
new file mode 100644
index 000000000..1551ae4d4
--- /dev/null
+++ b/Telegram/SourceFiles/api/api_websites.h
@@ -0,0 +1,62 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+#include "mtproto/sender.h"
+
+class ApiWrap;
+
+namespace Main {
+class Session;
+} // namespace Main
+
+namespace Api {
+
+class Websites final {
+public:
+ explicit Websites(not_null api);
+
+ struct Entry {
+ uint64 hash = 0;
+
+ not_null bot;
+ TimeId activeTime = 0;
+ QString active, platform, domain, browser, ip, location;
+ };
+ using List = std::vector;
+
+ void reload();
+ void cancelCurrentRequest();
+ void requestTerminate(
+ Fn &&done,
+ Fn &&fail,
+ std::optional hash = std::nullopt,
+ UserData *botToBlock = nullptr);
+
+ [[nodiscard]] crl::time lastReceivedTime();
+
+ [[nodiscard]] List list() const;
+ [[nodiscard]] rpl::producer listValue() const;
+ [[nodiscard]] int total() const;
+ [[nodiscard]] rpl::producer totalValue() const;
+
+private:
+ not_null _session;
+
+ MTP::Sender _api;
+ mtpRequestId _requestId = 0;
+
+ List _list;
+ rpl::event_stream<> _listChanges;
+
+ crl::time _lastReceived = 0;
+ rpl::lifetime _lifetime;
+
+};
+
+} // namespace Api
diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 5772b06c5..fec04ea1d 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_transcribes.h"
#include "api/api_premium.h"
#include "api/api_user_names.h"
+#include "api/api_websites.h"
#include "data/notify/data_notify_settings.h"
#include "data/stickers/data_stickers.h"
#include "data/data_drafts.h"
@@ -178,7 +179,8 @@ ApiWrap::ApiWrap(not_null session)
, _ringtones(std::make_unique(this))
, _transcribes(std::make_unique(this))
, _premium(std::make_unique(this))
-, _usernames(std::make_unique(this)) {
+, _usernames(std::make_unique(this))
+, _websites(std::make_unique(this)) {
crl::on_main(session, [=] {
// You can't use _session->lifetime() in the constructor,
// only queued, because it is not constructed yet.
@@ -4330,3 +4332,7 @@ Api::Premium &ApiWrap::premium() {
Api::Usernames &ApiWrap::usernames() {
return *_usernames;
}
+
+Api::Websites &ApiWrap::websites() {
+ return *_websites;
+}
diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h
index 5815fd3c0..954500f76 100644
--- a/Telegram/SourceFiles/apiwrap.h
+++ b/Telegram/SourceFiles/apiwrap.h
@@ -80,6 +80,7 @@ class Ringtones;
class Transcribes;
class Premium;
class Usernames;
+class Websites;
namespace details {
@@ -383,6 +384,7 @@ public:
[[nodiscard]] Api::Transcribes &transcribes();
[[nodiscard]] Api::Premium &premium();
[[nodiscard]] Api::Usernames &usernames();
+ [[nodiscard]] Api::Websites &websites();
void updatePrivacyLastSeens();
@@ -693,6 +695,7 @@ private:
const std::unique_ptr _transcribes;
const std::unique_ptr _premium;
const std::unique_ptr _usernames;
+ const std::unique_ptr _websites;
mtpRequestId _wallPaperRequestId = 0;
QString _wallPaperSlug;
diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style
index 00862eada..b952e5a6e 100644
--- a/Telegram/SourceFiles/boxes/boxes.style
+++ b/Telegram/SourceFiles/boxes/boxes.style
@@ -53,12 +53,12 @@ boxPhotoCaptionSkip: 8px;
defaultChangeUserpicIcon: icon {{ "new_chat_photo", activeButtonFg }};
defaultUploadUserpicIcon: icon {{ "upload_chat_photo", msgDateImgFg }};
defaultUserpicButton: UserpicButton {
- size: size(76px, 76px);
- photoSize: 76px;
+ size: size(72px, 72px);
+ photoSize: 72px;
photoPosition: point(-1px, -1px);
changeButton: defaultActiveButton;
changeIcon: defaultChangeUserpicIcon;
- changeIconPosition: point(23px, 25px);
+ changeIconPosition: point(21px, 23px);
duration: 500;
uploadHeight: 24px;
uploadBg: msgDateImgBgOver;
diff --git a/Telegram/SourceFiles/boxes/choose_filter_box.cpp b/Telegram/SourceFiles/boxes/choose_filter_box.cpp
index 416b30ff1..181dccb1e 100644
--- a/Telegram/SourceFiles/boxes/choose_filter_box.cpp
+++ b/Telegram/SourceFiles/boxes/choose_filter_box.cpp
@@ -70,8 +70,6 @@ void ChangeFilterById(
MTP_int(filter.id()),
filter.tl()
)).done([=, chat = history->peer->name(), name = filter.title()] {
- // Since only the primary window has dialogs list,
- // We can safely show toast there.
const auto account = &history->session().account();
if (const auto controller = Core::App().windowFor(account)) {
controller->showToast((add
@@ -120,17 +118,19 @@ bool ChooseFilterValidator::canRemove(FilterId filterId) const {
}
ChooseFilterValidator::LimitData ChooseFilterValidator::limitReached(
- FilterId filterId) const {
+ FilterId filterId,
+ bool always) const {
Expects(filterId != 0);
const auto list = _history->owner().chatsFilters().list();
const auto i = ranges::find(list, filterId, &Data::ChatFilter::id);
const auto limit = _history->owner().pinnedChatsLimit(filterId);
+ const auto &chatsList = always ? i->always() : i->never();
return {
.reached = (i != end(list))
- && !ranges::contains(i->always(), _history)
- && (i->always().size() >= limit),
- .count = int(i->always().size()),
+ && !ranges::contains(chatsList, _history)
+ && (chatsList.size() >= limit),
+ .count = int(chatsList.size()),
};
}
@@ -156,18 +156,21 @@ void FillChooseFilterMenu(
const auto contains = filter.contains(history);
const auto action = menu->addAction(filter.title(), [=] {
- if (filter.contains(history)) {
- if (validator.canRemove(id)) {
- validator.remove(id);
- }
- } else if (const auto r = validator.limitReached(id); r.reached) {
+ const auto toAdd = !filter.contains(history);
+ const auto r = validator.limitReached(id, toAdd);
+ if (r.reached) {
controller->show(Box(
FilterChatsLimitBox,
&controller->session(),
r.count,
- true));
- } else if (validator.canAdd()) {
- validator.add(id);
+ toAdd));
+ return;
+ } else if (toAdd ? validator.canAdd() : validator.canRemove(id)) {
+ if (toAdd) {
+ validator.add(id);
+ } else {
+ validator.remove(id);
+ }
}
}, contains ? &st::mediaPlayerMenuCheck : nullptr);
action->setEnabled(contains
diff --git a/Telegram/SourceFiles/boxes/choose_filter_box.h b/Telegram/SourceFiles/boxes/choose_filter_box.h
index 8e32b267c..e6c5ad335 100644
--- a/Telegram/SourceFiles/boxes/choose_filter_box.h
+++ b/Telegram/SourceFiles/boxes/choose_filter_box.h
@@ -27,7 +27,9 @@ public:
[[nodiscard]] bool canAdd() const;
[[nodiscard]] bool canRemove(FilterId filterId) const;
- [[nodiscard]] LimitData limitReached(FilterId filterId) const;
+ [[nodiscard]] LimitData limitReached(
+ FilterId filterId,
+ bool always) const;
void add(FilterId filterId) const;
void remove(FilterId filterId) const;
diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
index c9779b1f1..90a989ce7 100644
--- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
@@ -517,7 +517,8 @@ void EditCaptionBox::setInitialText() {
_field->setTextCursor(cursor);
_checkChangedTimer.setCallback([=] {
- if (_field->getTextWithAppliedMarkdown() == _initialText) {
+ if (_field->getTextWithAppliedMarkdown() == _initialText
+ && _preparedList.files.empty()) {
setCloseByOutsideClick(true);
}
});
@@ -738,6 +739,7 @@ bool EditCaptionBox::setPreparedList(Ui::PreparedList &&list) {
const auto wasSpoiler = hasSpoiler();
_preparedList = std::move(list);
_preparedList.files.front().spoiler = wasSpoiler;
+ setCloseByOutsideClick(false);
rebuildPreview();
return true;
}
diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp
index 51be4cd11..e5c601881 100644
--- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp
@@ -291,24 +291,17 @@ void EditPrivacyBox::setupContent() {
return Settings::ExceptionUsersCount(exceptions(exception));
}));
auto text = _controller->exceptionButtonTextKey(exception);
- const auto always = (exception == Exception::Always);
const auto button = content->add(
object_ptr>(
content,
CreateButton(
content,
rpl::duplicate(text),
- st::settingsButton,
- {
- (always
- ? &st::settingsIconPlus
- : &st::settingsIconMinus),
- always ? kIconGreen : kIconRed,
- })));
+ st::settingsButtonNoIcon)));
CreateRightLabel(
button->entity(),
std::move(label),
- st::settingsButton,
+ st::settingsButtonNoIcon,
std::move(text));
button->toggleOn(rpl::duplicate(
optionValue
@@ -384,9 +377,9 @@ void EditPrivacyBox::setupContent() {
});
addButton(tr::lng_cancel(), [this] { closeBox(); });
- const auto linkHeight = st::settingsButton.padding.top()
- + st::settingsButton.height
- + st::settingsButton.padding.bottom();
+ const auto linkHeight = st::settingsButtonNoIcon.padding.top()
+ + st::settingsButtonNoIcon.height
+ + st::settingsButtonNoIcon.padding.bottom();
widthValue(
) | rpl::start_with_next([=](int width) {
diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp
index 724dd7c47..88bbdca03 100644
--- a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp
+++ b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp
@@ -666,7 +666,7 @@ void EditFilterBox(
content,
tr::lng_filters_add_chats(),
st::settingsButtonActive,
- { &st::settingsIconAdd, 0, IconType::Round, &st::windowBgActive });
+ { &st::settingsIconAdd, IconType::Round, &st::windowBgActive });
const auto include = SetupChatsPreview(
content,
@@ -693,7 +693,7 @@ void EditFilterBox(
excludeInner,
tr::lng_filters_remove_chats(),
st::settingsButtonActive,
- { &st::settingsIconRemove, 0, IconType::Round, &st::windowBgActive });
+ { &st::settingsIconRemove, IconType::Round, &st::windowBgActive });
const auto exclude = SetupChatsPreview(
excludeInner,
@@ -746,13 +746,13 @@ void EditFilterBox(
state->hasLinks.value() | rpl::map(!rpl::mappers::_1),
tr::lng_filters_link_create(),
st::settingsButtonActive,
- { &st::settingsFolderShareIcon, 0, IconType::Simple });
+ { &st::settingsFolderShareIcon, IconType::Simple });
const auto addLink = AddToggledButton(
content,
state->hasLinks.value(),
tr::lng_group_invite_add(),
st::settingsButtonActive,
- { &st::settingsIconAdd, 0, IconType::Round, &st::windowBgActive });
+ { &st::settingsIconAdd, IconType::Round, &st::windowBgActive });
SetupFilterLinks(
content,
diff --git a/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp
index 9727f6c61..d5dbc6789 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp
@@ -354,6 +354,7 @@ struct IconSelector {
&owner->reactions(),
std::move(args),
[=] { state->animation->repaint(); },
+ [] { return st::windowFg->c; },
Data::CustomEmojiSizeTag::Large);
}
state->iconId = id;
diff --git a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp
index 9e0bfa2d9..48bc383c9 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp
@@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "ui/wrap/vertical_layout.h"
-#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
+#include "ui/text/text_utilities.h" // Ui::Text::RichLangValue
#include "boxes/peer_list_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/add_contact_box.h"
@@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "window/window_session_controller.h"
#include "styles/style_layers.h"
+#include "styles/style_menu_icons.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h"
#include "styles/style_settings.h"
@@ -271,7 +272,7 @@ void Controller::choose(not_null chat) {
above,
tr::lng_manage_discussion_group_create(),
st::infoCreateLinkedChatButton,
- { &st::settingsIconChat, Settings::kIconLightBlue }
+ { &st::menuIconGroupCreate }
)->addClickHandler([=, parent = above.data()] {
const auto guarded = crl::guard(parent, callback);
navigation->uiShow()->showBox(Box(
@@ -291,7 +292,7 @@ void Controller::choose(not_null chat) {
? tr::lng_manage_discussion_group_unlink
: tr::lng_manage_linked_channel_unlink)(),
st::infoUnlinkChatButton,
- { &st::settingsIconMinus, Settings::kIconRed }
+ { &st::menuIconRemove }
)->addClickHandler([=] { callback(nullptr); });
Settings::AddSkip(below);
}
diff --git a/Telegram/SourceFiles/boxes/peers/edit_members_visible.cpp b/Telegram/SourceFiles/boxes/peers/edit_members_visible.cpp
index 5ef44326a..ed0a363a2 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_members_visible.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_members_visible.cpp
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "lang/lang_keys.h"
#include "styles/style_info.h"
+#include "styles/style_menu_icons.h"
namespace {
@@ -52,8 +53,8 @@ namespace {
tr::lng_profile_hide_participants(),
rpl::single(QString()),
[] {},
- st::manageGroupTopicsButton,
- { &st::infoRoundedIconHideMembers, Settings::kIconDarkBlue }
+ st::manageGroupNoIconButton,
+ {}
))->toggleOn(rpl::single(
(megagroup->flags() & ChannelDataFlag::ParticipantsHidden) != 0
) | rpl::then(state->toggled.events()));
diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp
index e1d09efec..425e21c75 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp
@@ -1505,6 +1505,11 @@ void ParticipantsBoxController::loadMoreRows() {
LOG(("API Error: "
"channels.channelParticipantsNotModified received!"));
});
+ if (_offset > 0 && _role == Role::Admins && channel->isMegagroup()) {
+ if (channel->mgInfo->admins.empty() && channel->mgInfo->adminsLoaded) {
+ channel->mgInfo->adminsLoaded = false;
+ }
+ }
if (!firstLoad && !added) {
_allLoaded = true;
}
@@ -1679,7 +1684,7 @@ base::unique_qptr ParticipantsBoxController::rowContextMenu(
result->addAction(
tr::lng_context_restrict_user(tr::now),
crl::guard(this, [=] { showRestricted(user); }),
- &st::menuIconRestrict);
+ &st::menuIconPermissions);
}
}
if (user && _additional.canRemoveParticipant(participant)) {
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
index febf08ed6..01251e1f8 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
@@ -61,6 +61,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/profile/info_profile_icon.h"
#include "api/api_invite_links.h"
#include "styles/style_layers.h"
+#include "styles/style_menu_icons.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h"
#include "styles/style_settings.h"
@@ -307,11 +308,9 @@ private:
void fillPendingRequestsButton();
void fillBotUsernamesButton();
-#if 0 // Enable after design improvements.
void fillBotEditIntroButton();
void fillBotEditCommandsButton();
void fillBotEditSettingsButton();
-#endif
void submitTitle();
void submitDescription();
@@ -348,9 +347,7 @@ private:
void continueSave();
void cancelSave();
-#if 0 // Enable after design improvements.
void toggleBotManager(const QString &command);
-#endif
void togglePreHistoryHidden(
not_null channel,
@@ -605,7 +602,7 @@ object_ptr Controller::createStickersEdit() {
controller->show(
Box(controller->uiShow(), channel));
},
- { &st::settingsIconStickers, Settings::kIconLightOrange });
+ { &st::menuIconStickers });
Settings::AddSkip(container, bottomSkip);
@@ -770,9 +767,6 @@ void Controller::fillPrivacyTypeButton() {
&& _peer->asChannel()->requestToJoin()),
};
const auto isGroup = (_peer->isChat() || _peer->isMegagroup());
- const auto icon = isGroup
- ? &st::settingsIconGroup
- : &st::settingsIconChannel;
AddButtonWithText(
_controls.buttonsLayout,
(hasLocation
@@ -798,7 +792,7 @@ void Controller::fillPrivacyTypeButton() {
: tr::lng_manage_private_peer_title)();
}) | rpl::flatten_latest(),
[=] { showEditPeerTypeBox(); },
- { icon, Settings::kIconLightBlue });
+ { &st::menuIconCustomize });
_privacyTypeUpdates.fire_copy(_typeDataSavedValue->privacy);
}
@@ -839,7 +833,7 @@ void Controller::fillLinkedChatButton() {
std::move(text),
std::move(label),
[=] { showEditLinkedChatBox(); },
- { &st::settingsIconChat, Settings::kIconGreen });
+ { isGroup ? &st::menuIconChannel : &st::menuIconGroups });
_linkedChatUpdates.fire_copy(*_linkedChatSavedValue);
}
//
@@ -867,7 +861,7 @@ void Controller::fillForumButton() {
rpl::single(QString()),
[] {},
st::manageGroupTopicsButton,
- { &st::settingsIconTopics, Settings::kIconPurple }));
+ { &st::menuIconTopics }));
const auto unlocks = std::make_shared>();
button->toggleOn(
rpl::single(_peer->isForum()) | rpl::then(unlocks->events())
@@ -924,7 +918,7 @@ void Controller::fillSignaturesButton() {
tr::lng_edit_sign_messages(),
rpl::single(QString()),
[] {},
- { &st::infoRoundedIconSignature, Settings::kIconLightBlue }
+ { &st::menuIconSigned }
)->toggleOn(rpl::single(channel->addsSignature())
)->toggledValue(
) | rpl::start_with_next([=](bool toggled) {
@@ -986,7 +980,7 @@ void Controller::fillHistoryVisibilityButton() {
: tr::lng_manage_history_visibility_hidden)();
}) | rpl::flatten_latest(),
buttonCallback,
- { &st::settingsIconChat, Settings::kIconGreen });
+ { &st::menuIconChatBubble });
updateHistoryVisibility->fire_copy(*_historyVisibilitySavedValue);
@@ -1001,11 +995,9 @@ void Controller::fillManageSection() {
AddSkip(container, 0);
fillBotUsernamesButton();
-#if 0 // Enable after design improvements.
fillBotEditIntroButton();
fillBotEditCommandsButton();
fillBotEditSettingsButton();
-#endif
Settings::AddSkip(
container,
st::editPeerTopButtonsLayoutSkipCustomBottom);
@@ -1126,10 +1118,7 @@ void Controller::fillManageSection() {
//|| canEditInviteLinks
|| canViewOrEditLinkedChat
|| canEditType) {
- AddSkip(
- _controls.buttonsLayout,
- st::editPeerTopButtonsLayoutSkip,
- st::editPeerTopButtonsLayoutSkipCustomBottom);
+ AddSkip(_controls.buttonsLayout);
}
if (canEditReactions()) {
@@ -1174,7 +1163,7 @@ void Controller::fillManageSection() {
Data::PeerAllowedReactions(_peer),
done));
},
- { &st::infoRoundedIconReactions, Settings::kIconRed });
+ { &st::menuIconGroupReactions });
}
if (canEditPermissions) {
AddButtonWithCount(
@@ -1193,7 +1182,7 @@ void Controller::fillManageSection() {
});
}) | rpl::flatten_latest(),
[=] { ShowEditPermissions(_navigation, _peer); },
- { &st::settingsIconKey, Settings::kIconGreen });
+ { &st::menuIconPermissions });
}
if (canEditInviteLinks) {
auto count = Info::Profile::MigratedOrMeValue(
@@ -1227,7 +1216,7 @@ void Controller::fillManageSection() {
0,
0));
},
- { &st::infoRoundedIconInviteLinks, Settings::kIconLightOrange });
+ { &st::menuIconLinks });
wrap->toggle(true, anim::type::instant);
}
if (canViewAdmins) {
@@ -1246,7 +1235,7 @@ void Controller::fillManageSection() {
_peer,
ParticipantsBoxController::Role::Admins);
},
- { &st::infoRoundedIconAdministrators, Settings::kIconLightBlue });
+ { &st::menuIconAdmin });
}
if (canViewMembers) {
AddButtonWithCount(
@@ -1266,7 +1255,7 @@ void Controller::fillManageSection() {
_peer,
ParticipantsBoxController::Role::Members);
},
- { &st::settingsIconGroup, Settings::kIconDarkBlue });
+ { &st::menuIconGroups });
}
fillPendingRequestsButton();
@@ -1283,7 +1272,7 @@ void Controller::fillManageSection() {
_peer,
ParticipantsBoxController::Role::Kicked);
},
- { &st::settingsIconMinus, Settings::kIconRed });
+ { &st::menuIconRemove });
}
if (hasRecentActions) {
auto callback = [=] {
@@ -1295,12 +1284,11 @@ void Controller::fillManageSection() {
tr::lng_manage_peer_recent_actions(),
rpl::single(QString()), //Empty count.
std::move(callback),
- { &st::infoRoundedIconRecentActions, Settings::kIconPurple });
+ { &st::menuIconGroupLog });
}
if (canEditStickers || canDeleteChannel) {
- AddSkip(_controls.buttonsLayout,
- st::editPeerTopButtonsLayoutSkipCustomTop);
+ AddSkip(_controls.buttonsLayout);
}
if (canEditStickers) {
@@ -1316,6 +1304,10 @@ void Controller::fillManageSection() {
[=]{ deleteWithConfirmation(); }
);
}
+
+ if (canEditStickers || canDeleteChannel) {
+ AddSkip(_controls.buttonsLayout);
+ }
}
void Controller::fillPendingRequestsButton() {
@@ -1337,7 +1329,7 @@ void Controller::fillPendingRequestsButton() {
: tr::lng_manage_peer_requests_channel()),
rpl::duplicate(pendingRequestsCount) | ToPositiveNumberString(),
[=] { RequestsBoxController::Start(_navigation, _peer); },
- { &st::infoRoundedIconRequests, Settings::kIconRed });
+ { &st::menuIconInvite });
std::move(
pendingRequestsCount
) | rpl::start_with_next([=](int count) {
@@ -1396,10 +1388,9 @@ void Controller::fillBotUsernamesButton() {
[=] {
_navigation->uiShow()->showBox(Box(UsernamesBox, user));
},
- { &st::infoRoundedIconInviteLinks, Settings::kIconLightOrange });
+ { &st::menuIconLinks });
}
-#if 0 // Enable after design improvements.
void Controller::fillBotEditIntroButton() {
Expects(_isBot);
@@ -1409,7 +1400,7 @@ void Controller::fillBotEditIntroButton() {
tr::lng_manage_peer_bot_edit_intro(),
rpl::never(),
[=] { toggleBotManager(u"%1-intro"_q.arg(user->username())); },
- { &st::settingsIconChat, Settings::kIconLightBlue });
+ { &st::menuIconEdit });
}
void Controller::fillBotEditCommandsButton() {
@@ -1421,7 +1412,7 @@ void Controller::fillBotEditCommandsButton() {
tr::lng_manage_peer_bot_edit_commands(),
rpl::never(),
[=] { toggleBotManager(u"%1-commands"_q.arg(user->username())); },
- { &st::settingsIconChat, Settings::kIconLightBlue });
+ { &st::menuIconBotCommands });
}
void Controller::fillBotEditSettingsButton() {
@@ -1433,9 +1424,8 @@ void Controller::fillBotEditSettingsButton() {
tr::lng_manage_peer_bot_edit_settings(),
rpl::never(),
[=] { toggleBotManager(user->username()); },
- { &st::settingsIconChat, Settings::kIconLightBlue });
+ { &st::menuIconSettings });
}
-#endif
void Controller::submitTitle() {
Expects(_controls.title != nullptr);
@@ -1910,7 +1900,6 @@ void Controller::saveHistoryVisibility() {
[=] { cancelSave(); });
}
-#if 0 // Enable after design improvements.
void Controller::toggleBotManager(const QString &command) {
const auto controller = _navigation->parentController();
_api.request(MTPcontacts_ResolveUsername(
@@ -1926,7 +1915,6 @@ void Controller::toggleBotManager(const QString &command) {
}
}).send();
}
-#endif
void Controller::togglePreHistoryHidden(
not_null channel,
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp
index 420d5dc52..4c33b38fc 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp
@@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h"
+#include "styles/style_menu_icons.h"
#include "styles/style_window.h"
#include "styles/style_settings.h"
@@ -402,7 +403,7 @@ not_null AddInnerToggle(
(s.height() - label->height()) / 2);
arrow->moveToLeft(
std::min(
- labelLeft + label->naturalWidth(),
+ labelLeft + label->textMaxWidth(),
labelRight - arrow->width()),
(s.height() - arrow->height()) / 2);
}, button->lifetime());
@@ -818,7 +819,7 @@ void AddSuggestGigagroup(
rpl::single(QString()),
std::move(callback),
st::manageGroupTopicsButton,
- { &st::settingsIconAskQuestion, Settings::kIconGreen }));
+ { &st::menuIconChatDiscuss }));
container->add(
object_ptr(
@@ -854,7 +855,7 @@ void AddBannedButtons(
ParticipantsBoxController::Role::Restricted);
},
st::manageGroupTopicsButton,
- { &st::settingsIconKey, Settings::kIconLightOrange }));
+ { &st::menuIconPermissions }));
if (channel) {
container->add(EditPeerInfoBox::CreateButton(
container,
@@ -868,7 +869,7 @@ void AddBannedButtons(
ParticipantsBoxController::Role::Kicked);
},
st::manageGroupTopicsButton,
- { &st::settingsIconMinus, Settings::kIconRed }));
+ { &st::menuIconRemove }));
}
}
diff --git a/Telegram/SourceFiles/boxes/premium_preview_box.cpp b/Telegram/SourceFiles/boxes/premium_preview_box.cpp
index 20581a726..6505e31e6 100644
--- a/Telegram/SourceFiles/boxes/premium_preview_box.cpp
+++ b/Telegram/SourceFiles/boxes/premium_preview_box.cpp
@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/padding_wrap.h"
#include "ui/boxes/confirm_box.h"
#include "ui/painter.h"
+#include "settings/settings_common.h"
#include "settings/settings_premium.h"
#include "lottie/lottie_single_player.h"
#include "history/view/media/history_view_sticker.h"
@@ -92,6 +93,10 @@ void PreloadSticker(const std::shared_ptr &media) {
[[nodiscard]] rpl::producer SectionTitle(PremiumPreview section) {
switch (section) {
+ case PremiumPreview::Stories:
+ return tr::lng_premium_summary_subtitle_stories();
+ case PremiumPreview::DoubleLimits:
+ return tr::lng_premium_summary_subtitle_double_limits();
case PremiumPreview::MoreUpload:
return tr::lng_premium_summary_subtitle_more_upload();
case PremiumPreview::FasterDownload:
@@ -122,6 +127,10 @@ void PreloadSticker(const std::shared_ptr &media) {
[[nodiscard]] rpl::producer SectionAbout(PremiumPreview section) {
switch (section) {
+ case PremiumPreview::Stories:
+ return tr::lng_premium_summary_about_stories();
+ case PremiumPreview::DoubleLimits:
+ return tr::lng_premium_summary_about_double_limits();
case PremiumPreview::MoreUpload:
return tr::lng_premium_summary_about_more_upload();
case PremiumPreview::FasterDownload:
@@ -1117,6 +1126,56 @@ void Show(std::shared_ptr show, QImage back) {
}
}
+void DecorateListPromoBox(
+ not_null box,
+ std::shared_ptr show,
+ const Descriptor &descriptor) {
+ const auto session = &show->session();
+
+ box->addTopButton(st::boxTitleClose, [=] {
+ box->closeBox();
+ });
+
+ Data::AmPremiumValue(
+ session
+ ) | rpl::skip(1) | rpl::start_with_next([=] {
+ box->closeBox();
+ }, box->lifetime());
+
+ if (const auto &hidden = descriptor.hiddenCallback) {
+ box->boxClosing() | rpl::start_with_next(hidden, box->lifetime());
+ }
+
+ if (session->premium()) {
+ box->addButton(tr::lng_close(), [=] {
+ box->closeBox();
+ });
+ } else {
+ const auto button = Settings::CreateSubscribeButton({
+ .parent = box,
+ .computeRef = [] { return u"double_limits"_q; },
+ .show = show,
+ });
+
+ box->setShowFinishedCallback([=] {
+ button->startGlareAnimation();
+ });
+
+ box->setStyle(st::premiumPreviewDoubledLimitsBox);
+ box->widthValue(
+ ) | rpl::start_with_next([=](int width) {
+ const auto &padding =
+ st::premiumPreviewDoubledLimitsBox.buttonPadding;
+ button->resizeToWidth(width
+ - padding.left()
+ - padding.right());
+ button->moveToLeft(padding.left(), padding.top());
+ }, button->lifetime());
+ box->addButton(
+ object_ptr::fromRaw(button));
+ }
+}
+
void Show(
std::shared_ptr show,
Descriptor &&descriptor) {
@@ -1128,6 +1187,18 @@ void Show(
descriptor.shownCallback(raw);
}
return;
+ } else if (descriptor.section == PremiumPreview::DoubleLimits) {
+ show->showBox(Box([=](not_null box) {
+ DoubledLimitsPreviewBox(box, &show->session());
+ DecorateListPromoBox(box, show, descriptor);
+ }));
+ return;
+ } else if (descriptor.section == PremiumPreview::Stories) {
+ show->showBox(Box([=](not_null box) {
+ UpgradedStoriesPreviewBox(box, &show->session());
+ DecorateListPromoBox(box, show, descriptor);
+ }));
+ return;
}
auto &list = Preloads();
for (auto i = begin(list); i != end(list);) {
@@ -1240,11 +1311,13 @@ void PremiumUnavailableBox(not_null box) {
void DoubledLimitsPreviewBox(
not_null box,
not_null session) {
+ box->setTitle(tr::lng_premium_summary_subtitle_double_limits());
+
const auto limits = Data::PremiumLimits(session);
auto entries = std::vector();
{
const auto premium = limits.channelsPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_channels(),
tr::lng_premium_double_limits_about_channels(
lt_count,
@@ -1256,7 +1329,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.dialogsPinnedPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_pins(),
tr::lng_premium_double_limits_about_pins(
lt_count,
@@ -1268,7 +1341,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.channelsPublicPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_links(),
tr::lng_premium_double_limits_about_links(
lt_count,
@@ -1280,7 +1353,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.gifsPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_gifs(),
tr::lng_premium_double_limits_about_gifs(
lt_count,
@@ -1292,7 +1365,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.stickersFavedPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_stickers(),
tr::lng_premium_double_limits_about_stickers(
lt_count,
@@ -1304,7 +1377,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.aboutLengthPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_bio(),
tr::lng_premium_double_limits_about_bio(
Ui::Text::RichLangValue),
@@ -1314,7 +1387,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.captionLengthPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_captions(),
tr::lng_premium_double_limits_about_captions(
Ui::Text::RichLangValue),
@@ -1324,7 +1397,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.dialogFiltersPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_folders(),
tr::lng_premium_double_limits_about_folders(
lt_count,
@@ -1336,7 +1409,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.dialogFiltersChatsPremium();
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_folder_chats(),
tr::lng_premium_double_limits_about_folder_chats(
lt_count,
@@ -1350,7 +1423,7 @@ void DoubledLimitsPreviewBox(
const auto till = (nextMax >= Main::Domain::kPremiumMaxAccounts)
? QString::number(Main::Domain::kPremiumMaxAccounts)
: (QString::number(nextMax) + QChar('+'));
- entries.push_back(Ui::Premium::ListEntry{
+ entries.push_back({
tr::lng_premium_double_limits_subtitle_accounts(),
tr::lng_premium_double_limits_about_accounts(
lt_count,
@@ -1366,6 +1439,60 @@ void DoubledLimitsPreviewBox(
std::move(entries));
}
+void UpgradedStoriesPreviewBox(
+ not_null box,
+ not_null session) {
+ using namespace Ui::Text;
+
+ box->setTitle(tr::lng_premium_summary_subtitle_stories());
+
+ auto entries = std::vector();
+ entries.push_back({
+ .title = tr::lng_premium_stories_subtitle_order(),
+ .about = tr::lng_premium_stories_about_order(WithEntities),
+ .icon = &st::settingsStoriesIconOrder,
+ });
+ entries.push_back({
+ .title = tr::lng_premium_stories_subtitle_stealth(),
+ .about = tr::lng_premium_stories_about_stealth(WithEntities),
+ .icon = &st::settingsStoriesIconStealth,
+ });
+ entries.push_back({
+ .title = tr::lng_premium_stories_subtitle_views(),
+ .about = tr::lng_premium_stories_about_views(WithEntities),
+ .icon = &st::settingsStoriesIconViews,
+ });
+ entries.push_back({
+ .title = tr::lng_premium_stories_subtitle_expiration(),
+ .about = tr::lng_premium_stories_about_expiration(WithEntities),
+ .icon = &st::settingsStoriesIconExpiration,
+ });
+ entries.push_back({
+ .title = tr::lng_premium_stories_subtitle_download(),
+ .about = tr::lng_premium_stories_about_download(WithEntities),
+ .icon = &st::settingsStoriesIconDownload,
+ });
+ entries.push_back({
+ .title = tr::lng_premium_stories_subtitle_caption(),
+ .about = tr::lng_premium_stories_about_caption(WithEntities),
+ .icon = &st::settingsStoriesIconCaption,
+ });
+ entries.push_back({
+ .title = tr::lng_premium_stories_subtitle_links(),
+ .about = tr::lng_premium_stories_about_links(WithEntities),
+ .icon = &st::settingsStoriesIconLinks,
+ });
+
+ Ui::Premium::ShowListBox(
+ box,
+ st::defaultPremiumLimits,
+ std::move(entries));
+
+ Settings::AddDividerText(
+ box->verticalLayout(),
+ tr::lng_premium_stories_about_mobile());
+}
+
object_ptr CreateUnlockButton(
QWidget *parent,
rpl::producer text) {
diff --git a/Telegram/SourceFiles/boxes/premium_preview_box.h b/Telegram/SourceFiles/boxes/premium_preview_box.h
index 51f9bcfbd..dbe2be446 100644
--- a/Telegram/SourceFiles/boxes/premium_preview_box.h
+++ b/Telegram/SourceFiles/boxes/premium_preview_box.h
@@ -41,7 +41,13 @@ void DoubledLimitsPreviewBox(
not_null box,
not_null session);
+void UpgradedStoriesPreviewBox(
+ not_null box,
+ not_null session);
+
enum class PremiumPreview {
+ Stories,
+ DoubleLimits,
MoreUpload,
FasterDownload,
VoiceToText,
diff --git a/Telegram/SourceFiles/boxes/ringtones_box.cpp b/Telegram/SourceFiles/boxes/ringtones_box.cpp
index ef2d096ec..eb06f7066 100644
--- a/Telegram/SourceFiles/boxes/ringtones_box.cpp
+++ b/Telegram/SourceFiles/boxes/ringtones_box.cpp
@@ -278,7 +278,6 @@ void RingtonesBox(
st::ringtonesBoxButton,
{
&st::settingsIconAdd,
- 0,
Settings::IconType::Round,
&st::windowBgActive
}),
diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp
index 47cb78029..7313afd21 100644
--- a/Telegram/SourceFiles/boxes/send_files_box.cpp
+++ b/Telegram/SourceFiles/boxes/send_files_box.cpp
@@ -763,6 +763,8 @@ void SendFilesBox::pushBlock(int from, int till) {
) | rpl::filter([=] {
return !_removingIndex;
}) | rpl::start_with_next([=](int index) {
+ applyBlockChanges();
+
_removingIndex = index;
crl::on_main(this, [=] {
const auto index = base::take(_removingIndex).value_or(-1);
@@ -783,6 +785,8 @@ void SendFilesBox::pushBlock(int from, int till) {
const auto show = uiShow();
block.itemReplaceRequest(
) | rpl::start_with_next([=](int index) {
+ applyBlockChanges();
+
const auto replace = [=](Ui::PreparedList list) {
if (list.files.empty()) {
return;
@@ -858,6 +862,8 @@ void SendFilesBox::pushBlock(int from, int till) {
const auto openedOnce = widget->lifetime().make_state(false);
block.itemModifyRequest(
) | rpl::start_with_next([=, show = _show](int index) {
+ applyBlockChanges();
+
if (!(*openedOnce)) {
show->session().settings().incrementPhotoEditorHintShown();
show->session().saveSettings();
diff --git a/Telegram/SourceFiles/boxes/sessions_box.cpp b/Telegram/SourceFiles/boxes/sessions_box.cpp
index 55b5f499c..e30174be6 100644
--- a/Telegram/SourceFiles/boxes/sessions_box.cpp
+++ b/Telegram/SourceFiles/boxes/sessions_box.cpp
@@ -35,10 +35,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_info.h"
#include "styles/style_layers.h"
#include "styles/style_settings.h"
+#include "styles/style_menu_icons.h"
namespace {
-constexpr auto kSessionsShortPollTimeout = 60 * crl::time(1000);
+constexpr auto kShortPollTimeout = 60 * crl::time(1000);
constexpr auto kMaxDeviceModelLength = 32;
using EntryData = Api::Authorizations::Entry;
@@ -71,7 +72,6 @@ public:
Row(not_null delegate, const EntryData &data);
void update(const EntryData &data);
- void updateName(const QString &name);
[[nodiscard]] EntryData data() const;
@@ -80,6 +80,14 @@ public:
PaintRoundImageCallback generatePaintUserpicCallback(
bool forceRound) override;
+ QSize rightActionSize() const override {
+ return elementGeometry(2, 0).size();
+ }
+ QMargins rightActionMargins() const override {
+ const auto rect = elementGeometry(2, 0);
+ return QMargins(0, rect.y(), -(rect.x() + rect.width()), 0);
+ }
+
int elementsCount() const override;
QRect elementGeometry(int element, int outerWidth) const override;
bool elementDisabled(int element) const override;
@@ -458,28 +466,27 @@ void SessionInfoBox(
AddSkip(container, st::sessionSubtitleSkip);
AddSubsectionTitle(container, tr::lng_sessions_info());
- const auto add = [&](rpl::producer label, QString value) {
- if (value.isEmpty()) {
- return;
- }
- container->add(
- object_ptr(
- container,
- rpl::single(value),
- st::boxLabel),
- st::boxRowPadding + st::sessionValuePadding);
- container->add(
- object_ptr(
- container,
- std::move(label),
- st::sessionValueLabel),
- (st::boxRowPadding
- + style::margins{ 0, 0, 0, st::sessionValueSkip }));
- };
- add(tr::lng_sessions_application(), data.info);
- add(tr::lng_sessions_system(), data.system);
- add(tr::lng_sessions_ip(), data.ip);
- add(tr::lng_sessions_location(), data.location);
+ AddSessionInfoRow(
+ container,
+ tr::lng_sessions_application(),
+ data.info,
+ st::menuIconDevices);
+ AddSessionInfoRow(
+ container,
+ tr::lng_sessions_system(),
+ data.system,
+ st::menuIconInfo);
+ AddSessionInfoRow(
+ container,
+ tr::lng_sessions_ip(),
+ data.ip,
+ st::menuIconIpAddress);
+ AddSessionInfoRow(
+ container,
+ tr::lng_sessions_location(),
+ data.location,
+ st::menuIconAddress);
+
AddSkip(container, st::sessionValueSkip);
if (!data.location.isEmpty()) {
AddDividerText(container, tr::lng_sessions_location_about());
@@ -517,12 +524,6 @@ void Row::update(const EntryData &data) {
_delegate->rowUpdateRow(this);
}
-void Row::updateName(const QString &name) {
- _data.name = name;
- refreshName(st::sessionListItem);
- _delegate->rowUpdateRow(this);
-}
-
EntryData Row::data() const {
return _data;
}
@@ -615,8 +616,6 @@ void Row::elementsPaint(
outerWidth);
}
-} // namespace
-
class SessionsContent : public Ui::RpWidget {
public:
SessionsContent(
@@ -683,8 +682,6 @@ public:
style::margins margins = {});
private:
- void subscribeToCustomDeviceModel();
-
const not_null _session;
rpl::event_stream _terminateRequests;
@@ -760,7 +757,7 @@ void SessionsContent::setupContent() {
_inner->setVisible(!value);
}, lifetime());
- _authorizations->listChanges(
+ _authorizations->listValue(
) | rpl::start_with_next([=](const Api::Authorizations::List &list) {
parse(list);
}, lifetime());
@@ -791,7 +788,7 @@ void SessionsContent::parse(const Api::Authorizations::List &list) {
_inner->showData(_data);
- _shortPollTimer.callOnce(kSessionsShortPollTimeout);
+ _shortPollTimer.callOnce(kShortPollTimeout);
}
void SessionsContent::resizeEvent(QResizeEvent *e) {
@@ -816,7 +813,7 @@ void SessionsContent::paintEvent(QPaintEvent *e) {
}
void SessionsContent::shortPollSessions() {
- const auto left = kSessionsShortPollTimeout
+ const auto left = kShortPollTimeout
- (crl::now() - _authorizations->lastReceivedTime());
if (left > 0) {
parse(_authorizations->list());
@@ -1048,18 +1045,6 @@ Main::Session &SessionsContent::ListController::session() const {
return *_session;
}
-void SessionsContent::ListController::subscribeToCustomDeviceModel() {
- Core::App().settings().deviceModelChanges(
- ) | rpl::start_with_next([=](const QString &model) {
- for (auto i = 0; i != delegate()->peerListFullRowsCount(); ++i) {
- const auto row = delegate()->peerListRowAt(i);
- if (!row->id()) {
- static_cast(row.get())->updateName(model);
- }
- }
- }, lifetime());
-}
-
void SessionsContent::ListController::prepare() {
}
@@ -1148,27 +1133,7 @@ auto SessionsContent::ListController::Add(
return controller;
}
-SessionsBox::SessionsBox(
- QWidget*,
- not_null controller)
-: _controller(controller) {
-}
-
-void SessionsBox::prepare() {
- setTitle(tr::lng_sessions_other_header());
-
- addButton(tr::lng_close(), [=] { closeBox(); });
-
- const auto w = st::boxWideWidth;
-
- const auto content = setInnerWidget(
- object_ptr(this, _controller),
- st::sessionsScroll);
- content->resize(w, st::noContactsHeight);
- content->setupContent();
-
- setDimensions(w, st::sessionsHeight);
-}
+} // namespace
namespace Settings {
@@ -1193,4 +1158,41 @@ void Sessions::setupContent(not_null controller) {
Ui::ResizeFitChild(this, container);
}
+void AddSessionInfoRow(
+ not_null container,
+ rpl::producer label,
+ const QString &value,
+ const style::icon &icon) {
+ if (value.isEmpty()) {
+ return;
+ }
+
+ const auto text = container->add(
+ object_ptr(
+ container,
+ rpl::single(value),
+ st::boxLabel),
+ st::boxRowPadding + st::sessionValuePadding);
+ const auto left = st::sessionValuePadding.left();
+ container->add(
+ object_ptr(
+ container,
+ std::move(label),
+ st::sessionValueLabel),
+ (st::boxRowPadding
+ + style::margins{ left, 0, 0, st::sessionValueSkip }));
+
+ const auto widget = Ui::CreateChild(container.get());
+ widget->resize(icon.size());
+
+ text->topValue() | rpl::start_with_next([=](int top) {
+ widget->move(st::sessionValueIconPosition + QPoint(0, top));
+ }, widget->lifetime());
+
+ widget->paintRequest() | rpl::start_with_next([=, &icon] {
+ auto p = QPainter(widget);
+ icon.paintInCenter(p, widget->rect());
+ }, widget->lifetime());
+}
+
} // namespace Settings
diff --git a/Telegram/SourceFiles/boxes/sessions_box.h b/Telegram/SourceFiles/boxes/sessions_box.h
index d735189a5..47d03de27 100644
--- a/Telegram/SourceFiles/boxes/sessions_box.h
+++ b/Telegram/SourceFiles/boxes/sessions_box.h
@@ -7,12 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
-#include "boxes/abstract_box.h"
#include "settings/settings_common.h"
-namespace Main {
-class Session;
-} // namespace Main
+namespace Ui {
+class VerticalLayout;
+} // namespace Ui
namespace Settings {
@@ -29,16 +28,10 @@ private:
};
+void AddSessionInfoRow(
+ not_null container,
+ rpl::producer label,
+ const QString &value,
+ const style::icon &icon);
+
} // namespace Settings
-
-class SessionsBox : public Ui::BoxContent {
-public:
- SessionsBox(QWidget*, not_null controller);
-
-protected:
- void prepare() override;
-
-private:
- const not_null _controller;
-
-};
diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp
index f06f78cfd..17f0008e8 100644
--- a/Telegram/SourceFiles/calls/calls_top_bar.cpp
+++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp
@@ -731,14 +731,14 @@ void TopBar::updateControlsGeometry() {
width() - _mute->width() - _hangup->width(),
height());
- auto fullWidth = _fullInfoLabel->naturalWidth();
+ auto fullWidth = _fullInfoLabel->textMaxWidth();
auto showFull = (left + fullWidth + right <= width());
_fullInfoLabel->setVisible(showFull);
_shortInfoLabel->setVisible(!showFull);
auto setInfoLabelGeometry = [this, left, right](auto &&infoLabel) {
auto minPadding = qMax(left, right);
- auto infoWidth = infoLabel->naturalWidth();
+ auto infoWidth = infoLabel->textMaxWidth();
auto infoLeft = (width() - infoWidth) / 2;
if (infoLeft < minPadding) {
infoLeft = left;
diff --git a/Telegram/SourceFiles/calls/calls_video_incoming.cpp b/Telegram/SourceFiles/calls/calls_video_incoming.cpp
index 916a058dd..9ea9fe41c 100644
--- a/Telegram/SourceFiles/calls/calls_video_incoming.cpp
+++ b/Telegram/SourceFiles/calls/calls_video_incoming.cpp
@@ -73,6 +73,7 @@ private:
QSize _viewport;
float _factor = 1.;
+ int _ifactor = 1;
QVector2D _uniformViewport;
std::optional _contentBuffer;
@@ -189,9 +190,10 @@ void Panel::Incoming::RendererGL::paint(
return;
}
- const auto factor = widget->devicePixelRatio();
+ const auto factor = widget->devicePixelRatioF();
if (_factor != factor) {
_factor = factor;
+ _ifactor = int(std::ceil(_factor));
_controlsShadowImage.invalidate();
}
_viewport = widget->size();
@@ -375,9 +377,9 @@ void Panel::Incoming::RendererGL::validateShadowImage() {
return;
}
const auto size = st::callTitleShadowLeft.size();
- const auto full = QSize(size.width(), 2 * size.height()) * int(_factor);
+ const auto full = QSize(size.width(), 2 * size.height()) * _ifactor;
auto image = QImage(full, QImage::Format_ARGB32_Premultiplied);
- image.setDevicePixelRatio(_factor);
+ image.setDevicePixelRatio(_ifactor);
image.fill(Qt::transparent);
{
auto p = QPainter(&image);
diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp
index a240ce118..210eb0dce 100644
--- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp
+++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp
@@ -146,6 +146,23 @@ Main::Session &Show::session() const {
return panel->call()->peer()->session();
}
+#ifdef Q_OS_WIN
+void UnpinMaximized(not_null widget) {
+ SetWindowPos(
+ reinterpret_cast(widget->window()->windowHandle()->winId()),
+ HWND_NOTOPMOST,
+ 0,
+ 0,
+ 0,
+ 0,
+ (SWP_NOMOVE
+ | SWP_NOSIZE
+ | SWP_NOOWNERZORDER
+ | SWP_FRAMECHANGED
+ | SWP_NOACTIVATE));
+}
+#endif // Q_OS_WIN
+
} // namespace
struct Panel::ControlsBackgroundNarrow {
@@ -1257,7 +1274,12 @@ void Panel::createPinOnTop() {
_pinOnTop->setVisible(!fullScreenOrMaximized);
if (fullScreenOrMaximized) {
+#ifdef Q_OS_WIN
+ UnpinMaximized(window());
+ _unpinnedMaximized = true;
+#else // Q_OS_WIN
pin(false);
+#endif // Q_OS_WIN
_viewport->rp()->events(
) | rpl::filter([](not_null event) {
@@ -1269,6 +1291,9 @@ void Panel::createPinOnTop() {
_hideControlsTimer.callOnce(kHideControlsTimeout);
} else {
+ if (_unpinnedMaximized) {
+ pin(false);
+ }
_hideControlsTimerLifetime.destroy();
_hideControlsTimer.cancel();
refreshTitleGeometry();
@@ -2060,7 +2085,7 @@ void Panel::showNiceTooltip(
(normal ? widget().get() : container),
std::move(text),
st::groupCallNiceTooltipLabel);
- label->resizeToNaturalWidth(label->naturalWidth());
+ label->resizeToWidth(label->textMaxWidth());
if (normal) {
return label;
}
@@ -2522,8 +2547,8 @@ void Panel::refreshTitleGeometry() {
fullRect.height())
: fullRect;
const auto sep = st::groupCallTitleSeparator;
- const auto best = _title->naturalWidth() + (_viewers
- ? (_titleSeparator->width() + sep * 2 + _viewers->naturalWidth())
+ const auto best = _title->textMaxWidth() + (_viewers
+ ? (_titleSeparator->width() + sep * 2 + _viewers->textMaxWidth())
: 0);
const auto from = (widget()->width() - best) / 2;
const auto shownTop = (mode() == PanelMode::Default)
@@ -2541,8 +2566,8 @@ void Panel::refreshTitleGeometry() {
const auto left = titleRect.x();
const auto notEnough = std::max(0, best - titleRect.width());
- const auto titleMaxWidth = _title->naturalWidth();
- const auto viewersMaxWidth = _viewers ? _viewers->naturalWidth() : 0;
+ const auto titleMaxWidth = _title->textMaxWidth();
+ const auto viewersMaxWidth = _viewers ? _viewers->textMaxWidth() : 0;
const auto viewersNotEnough = std::clamp(
viewersMaxWidth - titleMaxWidth,
0,
@@ -2551,9 +2576,9 @@ void Panel::refreshTitleGeometry() {
(notEnough - std::abs(viewersMaxWidth - titleMaxWidth)) / 2,
0);
_title->resizeToWidth(
- _title->naturalWidth() - (notEnough - viewersNotEnough));
+ _title->textMaxWidth() - (notEnough - viewersNotEnough));
if (_viewers) {
- _viewers->resizeToWidth(_viewers->naturalWidth() - viewersNotEnough);
+ _viewers->resizeToWidth(_viewers->textMaxWidth() - viewersNotEnough);
}
const auto layout = [&](int position) {
_title->moveToLeft(position, top);
diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.h b/Telegram/SourceFiles/calls/group/calls_group_panel.h
index 8fab14540..cf9352697 100644
--- a/Telegram/SourceFiles/calls/group/calls_group_panel.h
+++ b/Telegram/SourceFiles/calls/group/calls_group_panel.h
@@ -228,6 +228,7 @@ private:
const std::unique_ptr _layerBg;
rpl::variable _mode;
rpl::variable _fullScreenOrMaximized = false;
+ bool _unpinnedMaximized = false;
#ifndef Q_OS_MAC
rpl::variable _controlsTop = 0;
diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp
index e4a04f7c5..26a9cbed0 100644
--- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp
+++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp
@@ -414,16 +414,20 @@ void Viewport::RendererGL::deinit(
}
void Viewport::RendererGL::setDefaultViewport(QOpenGLFunctions &f) {
- const auto size = _viewport * _factor;
- f.glViewport(0, 0, size.width(), size.height());
+ f.glViewport(
+ 0,
+ 0,
+ _viewport.width() * _factor,
+ _viewport.height() * _factor);
}
void Viewport::RendererGL::paint(
not_null widget,
QOpenGLFunctions &f) {
- const auto factor = widget->devicePixelRatio();
+ const auto factor = widget->devicePixelRatioF();
if (_factor != factor) {
_factor = factor;
+ _ifactor = int(std::ceil(_factor));
_buttons.invalidate();
}
_viewport = widget->size();
@@ -773,7 +777,7 @@ void Viewport::RendererGL::paintTile(
const auto program = _rgbaFrame
? &*_frameProgram.argb32
: &*_frameProgram.yuv420;
- const auto uniformViewport = QSizeF(_viewport * _factor);
+ const auto uniformViewport = QSizeF(_viewport) * _factor;
program->setUniformValue("viewport", uniformViewport);
program->setUniformValue(
@@ -1122,18 +1126,18 @@ void Viewport::RendererGL::ensureButtonsImage() {
+ backSize.height()
+ muteSize.height()
+ pausedSize.height()));
- const auto imageSize = fullSize * _factor;
+ const auto imageSize = fullSize * _ifactor;
auto image = _buttons.takeImage();
if (image.size() != imageSize) {
image = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
}
image.fill(Qt::transparent);
- image.setDevicePixelRatio(_factor);
+ image.setDevicePixelRatio(_ifactor);
{
auto p = Painter(&image);
auto hq = PainterHighQualityEnabler(p);
- _pinOn = QRect(QPoint(), pinOnSize * _factor);
+ _pinOn = QRect(QPoint(), pinOnSize * _ifactor);
VideoTile::PaintPinButton(
p,
true,
@@ -1145,8 +1149,8 @@ void Viewport::RendererGL::ensureButtonsImage() {
const auto pinOffTop = pinOnSize.height();
_pinOff = QRect(
- QPoint(0, pinOffTop) * _factor,
- pinOffSize * _factor);
+ QPoint(0, pinOffTop) * _ifactor,
+ pinOffSize * _ifactor);
VideoTile::PaintPinButton(
p,
false,
@@ -1157,7 +1161,7 @@ void Viewport::RendererGL::ensureButtonsImage() {
&_pinIcon);
const auto backTop = pinOffTop + pinOffSize.height();
- _back = QRect(QPoint(0, backTop) * _factor, backSize * _factor);
+ _back = QRect(QPoint(0, backTop) * _ifactor, backSize * _ifactor);
VideoTile::PaintBackButton(
p,
0,
@@ -1166,18 +1170,18 @@ void Viewport::RendererGL::ensureButtonsImage() {
&_pinBackground);
const auto muteTop = backTop + backSize.height();
- _muteOn = QRect(QPoint(0, muteTop) * _factor, muteSize * _factor);
+ _muteOn = QRect(QPoint(0, muteTop) * _ifactor, muteSize * _ifactor);
_muteIcon.paint(p, { 0, muteTop }, 1.);
_muteOff = QRect(
- QPoint(muteSize.width(), muteTop) * _factor,
- muteSize * _factor);
+ QPoint(muteSize.width(), muteTop) * _ifactor,
+ muteSize * _ifactor);
_muteIcon.paint(p, { muteSize.width(), muteTop }, 0.);
const auto pausedTop = muteTop + muteSize.height();
_paused = QRect(
- QPoint(0, pausedTop) * _factor,
- pausedSize * _factor);
+ QPoint(0, pausedTop) * _ifactor,
+ pausedSize * _ifactor);
st::groupCallPaused.paint(p, 0, pausedTop, fullSize.width());
}
_buttons.setImage(std::move(image));
diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h
index aab98c6fd..848174f86 100644
--- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h
+++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h
@@ -130,6 +130,7 @@ private:
const not_null _owner;
GLfloat _factor = 1.;
+ int _ifactor = 1;
QSize _viewport;
bool _rgbaFrame = false;
bool _userpicFrame;
diff --git a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp
index 93ee5f624..5344d1184 100644
--- a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp
+++ b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp
@@ -52,7 +52,9 @@ protected:
void paintButtonLoading(
QPainter &p,
const Ui::ChatStyle *st,
- const QRect &rect) const override;
+ const QRect &rect,
+ int outerWidth,
+ Ui::BubbleRounding rounding) const override;
int minButtonWidth(HistoryMessageMarkupButton::Type type) const override;
private:
@@ -107,7 +109,9 @@ void Style::paintButtonIcon(
void Style::paintButtonLoading(
QPainter &p,
const Ui::ChatStyle *st,
- const QRect &rect) const {
+ const QRect &rect,
+ int outerWidth,
+ Ui::BubbleRounding rounding) const {
// Buttons with loading progress should not appear here.
}
diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
index 79c85a03d..fb85201eb 100644
--- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style
+++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
@@ -118,6 +118,8 @@ EmojiPan {
tabs: SettingsSlider;
search: TabbedSearch;
searchMargin: margins;
+ colorAll: IconButton;
+ colorAllLabel: FlatLabel;
removeSet: IconButton;
boxLabel: FlatLabel;
icons: ComposeIcons;
@@ -196,6 +198,8 @@ ComposeControls {
send: SendButton;
attach: IconButton;
emoji: EmojiButton;
+ like: IconButton;
+ liked: icon;
suggestions: EmojiSuggestions;
tabbed: EmojiPan;
tabbedHeightMin: pixels;
@@ -446,6 +450,7 @@ inlineResultsMaxHeight: 640px;
emojiPanHeaderFont: semiboldFont;
emojiPanRemoveSkip: 10px;
emojiPanRemoveTop: 10px;
+emojiPanColorAllSkip: 9px;
emojiColorsPadding: 5px;
emojiColorsSep: 1px;
@@ -488,6 +493,25 @@ stickerIconMove: 400;
stickerPreviewDuration: 150;
stickerPreviewMin: 0.1;
+emojiPanColorAll: IconButton(stickerPanRemoveSet) {
+ width: 24px;
+ height: 24px;
+ rippleAreaSize: 24px;
+ icon: icon {{ "emoji/emoji_skin", smallCloseIconFg }};
+ iconOver: icon {{ "emoji/emoji_skin", smallCloseIconFgOver }};
+}
+emojiPanColorAllLabel: FlatLabel(defaultFlatLabel) {
+ textFg: windowSubTextFg;
+ align: align(top);
+ minWidth: 40px;
+ style: TextStyle(defaultTextStyle) {
+ font: font(12px);
+ linkFont: font(12px);
+ linkFontOver: font(12px);
+ }
+}
+emojiPanColorAllPadding: margins(10px, 6px, 10px, -1px);
+
stickerGroupCategorySize: 28px;
stickerGroupCategoryAbout: defaultTextStyle;
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
@@ -624,6 +648,8 @@ defaultEmojiPan: EmojiPan {
tabs: emojiTabs;
search: defaultTabbedSearch;
searchMargin: margins(1px, 11px, 2px, 5px);
+ colorAll: emojiPanColorAll;
+ colorAllLabel: emojiPanColorAllLabel;
removeSet: stickerPanRemoveSet;
boxLabel: boxLabel;
icons: defaultComposeIcons;
diff --git a/Telegram/SourceFiles/chat_helpers/compose/compose_features.h b/Telegram/SourceFiles/chat_helpers/compose/compose_features.h
index 2f9915679..ba6f43b4e 100644
--- a/Telegram/SourceFiles/chat_helpers/compose/compose_features.h
+++ b/Telegram/SourceFiles/chat_helpers/compose/compose_features.h
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace ChatHelpers {
struct ComposeFeatures {
+ bool likes = false;
bool sendAs = true;
bool ttlInfo = true;
bool botCommandSend = true;
diff --git a/Telegram/SourceFiles/chat_helpers/emoji_keywords.cpp b/Telegram/SourceFiles/chat_helpers/emoji_keywords.cpp
index 684027624..500de20b6 100644
--- a/Telegram/SourceFiles/chat_helpers/emoji_keywords.cpp
+++ b/Telegram/SourceFiles/chat_helpers/emoji_keywords.cpp
@@ -672,17 +672,9 @@ std::vector EmojiKeywords::PrioritizeRecent(
}
std::vector EmojiKeywords::ApplyVariants(std::vector list) {
+ auto &settings = Core::App().settings();
for (auto &item : list) {
- item.emoji = [&] {
- const auto result = item.emoji;
- const auto &variants = Core::App().settings().emojiVariants();
- const auto i = result->hasVariants()
- ? variants.find(result->nonColoredId())
- : end(variants);
- return (i != end(variants))
- ? result->variant(i->second)
- : result;
- }();
+ item.emoji = settings.lookupEmojiVariant(item.emoji);
}
return list;
}
diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
index f41482c19..cb3b034ce 100644
--- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
+++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
@@ -8,9 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/emoji_list_widget.h"
#include "base/unixtime.h"
+#include "ui/boxes/confirm_box.h"
#include "ui/controls/tabbed_search.h"
#include "ui/text/format_values.h"
#include "ui/effects/animations.h"
+#include "ui/widgets/menu/menu_add_action_callback.h"
+#include "ui/widgets/menu/menu_add_action_callback_factory.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/popup_menu.h"
#include "ui/widgets/shadow.h"
@@ -41,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "settings/settings_premium.h"
#include "window/window_session_controller.h"
#include "styles/style_chat_helpers.h"
+#include "styles/style_menu_icons.h"
namespace ChatHelpers {
namespace {
@@ -58,7 +62,7 @@ class EmojiColorPicker final : public Ui::RpWidget {
public:
EmojiColorPicker(QWidget *parent, const style::EmojiPan &st);
- void showEmoji(EmojiPtr emoji);
+ void showEmoji(EmojiPtr emoji, bool allLabel = false);
void clearSelection();
void handleMouseMove(QPoint globalPos);
@@ -79,8 +83,10 @@ protected:
void mouseMoveEvent(QMouseEvent *e) override;
private:
+ void createAllLabel();
void animationCallback();
void updateSize();
+ [[nodiscard]] int topColorAllSkip() const;
void drawVariant(QPainter &p, int variant);
@@ -106,6 +112,8 @@ private:
QPixmap _cache;
Ui::Animations::Simple _a_opacity;
+ std::unique_ptr _allLabel;
+
rpl::event_stream _chosen;
rpl::event_stream<> _hidden;
@@ -131,10 +139,15 @@ EmojiColorPicker::EmojiColorPicker(
setMouseTracking(true);
}
-void EmojiColorPicker::showEmoji(EmojiPtr emoji) {
+void EmojiColorPicker::showEmoji(EmojiPtr emoji, bool allLabel) {
if (!emoji || !emoji->hasVariants()) {
return;
}
+ if (!allLabel) {
+ _allLabel = nullptr;
+ } else if (!_allLabel) {
+ createAllLabel();
+ }
_ignoreShow = false;
_variants.resize(emoji->variantsCount() + 1);
@@ -144,10 +157,21 @@ void EmojiColorPicker::showEmoji(EmojiPtr emoji) {
updateSize();
- if (!_cache.isNull()) _cache = QPixmap();
+ if (!_cache.isNull()) {
+ _cache = QPixmap();
+ }
showAnimated();
}
+void EmojiColorPicker::createAllLabel() {
+ _allLabel = std::make_unique(
+ this,
+ tr::lng_emoji_color_all(),
+ _st.colorAllLabel);
+ _allLabel->show();
+ _allLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
+}
+
void EmojiColorPicker::updateSize() {
auto width = st::emojiPanMargins.left()
+ _singleSize.width() * _variants.size()
@@ -158,6 +182,17 @@ void EmojiColorPicker::updateSize() {
+ 2 * st::emojiColorsPadding
+ _singleSize.height()
+ st::emojiPanMargins.bottom();
+ if (_allLabel) {
+ _allLabel->resizeToWidth(width
+ - st::emojiPanMargins.left()
+ - st::emojiPanMargins.right()
+ - st::emojiPanColorAllPadding.left()
+ - st::emojiPanColorAllPadding.right());
+ _allLabel->move(
+ st::emojiPanMargins.left() + st::emojiPanColorAllPadding.left(),
+ st::emojiPanMargins.top() + st::emojiPanColorAllPadding.top());
+ height += topColorAllSkip();
+ }
resize(width, height);
update();
updateSelected();
@@ -186,11 +221,15 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
Ui::Shadow::paint(p, inner, width(), _st.showAnimation.shadow);
_backgroundRect.paint(p, inner);
+ const auto skip = topColorAllSkip();
auto x = st::emojiPanMargins.left() + 2 * st::emojiColorsPadding + _singleSize.width();
if (rtl()) x = width() - x - st::emojiColorsSep;
- p.fillRect(x, st::emojiPanMargins.top() + st::emojiColorsPadding, st::emojiColorsSep, inner.height() - st::emojiColorsPadding * 2, st::emojiColorsSepColor);
+ p.fillRect(x, st::emojiPanMargins.top() + skip + st::emojiColorsPadding, st::emojiColorsSep, inner.height() - st::emojiColorsPadding * 2 - skip, st::emojiColorsSepColor);
- if (_variants.isEmpty()) return;
+ if (_variants.isEmpty()) {
+ return;
+ }
+ p.translate(0, skip);
for (auto i = 0, count = int(_variants.size()); i != count; ++i) {
drawVariant(p, i);
}
@@ -248,6 +287,9 @@ void EmojiColorPicker::animationCallback() {
update();
if (!_a_opacity.animating()) {
_cache = QPixmap();
+ if (_allLabel) {
+ _allLabel->show();
+ }
if (_hiding) {
hide();
_hidden.fire({});
@@ -276,10 +318,16 @@ rpl::producer<> EmojiColorPicker::hidden() const {
void EmojiColorPicker::hideAnimated() {
if (_cache.isNull()) {
+ if (_allLabel) {
+ _allLabel->show();
+ }
_cache = Ui::GrabWidget(this);
clearSelection();
}
_hiding = true;
+ if (_allLabel) {
+ _allLabel->hide();
+ }
_a_opacity.start([this] { animationCallback(); }, 1., 0., st::emojiPanDuration);
}
@@ -291,10 +339,16 @@ void EmojiColorPicker::showAnimated() {
}
_hiding = false;
if (_cache.isNull()) {
+ if (_allLabel) {
+ _allLabel->show();
+ }
_cache = Ui::GrabWidget(this);
clearSelection();
}
show();
+ if (_allLabel) {
+ _allLabel->hide();
+ }
_a_opacity.start([this] { animationCallback(); }, 0., 1., st::emojiPanDuration);
}
@@ -304,10 +358,18 @@ void EmojiColorPicker::clearSelection() {
_lastMousePos = mapToGlobal(QPoint(-10, -10));
}
+int EmojiColorPicker::topColorAllSkip() const {
+ return _allLabel
+ ? (st::emojiPanColorAllPadding.top()
+ + _allLabel->height()
+ + st::emojiPanColorAllPadding.bottom())
+ : 0;
+}
+
void EmojiColorPicker::updateSelected() {
auto newSelected = -1;
auto p = mapFromGlobal(_lastMousePos);
- auto sx = rtl() ? (width() - p.x()) : p.x(), y = p.y() - st::emojiPanMargins.top() - st::emojiColorsPadding;
+ auto sx = rtl() ? (width() - p.x()) : p.x(), y = p.y() - st::emojiPanMargins.top() - topColorAllSkip() - st::emojiColorsPadding;
if (y >= 0 && y < _singleSize.height()) {
auto x = sx - st::emojiPanMargins.left() - st::emojiColorsPadding;
if (x >= 0 && x < _singleSize.width()) {
@@ -327,7 +389,8 @@ void EmojiColorPicker::setSelected(int newSelected) {
if (_selected == newSelected) {
return;
}
- auto updateSelectedRect = [this] {
+ const auto skip = topColorAllSkip();
+ const auto updateSelectedRect = [&] {
if (_selected < 0) return;
auto addedSkip = (_selected > 0)
? (2 * st::emojiColorsPadding + st::emojiColorsSep)
@@ -338,7 +401,7 @@ void EmojiColorPicker::setSelected(int newSelected) {
+ addedSkip;
rtlupdate(
left,
- st::emojiPanMargins.top() + st::emojiColorsPadding,
+ st::emojiPanMargins.top() + st::emojiColorsPadding + skip,
_singleSize.width(),
_singleSize.height());
};
@@ -851,6 +914,31 @@ void EmojiListWidget::setSingleSize(QSize size) {
_picker->setSingleSize(_singleSize);
}
+void EmojiListWidget::setColorAllForceRippled(bool force) {
+ _colorAllRippleForced = force;
+ if (_colorAllRippleForced) {
+ _colorAllRippleForcedLifetime = style::PaletteChanged(
+ ) | rpl::filter([=] {
+ return _colorAllRipple != nullptr;
+ }) | rpl::start_with_next([=] {
+ _colorAllRipple->forceRepaint();
+ });
+ if (!_colorAllRipple) {
+ _colorAllRipple = createButtonRipple(int(Section::People));
+ }
+ if (_colorAllRipple->empty()) {
+ _colorAllRipple->addFading();
+ } else {
+ _colorAllRipple->lastUnstop();
+ }
+ } else {
+ if (_colorAllRipple) {
+ _colorAllRipple->lastStop();
+ }
+ _colorAllRippleForcedLifetime.destroy();
+ }
+}
+
int EmojiListWidget::countDesiredHeight(int newWidth) {
const auto fullWidth = st().margin.left()
+ newWidth
@@ -897,14 +985,9 @@ void EmojiListWidget::ensureLoaded(int section) {
_emoji[section] = Ui::Emoji::GetSection(static_cast(section));
_counts[section] = _emoji[section].size();
- const auto &variants = Core::App().settings().emojiVariants();
+ const auto &settings = Core::App().settings();
for (auto &emoji : _emoji[section]) {
- if (emoji->hasVariants()) {
- const auto j = variants.find(emoji->nonColoredId());
- if (j != end(variants)) {
- emoji = emoji->variant(j->second);
- }
- }
+ emoji = settings.lookupEmojiVariant(emoji);
}
}
@@ -956,7 +1039,7 @@ void EmojiListWidget::fillRecentFrom(const std::vector &list) {
base::unique_qptr EmojiListWidget::fillContextMenu(
SendMenu::Type type) {
- if (_mode != Mode::EmojiStatus || v::is_null(_selected)) {
+ if (v::is_null(_selected)) {
return nullptr;
}
const auto over = std::get_if(&_selected);
@@ -965,13 +1048,104 @@ base::unique_qptr EmojiListWidget::fillContextMenu(
}
const auto section = over->section;
const auto index = over->index;
- const auto chosen = lookupCustomEmoji(index, section);
- if (!chosen) {
- return nullptr;
- }
auto menu = base::make_unique_q(
this,
- st::defaultPopupMenu);
+ (_mode == Mode::Full
+ ? st::popupMenuWithIcons
+ : st::defaultPopupMenu));
+ if (_mode == Mode::Full) {
+ fillRecentMenu(menu, section, index);
+ } else if (_mode == Mode::EmojiStatus) {
+ fillEmojiStatusMenu(menu, section, index);
+ }
+ if (menu->empty()) {
+ return nullptr;
+ }
+ return menu;
+}
+
+void EmojiListWidget::fillRecentMenu(
+ not_null menu,
+ int section,
+ int index) {
+ if (section != int(Section::Recent)) {
+ return;
+ }
+ const auto addAction = Ui::Menu::CreateAddActionCallback(menu);
+ const auto over = OverEmoji{ section, index };
+ const auto emoji = lookupOverEmoji(&over);
+ const auto custom = lookupCustomEmoji(index, section);
+ if (custom && custom->sticker()) {
+ const auto sticker = custom->sticker();
+ const auto emoji = sticker->alt;
+ const auto setId = sticker->set.id;
+ if (!emoji.isEmpty()) {
+ auto data = TextForMimeData{ emoji, { emoji } };
+ data.rich.entities.push_back({
+ EntityType::CustomEmoji,
+ 0,
+ int(emoji.size()),
+ Data::SerializeCustomEmojiId(custom)
+ });
+ addAction(tr::lng_emoji_copy(tr::now), [=] {
+ TextUtilities::SetClipboardText(data);
+ }, &st::menuIconCopy);
+ }
+ if (setId && _features.openStickerSets) {
+ addAction(
+ tr::lng_emoji_view_pack(tr::now),
+ crl::guard(this, [=] { displaySet(setId); }),
+ &st::menuIconShowAll);
+ }
+ } else if (emoji) {
+ addAction(tr::lng_emoji_copy(tr::now), [=] {
+ const auto text = emoji->text();
+ TextUtilities::SetClipboardText({ text, { text } });
+ }, &st::menuIconCopy);
+ }
+ auto id = RecentEmojiId{ emoji };
+ if (custom) {
+ id.data = RecentEmojiDocument{
+ .id = custom->id,
+ .test = custom->session().isTestMode(),
+ };
+ }
+ addAction(tr::lng_emoji_remove_recent(tr::now), crl::guard(this, [=] {
+ Core::App().settings().hideRecentEmoji(id);
+ refreshRecent();
+ }), &st::menuIconCancel);
+
+ menu->addSeparator(&st().expandedSeparator);
+
+ const auto resetRecent = [=] {
+ const auto sure = [=](Fn &&close) {
+ Core::App().settings().resetRecentEmoji();
+ refreshRecent();
+ close();
+ };
+ checkHideWithBox(Ui::MakeConfirmBox({
+ .text = tr::lng_emoji_reset_recent_sure(),
+ .confirmed = crl::guard(this, sure),
+ .confirmText = tr::lng_emoji_reset_recent_button(tr::now),
+ .labelStyle = &st().boxLabel,
+ }));
+ };
+ addAction({
+ .text = tr::lng_emoji_reset_recent(tr::now),
+ .handler = crl::guard(this, resetRecent),
+ .icon = &st::menuIconRestoreAttention,
+ .isAttention = true,
+ });
+}
+
+void EmojiListWidget::fillEmojiStatusMenu(
+ not_null menu,
+ int section,
+ int index) {
+ const auto chosen = lookupCustomEmoji(index, section);
+ if (!chosen) {
+ return;
+ }
const auto selectWith = [=](TimeId scheduled) {
selectCustom(
lookupChosen(chosen, nullptr, { .scheduled = scheduled }));
@@ -989,7 +1163,6 @@ base::unique_qptr EmojiListWidget::fillContextMenu(
tr::lng_manage_messages_ttl_after_custom(tr::now),
crl::guard(this, [=] { selectWith(
TabbedSelector::kPickCustomTimeId); }));
- return menu;
}
void EmojiListWidget::paintEvent(QPaintEvent *e) {
@@ -1366,8 +1539,7 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
if (emoji && emoji->hasVariants()) {
_pickerSelected = _selected;
setCursor(style::cur_default);
- const auto &variants = Core::App().settings().emojiVariants();
- if (!variants.contains(emoji->nonColoredId())) {
+ if (!Core::App().settings().hasChosenEmojiVariant(emoji)) {
showPicker();
} else {
_showPickerTimer.callOnce(500);
@@ -1385,12 +1557,11 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
return _picker->handleMouseRelease(QCursor::pos());
} else if (const auto over = std::get_if(&_pickerSelected)) {
const auto emoji = lookupOverEmoji(over);
- if (emoji && emoji->hasVariants()) {
- const auto &variants = Core::App().settings().emojiVariants();
- if (variants.contains(emoji->nonColoredId())) {
- _picker->hideAnimated();
- _pickerSelected = v::null;
- }
+ if (emoji
+ && emoji->hasVariants()
+ && Core::App().settings().hasChosenEmojiVariant(emoji)) {
+ _picker->hideAnimated();
+ _pickerSelected = v::null;
}
}
}
@@ -1429,11 +1600,15 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
&& set->section < _staticCount + _custom.size());
displaySet(_custom[set->section - _staticCount].id);
} else if (auto button = std::get_if(&pressed)) {
- Assert(button->section >= _staticCount
- && button->section < _staticCount + _custom.size());
- const auto id = _custom[button->section - _staticCount].id;
+ Assert(hasButton(button->section));
+ const auto id = hasColorButton(button->section)
+ ? 0
+ : _custom[button->section - _staticCount].id;
const auto usage = ChatHelpers::WindowUsage::PremiumPromo;
- if (hasRemoveButton(button->section)) {
+ if (hasColorButton(button->section)) {
+ _pickerSelected = pressed;
+ showPicker();
+ } else if (hasRemoveButton(button->section)) {
removeSet(id);
} else if (hasAddButton(button->section)) {
_localSetsManager->install(id);
@@ -1496,23 +1671,35 @@ void EmojiListWidget::showPicker() {
if (v::is_null(_pickerSelected)) {
return;
}
-
- const auto over = std::get_if(&_pickerSelected);
- const auto emoji = lookupOverEmoji(over);
- if (emoji && emoji->hasVariants()) {
- _picker->showEmoji(emoji);
-
- auto y = emojiRect(over->section, over->index).y();
+ const auto showAt = [&](float64 xCoef, int y, int height) {
y -= _picker->height() - st::emojiPanRadius + getVisibleTop();
if (y < st().header) {
- y += _picker->height() - st::emojiPanRadius + _singleSize.height() - st::emojiPanRadius;
+ y += _picker->height() + height;
}
auto xmax = width() - _picker->width();
- auto coef = float64(over->index % _columnCount) / float64(_columnCount - 1);
- if (rtl()) coef = 1. - coef;
- _picker->move(qRound(xmax * coef), y);
+ if (rtl()) xCoef = 1. - xCoef;
+ _picker->move(qRound(xmax * xCoef), y);
disableScroll(true);
+ };
+ if (const auto button = std::get_if(&_pickerSelected)) {
+ const auto hand = QString::fromUtf8("\xF0\x9F\x91\x8B");
+ const auto emoji = Ui::Emoji::Find(hand);
+ Assert(emoji != nullptr && emoji->hasVariants());
+ _picker->showEmoji(emoji, true);
+ setColorAllForceRippled(true);
+ const auto rect = buttonRect(button->section);
+ showAt(1., rect.y(), rect.height() - 2 * st::emojiPanRadius);
+ } else if (const auto over = std::get_if(&_pickerSelected)) {
+ const auto emoji = lookupOverEmoji(over);
+ if (emoji && emoji->hasVariants()) {
+ _picker->showEmoji(emoji);
+
+ const auto coef = float64(over->index % _columnCount)
+ / float64(_columnCount - 1);
+ const auto h = _singleSize.height() - 2 * st::emojiPanRadius;
+ showAt(coef, emojiRect(over->section, over->index).y(), h);
+ }
}
}
@@ -1520,11 +1707,34 @@ void EmojiListWidget::pickerHidden() {
_pickerSelected = v::null;
update();
disableScroll(false);
+ setColorAllForceRippled(false);
_lastMousePos = QCursor::pos();
updateSelected();
}
+bool EmojiListWidget::hasColorButton(int index) const {
+ return (_staticCount > int(Section::People))
+ && (index == int(Section::People));
+}
+
+QRect EmojiListWidget::colorButtonRect(int index) const {
+ return colorButtonRect(sectionInfo(index));
+}
+
+QRect EmojiListWidget::colorButtonRect(const SectionInfo &info) const {
+ if (_mode != Mode::Full) {
+ return QRect();
+ }
+ const auto &colorSt = st().colorAll;
+ const auto buttonw = colorSt.rippleAreaPosition.x()
+ + colorSt.rippleAreaSize;
+ const auto buttonh = colorSt.height;
+ const auto buttonx = emojiRight() - st::emojiPanColorAllSkip - buttonw;
+ const auto buttony = info.top + st::emojiPanRemoveTop;
+ return QRect(buttonx, buttony, buttonw, buttonh);
+}
+
bool EmojiListWidget::hasRemoveButton(int index) const {
if (index < _staticCount
|| index >= _staticCount + _custom.size()) {
@@ -1581,15 +1791,18 @@ QRect EmojiListWidget::unlockButtonRect(int index) const {
}
bool EmojiListWidget::hasButton(int index) const {
- if (index < _staticCount
- || index >= _staticCount + _custom.size()) {
- return false;
+ if (hasColorButton(index)
+ || (index >= _staticCount
+ && index < _staticCount + _custom.size())) {
+ return true;
}
- return true;
+ return false;
}
QRect EmojiListWidget::buttonRect(int index) const {
- return hasRemoveButton(index)
+ return hasColorButton(index)
+ ? colorButtonRect(index)
+ : hasRemoveButton(index)
? removeButtonRect(index)
: hasAddButton(index)
? addButtonRect(index)
@@ -1637,19 +1850,33 @@ QRect EmojiListWidget::emojiRect(int section, int index) const {
}
void EmojiListWidget::colorChosen(EmojiChosen data) {
+ Expects(data.emoji != nullptr && data.emoji->hasVariants());
+
const auto emoji = data.emoji;
- if (emoji->hasVariants()) {
- Core::App().settings().saveEmojiVariant(emoji);
+ auto &settings = Core::App().settings();
+ if (const auto button = std::get_if(&_pickerSelected)) {
+ settings.saveAllEmojiVariants(emoji);
+ for (auto section = int(Section::People)
+ ; section < _staticCount
+ ; ++section) {
+ for (auto &emoji : _emoji[section]) {
+ emoji = settings.lookupEmojiVariant(emoji);
+ }
+ }
+ update();
+ } else {
+ settings.saveEmojiVariant(emoji);
+
+ const auto over = std::get_if(&_pickerSelected);
+ if (over
+ && over->section > int(Section::Recent)
+ && over->section < _staticCount
+ && over->index < _emoji[over->section].size()) {
+ _emoji[over->section][over->index] = emoji;
+ rtlupdate(emojiRect(over->section, over->index));
+ }
+ selectEmoji(data);
}
- const auto over = std::get_if(&_pickerSelected);
- if (over
- && over->section > int(Section::Recent)
- && over->section < _staticCount
- && over->index < _emoji[over->section].size()) {
- _emoji[over->section][over->index] = emoji;
- rtlupdate(emojiRect(over->section, over->index));
- }
- selectEmoji(data);
_picker->hideAnimated();
}
@@ -1751,6 +1978,7 @@ void EmojiListWidget::refreshRecent() {
clearSelection();
fillRecent();
resizeToWidth(width());
+ update();
}
void EmojiListWidget::refreshCustom() {
@@ -1967,47 +2195,54 @@ int EmojiListWidget::paintButtonGetWidth(
const SectionInfo &info,
bool selected,
QRect clip) const {
- if (info.section < _staticCount
- || info.section >= _staticCount + _custom.size()) {
+ if (!hasButton(info.section)) {
return 0;
}
- auto &custom = _custom[info.section - _staticCount];
- if (hasRemoveButton(info.section)) {
- const auto remove = removeButtonRect(info);
- if (remove.isEmpty()) {
+ auto &ripple = (info.section >= _staticCount)
+ ? _custom[info.section - _staticCount].ripple
+ : _colorAllRipple;
+ const auto colorAll = hasColorButton(info.section);
+ if (colorAll || hasRemoveButton(info.section)) {
+ const auto rect = colorAll
+ ? colorButtonRect(info)
+ : removeButtonRect(info);
+ if (rect.isEmpty()) {
return 0;
- } else if (remove.intersects(clip)) {
- const auto &removeSt = st().removeSet;
- if (custom.ripple) {
- custom.ripple->paint(
+ } else if (rect.intersects(clip)) {
+ const auto &bst = colorAll ? st().colorAll : st().removeSet;
+ if (colorAll && _colorAllRippleForced) {
+ selected = true;
+ }
+ if (ripple) {
+ ripple->paint(
p,
- remove.x() + removeSt.rippleAreaPosition.x(),
- remove.y() + removeSt.rippleAreaPosition.y(),
+ rect.x() + bst.rippleAreaPosition.x(),
+ rect.y() + bst.rippleAreaPosition.y(),
width());
- if (custom.ripple->empty()) {
- custom.ripple.reset();
+ if (ripple->empty()) {
+ ripple.reset();
}
}
- const auto &icon = selected ? removeSt.iconOver : removeSt.icon;
+ const auto &icon = selected ? bst.iconOver : bst.icon;
icon.paint(
p,
- (remove.topLeft()
+ (rect.topLeft()
+ QPoint(
- remove.width() - icon.width(),
- remove.height() - icon.height()) / 2),
+ rect.width() - icon.width(),
+ rect.height() - icon.height()) / 2),
width());
}
- return emojiRight() - remove.x();
+ return emojiRight() - rect.x();
}
const auto canAdd = hasAddButton(info.section);
const auto &button = rightButton(info.section);
const auto rect = buttonRect(info, button);
p.drawImage(rect.topLeft(), selected ? button.backOver : button.back);
- if (custom.ripple) {
- const auto ripple = QColor(0, 0, 0, 36);
- custom.ripple->paint(p, rect.x(), rect.y(), width(), &ripple);
- if (custom.ripple->empty()) {
- custom.ripple.reset();
+ if (ripple) {
+ const auto color = QColor(0, 0, 0, 36);
+ ripple->paint(p, rect.x(), rect.y(), width(), &color);
+ if (ripple->empty()) {
+ ripple.reset();
}
}
p.setPen(!canAdd
@@ -2108,22 +2343,28 @@ void EmojiListWidget::setSelected(OverState newSelected) {
void EmojiListWidget::setPressed(OverState newPressed) {
if (auto button = std::get_if(&_pressed)) {
- Assert(button->section >= _staticCount
- && button->section < _staticCount + _custom.size());
- auto &set = _custom[button->section - _staticCount];
- if (set.ripple) {
- set.ripple->lastStop();
+ Assert(hasColorButton(button->section)
+ || (button->section >= _staticCount
+ && button->section < _staticCount + _custom.size()));
+ auto &ripple = (button->section >= _staticCount)
+ ? _custom[button->section - _staticCount].ripple
+ : _colorAllRipple;
+ if (ripple) {
+ ripple->lastStop();
}
}
_pressed = newPressed;
if (auto button = std::get_if(&_pressed)) {
- Assert(button->section >= _staticCount
- && button->section < _staticCount + _custom.size());
- auto &set = _custom[button->section - _staticCount];
- if (!set.ripple) {
- set.ripple = createButtonRipple(button->section);
+ Assert(hasColorButton(button->section)
+ || (button->section >= _staticCount
+ && button->section < _staticCount + _custom.size()));
+ auto &ripple = (button->section >= _staticCount)
+ ? _custom[button->section - _staticCount].ripple
+ : _colorAllRipple;
+ if (!ripple) {
+ ripple = createButtonRipple(button->section);
}
- set.ripple->add(mapFromGlobal(QCursor::pos()) - buttonRippleTopLeft(button->section));
+ ripple->add(mapFromGlobal(QCursor::pos()) - buttonRippleTopLeft(button->section));
}
}
@@ -2167,16 +2408,18 @@ void EmojiListWidget::initButton(
std::unique_ptr EmojiListWidget::createButtonRipple(
int section) {
- Expects(section >= _staticCount
- && section < _staticCount + _custom.size());
+ Expects(hasButton(section));
+ const auto colorAll = hasColorButton(section);
const auto remove = hasRemoveButton(section);
- const auto &removeSt = st().removeSet;
- const auto &st = remove ? removeSt.ripple : st::emojiPanButton.ripple;
- auto mask = remove
+ const auto &staticSt = colorAll ? st().colorAll : st().removeSet;
+ const auto &st = (colorAll || remove)
+ ? staticSt.ripple
+ : st::emojiPanButton.ripple;
+ auto mask = (colorAll || remove)
? Ui::RippleAnimation::EllipseMask(QSize(
- removeSt.rippleAreaSize,
- removeSt.rippleAreaSize))
+ staticSt.rippleAreaSize,
+ staticSt.rippleAreaSize))
: rightButton(section).rippleMask;
return std::make_unique(
st,
@@ -2185,11 +2428,12 @@ std::unique_ptr EmojiListWidget::createButtonRipple(
}
QPoint EmojiListWidget::buttonRippleTopLeft(int section) const {
- Expects(section >= _staticCount
- && section < _staticCount + _custom.size());
+ Expects(hasButton(section));
return myrtlrect(buttonRect(section)).topLeft()
- + (hasRemoveButton(section)
+ + (hasColorButton(section)
+ ? st().colorAll.rippleAreaPosition
+ : hasRemoveButton(section)
? st().removeSet.rippleAreaPosition
: QPoint());
}
diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h
index 374b6e7b3..5cc197995 100644
--- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h
+++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h
@@ -247,6 +247,7 @@ private:
[[nodiscard]] SectionInfo sectionInfoByOffset(int yOffset) const;
[[nodiscard]] int sectionsCount() const;
void setSingleSize(QSize size);
+ void setColorAllForceRippled(bool force);
void showPicker();
void pickerHidden();
@@ -265,6 +266,15 @@ private:
void setSelected(OverState newSelected);
void setPressed(OverState newPressed);
+ void fillRecentMenu(
+ not_null menu,
+ int section,
+ int index);
+ void fillEmojiStatusMenu(
+ not_null menu,
+ int section,
+ int index);
+
[[nodiscard]] EmojiPtr lookupOverEmoji(const OverEmoji *over) const;
[[nodiscard]] DocumentData *lookupCustomEmoji(
int index,
@@ -297,6 +307,9 @@ private:
int set,
int index);
void validateEmojiPaintContext(const ExpandingContext &context);
+ [[nodiscard]] bool hasColorButton(int index) const;
+ [[nodiscard]] QRect colorButtonRect(int index) const;
+ [[nodiscard]] QRect colorButtonRect(const SectionInfo &info) const;
[[nodiscard]] bool hasRemoveButton(int index) const;
[[nodiscard]] QRect removeButtonRect(int index) const;
[[nodiscard]] QRect removeButtonRect(const SectionInfo &info) const;
@@ -378,6 +391,10 @@ private:
Ui::RoundRect _overBg;
QImage _searchExpandCache;
+ mutable std::unique_ptr _colorAllRipple;
+ bool _colorAllRippleForced = false;
+ rpl::lifetime _colorAllRippleForcedLifetime;
+
std::vector _nextSearchQuery;
std::vector _searchQuery;
base::flat_set _searchEmoji;
diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp
index 7f5c7a52e..8f5f5fec5 100644
--- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp
+++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp
@@ -422,7 +422,9 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
if (_chat) {
maxListSize += (_chat->participants.empty() ? _chat->lastAuthors.size() : _chat->participants.size());
} else if (_channel && _channel->isMegagroup()) {
- if (!_channel->lastParticipantsRequestNeeded()) {
+ if (!_channel->canViewMembers()) {
+ maxListSize += _channel->mgInfo->admins.size();
+ } else if (!_channel->lastParticipantsRequestNeeded()) {
maxListSize += _channel->mgInfo->lastParticipants.size();
}
}
@@ -488,10 +490,22 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
--i;
mrows.push_back({ i->second });
}
- } else if (_channel
- && _channel->isMegagroup()
- && _channel->canViewMembers()) {
- if (_channel->lastParticipantsRequestNeeded()) {
+ } else if (_channel && _channel->isMegagroup()) {
+ if (!_channel->canViewMembers()) {
+ if (!_channel->mgInfo->adminsLoaded) {
+ _channel->session().api().chatParticipants().requestAdmins(_channel);
+ } else {
+ mrows.reserve(mrows.size() + _channel->mgInfo->admins.size());
+ for (const auto &[userId, rank] : _channel->mgInfo->admins) {
+ if (const auto user = _channel->owner().userLoaded(userId)) {
+ if (user->isInaccessible()) continue;
+ if (!listAllSuggestions && filterNotPassedByName(user)) continue;
+ if (indexOfInFirstN(mrows, user, recentInlineBots) >= 0) continue;
+ mrows.push_back({ user });
+ }
+ }
+ }
+ } else if (_channel->lastParticipantsRequestNeeded()) {
_channel->session().api().chatParticipants().requestLast(
_channel);
} else {
diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp
index b0e263c4a..304c7d3a0 100644
--- a/Telegram/SourceFiles/chat_helpers/message_field.cpp
+++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp
@@ -279,6 +279,19 @@ TextWithTags PrepareEditText(not_null item) {
};
}
+bool EditTextChanged(
+ not_null item,
+ const TextWithTags &updated) {
+ const auto original = PrepareEditText(item);
+
+ // Tags can be different for the same entities, because for
+ // animated emoji each tag contains a different random number.
+ // So we compare entities instead of tags.
+ return (original.text != updated.text)
+ || (TextUtilities::ConvertTextTagsToEntities(original.tags)
+ != TextUtilities::ConvertTextTagsToEntities(updated.tags));
+}
+
Fntype() == QEvent::KeyPress) {
@@ -625,7 +642,7 @@ void MessageLinksParser::parse() {
const auto &text = textWithTags.text;
const auto &tags = textWithTags.tags;
const auto &markdownTags = _field->getMarkdownTags();
- if (text.isEmpty()) {
+ if (_disabled || text.isEmpty()) {
_list = QStringList();
return;
}
diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h
index 13012557b..acc2808a1 100644
--- a/Telegram/SourceFiles/chat_helpers/message_field.h
+++ b/Telegram/SourceFiles/chat_helpers/message_field.h
@@ -37,8 +37,11 @@ namespace Ui {
class PopupMenu;
} // namespace Ui
-QString PrepareMentionTag(not_null user);
-TextWithTags PrepareEditText(not_null item);
+[[nodiscard]] QString PrepareMentionTag(not_null user);
+[[nodiscard]] TextWithTags PrepareEditText(not_null item);
+[[nodiscard]] bool EditTextChanged(
+ not_null item,
+ const TextWithTags &updated);
Fn field);
void parseNow();
+ void setDisabled(bool disabled);
[[nodiscard]] const rpl::variable &list() const;
@@ -126,6 +130,7 @@ private:
not_null _field;
rpl::variable _list;
int _lastLength = 0;
+ bool _disabled = false;
base::Timer _timer;
base::qt_connection _connection;
diff --git a/Telegram/SourceFiles/core/click_handler_types.h b/Telegram/SourceFiles/core/click_handler_types.h
index de5708322..15a7dc1f9 100644
--- a/Telegram/SourceFiles/core/click_handler_types.h
+++ b/Telegram/SourceFiles/core/click_handler_types.h
@@ -38,6 +38,7 @@ class SessionController;
class PeerData;
struct ClickHandlerContext {
FullMsgId itemId;
+ QString attachBotWebviewUrl;
// Is filled from sections.
Fn elementDelegate;
base::weak_ptr sessionWindow;
diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp
index 8d620a0b6..4eaed6178 100644
--- a/Telegram/SourceFiles/core/core_settings.cpp
+++ b/Telegram/SourceFiles/core/core_settings.cpp
@@ -203,7 +203,10 @@ QByteArray Settings::serialize() const {
+ Serialize::bytearraySize(mediaViewPosition)
+ sizeof(qint32)
+ sizeof(quint64)
- + sizeof(qint32);
+ + sizeof(qint32) * 2;
+ for (const auto &id : _recentEmojiSkip) {
+ size += Serialize::stringSize(id);
+ }
auto result = QByteArray();
result.reserve(size);
@@ -338,7 +341,11 @@ QByteArray Settings::serialize() const {
<< mediaViewPosition
<< qint32(_ignoreBatterySaving.current() ? 1 : 0)
<< quint64(_macRoundIconDigest.value_or(0))
- << qint32(_storiesClickTooltipHidden.current() ? 1 : 0);
+ << qint32(_storiesClickTooltipHidden.current() ? 1 : 0)
+ << qint32(_recentEmojiSkip.size());
+ for (const auto &id : _recentEmojiSkip) {
+ stream << id;
+ }
}
return result;
}
@@ -447,6 +454,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 ignoreBatterySaving = _ignoreBatterySaving.current() ? 1 : 0;
quint64 macRoundIconDigest = _macRoundIconDigest.value_or(0);
qint32 storiesClickTooltipHidden = _storiesClickTooltipHidden.current() ? 1 : 0;
+ base::flat_set recentEmojiSkip;
stream >> themesAccentColors;
if (!stream.atEnd()) {
@@ -684,6 +692,19 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> storiesClickTooltipHidden;
}
+ if (!stream.atEnd()) {
+ auto count = qint32();
+ stream >> count;
+ if (stream.status() == QDataStream::Ok) {
+ for (auto i = 0; i != count; ++i) {
+ auto id = QString();
+ stream >> id;
+ if (stream.status() == QDataStream::Ok) {
+ recentEmojiSkip.emplace(id);
+ }
+ }
+ }
+ }
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
@@ -876,6 +897,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
_ignoreBatterySaving = (ignoreBatterySaving == 1);
_macRoundIconDigest = macRoundIconDigest ? macRoundIconDigest : std::optional();
_storiesClickTooltipHidden = (storiesClickTooltipHidden == 1);
+ _recentEmojiSkip = std::move(recentEmojiSkip);
}
QString Settings::getSoundPath(const QString &key) const {
@@ -968,7 +990,8 @@ rpl::producer Settings::thirdColumnWidthChanges() const {
}
const std::vector &Settings::recentEmoji() const {
- if (_recentEmoji.empty()) {
+ if (!_recentEmojiResolved) {
+ _recentEmojiResolved = true;
resolveRecentEmoji();
}
return _recentEmoji;
@@ -1009,6 +1032,8 @@ void Settings::resolveRecentEmoji() const {
for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
if (_recentEmoji.size() >= specialCount + kRecentEmojiLimit) {
break;
+ } else if (_recentEmojiSkip.contains(emoji->id())) {
+ continue;
} else if (!haveAlready({ emoji })) {
_recentEmoji.push_back({ { emoji }, 1 });
}
@@ -1018,6 +1043,9 @@ void Settings::resolveRecentEmoji() const {
void Settings::incrementRecentEmoji(RecentEmojiId id) {
resolveRecentEmoji();
+ if (const auto emoji = std::get_if(&id.data)) {
+ _recentEmojiSkip.remove((*emoji)->id());
+ }
auto i = _recentEmoji.begin(), e = _recentEmoji.end();
for (; i != e; ++i) {
if (i->id == id) {
@@ -1069,6 +1097,36 @@ void Settings::incrementRecentEmoji(RecentEmojiId id) {
_saveDelayed.fire({});
}
+void Settings::hideRecentEmoji(RecentEmojiId id) {
+ resolveRecentEmoji();
+
+ _recentEmoji.erase(
+ ranges::remove(_recentEmoji, id, &RecentEmoji::id),
+ end(_recentEmoji));
+ if (const auto emoji = std::get_if(&id.data)) {
+ for (const auto always : Ui::Emoji::GetDefaultRecent()) {
+ if (always == *emoji) {
+ _recentEmojiSkip.emplace(always->id());
+ break;
+ }
+ }
+ }
+ _recentEmojiUpdated.fire({});
+ _saveDelayed.fire({});
+}
+
+void Settings::resetRecentEmoji() {
+ resolveRecentEmoji();
+
+ _recentEmoji.clear();
+ _recentEmojiSkip.clear();
+ _recentEmojiPreload.clear();
+ _recentEmojiResolved = false;
+
+ _recentEmojiUpdated.fire({});
+ _saveDelayed.fire({});
+}
+
void Settings::setLegacyRecentEmojiPreload(
QVector> data) {
if (!_recentEmojiPreload.empty() || data.isEmpty()) {
@@ -1080,11 +1138,40 @@ void Settings::setLegacyRecentEmojiPreload(
}
}
+EmojiPtr Settings::lookupEmojiVariant(EmojiPtr emoji) const {
+ if (emoji->hasVariants()) {
+ const auto i = _emojiVariants.find(emoji->nonColoredId());
+ if (i != end(_emojiVariants)) {
+ return emoji->variant(i->second);
+ }
+ const auto j = _emojiVariants.find(QString());
+ if (j != end(_emojiVariants)) {
+ return emoji->variant(j->second);
+ }
+ }
+ return emoji;
+}
+
+bool Settings::hasChosenEmojiVariant(EmojiPtr emoji) const {
+ return _emojiVariants.contains(QString())
+ || _emojiVariants.contains(emoji->nonColoredId());
+}
+
void Settings::saveEmojiVariant(EmojiPtr emoji) {
+ Expects(emoji->hasVariants());
+
_emojiVariants[emoji->nonColoredId()] = emoji->variantIndex(emoji);
_saveDelayed.fire({});
}
+void Settings::saveAllEmojiVariants(EmojiPtr emoji) {
+ Expects(emoji->hasVariants());
+
+ _emojiVariants.clear();
+ _emojiVariants[QString()] = emoji->variantIndex(emoji);
+ _saveDelayed.fire({});
+}
+
void Settings::setLegacyEmojiVariants(QMap data) {
if (!_emojiVariants.empty() || data.isEmpty()) {
return;
diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h
index 72468e755..f25345da6 100644
--- a/Telegram/SourceFiles/core/core_settings.h
+++ b/Telegram/SourceFiles/core/core_settings.h
@@ -72,7 +72,7 @@ struct WindowTitleContent {
WindowTitleContent) = default;
};
-constexpr auto kRecentEmojiLimit = 42;
+constexpr auto kRecentEmojiLimit = 54;
struct RecentEmojiDocument {
DocumentId id = 0;
@@ -660,6 +660,8 @@ public:
[[nodiscard]] const std::vector &recentEmoji() const;
void incrementRecentEmoji(RecentEmojiId id);
+ void hideRecentEmoji(RecentEmojiId id);
+ void resetRecentEmoji();
void setLegacyRecentEmojiPreload(QVector> data);
[[nodiscard]] rpl::producer<> recentEmojiUpdated() const {
return _recentEmojiUpdated.events();
@@ -668,7 +670,10 @@ public:
[[nodiscard]] const base::flat_map &emojiVariants() const {
return _emojiVariants;
}
+ [[nodiscard]] EmojiPtr lookupEmojiVariant(EmojiPtr emoji) const;
+ [[nodiscard]] bool hasChosenEmojiVariant(EmojiPtr emoji) const;
void saveEmojiVariant(EmojiPtr emoji);
+ void saveAllEmojiVariants(EmojiPtr emoji);
void setLegacyEmojiVariants(QMap data);
[[nodiscard]] bool disableOpenGL() const {
@@ -891,6 +896,8 @@ private:
rpl::variable _mainMenuAccountsShown = true;
mutable std::vector _recentEmojiPreload;
mutable std::vector _recentEmoji;
+ base::flat_set _recentEmojiSkip;
+ mutable bool _recentEmojiResolved = false;
base::flat_map _emojiVariants;
rpl::event_stream<> _recentEmojiUpdated;
bool _tabbedSelectorSectionEnabled = false; // per-window
diff --git a/Telegram/SourceFiles/core/launcher.cpp b/Telegram/SourceFiles/core/launcher.cpp
index 6c14ccd0e..fee3b0140 100644
--- a/Telegram/SourceFiles/core/launcher.cpp
+++ b/Telegram/SourceFiles/core/launcher.cpp
@@ -466,17 +466,9 @@ void Launcher::initQtMessageLogging() {
QtMsgType type,
const QMessageLogContext &context,
const QString &msg) {
- const auto InvokeOriginal = [&] {
-#ifndef _DEBUG
- if (Logs::DebugEnabled()) {
- return;
- }
-#endif // _DEBUG
- if (OriginalMessageHandler) {
- OriginalMessageHandler(type, context, msg);
- }
- };
- InvokeOriginal();
+ if (OriginalMessageHandler) {
+ OriginalMessageHandler(type, context, msg);
+ }
if (Logs::DebugEnabled() || !Logs::started()) {
if (!Logs::WritingEntry()) {
// Sometimes Qt logs something inside our own logging.
diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp
index d18b842c0..9daf74d62 100644
--- a/Telegram/SourceFiles/core/local_url_handlers.cpp
+++ b/Telegram/SourceFiles/core/local_url_handlers.cpp
@@ -412,6 +412,7 @@ bool ResolveUsernameOrPhone(
}
const auto myContext = context.value();
using Navigation = Window::SessionNavigation;
+ controller->window().activate();
controller->showPeerByLink(Navigation::PeerByLinkInfo{
.usernameOrId = domain,
.phone = phone,
@@ -446,8 +447,8 @@ bool ResolveUsernameOrPhone(
? std::make_optional(params.value(u"voicechat"_q))
: std::nullopt),
.clickFromMessageId = myContext.itemId,
+ .clickFromAttachBotWebviewUrl = myContext.attachBotWebviewUrl,
});
- controller->window().activate();
return true;
}
@@ -473,7 +474,7 @@ bool ResolvePrivatePost(
if (!channelId || (msgId && !IsServerMsgId(msgId))) {
return false;
}
- const auto fromMessageId = context.value().itemId;
+ const auto my = context.value();
using Navigation = Window::SessionNavigation;
controller->showPeerByLink(Navigation::PeerByLinkInfo{
.usernameOrId = channelId,
@@ -487,7 +488,8 @@ bool ResolvePrivatePost(
Navigation::ThreadId{ threadId }
}
: Navigation::RepliesByLinkInfo{ v::null },
- .clickFromMessageId = fromMessageId,
+ .clickFromMessageId = my.itemId,
+ .clickFromAttachBotWebviewUrl = my.attachBotWebviewUrl,
});
controller->window().activate();
return true;
diff --git a/Telegram/SourceFiles/core/sandbox.cpp b/Telegram/SourceFiles/core/sandbox.cpp
index c051a4375..1c1419bb2 100644
--- a/Telegram/SourceFiles/core/sandbox.cpp
+++ b/Telegram/SourceFiles/core/sandbox.cpp
@@ -586,7 +586,7 @@ void Sandbox::registerEnterFromEventLoop() {
bool Sandbox::notifyOrInvoke(QObject *receiver, QEvent *e) {
const auto type = e->type();
- if (type == base::InvokeQueuedEvent::kType) {
+ if (type == base::InvokeQueuedEvent::Type()) {
static_cast(e)->invoke();
return true;
} else if (receiver == this) {
diff --git a/Telegram/SourceFiles/core/ui_integration.cpp b/Telegram/SourceFiles/core/ui_integration.cpp
index e7351e8fd..ead942262 100644
--- a/Telegram/SourceFiles/core/ui_integration.cpp
+++ b/Telegram/SourceFiles/core/ui_integration.cpp
@@ -282,15 +282,10 @@ rpl::producer<> UiIntegration::forcePopupMenuHideRequests() {
const Ui::Emoji::One *UiIntegration::defaultEmojiVariant(
const Ui::Emoji::One *emoji) {
- if (!emoji || !emoji->hasVariants()) {
+ if (!emoji) {
return emoji;
}
- const auto nonColored = emoji->nonColoredId();
- const auto &variants = Core::App().settings().emojiVariants();
- const auto i = variants.find(nonColored);
- const auto result = (i != end(variants))
- ? emoji->variant(i->second)
- : emoji;
+ const auto result = Core::App().settings().lookupEmojiVariant(emoji);
Core::App().settings().incrementRecentEmoji({ result });
return result;
}
diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h
index df60a4902..e6f40049b 100644
--- a/Telegram/SourceFiles/core/version.h
+++ b/Telegram/SourceFiles/core/version.h
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
constexpr auto AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs;
-constexpr auto AppVersion = 4008011;
-constexpr auto AppVersionStr = "4.8.11";
-constexpr auto AppBetaVersion = true;
+constexpr auto AppVersion = 4009003;
+constexpr auto AppVersionStr = "4.9.3";
+constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
diff --git a/Telegram/SourceFiles/data/data_changes.h b/Telegram/SourceFiles/data/data_changes.h
index d4fee22c8..304749900 100644
--- a/Telegram/SourceFiles/data/data_changes.h
+++ b/Telegram/SourceFiles/data/data_changes.h
@@ -226,8 +226,9 @@ struct StoryUpdate {
NewAdded = (1U << 2),
ViewsAdded = (1U << 3),
MarkRead = (1U << 4),
+ Reaction = (1U << 5),
- LastUsedBit = (1U << 4),
+ LastUsedBit = (1U << 5),
};
using Flags = base::flags;
friend inline constexpr auto is_flag_type(Flag) { return true; }
diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h
index 9817da915..6c05d5c88 100644
--- a/Telegram/SourceFiles/data/data_channel.h
+++ b/Telegram/SourceFiles/data/data_channel.h
@@ -116,6 +116,7 @@ public:
QString creatorRank;
int botStatus = 0; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other
bool joinedMessageFound = false;
+ bool adminsLoaded = false;
StickerSetIdentifier stickerSet;
enum LastParticipantsStatus {
diff --git a/Telegram/SourceFiles/data/data_download_manager.cpp b/Telegram/SourceFiles/data/data_download_manager.cpp
index 088dc0b92..6b984e4cf 100644
--- a/Telegram/SourceFiles/data/data_download_manager.cpp
+++ b/Telegram/SourceFiles/data/data_download_manager.cpp
@@ -64,26 +64,43 @@ constexpr auto ByDocument = [](const auto &entry) {
return 0;
}
-[[nodiscard]] PhotoData *ItemPhoto(not_null item) {
- if (const auto media = item->media()) {
- if (const auto page = media->webpage()) {
- return page->document ? nullptr : page->photo;
- } else if (const auto photo = media->photo()) {
- return photo;
+[[nodiscard]] bool ItemContainsMedia(const DownloadObject &object) {
+ if (const auto photo = object.photo) {
+ if (const auto media = object.item->media()) {
+ if (const auto page = media->webpage()) {
+ if (page->photo == photo) {
+ return true;
+ }
+ for (const auto &item : page->collage.items) {
+ if (const auto v = std::get_if(&item)) {
+ if ((*v) == photo) {
+ return true;
+ }
+ }
+ }
+ } else {
+ return (media->photo() == photo);
+ }
+ }
+ } else if (const auto document = object.document) {
+ if (const auto media = object.item->media()) {
+ if (const auto page = media->webpage()) {
+ if (page->document == document) {
+ return true;
+ }
+ for (const auto &item : page->collage.items) {
+ if (const auto v = std::get_if(&item)) {
+ if ((*v) == document) {
+ return true;
+ }
+ }
+ }
+ } else {
+ return (media->document() == document);
+ }
}
}
- return nullptr;
-}
-
-[[nodiscard]] DocumentData *ItemDocument(not_null item) {
- if (const auto media = item->media()) {
- if (const auto page = media->webpage()) {
- return page->document;
- } else if (const auto document = media->document()) {
- return document;
- }
- }
- return nullptr;
+ return false;
}
struct DocumentDescriptor {
@@ -242,12 +259,12 @@ void DownloadManager::check(
std::vector::iterator i) {
auto &entry = *i;
- const auto photo = ItemPhoto(entry.object.item);
- const auto document = ItemDocument(entry.object.item);
- if (entry.object.photo != photo || entry.object.document != document) {
+ if (!ItemContainsMedia(entry.object)) {
cancel(data, i);
return;
}
+ const auto document = entry.object.document;
+
// Load with progress only documents for now.
Assert(document != nullptr);
@@ -794,11 +811,14 @@ void DownloadManager::cancel(
SessionData &data,
std::vector::iterator i) {
const auto object = i->object;
+ const auto item = object.item;
remove(data, i);
- if (const auto document = object.document) {
- document->cancel();
- } else if (const auto photo = object.photo) {
- photo->cancel();
+ if (!item->isAdminLogEntry()) {
+ if (const auto document = object.document) {
+ document->cancel();
+ } else if (const auto photo = object.photo) {
+ photo->cancel();
+ }
}
}
diff --git a/Telegram/SourceFiles/data/data_file_click_handler.cpp b/Telegram/SourceFiles/data/data_file_click_handler.cpp
index 9fee965f5..e42397d19 100644
--- a/Telegram/SourceFiles/data/data_file_click_handler.cpp
+++ b/Telegram/SourceFiles/data/data_file_click_handler.cpp
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_download_manager.h"
#include "data/data_photo.h"
+#include "main/main_session.h"
FileClickHandler::FileClickHandler(FullMsgId context)
: _context(context) {
@@ -73,14 +74,25 @@ void DocumentOpenClickHandler::onClickImpl() const {
void DocumentSaveClickHandler::Save(
Data::FileOrigin origin,
not_null data,
- Mode mode) {
+ Mode mode,
+ Fn started) {
if (data->isNull()) {
return;
}
auto savename = QString();
- if (mode != Mode::ToCacheOrFile || !data->saveToCache()) {
+ if (mode == Mode::ToCacheOrFile && data->saveToCache()) {
+ data->save(origin, savename);
+ return;
+ }
+ InvokeQueued(qApp, crl::guard(&data->session(), [=] {
+ // If we call file dialog synchronously, it will stop
+ // background thread timers from working which would
+ // stop audio playback in voice chats / live streams.
if (mode != Mode::ToNewFile && data->saveFromData()) {
+ if (started) {
+ started();
+ }
return;
}
const auto filepath = data->filepath(true);
@@ -92,31 +104,38 @@ void DocumentSaveClickHandler::Save(
const auto filename = filepath.isEmpty()
? QString()
: fileinfo.fileName();
- savename = DocumentFileNameForSave(
+ const auto savename = DocumentFileNameForSave(
data,
(mode == Mode::ToNewFile),
filename,
filedir);
- if (savename.isEmpty()) {
- return;
+ if (!savename.isEmpty()) {
+ data->save(origin, savename);
+ if (started) {
+ started();
+ }
}
- }
- data->save(origin, savename);
+ }));
}
void DocumentSaveClickHandler::SaveAndTrack(
FullMsgId itemId,
not_null document,
- Mode mode) {
- Save(itemId ? itemId : Data::FileOrigin(), document, mode);
- if (document->loading() && !document->loadingFilePath().isEmpty()) {
- if (const auto item = document->owner().message(itemId)) {
- Core::App().downloadManager().addLoading({
- .item = item,
- .document = document,
- });
+ Mode mode,
+ Fn started) {
+ Save(itemId ? itemId : Data::FileOrigin(), document, mode, [=] {
+ if (document->loading() && !document->loadingFilePath().isEmpty()) {
+ if (const auto item = document->owner().message(itemId)) {
+ Core::App().downloadManager().addLoading({
+ .item = item,
+ .document = document,
+ });
+ }
}
- }
+ if (started) {
+ started();
+ }
+ });
}
void DocumentSaveClickHandler::onClickImpl() const {
diff --git a/Telegram/SourceFiles/data/data_file_click_handler.h b/Telegram/SourceFiles/data/data_file_click_handler.h
index 472d04d15..46eaa5b82 100644
--- a/Telegram/SourceFiles/data/data_file_click_handler.h
+++ b/Telegram/SourceFiles/data/data_file_click_handler.h
@@ -53,11 +53,13 @@ public:
static void Save(
Data::FileOrigin origin,
not_null document,
- Mode mode = Mode::ToCacheOrFile);
+ Mode mode = Mode::ToCacheOrFile,
+ Fn started = nullptr);
static void SaveAndTrack(
FullMsgId itemId,
not_null document,
- Mode mode = Mode::ToCacheOrFile);
+ Mode mode = Mode::ToCacheOrFile,
+ Fn started = nullptr);
protected:
void onClickImpl() const override;
diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp
index 19d89c500..7a36a5515 100644
--- a/Telegram/SourceFiles/data/data_media_types.cpp
+++ b/Telegram/SourceFiles/data/data_media_types.cpp
@@ -1848,8 +1848,7 @@ ClickHandlerPtr MediaDice::MakeHandler(
.multiline = true,
};
if (CanSend(history->peer, ChatRestriction::SendOther)) {
- auto link = Ui::Text::Link(
- tr::lng_about_random_send(tr::now).toUpper());
+ auto link = Ui::Text::Link(tr::lng_about_random_send(tr::now));
link.entities.push_back(
EntityInText(EntityType::Semibold, 0, link.text.size()));
config.text.append(' ').append(std::move(link));
diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp
index e4279cbb3..7aa820101 100644
--- a/Telegram/SourceFiles/data/data_message_reactions.cpp
+++ b/Telegram/SourceFiles/data/data_message_reactions.cpp
@@ -381,7 +381,7 @@ void Reactions::preloadImageFor(const ReactionId &id) {
loadImage(set, document, !i->centerIcon);
} else if (!_waitingForList) {
_waitingForList = true;
- refreshRecent();
+ refreshDefault();
}
}
diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp
index 273e60663..b879d4bc5 100644
--- a/Telegram/SourceFiles/data/data_stories.cpp
+++ b/Telegram/SourceFiles/data/data_stories.cpp
@@ -192,6 +192,14 @@ void Stories::apply(const MTPDupdateReadStories &data) {
bumpReadTill(peerFromUser(data.vuser_id()), data.vmax_id().v);
}
+void Stories::apply(const MTPStoriesStealthMode &stealthMode) {
+ const auto &data = stealthMode.data();
+ _stealthMode = StealthMode{
+ .enabledTill = data.vactive_until_date().value_or_empty(),
+ .cooldownTill = data.vcooldown_until_date().value_or_empty(),
+ };
+}
+
void Stories::apply(not_null peer, const MTPUserStories *data) {
// AyuGram disableStories
const auto settings = &AyuSettings::getInstance();
@@ -369,7 +377,10 @@ void Stories::parseAndApply(const MTPUserStories &stories) {
}
sort(list);
};
- if (result.user->isContact()) {
+ if (result.user->isSelf()
+ || result.user->isBot()
+ || result.user->isServiceUser()
+ || result.user->isContact()) {
const auto hidden = result.user->hasStoriesHidden();
using List = StorySourcesList;
add(hidden ? List::Hidden : List::NotHidden);
@@ -568,6 +579,10 @@ void Stories::loadMore(StorySourcesList list) {
}, [](const MTPDstories_allStoriesNotModified &) {
});
+ result.match([&](const auto &data) {
+ apply(data.vstealth_mode());
+ });
+
preloadListsMore();
}).fail([=] {
_loadMoreRequestId[index] = 0;
@@ -751,6 +766,7 @@ void Stories::applyDeleted(FullStoryId id) {
}
}
if (_preloading && _preloading->id() == id) {
+ _preloading = nullptr;
preloadFinished(id);
}
_owner->refreshStoryItemViews(id);
@@ -868,6 +884,42 @@ std::shared_ptr Stories::lookupItem(not_null story) {
return j->second.lock();
}
+StealthMode Stories::stealthMode() const {
+ return _stealthMode.current();
+}
+
+rpl::producer Stories::stealthModeValue() const {
+ return _stealthMode.value();
+}
+
+void Stories::activateStealthMode(Fn done) {
+ const auto api = &session().api();
+ using Flag = MTPstories_ActivateStealthMode::Flag;
+ api->request(MTPstories_ActivateStealthMode(
+ MTP_flags(Flag::f_past | Flag::f_future)
+ )).done([=](const MTPUpdates &result) {
+ api->applyUpdates(result);
+ if (done) done();
+ }).fail([=] {
+ if (done) done();
+ }).send();
+}
+
+void Stories::sendReaction(FullStoryId id, Data::ReactionId reaction) {
+ if (const auto maybeStory = lookup(id)) {
+ const auto story = *maybeStory;
+ story->setReactionId(reaction);
+
+ const auto api = &session().api();
+ api->request(MTPstories_SendReaction(
+ MTP_flags(0),
+ story->peer()->asUser()->inputUser,
+ MTP_int(id.story),
+ ReactionToMTP(reaction)
+ )).send();
+ }
+}
+
std::shared_ptr Stories::resolveItem(not_null story) {
auto &items = _items[story->peer()->id];
auto i = items.find(story->id());
@@ -1251,11 +1303,11 @@ void Stories::sendIncrementViewsRequests() {
void Stories::loadViewsSlice(
StoryId id,
- std::optional offset,
- Fn)> done) {
+ QString offset,
+ Fn done) {
if (_viewsStoryId == id
&& _viewsOffset == offset
- && (offset || _viewsRequestId)) {
+ && (!offset.isEmpty() || _viewsRequestId)) {
if (_viewsRequestId) {
_viewsDone = std::move(done);
}
@@ -1268,22 +1320,30 @@ void Stories::loadViewsSlice(
const auto api = &_owner->session().api();
const auto perPage = _viewsDone ? kViewsPerPage : kPollingViewsPerPage;
api->request(_viewsRequestId).cancel();
+ using Flag = MTPstories_GetStoryViewsList::Flag;
_viewsRequestId = api->request(MTPstories_GetStoryViewsList(
+ MTP_flags(Flag::f_reactions_first),
+ MTPstring(), // q
MTP_int(id),
- MTP_int(offset ? offset->date : 0),
- MTP_long(offset ? peerToUser(offset->peer->id).bare : 0),
+ MTP_string(offset),
MTP_int(perPage)
)).done([=](const MTPstories_StoryViewsList &result) {
_viewsRequestId = 0;
- auto slice = std::vector();
-
const auto &data = result.data();
+ auto slice = StoryViews{
+ .nextOffset = data.vnext_offset().value_or_empty(),
+ .reactions = data.vreactions_count().v,
+ .total = data.vcount().v,
+ };
_owner->processUsers(data.vusers());
- slice.reserve(data.vviews().v.size());
+ slice.list.reserve(data.vviews().v.size());
for (const auto &view : data.vviews().v) {
- slice.push_back({
+ slice.list.push_back({
.peer = _owner->peer(peerFromUser(view.data().vuser_id())),
+ .reaction = (view.data().vreaction()
+ ? ReactionFromMTP(*view.data().vreaction())
+ : Data::ReactionId()),
.date = view.data().vdate().v,
});
}
@@ -1292,7 +1352,7 @@ void Stories::loadViewsSlice(
.story = _viewsStoryId,
};
if (const auto story = lookup(fullId)) {
- (*story)->applyViewsSlice(_viewsOffset, slice, data.vcount().v);
+ (*story)->applyViewsSlice(_viewsOffset, slice);
}
if (const auto done = base::take(_viewsDone)) {
done(std::move(slice));
@@ -1731,7 +1791,7 @@ void Stories::sendPollingViewsRequests() {
return;
} else if (!_viewsRequestId) {
Assert(_viewsDone == nullptr);
- loadViewsSlice(_pollingViews.front()->id(), std::nullopt, nullptr);
+ loadViewsSlice(_pollingViews.front()->id(), QString(), nullptr);
}
_pollingViewsTimer.callOnce(kPollViewsInterval);
}
diff --git a/Telegram/SourceFiles/data/data_stories.h b/Telegram/SourceFiles/data/data_stories.h
index 48ea79688..8d8b23da4 100644
--- a/Telegram/SourceFiles/data/data_stories.h
+++ b/Telegram/SourceFiles/data/data_stories.h
@@ -116,6 +116,14 @@ struct StoriesContext {
friend inline bool operator==(StoriesContext, StoriesContext) = default;
};
+struct StealthMode {
+ TimeId enabledTill = 0;
+ TimeId cooldownTill = 0;
+
+ friend inline auto operator<=>(StealthMode, StealthMode) = default;
+ friend inline bool operator==(StealthMode, StealthMode) = default;
+};
+
inline constexpr auto kStorySourcesListCount = 2;
class Stories final : public base::has_weak_ptr {
@@ -139,6 +147,7 @@ public:
void loadMore(StorySourcesList list);
void apply(const MTPDupdateStory &data);
void apply(const MTPDupdateReadStories &data);
+ void apply(const MTPStoriesStealthMode &stealthMode);
void apply(not_null peer, const MTPUserStories *data);
Story *applyFromWebpage(PeerId peerId, const MTPstoryItem &story);
void loadAround(FullStoryId id, StoriesContext context);
@@ -170,8 +179,8 @@ public:
static constexpr auto kViewsPerPage = 50;
void loadViewsSlice(
StoryId id,
- std::optional offset,
- Fn)> done);
+ QString offset,
+ Fn done);
[[nodiscard]] const StoriesIds &archive() const;
[[nodiscard]] rpl::producer<> archiveChanged() const;
@@ -227,6 +236,12 @@ public:
[[nodiscard]] std::shared_ptr lookupItem(
not_null story);
+ [[nodiscard]] StealthMode stealthMode() const;
+ [[nodiscard]] rpl::producer stealthModeValue() const;
+ void activateStealthMode(Fn done = nullptr);
+
+ void sendReaction(FullStoryId id, Data::ReactionId reaction);
+
private:
struct Saved {
StoriesIds ids;
@@ -353,8 +368,8 @@ private:
base::flat_set _incrementViewsRequests;
StoryId _viewsStoryId = 0;
- std::optional _viewsOffset;
- Fn)> _viewsDone;
+ QString _viewsOffset;
+ Fn _viewsDone;
mtpRequestId _viewsRequestId = 0;
base::flat_set _preloaded;
@@ -375,6 +390,8 @@ private:
base::Timer _pollingTimer;
base::Timer _pollingViewsTimer;
+ rpl::variable _stealthMode;
+
};
} // namespace Data
diff --git a/Telegram/SourceFiles/data/data_story.cpp b/Telegram/SourceFiles/data/data_story.cpp
index fbc678581..d5faa4350 100644
--- a/Telegram/SourceFiles/data/data_story.cpp
+++ b/Telegram/SourceFiles/data/data_story.cpp
@@ -31,6 +31,47 @@ namespace {
using UpdateFlag = StoryUpdate::Flag;
+[[nodiscard]] StoryArea ParseArea(const MTPMediaAreaCoordinates &area) {
+ const auto &data = area.data();
+ const auto center = QPointF(data.vx().v, data.vy().v);
+ const auto size = QSizeF(data.vw().v, data.vh().v);
+ const auto corner = center - QPointF(size.width(), size.height()) / 2.;
+ return {
+ .geometry = { corner / 100., size / 100. },
+ .rotation = data.vrotation().v,
+ };
+}
+
+[[nodiscard]] auto ParseLocation(const MTPMediaArea &area)
+-> std::optional {
+ auto result = std::optional();
+ area.match([&](const MTPDmediaAreaVenue &data) {
+ data.vgeo().match([&](const MTPDgeoPoint &geo) {
+ result.emplace(StoryLocation{
+ .area = ParseArea(data.vcoordinates()),
+ .point = Data::LocationPoint(geo),
+ .title = qs(data.vtitle()),
+ .address = qs(data.vaddress()),
+ .provider = qs(data.vprovider()),
+ .venueId = qs(data.vvenue_id()),
+ .venueType = qs(data.vvenue_type()),
+ });
+ }, [](const MTPDgeoPointEmpty &) {
+ });
+ }, [&](const MTPDmediaAreaGeoPoint &data) {
+ data.vgeo().match([&](const MTPDgeoPoint &geo) {
+ result.emplace(StoryLocation{
+ .area = ParseArea(data.vcoordinates()),
+ .point = Data::LocationPoint(geo),
+ });
+ }, [](const MTPDgeoPointEmpty &) {
+ });
+ }, [&](const MTPDinputMediaAreaVenue &data) {
+ LOG(("API Error: Unexpected inputMediaAreaVenue in API data."));
+ });
+ return result;
+}
+
} // namespace
class StoryPreload::LoadTask final : private Storage::DownloadMtprotoTask {
@@ -276,8 +317,13 @@ bool Story::edited() const {
return _edited;
}
-bool Story::canDownload() const {
- return /*!forbidsForward() || */_peer->isSelf();
+bool Story::canDownloadIfPremium() const {
+ return !forbidsForward() || _peer->isSelf();
+}
+
+bool Story::canDownloadChecked() const {
+ return _peer->isSelf()
+ || (canDownloadIfPremium() && _peer->session().premium());
}
bool Story::canShare() const {
@@ -330,55 +376,61 @@ const TextWithEntities &Story::caption() const {
return unsupported() ? empty : _caption;
}
+Data::ReactionId Story::sentReactionId() const {
+ return _sentReactionId;
+}
+
+void Story::setReactionId(Data::ReactionId id) {
+ if (_sentReactionId != id) {
+ _sentReactionId = id;
+ session().changes().storyUpdated(this, UpdateFlag::Reaction);
+ }
+}
+
const std::vector> &Story::recentViewers() const {
return _recentViewers;
}
-const std::vector &Story::viewsList() const {
- return _viewsList;
-}
-
-int Story::views() const {
+const StoryViews &Story::viewsList() const {
return _views;
}
+int Story::views() const {
+ return _views.total;
+}
+
+int Story::reactions() const {
+ return _views.reactions;
+}
+
void Story::applyViewsSlice(
- const std::optional &offset,
- const std::vector &slice,
- int total) {
- const auto changed = (_views != total);
- _views = total;
- if (!offset) {
- const auto i = _viewsList.empty()
- ? end(slice)
- : ranges::find(slice, _viewsList.front());
- const auto merge = (i != end(slice))
- && !ranges::contains(slice, _viewsList.back());
- if (merge) {
- _viewsList.insert(begin(_viewsList), begin(slice), i);
- } else {
- _viewsList = slice;
- }
- } else if (!slice.empty()) {
- const auto i = ranges::find(_viewsList, *offset);
- const auto merge = (i != end(_viewsList))
- && !ranges::contains(_viewsList, slice.back());
- if (merge) {
- const auto after = i + 1;
- if (after == end(_viewsList)) {
- _viewsList.insert(after, begin(slice), end(slice));
- } else {
- const auto j = ranges::find(slice, _viewsList.back());
- if (j != end(slice)) {
- _viewsList.insert(end(_viewsList), j + 1, end(slice));
- }
- }
+ const QString &offset,
+ const StoryViews &slice) {
+ const auto changed = (_views.reactions != slice.reactions)
+ || (_views.total != slice.total);
+ _views.reactions = slice.reactions;
+ _views.total = slice.total;
+ if (offset.isEmpty()) {
+ _views = slice;
+ } else if (_views.nextOffset == offset) {
+ _views.list.insert(
+ end(_views.list),
+ begin(slice.list),
+ end(slice.list));
+ _views.nextOffset = slice.nextOffset;
+ if (_views.nextOffset.isEmpty()) {
+ _views.total = int(_views.list.size());
+ _views.reactions = _views.total
+ - ranges::count(
+ _views.list,
+ Data::ReactionId(),
+ &StoryView::reaction);
}
}
- const auto known = int(_viewsList.size());
+ const auto known = int(_views.list.size());
if (known >= _recentViewers.size()) {
const auto take = std::min(known, kRecentViewersMax);
- auto viewers = _viewsList
+ auto viewers = _views.list
| ranges::views::take(take)
| ranges::views::transform(&StoryView::peer)
| ranges::to_vector;
@@ -399,6 +451,10 @@ void Story::applyViewsSlice(
}
}
+const std::vector &Story::locations() const {
+ return _locations;
+}
+
void Story::applyChanges(
StoryMedia media,
const MTPDstoryItem &data,
@@ -413,6 +469,9 @@ void Story::applyFields(
bool initial) {
_lastUpdateTime = now;
+ const auto reaction = data.vsent_reaction()
+ ? Data::ReactionFromMTP(*data.vsent_reaction())
+ : Data::ReactionId();
const auto pinned = data.is_pinned();
const auto edited = data.is_edited();
const auto privacy = data.is_public()
@@ -431,11 +490,13 @@ void Story::applyFields(
&owner().session(),
data.ventities().value_or_empty()),
};
- auto views = _views;
+ auto views = _views.total;
+ auto reactions = _views.reactions;
auto viewers = std::vector>();
if (!data.is_min()) {
if (const auto info = data.vviews()) {
views = info->data().vviews_count().v;
+ reactions = info->data().vreactions_count().v;
if (const auto list = info->data().vrecent_viewers()) {
viewers.reserve(list->v.size());
auto &owner = _peer->owner();
@@ -447,13 +508,25 @@ void Story::applyFields(
}
}
}
+ auto locations = std::vector();
+ if (const auto areas = data.vmedia_areas()) {
+ locations.reserve(areas->v.size());
+ for (const auto &area : areas->v) {
+ if (const auto parsed = ParseLocation(area)) {
+ locations.push_back(*parsed);
+ }
+ }
+ }
const auto pinnedChanged = (_pinned != pinned);
const auto editedChanged = (_edited != edited);
const auto mediaChanged = (_media != media);
const auto captionChanged = (_caption != caption);
- const auto viewsChanged = (_views != views)
+ const auto viewsChanged = (_views.total != views)
+ || (_views.reactions != reactions)
|| (_recentViewers != viewers);
+ const auto locationsChanged = (_locations != locations);
+ const auto reactionChanged = (_sentReactionId != reaction);
_privacyPublic = (privacy == StoryPrivacy::Public);
_privacyCloseFriends = (privacy == StoryPrivacy::CloseFriends);
@@ -463,8 +536,10 @@ void Story::applyFields(
_edited = edited;
_pinned = pinned;
_noForwards = noForwards;
+ if (_views.reactions != reactions || _views.total != views) {
+ _views = StoryViews{ .reactions = reactions, .total = views };
+ }
if (viewsChanged) {
- _views = views;
_recentViewers = std::move(viewers);
}
if (mediaChanged) {
@@ -473,12 +548,22 @@ void Story::applyFields(
if (captionChanged) {
_caption = std::move(caption);
}
+ if (locationsChanged) {
+ _locations = std::move(locations);
+ }
+ if (reactionChanged) {
+ _sentReactionId = reaction;
+ }
- const auto changed = (editedChanged || captionChanged || mediaChanged);
- if (!initial && (changed || viewsChanged)) {
+ const auto changed = editedChanged
+ || captionChanged
+ || mediaChanged
+ || locationsChanged;
+ if (!initial && (changed || viewsChanged || reactionChanged)) {
_peer->session().changes().storyUpdated(this, UpdateFlag()
| (changed ? UpdateFlag::Edited : UpdateFlag())
- | (viewsChanged ? UpdateFlag::ViewsAdded : UpdateFlag()));
+ | (viewsChanged ? UpdateFlag::ViewsAdded : UpdateFlag())
+ | (reactionChanged ? UpdateFlag::Reaction : UpdateFlag()));
}
if (!initial && (captionChanged || mediaChanged)) {
if (const auto item = _peer->owner().stories().lookupItem(this)) {
diff --git a/Telegram/SourceFiles/data/data_story.h b/Telegram/SourceFiles/data/data_story.h
index 8ea17b7b7..dcfe4495c 100644
--- a/Telegram/SourceFiles/data/data_story.h
+++ b/Telegram/SourceFiles/data/data_story.h
@@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "base/weak_ptr.h"
+#include "data/data_location.h"
+#include "data/data_message_reaction_id.h"
class Image;
class PhotoData;
@@ -58,11 +60,42 @@ struct StoryMedia {
struct StoryView {
not_null peer;
+ Data::ReactionId reaction;
TimeId date = 0;
friend inline bool operator==(StoryView, StoryView) = default;
};
+struct StoryViews {
+ std::vector list;
+ QString nextOffset;
+ int reactions = 0;
+ int total = 0;
+};
+
+struct StoryArea {
+ QRectF geometry;
+ float64 rotation = 0;
+
+ friend inline bool operator==(
+ const StoryArea &,
+ const StoryArea &) = default;
+};
+
+struct StoryLocation {
+ StoryArea area;
+ Data::LocationPoint point;
+ QString title;
+ QString address;
+ QString provider;
+ QString venueId;
+ QString venueType;
+
+ friend inline bool operator==(
+ const StoryLocation &,
+ const StoryLocation &) = default;
+};
+
class Story final {
public:
Story(
@@ -100,7 +133,8 @@ public:
[[nodiscard]] bool forbidsForward() const;
[[nodiscard]] bool edited() const;
- [[nodiscard]] bool canDownload() const;
+ [[nodiscard]] bool canDownloadIfPremium() const;
+ [[nodiscard]] bool canDownloadChecked() const;
[[nodiscard]] bool canShare() const;
[[nodiscard]] bool canDelete() const;
[[nodiscard]] bool canReport() const;
@@ -112,14 +146,17 @@ public:
void setCaption(TextWithEntities &&caption);
[[nodiscard]] const TextWithEntities &caption() const;
+ [[nodiscard]] Data::ReactionId sentReactionId() const;
+ void setReactionId(Data::ReactionId id);
+
[[nodiscard]] auto recentViewers() const
-> const std::vector> &;
- [[nodiscard]] const std::vector &viewsList() const;
+ [[nodiscard]] const StoryViews &viewsList() const;
[[nodiscard]] int views() const;
- void applyViewsSlice(
- const std::optional &offset,
- const std::vector &slice,
- int total);
+ [[nodiscard]] int reactions() const;
+ void applyViewsSlice(const QString &offset, const StoryViews &slice);
+
+ [[nodiscard]] const std::vector &locations() const;
void applyChanges(
StoryMedia media,
@@ -136,11 +173,12 @@ private:
const StoryId _id = 0;
const not_null _peer;
+ Data::ReactionId _sentReactionId;
StoryMedia _media;
TextWithEntities _caption;
std::vector> _recentViewers;
- std::vector _viewsList;
- int _views = 0;
+ std::vector _locations;
+ StoryViews _views;
const TimeId _date = 0;
const TimeId _expires = 0;
TimeId _lastUpdateTime = 0;
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
index d0d01778b..697862166 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
@@ -2818,12 +2818,9 @@ void InnerWidget::resizeEmptyLabel() {
if (!_empty) {
return;
}
- const auto useWidth = std::min(
- _empty->naturalWidth(),
- width() - 2 * st::dialogsEmptySkip);
- const auto left = (width() - useWidth) / 2;
- _empty->resizeToWidth(useWidth);
- _empty->move(left, (st::dialogsEmptyHeight - _empty->height()) / 2);
+ const auto skip = st::dialogsEmptySkip;
+ _empty->resizeToWidth(width() - 2 * skip);
+ _empty->move(skip, (st::dialogsEmptyHeight - _empty->height()) / 2);
}
void InnerWidget::clearMouseSelection(bool clearSelection) {
diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
index 9b02fa341..c19d5e4b1 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
@@ -125,7 +125,7 @@ Widget::BottomButton::BottomButton(
const style::icon &icon,
const style::icon &iconOver)
: RippleButton(parent, st.ripple)
-, _text(text.toUpper())
+, _text(text)
, _st(st)
, _icon(icon)
, _iconOver(iconOver) {
@@ -133,7 +133,7 @@ Widget::BottomButton::BottomButton(
}
void Widget::BottomButton::setText(const QString &text) {
- _text = text.toUpper();
+ _text = text;
update();
}
@@ -1457,6 +1457,8 @@ void Widget::startWidthAnimation() {
st::columnMinimalWidthLeft,
scrollGeometry.height());
_scroll->setGeometry(grabGeometry);
+ _inner->resize(st::columnMinimalWidthLeft, _inner->height());
+ _inner->setNarrowRatio(0.);
Ui::SendPendingMoveResizeEvents(_scroll);
auto image = QImage(
grabGeometry.size() * cIntRetinaFactor(),
@@ -1468,7 +1470,10 @@ void Widget::startWidthAnimation() {
Ui::RenderWidget(p, _scroll);
}
_widthAnimationCache = Ui::PixmapFromImage(std::move(image));
- _scroll->setGeometry(scrollGeometry);
+ if (scrollGeometry != grabGeometry) {
+ _scroll->setGeometry(scrollGeometry);
+ updateControlsGeometry();
+ }
_scroll->hide();
updateStoriesVisibility();
}
diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp
index ed723b55e..f737d1615 100644
--- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp
+++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp
@@ -347,9 +347,7 @@ Content State::next() {
}
result.elements.push_back({
.id = uint64(user->id.value),
- .name = (user->isSelf()
- ? tr::lng_stories_my_name(tr::now)
- : user->shortName()),
+ .name = user->shortName(),
.thumbnail = std::move(userpic),
.count = info.count,
.unreadCount = info.unreadCount,
diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp
index 82854b90b..cda8da94d 100644
--- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp
+++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp
@@ -671,7 +671,14 @@ void List::validateName(not_null- item) {
const auto &full = _st.full;
const auto &font = full.nameStyle.font;
const auto available = AvailableNameWidth(_st);
- const auto text = Ui::Text::String(full.nameStyle, element.name);
+ const auto my = element.skipSmall
+ ? tr::lng_stories_my_name(tr::now)
+ : QString();
+ const auto use = (my.isEmpty()
+ || full.nameStyle.font->width(my) > available)
+ ? element.name
+ : my;
+ const auto text = Ui::Text::String(full.nameStyle, use);
const auto ratio = style::DevicePixelRatio();
item->nameCacheColor = color->c;
item->nameCache = QImage(
diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp
index 0d166a1e3..e105cd441 100644
--- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp
+++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp
@@ -16,6 +16,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include
#endif // LIB_FFMPEG_USE_QT_PRIVATE_API
+#include
+
extern "C" {
#include
#if !defined DESKTOP_APP_USE_PACKAGED && !defined Q_OS_WIN && !defined Q_OS_MAC
diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
index f6e5c92d5..2b49f8c1c 100644
--- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
+++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
@@ -1468,7 +1468,7 @@ void InnerWidget::suggestRestrictParticipant(
editRestrictions(false, ChatRestrictionsInfo());
}).send();
}
- }, &st::menuIconRestrict);
+ }, &st::menuIconPermissions);
}
void InnerWidget::restrictParticipant(
@@ -1892,8 +1892,7 @@ void InnerWidget::performDrag() {
// auto pressedMedia = static_cast(nullptr);
// if (auto pressedItem = Element::Pressed()) {
// pressedMedia = pressedItem->media();
- // if (_mouseCursorState == CursorState::Date
- // || (pressedMedia && pressedMedia->dragItem())) {
+ // if (_mouseCursorState == CursorState::Date) {
// forwardMimeType = u"application/x-td-forward"_q;
// session().data().setMimeForwardIds(
// session().data().itemOrItsGroup(pressedItem->data()));
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index b1acb3727..ffbbc4d84 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -551,8 +551,10 @@ void History::destroyMessage(not_null