Compare commits

...

120 Commits

Author SHA1 Message Date
AlexeyZavar 0e26b39faf fix: possible crash 2024-03-13 16:34:39 +03:00
AlexeyZavar 2414e51a9b feat: clear selected & close box after shot & scroll to bottom 2024-03-13 15:58:11 +03:00
AlexeyZavar 8bfb7e221b fix: hideNotificationCounters 2024-03-13 15:31:37 +03:00
AlexeyZavar 1935a2b144 fix: replies in topics for message shot 2024-03-13 15:19:38 +03:00
AlexeyZavar c525fd64ca fix: restore menu 2024-03-13 14:47:50 +03:00
AlexeyZavar 6d08b5bf23 fix: read after forward 2024-03-13 13:48:56 +03:00
AlexeyZavar a73da65253 feat: faster animations 2024-03-13 13:25:05 +03:00
AlexeyZavar 2be73d7924 fix: make it build 2024-03-13 12:30:19 +03:00
AlexeyZavar 080400d7b8 Merge tag 'v4.15.2' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/info/info_wrap_widget.cpp
#	Telegram/SourceFiles/settings/settings_common_session.cpp
#	Telegram/lib_ui
#	docs/building-mac.md
#	snap/snapcraft.yaml
2024-03-13 11:44:48 +03:00
John Preston bf1b3dc8f6 Version 4.15.2: Update fcitx-qt5.
I hope this fixes #27573.
2024-03-13 09:21:35 +04:00
John Preston f13971dce1 Use line-tables-only debug information format on macOS.
Otherwise linking fails on x86_64 in Release mode.
2024-03-13 09:20:14 +04:00
AlexeyZavar 3f639d5689 fix: remove rate call box
chore: revisit constants
2024-03-13 00:23:58 +03:00
AlexeyZavar 19a5dc8a0c fix: hint stacking for TTL messages 2024-03-12 22:38:07 +03:00
John Preston 5573bbc776 Version 4.15.2.
- Telegram Business: Greeting Message.
- Telegram Business: Away Message.
- Telegram Business: Quick Replies.
- Telegram Business: Working Hours.
- Close the ongoing call window without hanging up the call.
- Fast scroll through chats list with Ctrl or Shift pressed.
- Several bugfixes.
2024-03-12 23:30:49 +04:00
John Preston 8c5db25476 Fix a crash in main settings destructor.
Fixes #27544.
2024-03-12 23:24:43 +04:00
John Preston c6f49486ee Use regular good-green color in unmute. 2024-03-12 18:34:57 +04:00
John Preston cf6d13acc2 Add fast Ctrl/Shift scroll to ElasticScroll. 2024-03-12 18:34:49 +04:00
John Preston 1647991f6a Fix autologin token account selection. 2024-03-12 15:57:18 +04:00
John Preston b4993453c0 Update submodules. 2024-03-12 14:38:06 +04:00
John Preston 68bb0a1744 Fix recent actions date marks.
Regression was introduced in 7f3ebde252.
2024-03-12 14:38:02 +04:00
John Preston 12356b1617 Fix possible crash in WebView2 destruction. 2024-03-12 14:37:46 +04:00
prawwtocol fc0cfbf003 Update mac build instructions with up-to-date homebrew link 2024-03-10 21:36:51 +04:00
Kolya 77dcbaf00c don't use brotli (built by other dependencies) 2024-03-10 21:35:50 +04:00
AlexeyZavar 69e9841bbb fix: rare crashes 2024-03-09 15:20:23 +03:00
John Preston 626b3395ab Show 00:00-23:59 as "open 24 hours". 2024-03-09 10:58:05 +04:00
John Preston 506b8fd4f1 Fix saving of empty working intervals. 2024-03-09 10:58:05 +04:00
Kolya d3b1abb61e fix windows build 2024-03-09 10:46:27 +04:00
John Preston 990ae11f62 Version 4.15.1: Fix build with GCC. 2024-03-08 15:49:30 +04:00
Ilya Fedin 3d5092f7ad Update cmake_helpers 2024-03-08 15:32:58 +04:00
Ilya Fedin 296e8c1ab1 Use ExecutablePathForShortcuts in PortalAutostart 2024-03-08 15:32:58 +04:00
Ilya Fedin 0df8864ae0 Port specific_linux to cppgir 2024-03-08 15:32:58 +04:00
John Preston 7c002cf8be Version 4.15.1: Fix sending media albums. 2024-03-08 15:26:14 +04:00
John Preston c345b50ab7 Version 4.15.1.
Telegram Business features.
2024-03-08 12:55:20 +04:00
John Preston d729e625e6 Show business section settings only when loaded. 2024-03-08 12:28:53 +04:00
John Preston 2c03d90fc8 Fix the new time picker. 2024-03-08 11:47:29 +04:00
John Preston 5ebd5852ba Update lib_ui submodule. 2024-03-08 10:55:50 +04:00
John Preston 5397f64b23 Add Telegram Business icon to Premium promo. 2024-03-08 10:54:00 +04:00
John Preston 4975cf2ec1 Implement double-drumroll time picker. 2024-03-08 10:54:00 +04:00
John Preston bef26cf9d2 Force right-alignment in quick replies editing. 2024-03-08 10:54:00 +04:00
John Preston 9483d17fc8 Validate quick reply name. 2024-03-08 10:54:00 +04:00
John Preston 288979d8e7 Allow editing quick replies from the suggestions. 2024-03-08 10:54:00 +04:00
John Preston 49ec051760 Make premium toast adaptive. 2024-03-08 10:54:00 +04:00
John Preston 0a8e961142 Suggest premium when sending existing quick replies. 2024-03-08 10:54:00 +04:00
John Preston 6d352597b4 Disable quick replies in bot chats. 2024-03-08 10:54:00 +04:00
John Preston d14f11bd88 fixup Implement preview and save of chatbots. 2024-03-08 10:54:00 +04:00
John Preston d608bffecb Fix limit in business features exception box. 2024-03-08 10:54:00 +04:00
John Preston 00dcf11691 Improve recipients selection in business features. 2024-03-08 10:54:00 +04:00
John Preston e3f6c189a7 Implement preview and save of chatbots. 2024-03-08 10:54:00 +04:00
John Preston ea36345eee Show location and working hours in profile. 2024-03-08 10:53:59 +04:00
John Preston 5e82860376 Allow sending quick replies like bot commands. 2024-03-08 10:53:59 +04:00
John Preston 37f5160d1c Fix bold formatting in the beginning of a quote. 2024-03-08 10:53:59 +04:00
John Preston ee847bc1a3 Fix legacy group pins loading on first group open.
Fixes #27466.
2024-03-08 10:53:59 +04:00
John Preston c94da177d7 Fix build with Xcode. 2024-03-08 10:53:59 +04:00
John Preston 88751896af PremiumPreview/BusinessFeature -> PremiumFeature. 2024-03-08 10:53:59 +04:00
John Preston f812166249 Use server-side order for business features list. 2024-03-08 10:53:59 +04:00
John Preston a47c6f9c9a Show errors on business info savings. 2024-03-08 10:53:59 +04:00
John Preston cf8aaf5f9d Save away / greeting settings. 2024-03-08 10:53:59 +04:00
John Preston ca4cbddba6 Check shortcuts / messages limits. 2024-03-08 10:53:59 +04:00
John Preston dd6768a476 Add stories rights by default to new admins. 2024-03-08 10:53:59 +04:00
John Preston 7f7d544943 Show nice empty quick reply placeholder. 2024-03-08 10:53:59 +04:00
John Preston d5e920e45a Update API scheme on layer 176. 2024-03-08 10:53:59 +04:00
John Preston 8545a14763 Fix shortcut messages sizing / emoji panel. 2024-03-08 10:53:59 +04:00
John Preston aad8e989d8 Shortcuts edit / delete menu. 2024-03-08 10:53:59 +04:00
John Preston f086203d25 Implement proper shortcut management. 2024-03-08 10:53:59 +04:00
John Preston 23e22de6ec Fix deleting shortcut items. 2024-03-08 10:53:59 +04:00
John Preston fb539b0f70 Improve shortcut messages geometry. 2024-03-08 10:53:59 +04:00
John Preston 6e08b00dba Fix sending .tgs files as stickers.
Regression was introduced in 3467fe226f.
2024-03-08 10:53:59 +04:00
John Preston 7f3ebde252 Implement sending of shortcutted messages. 2024-03-08 10:53:59 +04:00
John Preston 5c11fa4f63 Update API scheme on layer 176. 2024-03-08 10:53:59 +04:00
John Preston d05c4e0990 Start shortcut messages sending. 2024-03-08 10:53:59 +04:00
John Preston dd7ccada2f Support edit / save of greeting message settings. 2024-03-08 10:53:59 +04:00
John Preston e6b9ac2267 Support edit / save of away message settings. 2024-03-08 10:53:58 +04:00
John Preston f85c3c88f7 Add rpl interface to RadiobuttonGroup. 2024-03-08 10:53:58 +04:00
John Preston e05eb63476 Update API scheme on layer 176. 2024-03-08 10:53:58 +04:00
John Preston c513906996 Change default for business recipients. 2024-03-08 10:53:58 +04:00
John Preston dd0bdd62fb Support business working hours API. 2024-03-08 10:53:58 +04:00
John Preston 4d12f1c0ef Initial working hours editing. 2024-03-08 10:53:58 +04:00
John Preston 1fe641c458 Update API scheme to layer 176. 2024-03-08 10:53:58 +04:00
John Preston 1e5f821c6f Start all business sections implementation. 2024-03-08 10:53:58 +04:00
John Preston 0af131f144 Invert group / channel features list. 2024-03-08 10:53:58 +04:00
John Preston ad9107ca90 Implement chatbots section editing. 2024-03-08 10:53:58 +04:00
John Preston 205479fccc Layout chatbots editing section. 2024-03-08 10:53:58 +04:00
John Preston 0c991466f5 Update API scheme to layer 175. Business promo. 2024-03-08 10:53:58 +04:00
23rd 0fad42b5b4 Added ability to open box for voice restrictions without premium. 2024-03-08 10:53:58 +04:00
23rd 27bd9e3ee5 Added icons to buttons for privacy settings that require premium. 2024-03-08 10:53:58 +04:00
23rd 02e1c03ed9 Fixed position of connecting state widget when forum is opened.
Fixed #27548.
2024-03-08 10:53:58 +04:00
23rd f56b16c6ef Added initial badges for minimal level of boosts to channel settings. 2024-03-08 10:53:58 +04:00
23rd 09285bc9cd Moved out minimal levels of boosts for channel settings to single place. 2024-03-08 10:53:58 +04:00
23rd eab249fc13 Fixed countdown label for input field of bio. 2024-03-08 10:53:58 +04:00
23rd 48eb408fb8 Fixed text elision of vote amount in polls with reactions. 2024-03-08 10:53:58 +04:00
23rd ef474f0dc8 Fixed opening of local links from webview bots in appropriate window. 2024-03-08 10:53:58 +04:00
23rd a704611705 Fixed ability to create vertical drum picker with first chosen item. 2024-03-08 10:53:58 +04:00
23rd b790847fde Added ability to close call panel without hanging up call. 2024-03-08 10:53:58 +04:00
23rd c0c330a150 Fixed bubble color under strip of emoji pad for reactions. 2024-03-08 10:53:58 +04:00
23rd aec4857e7b Fixed format of phone number in intro widget. 2024-03-08 10:53:58 +04:00
23rd 5dc6bdcc42 Fixed reply bar stuck when sending file in replies section. 2024-03-08 10:53:58 +04:00
23rd 08717dcd78 Added counter label of characters limit to edit mode without media. 2024-03-08 10:53:58 +04:00
23rd a77c547a62 Fixed edit of long media caption with emoji. 2024-03-08 10:53:58 +04:00
23rd d252427e34 Added blockquote to white list for message links parser. 2024-03-08 10:53:58 +04:00
23rd 58443bc197 Fixed ability to schedule forwarded messages without comment. 2024-03-08 10:53:58 +04:00
23rd ea20e41f1d Added drag text to contact view. 2024-03-08 10:53:58 +04:00
23rd afdd22d154 Fixed phone formatting generally. 2024-03-08 10:53:58 +04:00
23rd 93d1a187ca Improved view style of contacts. 2024-03-08 10:53:57 +04:00
23rd 52c779bffa Added support of inline markup reply to HTML export. 2024-03-08 10:53:57 +04:00
23rd de1bd6ef28 Slightly simplified creation of universal variables in prepare.py. 2024-03-08 10:53:57 +04:00
23rd c26982be3e Added support for AVIF, HEIF and JPEG XL on macOS. 2024-03-08 10:53:57 +04:00
mrbesen 5971aefb83 add bash shebang 2024-03-08 08:05:55 +04:00
Ilya Fedin 41481129f7 Port main_window_linux to cppgir 2024-03-08 08:05:12 +04:00
Ilya Fedin 7b8cdb43c4 Port linux_xdp_open_with_dialog to cppgir 2024-03-08 08:05:12 +04:00
Ilya Fedin 1e9b7e2726 Use XDP::kObjectPath for session and request paths 2024-03-08 08:05:12 +04:00
Ilya Fedin a66b886c51 Initialize Linux lock screen monitor fully asynchronously 2024-03-08 08:05:12 +04:00
Ilya Fedin 5b62d97288 Update submodules 2024-03-08 08:05:12 +04:00
Kolya b040b62b4e prepare.py: simplify qt5 clone 2024-03-07 18:14:34 +04:00
Kolya 50f51d0747 update new script location in qt repo 2024-03-07 18:14:34 +04:00
xmdn 95b4fc0216 use modern installer style 2024-03-01 12:43:33 +04:00
GitHub Action da047edbc5 Update User-Agent for DNS to Chrome 122.0.0.0. 2024-03-01 12:41:47 +04:00
Ilya Fedin a8b5061003 Fix a std::clamp assertion 2024-03-01 12:41:35 +04:00
Kolya ec427ad45d Use TOOLCHAIN variable name 2024-02-23 13:17:55 +04:00
Kolya 778ab70b72 Fix libvpx build on VS 17.8+
use with https://github.com/desktop-app/patches/pull/182
2024-02-23 13:17:55 +04:00
Ilya Fedin 5d1aa10768 Remove no longer needed boost-program-options from snap
Looks like cppgir has stopped to use it during some of the updates
2024-02-19 14:31:08 +04:00
336 changed files with 12331 additions and 3024 deletions
+1 -1
View File
@@ -64,7 +64,7 @@ jobs:
- name: First set up.
run: |
sudo chown -R `whoami`:admin /usr/local/share
brew install automake ninja pkg-config
brew install automake ninja pkg-config nasm meson
# Disable spotlight.
sudo mdutil -a -i off
+3
View File
@@ -100,3 +100,6 @@
[submodule "Telegram/ThirdParty/libprisma"]
path = Telegram/ThirdParty/libprisma
url = https://github.com/desktop-app/libprisma.git
[submodule "Telegram/ThirdParty/xdg-desktop-portal"]
path = Telegram/ThirdParty/xdg-desktop-portal
url = https://github.com/flatpak/xdg-desktop-portal.git
+30 -1
View File
@@ -248,6 +248,8 @@ PRIVATE
boxes/filters/edit_filter_box.h
boxes/filters/edit_filter_chats_list.cpp
boxes/filters/edit_filter_chats_list.h
boxes/filters/edit_filter_chats_preview.cpp
boxes/filters/edit_filter_chats_preview.h
boxes/filters/edit_filter_links.cpp
boxes/filters/edit_filter_links.h
boxes/peers/add_bot_to_chat_box.cpp
@@ -514,6 +516,14 @@ PRIVATE
core/version.h
countries/countries_manager.cpp
countries/countries_manager.h
data/business/data_business_chatbots.cpp
data/business/data_business_chatbots.h
data/business/data_business_common.cpp
data/business/data_business_common.h
data/business/data_business_info.cpp
data/business/data_business_info.h
data/business/data_shortcut_messages.cpp
data/business/data_shortcut_messages.h
data/notify/data_notify_settings.cpp
data/notify/data_notify_settings.h
data/notify/data_peer_notify_settings.cpp
@@ -1345,6 +1355,22 @@ PRIVATE
profile/profile_block_widget.h
profile/profile_cover_drop_area.cpp
profile/profile_cover_drop_area.h
settings/business/settings_away_message.cpp
settings/business/settings_away_message.h
settings/business/settings_shortcut_messages.cpp
settings/business/settings_shortcut_messages.h
settings/business/settings_chatbots.cpp
settings/business/settings_chatbots.h
settings/business/settings_greeting.cpp
settings/business/settings_greeting.h
settings/business/settings_location.cpp
settings/business/settings_location.h
settings/business/settings_quick_replies.cpp
settings/business/settings_quick_replies.h
settings/business/settings_recipients_helper.cpp
settings/business/settings_recipients_helper.h
settings/business/settings_working_hours.cpp
settings/business/settings_working_hours.h
settings/cloud_password/settings_cloud_password_common.cpp
settings/cloud_password/settings_cloud_password_common.h
settings/cloud_password/settings_cloud_password_email.cpp
@@ -1363,6 +1389,8 @@ PRIVATE
settings/settings_advanced.h
settings/settings_blocked_peers.cpp
settings/settings_blocked_peers.h
settings/settings_business.cpp
settings/settings_business.h
settings/settings_chat.cpp
settings/settings_chat.h
settings/settings_calls.cpp
@@ -1722,7 +1750,7 @@ else()
)
include(${cmake_helpers_loc}/external/glib/generate_dbus.cmake)
generate_dbus(Telegram org.freedesktop.portal. XdpInhibit ${src_loc}/platform/linux/org.freedesktop.portal.Inhibit.xml)
generate_dbus(Telegram org.freedesktop.portal. XdpBackground ${third_party_loc}/xdg-desktop-portal/data/org.freedesktop.portal.Background.xml)
if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION)
target_link_libraries(Telegram
@@ -1796,6 +1824,7 @@ set_target_properties(Telegram PROPERTIES
XCODE_ATTRIBUTE_ALWAYS_SEARCH_USER_PATHS NO
XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY libc++
XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS --deep
XCODE_ATTRIBUTE_CLANG_DEBUG_INFORMATION_LEVEL $<IF:$<CONFIG:Debug>,default,line-tables-only>
)
set(entitlement_sources
"${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Telegram.entitlements"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

@@ -559,3 +559,26 @@ div.toast_shown {
opacity: 0;
user-select: none;
}
.bot_buttons_table {
border-spacing: 0px 2px;
width: 100%;
}
.bot_button {
border-radius: 8px;
text-align: center;
vertical-align: middle;
background-color: #168acd40;
}
.bot_button_row {
display: table;
table-layout: fixed;
padding: 0px;
width:100%;
}
.bot_button_row div {
display: table-cell;
}
.bot_button_column_separator {
width: 2px
}
@@ -62,6 +62,12 @@ function ShowNotAvailableEmoji() {
return false;
}
function ShowTextCopied(content) {
navigator.clipboard.writeText(content);
ShowToast("Text copied to clipboard.");
return false;
}
function ShowSpoiler(target) {
if (target.classList.contains("hidden")) {
target.classList.toggle("hidden");
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 B

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 787 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

+142
View File
@@ -1313,6 +1313,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_info_link_label" = "Link";
"lng_info_location_label" = "Location";
"lng_info_about_label" = "About";
"lng_info_work_open" = "Open";
"lng_info_work_closed" = "Closed";
"lng_info_hours_label" = "Business hours";
"lng_info_hours_closed" = "closed";
"lng_info_hours_opens_in_minutes#one" = "opens in {count} minute";
"lng_info_hours_opens_in_minutes#other" = "opens in {count} minutes";
"lng_info_hours_opens_in_hours#one" = "opens in {count} hour";
"lng_info_hours_opens_in_hours#other" = "opens in {count} hours";
"lng_info_hours_opens_in_days#one" = "opens in {count} day";
"lng_info_hours_opens_in_days#other" = "opens in {count} days";
"lng_info_hours_open_full" = "open 24 hours";
"lng_info_hours_next_day" = "{time} (next day)";
"lng_info_hours_local_time" = "local time";
"lng_info_hours_my_time" = "my time";
"lng_info_user_title" = "User Info";
"lng_info_bot_title" = "Bot Info";
"lng_info_group_title" = "Group Info";
@@ -2056,6 +2070,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_summary_about_animated_userpics" = "Video avatars animated in chat lists and chats to allow for additional self-expression.";
"lng_premium_summary_subtitle_translation" = "Real-Time Translation";
"lng_premium_summary_about_translation" = "Real-time translation of channels and chats into other languages.";
"lng_premium_summary_subtitle_business" = "Telegram Business";
"lng_premium_summary_about_business" = "Upgrade your account with business features such as location, opening hours and quick replies.";
"lng_premium_summary_bottom_subtitle" = "About Telegram Premium";
"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";
@@ -2154,6 +2170,125 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_gifts_terms" = "By gifting Telegram Premium, you agree to the Telegram {link} and {policy}.";
"lng_premium_gifts_terms_policy" = "Privacy Policy";
"lng_business_title" = "Telegram Business";
"lng_business_about" = "Turn your account to a business page with these additional features.";
"lng_business_unlocked" = "You have now unlocked these additional business features.";
"lng_business_subtitle_location" = "Location";
"lng_business_about_location" = "Display the location of your business on your account.";
"lng_business_subtitle_opening_hours" = "Opening Hours";
"lng_business_about_opening_hours" = "Show to your customers when you are open for business.";
"lng_business_subtitle_quick_replies" = "Quick Replies";
"lng_business_about_quick_replies" = "Set up shortcuts up to 20 messages each to respond to customers faster.";
"lng_business_subtitle_greeting_messages" = "Greeting Messages";
"lng_business_about_greeting_messages" = "Create greetings that will be automatically sent to new customers.";
"lng_business_subtitle_away_messages" = "Away Messages";
"lng_business_about_away_messages" = "Define messages that are automatically sent when you are off.";
"lng_business_subtitle_chatbots" = "Chatbots";
"lng_business_about_chatbots" = "Add any third party chatbots that will process customer interactions.";
"lng_location_title" = "Location";
"lng_location_about" = "Display the location of your business on your account.";
"lng_location_address" = "Enter Address";
"lng_location_fallback" = "You can set your location on the map from your mobile device.";
"lng_hours_title" = "Business Hours";
"lng_hours_about" = "Turn this on to show your opening hours schedule to your customers.";
"lng_hours_show" = "Show Business Hours";
"lng_hours_time_zone" = "Time Zone";
"lng_hours_monday" = "Monday";
"lng_hours_tuesday" = "Tuesday";
"lng_hours_wednesday" = "Wednesday";
"lng_hours_thursday" = "Thursday";
"lng_hours_friday" = "Friday";
"lng_hours_saturday" = "Saturday";
"lng_hours_sunday" = "Sunday";
"lng_hours_closed" = "Closed";
"lng_hours_open_full" = "Open 24 hours";
"lng_hours_next_day" = "{time} (Next day)";
"lng_hours_on_next_day" = "Next day {time}";
"lng_hours_time_zone_title" = "Choose Time Zone";
"lng_hours_add_button" = "Add a Set of Hours";
"lng_hours_opening" = "Opening Time";
"lng_hours_closing" = "Closing Time";
"lng_hours_remove" = "Remove";
"lng_hours_about_day" = "Specify your working hours during the day.";
"lng_replies_title" = "Quick Replies";
"lng_replies_about" = "Set up shortcuts with rich text and media to respond to messages faster.";
"lng_replies_add" = "Add Quick Reply";
"lng_replies_add_title" = "New Quick Reply";
"lng_replies_add_shortcut" = "Add a shortcut for your reply.";
"lng_replies_add_placeholder" = "Shortcut";
"lng_replies_add_exists" = "This shortcut already exists.";
"lng_replies_empty_title" = "New Quick Reply";
"lng_replies_empty_about" = "Enter a message below that will be sent in chat when you type {shortcut}.\n\nYou can access Quick Replies in any chat by typing /.";
"lng_replies_remove_title" = "Remove Shortcut";
"lng_replies_remove_text" = "You didn't create a quick reply message. Do you want to remove the shortcut?";
"lng_replies_edit_title" = "Edit Shortcut";
"lng_replies_edit_about" = "Edit the name for this shortcut.";
"lng_replies_message_placeholder" = "Add a Quick Reply";
"lng_replies_delete_sure" = "Are you sure you want to delete this quick reply with all its messages?";
"lng_replies_error_occupied" = "This shortcut is already used.";
"lng_replies_edit_button" = "Edit Quick Replies";
"lng_greeting_title" = "Greeting Message";
"lng_greeting_about" = "Greet customers when they message you the first time or after a period of no activity.";
"lng_greeting_enable" = "Send Greeting Message";
"lng_greeting_create" = "Create a Greeting Message";
"lng_greeting_recipients" = "Recipients";
"lng_greeting_select" = "Select chats or entire chat categories for sending a greeting message.";
"lng_greeting_period_title" = "Period of no activity";
"lng_greeting_period_about" = "Choose how many days should pass after your last interaction with a recipient to send them a greeting in response to their message.";
"lng_greeting_empty_title" = "New Greeting Message";
"lng_greeting_empty_about" = "Create greetings that will be automatically sent to new customers.";
"lng_greeting_message_placeholder" = "Add a Greeting";
"lng_greeting_limit_reached" = "You have too many quick replies. Remove one to add a greeting message.";
"lng_greeting_recipients_empty" = "Please choose at least one recipient.";
"lng_away_title" = "Away Message";
"lng_away_about" = "Automatically reply with a message when you are away.";
"lng_away_enable" = "Send Away Message";
"lng_away_create" = "Create an Away Message";
"lng_away_schedule" = "Schedule";
"lng_away_schedule_always" = "Send Always";
"lng_away_schedule_outside" = "Outside of Business Hours";
"lng_away_schedule_custom" = "Custom Schedule";
"lng_away_custom_start" = "Start Time";
"lng_away_custom_end" = "End Time";
"lng_away_offline_only" = "Only if Offline";
"lng_away_offline_only_about" = "Don't send the away message if you've recently been online.";
"lng_away_recipients" = "Recipients";
"lng_away_select" = "Select chats or entire chat categories for sending an away message.";
"lng_away_empty_title" = "New Away Message";
"lng_away_empty_about" = "Add messages that will be automatically sent when you are off.";
"lng_away_message_placeholder" = "Add an Away Message";
"lng_away_limit_reached" = "You have too many quick replies. Remove one to add an away message.";
"lng_business_edit_messages" = "Edit messages";
"lng_business_limit_reached#one" = "Limit of {count} message reached.";
"lng_business_limit_reached#other" = "Limit of {count} messages reached.";
"lng_chatbots_title" = "Chatbots";
"lng_chatbots_about" = "Add a bot to your account to help you automatically process and respond to the messages you receive. {link}";
"lng_chatbots_about_link" = "Learn more...";
"lng_chatbots_placeholder" = "Enter bot URL or username";
"lng_chatbots_add_about" = "Enter the link to the Telegram bot that you want to automatically process your chats.";
"lng_chatbots_access_title" = "Chats accessible for the bot";
"lng_chatbots_all_except" = "All 1-to-1 Chats Except...";
"lng_chatbots_selected" = "Only Selected Chats";
"lng_chatbots_excluded_title" = "Excluded chats";
"lng_chatbots_exclude_button" = "Exclude Chats";
"lng_chatbots_included_title" = "Included chats";
"lng_chatbots_include_button" = "Select Chats";
"lng_chatbots_exclude_about" = "Select chats or entire chat categories which the bot will not have access to.";
"lng_chatbots_permissions_title" = "Bot permissions";
"lng_chatbots_reply" = "Reply to Messages";
"lng_chatbots_reply_about" = "The bot will be able to view all new incoming messages, but not the messages that had been sent before you added the bot.";
"lng_chatbots_remove" = "Remove Bot";
"lng_chatbots_not_found" = "Chatbot not found.";
"lng_chatbots_add" = "Add";
"lng_chatbots_info_url" = "https://telegram.org/privacy";
"lng_boost_channel_button" = "Boost Channel";
"lng_boost_group_button" = "Boost Group";
"lng_boost_again_button" = "Boost Again";
@@ -2917,6 +3052,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_translate_selected" = "Translate Selected Text";
"lng_context_read_hidden" = "read";
"lng_context_read_show" = "show when";
"lng_context_edit_shortcut" = "Edit Shortcut";
"lng_context_delete_shortcut" = "Delete Quick Reply";
"lng_add_tag_about" = "Tag this message with an emoji for quick search.";
"lng_subscribe_tag_about" = "Organize your Saved Messages with tags. {link}";
@@ -4305,6 +4442,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_filters_type_non_contacts" = "Non-Contacts";
"lng_filters_type_groups" = "Groups";
"lng_filters_type_channels" = "Channels";
"lng_filters_type_new" = "New Chats";
"lng_filters_type_existing" = "Existing Chats";
"lng_filters_type_bots" = "Bots";
"lng_filters_type_no_archived" = "Archived";
"lng_filters_type_no_muted" = "Muted";
@@ -4724,6 +4863,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_boosts_prepaid_giveaway_status#one" = "{count} subscription {duration}";
"lng_boosts_prepaid_giveaway_status#other" = "{count} subscriptions {duration}";
"lng_contact_add" = "Add";
"lng_contact_send_message" = "message";
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";
@@ -14,5 +14,12 @@
<file alias="voice_ttl_idle.tgs">../../animations/voice_ttl_idle.tgs</file>
<file alias="voice_ttl_start.tgs">../../animations/voice_ttl_start.tgs</file>
<file alias="palette.tgs">../../animations/palette.tgs</file>
<file alias="sleep.tgs">../../animations/sleep.tgs</file>
<file alias="greeting.tgs">../../animations/greeting.tgs</file>
<file alias="location.tgs">../../animations/location.tgs</file>
<file alias="robot.tgs">../../animations/robot.tgs</file>
<file alias="writing.tgs">../../animations/writing.tgs</file>
<file alias="hours.tgs">../../animations/hours.tgs</file>
<file alias="phone.tgs">../../animations/phone.tgs</file>
</qresource>
</RCC>
@@ -3,6 +3,7 @@
<file alias="art/background.tgv">../../art/background.tgv</file>
<file alias="art/bg_thumbnail.png">../../art/bg_thumbnail.png</file>
<file alias="art/bg_initial.jpg">../../art/bg_initial.jpg</file>
<file alias="art/business_logo.png">../../art/business_logo.png</file>
<file alias="art/logo_256.png">../../art/logo_256.png</file>
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
<file alias="art/themeimage.jpg">../../art/themeimage.jpg</file>
+1 -1
View File
@@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="4.15.0.0" />
Version="4.15.2.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
+4 -4
View File
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,15,0,0
PRODUCTVERSION 4,15,0,0
FILEVERSION 4,15,2,0
PRODUCTVERSION 4,15,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "4.15.0.0"
VALUE "FileVersion", "4.15.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.15.0.0"
VALUE "ProductVersion", "4.15.2.0"
END
END
BLOCK "VarFileInfo"
+4 -4
View File
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,15,0,0
PRODUCTVERSION 4,15,0,0
FILEVERSION 4,15,2,0
PRODUCTVERSION 4,15,2,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.15.0.0"
VALUE "FileVersion", "4.15.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.15.0.0"
VALUE "ProductVersion", "4.15.2.0"
END
END
BLOCK "VarFileInfo"
+1
View File
@@ -22,6 +22,7 @@ inline constexpr auto kScheduledUntilOnlineTimestamp = TimeId(0x7FFFFFFE);
struct SendOptions {
PeerData *sendAs = nullptr;
TimeId scheduled = 0;
BusinessShortcutId shortcutId = 0;
bool silent = false;
bool handleSupportSwitch = false;
bool hideViaBot = false;
+8 -1
View File
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_media.h"
#include "api/api_text_entities.h"
#include "ui/boxes/confirm_box.h"
#include "data/business/data_shortcut_messages.h"
#include "data/data_histories.h"
#include "data/data_scheduled_messages.h"
#include "data/data_session.h"
@@ -88,10 +89,15 @@ mtpRequestId EditMessage(
: emptyFlag)
| (options.scheduled
? MTPmessages_EditMessage::Flag::f_schedule_date
: emptyFlag)
| (item->isBusinessShortcut()
? MTPmessages_EditMessage::Flag::f_quick_reply_shortcut_id
: emptyFlag);
const auto id = item->isScheduled()
? session->data().scheduledMessages().lookupId(item)
: item->isBusinessShortcut()
? session->data().shortcutMessages().lookupId(item)
: item->id;
return api->request(MTPmessages_EditMessage(
MTP_flags(flags),
@@ -101,7 +107,8 @@ mtpRequestId EditMessage(
inputMedia.value_or(Data::WebPageForMTP(webpage, text.isEmpty())),
MTPReplyMarkup(),
sentEntities,
MTP_int(options.scheduled)
MTP_int(options.scheduled),
MTP_int(item->shortcutId())
)).done([=](
const MTPUpdates &result,
[[maybe_unused]] mtpRequestId requestId) {
+8 -2
View File
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_updates.h"
#include "apiwrap.h"
#include "base/random.h"
#include "data/business/data_shortcut_messages.h"
#include "data/data_changes.h"
#include "data/data_histories.h"
#include "data/data_poll.h"
@@ -69,6 +70,9 @@ void Polls::create(
if (action.options.scheduled) {
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
if (action.options.shortcutId) {
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
const auto sendAs = action.options.sendAs;
if (sendAs) {
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
@@ -89,7 +93,8 @@ void Polls::create(
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, action.options.shortcutId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
if (clearCloudDraft) {
history->finishSavingCloudDraft(
@@ -184,7 +189,8 @@ void Polls::close(not_null<HistoryItem*> item) {
PollDataToInputMedia(poll, true),
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(0) // schedule_date
MTP_int(0), // schedule_date
MTPint() // quick_reply_shortcut_id
)).done([=](const MTPUpdates &result) {
_pollCloseRequestIds.erase(itemId);
_session->updates().applyUpdates(result);
+73 -59
View File
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_text_entities.h"
#include "base/random.h"
#include "base/unixtime.h"
#include "data/business/data_shortcut_messages.h"
#include "data/data_document.h"
#include "data/data_photo.h"
#include "data/data_channel.h" // ChannelData::addsSignature.
@@ -84,20 +85,21 @@ void SendExistingMedia(
? (*localMessageId)
: session->data().nextLocalMessageId());
const auto randomId = base::RandomValue<uint64>();
const auto &action = message.action;
auto flags = NewMessageFlags(peer);
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) {
if (action.replyTo) {
flags |= MessageFlag::HasReplyInfo;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
}
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, message.action.options);
InnerFillMessagePostFlags(message.action.options, peer, flags);
const auto silentPost = ShouldSendSilent(peer, action.options);
InnerFillMessagePostFlags(action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
const auto sendAs = message.action.options.sendAs;
const auto sendAs = action.options.sendAs;
const auto messageFromId = sendAs
? sendAs->id
: anonymousPost
@@ -124,32 +126,34 @@ void SendExistingMedia(
}
const auto captionText = caption.text;
if (message.action.options.scheduled) {
if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled;
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
session->data().registerMessageRandomId(randomId, newId);
const auto viaBotId = UserId();
history->addNewLocalMessage(
newId.msg,
flags,
viaBotId,
message.action.replyTo,
HistoryItem::NewMessageDate(message.action.options.scheduled),
messageFromId,
messagePostAuthor,
media,
caption,
HistoryMessageMarkupData());
history->addNewLocalMessage({
.id = newId.msg,
.flags = flags,
.from = messageFromId,
.replyTo = action.replyTo,
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
}, media, caption);
const auto performRequest = [=](const auto &repeatRequest) -> void {
auto &histories = history->owner().histories();
const auto session = &history->session();
const auto usedFileReference = media->fileReference();
histories.sendPreparedMessage(
history,
message.action.replyTo,
action.replyTo,
randomId,
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
MTP_flags(sendFlags),
@@ -160,8 +164,9 @@ void SendExistingMedia(
MTP_long(randomId),
MTPReplyMarkup(),
sentEntities,
MTP_int(message.action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(session, action.options.shortcutId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
}, [=](const MTP::Error &error, const MTP::Response &response) {
if (error.code() == 400
@@ -180,7 +185,7 @@ void SendExistingMedia(
};
performRequest(performRequest);
api->finishForwarding(message.action);
api->finishForwarding(action);
}
} // namespace
@@ -259,7 +264,10 @@ bool SendDice(MessageToSend &message) {
message.textWithTags = TextWithTags();
message.action.clearDraft = false;
message.action.generateLocal = true;
api->sendAction(message.action);
const auto &action = message.action;
api->sendAction(action);
const auto newId = FullMsgId(
peer->id,
@@ -269,17 +277,17 @@ bool SendDice(MessageToSend &message) {
auto &histories = history->owner().histories();
auto flags = NewMessageFlags(peer);
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) {
if (action.replyTo) {
flags |= MessageFlag::HasReplyInfo;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
}
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, message.action.options);
InnerFillMessagePostFlags(message.action.options, peer, flags);
const auto silentPost = ShouldSendSilent(peer, action.options);
InnerFillMessagePostFlags(action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
const auto sendAs = message.action.options.sendAs;
const auto sendAs = action.options.sendAs;
const auto messageFromId = sendAs
? sendAs->id
: anonymousPost
@@ -292,28 +300,31 @@ bool SendDice(MessageToSend &message) {
? session->user()->name()
: QString();
if (message.action.options.scheduled) {
if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled;
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
session->data().registerMessageRandomId(randomId, newId);
const auto viaBotId = UserId();
history->addNewLocalMessage(
newId.msg,
flags,
viaBotId,
message.action.replyTo,
HistoryItem::NewMessageDate(message.action.options.scheduled),
messageFromId,
messagePostAuthor,
TextWithEntities(),
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
HistoryMessageMarkupData());
history->addNewLocalMessage({
.id = newId.msg,
.flags = flags,
.from = messageFromId,
.replyTo = action.replyTo,
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
}, TextWithEntities(), MTP_messageMediaDice(
MTP_int(0),
MTP_string(emoji)));
histories.sendPreparedMessage(
history,
message.action.replyTo,
action.replyTo,
randomId,
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
MTP_flags(sendFlags),
@@ -324,13 +335,14 @@ bool SendDice(MessageToSend &message) {
MTP_long(randomId),
MTPReplyMarkup(),
MTP_vector<MTPMessageEntity>(),
MTP_int(message.action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(session, action.options.shortcutId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
}, [=](const MTP::Error &error, const MTP::Response &response) {
api->sendMessageFail(error, peer, randomId, newId);
});
api->finishForwarding(message.action);
api->finishForwarding(action);
return true;
}
@@ -406,7 +418,13 @@ void SendConfirmedFile(
if (file->to.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled;
// Scheduled messages have no the 'edited' badge.
// Scheduled messages have no 'edited' badge.
flags |= MessageFlag::HideEdited;
}
if (file->to.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
// Shortcut messages have no 'edited' badge.
flags |= MessageFlag::HideEdited;
}
if (file->type == SendMediaType::Audio) {
@@ -415,8 +433,7 @@ void SendConfirmedFile(
}
}
const auto messageFromId =
file->to.options.sendAs
const auto messageFromId = file->to.options.sendAs
? file->to.options.sendAs->id
: anonymousPost
? PeerId()
@@ -486,19 +503,16 @@ void SendConfirmedFile(
edition.savePreviousMedia = true;
itemToEdit->applyEdition(std::move(edition));
} else {
const auto viaBotId = UserId();
history->addNewLocalMessage(
newId.msg,
flags,
viaBotId,
file->to.replyTo,
HistoryItem::NewMessageDate(file->to.options.scheduled),
messageFromId,
messagePostAuthor,
caption,
media,
HistoryMessageMarkupData(),
groupId);
history->addNewLocalMessage({
.id = newId.msg,
.flags = flags,
.from = messageFromId,
.replyTo = file->to.replyTo,
.date = HistoryItem::NewMessageDate(file->to.options),
.shortcutId = file->to.options.shortcutId,
.postAuthor = messagePostAuthor,
.groupedId = groupId,
}, caption, media);
}
if (isEditing) {
+32 -2
View File
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtp_instance.h"
#include "mtproto/mtproto_config.h"
#include "mtproto/mtproto_dc_options.h"
#include "data/business/data_shortcut_messages.h"
#include "data/notify/data_notify_settings.h"
#include "data/stickers/data_stickers.h"
#include "data/data_saved_messages.h"
@@ -1141,7 +1142,8 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
MTPlong(),
MTPMessageReactions(),
MTPVector<MTPRestrictionReason>(),
MTP_int(d.vttl_period().value_or_empty())),
MTP_int(d.vttl_period().value_or_empty()),
MTPint()), // quick_reply_shortcut_id
MessageFlags(),
NewMessageType::Unread);
} break;
@@ -1174,7 +1176,8 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
MTPlong(),
MTPMessageReactions(),
MTPVector<MTPRestrictionReason>(),
MTP_int(d.vttl_period().value_or_empty())),
MTP_int(d.vttl_period().value_or_empty()),
MTPint()), // quick_reply_shortcut_id
MessageFlags(),
NewMessageType::Unread);
} break;
@@ -1565,6 +1568,8 @@ void Updates::feedUpdate(const MTPUpdate &update) {
if (const auto local = owner.message(id)) {
if (local->isScheduled()) {
session().data().scheduledMessages().apply(d, local);
} else if (local->isBusinessShortcut()) {
session().data().shortcutMessages().apply(d, local);
} else {
const auto existing = session().data().message(
id.peer,
@@ -1780,6 +1785,31 @@ void Updates::feedUpdate(const MTPUpdate &update) {
session().data().scheduledMessages().apply(d);
} break;
case mtpc_updateQuickReplies: {
const auto &d = update.c_updateQuickReplies();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateNewQuickReply: {
const auto &d = update.c_updateNewQuickReply();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateDeleteQuickReply: {
const auto &d = update.c_updateDeleteQuickReply();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateQuickReplyMessage: {
const auto &d = update.c_updateQuickReplyMessage();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateDeleteQuickReplyMessages: {
const auto &d = update.c_updateDeleteQuickReplyMessages();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateWebPage: {
auto &d = update.c_updateWebPage();
+124 -63
View File
@@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_premium.h"
#include "api/api_user_names.h"
#include "api/api_websites.h"
#include "data/business/data_shortcut_messages.h"
#include "data/notify/data_notify_settings.h"
#include "data/data_changes.h"
#include "data/data_web_page.h"
@@ -86,6 +87,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
// AyuGram includes
#include "ayu/ayu_settings.h"
#include "ayu/ayu_worker.h"
#include "ayu/utils/telegram_helpers.h"
namespace {
@@ -968,6 +970,7 @@ void ApiWrap::requestMoreDialogsIfNeeded() {
}
}
requestContacts();
_session->data().shortcutMessages().preloadShortcuts();
}
void ApiWrap::updateDialogsOffset(
@@ -2480,6 +2483,14 @@ void ApiWrap::refreshFileReference(
request(MTPmessages_GetScheduledMessages(
item->history()->peer->input,
MTP_vector<MTPint>(1, MTP_int(realId))));
} else if (item->isBusinessShortcut()) {
const auto &shortcuts = _session->data().shortcutMessages();
const auto realId = shortcuts.lookupId(item);
request(MTPmessages_GetQuickReplyMessages(
MTP_flags(MTPmessages_GetQuickReplyMessages::Flag::f_id),
MTP_int(item->shortcutId()),
MTP_vector<MTPint>(1, MTP_int(realId)),
MTP_long(0)));
} else if (const auto channel = item->history()->peer->asChannel()) {
request(MTPchannels_GetMessages(
channel->inputChannel,
@@ -3155,6 +3166,7 @@ void ApiWrap::sharedMediaDone(
if (topicRootId && !topic) {
return;
}
const auto hasMessages = !parsed.messageIds.empty();
_session->storage().add(Storage::SharedMediaAddSlice(
peer->id,
topicRootId,
@@ -3163,7 +3175,7 @@ void ApiWrap::sharedMediaDone(
parsed.noSkipRange,
parsed.fullCount
));
if (type == SharedMediaType::Pinned && !parsed.messageIds.empty()) {
if (type == SharedMediaType::Pinned && hasMessages) {
peer->owner().history(peer)->setHasPinnedMessages(true);
if (topic) {
topic->setHasPinnedMessages(true);
@@ -3172,7 +3184,9 @@ void ApiWrap::sharedMediaDone(
}
void ApiWrap::sendAction(const SendAction &action) {
if (!action.options.scheduled && !action.replaceMediaOf) {
if (!action.options.scheduled
&& !action.options.shortcutId
&& !action.replaceMediaOf) {
const auto topicRootId = action.replyTo.topicRootId;
const auto topic = topicRootId
? action.history->peer->forumTopicFor(topicRootId)
@@ -3207,11 +3221,13 @@ void ApiWrap::finishForwarding(const SendAction &action) {
}
_session->data().sendHistoryChangeNotifications();
_session->changes().historyUpdated(
history,
(action.options.scheduled
? Data::HistoryUpdate::Flag::ScheduledSent
: Data::HistoryUpdate::Flag::MessageSent));
if (!action.options.shortcutId) {
_session->changes().historyUpdated(
history,
(action.options.scheduled
? Data::HistoryUpdate::Flag::ScheduledSent
: Data::HistoryUpdate::Flag::MessageSent));
}
}
void ApiWrap::forwardMessages(
@@ -3240,7 +3256,7 @@ void ApiWrap::forwardMessages(
const auto history = action.history;
const auto peer = history->peer;
if (!action.options.scheduled) {
if (!action.options.scheduled && !action.options.shortcutId) {
histories.readInbox(history);
}
const auto anonymousPost = peer->amAnonymous();
@@ -3258,6 +3274,10 @@ void ApiWrap::forwardMessages(
flags |= MessageFlag::IsOrWasScheduled;
sendFlags |= SendFlag::f_schedule_date;
}
if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= SendFlag::f_quick_reply_shortcut;
}
if (draft.options != Data::ForwardOptions::PreserveInfo) {
sendFlags |= SendFlag::f_drop_author;
}
@@ -3296,12 +3316,20 @@ void ApiWrap::forwardMessages(
peer->input,
MTP_int(topMsgId),
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, action.options.shortcutId)
)).done([=](const MTPUpdates &result) {
applyUpdates(result);
if (shared && !--shared->requestsLeft) {
shared->callback();
}
const auto settings = &AyuSettings::getInstance();
if (!settings->sendReadMessages && settings->markReadAfterPoll && history->lastMessage())
{
readHistory(history->lastMessage());
}
finish();
}).fail([=](const MTP::Error &error) {
if (idsCopy) {
@@ -3340,14 +3368,15 @@ void ApiWrap::forwardMessages(
const auto messagePostAuthor = peer->isBroadcast()
? self->name()
: QString();
history->addNewLocalMessage(
newId.msg,
flags,
HistoryItem::NewMessageDate(action.options.scheduled),
messageFromId,
messagePostAuthor,
item,
topMsgId);
history->addNewLocalMessage({
.id = newId.msg,
.flags = flags,
.from = messageFromId,
.replyTo = { .topicRootId = topMsgId },
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
}, item);
_session->data().registerMessageRandomId(randomId, newId);
if (!localIds) {
localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>();
@@ -3428,6 +3457,9 @@ void ApiWrap::sendSharedContact(
if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled;
}
if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
}
const auto messageFromId = action.options.sendAs
? action.options.sendAs->id
: anonymousPost
@@ -3436,23 +3468,20 @@ void ApiWrap::sendSharedContact(
const auto messagePostAuthor = peer->isBroadcast()
? _session->user()->name()
: QString();
const auto viaBotId = UserId();
const auto item = history->addNewLocalMessage(
newId.msg,
flags,
viaBotId,
action.replyTo,
HistoryItem::NewMessageDate(action.options.scheduled),
messageFromId,
messagePostAuthor,
TextWithEntities(),
MTP_messageMediaContact(
MTP_string(phone),
MTP_string(firstName),
MTP_string(lastName),
MTP_string(), // vcard
MTP_long(userId.bare)),
HistoryMessageMarkupData());
const auto item = history->addNewLocalMessage({
.id = newId.msg,
.flags = flags,
.from = messageFromId,
.replyTo = action.replyTo,
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
}, TextWithEntities(), MTP_messageMediaContact(
MTP_string(phone),
MTP_string(firstName),
MTP_string(lastName),
MTP_string(), // vcard
MTP_long(userId.bare)));
const auto media = MTP_inputMediaContact(
MTP_string(phone),
@@ -3635,6 +3664,17 @@ void ApiWrap::cancelLocalItem(not_null<HistoryItem*> item) {
}
}
void ApiWrap::sendShortcutMessages(
not_null<PeerData*> peer,
BusinessShortcutId id) {
request(MTPmessages_SendQuickReplyMessages(
peer->input,
MTP_int(id)
)).done([=](const MTPUpdates &result) {
applyUpdates(result);
}).send();
}
void ApiWrap::sendMessage(MessageToSend &&message) {
const auto history = message.action.history;
const auto peer = history->peer;
@@ -3776,18 +3816,20 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
mediaFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
const auto viaBotId = UserId();
lastMessage = history->addNewLocalMessage(
newId.msg,
flags,
viaBotId,
action.replyTo,
HistoryItem::NewMessageDate(action.options.scheduled),
messageFromId,
messagePostAuthor,
sending,
media,
HistoryMessageMarkupData());
if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMessage::Flag::f_quick_reply_shortcut;
mediaFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
lastMessage = history->addNewLocalMessage({
.id = newId.msg,
.flags = flags,
.from = messageFromId,
.replyTo = action.replyTo,
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
}, sending, media);
const auto done = [=](
const MTPUpdates &result,
const MTP::Response &response) {
@@ -3813,6 +3855,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
UnixtimeFromMsgId(response.outerMsgId));
}
};
const auto mtpShortcut = Data::ShortcutIdToMTP(
_session,
action.options.shortcutId);
if (exactWebPage
&& !ignoreWebPage
&& (manualWebPage || sending.empty())) {
@@ -3829,8 +3874,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
MTP_long(randomId),
MTPReplyMarkup(),
sentEntities,
MTP_int(message.action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
mtpShortcut
), done, fail);
} else {
histories.sendPreparedMessage(
@@ -3846,7 +3892,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
MTPReplyMarkup(),
sentEntities,
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
mtpShortcut
), done, fail);
}
isFirst = false;
@@ -3937,6 +3984,10 @@ void ApiWrap::sendInlineResult(
flags |= MessageFlag::IsOrWasScheduled;
sendFlags |= SendFlag::f_schedule_date;
}
if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= SendFlag::f_quick_reply_shortcut;
}
if (action.options.hideViaBot) {
sendFlags |= SendFlag::f_hide_via;
}
@@ -3955,15 +4006,18 @@ void ApiWrap::sendInlineResult(
_session->data().registerMessageRandomId(randomId, newId);
data->addToHistory(
history,
flags,
newId.msg,
messageFromId,
HistoryItem::NewMessageDate(action.options.scheduled),
(bot && !action.options.hideViaBot) ? peerToUser(bot->id) : 0,
action.replyTo,
messagePostAuthor);
data->addToHistory(history, {
.id = newId.msg,
.flags = flags,
.from = messageFromId,
.replyTo = action.replyTo,
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.viaBotId = ((bot && !action.options.hideViaBot)
? peerToUser(bot->id)
: UserId()),
.postAuthor = messagePostAuthor,
});
history->clearCloudDraft(topicRootId);
history->startSavingCloudDraft(topicRootId);
@@ -3981,7 +4035,8 @@ void ApiWrap::sendInlineResult(
MTP_long(data->getQueryId()),
MTP_string(data->getId()),
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, action.options.shortcutId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
history->finishSavingCloudDraft(
topicRootId,
@@ -4118,7 +4173,8 @@ void ApiWrap::sendMediaWithRandomId(
: Flag(0))
| (!sentEntities.v.isEmpty() ? Flag::f_entities : Flag(0))
| (options.scheduled ? Flag::f_schedule_date : Flag(0))
| (options.sendAs ? Flag::f_send_as : Flag(0));
| (options.sendAs ? Flag::f_send_as : Flag(0))
| (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0));
auto &histories = history->owner().histories();
const auto peer = history->peer;
@@ -4137,7 +4193,8 @@ void ApiWrap::sendMediaWithRandomId(
MTPReplyMarkup(),
sentEntities,
MTP_int(options.scheduled),
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty())
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, options.shortcutId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
if (done) done(true);
if (updateRecentStickers) {
@@ -4233,7 +4290,10 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
? Flag::f_silent
: Flag(0))
| (album->options.scheduled ? Flag::f_schedule_date : Flag(0))
| (sendAs ? Flag::f_send_as : Flag(0));
| (sendAs ? Flag::f_send_as : Flag(0))
| (album->options.shortcutId
? Flag::f_quick_reply_shortcut
: Flag(0));
auto &histories = history->owner().histories();
const auto peer = history->peer;
histories.sendPreparedMessage(
@@ -4246,7 +4306,8 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
Data::Histories::ReplyToPlaceholder(),
MTP_vector<MTPInputSingleMedia>(medias),
MTP_int(album->options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, album->options.shortcutId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
_sendingAlbums.remove(groupId);
+3
View File
@@ -337,6 +337,9 @@ public:
void cancelLocalItem(not_null<HistoryItem*> item);
void sendShortcutMessages(
not_null<PeerData*> peer,
BusinessShortcutId id);
void sendMessage(MessageToSend &&message);
void sendBotStart(
not_null<UserData*> bot,
+1 -1
View File
@@ -34,7 +34,7 @@ void lateInit() {
}
void runOnce() {
if (!Core::IsAppLaunched() || !Core::App().domain().started()) {
if (!Core::IsAppLaunched() || !Core::App().domain().started() || Core::Quitting()) {
return;
}
+11 -5
View File
@@ -153,13 +153,19 @@ void moveCurrentDatabase() {
}
void initialize() {
const auto res = storage.sync_schema_simulate(true);
auto movePrevious = false;
for (const auto val : res | std::views::values) {
if (val == sync_schema_result::dropped_and_recreated) {
movePrevious = true;
break;
try {
const auto res = storage.sync_schema_simulate(true);
for (const auto val : res | std::views::values) {
if (val == sync_schema_result::dropped_and_recreated) {
movePrevious = true;
break;
}
}
} catch (...) {
LOG(("Exception during sync simulation; possibly corrupted database"));
movePrevious = true;
}
if (movePrevious) {
@@ -13,12 +13,14 @@
#include "ayu/ui/boxes/message_shot_box.h"
#include "boxes/abstract_box.h"
#include "data/data_cloud_themes.h"
#include "data/data_forum.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "history/history.h"
#include "history/history_inner_widget.h"
#include "history/history_item.h"
#include "history/view/history_view_element.h"
#include "history/history_item_components.h"
#include "history/view/media/history_view_media.h"
#include "main/main_session.h"
#include "styles/style_chat.h"
@@ -152,27 +154,28 @@ public:
not_null<QWidget*> parent,
not_null<Ui::ChatStyle*> st,
Fn<void()> update,
bool isTopic);
not_null<History*> history);
bool elementAnimationsPaused() override;
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
HistoryView::Context elementContext() override;
bool elementHideReply(not_null<const HistoryView::Element*> view) override;
bool elementIsChatWide() override;
private:
const not_null<QWidget*> _parent;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
HistoryView::Context _context;
not_null<History*> _history;
};
MessageShotDelegate::MessageShotDelegate(
not_null<QWidget*> parent,
not_null<Ui::ChatStyle*> st,
Fn<void()> update,
bool isTopic)
not_null<History*> history)
: _parent(parent)
, _pathGradient(HistoryView::MakePathShiftGradient(st, update)) {
_context = isTopic ? HistoryView::Context::Replies : HistoryView::Context::AdminLog;
, _pathGradient(HistoryView::MakePathShiftGradient(st, update))
, _history(history) {
}
bool MessageShotDelegate::elementAnimationsPaused() {
@@ -188,6 +191,21 @@ HistoryView::Context MessageShotDelegate::elementContext() {
return HistoryView::Context::AdminLog;
}
bool MessageShotDelegate::elementHideReply(not_null<const HistoryView::Element*> view) {
if (const auto reply = view->data()->Get<HistoryMessageReply>()) {
const auto replyToPeerId = reply->externalPeerId()
? reply->externalPeerId()
: _history->peer->id;
if (reply->fields().manualQuote) {
return false;
} else if (replyToPeerId == _history->peer->id) {
return _history->asForum() && _history->asForum()->topicFor(reply->messageId());
}
}
return false;
}
bool MessageShotDelegate::elementIsChatWide() {
return true;
}
@@ -267,7 +285,7 @@ QImage Make(not_null<QWidget*> box, const ShotConfig &config) {
{
box->update();
},
messages.front()->history()->asTopic());
messages.front()->history());
// remove deleted messages
messages.erase(
@@ -393,7 +411,7 @@ QImage Make(not_null<QWidget*> box, const ShotConfig &config) {
return newResult;
}
void Wrapper(not_null<HistoryView::ListWidget*> widget) {
void Wrapper(not_null<HistoryView::ListWidget*> widget, Fn<void()> clearSelected) {
const auto items = widget->getSelectedIds();
if (items.empty()) {
return;
@@ -418,6 +436,10 @@ void Wrapper(not_null<HistoryView::ListWidget*> widget) {
messages,
};
auto box = Box<MessageShotBox>(config);
box->boxClosing() | rpl::start_with_next([=]
{
clearSelected();
}, box->lifetime());
Ui::show(std::move(box));
}
@@ -19,7 +19,7 @@ struct ShotConfig
std::shared_ptr<Ui::ChatStyle> st;
std::vector<not_null<HistoryItem*>> messages;
bool showBackground;
bool showBackground = true;
bool showDate;
bool showReactions;
};
@@ -69,6 +69,6 @@ QColor makeDefaultBackgroundColor();
QImage Make(not_null<QWidget*> box, const ShotConfig &config);
void Wrapper(not_null<HistoryView::ListWidget*> widget);
void Wrapper(not_null<HistoryView::ListWidget*> widget, Fn<void()> clearSelected);
}
@@ -113,7 +113,7 @@ void MessageShotBox::setupContent() {
content,
tr::ayu_MessageShotShowBackground(),
st::settingsButtonNoIcon
)->toggleOn(rpl::single(false)
)->toggleOn(rpl::single(_config.showBackground)
)->toggledValue(
) | start_with_next(
[=](bool enabled)
@@ -128,7 +128,7 @@ void MessageShotBox::setupContent() {
content,
tr::ayu_MessageShotShowDate(),
st::settingsButtonNoIcon
)->toggleOn(rpl::single(false)
)->toggleOn(rpl::single(_config.showDate)
)->toggledValue(
) | start_with_next(
[=](bool enabled)
@@ -143,7 +143,7 @@ void MessageShotBox::setupContent() {
content,
tr::ayu_MessageShotShowReactions(),
st::settingsButtonNoIcon
)->toggleOn(rpl::single(false)
)->toggleOn(rpl::single(_config.showReactions)
)->toggledValue(
) | start_with_next(
[=](bool enabled)
@@ -154,11 +154,12 @@ void MessageShotBox::setupContent() {
},
content->lifetime());
AddButtonWithIcon(
const auto latestToggle = AddButtonWithIcon(
content,
tr::ayu_MessageShotShowColorfulReplies(),
st::settingsButtonNoIcon
)->toggleOn(rpl::single(savedShowColorfulReplies)
);
latestToggle->toggleOn(rpl::single(savedShowColorfulReplies)
)->toggledValue(
) | start_with_next(
[=](bool enabled)
@@ -186,11 +187,15 @@ void MessageShotBox::setupContent() {
if (!path.isEmpty()) {
image.save(path);
}
closeBox();
});
addButton(tr::ayu_MessageShotCopy(),
[=]
{
QGuiApplication::clipboard()->setImage(imageView->getImage());
closeBox();
});
updatePreview();
@@ -210,4 +215,7 @@ void MessageShotBox::setupContent() {
content->lifetime());
setDimensionsToContent(boxWidth, content);
// scroll to the end
scrollToWidget(latestToggle);
}
@@ -1528,7 +1528,7 @@ void InnerWidget::updateSelected() {
if (dragState.link
|| dragState.cursor == CursorState::Date
|| dragState.cursor == CursorState::Forwarded) {
Ui::Tooltip::Show(1000, this);
Ui::Tooltip::Show(350, this);
}
auto cursor = style::cur_default;
@@ -614,8 +614,6 @@ void GenerateItems(
not_null<History*> history,
EditedMessage message,
Fn<void(OwnedItem item, TimeId sentDate, MsgId)> callback) {
const auto session = &history->session();
const auto id = message.fakeId;
PeerData *from = history->owner().userLoaded(message.fromId);
if (!from) {
from = history->owner().channelLoaded(message.fromId);
@@ -639,43 +637,14 @@ void GenerateItems(
const auto fromLink = from->createOpenLink();
const auto fromLinkText = Ui::Text::Link(fromName, QString());
const auto addSimpleServiceMessage = [&](
const TextWithEntities &text,
MsgId realId = MsgId(),
PhotoData *photo = nullptr)
{
auto message = PreparedServiceText{text};
message.links.push_back(fromLink);
addPart(
history->makeMessage(
history->nextNonHistoryEntryId(),
MessageFlag::AdminLogEntry,
date,
std::move(message),
peerToUser(from->id),
photo),
0,
realId);
};
const auto makeSimpleTextMessage = [&](TextWithEntities &&text)
{
const auto bodyFlags = MessageFlag::HasFromId | MessageFlag::Local;
const auto bodyReplyTo = FullReplyTo();
const auto bodyViaBotId = UserId();
const auto bodyGroupedId = uint64();
return history->makeMessage(
history->nextNonHistoryEntryId(),
bodyFlags,
bodyReplyTo,
bodyViaBotId,
date,
peerToUser(from->id),
QString(),
std::move(text),
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
bodyGroupedId);
return history->makeMessage({
.id = history->nextNonHistoryEntryId(),
.flags = MessageFlag::HasFromId | MessageFlag::AdminLogEntry,
.from = from->id,
.date = date,
}, std::move(text), MTP_messageMediaEmpty());
};
const auto addSimpleTextMessage = [&](TextWithEntities &&text)
@@ -26,6 +26,7 @@
#include "styles/style_widgets.h"
#include "icon_picker.h"
#include "core/application.h"
#include "styles/style_ayu_icons.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
@@ -35,6 +36,7 @@
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/menu/menu_add_action_callback.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
@@ -391,6 +393,17 @@ rpl::producer<QString> Ayu::title() {
return tr::ayu_AyuPreferences();
}
void Ayu::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
addAction(
tr::ayu_RegisterURLScheme(tr::now),
[=] { Core::Application::RegisterUrlScheme(); },
&st::menuIconLinks);
addAction(
tr::lng_restart_button(tr::now),
[=] { Core::Restart(); },
&st::menuIconRestore);
}
Ayu::Ayu(
QWidget *parent,
not_null<Window::SessionController*> controller)
@@ -25,6 +25,9 @@ public:
[[nodiscard]] rpl::producer<QString> title() override;
void fillTopBarMenu(
const Ui::Menu::MenuCallback &addAction) override;
private:
void setupContent(not_null<Window::SessionController*> controller);
};
@@ -1018,7 +1018,7 @@ void SetupChannelBox::prepare() {
cancel);
connect(_link, &Ui::MaskedInputField::changed, [=] { handleChange(); });
_link->setVisible(_privacyGroup->value() == Privacy::Public);
_link->setVisible(_privacyGroup->current() == Privacy::Public);
_privacyGroup->setChangedCallback([=](Privacy value) {
privacyChanged(value);
@@ -1063,7 +1063,7 @@ void SetupChannelBox::updateMaxHeight() {
: 0)
+ st::newGroupPadding.bottom();
if (!_channel->isMegagroup()
|| _privacyGroup->value() == Privacy::Public) {
|| _privacyGroup->current() == Privacy::Public) {
newHeight += st::newGroupLinkPadding.top()
+ _link->height()
+ st::newGroupLinkPadding.bottom();
@@ -1264,7 +1264,7 @@ void SetupChannelBox::save() {
};
if (_saveRequestId) {
return;
} else if (_privacyGroup->value() == Privacy::Private) {
} else if (_privacyGroup->current() == Privacy::Private) {
closeBox();
} else {
const auto link = _link->text().trimmed();
+5 -3
View File
@@ -81,9 +81,9 @@ void AutoLockBox::prepare() {
const auto timeInput = Ui::CreateChild<Ui::TimeInput>(
this,
(group->value() == kCustom)
(group->current() == kCustom
? TimeString(currentTime)
: kDefaultCustom.utf8(),
: kDefaultCustom.utf8()),
st::autolockTimeField,
st::autolockDateField,
st::scheduleTimeSeparator,
@@ -115,7 +115,9 @@ void AutoLockBox::prepare() {
});
rpl::merge(
boxClosing() | rpl::filter([=] { return group->value() == kCustom; }),
boxClosing() | rpl::filter(
[=] { return group->current() == kCustom; }
),
timeInput->submitRequests()
) | rpl::start_with_next([=] {
if (const auto result = collect()) {
@@ -31,8 +31,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "history/history_item_helpers.h"
#include "history/view/history_view_message.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
#include "apiwrap.h"
#include "data/data_session.h"
@@ -42,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document_resolver.h"
#include "data/data_file_origin.h"
#include "data/data_peer_values.h"
#include "data/data_premium_limits.h"
#include "settings/settings_premium.h"
#include "storage/file_upload.h"
#include "storage/localimageloader.h"
@@ -82,11 +81,11 @@ constexpr auto kMaxWallPaperSlugLength = 255;
const auto flags = MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| (out ? MessageFlag::Outgoing : MessageFlag(0));
const auto item = history->makeMessage(
history->owner().nextLocalMessageId(),
flags,
base::unixtime::now(),
PreparedServiceText{ { text } });
const auto item = history->makeMessage({
.id = history->owner().nextLocalMessageId(),
.flags = flags,
.date = base::unixtime::now(),
}, PreparedServiceText{ { text } });
return AdminLog::OwnedItem(delegate, item);
}
@@ -97,24 +96,16 @@ constexpr auto kMaxWallPaperSlugLength = 255;
bool out) {
Expects(history->peer->isUser());
const auto flags = MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| (out ? MessageFlag::Outgoing : MessageFlag(0));
const auto replyTo = FullReplyTo();
const auto viaBotId = UserId();
const auto groupedId = uint64();
const auto item = history->makeMessage(
history->nextNonHistoryEntryId(),
flags,
replyTo,
viaBotId,
base::unixtime::now(),
out ? history->session().userId() : peerToUser(history->peer->id),
QString(),
TextWithEntities{ text },
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
groupedId);
const auto item = history->makeMessage({
.id = history->nextNonHistoryEntryId(),
.flags = (MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| (out ? MessageFlag::Outgoing : MessageFlag(0))),
.from = (out
? history->session().userId()
: peerToUser(history->peer->id)),
.date = base::unixtime::now(),
}, TextWithEntities{ text }, MTP_messageMediaEmpty());
return AdminLog::OwnedItem(delegate, item);
}
@@ -699,16 +690,10 @@ void BackgroundPreviewBox::checkLevelForChannel() {
if (!weak) {
return std::optional<Ui::AskBoostReason>();
}
const auto appConfig = &_forPeer->session().account().appConfig();
const auto defaultRequired = appConfig->get<int>(
"channel_wallpaper_level_min",
9);
const auto customRequired = appConfig->get<int>(
"channel_custom_wallpaper_level_min",
10);
const auto limits = Data::LevelLimits(&_forPeer->session());
const auto required = _paperEmojiId.isEmpty()
? customRequired
: defaultRequired;
? limits.channelCustomWallpaperLevelMin()
: limits.channelWallpaperLevelMin();
if (level >= required) {
applyForPeer(false);
return std::optional<Ui::AskBoostReason>();
@@ -791,7 +776,7 @@ void BackgroundPreviewBox::applyForPeer() {
} else {
ShowPremiumPreviewBox(
_controller->uiShow(),
PremiumPreview::Wallpapers);
PremiumFeature::Wallpapers);
}
});
const auto cancel = CreateChild<RoundButton>(
+2 -2
View File
@@ -711,7 +711,7 @@ createPollOptionRemove: CrossButton {
crossFgOver: boxTitleCloseFgOver;
crossPosition: point(0px, 0px);
duration: 150;
duration: 135;
loadingPeriod: 1000;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
@@ -751,7 +751,7 @@ backgroundCheck: ServiceCheck {
large: 6px;
stroke: 2px;
color: msgServiceFg;
duration: 200;
duration: 180;
}
backgroundConfirmPadding: margins(24px, 16px, 24px, 16px);
backgroundConfirm: RoundButton(defaultActiveButton) {
@@ -717,7 +717,7 @@ void ProxiesBox::refreshProxyForCalls() {
return;
}
_proxyForCalls->toggle(
(_proxySettings->value() == ProxyData::Settings::Enabled
(_proxySettings->current() == ProxyData::Settings::Enabled
&& _currentProxySupportsCallsId != 0),
anim::type::normal);
}
@@ -864,7 +864,7 @@ void ProxyBox::refreshButtons() {
addButton(tr::lng_settings_save(), [=] { save(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });
const auto type = _type->value();
const auto type = _type->current();
if (type == Type::Socks5 || type == Type::Mtproto) {
addLeftButton(tr::lng_proxy_share(), [=] { share(); });
}
@@ -885,7 +885,7 @@ void ProxyBox::share() {
ProxyData ProxyBox::collectData() {
auto result = ProxyData();
result.type = _type->value();
result.type = _type->current();
result.host = _host->getLastText().trimmed();
result.port = _port->getLastText().trimmed().toInt();
result.user = (result.type == Type::Mtproto)
@@ -1053,7 +1053,7 @@ void ProxyBox::setupControls(const ProxyData &data) {
handleType(type);
refreshButtons();
});
handleType(_type->value());
handleType(_type->current());
}
void ProxyBox::addLabel(
@@ -44,7 +44,9 @@ void DownloadPathBox::prepare() {
setTitle(tr::lng_download_path_header());
_group->setChangedCallback([this](Directory value) { radioChanged(value); });
_group->setChangedCallback([this](Directory value) {
radioChanged(value);
});
_pathLink->addClickHandler([=] { editPath(); });
if (!_path.isEmpty() && _path != FileDialog::Tmp()) {
@@ -54,7 +56,7 @@ void DownloadPathBox::prepare() {
}
void DownloadPathBox::updateControlsVisibility() {
auto custom = (_group->value() == Directory::Custom);
auto custom = (_group->current() == Directory::Custom);
_pathLink->setVisible(custom);
auto newHeight = st::boxOptionListPadding.top() + (_default ? _default->getMargins().top() + _default->heightNoMargins() : 0) + st::boxOptionListSkip + _temp->heightNoMargins() + st::boxOptionListSkip + _dir->heightNoMargins();
@@ -122,7 +124,7 @@ void DownloadPathBox::editPath() {
void DownloadPathBox::save() {
#ifndef OS_WIN_STORE
auto value = _group->value();
auto value = _group->current();
auto computePath = [this, value] {
if (value == Directory::Custom) {
return _path;
@@ -682,7 +682,7 @@ void EditCaptionBox::setupEmojiPanel() {
&& !_controller->session().premium()) {
ShowPremiumPreviewBox(
_controller,
PremiumPreview::AnimatedEmoji);
PremiumFeature::AnimatedEmoji);
} else {
Data::InsertCustomEmoji(_field.get(), data.document);
}
@@ -895,6 +895,7 @@ void EditCaptionBox::save() {
auto options = Api::SendOptions();
options.scheduled = item->isScheduled() ? item->date() : 0;
options.shortcutId = item->shortcutId();
if (!_preparedList.files.empty()) {
if ((_albumType != Ui::AlbumType::None)
+51 -10
View File
@@ -10,28 +10,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_global_privacy.h"
#include "ui/layers/generic_box.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/shadow.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
#include "history/history.h"
#include "boxes/peer_list_controllers.h"
#include "settings/settings_common.h"
#include "settings/settings_premium.h"
#include "settings/settings_privacy_security.h"
#include "calls/calls_instance.h"
#include "base/binary_guard.h"
#include "lang/lang_keys.h"
#include "apiwrap.h"
#include "main/main_session.h"
#include "data/data_user.h"
#include "data/data_chat.h"
#include "data/data_channel.h"
#include "data/data_peer_values.h"
#include "window/window_session_controller.h"
#include "styles/style_settings.h"
#include "styles/style_layers.h"
@@ -67,6 +63,32 @@ void CreateRadiobuttonLock(
}, lock->lifetime());
}
void AddPremiumRequiredRow(
not_null<Ui::RpWidget*> widget,
not_null<Main::Session*> session,
Fn<void()> clickedCallback,
Fn<void()> setDefaultOption,
const style::Checkbox &st) {
const auto row = Ui::CreateChild<Ui::AbstractButton>(widget.get());
widget->sizeValue(
) | rpl::start_with_next([=](const QSize &s) {
row->resize(s);
}, row->lifetime());
row->setClickedCallback(std::move(clickedCallback));
CreateRadiobuttonLock(row, st);
Data::AmPremiumValue(
session
) | rpl::start_with_next([=](bool premium) {
row->setVisible(!premium);
if (!premium) {
setDefaultOption();
}
}, row->lifetime());
}
} // namespace
class PrivacyExceptionsBoxController : public ChatsListBoxController {
@@ -363,10 +385,29 @@ void EditPrivacyBox::setupContent() {
content,
_controller->optionsTitleKey(),
{ 0, st::settingsPrivacySkipTop, 0, 0 });
addOptionRow(Option::Everyone);
addOptionRow(Option::Contacts);
addOptionRow(Option::CloseFriends);
addOptionRow(Option::Nobody);
const auto options = {
Option::Everyone,
Option::Contacts,
Option::CloseFriends,
Option::Nobody,
};
for (const auto &option : options) {
if (const auto row = addOptionRow(option)) {
const auto premiumCallback = _controller->premiumClickedCallback(
option,
_window);
if (premiumCallback) {
AddPremiumRequiredRow(
row,
&_window->session(),
premiumCallback,
[=] { group->setValue(Option::Everyone); },
st::messagePrivacyCheck);
}
}
}
const auto warning = addLabelOrDivider(
content,
_controller->warning(),
@@ -541,7 +582,7 @@ void EditMessagesPrivacyBox(
box->addButton(tr::lng_settings_save(), [=] {
if (controller->session().premium()) {
privacy->updateNewRequirePremium(
group->value() == kOptionPremium);
group->current() == kOptionPremium);
box->closeBox();
} else {
showToast();
@@ -88,6 +88,12 @@ public:
virtual void saveAdditional() {
}
[[nodiscard]] virtual Fn<void()> premiumClickedCallback(
Option option,
not_null<Window::SessionController*> controller) {
return nullptr;
}
virtual ~EditPrivacyController() = default;
protected:
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/filters/edit_filter_box.h"
#include "boxes/filters/edit_filter_chats_list.h"
#include "boxes/filters/edit_filter_chats_preview.h"
#include "boxes/filters/edit_filter_links.h"
#include "boxes/premium_limits_box.h"
#include "chat_helpers/emoji_suggestions_widget.h"
@@ -26,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat_filters.h"
#include "data/data_peer.h"
#include "data/data_peer_values.h" // Data::AmPremiumValue.
#include "data/data_premium_limits.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "core/application.h"
@@ -56,60 +58,6 @@ using Flags = Data::ChatFilter::Flags;
using ExceptionPeersRef = const base::flat_set<not_null<History*>> &;
using ExceptionPeersGetter = ExceptionPeersRef(Data::ChatFilter::*)() const;
constexpr auto kAllTypes = {
Flag::Contacts,
Flag::NonContacts,
Flag::Groups,
Flag::Channels,
Flag::Bots,
Flag::NoMuted,
Flag::NoRead,
Flag::NoArchived,
};
class FilterChatsPreview final : public Ui::RpWidget {
public:
FilterChatsPreview(
not_null<QWidget*> parent,
Flags flags,
const base::flat_set<not_null<History*>> &peers);
[[nodiscard]] rpl::producer<Flag> flagRemoved() const;
[[nodiscard]] rpl::producer<not_null<History*>> peerRemoved() const;
void updateData(
Flags flags,
const base::flat_set<not_null<History*>> &peers);
int resizeGetHeight(int newWidth) override;
private:
using Button = base::unique_qptr<Ui::IconButton>;
struct FlagButton {
Flag flag = Flag();
Button button;
};
struct PeerButton {
not_null<History*> history;
Ui::PeerUserpicView userpic;
Ui::Text::String name;
Button button;
};
void paintEvent(QPaintEvent *e) override;
void refresh();
void removeFlag(Flag flag);
void removePeer(not_null<History*> history);
std::vector<FlagButton> _removeFlag;
std::vector<PeerButton> _removePeer;
rpl::event_stream<Flag> _flagRemoved;
rpl::event_stream<not_null<History*>> _peerRemoved;
};
struct NameEditing {
not_null<Ui::InputField*> field;
bool custom = false;
@@ -167,167 +115,6 @@ not_null<FilterChatsPreview*> SetupChatsPreview(
return preview;
}
FilterChatsPreview::FilterChatsPreview(
not_null<QWidget*> parent,
Flags flags,
const base::flat_set<not_null<History*>> &peers)
: RpWidget(parent) {
updateData(flags, peers);
}
void FilterChatsPreview::refresh() {
resizeToWidth(width());
}
void FilterChatsPreview::updateData(
Flags flags,
const base::flat_set<not_null<History*>> &peers) {
_removeFlag.clear();
_removePeer.clear();
const auto makeButton = [&](Fn<void()> handler) {
auto result = base::make_unique_q<Ui::IconButton>(
this,
st::windowFilterSmallRemove);
result->setClickedCallback(std::move(handler));
return result;
};
for (const auto flag : kAllTypes) {
if (flags & flag) {
_removeFlag.push_back({
flag,
makeButton([=] { removeFlag(flag); }) });
}
}
for (const auto &history : peers) {
_removePeer.push_back(PeerButton{
.history = history,
.button = makeButton([=] { removePeer(history); })
});
}
refresh();
}
int FilterChatsPreview::resizeGetHeight(int newWidth) {
const auto right = st::windowFilterSmallRemoveRight;
const auto add = (st::windowFilterSmallItem.height
- st::windowFilterSmallRemove.height) / 2;
auto top = 0;
const auto moveNextButton = [&](not_null<Ui::IconButton*> button) {
button->moveToRight(right, top + add, newWidth);
top += st::windowFilterSmallItem.height;
};
for (const auto &[flag, button] : _removeFlag) {
moveNextButton(button.get());
}
for (const auto &[history, userpic, name, button] : _removePeer) {
moveNextButton(button.get());
}
return top;
}
void FilterChatsPreview::paintEvent(QPaintEvent *e) {
auto p = Painter(this);
auto top = 0;
const auto &st = st::windowFilterSmallItem;
const auto iconLeft = st.photoPosition.x();
const auto iconTop = st.photoPosition.y();
const auto nameLeft = st.namePosition.x();
p.setFont(st::windowFilterSmallItem.nameStyle.font);
const auto nameTop = st.namePosition.y();
for (const auto &[flag, button] : _removeFlag) {
PaintFilterChatsTypeIcon(
p,
flag,
iconLeft,
top + iconTop,
width(),
st.photoSize);
p.setPen(st::contactsNameFg);
p.drawTextLeft(
nameLeft,
top + nameTop,
width(),
FilterChatsTypeName(flag));
top += st.height;
}
for (auto &[history, userpic, name, button] : _removePeer) {
const auto savedMessages = history->peer->isSelf();
const auto repliesMessages = history->peer->isRepliesChat();
if (savedMessages || repliesMessages) {
if (savedMessages) {
Ui::EmptyUserpic::PaintSavedMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
} else {
Ui::EmptyUserpic::PaintRepliesMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
}
p.setPen(st::contactsNameFg);
p.drawTextLeft(
nameLeft,
top + nameTop,
width(),
(savedMessages
? tr::lng_saved_messages(tr::now)
: tr::lng_replies_messages(tr::now)));
} else {
history->peer->paintUserpicLeft(
p,
userpic,
iconLeft,
top + iconTop,
width(),
st.photoSize);
p.setPen(st::contactsNameFg);
if (name.isEmpty()) {
name.setText(
st::msgNameStyle,
history->peer->name(),
Ui::NameTextOptions());
}
name.drawLeftElided(
p,
nameLeft,
top + nameTop,
button->x() - nameLeft,
width());
}
top += st.height;
}
}
void FilterChatsPreview::removeFlag(Flag flag) {
const auto i = ranges::find(_removeFlag, flag, &FlagButton::flag);
Assert(i != end(_removeFlag));
_removeFlag.erase(i);
refresh();
_flagRemoved.fire_copy(flag);
}
void FilterChatsPreview::removePeer(not_null<History*> history) {
const auto i = ranges::find(_removePeer, history, &PeerButton::history);
Assert(i != end(_removePeer));
_removePeer.erase(i);
refresh();
_peerRemoved.fire_copy(history);
}
rpl::producer<Flag> FilterChatsPreview::flagRemoved() const {
return _flagRemoved.events();
}
rpl::producer<not_null<History*>> FilterChatsPreview::peerRemoved() const {
return _peerRemoved.events();
}
void EditExceptions(
not_null<Window::SessionController*> window,
not_null<QObject*> context,
@@ -338,6 +125,12 @@ void EditExceptions(
const auto include = (options & Flag::Contacts) != Flags(0);
const auto rules = data->current();
const auto session = &window->session();
const auto limit = Data::PremiumLimits(
session
).dialogFiltersChatsCurrent();
const auto showLimitReached = [=] {
window->show(Box(FilterChatsLimitBox, session, limit, include));
};
auto controller = std::make_unique<EditFilterChatsListController>(
session,
(include
@@ -346,9 +139,8 @@ void EditExceptions(
options,
rules.flags() & options,
include ? rules.always() : rules.never(),
[=](int count) {
return Box(FilterChatsLimitBox, session, count, include);
});
limit,
showLimitReached);
const auto rawController = controller.get();
auto initBox = [=](not_null<PeerListBox*> box) {
box->setCloseByOutsideClick(false);
@@ -28,6 +28,8 @@ using Flag = Data::ChatFilter::Flag;
using Flags = Data::ChatFilter::Flags;
constexpr auto kAllTypes = {
Flag::NewChats,
Flag::ExistingChats,
Flag::Contacts,
Flag::NonContacts,
Flag::Groups,
@@ -119,7 +121,7 @@ PaintRoundImageCallback TypeRow::generatePaintUserpicCallback(
}
Flag TypeRow::flag() const {
return static_cast<Flag>(id() & 0xFF);
return static_cast<Flag>(id() & 0xFFFF);
}
ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
@@ -219,6 +221,8 @@ auto TypeController::rowSelectionChanges() const
[[nodiscard]] QString FilterChatsTypeName(Flag flag) {
switch (flag) {
case Flag::NewChats: return tr::lng_filters_type_new(tr::now);
case Flag::ExistingChats: return tr::lng_filters_type_existing(tr::now);
case Flag::Contacts: return tr::lng_filters_type_contacts(tr::now);
case Flag::NonContacts:
return tr::lng_filters_type_non_contacts(tr::now);
@@ -241,6 +245,8 @@ void PaintFilterChatsTypeIcon(
int size) {
const auto &color1 = [&]() -> const style::color& {
switch (flag) {
case Flag::NewChats: return st::historyPeer5UserpicBg;
case Flag::ExistingChats: return st::historyPeer8UserpicBg;
case Flag::Contacts: return st::historyPeer4UserpicBg;
case Flag::NonContacts: return st::historyPeer7UserpicBg;
case Flag::Groups: return st::historyPeer2UserpicBg;
@@ -254,6 +260,8 @@ void PaintFilterChatsTypeIcon(
}();
const auto &color2 = [&]() -> const style::color& {
switch (flag) {
case Flag::NewChats: return st::historyPeer5UserpicBg2;
case Flag::ExistingChats: return st::historyPeer8UserpicBg2;
case Flag::Contacts: return st::historyPeer4UserpicBg2;
case Flag::NonContacts: return st::historyPeer7UserpicBg2;
case Flag::Groups: return st::historyPeer2UserpicBg2;
@@ -267,6 +275,8 @@ void PaintFilterChatsTypeIcon(
}();
const auto &icon = [&]() -> const style::icon& {
switch (flag) {
case Flag::NewChats: return st::windowFilterTypeNewChats;
case Flag::ExistingChats: return st::windowFilterTypeExistingChats;
case Flag::Contacts: return st::windowFilterTypeContacts;
case Flag::NonContacts: return st::windowFilterTypeNonContacts;
case Flag::Groups: return st::windowFilterTypeGroups;
@@ -323,17 +333,17 @@ EditFilterChatsListController::EditFilterChatsListController(
Flags options,
Flags selected,
const base::flat_set<not_null<History*>> &peers,
LimitBoxFactory limitBox)
int limit,
Fn<void()> showLimitReached)
: ChatsListBoxController(session)
, _session(session)
, _limitBox(std::move(limitBox))
, _showLimitReached(std::move(showLimitReached))
, _title(std::move(title))
, _peers(peers)
, _options(options & ~Flag::Chatlist)
, _selected(selected)
, _limit(Data::PremiumLimits(session).dialogFiltersChatsCurrent())
, _limit(limit)
, _chatlist(options & Flag::Chatlist) {
Expects(_limitBox != nullptr);
}
Main::Session &EditFilterChatsListController::session() const {
@@ -361,8 +371,8 @@ void EditFilterChatsListController::rowClicked(not_null<PeerListRow*> row) {
if (count < _limit || row->checked()) {
delegate()->peerListSetRowChecked(row, !row->checked());
updateTitle();
} else {
delegate()->peerListUiShow()->showBox(_limitBox(count));
} else if (const auto copy = _showLimitReached) {
copy();
}
}
@@ -469,6 +479,10 @@ object_ptr<Ui::RpWidget> EditFilterChatsListController::prepareTypesList() {
auto EditFilterChatsListController::createRow(not_null<History*> history)
-> std::unique_ptr<Row> {
const auto business = _options & (Flag::NewChats | Flag::ExistingChats);
if (business && (history->peer->isSelf() || !history->peer->isUser())) {
return nullptr;
}
return history->inChatList()
? std::make_unique<ExceptionRow>(history)
: nullptr;
@@ -43,7 +43,6 @@ class EditFilterChatsListController final : public ChatsListBoxController {
public:
using Flag = Data::ChatFilter::Flag;
using Flags = Data::ChatFilter::Flags;
using LimitBoxFactory = Fn<object_ptr<Ui::BoxContent>(int)>;
EditFilterChatsListController(
not_null<Main::Session*> session,
@@ -51,7 +50,8 @@ public:
Flags options,
Flags selected,
const base::flat_set<not_null<History*>> &peers,
LimitBoxFactory limitBox);
int limit,
Fn<void()> showLimitReached);
[[nodiscard]] Main::Session &session() const override;
[[nodiscard]] Flags chosenOptions() const {
@@ -72,7 +72,7 @@ private:
void updateTitle();
const not_null<Main::Session*> _session;
const LimitBoxFactory _limitBox;
const Fn<void()> _showLimitReached;
rpl::producer<QString> _title;
base::flat_set<not_null<History*>> _peers;
Flags _options;
@@ -0,0 +1,199 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/filters/edit_filter_chats_preview.h"
#include "boxes/filters/edit_filter_chats_list.h"
#include "data/data_peer.h"
#include "history/history.h"
#include "lang/lang_keys.h"
#include "ui/text/text_options.h"
#include "ui/widgets/buttons.h"
#include "ui/painter.h"
#include "styles/style_chat.h"
#include "styles/style_window.h"
namespace {
using Flag = Data::ChatFilter::Flag;
constexpr auto kAllTypes = {
Flag::NewChats,
Flag::ExistingChats,
Flag::Contacts,
Flag::NonContacts,
Flag::Groups,
Flag::Channels,
Flag::Bots,
Flag::NoMuted,
Flag::NoRead,
Flag::NoArchived,
};
} // namespace
FilterChatsPreview::FilterChatsPreview(
not_null<QWidget*> parent,
Flags flags,
const base::flat_set<not_null<History*>> &peers)
: RpWidget(parent) {
updateData(flags, peers);
}
void FilterChatsPreview::refresh() {
resizeToWidth(width());
}
void FilterChatsPreview::updateData(
Flags flags,
const base::flat_set<not_null<History*>> &peers) {
_removeFlag.clear();
_removePeer.clear();
const auto makeButton = [&](Fn<void()> handler) {
auto result = base::make_unique_q<Ui::IconButton>(
this,
st::windowFilterSmallRemove);
result->setClickedCallback(std::move(handler));
result->show();
return result;
};
for (const auto flag : kAllTypes) {
if (flags & flag) {
_removeFlag.push_back({
flag,
makeButton([=] { removeFlag(flag); }) });
}
}
for (const auto &history : peers) {
_removePeer.push_back(PeerButton{
.history = history,
.button = makeButton([=] { removePeer(history); })
});
}
refresh();
}
int FilterChatsPreview::resizeGetHeight(int newWidth) {
const auto right = st::windowFilterSmallRemoveRight;
const auto add = (st::windowFilterSmallItem.height
- st::windowFilterSmallRemove.height) / 2;
auto top = 0;
const auto moveNextButton = [&](not_null<Ui::IconButton*> button) {
button->moveToRight(right, top + add, newWidth);
top += st::windowFilterSmallItem.height;
};
for (const auto &[flag, button] : _removeFlag) {
moveNextButton(button.get());
}
for (const auto &[history, userpic, name, button] : _removePeer) {
moveNextButton(button.get());
}
return top;
}
void FilterChatsPreview::paintEvent(QPaintEvent *e) {
auto p = Painter(this);
auto top = 0;
const auto &st = st::windowFilterSmallItem;
const auto iconLeft = st.photoPosition.x();
const auto iconTop = st.photoPosition.y();
const auto nameLeft = st.namePosition.x();
p.setFont(st::windowFilterSmallItem.nameStyle.font);
const auto nameTop = st.namePosition.y();
for (const auto &[flag, button] : _removeFlag) {
PaintFilterChatsTypeIcon(
p,
flag,
iconLeft,
top + iconTop,
width(),
st.photoSize);
p.setPen(st::contactsNameFg);
p.drawTextLeft(
nameLeft,
top + nameTop,
width(),
FilterChatsTypeName(flag));
top += st.height;
}
for (auto &[history, userpic, name, button] : _removePeer) {
const auto savedMessages = history->peer->isSelf();
const auto repliesMessages = history->peer->isRepliesChat();
if (savedMessages || repliesMessages) {
if (savedMessages) {
Ui::EmptyUserpic::PaintSavedMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
} else {
Ui::EmptyUserpic::PaintRepliesMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
}
p.setPen(st::contactsNameFg);
p.drawTextLeft(
nameLeft,
top + nameTop,
width(),
(savedMessages
? tr::lng_saved_messages(tr::now)
: tr::lng_replies_messages(tr::now)));
} else {
history->peer->paintUserpicLeft(
p,
userpic,
iconLeft,
top + iconTop,
width(),
st.photoSize);
p.setPen(st::contactsNameFg);
if (name.isEmpty()) {
name.setText(
st::msgNameStyle,
history->peer->name(),
Ui::NameTextOptions());
}
name.drawLeftElided(
p,
nameLeft,
top + nameTop,
button->x() - nameLeft,
width());
}
top += st.height;
}
}
void FilterChatsPreview::removeFlag(Flag flag) {
const auto i = ranges::find(_removeFlag, flag, &FlagButton::flag);
Assert(i != end(_removeFlag));
_removeFlag.erase(i);
refresh();
_flagRemoved.fire_copy(flag);
}
void FilterChatsPreview::removePeer(not_null<History*> history) {
const auto i = ranges::find(_removePeer, history, &PeerButton::history);
Assert(i != end(_removePeer));
_removePeer.erase(i);
refresh();
_peerRemoved.fire_copy(history);
}
rpl::producer<Flag> FilterChatsPreview::flagRemoved() const {
return _flagRemoved.events();
}
rpl::producer<not_null<History*>> FilterChatsPreview::peerRemoved() const {
return _peerRemoved.events();
}
@@ -0,0 +1,64 @@
/*
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 "data/data_chat_filters.h"
#include "ui/rp_widget.h"
#include "ui/userpic_view.h"
class History;
namespace Ui {
class IconButton;
} // namespace Ui
class FilterChatsPreview final : public Ui::RpWidget {
public:
using Flag = Data::ChatFilter::Flag;
using Flags = Data::ChatFilter::Flags;
FilterChatsPreview(
not_null<QWidget*> parent,
Flags flags,
const base::flat_set<not_null<History*>> &peers);
[[nodiscard]] rpl::producer<Flag> flagRemoved() const;
[[nodiscard]] rpl::producer<not_null<History*>> peerRemoved() const;
void updateData(
Flags flags,
const base::flat_set<not_null<History*>> &peers);
int resizeGetHeight(int newWidth) override;
private:
using Button = base::unique_qptr<Ui::IconButton>;
struct FlagButton {
Flag flag = Flag();
Button button;
};
struct PeerButton {
not_null<History*> history;
Ui::PeerUserpicView userpic;
Ui::Text::String name;
Button button;
};
void paintEvent(QPaintEvent *e) override;
void refresh();
void removeFlag(Flag flag);
void removePeer(not_null<History*> history);
std::vector<FlagButton> _removeFlag;
std::vector<PeerButton> _removePeer;
rpl::event_stream<Flag> _flagRemoved;
rpl::event_stream<not_null<History*>> _peerRemoved;
};
@@ -982,8 +982,7 @@ bool GoodForExportFilterLink(
not_null<Window::SessionController*> window,
const Data::ChatFilter &filter) {
using Flag = Data::ChatFilter::Flag;
const auto listflags = Flag::Chatlist | Flag::HasMyLinks;
if (!filter.never().empty() || (filter.flags() & ~listflags)) {
if (!filter.never().empty() || (filter.flags() & Flag::RulesMask)) {
window->showToast(tr::lng_filters_link_cant(tr::now));
return false;
}
@@ -386,7 +386,7 @@ void GiftBox(
state->buttonText.events(),
Ui::Premium::GiftGradientStops(),
[=] {
const auto value = group->value();
const auto value = group->current();
return (value < options.size() && value >= 0)
? options[value].botUrl
: QString();
@@ -587,7 +587,7 @@ void GiftsBox(
const auto content = box->addRow(
object_ptr<Ui::VerticalLayout>(box),
{});
auto buttonCallback = [=](PremiumPreview section) {
auto buttonCallback = [=](PremiumFeature section) {
stars->setPaused(true);
const auto previewBoxShown = [=](
not_null<Ui::BoxContent*> previewBox) {
@@ -665,7 +665,7 @@ void GiftsBox(
}
auto invoice = api->invoice(
users.size(),
api->monthsFromPreset(group->value()));
api->monthsFromPreset(group->current()));
invoice.purpose = Payments::InvoicePremiumGiftCodeUsers{ users };
state->confirmButtonBusy = true;
+1 -1
View File
@@ -1216,7 +1216,7 @@ void LanguageBox::setupTop(not_null<Ui::VerticalLayout*> container) {
if (checked && !premium) {
ShowPremiumPreviewToBuy(
_controller,
PremiumPreview::RealTimeTranslation);
PremiumFeature::RealTimeTranslation);
_translateChatTurnOff.fire(false);
}
return premium
@@ -260,11 +260,11 @@ void Controller::choose(not_null<ChatData*> chat) {
const auto init = [=](not_null<ListBox*> box) {
auto above = object_ptr<Ui::VerticalLayout>(box);
Settings::AddDividerTextWithLottie(
above,
box->showFinishes(),
About(channel, chat),
u"discussion"_q);
Settings::AddDividerTextWithLottie(above, {
.lottie = u"discussion"_q,
.showFinished = box->showFinishes(),
.about = About(channel, chat),
});
if (!chat) {
Assert(channel->isBroadcast());
@@ -216,6 +216,9 @@ ChatAdminRightsInfo EditAdminBox::defaultRights() const {
: peer()->isMegagroup()
? ChatAdminRightsInfo{ (Flag::ChangeInfo
| Flag::DeleteMessages
| Flag::PostStories
| Flag::EditStories
| Flag::DeleteStories
| Flag::BanUsers
| Flag::InviteByLinkOrAdd
| Flag::ManageTopics
@@ -225,6 +228,9 @@ ChatAdminRightsInfo EditAdminBox::defaultRights() const {
| Flag::PostMessages
| Flag::EditMessages
| Flag::DeleteMessages
| Flag::PostStories
| Flag::EditStories
| Flag::DeleteStories
| Flag::InviteByLinkOrAdd
| Flag::ManageCall) };
}
@@ -840,7 +846,7 @@ void EditRestrictedBox::createUntilGroup() {
void EditRestrictedBox::createUntilVariants() {
auto addVariant = [&](int value, const QString &text) {
if (!canSave() && _untilGroup->value() != value) {
if (!canSave() && _untilGroup->current() != value) {
return;
}
_untilVariants.emplace_back(
@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/background_box.h"
#include "boxes/stickers_box.h"
#include "chat_helpers/compose/compose_show.h"
#include "core/ui_integration.h" // Core::MarkedTextContext.
#include "data/stickers/data_custom_emoji.h"
#include "data/stickers/data_stickers.h"
#include "data/data_changes.h"
@@ -23,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_emoji_statuses.h"
#include "data/data_file_origin.h"
#include "data/data_peer.h"
#include "data/data_premium_limits.h"
#include "data/data_session.h"
#include "data/data_web_page.h"
#include "history/view/history_view_element.h"
@@ -34,8 +36,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "lottie/lottie_icon.h"
#include "lottie/lottie_single_player.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
#include "settings/settings_common.h"
#include "settings/settings_premium.h"
@@ -43,10 +43,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/chat_style.h"
#include "ui/chat/chat_theme.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/effects/premium_graphics.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/buttons.h"
#include "ui/painter.h"
#include "ui/rect.h"
#include "ui/vertical_list.h"
#include "window/themes/window_theme.h"
#include "window/section_widget.h"
@@ -146,6 +148,28 @@ private:
};
class LevelBadge final : public Ui::RpWidget {
public:
LevelBadge(
not_null<QWidget*> parent,
uint32 level,
not_null<Main::Session*> session);
void setMinimal(bool value);
private:
void paintEvent(QPaintEvent *e) override;
void updateText();
const uint32 _level;
const TextWithEntities _icon;
const Core::MarkedTextContext _context;
Ui::Text::String _text;
bool _minimal = false;
};
ColorSample::ColorSample(
not_null<QWidget*> parent,
std::shared_ptr<Ui::ChatStyle> style,
@@ -295,47 +319,36 @@ PreviewWrap::PreviewWrap(
, _delegate(std::make_unique<PreviewDelegate>(box, _style.get(), [=] {
update();
}))
, _replyToItem(_history->addNewLocalMessage(
_history->nextNonHistoryEntryId(),
(MessageFlag::FakeHistoryItem
, _replyToItem(_history->addNewLocalMessage({
.id = _history->nextNonHistoryEntryId(),
.flags = (MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| MessageFlag::Post),
UserId(), // via
FullReplyTo(),
base::unixtime::now(), // date
_fake->id,
QString(), // postAuthor
TextWithEntities{ _peer->isSelf()
? tr::lng_settings_color_reply(tr::now)
: tr::lng_settings_color_reply_channel(tr::now),
},
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
uint64(0)))
, _replyItem(_history->addNewLocalMessage(
_history->nextNonHistoryEntryId(),
(MessageFlag::FakeHistoryItem
.from = _fake->id,
.date = base::unixtime::now(),
}, TextWithEntities{ _peer->isSelf()
? tr::lng_settings_color_reply(tr::now)
: tr::lng_settings_color_reply_channel(tr::now),
}, MTP_messageMediaEmpty()))
, _replyItem(_history->addNewLocalMessage({
.id = _history->nextNonHistoryEntryId(),
.flags = (MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| MessageFlag::HasReplyInfo
| MessageFlag::Post),
UserId(), // via
FullReplyTo{ .messageId = _replyToItem->fullId() },
base::unixtime::now(), // date
_fake->id,
QString(), // postAuthor
TextWithEntities{ _peer->isSelf()
? tr::lng_settings_color_text(tr::now)
: tr::lng_settings_color_text_channel(tr::now),
},
MTP_messageMediaWebPage(
.from = _fake->id,
.replyTo = FullReplyTo{.messageId = _replyToItem->fullId() },
.date = base::unixtime::now(),
}, TextWithEntities{ _peer->isSelf()
? tr::lng_settings_color_text(tr::now)
: tr::lng_settings_color_text_channel(tr::now),
}, MTP_messageMediaWebPage(
MTP_flags(0),
MTP_webPagePending(
MTP_flags(0),
MTP_webPagePending(
MTP_flags(0),
MTP_long(_webpage->id),
MTPstring(),
MTP_int(0))),
HistoryMessageMarkupData(),
uint64(0)))
MTP_long(_webpage->id),
MTPstring(),
MTP_int(0)))))
, _element(_replyItem->createView(_delegate.get()))
, _position(0, st::msgMargin.bottom()) {
_style->apply(_theme.get());
@@ -437,6 +450,108 @@ HistoryView::Context PreviewDelegate::elementContext() {
return HistoryView::Context::AdminLog;
}
LevelBadge::LevelBadge(
not_null<QWidget*> parent,
uint32 level,
not_null<Main::Session*> session)
: Ui::RpWidget(parent)
, _level(level)
, _icon(Ui::Text::SingleCustomEmoji(
session->data().customEmojiManager().registerInternalEmoji(
st::settingsLevelBadgeLock,
QMargins(0, st::settingsLevelBadgeLockSkip, 0, 0),
false)))
, _context({ .session = session }) {
updateText();
}
void LevelBadge::updateText() {
auto text = _icon;
text.append(' ');
if (!_minimal) {
text.append(tr::lng_boost_level(
tr::now,
lt_count,
_level,
Ui::Text::WithEntities));
} else {
text.append(QString::number(_level));
}
const auto &st = st::settingsPremiumNewBadge.style;
_text.setMarkedText(
st,
text,
kMarkupTextOptions,
_context);
const auto &padding = st::settingsColorSamplePadding;
QWidget::resize(
_text.maxWidth() + rect::m::sum::h(padding),
st.font->height + rect::m::sum::v(padding));
}
void LevelBadge::setMinimal(bool value) {
if ((value != _minimal) && value) {
_minimal = value;
updateText();
update();
}
}
void LevelBadge::paintEvent(QPaintEvent *e) {
auto p = QPainter(this);
auto hq = PainterHighQualityEnabler(p);
const auto radius = height() / 2;
p.setPen(Qt::NoPen);
auto gradient = QLinearGradient(QPointF(0, 0), QPointF(width(), 0));
gradient.setStops(Ui::Premium::ButtonGradientStops());
p.setBrush(gradient);
p.drawRoundedRect(rect(), radius, radius);
p.setPen(st::premiumButtonFg);
p.setBrush(Qt::NoBrush);
const auto context = Ui::Text::PaintContext{
.position = rect::m::pos::tl(st::settingsColorSamplePadding),
.outerWidth = width(),
.availableWidth = width(),
};
_text.draw(p, context);
}
void AddLevelBadge(
int level,
not_null<Ui::SettingsButton*> button,
Ui::RpWidget *right,
not_null<ChannelData*> channel,
const QMargins &padding,
rpl::producer<QString> text) {
if (channel->levelHint() >= level) {
return;
}
const auto badge = Ui::CreateChild<LevelBadge>(
button.get(),
level,
&channel->session());
badge->show();
const auto sampleLeft = st::settingsColorSamplePadding.left();
const auto badgeLeft = padding.left() + sampleLeft;
rpl::combine(
button->sizeValue(),
std::move(text)
) | rpl::start_with_next([=](const QSize &s, const QString &) {
if (s.isNull()) {
return;
}
badge->moveToLeft(
button->fullTextWidth() + badgeLeft,
(s.height() - badge->height()) / 2);
const auto rightEdge = right ? right->pos().x() : button->width();
badge->setMinimal((rect::right(badge) + sampleLeft) > rightEdge);
badge->setVisible((rect::right(badge) + sampleLeft) < rightEdge);
}, badge->lifetime());
}
struct SetValues {
uint8 colorIndex = 0;
DocumentId backgroundEmojiId = 0;
@@ -541,16 +656,13 @@ void Apply(
: peerColors->requiredChannelLevelFor(
peer->id,
values.colorIndex);
const auto limits = Data::LevelLimits(&peer->session());
const auto iconRequired = values.backgroundEmojiId
? session->account().appConfig().get<int>(
"channel_bg_icon_level_min",
5)
? limits.channelBgIconLevelMin()
: 0;
const auto statusRequired = (values.statusChanged
&& values.statusId)
? session->account().appConfig().get<int>(
"channel_emoji_status_level_min",
8)
? limits.channelEmojiStatusLevelMin()
: 0;
const auto required = std::max({
colorRequired,
@@ -726,6 +838,7 @@ struct ButtonWithEmoji {
not_null<Ui::RpWidget*> parent,
std::shared_ptr<ChatHelpers::Show> show,
std::shared_ptr<Ui::ChatStyle> style,
not_null<PeerData*> peer,
rpl::producer<uint8> colorIndexValue,
rpl::producer<DocumentId> emojiIdValue,
Fn<void(DocumentId)> emojiIdChosen) {
@@ -827,21 +940,33 @@ struct ButtonWithEmoji {
}
});
if (const auto channel = peer->asChannel()) {
AddLevelBadge(
Data::LevelLimits(&channel->session()).channelBgIconLevelMin(),
raw,
right,
channel,
button.st->padding,
tr::lng_settings_color_emoji());
}
return result;
}
[[nodiscard]] object_ptr<Ui::SettingsButton> CreateEmojiStatusButton(
not_null<Ui::RpWidget*> parent,
std::shared_ptr<ChatHelpers::Show> show,
not_null<ChannelData*> channel,
rpl::producer<DocumentId> statusIdValue,
Fn<void(DocumentId,TimeId)> statusIdChosen,
bool group) {
const auto button = ButtonStyleWithRightEmoji(parent);
const auto &phrase = group
? tr::lng_edit_channel_status_group
: tr::lng_edit_channel_status;
auto result = Settings::CreateButtonWithIcon(
parent,
(group
? tr::lng_edit_channel_status_group()
: tr::lng_edit_channel_status()),
phrase(),
*button.st,
{ &st::menuBlueIconEmojiStatus });
const auto raw = result.data();
@@ -926,6 +1051,17 @@ struct ButtonWithEmoji {
}
});
const auto limits = Data::LevelLimits(&channel->session());
AddLevelBadge(
(group
? limits.groupEmojiStatusLevelMin()
: limits.channelEmojiStatusLevelMin()),
raw,
right,
channel,
button.st->padding,
phrase());
return result;
}
@@ -1036,6 +1172,14 @@ struct ButtonWithEmoji {
}
}, right->lifetime());
AddLevelBadge(
Data::LevelLimits(&channel->session()).groupEmojiStickersLevelMin(),
raw,
right,
channel,
button.st->padding,
tr::lng_group_emoji());
return result;
}
@@ -1068,38 +1212,15 @@ void EditPeerColorBox(
state->index = peer->colorIndex();
state->emojiId = peer->backgroundEmojiId();
state->statusId = peer->emojiStatusId();
if (group) {
const auto divider = Ui::CreateChild<Ui::BoxContentDivider>(
box.get());
const auto verticalLayout = box->verticalLayout()->add(
object_ptr<Ui::VerticalLayout>(box.get()));
auto icon = CreateLottieIcon(
verticalLayout,
{
.name = u"palette"_q,
.sizeOverride = {
st::settingsCloudPasswordIconSize,
st::settingsCloudPasswordIconSize,
},
},
st::peerAppearanceIconPadding);
box->setShowFinishedCallback([animate = std::move(icon.animate)] {
animate(anim::repeat::once);
Settings::AddDividerTextWithLottie(box->verticalLayout(), {
.lottie = u"palette"_q,
.lottieSize = st::settingsCloudPasswordIconSize,
.lottieMargins = st::peerAppearanceIconPadding,
.showFinished = box->showFinishes(),
.about = tr::lng_boost_group_about(Ui::Text::WithEntities),
.aboutMargins = st::peerAppearanceCoverLabelMargin,
});
verticalLayout->add(std::move(icon.widget));
verticalLayout->add(
object_ptr<Ui::FlatLabel>(
verticalLayout,
tr::lng_boost_group_about(),
st::peerAppearanceCoverLabel),
st::peerAppearanceCoverLabelMargin);
verticalLayout->geometryValue(
) | rpl::start_with_next([=](const QRect &r) {
divider->setGeometry(r);
}, divider->lifetime());
} else {
box->addRow(object_ptr<PreviewWrap>(
box,
@@ -1135,6 +1256,7 @@ void EditPeerColorBox(
container,
show,
style,
peer,
state->index.value(),
state->emojiId.value(),
[=](DocumentId id) { state->emojiId = id; }));
@@ -1150,20 +1272,35 @@ void EditPeerColorBox(
if (const auto channel = peer->asChannel()) {
Ui::AddSkip(container, st::settingsColorSampleSkip);
Settings::AddButtonWithIcon(
const auto &phrase = group
? tr::lng_edit_channel_wallpaper_group
: tr::lng_edit_channel_wallpaper;
const auto button = Settings::AddButtonWithIcon(
container,
(group
? tr::lng_edit_channel_wallpaper_group()
: tr::lng_edit_channel_wallpaper()),
phrase(),
st::peerAppearanceButton,
{ &st::menuBlueIconWallpaper }
)->setClickedCallback([=] {
);
button->setClickedCallback([=] {
const auto usage = ChatHelpers::WindowUsage::PremiumPromo;
if (const auto strong = show->resolveWindow(usage)) {
show->show(Box<BackgroundBox>(strong, channel));
}
});
{
const auto limits = Data::LevelLimits(&channel->session());
AddLevelBadge(
group
? limits.groupCustomWallpaperLevelMin()
: limits.channelCustomWallpaperLevelMin(),
button,
nullptr,
channel,
st::peerAppearanceButton.padding,
phrase());
}
Ui::AddSkip(container, st::settingsColorSampleSkip);
Ui::AddDividerText(
container,
@@ -1201,6 +1338,7 @@ void EditPeerColorBox(
container->add(CreateEmojiStatusButton(
container,
show,
channel,
state->statusId.value(),
[=](DocumentId id, TimeId until) {
state->statusId = id;
@@ -25,7 +25,7 @@ void EditPeerHistoryVisibilityBox(
box->setTitle(tr::lng_manage_history_visibility_title());
box->addButton(tr::lng_settings_save(), [=] {
savedCallback(historyVisibility->value());
savedCallback(historyVisibility->current());
box->closeBox();
});
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
@@ -34,7 +34,7 @@ namespace {
constexpr auto kFirstPageCount = 16;
constexpr auto kPerPage = 200;
constexpr auto kServerSearchDelay = crl::time(1000);
constexpr auto kServerSearchDelay = crl::time(150);
constexpr auto kAcceptButton = 1;
constexpr auto kRejectButton = 2;
@@ -76,7 +76,7 @@ public:
}
[[nodiscard]] Privacy getPrivacy() const {
return _controls.privacy->value();
return _controls.privacy->current();
}
[[nodiscard]] bool noForwards() const {
@@ -238,7 +238,7 @@ void Controller::createContent() {
}, wrap->lifetime());
} else {
_controls.whoSendWrap->toggle(
(_controls.privacy->value() == Privacy::HasUsername),
(_controls.privacy->current() == Privacy::HasUsername),
anim::type::instant);
}
auto joinToWrite = _controls.joinToWrite
@@ -299,7 +299,7 @@ void Controller::createContent() {
if (_linkOnly) {
_controls.inviteLinkWrap->show(anim::type::instant);
} else {
if (_controls.privacy->value() == Privacy::NoUsername) {
if (_controls.privacy->current() == Privacy::NoUsername) {
checkUsernameAvailability();
}
const auto forShowing = _dataSavedValue
@@ -474,7 +474,7 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
&Ui::UsernameInput::changed,
[this] { usernameChanged(); });
const auto shown = (_controls.privacy->value() == Privacy::HasUsername);
const auto shown = (_controls.privacy->current() == Privacy::HasUsername);
result->toggle(shown, anim::type::instant);
return result;
@@ -539,7 +539,7 @@ void Controller::checkUsernameAvailability() {
if (!_controls.usernameInput) {
return;
}
const auto initial = (_controls.privacy->value() != Privacy::HasUsername);
const auto initial = (_controls.privacy->current() != Privacy::HasUsername);
const auto checking = initial
? u".bad."_q
: getUsernameInput();
@@ -573,11 +573,11 @@ void Controller::checkUsernameAvailability() {
_controls.privacy->setValue(Privacy::NoUsername);
} else if (type == u"CHANNELS_ADMIN_PUBLIC_TOO_MUCH"_q) {
_usernameState = UsernameState::TooMany;
if (_controls.privacy->value() == Privacy::HasUsername) {
if (_controls.privacy->current() == Privacy::HasUsername) {
askUsernameRevoke();
}
} else if (initial) {
if (_controls.privacy->value() == Privacy::HasUsername) {
if (_controls.privacy->current() == Privacy::HasUsername) {
showUsernameEmpty();
setFocusUsername();
}
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "base/event_filter.h"
#include "base/unixtime.h"
#include "data/data_premium_limits.h"
#include "boxes/peer_list_box.h"
#include "data/data_channel.h"
#include "data/data_cloud_themes.h"
@@ -424,14 +425,9 @@ Ui::BoostCounters ParseBoostCounters(
}
Ui::BoostFeatures LookupBoostFeatures(not_null<ChannelData*> channel) {
const auto group = channel->isMegagroup();
const auto appConfig = &channel->session().account().appConfig();
const auto get = [&](const QString &key, int fallback, bool ok = true) {
return ok ? appConfig->get<int>(key, fallback) : 0;
};
auto nameColorsByLevel = base::flat_map<int, int>();
auto linkStylesByLevel = base::flat_map<int, int>();
const auto group = channel->isMegagroup();
const auto peerColors = &channel->session().api().peerColors();
const auto &list = group
? peerColors->requiredLevelsGroup()
@@ -447,22 +443,23 @@ Ui::BoostFeatures LookupBoostFeatures(not_null<ChannelData*> channel) {
if (themes.empty()) {
channel->owner().cloudThemes().refreshChatThemes();
}
const auto levelLimits = Data::LevelLimits(&channel->session());
return Ui::BoostFeatures{
.nameColorsByLevel = std::move(nameColorsByLevel),
.linkStylesByLevel = std::move(linkStylesByLevel),
.linkLogoLevel = get(u"channel_bg_icon_level_min"_q, 4, !group),
.transcribeLevel = get(u"group_transcribe_level_min"_q, 6, group),
.emojiPackLevel = get(u"group_emoji_stickers_level_min"_q, 4, group),
.emojiStatusLevel = get(group
? u"group_emoji_status_level_min"_q
: u"channel_emoji_status_level_min"_q, 8),
.wallpaperLevel = get(group
? u"group_wallpaper_level_min"_q
: u"channel_wallpaper_level_min"_q, 9),
.linkLogoLevel = group ? 0 : levelLimits.channelBgIconLevelMin(),
.transcribeLevel = group ? levelLimits.groupTranscribeLevelMin() : 0,
.emojiPackLevel = group ? levelLimits.groupEmojiStickersLevelMin() : 0,
.emojiStatusLevel = group
? levelLimits.groupEmojiStatusLevelMin()
: levelLimits.channelEmojiStatusLevelMin(),
.wallpaperLevel = group
? levelLimits.groupWallpaperLevelMin()
: levelLimits.channelWallpaperLevelMin(),
.wallpapersCount = themes.empty() ? 8 : int(themes.size()),
.customWallpaperLevel = get(group
? u"channel_custom_wallpaper_level_min"_q
: u"group_custom_wallpaper_level_min"_q, 10),
.customWallpaperLevel = group
? levelLimits.groupCustomWallpaperLevelMin()
: levelLimits.channelCustomWallpaperLevelMin(),
};
}
@@ -1142,7 +1142,7 @@ void AccountsLimitBox(
const auto ref = QString();
const auto wasAccount = &session->account();
const auto nowAccount = accounts[group->value()];
const auto nowAccount = accounts[group->current()];
if (wasAccount == nowAccount) {
Settings::ShowPremium(session, ref);
return;
@@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/confirm_box.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
#include "settings/settings_business.h"
#include "settings/settings_premium.h"
#include "lottie/lottie_single_player.h"
#include "history/view/media/history_view_sticker.h"
@@ -59,7 +60,7 @@ constexpr auto kStarPeriod = 3 * crl::time(1000);
using Data::ReactionId;
struct Descriptor {
PremiumPreview section = PremiumPreview::Stickers;
PremiumFeature section = PremiumFeature::Stickers;
DocumentData *requestedSticker = nullptr;
bool fromSettings = false;
Fn<void()> hiddenCallback;
@@ -90,88 +91,118 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
media->videoThumbnailWanted(origin);
}
[[nodiscard]] rpl::producer<QString> SectionTitle(PremiumPreview section) {
[[nodiscard]] rpl::producer<QString> SectionTitle(PremiumFeature section) {
switch (section) {
case PremiumPreview::Wallpapers:
case PremiumFeature::Wallpapers:
return tr::lng_premium_summary_subtitle_wallpapers();
case PremiumPreview::Stories:
case PremiumFeature::Stories:
return tr::lng_premium_summary_subtitle_stories();
case PremiumPreview::DoubleLimits:
case PremiumFeature::DoubleLimits:
return tr::lng_premium_summary_subtitle_double_limits();
case PremiumPreview::MoreUpload:
case PremiumFeature::MoreUpload:
return tr::lng_premium_summary_subtitle_more_upload();
case PremiumPreview::FasterDownload:
case PremiumFeature::FasterDownload:
return tr::lng_premium_summary_subtitle_faster_download();
case PremiumPreview::VoiceToText:
case PremiumFeature::VoiceToText:
return tr::lng_premium_summary_subtitle_voice_to_text();
case PremiumPreview::NoAds:
case PremiumFeature::NoAds:
return tr::lng_premium_summary_subtitle_no_ads();
case PremiumPreview::EmojiStatus:
case PremiumFeature::EmojiStatus:
return tr::lng_premium_summary_subtitle_emoji_status();
case PremiumPreview::InfiniteReactions:
case PremiumFeature::InfiniteReactions:
return tr::lng_premium_summary_subtitle_infinite_reactions();
case PremiumPreview::TagsForMessages:
case PremiumFeature::TagsForMessages:
return tr::lng_premium_summary_subtitle_tags_for_messages();
case PremiumPreview::LastSeen:
case PremiumFeature::LastSeen:
return tr::lng_premium_summary_subtitle_last_seen();
case PremiumPreview::MessagePrivacy:
case PremiumFeature::MessagePrivacy:
return tr::lng_premium_summary_subtitle_message_privacy();
case PremiumPreview::Stickers:
case PremiumFeature::Stickers:
return tr::lng_premium_summary_subtitle_premium_stickers();
case PremiumPreview::AnimatedEmoji:
case PremiumFeature::AnimatedEmoji:
return tr::lng_premium_summary_subtitle_animated_emoji();
case PremiumPreview::AdvancedChatManagement:
case PremiumFeature::AdvancedChatManagement:
return tr::lng_premium_summary_subtitle_advanced_chat_management();
case PremiumPreview::ProfileBadge:
case PremiumFeature::ProfileBadge:
return tr::lng_premium_summary_subtitle_profile_badge();
case PremiumPreview::AnimatedUserpics:
case PremiumFeature::AnimatedUserpics:
return tr::lng_premium_summary_subtitle_animated_userpics();
case PremiumPreview::RealTimeTranslation:
case PremiumFeature::RealTimeTranslation:
return tr::lng_premium_summary_subtitle_translation();
case PremiumFeature::Business:
return tr::lng_premium_summary_subtitle_business();
case PremiumFeature::BusinessLocation:
return tr::lng_business_subtitle_location();
case PremiumFeature::BusinessHours:
return tr::lng_business_subtitle_opening_hours();
case PremiumFeature::QuickReplies:
return tr::lng_business_subtitle_quick_replies();
case PremiumFeature::GreetingMessage:
return tr::lng_business_subtitle_greeting_messages();
case PremiumFeature::AwayMessage:
return tr::lng_business_subtitle_away_messages();
case PremiumFeature::BusinessBots:
return tr::lng_business_subtitle_chatbots();
}
Unexpected("PremiumPreview in SectionTitle.");
Unexpected("PremiumFeature in SectionTitle.");
}
[[nodiscard]] rpl::producer<QString> SectionAbout(PremiumPreview section) {
[[nodiscard]] rpl::producer<QString> SectionAbout(PremiumFeature section) {
switch (section) {
case PremiumPreview::Wallpapers:
case PremiumFeature::Wallpapers:
return tr::lng_premium_summary_about_wallpapers();
case PremiumPreview::Stories:
case PremiumFeature::Stories:
return tr::lng_premium_summary_about_stories();
case PremiumPreview::DoubleLimits:
case PremiumFeature::DoubleLimits:
return tr::lng_premium_summary_about_double_limits();
case PremiumPreview::MoreUpload:
case PremiumFeature::MoreUpload:
return tr::lng_premium_summary_about_more_upload();
case PremiumPreview::FasterDownload:
case PremiumFeature::FasterDownload:
return tr::lng_premium_summary_about_faster_download();
case PremiumPreview::VoiceToText:
case PremiumFeature::VoiceToText:
return tr::lng_premium_summary_about_voice_to_text();
case PremiumPreview::NoAds:
case PremiumFeature::NoAds:
return tr::lng_premium_summary_about_no_ads();
case PremiumPreview::EmojiStatus:
case PremiumFeature::EmojiStatus:
return tr::lng_premium_summary_about_emoji_status();
case PremiumPreview::InfiniteReactions:
case PremiumFeature::InfiniteReactions:
return tr::lng_premium_summary_about_infinite_reactions();
case PremiumPreview::TagsForMessages:
case PremiumFeature::TagsForMessages:
return tr::lng_premium_summary_about_tags_for_messages();
case PremiumPreview::LastSeen:
case PremiumFeature::LastSeen:
return tr::lng_premium_summary_about_last_seen();
case PremiumPreview::MessagePrivacy:
case PremiumFeature::MessagePrivacy:
return tr::lng_premium_summary_about_message_privacy();
case PremiumPreview::Stickers:
case PremiumFeature::Stickers:
return tr::lng_premium_summary_about_premium_stickers();
case PremiumPreview::AnimatedEmoji:
case PremiumFeature::AnimatedEmoji:
return tr::lng_premium_summary_about_animated_emoji();
case PremiumPreview::AdvancedChatManagement:
case PremiumFeature::AdvancedChatManagement:
return tr::lng_premium_summary_about_advanced_chat_management();
case PremiumPreview::ProfileBadge:
case PremiumFeature::ProfileBadge:
return tr::lng_premium_summary_about_profile_badge();
case PremiumPreview::AnimatedUserpics:
case PremiumFeature::AnimatedUserpics:
return tr::lng_premium_summary_about_animated_userpics();
case PremiumPreview::RealTimeTranslation:
case PremiumFeature::RealTimeTranslation:
return tr::lng_premium_summary_about_translation();
case PremiumFeature::Business:
return tr::lng_premium_summary_about_business();
case PremiumFeature::BusinessLocation:
return tr::lng_business_about_location();
case PremiumFeature::BusinessHours:
return tr::lng_business_about_opening_hours();
case PremiumFeature::QuickReplies:
return tr::lng_business_about_quick_replies();
case PremiumFeature::GreetingMessage:
return tr::lng_business_about_greeting_messages();
case PremiumFeature::AwayMessage:
return tr::lng_business_about_away_messages();
case PremiumFeature::BusinessBots:
return tr::lng_business_about_chatbots();
}
Unexpected("PremiumPreview in SectionTitle.");
Unexpected("PremiumFeature in SectionTitle.");
}
[[nodiscard]] object_ptr<Ui::RpWidget> ChatBackPreview(
@@ -463,33 +494,40 @@ struct VideoPreviewDocument {
RectPart align = RectPart::Bottom;
};
[[nodiscard]] bool VideoAlignToTop(PremiumPreview section) {
return (section == PremiumPreview::MoreUpload)
|| (section == PremiumPreview::NoAds)
|| (section == PremiumPreview::AnimatedEmoji);
[[nodiscard]] bool VideoAlignToTop(PremiumFeature section) {
return (section == PremiumFeature::MoreUpload)
|| (section == PremiumFeature::NoAds)
|| (section == PremiumFeature::AnimatedEmoji);
}
[[nodiscard]] DocumentData *LookupVideo(
not_null<Main::Session*> session,
PremiumPreview section) {
PremiumFeature section) {
const auto name = [&] {
switch (section) {
case PremiumPreview::MoreUpload: return "more_upload";
case PremiumPreview::FasterDownload: return "faster_download";
case PremiumPreview::VoiceToText: return "voice_to_text";
case PremiumPreview::NoAds: return "no_ads";
case PremiumPreview::AnimatedEmoji: return "animated_emoji";
case PremiumPreview::AdvancedChatManagement:
case PremiumFeature::MoreUpload: return "more_upload";
case PremiumFeature::FasterDownload: return "faster_download";
case PremiumFeature::VoiceToText: return "voice_to_text";
case PremiumFeature::NoAds: return "no_ads";
case PremiumFeature::AnimatedEmoji: return "animated_emoji";
case PremiumFeature::AdvancedChatManagement:
return "advanced_chat_management";
case PremiumPreview::EmojiStatus: return "emoji_status";
case PremiumPreview::InfiniteReactions: return "infinite_reactions";
case PremiumPreview::TagsForMessages: return "saved_tags";
case PremiumPreview::ProfileBadge: return "profile_badge";
case PremiumPreview::AnimatedUserpics: return "animated_userpics";
case PremiumPreview::RealTimeTranslation: return "translations";
case PremiumPreview::Wallpapers: return "wallpapers";
case PremiumPreview::LastSeen: return "last_seen";
case PremiumPreview::MessagePrivacy: return "message_privacy";
case PremiumFeature::EmojiStatus: return "emoji_status";
case PremiumFeature::InfiniteReactions: return "infinite_reactions";
case PremiumFeature::TagsForMessages: return "saved_tags";
case PremiumFeature::ProfileBadge: return "profile_badge";
case PremiumFeature::AnimatedUserpics: return "animated_userpics";
case PremiumFeature::RealTimeTranslation: return "translations";
case PremiumFeature::Wallpapers: return "wallpapers";
case PremiumFeature::LastSeen: return "last_seen";
case PremiumFeature::MessagePrivacy: return "message_privacy";
case PremiumFeature::BusinessLocation: return "business_location";
case PremiumFeature::BusinessHours: return "business_hours";
case PremiumFeature::QuickReplies: return "quick_replies";
case PremiumFeature::GreetingMessage: return "greeting_message";
case PremiumFeature::AwayMessage: return "away_message";
case PremiumFeature::BusinessBots: return "business_bots";
}
return "";
}();
@@ -716,7 +754,7 @@ struct VideoPreviewDocument {
[[nodiscard]] not_null<Ui::RpWidget*> GenericPreview(
not_null<Ui::RpWidget*> parent,
std::shared_ptr<ChatHelpers::Show> show,
PremiumPreview section,
PremiumFeature section,
Fn<void()> readyCallback) {
const auto result = Ui::CreateChild<Ui::RpWidget>(parent.get());
result->show();
@@ -757,10 +795,10 @@ struct VideoPreviewDocument {
[[nodiscard]] not_null<Ui::RpWidget*> GenerateDefaultPreview(
not_null<Ui::RpWidget*> parent,
std::shared_ptr<ChatHelpers::Show> show,
PremiumPreview section,
PremiumFeature section,
Fn<void()> readyCallback) {
switch (section) {
case PremiumPreview::Stickers:
case PremiumFeature::Stickers:
return StickersPreview(parent, std::move(show), readyCallback);
default:
return GenericPreview(
@@ -784,8 +822,8 @@ struct VideoPreviewDocument {
[[nodiscard]] object_ptr<Ui::RpWidget> CreateSwitch(
not_null<Ui::RpWidget*> parent,
not_null<rpl::variable<PremiumPreview>*> selected,
std::vector<PremiumPreview> order) {
not_null<rpl::variable<PremiumFeature>*> selected,
std::vector<PremiumFeature> order) {
const auto padding = st::premiumDotPadding;
const auto width = padding.left() + st::premiumDot + padding.right();
const auto height = padding.top() + st::premiumDot + padding.bottom();
@@ -856,14 +894,20 @@ void PreviewBox(
Ui::Animations::Simple animation;
Fn<void()> preload;
std::vector<Hiding> hiding;
rpl::variable<PremiumPreview> selected;
std::vector<PremiumPreview> order;
rpl::variable<PremiumFeature> selected;
std::vector<PremiumFeature> order;
};
const auto state = outer->lifetime().make_state<State>();
state->selected = descriptor.section;
state->order = Settings::PremiumPreviewOrder(&show->session());
auto premiumOrder = Settings::PremiumFeaturesOrder(&show->session());
auto businessOrder = Settings::BusinessFeaturesOrder(&show->session());
state->order = ranges::contains(businessOrder, descriptor.section)
? std::move(businessOrder)
: ranges::contains(businessOrder, descriptor.section)
? std::move(premiumOrder)
: std::vector{ descriptor.section };
const auto index = [=](PremiumPreview section) {
const auto index = [=](PremiumFeature section) {
const auto it = ranges::find(state->order, section);
return (it == end(state->order))
? 0
@@ -906,7 +950,7 @@ void PreviewBox(
return;
}
const auto now = state->selected.current();
if (now != PremiumPreview::Stickers && !state->stickersPreload) {
if (now != PremiumFeature::Stickers && !state->stickersPreload) {
const auto ready = [=] {
if (state->stickersPreload) {
state->stickersPreloadReady = true;
@@ -917,14 +961,14 @@ void PreviewBox(
state->stickersPreload = GenerateDefaultPreview(
outer,
show,
PremiumPreview::Stickers,
PremiumFeature::Stickers,
ready);
state->stickersPreload->hide();
}
};
switch (descriptor.section) {
case PremiumPreview::Stickers:
case PremiumFeature::Stickers:
state->content = media
? StickerPreview(outer, show, media, state->preload)
: StickersPreview(outer, show, state->preload);
@@ -940,7 +984,7 @@ void PreviewBox(
state->selected.value(
) | rpl::combine_previous(
) | rpl::start_with_next([=](PremiumPreview was, PremiumPreview now) {
) | rpl::start_with_next([=](PremiumFeature was, PremiumFeature now) {
const auto animationCallback = [=] {
if (!state->animation.animating()) {
for (const auto &hiding : base::take(state->hiding)) {
@@ -982,7 +1026,7 @@ void PreviewBox(
.leftTill = state->content->x() - start,
});
state->leftFrom = start;
if (now == PremiumPreview::Stickers && state->stickersPreload) {
if (now == PremiumFeature::Stickers && state->stickersPreload) {
state->content = base::take(state->stickersPreload);
state->content->show();
if (base::take(state->stickersPreloadReady)) {
@@ -1053,14 +1097,14 @@ void PreviewBox(
return Settings::LookupPremiumRef(state->selected.current());
};
auto unlock = state->selected.value(
) | rpl::map([=](PremiumPreview section) {
return (section == PremiumPreview::InfiniteReactions)
) | rpl::map([=](PremiumFeature section) {
return (section == PremiumFeature::InfiniteReactions)
? tr::lng_premium_unlock_reactions()
: (section == PremiumPreview::Stickers)
: (section == PremiumFeature::Stickers)
? tr::lng_premium_unlock_stickers()
: (section == PremiumPreview::AnimatedEmoji)
: (section == PremiumFeature::AnimatedEmoji)
? tr::lng_premium_unlock_emoji()
: (section == PremiumPreview::EmojiStatus)
: (section == PremiumFeature::EmojiStatus)
? tr::lng_premium_unlock_status()
: tr::lng_premium_more_about();
}) | rpl::flatten_latest();
@@ -1207,18 +1251,25 @@ void Show(
descriptor.shownCallback(raw);
}
return;
} else if (descriptor.section == PremiumPreview::DoubleLimits) {
} else if (descriptor.section == PremiumFeature::DoubleLimits) {
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
DoubledLimitsPreviewBox(box, &show->session());
DecorateListPromoBox(box, show, descriptor);
}));
return;
} else if (descriptor.section == PremiumPreview::Stories) {
} else if (descriptor.section == PremiumFeature::Stories) {
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
UpgradedStoriesPreviewBox(box, &show->session());
DecorateListPromoBox(box, show, descriptor);
}));
return;
} else if (descriptor.section == PremiumFeature::Business) {
const auto window = show->resolveWindow(
ChatHelpers::WindowUsage::PremiumPromo);
if (window) {
Settings::ShowBusiness(window);
}
return;
}
auto &list = Preloads();
for (auto i = begin(list); i != end(list);) {
@@ -1286,21 +1337,21 @@ void ShowStickerPreviewBox(
std::shared_ptr<ChatHelpers::Show> show,
not_null<DocumentData*> document) {
Show(std::move(show), Descriptor{
.section = PremiumPreview::Stickers,
.section = PremiumFeature::Stickers,
.requestedSticker = document,
});
}
void ShowPremiumPreviewBox(
not_null<Window::SessionController*> controller,
PremiumPreview section,
PremiumFeature section,
Fn<void(not_null<Ui::BoxContent*>)> shown) {
ShowPremiumPreviewBox(controller->uiShow(), section, std::move(shown));
}
void ShowPremiumPreviewBox(
std::shared_ptr<ChatHelpers::Show> show,
PremiumPreview section,
PremiumFeature section,
Fn<void(not_null<Ui::BoxContent*>)> shown,
bool hideSubscriptionButton) {
Show(std::move(show), Descriptor{
@@ -1312,7 +1363,7 @@ void ShowPremiumPreviewBox(
void ShowPremiumPreviewToBuy(
not_null<Window::SessionController*> controller,
PremiumPreview section,
PremiumFeature section,
Fn<void()> hiddenCallback) {
Show(controller->uiShow(), Descriptor{
.section = section,

Some files were not shown because too many files have changed in this diff Show More