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
2
.github/workflows/mac.yml
vendored
|
@ -64,7 +64,7 @@ jobs:
|
||||||
- name: First set up.
|
- name: First set up.
|
||||||
run: |
|
run: |
|
||||||
sudo chown -R `whoami`:admin /usr/local/share
|
sudo chown -R `whoami`:admin /usr/local/share
|
||||||
brew install automake ninja pkg-config
|
brew install automake ninja pkg-config nasm meson
|
||||||
|
|
||||||
# Disable spotlight.
|
# Disable spotlight.
|
||||||
sudo mdutil -a -i off
|
sudo mdutil -a -i off
|
||||||
|
|
3
.gitmodules
vendored
|
@ -100,3 +100,6 @@
|
||||||
[submodule "Telegram/ThirdParty/libprisma"]
|
[submodule "Telegram/ThirdParty/libprisma"]
|
||||||
path = Telegram/ThirdParty/libprisma
|
path = Telegram/ThirdParty/libprisma
|
||||||
url = https://github.com/desktop-app/libprisma.git
|
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
|
||||||
|
|
|
@ -248,6 +248,8 @@ PRIVATE
|
||||||
boxes/filters/edit_filter_box.h
|
boxes/filters/edit_filter_box.h
|
||||||
boxes/filters/edit_filter_chats_list.cpp
|
boxes/filters/edit_filter_chats_list.cpp
|
||||||
boxes/filters/edit_filter_chats_list.h
|
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.cpp
|
||||||
boxes/filters/edit_filter_links.h
|
boxes/filters/edit_filter_links.h
|
||||||
boxes/peers/add_bot_to_chat_box.cpp
|
boxes/peers/add_bot_to_chat_box.cpp
|
||||||
|
@ -514,6 +516,14 @@ PRIVATE
|
||||||
core/version.h
|
core/version.h
|
||||||
countries/countries_manager.cpp
|
countries/countries_manager.cpp
|
||||||
countries/countries_manager.h
|
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.cpp
|
||||||
data/notify/data_notify_settings.h
|
data/notify/data_notify_settings.h
|
||||||
data/notify/data_peer_notify_settings.cpp
|
data/notify/data_peer_notify_settings.cpp
|
||||||
|
@ -1345,6 +1355,22 @@ PRIVATE
|
||||||
profile/profile_block_widget.h
|
profile/profile_block_widget.h
|
||||||
profile/profile_cover_drop_area.cpp
|
profile/profile_cover_drop_area.cpp
|
||||||
profile/profile_cover_drop_area.h
|
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.cpp
|
||||||
settings/cloud_password/settings_cloud_password_common.h
|
settings/cloud_password/settings_cloud_password_common.h
|
||||||
settings/cloud_password/settings_cloud_password_email.cpp
|
settings/cloud_password/settings_cloud_password_email.cpp
|
||||||
|
@ -1363,6 +1389,8 @@ PRIVATE
|
||||||
settings/settings_advanced.h
|
settings/settings_advanced.h
|
||||||
settings/settings_blocked_peers.cpp
|
settings/settings_blocked_peers.cpp
|
||||||
settings/settings_blocked_peers.h
|
settings/settings_blocked_peers.h
|
||||||
|
settings/settings_business.cpp
|
||||||
|
settings/settings_business.h
|
||||||
settings/settings_chat.cpp
|
settings/settings_chat.cpp
|
||||||
settings/settings_chat.h
|
settings/settings_chat.h
|
||||||
settings/settings_calls.cpp
|
settings/settings_calls.cpp
|
||||||
|
@ -1722,7 +1750,7 @@ else()
|
||||||
)
|
)
|
||||||
|
|
||||||
include(${cmake_helpers_loc}/external/glib/generate_dbus.cmake)
|
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)
|
if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION)
|
||||||
target_link_libraries(Telegram
|
target_link_libraries(Telegram
|
||||||
|
@ -1796,6 +1824,7 @@ set_target_properties(Telegram PROPERTIES
|
||||||
XCODE_ATTRIBUTE_ALWAYS_SEARCH_USER_PATHS NO
|
XCODE_ATTRIBUTE_ALWAYS_SEARCH_USER_PATHS NO
|
||||||
XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY libc++
|
XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY libc++
|
||||||
XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS --deep
|
XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS --deep
|
||||||
|
XCODE_ATTRIBUTE_CLANG_DEBUG_INFORMATION_LEVEL $<IF:$<CONFIG:Debug>,default,line-tables-only>
|
||||||
)
|
)
|
||||||
set(entitlement_sources
|
set(entitlement_sources
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Telegram.entitlements"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Telegram.entitlements"
|
||||||
|
|
BIN
Telegram/Resources/animations/greeting.tgs
Normal file
BIN
Telegram/Resources/animations/hours.tgs
Normal file
BIN
Telegram/Resources/animations/location.tgs
Normal file
BIN
Telegram/Resources/animations/phone.tgs
Normal file
BIN
Telegram/Resources/animations/robot.tgs
Normal file
BIN
Telegram/Resources/animations/sleep.tgs
Normal file
BIN
Telegram/Resources/animations/writing.tgs
Normal file
BIN
Telegram/Resources/art/business_logo.png
Normal file
After Width: | Height: | Size: 47 KiB |
|
@ -559,3 +559,26 @@ div.toast_shown {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
user-select: none;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ShowTextCopied(content) {
|
||||||
|
navigator.clipboard.writeText(content);
|
||||||
|
ShowToast("Text copied to clipboard.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function ShowSpoiler(target) {
|
function ShowSpoiler(target) {
|
||||||
if (target.classList.contains("hidden")) {
|
if (target.classList.contains("hidden")) {
|
||||||
target.classList.toggle("hidden");
|
target.classList.toggle("hidden");
|
||||||
|
|
BIN
Telegram/Resources/icons/chat/large_away.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
Telegram/Resources/icons/chat/large_away@2x.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
Telegram/Resources/icons/chat/large_away@3x.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
Telegram/Resources/icons/chat/large_greeting.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
Telegram/Resources/icons/chat/large_greeting@2x.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
Telegram/Resources/icons/chat/large_greeting@3x.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
Telegram/Resources/icons/chat/large_quickreply.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
Telegram/Resources/icons/chat/large_quickreply@2x.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
Telegram/Resources/icons/chat/large_quickreply@3x.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
Telegram/Resources/icons/folders/folder_existing_chats.png
Normal file
After Width: | Height: | Size: 592 B |
BIN
Telegram/Resources/icons/folders/folder_existing_chats@2x.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/folders/folder_existing_chats@3x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/folders/folder_new_chats.png
Normal file
After Width: | Height: | Size: 598 B |
BIN
Telegram/Resources/icons/folders/folder_new_chats@2x.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/folders/folder_new_chats@3x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/menu/shop.png
Normal file
After Width: | Height: | Size: 687 B |
BIN
Telegram/Resources/icons/menu/shop@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/menu/shop@3x.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 662 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 499 B |
After Width: | Height: | Size: 928 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 426 B |
After Width: | Height: | Size: 765 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 454 B |
After Width: | Height: | Size: 845 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 615 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/settings/premium/market.png
Normal file
After Width: | Height: | Size: 396 B |
BIN
Telegram/Resources/icons/settings/premium/market@2x.png
Normal file
After Width: | Height: | Size: 607 B |
BIN
Telegram/Resources/icons/settings/premium/market@3x.png
Normal file
After Width: | Height: | Size: 955 B |
Before Width: | Height: | Size: 497 B After Width: | Height: | Size: 568 B |
Before Width: | Height: | Size: 787 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.6 KiB |
|
@ -1313,6 +1313,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_info_link_label" = "Link";
|
"lng_info_link_label" = "Link";
|
||||||
"lng_info_location_label" = "Location";
|
"lng_info_location_label" = "Location";
|
||||||
"lng_info_about_label" = "About";
|
"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_user_title" = "User Info";
|
||||||
"lng_info_bot_title" = "Bot Info";
|
"lng_info_bot_title" = "Bot Info";
|
||||||
"lng_info_group_title" = "Group 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_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_subtitle_translation" = "Real-Time Translation";
|
||||||
"lng_premium_summary_about_translation" = "Real-time translation of channels and chats into other languages.";
|
"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_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_bottom_about" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";
|
||||||
"lng_premium_summary_button" = "Subscribe for {cost} per month";
|
"lng_premium_summary_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" = "By gifting Telegram Premium, you agree to the Telegram {link} and {policy}.";
|
||||||
"lng_premium_gifts_terms_policy" = "Privacy 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_channel_button" = "Boost Channel";
|
||||||
"lng_boost_group_button" = "Boost Group";
|
"lng_boost_group_button" = "Boost Group";
|
||||||
"lng_boost_again_button" = "Boost Again";
|
"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_translate_selected" = "Translate Selected Text";
|
||||||
"lng_context_read_hidden" = "read";
|
"lng_context_read_hidden" = "read";
|
||||||
"lng_context_read_show" = "show when";
|
"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_add_tag_about" = "Tag this message with an emoji for quick search.";
|
||||||
"lng_subscribe_tag_about" = "Organize your Saved Messages with tags. {link}";
|
"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_non_contacts" = "Non-Contacts";
|
||||||
"lng_filters_type_groups" = "Groups";
|
"lng_filters_type_groups" = "Groups";
|
||||||
"lng_filters_type_channels" = "Channels";
|
"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_bots" = "Bots";
|
||||||
"lng_filters_type_no_archived" = "Archived";
|
"lng_filters_type_no_archived" = "Archived";
|
||||||
"lng_filters_type_no_muted" = "Muted";
|
"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#one" = "{count} subscription {duration}";
|
||||||
"lng_boosts_prepaid_giveaway_status#other" = "{count} subscriptions {duration}";
|
"lng_boosts_prepaid_giveaway_status#other" = "{count} subscriptions {duration}";
|
||||||
|
|
||||||
|
"lng_contact_add" = "Add";
|
||||||
|
"lng_contact_send_message" = "message";
|
||||||
|
|
||||||
// Wnd specific
|
// Wnd specific
|
||||||
|
|
||||||
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
"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_idle.tgs">../../animations/voice_ttl_idle.tgs</file>
|
||||||
<file alias="voice_ttl_start.tgs">../../animations/voice_ttl_start.tgs</file>
|
<file alias="voice_ttl_start.tgs">../../animations/voice_ttl_start.tgs</file>
|
||||||
<file alias="palette.tgs">../../animations/palette.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>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<file alias="art/background.tgv">../../art/background.tgv</file>
|
<file alias="art/background.tgv">../../art/background.tgv</file>
|
||||||
<file alias="art/bg_thumbnail.png">../../art/bg_thumbnail.png</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/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.png">../../art/logo_256.png</file>
|
||||||
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.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>
|
<file alias="art/themeimage.jpg">../../art/themeimage.jpg</file>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||||
ProcessorArchitecture="ARCHITECTURE"
|
ProcessorArchitecture="ARCHITECTURE"
|
||||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||||
Version="4.15.0.0" />
|
Version="4.15.2.0" />
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>Telegram Desktop</DisplayName>
|
<DisplayName>Telegram Desktop</DisplayName>
|
||||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||||
|
|
|
@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 4,15,0,0
|
FILEVERSION 4,15,2,0
|
||||||
PRODUCTVERSION 4,15,0,0
|
PRODUCTVERSION 4,15,2,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -62,10 +62,10 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Radolyn Labs"
|
VALUE "CompanyName", "Radolyn Labs"
|
||||||
VALUE "FileDescription", "AyuGram Desktop"
|
VALUE "FileDescription", "AyuGram Desktop"
|
||||||
VALUE "FileVersion", "4.15.0.0"
|
VALUE "FileVersion", "4.15.2.0"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||||
VALUE "ProductName", "AyuGram Desktop"
|
VALUE "ProductName", "AyuGram Desktop"
|
||||||
VALUE "ProductVersion", "4.15.0.0"
|
VALUE "ProductVersion", "4.15.2.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 4,15,0,0
|
FILEVERSION 4,15,2,0
|
||||||
PRODUCTVERSION 4,15,0,0
|
PRODUCTVERSION 4,15,2,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -53,10 +53,10 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Radolyn Labs"
|
VALUE "CompanyName", "Radolyn Labs"
|
||||||
VALUE "FileDescription", "AyuGram Desktop Updater"
|
VALUE "FileDescription", "AyuGram Desktop Updater"
|
||||||
VALUE "FileVersion", "4.15.0.0"
|
VALUE "FileVersion", "4.15.2.0"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||||
VALUE "ProductName", "AyuGram Desktop"
|
VALUE "ProductName", "AyuGram Desktop"
|
||||||
VALUE "ProductVersion", "4.15.0.0"
|
VALUE "ProductVersion", "4.15.2.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -22,6 +22,7 @@ inline constexpr auto kScheduledUntilOnlineTimestamp = TimeId(0x7FFFFFFE);
|
||||||
struct SendOptions {
|
struct SendOptions {
|
||||||
PeerData *sendAs = nullptr;
|
PeerData *sendAs = nullptr;
|
||||||
TimeId scheduled = 0;
|
TimeId scheduled = 0;
|
||||||
|
BusinessShortcutId shortcutId = 0;
|
||||||
bool silent = false;
|
bool silent = false;
|
||||||
bool handleSupportSwitch = false;
|
bool handleSupportSwitch = false;
|
||||||
bool hideViaBot = false;
|
bool hideViaBot = false;
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_media.h"
|
#include "api/api_media.h"
|
||||||
#include "api/api_text_entities.h"
|
#include "api/api_text_entities.h"
|
||||||
#include "ui/boxes/confirm_box.h"
|
#include "ui/boxes/confirm_box.h"
|
||||||
|
#include "data/business/data_shortcut_messages.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
#include "data/data_scheduled_messages.h"
|
#include "data/data_scheduled_messages.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -88,10 +89,15 @@ mtpRequestId EditMessage(
|
||||||
: emptyFlag)
|
: emptyFlag)
|
||||||
| (options.scheduled
|
| (options.scheduled
|
||||||
? MTPmessages_EditMessage::Flag::f_schedule_date
|
? MTPmessages_EditMessage::Flag::f_schedule_date
|
||||||
|
: emptyFlag)
|
||||||
|
| (item->isBusinessShortcut()
|
||||||
|
? MTPmessages_EditMessage::Flag::f_quick_reply_shortcut_id
|
||||||
: emptyFlag);
|
: emptyFlag);
|
||||||
|
|
||||||
const auto id = item->isScheduled()
|
const auto id = item->isScheduled()
|
||||||
? session->data().scheduledMessages().lookupId(item)
|
? session->data().scheduledMessages().lookupId(item)
|
||||||
|
: item->isBusinessShortcut()
|
||||||
|
? session->data().shortcutMessages().lookupId(item)
|
||||||
: item->id;
|
: item->id;
|
||||||
return api->request(MTPmessages_EditMessage(
|
return api->request(MTPmessages_EditMessage(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
|
@ -101,7 +107,8 @@ mtpRequestId EditMessage(
|
||||||
inputMedia.value_or(Data::WebPageForMTP(webpage, text.isEmpty())),
|
inputMedia.value_or(Data::WebPageForMTP(webpage, text.isEmpty())),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
sentEntities,
|
sentEntities,
|
||||||
MTP_int(options.scheduled)
|
MTP_int(options.scheduled),
|
||||||
|
MTP_int(item->shortcutId())
|
||||||
)).done([=](
|
)).done([=](
|
||||||
const MTPUpdates &result,
|
const MTPUpdates &result,
|
||||||
[[maybe_unused]] mtpRequestId requestId) {
|
[[maybe_unused]] mtpRequestId requestId) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_updates.h"
|
#include "api/api_updates.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
|
#include "data/business/data_shortcut_messages.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
#include "data/data_poll.h"
|
#include "data/data_poll.h"
|
||||||
|
@ -69,6 +70,9 @@ void Polls::create(
|
||||||
if (action.options.scheduled) {
|
if (action.options.scheduled) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
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;
|
const auto sendAs = action.options.sendAs;
|
||||||
if (sendAs) {
|
if (sendAs) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||||
|
@ -89,7 +93,8 @@ void Polls::create(
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
MTPVector<MTPMessageEntity>(),
|
MTPVector<MTPMessageEntity>(),
|
||||||
MTP_int(action.options.scheduled),
|
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) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
|
@ -184,7 +189,8 @@ void Polls::close(not_null<HistoryItem*> item) {
|
||||||
PollDataToInputMedia(poll, true),
|
PollDataToInputMedia(poll, true),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
MTPVector<MTPMessageEntity>(),
|
MTPVector<MTPMessageEntity>(),
|
||||||
MTP_int(0) // schedule_date
|
MTP_int(0), // schedule_date
|
||||||
|
MTPint() // quick_reply_shortcut_id
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
_pollCloseRequestIds.erase(itemId);
|
_pollCloseRequestIds.erase(itemId);
|
||||||
_session->updates().applyUpdates(result);
|
_session->updates().applyUpdates(result);
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_text_entities.h"
|
#include "api/api_text_entities.h"
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
|
#include "data/business/data_shortcut_messages.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
#include "data/data_channel.h" // ChannelData::addsSignature.
|
#include "data/data_channel.h" // ChannelData::addsSignature.
|
||||||
|
@ -84,20 +85,21 @@ void SendExistingMedia(
|
||||||
? (*localMessageId)
|
? (*localMessageId)
|
||||||
: session->data().nextLocalMessageId());
|
: session->data().nextLocalMessageId());
|
||||||
const auto randomId = base::RandomValue<uint64>();
|
const auto randomId = base::RandomValue<uint64>();
|
||||||
|
const auto &action = message.action;
|
||||||
|
|
||||||
auto flags = NewMessageFlags(peer);
|
auto flags = NewMessageFlags(peer);
|
||||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||||
if (message.action.replyTo) {
|
if (action.replyTo) {
|
||||||
flags |= MessageFlag::HasReplyInfo;
|
flags |= MessageFlag::HasReplyInfo;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||||
}
|
}
|
||||||
const auto anonymousPost = peer->amAnonymous();
|
const auto anonymousPost = peer->amAnonymous();
|
||||||
const auto silentPost = ShouldSendSilent(peer, message.action.options);
|
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||||
InnerFillMessagePostFlags(message.action.options, peer, flags);
|
InnerFillMessagePostFlags(action.options, peer, flags);
|
||||||
if (silentPost) {
|
if (silentPost) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||||
}
|
}
|
||||||
const auto sendAs = message.action.options.sendAs;
|
const auto sendAs = action.options.sendAs;
|
||||||
const auto messageFromId = sendAs
|
const auto messageFromId = sendAs
|
||||||
? sendAs->id
|
? sendAs->id
|
||||||
: anonymousPost
|
: anonymousPost
|
||||||
|
@ -124,32 +126,34 @@ void SendExistingMedia(
|
||||||
}
|
}
|
||||||
const auto captionText = caption.text;
|
const auto captionText = caption.text;
|
||||||
|
|
||||||
if (message.action.options.scheduled) {
|
if (action.options.scheduled) {
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
flags |= MessageFlag::IsOrWasScheduled;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
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);
|
session->data().registerMessageRandomId(randomId, newId);
|
||||||
|
|
||||||
const auto viaBotId = UserId();
|
history->addNewLocalMessage({
|
||||||
history->addNewLocalMessage(
|
.id = newId.msg,
|
||||||
newId.msg,
|
.flags = flags,
|
||||||
flags,
|
.from = messageFromId,
|
||||||
viaBotId,
|
.replyTo = action.replyTo,
|
||||||
message.action.replyTo,
|
.date = HistoryItem::NewMessageDate(action.options),
|
||||||
HistoryItem::NewMessageDate(message.action.options.scheduled),
|
.shortcutId = action.options.shortcutId,
|
||||||
messageFromId,
|
.postAuthor = messagePostAuthor,
|
||||||
messagePostAuthor,
|
}, media, caption);
|
||||||
media,
|
|
||||||
caption,
|
|
||||||
HistoryMessageMarkupData());
|
|
||||||
|
|
||||||
const auto performRequest = [=](const auto &repeatRequest) -> void {
|
const auto performRequest = [=](const auto &repeatRequest) -> void {
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
|
const auto session = &history->session();
|
||||||
const auto usedFileReference = media->fileReference();
|
const auto usedFileReference = media->fileReference();
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
message.action.replyTo,
|
action.replyTo,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||||
MTP_flags(sendFlags),
|
MTP_flags(sendFlags),
|
||||||
|
@ -160,8 +164,9 @@ void SendExistingMedia(
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
sentEntities,
|
sentEntities,
|
||||||
MTP_int(message.action.options.scheduled),
|
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) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
if (error.code() == 400
|
if (error.code() == 400
|
||||||
|
@ -180,7 +185,7 @@ void SendExistingMedia(
|
||||||
};
|
};
|
||||||
performRequest(performRequest);
|
performRequest(performRequest);
|
||||||
|
|
||||||
api->finishForwarding(message.action);
|
api->finishForwarding(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -259,7 +264,10 @@ bool SendDice(MessageToSend &message) {
|
||||||
message.textWithTags = TextWithTags();
|
message.textWithTags = TextWithTags();
|
||||||
message.action.clearDraft = false;
|
message.action.clearDraft = false;
|
||||||
message.action.generateLocal = true;
|
message.action.generateLocal = true;
|
||||||
api->sendAction(message.action);
|
|
||||||
|
|
||||||
|
const auto &action = message.action;
|
||||||
|
api->sendAction(action);
|
||||||
|
|
||||||
const auto newId = FullMsgId(
|
const auto newId = FullMsgId(
|
||||||
peer->id,
|
peer->id,
|
||||||
|
@ -269,17 +277,17 @@ bool SendDice(MessageToSend &message) {
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
auto flags = NewMessageFlags(peer);
|
auto flags = NewMessageFlags(peer);
|
||||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||||
if (message.action.replyTo) {
|
if (action.replyTo) {
|
||||||
flags |= MessageFlag::HasReplyInfo;
|
flags |= MessageFlag::HasReplyInfo;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||||
}
|
}
|
||||||
const auto anonymousPost = peer->amAnonymous();
|
const auto anonymousPost = peer->amAnonymous();
|
||||||
const auto silentPost = ShouldSendSilent(peer, message.action.options);
|
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||||
InnerFillMessagePostFlags(message.action.options, peer, flags);
|
InnerFillMessagePostFlags(action.options, peer, flags);
|
||||||
if (silentPost) {
|
if (silentPost) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||||
}
|
}
|
||||||
const auto sendAs = message.action.options.sendAs;
|
const auto sendAs = action.options.sendAs;
|
||||||
const auto messageFromId = sendAs
|
const auto messageFromId = sendAs
|
||||||
? sendAs->id
|
? sendAs->id
|
||||||
: anonymousPost
|
: anonymousPost
|
||||||
|
@ -292,28 +300,31 @@ bool SendDice(MessageToSend &message) {
|
||||||
? session->user()->name()
|
? session->user()->name()
|
||||||
: QString();
|
: QString();
|
||||||
|
|
||||||
if (message.action.options.scheduled) {
|
if (action.options.scheduled) {
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
flags |= MessageFlag::IsOrWasScheduled;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
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);
|
session->data().registerMessageRandomId(randomId, newId);
|
||||||
|
|
||||||
const auto viaBotId = UserId();
|
history->addNewLocalMessage({
|
||||||
history->addNewLocalMessage(
|
.id = newId.msg,
|
||||||
newId.msg,
|
.flags = flags,
|
||||||
flags,
|
.from = messageFromId,
|
||||||
viaBotId,
|
.replyTo = action.replyTo,
|
||||||
message.action.replyTo,
|
.date = HistoryItem::NewMessageDate(action.options),
|
||||||
HistoryItem::NewMessageDate(message.action.options.scheduled),
|
.shortcutId = action.options.shortcutId,
|
||||||
messageFromId,
|
.postAuthor = messagePostAuthor,
|
||||||
messagePostAuthor,
|
}, TextWithEntities(), MTP_messageMediaDice(
|
||||||
TextWithEntities(),
|
MTP_int(0),
|
||||||
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
|
MTP_string(emoji)));
|
||||||
HistoryMessageMarkupData());
|
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
message.action.replyTo,
|
action.replyTo,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||||
MTP_flags(sendFlags),
|
MTP_flags(sendFlags),
|
||||||
|
@ -324,13 +335,14 @@ bool SendDice(MessageToSend &message) {
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
MTP_vector<MTPMessageEntity>(),
|
MTP_vector<MTPMessageEntity>(),
|
||||||
MTP_int(message.action.options.scheduled),
|
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) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
api->sendMessageFail(error, peer, randomId, newId);
|
api->sendMessageFail(error, peer, randomId, newId);
|
||||||
});
|
});
|
||||||
api->finishForwarding(message.action);
|
api->finishForwarding(action);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +418,13 @@ void SendConfirmedFile(
|
||||||
if (file->to.options.scheduled) {
|
if (file->to.options.scheduled) {
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
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;
|
flags |= MessageFlag::HideEdited;
|
||||||
}
|
}
|
||||||
if (file->type == SendMediaType::Audio) {
|
if (file->type == SendMediaType::Audio) {
|
||||||
|
@ -415,8 +433,7 @@ void SendConfirmedFile(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto messageFromId =
|
const auto messageFromId = file->to.options.sendAs
|
||||||
file->to.options.sendAs
|
|
||||||
? file->to.options.sendAs->id
|
? file->to.options.sendAs->id
|
||||||
: anonymousPost
|
: anonymousPost
|
||||||
? PeerId()
|
? PeerId()
|
||||||
|
@ -486,19 +503,16 @@ void SendConfirmedFile(
|
||||||
edition.savePreviousMedia = true;
|
edition.savePreviousMedia = true;
|
||||||
itemToEdit->applyEdition(std::move(edition));
|
itemToEdit->applyEdition(std::move(edition));
|
||||||
} else {
|
} else {
|
||||||
const auto viaBotId = UserId();
|
history->addNewLocalMessage({
|
||||||
history->addNewLocalMessage(
|
.id = newId.msg,
|
||||||
newId.msg,
|
.flags = flags,
|
||||||
flags,
|
.from = messageFromId,
|
||||||
viaBotId,
|
.replyTo = file->to.replyTo,
|
||||||
file->to.replyTo,
|
.date = HistoryItem::NewMessageDate(file->to.options),
|
||||||
HistoryItem::NewMessageDate(file->to.options.scheduled),
|
.shortcutId = file->to.options.shortcutId,
|
||||||
messageFromId,
|
.postAuthor = messagePostAuthor,
|
||||||
messagePostAuthor,
|
.groupedId = groupId,
|
||||||
caption,
|
}, caption, media);
|
||||||
media,
|
|
||||||
HistoryMessageMarkupData(),
|
|
||||||
groupId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mtproto/mtp_instance.h"
|
#include "mtproto/mtp_instance.h"
|
||||||
#include "mtproto/mtproto_config.h"
|
#include "mtproto/mtproto_config.h"
|
||||||
#include "mtproto/mtproto_dc_options.h"
|
#include "mtproto/mtproto_dc_options.h"
|
||||||
|
#include "data/business/data_shortcut_messages.h"
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "data/data_saved_messages.h"
|
#include "data/data_saved_messages.h"
|
||||||
|
@ -1141,7 +1142,8 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||||
MTPlong(),
|
MTPlong(),
|
||||||
MTPMessageReactions(),
|
MTPMessageReactions(),
|
||||||
MTPVector<MTPRestrictionReason>(),
|
MTPVector<MTPRestrictionReason>(),
|
||||||
MTP_int(d.vttl_period().value_or_empty())),
|
MTP_int(d.vttl_period().value_or_empty()),
|
||||||
|
MTPint()), // quick_reply_shortcut_id
|
||||||
MessageFlags(),
|
MessageFlags(),
|
||||||
NewMessageType::Unread);
|
NewMessageType::Unread);
|
||||||
} break;
|
} break;
|
||||||
|
@ -1174,7 +1176,8 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||||
MTPlong(),
|
MTPlong(),
|
||||||
MTPMessageReactions(),
|
MTPMessageReactions(),
|
||||||
MTPVector<MTPRestrictionReason>(),
|
MTPVector<MTPRestrictionReason>(),
|
||||||
MTP_int(d.vttl_period().value_or_empty())),
|
MTP_int(d.vttl_period().value_or_empty()),
|
||||||
|
MTPint()), // quick_reply_shortcut_id
|
||||||
MessageFlags(),
|
MessageFlags(),
|
||||||
NewMessageType::Unread);
|
NewMessageType::Unread);
|
||||||
} break;
|
} break;
|
||||||
|
@ -1565,6 +1568,8 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
if (const auto local = owner.message(id)) {
|
if (const auto local = owner.message(id)) {
|
||||||
if (local->isScheduled()) {
|
if (local->isScheduled()) {
|
||||||
session().data().scheduledMessages().apply(d, local);
|
session().data().scheduledMessages().apply(d, local);
|
||||||
|
} else if (local->isBusinessShortcut()) {
|
||||||
|
session().data().shortcutMessages().apply(d, local);
|
||||||
} else {
|
} else {
|
||||||
const auto existing = session().data().message(
|
const auto existing = session().data().message(
|
||||||
id.peer,
|
id.peer,
|
||||||
|
@ -1780,6 +1785,31 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
session().data().scheduledMessages().apply(d);
|
session().data().scheduledMessages().apply(d);
|
||||||
} break;
|
} 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: {
|
case mtpc_updateWebPage: {
|
||||||
auto &d = update.c_updateWebPage();
|
auto &d = update.c_updateWebPage();
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_premium.h"
|
#include "api/api_premium.h"
|
||||||
#include "api/api_user_names.h"
|
#include "api/api_user_names.h"
|
||||||
#include "api/api_websites.h"
|
#include "api/api_websites.h"
|
||||||
|
#include "data/business/data_shortcut_messages.h"
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_web_page.h"
|
#include "data/data_web_page.h"
|
||||||
|
@ -968,6 +969,7 @@ void ApiWrap::requestMoreDialogsIfNeeded() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestContacts();
|
requestContacts();
|
||||||
|
_session->data().shortcutMessages().preloadShortcuts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::updateDialogsOffset(
|
void ApiWrap::updateDialogsOffset(
|
||||||
|
@ -2480,6 +2482,14 @@ void ApiWrap::refreshFileReference(
|
||||||
request(MTPmessages_GetScheduledMessages(
|
request(MTPmessages_GetScheduledMessages(
|
||||||
item->history()->peer->input,
|
item->history()->peer->input,
|
||||||
MTP_vector<MTPint>(1, MTP_int(realId))));
|
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()) {
|
} else if (const auto channel = item->history()->peer->asChannel()) {
|
||||||
request(MTPchannels_GetMessages(
|
request(MTPchannels_GetMessages(
|
||||||
channel->inputChannel,
|
channel->inputChannel,
|
||||||
|
@ -3155,6 +3165,7 @@ void ApiWrap::sharedMediaDone(
|
||||||
if (topicRootId && !topic) {
|
if (topicRootId && !topic) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto hasMessages = !parsed.messageIds.empty();
|
||||||
_session->storage().add(Storage::SharedMediaAddSlice(
|
_session->storage().add(Storage::SharedMediaAddSlice(
|
||||||
peer->id,
|
peer->id,
|
||||||
topicRootId,
|
topicRootId,
|
||||||
|
@ -3163,7 +3174,7 @@ void ApiWrap::sharedMediaDone(
|
||||||
parsed.noSkipRange,
|
parsed.noSkipRange,
|
||||||
parsed.fullCount
|
parsed.fullCount
|
||||||
));
|
));
|
||||||
if (type == SharedMediaType::Pinned && !parsed.messageIds.empty()) {
|
if (type == SharedMediaType::Pinned && hasMessages) {
|
||||||
peer->owner().history(peer)->setHasPinnedMessages(true);
|
peer->owner().history(peer)->setHasPinnedMessages(true);
|
||||||
if (topic) {
|
if (topic) {
|
||||||
topic->setHasPinnedMessages(true);
|
topic->setHasPinnedMessages(true);
|
||||||
|
@ -3172,7 +3183,9 @@ void ApiWrap::sharedMediaDone(
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::sendAction(const SendAction &action) {
|
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 topicRootId = action.replyTo.topicRootId;
|
||||||
const auto topic = topicRootId
|
const auto topic = topicRootId
|
||||||
? action.history->peer->forumTopicFor(topicRootId)
|
? action.history->peer->forumTopicFor(topicRootId)
|
||||||
|
@ -3207,11 +3220,13 @@ void ApiWrap::finishForwarding(const SendAction &action) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_session->data().sendHistoryChangeNotifications();
|
_session->data().sendHistoryChangeNotifications();
|
||||||
_session->changes().historyUpdated(
|
if (!action.options.shortcutId) {
|
||||||
history,
|
_session->changes().historyUpdated(
|
||||||
(action.options.scheduled
|
history,
|
||||||
? Data::HistoryUpdate::Flag::ScheduledSent
|
(action.options.scheduled
|
||||||
: Data::HistoryUpdate::Flag::MessageSent));
|
? Data::HistoryUpdate::Flag::ScheduledSent
|
||||||
|
: Data::HistoryUpdate::Flag::MessageSent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::forwardMessages(
|
void ApiWrap::forwardMessages(
|
||||||
|
@ -3240,7 +3255,7 @@ void ApiWrap::forwardMessages(
|
||||||
const auto history = action.history;
|
const auto history = action.history;
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
|
||||||
if (!action.options.scheduled) {
|
if (!action.options.scheduled && !action.options.shortcutId) {
|
||||||
histories.readInbox(history);
|
histories.readInbox(history);
|
||||||
}
|
}
|
||||||
const auto anonymousPost = peer->amAnonymous();
|
const auto anonymousPost = peer->amAnonymous();
|
||||||
|
@ -3258,6 +3273,10 @@ void ApiWrap::forwardMessages(
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
flags |= MessageFlag::IsOrWasScheduled;
|
||||||
sendFlags |= SendFlag::f_schedule_date;
|
sendFlags |= SendFlag::f_schedule_date;
|
||||||
}
|
}
|
||||||
|
if (action.options.shortcutId) {
|
||||||
|
flags |= MessageFlag::ShortcutMessage;
|
||||||
|
sendFlags |= SendFlag::f_quick_reply_shortcut;
|
||||||
|
}
|
||||||
if (draft.options != Data::ForwardOptions::PreserveInfo) {
|
if (draft.options != Data::ForwardOptions::PreserveInfo) {
|
||||||
sendFlags |= SendFlag::f_drop_author;
|
sendFlags |= SendFlag::f_drop_author;
|
||||||
}
|
}
|
||||||
|
@ -3296,7 +3315,8 @@ void ApiWrap::forwardMessages(
|
||||||
peer->input,
|
peer->input,
|
||||||
MTP_int(topMsgId),
|
MTP_int(topMsgId),
|
||||||
MTP_int(action.options.scheduled),
|
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) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
applyUpdates(result);
|
applyUpdates(result);
|
||||||
if (shared && !--shared->requestsLeft) {
|
if (shared && !--shared->requestsLeft) {
|
||||||
|
@ -3340,14 +3360,15 @@ void ApiWrap::forwardMessages(
|
||||||
const auto messagePostAuthor = peer->isBroadcast()
|
const auto messagePostAuthor = peer->isBroadcast()
|
||||||
? self->name()
|
? self->name()
|
||||||
: QString();
|
: QString();
|
||||||
history->addNewLocalMessage(
|
history->addNewLocalMessage({
|
||||||
newId.msg,
|
.id = newId.msg,
|
||||||
flags,
|
.flags = flags,
|
||||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
.from = messageFromId,
|
||||||
messageFromId,
|
.replyTo = { .topicRootId = topMsgId },
|
||||||
messagePostAuthor,
|
.date = HistoryItem::NewMessageDate(action.options),
|
||||||
item,
|
.shortcutId = action.options.shortcutId,
|
||||||
topMsgId);
|
.postAuthor = messagePostAuthor,
|
||||||
|
}, item);
|
||||||
_session->data().registerMessageRandomId(randomId, newId);
|
_session->data().registerMessageRandomId(randomId, newId);
|
||||||
if (!localIds) {
|
if (!localIds) {
|
||||||
localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>();
|
localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>();
|
||||||
|
@ -3428,6 +3449,9 @@ void ApiWrap::sendSharedContact(
|
||||||
if (action.options.scheduled) {
|
if (action.options.scheduled) {
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
flags |= MessageFlag::IsOrWasScheduled;
|
||||||
}
|
}
|
||||||
|
if (action.options.shortcutId) {
|
||||||
|
flags |= MessageFlag::ShortcutMessage;
|
||||||
|
}
|
||||||
const auto messageFromId = action.options.sendAs
|
const auto messageFromId = action.options.sendAs
|
||||||
? action.options.sendAs->id
|
? action.options.sendAs->id
|
||||||
: anonymousPost
|
: anonymousPost
|
||||||
|
@ -3436,23 +3460,20 @@ void ApiWrap::sendSharedContact(
|
||||||
const auto messagePostAuthor = peer->isBroadcast()
|
const auto messagePostAuthor = peer->isBroadcast()
|
||||||
? _session->user()->name()
|
? _session->user()->name()
|
||||||
: QString();
|
: QString();
|
||||||
const auto viaBotId = UserId();
|
const auto item = history->addNewLocalMessage({
|
||||||
const auto item = history->addNewLocalMessage(
|
.id = newId.msg,
|
||||||
newId.msg,
|
.flags = flags,
|
||||||
flags,
|
.from = messageFromId,
|
||||||
viaBotId,
|
.replyTo = action.replyTo,
|
||||||
action.replyTo,
|
.date = HistoryItem::NewMessageDate(action.options),
|
||||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
.shortcutId = action.options.shortcutId,
|
||||||
messageFromId,
|
.postAuthor = messagePostAuthor,
|
||||||
messagePostAuthor,
|
}, TextWithEntities(), MTP_messageMediaContact(
|
||||||
TextWithEntities(),
|
MTP_string(phone),
|
||||||
MTP_messageMediaContact(
|
MTP_string(firstName),
|
||||||
MTP_string(phone),
|
MTP_string(lastName),
|
||||||
MTP_string(firstName),
|
MTP_string(), // vcard
|
||||||
MTP_string(lastName),
|
MTP_long(userId.bare)));
|
||||||
MTP_string(), // vcard
|
|
||||||
MTP_long(userId.bare)),
|
|
||||||
HistoryMessageMarkupData());
|
|
||||||
|
|
||||||
const auto media = MTP_inputMediaContact(
|
const auto media = MTP_inputMediaContact(
|
||||||
MTP_string(phone),
|
MTP_string(phone),
|
||||||
|
@ -3635,6 +3656,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) {
|
void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
const auto history = message.action.history;
|
const auto history = message.action.history;
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
@ -3776,18 +3808,20 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
||||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
mediaFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||||
}
|
}
|
||||||
const auto viaBotId = UserId();
|
if (action.options.shortcutId) {
|
||||||
lastMessage = history->addNewLocalMessage(
|
flags |= MessageFlag::ShortcutMessage;
|
||||||
newId.msg,
|
sendFlags |= MTPmessages_SendMessage::Flag::f_quick_reply_shortcut;
|
||||||
flags,
|
mediaFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
|
||||||
viaBotId,
|
}
|
||||||
action.replyTo,
|
lastMessage = history->addNewLocalMessage({
|
||||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
.id = newId.msg,
|
||||||
messageFromId,
|
.flags = flags,
|
||||||
messagePostAuthor,
|
.from = messageFromId,
|
||||||
sending,
|
.replyTo = action.replyTo,
|
||||||
media,
|
.date = HistoryItem::NewMessageDate(action.options),
|
||||||
HistoryMessageMarkupData());
|
.shortcutId = action.options.shortcutId,
|
||||||
|
.postAuthor = messagePostAuthor,
|
||||||
|
}, sending, media);
|
||||||
const auto done = [=](
|
const auto done = [=](
|
||||||
const MTPUpdates &result,
|
const MTPUpdates &result,
|
||||||
const MTP::Response &response) {
|
const MTP::Response &response) {
|
||||||
|
@ -3813,6 +3847,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const auto mtpShortcut = Data::ShortcutIdToMTP(
|
||||||
|
_session,
|
||||||
|
action.options.shortcutId);
|
||||||
if (exactWebPage
|
if (exactWebPage
|
||||||
&& !ignoreWebPage
|
&& !ignoreWebPage
|
||||||
&& (manualWebPage || sending.empty())) {
|
&& (manualWebPage || sending.empty())) {
|
||||||
|
@ -3829,8 +3866,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
sentEntities,
|
sentEntities,
|
||||||
MTP_int(message.action.options.scheduled),
|
MTP_int(action.options.scheduled),
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||||
|
mtpShortcut
|
||||||
), done, fail);
|
), done, fail);
|
||||||
} else {
|
} else {
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
|
@ -3846,7 +3884,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
sentEntities,
|
sentEntities,
|
||||||
MTP_int(action.options.scheduled),
|
MTP_int(action.options.scheduled),
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||||
|
mtpShortcut
|
||||||
), done, fail);
|
), done, fail);
|
||||||
}
|
}
|
||||||
isFirst = false;
|
isFirst = false;
|
||||||
|
@ -3937,6 +3976,10 @@ void ApiWrap::sendInlineResult(
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
flags |= MessageFlag::IsOrWasScheduled;
|
||||||
sendFlags |= SendFlag::f_schedule_date;
|
sendFlags |= SendFlag::f_schedule_date;
|
||||||
}
|
}
|
||||||
|
if (action.options.shortcutId) {
|
||||||
|
flags |= MessageFlag::ShortcutMessage;
|
||||||
|
sendFlags |= SendFlag::f_quick_reply_shortcut;
|
||||||
|
}
|
||||||
if (action.options.hideViaBot) {
|
if (action.options.hideViaBot) {
|
||||||
sendFlags |= SendFlag::f_hide_via;
|
sendFlags |= SendFlag::f_hide_via;
|
||||||
}
|
}
|
||||||
|
@ -3955,15 +3998,18 @@ void ApiWrap::sendInlineResult(
|
||||||
|
|
||||||
_session->data().registerMessageRandomId(randomId, newId);
|
_session->data().registerMessageRandomId(randomId, newId);
|
||||||
|
|
||||||
data->addToHistory(
|
data->addToHistory(history, {
|
||||||
history,
|
.id = newId.msg,
|
||||||
flags,
|
.flags = flags,
|
||||||
newId.msg,
|
.from = messageFromId,
|
||||||
messageFromId,
|
.replyTo = action.replyTo,
|
||||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
.date = HistoryItem::NewMessageDate(action.options),
|
||||||
(bot && !action.options.hideViaBot) ? peerToUser(bot->id) : 0,
|
.shortcutId = action.options.shortcutId,
|
||||||
action.replyTo,
|
.viaBotId = ((bot && !action.options.hideViaBot)
|
||||||
messagePostAuthor);
|
? peerToUser(bot->id)
|
||||||
|
: UserId()),
|
||||||
|
.postAuthor = messagePostAuthor,
|
||||||
|
});
|
||||||
|
|
||||||
history->clearCloudDraft(topicRootId);
|
history->clearCloudDraft(topicRootId);
|
||||||
history->startSavingCloudDraft(topicRootId);
|
history->startSavingCloudDraft(topicRootId);
|
||||||
|
@ -3981,7 +4027,8 @@ void ApiWrap::sendInlineResult(
|
||||||
MTP_long(data->getQueryId()),
|
MTP_long(data->getQueryId()),
|
||||||
MTP_string(data->getId()),
|
MTP_string(data->getId()),
|
||||||
MTP_int(action.options.scheduled),
|
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) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
topicRootId,
|
topicRootId,
|
||||||
|
@ -4118,7 +4165,8 @@ void ApiWrap::sendMediaWithRandomId(
|
||||||
: Flag(0))
|
: Flag(0))
|
||||||
| (!sentEntities.v.isEmpty() ? Flag::f_entities : Flag(0))
|
| (!sentEntities.v.isEmpty() ? Flag::f_entities : Flag(0))
|
||||||
| (options.scheduled ? Flag::f_schedule_date : 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();
|
auto &histories = history->owner().histories();
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
@ -4137,7 +4185,8 @@ void ApiWrap::sendMediaWithRandomId(
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
sentEntities,
|
sentEntities,
|
||||||
MTP_int(options.scheduled),
|
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) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
if (done) done(true);
|
if (done) done(true);
|
||||||
if (updateRecentStickers) {
|
if (updateRecentStickers) {
|
||||||
|
@ -4233,7 +4282,10 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||||
? Flag::f_silent
|
? Flag::f_silent
|
||||||
: Flag(0))
|
: Flag(0))
|
||||||
| (album->options.scheduled ? Flag::f_schedule_date : 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();
|
auto &histories = history->owner().histories();
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
|
@ -4246,7 +4298,8 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
MTP_vector<MTPInputSingleMedia>(medias),
|
MTP_vector<MTPInputSingleMedia>(medias),
|
||||||
MTP_int(album->options.scheduled),
|
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) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
_sendingAlbums.remove(groupId);
|
_sendingAlbums.remove(groupId);
|
||||||
|
|
||||||
|
|
|
@ -337,6 +337,9 @@ public:
|
||||||
|
|
||||||
void cancelLocalItem(not_null<HistoryItem*> item);
|
void cancelLocalItem(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
|
void sendShortcutMessages(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
BusinessShortcutId id);
|
||||||
void sendMessage(MessageToSend &&message);
|
void sendMessage(MessageToSend &&message);
|
||||||
void sendBotStart(
|
void sendBotStart(
|
||||||
not_null<UserData*> bot,
|
not_null<UserData*> bot,
|
||||||
|
|
|
@ -1018,7 +1018,7 @@ void SetupChannelBox::prepare() {
|
||||||
cancel);
|
cancel);
|
||||||
|
|
||||||
connect(_link, &Ui::MaskedInputField::changed, [=] { handleChange(); });
|
connect(_link, &Ui::MaskedInputField::changed, [=] { handleChange(); });
|
||||||
_link->setVisible(_privacyGroup->value() == Privacy::Public);
|
_link->setVisible(_privacyGroup->current() == Privacy::Public);
|
||||||
|
|
||||||
_privacyGroup->setChangedCallback([=](Privacy value) {
|
_privacyGroup->setChangedCallback([=](Privacy value) {
|
||||||
privacyChanged(value);
|
privacyChanged(value);
|
||||||
|
@ -1063,7 +1063,7 @@ void SetupChannelBox::updateMaxHeight() {
|
||||||
: 0)
|
: 0)
|
||||||
+ st::newGroupPadding.bottom();
|
+ st::newGroupPadding.bottom();
|
||||||
if (!_channel->isMegagroup()
|
if (!_channel->isMegagroup()
|
||||||
|| _privacyGroup->value() == Privacy::Public) {
|
|| _privacyGroup->current() == Privacy::Public) {
|
||||||
newHeight += st::newGroupLinkPadding.top()
|
newHeight += st::newGroupLinkPadding.top()
|
||||||
+ _link->height()
|
+ _link->height()
|
||||||
+ st::newGroupLinkPadding.bottom();
|
+ st::newGroupLinkPadding.bottom();
|
||||||
|
@ -1264,7 +1264,7 @@ void SetupChannelBox::save() {
|
||||||
};
|
};
|
||||||
if (_saveRequestId) {
|
if (_saveRequestId) {
|
||||||
return;
|
return;
|
||||||
} else if (_privacyGroup->value() == Privacy::Private) {
|
} else if (_privacyGroup->current() == Privacy::Private) {
|
||||||
closeBox();
|
closeBox();
|
||||||
} else {
|
} else {
|
||||||
const auto link = _link->text().trimmed();
|
const auto link = _link->text().trimmed();
|
||||||
|
|
|
@ -81,9 +81,9 @@ void AutoLockBox::prepare() {
|
||||||
|
|
||||||
const auto timeInput = Ui::CreateChild<Ui::TimeInput>(
|
const auto timeInput = Ui::CreateChild<Ui::TimeInput>(
|
||||||
this,
|
this,
|
||||||
(group->value() == kCustom)
|
(group->current() == kCustom
|
||||||
? TimeString(currentTime)
|
? TimeString(currentTime)
|
||||||
: kDefaultCustom.utf8(),
|
: kDefaultCustom.utf8()),
|
||||||
st::autolockTimeField,
|
st::autolockTimeField,
|
||||||
st::autolockDateField,
|
st::autolockDateField,
|
||||||
st::scheduleTimeSeparator,
|
st::scheduleTimeSeparator,
|
||||||
|
@ -115,7 +115,9 @@ void AutoLockBox::prepare() {
|
||||||
});
|
});
|
||||||
|
|
||||||
rpl::merge(
|
rpl::merge(
|
||||||
boxClosing() | rpl::filter([=] { return group->value() == kCustom; }),
|
boxClosing() | rpl::filter(
|
||||||
|
[=] { return group->current() == kCustom; }
|
||||||
|
),
|
||||||
timeInput->submitRequests()
|
timeInput->submitRequests()
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
if (const auto result = collect()) {
|
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.h"
|
||||||
#include "history/history_item_helpers.h"
|
#include "history/history_item_helpers.h"
|
||||||
#include "history/view/history_view_message.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 "main/main_session.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "data/data_session.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_document_resolver.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_peer_values.h"
|
#include "data/data_peer_values.h"
|
||||||
|
#include "data/data_premium_limits.h"
|
||||||
#include "settings/settings_premium.h"
|
#include "settings/settings_premium.h"
|
||||||
#include "storage/file_upload.h"
|
#include "storage/file_upload.h"
|
||||||
#include "storage/localimageloader.h"
|
#include "storage/localimageloader.h"
|
||||||
|
@ -82,11 +81,11 @@ constexpr auto kMaxWallPaperSlugLength = 255;
|
||||||
const auto flags = MessageFlag::FakeHistoryItem
|
const auto flags = MessageFlag::FakeHistoryItem
|
||||||
| MessageFlag::HasFromId
|
| MessageFlag::HasFromId
|
||||||
| (out ? MessageFlag::Outgoing : MessageFlag(0));
|
| (out ? MessageFlag::Outgoing : MessageFlag(0));
|
||||||
const auto item = history->makeMessage(
|
const auto item = history->makeMessage({
|
||||||
history->owner().nextLocalMessageId(),
|
.id = history->owner().nextLocalMessageId(),
|
||||||
flags,
|
.flags = flags,
|
||||||
base::unixtime::now(),
|
.date = base::unixtime::now(),
|
||||||
PreparedServiceText{ { text } });
|
}, PreparedServiceText{ { text } });
|
||||||
return AdminLog::OwnedItem(delegate, item);
|
return AdminLog::OwnedItem(delegate, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,24 +96,16 @@ constexpr auto kMaxWallPaperSlugLength = 255;
|
||||||
bool out) {
|
bool out) {
|
||||||
Expects(history->peer->isUser());
|
Expects(history->peer->isUser());
|
||||||
|
|
||||||
const auto flags = MessageFlag::FakeHistoryItem
|
const auto item = history->makeMessage({
|
||||||
| MessageFlag::HasFromId
|
.id = history->nextNonHistoryEntryId(),
|
||||||
| (out ? MessageFlag::Outgoing : MessageFlag(0));
|
.flags = (MessageFlag::FakeHistoryItem
|
||||||
const auto replyTo = FullReplyTo();
|
| MessageFlag::HasFromId
|
||||||
const auto viaBotId = UserId();
|
| (out ? MessageFlag::Outgoing : MessageFlag(0))),
|
||||||
const auto groupedId = uint64();
|
.from = (out
|
||||||
const auto item = history->makeMessage(
|
? history->session().userId()
|
||||||
history->nextNonHistoryEntryId(),
|
: peerToUser(history->peer->id)),
|
||||||
flags,
|
.date = base::unixtime::now(),
|
||||||
replyTo,
|
}, TextWithEntities{ text }, MTP_messageMediaEmpty());
|
||||||
viaBotId,
|
|
||||||
base::unixtime::now(),
|
|
||||||
out ? history->session().userId() : peerToUser(history->peer->id),
|
|
||||||
QString(),
|
|
||||||
TextWithEntities{ text },
|
|
||||||
MTP_messageMediaEmpty(),
|
|
||||||
HistoryMessageMarkupData(),
|
|
||||||
groupedId);
|
|
||||||
return AdminLog::OwnedItem(delegate, item);
|
return AdminLog::OwnedItem(delegate, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,16 +690,10 @@ void BackgroundPreviewBox::checkLevelForChannel() {
|
||||||
if (!weak) {
|
if (!weak) {
|
||||||
return std::optional<Ui::AskBoostReason>();
|
return std::optional<Ui::AskBoostReason>();
|
||||||
}
|
}
|
||||||
const auto appConfig = &_forPeer->session().account().appConfig();
|
const auto limits = Data::LevelLimits(&_forPeer->session());
|
||||||
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 required = _paperEmojiId.isEmpty()
|
const auto required = _paperEmojiId.isEmpty()
|
||||||
? customRequired
|
? limits.channelCustomWallpaperLevelMin()
|
||||||
: defaultRequired;
|
: limits.channelWallpaperLevelMin();
|
||||||
if (level >= required) {
|
if (level >= required) {
|
||||||
applyForPeer(false);
|
applyForPeer(false);
|
||||||
return std::optional<Ui::AskBoostReason>();
|
return std::optional<Ui::AskBoostReason>();
|
||||||
|
@ -791,7 +776,7 @@ void BackgroundPreviewBox::applyForPeer() {
|
||||||
} else {
|
} else {
|
||||||
ShowPremiumPreviewBox(
|
ShowPremiumPreviewBox(
|
||||||
_controller->uiShow(),
|
_controller->uiShow(),
|
||||||
PremiumPreview::Wallpapers);
|
PremiumFeature::Wallpapers);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const auto cancel = CreateChild<RoundButton>(
|
const auto cancel = CreateChild<RoundButton>(
|
||||||
|
|
|
@ -717,7 +717,7 @@ void ProxiesBox::refreshProxyForCalls() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_proxyForCalls->toggle(
|
_proxyForCalls->toggle(
|
||||||
(_proxySettings->value() == ProxyData::Settings::Enabled
|
(_proxySettings->current() == ProxyData::Settings::Enabled
|
||||||
&& _currentProxySupportsCallsId != 0),
|
&& _currentProxySupportsCallsId != 0),
|
||||||
anim::type::normal);
|
anim::type::normal);
|
||||||
}
|
}
|
||||||
|
@ -864,7 +864,7 @@ void ProxyBox::refreshButtons() {
|
||||||
addButton(tr::lng_settings_save(), [=] { save(); });
|
addButton(tr::lng_settings_save(), [=] { save(); });
|
||||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||||
|
|
||||||
const auto type = _type->value();
|
const auto type = _type->current();
|
||||||
if (type == Type::Socks5 || type == Type::Mtproto) {
|
if (type == Type::Socks5 || type == Type::Mtproto) {
|
||||||
addLeftButton(tr::lng_proxy_share(), [=] { share(); });
|
addLeftButton(tr::lng_proxy_share(), [=] { share(); });
|
||||||
}
|
}
|
||||||
|
@ -885,7 +885,7 @@ void ProxyBox::share() {
|
||||||
|
|
||||||
ProxyData ProxyBox::collectData() {
|
ProxyData ProxyBox::collectData() {
|
||||||
auto result = ProxyData();
|
auto result = ProxyData();
|
||||||
result.type = _type->value();
|
result.type = _type->current();
|
||||||
result.host = _host->getLastText().trimmed();
|
result.host = _host->getLastText().trimmed();
|
||||||
result.port = _port->getLastText().trimmed().toInt();
|
result.port = _port->getLastText().trimmed().toInt();
|
||||||
result.user = (result.type == Type::Mtproto)
|
result.user = (result.type == Type::Mtproto)
|
||||||
|
@ -1053,7 +1053,7 @@ void ProxyBox::setupControls(const ProxyData &data) {
|
||||||
handleType(type);
|
handleType(type);
|
||||||
refreshButtons();
|
refreshButtons();
|
||||||
});
|
});
|
||||||
handleType(_type->value());
|
handleType(_type->current());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProxyBox::addLabel(
|
void ProxyBox::addLabel(
|
||||||
|
|
|
@ -44,7 +44,9 @@ void DownloadPathBox::prepare() {
|
||||||
|
|
||||||
setTitle(tr::lng_download_path_header());
|
setTitle(tr::lng_download_path_header());
|
||||||
|
|
||||||
_group->setChangedCallback([this](Directory value) { radioChanged(value); });
|
_group->setChangedCallback([this](Directory value) {
|
||||||
|
radioChanged(value);
|
||||||
|
});
|
||||||
|
|
||||||
_pathLink->addClickHandler([=] { editPath(); });
|
_pathLink->addClickHandler([=] { editPath(); });
|
||||||
if (!_path.isEmpty() && _path != FileDialog::Tmp()) {
|
if (!_path.isEmpty() && _path != FileDialog::Tmp()) {
|
||||||
|
@ -54,7 +56,7 @@ void DownloadPathBox::prepare() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadPathBox::updateControlsVisibility() {
|
void DownloadPathBox::updateControlsVisibility() {
|
||||||
auto custom = (_group->value() == Directory::Custom);
|
auto custom = (_group->current() == Directory::Custom);
|
||||||
_pathLink->setVisible(custom);
|
_pathLink->setVisible(custom);
|
||||||
|
|
||||||
auto newHeight = st::boxOptionListPadding.top() + (_default ? _default->getMargins().top() + _default->heightNoMargins() : 0) + st::boxOptionListSkip + _temp->heightNoMargins() + st::boxOptionListSkip + _dir->heightNoMargins();
|
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() {
|
void DownloadPathBox::save() {
|
||||||
#ifndef OS_WIN_STORE
|
#ifndef OS_WIN_STORE
|
||||||
auto value = _group->value();
|
auto value = _group->current();
|
||||||
auto computePath = [this, value] {
|
auto computePath = [this, value] {
|
||||||
if (value == Directory::Custom) {
|
if (value == Directory::Custom) {
|
||||||
return _path;
|
return _path;
|
||||||
|
|
|
@ -682,7 +682,7 @@ void EditCaptionBox::setupEmojiPanel() {
|
||||||
&& !_controller->session().premium()) {
|
&& !_controller->session().premium()) {
|
||||||
ShowPremiumPreviewBox(
|
ShowPremiumPreviewBox(
|
||||||
_controller,
|
_controller,
|
||||||
PremiumPreview::AnimatedEmoji);
|
PremiumFeature::AnimatedEmoji);
|
||||||
} else {
|
} else {
|
||||||
Data::InsertCustomEmoji(_field.get(), data.document);
|
Data::InsertCustomEmoji(_field.get(), data.document);
|
||||||
}
|
}
|
||||||
|
@ -895,6 +895,7 @@ void EditCaptionBox::save() {
|
||||||
|
|
||||||
auto options = Api::SendOptions();
|
auto options = Api::SendOptions();
|
||||||
options.scheduled = item->isScheduled() ? item->date() : 0;
|
options.scheduled = item->isScheduled() ? item->date() : 0;
|
||||||
|
options.shortcutId = item->shortcutId();
|
||||||
|
|
||||||
if (!_preparedList.files.empty()) {
|
if (!_preparedList.files.empty()) {
|
||||||
if ((_albumType != Ui::AlbumType::None)
|
if ((_albumType != Ui::AlbumType::None)
|
||||||
|
|
|
@ -10,28 +10,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_global_privacy.h"
|
#include "api/api_global_privacy.h"
|
||||||
#include "ui/layers/generic_box.h"
|
#include "ui/layers/generic_box.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/widgets/labels.h"
|
|
||||||
#include "ui/widgets/buttons.h"
|
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "boxes/peer_list_controllers.h"
|
#include "boxes/peer_list_controllers.h"
|
||||||
#include "settings/settings_common.h"
|
|
||||||
#include "settings/settings_premium.h"
|
#include "settings/settings_premium.h"
|
||||||
#include "settings/settings_privacy_security.h"
|
#include "settings/settings_privacy_security.h"
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
#include "base/binary_guard.h"
|
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_chat.h"
|
#include "data/data_chat.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_peer_values.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
|
@ -67,6 +63,32 @@ void CreateRadiobuttonLock(
|
||||||
}, lock->lifetime());
|
}, 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
|
} // namespace
|
||||||
|
|
||||||
class PrivacyExceptionsBoxController : public ChatsListBoxController {
|
class PrivacyExceptionsBoxController : public ChatsListBoxController {
|
||||||
|
@ -363,10 +385,29 @@ void EditPrivacyBox::setupContent() {
|
||||||
content,
|
content,
|
||||||
_controller->optionsTitleKey(),
|
_controller->optionsTitleKey(),
|
||||||
{ 0, st::settingsPrivacySkipTop, 0, 0 });
|
{ 0, st::settingsPrivacySkipTop, 0, 0 });
|
||||||
addOptionRow(Option::Everyone);
|
|
||||||
addOptionRow(Option::Contacts);
|
const auto options = {
|
||||||
addOptionRow(Option::CloseFriends);
|
Option::Everyone,
|
||||||
addOptionRow(Option::Nobody);
|
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(
|
const auto warning = addLabelOrDivider(
|
||||||
content,
|
content,
|
||||||
_controller->warning(),
|
_controller->warning(),
|
||||||
|
@ -541,7 +582,7 @@ void EditMessagesPrivacyBox(
|
||||||
box->addButton(tr::lng_settings_save(), [=] {
|
box->addButton(tr::lng_settings_save(), [=] {
|
||||||
if (controller->session().premium()) {
|
if (controller->session().premium()) {
|
||||||
privacy->updateNewRequirePremium(
|
privacy->updateNewRequirePremium(
|
||||||
group->value() == kOptionPremium);
|
group->current() == kOptionPremium);
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
} else {
|
} else {
|
||||||
showToast();
|
showToast();
|
||||||
|
|
|
@ -88,6 +88,12 @@ public:
|
||||||
virtual void saveAdditional() {
|
virtual void saveAdditional() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual Fn<void()> premiumClickedCallback(
|
||||||
|
Option option,
|
||||||
|
not_null<Window::SessionController*> controller) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~EditPrivacyController() = default;
|
virtual ~EditPrivacyController() = default;
|
||||||
|
|
||||||
protected:
|
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_box.h"
|
||||||
|
|
||||||
#include "boxes/filters/edit_filter_chats_list.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/filters/edit_filter_links.h"
|
||||||
#include "boxes/premium_limits_box.h"
|
#include "boxes/premium_limits_box.h"
|
||||||
#include "chat_helpers/emoji_suggestions_widget.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_chat_filters.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_peer_values.h" // Data::AmPremiumValue.
|
#include "data/data_peer_values.h" // Data::AmPremiumValue.
|
||||||
|
#include "data/data_premium_limits.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
|
@ -56,60 +58,6 @@ using Flags = Data::ChatFilter::Flags;
|
||||||
using ExceptionPeersRef = const base::flat_set<not_null<History*>> &;
|
using ExceptionPeersRef = const base::flat_set<not_null<History*>> &;
|
||||||
using ExceptionPeersGetter = ExceptionPeersRef(Data::ChatFilter::*)() const;
|
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 {
|
struct NameEditing {
|
||||||
not_null<Ui::InputField*> field;
|
not_null<Ui::InputField*> field;
|
||||||
bool custom = false;
|
bool custom = false;
|
||||||
|
@ -167,167 +115,6 @@ not_null<FilterChatsPreview*> SetupChatsPreview(
|
||||||
return preview;
|
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(
|
void EditExceptions(
|
||||||
not_null<Window::SessionController*> window,
|
not_null<Window::SessionController*> window,
|
||||||
not_null<QObject*> context,
|
not_null<QObject*> context,
|
||||||
|
@ -338,6 +125,12 @@ void EditExceptions(
|
||||||
const auto include = (options & Flag::Contacts) != Flags(0);
|
const auto include = (options & Flag::Contacts) != Flags(0);
|
||||||
const auto rules = data->current();
|
const auto rules = data->current();
|
||||||
const auto session = &window->session();
|
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>(
|
auto controller = std::make_unique<EditFilterChatsListController>(
|
||||||
session,
|
session,
|
||||||
(include
|
(include
|
||||||
|
@ -346,9 +139,8 @@ void EditExceptions(
|
||||||
options,
|
options,
|
||||||
rules.flags() & options,
|
rules.flags() & options,
|
||||||
include ? rules.always() : rules.never(),
|
include ? rules.always() : rules.never(),
|
||||||
[=](int count) {
|
limit,
|
||||||
return Box(FilterChatsLimitBox, session, count, include);
|
showLimitReached);
|
||||||
});
|
|
||||||
const auto rawController = controller.get();
|
const auto rawController = controller.get();
|
||||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||||
box->setCloseByOutsideClick(false);
|
box->setCloseByOutsideClick(false);
|
||||||
|
|
|
@ -28,6 +28,8 @@ using Flag = Data::ChatFilter::Flag;
|
||||||
using Flags = Data::ChatFilter::Flags;
|
using Flags = Data::ChatFilter::Flags;
|
||||||
|
|
||||||
constexpr auto kAllTypes = {
|
constexpr auto kAllTypes = {
|
||||||
|
Flag::NewChats,
|
||||||
|
Flag::ExistingChats,
|
||||||
Flag::Contacts,
|
Flag::Contacts,
|
||||||
Flag::NonContacts,
|
Flag::NonContacts,
|
||||||
Flag::Groups,
|
Flag::Groups,
|
||||||
|
@ -119,7 +121,7 @@ PaintRoundImageCallback TypeRow::generatePaintUserpicCallback(
|
||||||
}
|
}
|
||||||
|
|
||||||
Flag TypeRow::flag() const {
|
Flag TypeRow::flag() const {
|
||||||
return static_cast<Flag>(id() & 0xFF);
|
return static_cast<Flag>(id() & 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
|
ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
|
||||||
|
@ -219,6 +221,8 @@ auto TypeController::rowSelectionChanges() const
|
||||||
|
|
||||||
[[nodiscard]] QString FilterChatsTypeName(Flag flag) {
|
[[nodiscard]] QString FilterChatsTypeName(Flag flag) {
|
||||||
switch (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::Contacts: return tr::lng_filters_type_contacts(tr::now);
|
||||||
case Flag::NonContacts:
|
case Flag::NonContacts:
|
||||||
return tr::lng_filters_type_non_contacts(tr::now);
|
return tr::lng_filters_type_non_contacts(tr::now);
|
||||||
|
@ -241,6 +245,8 @@ void PaintFilterChatsTypeIcon(
|
||||||
int size) {
|
int size) {
|
||||||
const auto &color1 = [&]() -> const style::color& {
|
const auto &color1 = [&]() -> const style::color& {
|
||||||
switch (flag) {
|
switch (flag) {
|
||||||
|
case Flag::NewChats: return st::historyPeer5UserpicBg;
|
||||||
|
case Flag::ExistingChats: return st::historyPeer8UserpicBg;
|
||||||
case Flag::Contacts: return st::historyPeer4UserpicBg;
|
case Flag::Contacts: return st::historyPeer4UserpicBg;
|
||||||
case Flag::NonContacts: return st::historyPeer7UserpicBg;
|
case Flag::NonContacts: return st::historyPeer7UserpicBg;
|
||||||
case Flag::Groups: return st::historyPeer2UserpicBg;
|
case Flag::Groups: return st::historyPeer2UserpicBg;
|
||||||
|
@ -254,6 +260,8 @@ void PaintFilterChatsTypeIcon(
|
||||||
}();
|
}();
|
||||||
const auto &color2 = [&]() -> const style::color& {
|
const auto &color2 = [&]() -> const style::color& {
|
||||||
switch (flag) {
|
switch (flag) {
|
||||||
|
case Flag::NewChats: return st::historyPeer5UserpicBg2;
|
||||||
|
case Flag::ExistingChats: return st::historyPeer8UserpicBg2;
|
||||||
case Flag::Contacts: return st::historyPeer4UserpicBg2;
|
case Flag::Contacts: return st::historyPeer4UserpicBg2;
|
||||||
case Flag::NonContacts: return st::historyPeer7UserpicBg2;
|
case Flag::NonContacts: return st::historyPeer7UserpicBg2;
|
||||||
case Flag::Groups: return st::historyPeer2UserpicBg2;
|
case Flag::Groups: return st::historyPeer2UserpicBg2;
|
||||||
|
@ -267,6 +275,8 @@ void PaintFilterChatsTypeIcon(
|
||||||
}();
|
}();
|
||||||
const auto &icon = [&]() -> const style::icon& {
|
const auto &icon = [&]() -> const style::icon& {
|
||||||
switch (flag) {
|
switch (flag) {
|
||||||
|
case Flag::NewChats: return st::windowFilterTypeNewChats;
|
||||||
|
case Flag::ExistingChats: return st::windowFilterTypeExistingChats;
|
||||||
case Flag::Contacts: return st::windowFilterTypeContacts;
|
case Flag::Contacts: return st::windowFilterTypeContacts;
|
||||||
case Flag::NonContacts: return st::windowFilterTypeNonContacts;
|
case Flag::NonContacts: return st::windowFilterTypeNonContacts;
|
||||||
case Flag::Groups: return st::windowFilterTypeGroups;
|
case Flag::Groups: return st::windowFilterTypeGroups;
|
||||||
|
@ -323,17 +333,17 @@ EditFilterChatsListController::EditFilterChatsListController(
|
||||||
Flags options,
|
Flags options,
|
||||||
Flags selected,
|
Flags selected,
|
||||||
const base::flat_set<not_null<History*>> &peers,
|
const base::flat_set<not_null<History*>> &peers,
|
||||||
LimitBoxFactory limitBox)
|
int limit,
|
||||||
|
Fn<void()> showLimitReached)
|
||||||
: ChatsListBoxController(session)
|
: ChatsListBoxController(session)
|
||||||
, _session(session)
|
, _session(session)
|
||||||
, _limitBox(std::move(limitBox))
|
, _showLimitReached(std::move(showLimitReached))
|
||||||
, _title(std::move(title))
|
, _title(std::move(title))
|
||||||
, _peers(peers)
|
, _peers(peers)
|
||||||
, _options(options & ~Flag::Chatlist)
|
, _options(options & ~Flag::Chatlist)
|
||||||
, _selected(selected)
|
, _selected(selected)
|
||||||
, _limit(Data::PremiumLimits(session).dialogFiltersChatsCurrent())
|
, _limit(limit)
|
||||||
, _chatlist(options & Flag::Chatlist) {
|
, _chatlist(options & Flag::Chatlist) {
|
||||||
Expects(_limitBox != nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Main::Session &EditFilterChatsListController::session() const {
|
Main::Session &EditFilterChatsListController::session() const {
|
||||||
|
@ -361,8 +371,8 @@ void EditFilterChatsListController::rowClicked(not_null<PeerListRow*> row) {
|
||||||
if (count < _limit || row->checked()) {
|
if (count < _limit || row->checked()) {
|
||||||
delegate()->peerListSetRowChecked(row, !row->checked());
|
delegate()->peerListSetRowChecked(row, !row->checked());
|
||||||
updateTitle();
|
updateTitle();
|
||||||
} else {
|
} else if (const auto copy = _showLimitReached) {
|
||||||
delegate()->peerListUiShow()->showBox(_limitBox(count));
|
copy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,6 +479,10 @@ object_ptr<Ui::RpWidget> EditFilterChatsListController::prepareTypesList() {
|
||||||
|
|
||||||
auto EditFilterChatsListController::createRow(not_null<History*> history)
|
auto EditFilterChatsListController::createRow(not_null<History*> history)
|
||||||
-> std::unique_ptr<Row> {
|
-> 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()
|
return history->inChatList()
|
||||||
? std::make_unique<ExceptionRow>(history)
|
? std::make_unique<ExceptionRow>(history)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
|
|
@ -43,7 +43,6 @@ class EditFilterChatsListController final : public ChatsListBoxController {
|
||||||
public:
|
public:
|
||||||
using Flag = Data::ChatFilter::Flag;
|
using Flag = Data::ChatFilter::Flag;
|
||||||
using Flags = Data::ChatFilter::Flags;
|
using Flags = Data::ChatFilter::Flags;
|
||||||
using LimitBoxFactory = Fn<object_ptr<Ui::BoxContent>(int)>;
|
|
||||||
|
|
||||||
EditFilterChatsListController(
|
EditFilterChatsListController(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
|
@ -51,7 +50,8 @@ public:
|
||||||
Flags options,
|
Flags options,
|
||||||
Flags selected,
|
Flags selected,
|
||||||
const base::flat_set<not_null<History*>> &peers,
|
const base::flat_set<not_null<History*>> &peers,
|
||||||
LimitBoxFactory limitBox);
|
int limit,
|
||||||
|
Fn<void()> showLimitReached);
|
||||||
|
|
||||||
[[nodiscard]] Main::Session &session() const override;
|
[[nodiscard]] Main::Session &session() const override;
|
||||||
[[nodiscard]] Flags chosenOptions() const {
|
[[nodiscard]] Flags chosenOptions() const {
|
||||||
|
@ -72,7 +72,7 @@ private:
|
||||||
void updateTitle();
|
void updateTitle();
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
const LimitBoxFactory _limitBox;
|
const Fn<void()> _showLimitReached;
|
||||||
rpl::producer<QString> _title;
|
rpl::producer<QString> _title;
|
||||||
base::flat_set<not_null<History*>> _peers;
|
base::flat_set<not_null<History*>> _peers;
|
||||||
Flags _options;
|
Flags _options;
|
||||||
|
|
199
Telegram/SourceFiles/boxes/filters/edit_filter_chats_preview.cpp
Normal file
|
@ -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,
|
not_null<Window::SessionController*> window,
|
||||||
const Data::ChatFilter &filter) {
|
const Data::ChatFilter &filter) {
|
||||||
using Flag = Data::ChatFilter::Flag;
|
using Flag = Data::ChatFilter::Flag;
|
||||||
const auto listflags = Flag::Chatlist | Flag::HasMyLinks;
|
if (!filter.never().empty() || (filter.flags() & Flag::RulesMask)) {
|
||||||
if (!filter.never().empty() || (filter.flags() & ~listflags)) {
|
|
||||||
window->showToast(tr::lng_filters_link_cant(tr::now));
|
window->showToast(tr::lng_filters_link_cant(tr::now));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,7 +386,7 @@ void GiftBox(
|
||||||
state->buttonText.events(),
|
state->buttonText.events(),
|
||||||
Ui::Premium::GiftGradientStops(),
|
Ui::Premium::GiftGradientStops(),
|
||||||
[=] {
|
[=] {
|
||||||
const auto value = group->value();
|
const auto value = group->current();
|
||||||
return (value < options.size() && value >= 0)
|
return (value < options.size() && value >= 0)
|
||||||
? options[value].botUrl
|
? options[value].botUrl
|
||||||
: QString();
|
: QString();
|
||||||
|
@ -587,7 +587,7 @@ void GiftsBox(
|
||||||
const auto content = box->addRow(
|
const auto content = box->addRow(
|
||||||
object_ptr<Ui::VerticalLayout>(box),
|
object_ptr<Ui::VerticalLayout>(box),
|
||||||
{});
|
{});
|
||||||
auto buttonCallback = [=](PremiumPreview section) {
|
auto buttonCallback = [=](PremiumFeature section) {
|
||||||
stars->setPaused(true);
|
stars->setPaused(true);
|
||||||
const auto previewBoxShown = [=](
|
const auto previewBoxShown = [=](
|
||||||
not_null<Ui::BoxContent*> previewBox) {
|
not_null<Ui::BoxContent*> previewBox) {
|
||||||
|
@ -665,7 +665,7 @@ void GiftsBox(
|
||||||
}
|
}
|
||||||
auto invoice = api->invoice(
|
auto invoice = api->invoice(
|
||||||
users.size(),
|
users.size(),
|
||||||
api->monthsFromPreset(group->value()));
|
api->monthsFromPreset(group->current()));
|
||||||
invoice.purpose = Payments::InvoicePremiumGiftCodeUsers{ users };
|
invoice.purpose = Payments::InvoicePremiumGiftCodeUsers{ users };
|
||||||
|
|
||||||
state->confirmButtonBusy = true;
|
state->confirmButtonBusy = true;
|
||||||
|
|
|
@ -1216,7 +1216,7 @@ void LanguageBox::setupTop(not_null<Ui::VerticalLayout*> container) {
|
||||||
if (checked && !premium) {
|
if (checked && !premium) {
|
||||||
ShowPremiumPreviewToBuy(
|
ShowPremiumPreviewToBuy(
|
||||||
_controller,
|
_controller,
|
||||||
PremiumPreview::RealTimeTranslation);
|
PremiumFeature::RealTimeTranslation);
|
||||||
_translateChatTurnOff.fire(false);
|
_translateChatTurnOff.fire(false);
|
||||||
}
|
}
|
||||||
return premium
|
return premium
|
||||||
|
|
|
@ -260,11 +260,11 @@ void Controller::choose(not_null<ChatData*> chat) {
|
||||||
|
|
||||||
const auto init = [=](not_null<ListBox*> box) {
|
const auto init = [=](not_null<ListBox*> box) {
|
||||||
auto above = object_ptr<Ui::VerticalLayout>(box);
|
auto above = object_ptr<Ui::VerticalLayout>(box);
|
||||||
Settings::AddDividerTextWithLottie(
|
Settings::AddDividerTextWithLottie(above, {
|
||||||
above,
|
.lottie = u"discussion"_q,
|
||||||
box->showFinishes(),
|
.showFinished = box->showFinishes(),
|
||||||
About(channel, chat),
|
.about = About(channel, chat),
|
||||||
u"discussion"_q);
|
});
|
||||||
if (!chat) {
|
if (!chat) {
|
||||||
Assert(channel->isBroadcast());
|
Assert(channel->isBroadcast());
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,9 @@ ChatAdminRightsInfo EditAdminBox::defaultRights() const {
|
||||||
: peer()->isMegagroup()
|
: peer()->isMegagroup()
|
||||||
? ChatAdminRightsInfo{ (Flag::ChangeInfo
|
? ChatAdminRightsInfo{ (Flag::ChangeInfo
|
||||||
| Flag::DeleteMessages
|
| Flag::DeleteMessages
|
||||||
|
| Flag::PostStories
|
||||||
|
| Flag::EditStories
|
||||||
|
| Flag::DeleteStories
|
||||||
| Flag::BanUsers
|
| Flag::BanUsers
|
||||||
| Flag::InviteByLinkOrAdd
|
| Flag::InviteByLinkOrAdd
|
||||||
| Flag::ManageTopics
|
| Flag::ManageTopics
|
||||||
|
@ -225,6 +228,9 @@ ChatAdminRightsInfo EditAdminBox::defaultRights() const {
|
||||||
| Flag::PostMessages
|
| Flag::PostMessages
|
||||||
| Flag::EditMessages
|
| Flag::EditMessages
|
||||||
| Flag::DeleteMessages
|
| Flag::DeleteMessages
|
||||||
|
| Flag::PostStories
|
||||||
|
| Flag::EditStories
|
||||||
|
| Flag::DeleteStories
|
||||||
| Flag::InviteByLinkOrAdd
|
| Flag::InviteByLinkOrAdd
|
||||||
| Flag::ManageCall) };
|
| Flag::ManageCall) };
|
||||||
}
|
}
|
||||||
|
@ -840,7 +846,7 @@ void EditRestrictedBox::createUntilGroup() {
|
||||||
|
|
||||||
void EditRestrictedBox::createUntilVariants() {
|
void EditRestrictedBox::createUntilVariants() {
|
||||||
auto addVariant = [&](int value, const QString &text) {
|
auto addVariant = [&](int value, const QString &text) {
|
||||||
if (!canSave() && _untilGroup->value() != value) {
|
if (!canSave() && _untilGroup->current() != value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_untilVariants.emplace_back(
|
_untilVariants.emplace_back(
|
||||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/background_box.h"
|
#include "boxes/background_box.h"
|
||||||
#include "boxes/stickers_box.h"
|
#include "boxes/stickers_box.h"
|
||||||
#include "chat_helpers/compose/compose_show.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_custom_emoji.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "data/data_changes.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_emoji_statuses.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
|
#include "data/data_premium_limits.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_web_page.h"
|
#include "data/data_web_page.h"
|
||||||
#include "history/view/history_view_element.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 "lang/lang_keys.h"
|
||||||
#include "lottie/lottie_icon.h"
|
#include "lottie/lottie_icon.h"
|
||||||
#include "lottie/lottie_single_player.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "main/main_account.h"
|
|
||||||
#include "main/main_app_config.h"
|
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "settings/settings_common.h"
|
#include "settings/settings_common.h"
|
||||||
#include "settings/settings_premium.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_style.h"
|
||||||
#include "ui/chat/chat_theme.h"
|
#include "ui/chat/chat_theme.h"
|
||||||
#include "ui/effects/path_shift_gradient.h"
|
#include "ui/effects/path_shift_gradient.h"
|
||||||
|
#include "ui/effects/premium_graphics.h"
|
||||||
#include "ui/layers/generic_box.h"
|
#include "ui/layers/generic_box.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
#include "ui/rect.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "window/section_widget.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(
|
ColorSample::ColorSample(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
std::shared_ptr<Ui::ChatStyle> style,
|
std::shared_ptr<Ui::ChatStyle> style,
|
||||||
|
@ -295,47 +319,36 @@ PreviewWrap::PreviewWrap(
|
||||||
, _delegate(std::make_unique<PreviewDelegate>(box, _style.get(), [=] {
|
, _delegate(std::make_unique<PreviewDelegate>(box, _style.get(), [=] {
|
||||||
update();
|
update();
|
||||||
}))
|
}))
|
||||||
, _replyToItem(_history->addNewLocalMessage(
|
, _replyToItem(_history->addNewLocalMessage({
|
||||||
_history->nextNonHistoryEntryId(),
|
.id = _history->nextNonHistoryEntryId(),
|
||||||
(MessageFlag::FakeHistoryItem
|
.flags = (MessageFlag::FakeHistoryItem
|
||||||
| MessageFlag::HasFromId
|
| MessageFlag::HasFromId
|
||||||
| MessageFlag::Post),
|
| MessageFlag::Post),
|
||||||
UserId(), // via
|
.from = _fake->id,
|
||||||
FullReplyTo(),
|
.date = base::unixtime::now(),
|
||||||
base::unixtime::now(), // date
|
}, TextWithEntities{ _peer->isSelf()
|
||||||
_fake->id,
|
? tr::lng_settings_color_reply(tr::now)
|
||||||
QString(), // postAuthor
|
: tr::lng_settings_color_reply_channel(tr::now),
|
||||||
TextWithEntities{ _peer->isSelf()
|
}, MTP_messageMediaEmpty()))
|
||||||
? tr::lng_settings_color_reply(tr::now)
|
, _replyItem(_history->addNewLocalMessage({
|
||||||
: tr::lng_settings_color_reply_channel(tr::now),
|
.id = _history->nextNonHistoryEntryId(),
|
||||||
},
|
.flags = (MessageFlag::FakeHistoryItem
|
||||||
MTP_messageMediaEmpty(),
|
|
||||||
HistoryMessageMarkupData(),
|
|
||||||
uint64(0)))
|
|
||||||
, _replyItem(_history->addNewLocalMessage(
|
|
||||||
_history->nextNonHistoryEntryId(),
|
|
||||||
(MessageFlag::FakeHistoryItem
|
|
||||||
| MessageFlag::HasFromId
|
| MessageFlag::HasFromId
|
||||||
| MessageFlag::HasReplyInfo
|
| MessageFlag::HasReplyInfo
|
||||||
| MessageFlag::Post),
|
| MessageFlag::Post),
|
||||||
UserId(), // via
|
.from = _fake->id,
|
||||||
FullReplyTo{ .messageId = _replyToItem->fullId() },
|
.replyTo = FullReplyTo{.messageId = _replyToItem->fullId() },
|
||||||
base::unixtime::now(), // date
|
.date = base::unixtime::now(),
|
||||||
_fake->id,
|
}, TextWithEntities{ _peer->isSelf()
|
||||||
QString(), // postAuthor
|
? tr::lng_settings_color_text(tr::now)
|
||||||
TextWithEntities{ _peer->isSelf()
|
: tr::lng_settings_color_text_channel(tr::now),
|
||||||
? tr::lng_settings_color_text(tr::now)
|
}, MTP_messageMediaWebPage(
|
||||||
: tr::lng_settings_color_text_channel(tr::now),
|
MTP_flags(0),
|
||||||
},
|
MTP_webPagePending(
|
||||||
MTP_messageMediaWebPage(
|
|
||||||
MTP_flags(0),
|
MTP_flags(0),
|
||||||
MTP_webPagePending(
|
MTP_long(_webpage->id),
|
||||||
MTP_flags(0),
|
MTPstring(),
|
||||||
MTP_long(_webpage->id),
|
MTP_int(0)))))
|
||||||
MTPstring(),
|
|
||||||
MTP_int(0))),
|
|
||||||
HistoryMessageMarkupData(),
|
|
||||||
uint64(0)))
|
|
||||||
, _element(_replyItem->createView(_delegate.get()))
|
, _element(_replyItem->createView(_delegate.get()))
|
||||||
, _position(0, st::msgMargin.bottom()) {
|
, _position(0, st::msgMargin.bottom()) {
|
||||||
_style->apply(_theme.get());
|
_style->apply(_theme.get());
|
||||||
|
@ -437,6 +450,108 @@ HistoryView::Context PreviewDelegate::elementContext() {
|
||||||
return HistoryView::Context::AdminLog;
|
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 {
|
struct SetValues {
|
||||||
uint8 colorIndex = 0;
|
uint8 colorIndex = 0;
|
||||||
DocumentId backgroundEmojiId = 0;
|
DocumentId backgroundEmojiId = 0;
|
||||||
|
@ -541,16 +656,13 @@ void Apply(
|
||||||
: peerColors->requiredChannelLevelFor(
|
: peerColors->requiredChannelLevelFor(
|
||||||
peer->id,
|
peer->id,
|
||||||
values.colorIndex);
|
values.colorIndex);
|
||||||
|
const auto limits = Data::LevelLimits(&peer->session());
|
||||||
const auto iconRequired = values.backgroundEmojiId
|
const auto iconRequired = values.backgroundEmojiId
|
||||||
? session->account().appConfig().get<int>(
|
? limits.channelBgIconLevelMin()
|
||||||
"channel_bg_icon_level_min",
|
|
||||||
5)
|
|
||||||
: 0;
|
: 0;
|
||||||
const auto statusRequired = (values.statusChanged
|
const auto statusRequired = (values.statusChanged
|
||||||
&& values.statusId)
|
&& values.statusId)
|
||||||
? session->account().appConfig().get<int>(
|
? limits.channelEmojiStatusLevelMin()
|
||||||
"channel_emoji_status_level_min",
|
|
||||||
8)
|
|
||||||
: 0;
|
: 0;
|
||||||
const auto required = std::max({
|
const auto required = std::max({
|
||||||
colorRequired,
|
colorRequired,
|
||||||
|
@ -726,6 +838,7 @@ struct ButtonWithEmoji {
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
std::shared_ptr<Ui::ChatStyle> style,
|
std::shared_ptr<Ui::ChatStyle> style,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
rpl::producer<uint8> colorIndexValue,
|
rpl::producer<uint8> colorIndexValue,
|
||||||
rpl::producer<DocumentId> emojiIdValue,
|
rpl::producer<DocumentId> emojiIdValue,
|
||||||
Fn<void(DocumentId)> emojiIdChosen) {
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] object_ptr<Ui::SettingsButton> CreateEmojiStatusButton(
|
[[nodiscard]] object_ptr<Ui::SettingsButton> CreateEmojiStatusButton(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
|
not_null<ChannelData*> channel,
|
||||||
rpl::producer<DocumentId> statusIdValue,
|
rpl::producer<DocumentId> statusIdValue,
|
||||||
Fn<void(DocumentId,TimeId)> statusIdChosen,
|
Fn<void(DocumentId,TimeId)> statusIdChosen,
|
||||||
bool group) {
|
bool group) {
|
||||||
const auto button = ButtonStyleWithRightEmoji(parent);
|
const auto button = ButtonStyleWithRightEmoji(parent);
|
||||||
|
const auto &phrase = group
|
||||||
|
? tr::lng_edit_channel_status_group
|
||||||
|
: tr::lng_edit_channel_status;
|
||||||
auto result = Settings::CreateButtonWithIcon(
|
auto result = Settings::CreateButtonWithIcon(
|
||||||
parent,
|
parent,
|
||||||
(group
|
phrase(),
|
||||||
? tr::lng_edit_channel_status_group()
|
|
||||||
: tr::lng_edit_channel_status()),
|
|
||||||
*button.st,
|
*button.st,
|
||||||
{ &st::menuBlueIconEmojiStatus });
|
{ &st::menuBlueIconEmojiStatus });
|
||||||
const auto raw = result.data();
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1036,6 +1172,14 @@ struct ButtonWithEmoji {
|
||||||
}
|
}
|
||||||
}, right->lifetime());
|
}, right->lifetime());
|
||||||
|
|
||||||
|
AddLevelBadge(
|
||||||
|
Data::LevelLimits(&channel->session()).groupEmojiStickersLevelMin(),
|
||||||
|
raw,
|
||||||
|
right,
|
||||||
|
channel,
|
||||||
|
button.st->padding,
|
||||||
|
tr::lng_group_emoji());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1068,38 +1212,15 @@ void EditPeerColorBox(
|
||||||
state->index = peer->colorIndex();
|
state->index = peer->colorIndex();
|
||||||
state->emojiId = peer->backgroundEmojiId();
|
state->emojiId = peer->backgroundEmojiId();
|
||||||
state->statusId = peer->emojiStatusId();
|
state->statusId = peer->emojiStatusId();
|
||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
const auto divider = Ui::CreateChild<Ui::BoxContentDivider>(
|
Settings::AddDividerTextWithLottie(box->verticalLayout(), {
|
||||||
box.get());
|
.lottie = u"palette"_q,
|
||||||
const auto verticalLayout = box->verticalLayout()->add(
|
.lottieSize = st::settingsCloudPasswordIconSize,
|
||||||
object_ptr<Ui::VerticalLayout>(box.get()));
|
.lottieMargins = st::peerAppearanceIconPadding,
|
||||||
|
.showFinished = box->showFinishes(),
|
||||||
auto icon = CreateLottieIcon(
|
.about = tr::lng_boost_group_about(Ui::Text::WithEntities),
|
||||||
verticalLayout,
|
.aboutMargins = st::peerAppearanceCoverLabelMargin,
|
||||||
{
|
|
||||||
.name = u"palette"_q,
|
|
||||||
.sizeOverride = {
|
|
||||||
st::settingsCloudPasswordIconSize,
|
|
||||||
st::settingsCloudPasswordIconSize,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
st::peerAppearanceIconPadding);
|
|
||||||
box->setShowFinishedCallback([animate = std::move(icon.animate)] {
|
|
||||||
animate(anim::repeat::once);
|
|
||||||
});
|
});
|
||||||
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 {
|
} else {
|
||||||
box->addRow(object_ptr<PreviewWrap>(
|
box->addRow(object_ptr<PreviewWrap>(
|
||||||
box,
|
box,
|
||||||
|
@ -1135,6 +1256,7 @@ void EditPeerColorBox(
|
||||||
container,
|
container,
|
||||||
show,
|
show,
|
||||||
style,
|
style,
|
||||||
|
peer,
|
||||||
state->index.value(),
|
state->index.value(),
|
||||||
state->emojiId.value(),
|
state->emojiId.value(),
|
||||||
[=](DocumentId id) { state->emojiId = id; }));
|
[=](DocumentId id) { state->emojiId = id; }));
|
||||||
|
@ -1150,20 +1272,35 @@ void EditPeerColorBox(
|
||||||
|
|
||||||
if (const auto channel = peer->asChannel()) {
|
if (const auto channel = peer->asChannel()) {
|
||||||
Ui::AddSkip(container, st::settingsColorSampleSkip);
|
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,
|
container,
|
||||||
(group
|
phrase(),
|
||||||
? tr::lng_edit_channel_wallpaper_group()
|
|
||||||
: tr::lng_edit_channel_wallpaper()),
|
|
||||||
st::peerAppearanceButton,
|
st::peerAppearanceButton,
|
||||||
{ &st::menuBlueIconWallpaper }
|
{ &st::menuBlueIconWallpaper }
|
||||||
)->setClickedCallback([=] {
|
);
|
||||||
|
button->setClickedCallback([=] {
|
||||||
const auto usage = ChatHelpers::WindowUsage::PremiumPromo;
|
const auto usage = ChatHelpers::WindowUsage::PremiumPromo;
|
||||||
if (const auto strong = show->resolveWindow(usage)) {
|
if (const auto strong = show->resolveWindow(usage)) {
|
||||||
show->show(Box<BackgroundBox>(strong, channel));
|
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::AddSkip(container, st::settingsColorSampleSkip);
|
||||||
Ui::AddDividerText(
|
Ui::AddDividerText(
|
||||||
container,
|
container,
|
||||||
|
@ -1201,6 +1338,7 @@ void EditPeerColorBox(
|
||||||
container->add(CreateEmojiStatusButton(
|
container->add(CreateEmojiStatusButton(
|
||||||
container,
|
container,
|
||||||
show,
|
show,
|
||||||
|
channel,
|
||||||
state->statusId.value(),
|
state->statusId.value(),
|
||||||
[=](DocumentId id, TimeId until) {
|
[=](DocumentId id, TimeId until) {
|
||||||
state->statusId = id;
|
state->statusId = id;
|
||||||
|
|
|
@ -25,7 +25,7 @@ void EditPeerHistoryVisibilityBox(
|
||||||
|
|
||||||
box->setTitle(tr::lng_manage_history_visibility_title());
|
box->setTitle(tr::lng_manage_history_visibility_title());
|
||||||
box->addButton(tr::lng_settings_save(), [=] {
|
box->addButton(tr::lng_settings_save(), [=] {
|
||||||
savedCallback(historyVisibility->value());
|
savedCallback(historyVisibility->current());
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
});
|
});
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
|
|
@ -76,7 +76,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Privacy getPrivacy() const {
|
[[nodiscard]] Privacy getPrivacy() const {
|
||||||
return _controls.privacy->value();
|
return _controls.privacy->current();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool noForwards() const {
|
[[nodiscard]] bool noForwards() const {
|
||||||
|
@ -238,7 +238,7 @@ void Controller::createContent() {
|
||||||
}, wrap->lifetime());
|
}, wrap->lifetime());
|
||||||
} else {
|
} else {
|
||||||
_controls.whoSendWrap->toggle(
|
_controls.whoSendWrap->toggle(
|
||||||
(_controls.privacy->value() == Privacy::HasUsername),
|
(_controls.privacy->current() == Privacy::HasUsername),
|
||||||
anim::type::instant);
|
anim::type::instant);
|
||||||
}
|
}
|
||||||
auto joinToWrite = _controls.joinToWrite
|
auto joinToWrite = _controls.joinToWrite
|
||||||
|
@ -299,7 +299,7 @@ void Controller::createContent() {
|
||||||
if (_linkOnly) {
|
if (_linkOnly) {
|
||||||
_controls.inviteLinkWrap->show(anim::type::instant);
|
_controls.inviteLinkWrap->show(anim::type::instant);
|
||||||
} else {
|
} else {
|
||||||
if (_controls.privacy->value() == Privacy::NoUsername) {
|
if (_controls.privacy->current() == Privacy::NoUsername) {
|
||||||
checkUsernameAvailability();
|
checkUsernameAvailability();
|
||||||
}
|
}
|
||||||
const auto forShowing = _dataSavedValue
|
const auto forShowing = _dataSavedValue
|
||||||
|
@ -474,7 +474,7 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
|
||||||
&Ui::UsernameInput::changed,
|
&Ui::UsernameInput::changed,
|
||||||
[this] { usernameChanged(); });
|
[this] { usernameChanged(); });
|
||||||
|
|
||||||
const auto shown = (_controls.privacy->value() == Privacy::HasUsername);
|
const auto shown = (_controls.privacy->current() == Privacy::HasUsername);
|
||||||
result->toggle(shown, anim::type::instant);
|
result->toggle(shown, anim::type::instant);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -539,7 +539,7 @@ void Controller::checkUsernameAvailability() {
|
||||||
if (!_controls.usernameInput) {
|
if (!_controls.usernameInput) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto initial = (_controls.privacy->value() != Privacy::HasUsername);
|
const auto initial = (_controls.privacy->current() != Privacy::HasUsername);
|
||||||
const auto checking = initial
|
const auto checking = initial
|
||||||
? u".bad."_q
|
? u".bad."_q
|
||||||
: getUsernameInput();
|
: getUsernameInput();
|
||||||
|
@ -573,11 +573,11 @@ void Controller::checkUsernameAvailability() {
|
||||||
_controls.privacy->setValue(Privacy::NoUsername);
|
_controls.privacy->setValue(Privacy::NoUsername);
|
||||||
} else if (type == u"CHANNELS_ADMIN_PUBLIC_TOO_MUCH"_q) {
|
} else if (type == u"CHANNELS_ADMIN_PUBLIC_TOO_MUCH"_q) {
|
||||||
_usernameState = UsernameState::TooMany;
|
_usernameState = UsernameState::TooMany;
|
||||||
if (_controls.privacy->value() == Privacy::HasUsername) {
|
if (_controls.privacy->current() == Privacy::HasUsername) {
|
||||||
askUsernameRevoke();
|
askUsernameRevoke();
|
||||||
}
|
}
|
||||||
} else if (initial) {
|
} else if (initial) {
|
||||||
if (_controls.privacy->value() == Privacy::HasUsername) {
|
if (_controls.privacy->current() == Privacy::HasUsername) {
|
||||||
showUsernameEmpty();
|
showUsernameEmpty();
|
||||||
setFocusUsername();
|
setFocusUsername();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/event_filter.h"
|
#include "base/event_filter.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
|
#include "data/data_premium_limits.h"
|
||||||
#include "boxes/peer_list_box.h"
|
#include "boxes/peer_list_box.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_cloud_themes.h"
|
#include "data/data_cloud_themes.h"
|
||||||
|
@ -424,14 +425,9 @@ Ui::BoostCounters ParseBoostCounters(
|
||||||
}
|
}
|
||||||
|
|
||||||
Ui::BoostFeatures LookupBoostFeatures(not_null<ChannelData*> channel) {
|
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 nameColorsByLevel = base::flat_map<int, int>();
|
||||||
auto linkStylesByLevel = 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 peerColors = &channel->session().api().peerColors();
|
||||||
const auto &list = group
|
const auto &list = group
|
||||||
? peerColors->requiredLevelsGroup()
|
? peerColors->requiredLevelsGroup()
|
||||||
|
@ -447,22 +443,23 @@ Ui::BoostFeatures LookupBoostFeatures(not_null<ChannelData*> channel) {
|
||||||
if (themes.empty()) {
|
if (themes.empty()) {
|
||||||
channel->owner().cloudThemes().refreshChatThemes();
|
channel->owner().cloudThemes().refreshChatThemes();
|
||||||
}
|
}
|
||||||
|
const auto levelLimits = Data::LevelLimits(&channel->session());
|
||||||
return Ui::BoostFeatures{
|
return Ui::BoostFeatures{
|
||||||
.nameColorsByLevel = std::move(nameColorsByLevel),
|
.nameColorsByLevel = std::move(nameColorsByLevel),
|
||||||
.linkStylesByLevel = std::move(linkStylesByLevel),
|
.linkStylesByLevel = std::move(linkStylesByLevel),
|
||||||
.linkLogoLevel = get(u"channel_bg_icon_level_min"_q, 4, !group),
|
.linkLogoLevel = group ? 0 : levelLimits.channelBgIconLevelMin(),
|
||||||
.transcribeLevel = get(u"group_transcribe_level_min"_q, 6, group),
|
.transcribeLevel = group ? levelLimits.groupTranscribeLevelMin() : 0,
|
||||||
.emojiPackLevel = get(u"group_emoji_stickers_level_min"_q, 4, group),
|
.emojiPackLevel = group ? levelLimits.groupEmojiStickersLevelMin() : 0,
|
||||||
.emojiStatusLevel = get(group
|
.emojiStatusLevel = group
|
||||||
? u"group_emoji_status_level_min"_q
|
? levelLimits.groupEmojiStatusLevelMin()
|
||||||
: u"channel_emoji_status_level_min"_q, 8),
|
: levelLimits.channelEmojiStatusLevelMin(),
|
||||||
.wallpaperLevel = get(group
|
.wallpaperLevel = group
|
||||||
? u"group_wallpaper_level_min"_q
|
? levelLimits.groupWallpaperLevelMin()
|
||||||
: u"channel_wallpaper_level_min"_q, 9),
|
: levelLimits.channelWallpaperLevelMin(),
|
||||||
.wallpapersCount = themes.empty() ? 8 : int(themes.size()),
|
.wallpapersCount = themes.empty() ? 8 : int(themes.size()),
|
||||||
.customWallpaperLevel = get(group
|
.customWallpaperLevel = group
|
||||||
? u"channel_custom_wallpaper_level_min"_q
|
? levelLimits.groupCustomWallpaperLevelMin()
|
||||||
: u"group_custom_wallpaper_level_min"_q, 10),
|
: levelLimits.channelCustomWallpaperLevelMin(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1142,7 +1142,7 @@ void AccountsLimitBox(
|
||||||
const auto ref = QString();
|
const auto ref = QString();
|
||||||
|
|
||||||
const auto wasAccount = &session->account();
|
const auto wasAccount = &session->account();
|
||||||
const auto nowAccount = accounts[group->value()];
|
const auto nowAccount = accounts[group->current()];
|
||||||
if (wasAccount == nowAccount) {
|
if (wasAccount == nowAccount) {
|
||||||
Settings::ShowPremium(session, ref);
|
Settings::ShowPremium(session, ref);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/boxes/confirm_box.h"
|
#include "ui/boxes/confirm_box.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
|
#include "settings/settings_business.h"
|
||||||
#include "settings/settings_premium.h"
|
#include "settings/settings_premium.h"
|
||||||
#include "lottie/lottie_single_player.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "history/view/media/history_view_sticker.h"
|
#include "history/view/media/history_view_sticker.h"
|
||||||
|
@ -59,7 +60,7 @@ constexpr auto kStarPeriod = 3 * crl::time(1000);
|
||||||
using Data::ReactionId;
|
using Data::ReactionId;
|
||||||
|
|
||||||
struct Descriptor {
|
struct Descriptor {
|
||||||
PremiumPreview section = PremiumPreview::Stickers;
|
PremiumFeature section = PremiumFeature::Stickers;
|
||||||
DocumentData *requestedSticker = nullptr;
|
DocumentData *requestedSticker = nullptr;
|
||||||
bool fromSettings = false;
|
bool fromSettings = false;
|
||||||
Fn<void()> hiddenCallback;
|
Fn<void()> hiddenCallback;
|
||||||
|
@ -90,88 +91,118 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
||||||
media->videoThumbnailWanted(origin);
|
media->videoThumbnailWanted(origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<QString> SectionTitle(PremiumPreview section) {
|
[[nodiscard]] rpl::producer<QString> SectionTitle(PremiumFeature section) {
|
||||||
switch (section) {
|
switch (section) {
|
||||||
case PremiumPreview::Wallpapers:
|
case PremiumFeature::Wallpapers:
|
||||||
return tr::lng_premium_summary_subtitle_wallpapers();
|
return tr::lng_premium_summary_subtitle_wallpapers();
|
||||||
case PremiumPreview::Stories:
|
case PremiumFeature::Stories:
|
||||||
return tr::lng_premium_summary_subtitle_stories();
|
return tr::lng_premium_summary_subtitle_stories();
|
||||||
case PremiumPreview::DoubleLimits:
|
case PremiumFeature::DoubleLimits:
|
||||||
return tr::lng_premium_summary_subtitle_double_limits();
|
return tr::lng_premium_summary_subtitle_double_limits();
|
||||||
case PremiumPreview::MoreUpload:
|
case PremiumFeature::MoreUpload:
|
||||||
return tr::lng_premium_summary_subtitle_more_upload();
|
return tr::lng_premium_summary_subtitle_more_upload();
|
||||||
case PremiumPreview::FasterDownload:
|
case PremiumFeature::FasterDownload:
|
||||||
return tr::lng_premium_summary_subtitle_faster_download();
|
return tr::lng_premium_summary_subtitle_faster_download();
|
||||||
case PremiumPreview::VoiceToText:
|
case PremiumFeature::VoiceToText:
|
||||||
return tr::lng_premium_summary_subtitle_voice_to_text();
|
return tr::lng_premium_summary_subtitle_voice_to_text();
|
||||||
case PremiumPreview::NoAds:
|
case PremiumFeature::NoAds:
|
||||||
return tr::lng_premium_summary_subtitle_no_ads();
|
return tr::lng_premium_summary_subtitle_no_ads();
|
||||||
case PremiumPreview::EmojiStatus:
|
case PremiumFeature::EmojiStatus:
|
||||||
return tr::lng_premium_summary_subtitle_emoji_status();
|
return tr::lng_premium_summary_subtitle_emoji_status();
|
||||||
case PremiumPreview::InfiniteReactions:
|
case PremiumFeature::InfiniteReactions:
|
||||||
return tr::lng_premium_summary_subtitle_infinite_reactions();
|
return tr::lng_premium_summary_subtitle_infinite_reactions();
|
||||||
case PremiumPreview::TagsForMessages:
|
case PremiumFeature::TagsForMessages:
|
||||||
return tr::lng_premium_summary_subtitle_tags_for_messages();
|
return tr::lng_premium_summary_subtitle_tags_for_messages();
|
||||||
case PremiumPreview::LastSeen:
|
case PremiumFeature::LastSeen:
|
||||||
return tr::lng_premium_summary_subtitle_last_seen();
|
return tr::lng_premium_summary_subtitle_last_seen();
|
||||||
case PremiumPreview::MessagePrivacy:
|
case PremiumFeature::MessagePrivacy:
|
||||||
return tr::lng_premium_summary_subtitle_message_privacy();
|
return tr::lng_premium_summary_subtitle_message_privacy();
|
||||||
case PremiumPreview::Stickers:
|
case PremiumFeature::Stickers:
|
||||||
return tr::lng_premium_summary_subtitle_premium_stickers();
|
return tr::lng_premium_summary_subtitle_premium_stickers();
|
||||||
case PremiumPreview::AnimatedEmoji:
|
case PremiumFeature::AnimatedEmoji:
|
||||||
return tr::lng_premium_summary_subtitle_animated_emoji();
|
return tr::lng_premium_summary_subtitle_animated_emoji();
|
||||||
case PremiumPreview::AdvancedChatManagement:
|
case PremiumFeature::AdvancedChatManagement:
|
||||||
return tr::lng_premium_summary_subtitle_advanced_chat_management();
|
return tr::lng_premium_summary_subtitle_advanced_chat_management();
|
||||||
case PremiumPreview::ProfileBadge:
|
case PremiumFeature::ProfileBadge:
|
||||||
return tr::lng_premium_summary_subtitle_profile_badge();
|
return tr::lng_premium_summary_subtitle_profile_badge();
|
||||||
case PremiumPreview::AnimatedUserpics:
|
case PremiumFeature::AnimatedUserpics:
|
||||||
return tr::lng_premium_summary_subtitle_animated_userpics();
|
return tr::lng_premium_summary_subtitle_animated_userpics();
|
||||||
case PremiumPreview::RealTimeTranslation:
|
case PremiumFeature::RealTimeTranslation:
|
||||||
return tr::lng_premium_summary_subtitle_translation();
|
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) {
|
switch (section) {
|
||||||
case PremiumPreview::Wallpapers:
|
case PremiumFeature::Wallpapers:
|
||||||
return tr::lng_premium_summary_about_wallpapers();
|
return tr::lng_premium_summary_about_wallpapers();
|
||||||
case PremiumPreview::Stories:
|
case PremiumFeature::Stories:
|
||||||
return tr::lng_premium_summary_about_stories();
|
return tr::lng_premium_summary_about_stories();
|
||||||
case PremiumPreview::DoubleLimits:
|
case PremiumFeature::DoubleLimits:
|
||||||
return tr::lng_premium_summary_about_double_limits();
|
return tr::lng_premium_summary_about_double_limits();
|
||||||
case PremiumPreview::MoreUpload:
|
case PremiumFeature::MoreUpload:
|
||||||
return tr::lng_premium_summary_about_more_upload();
|
return tr::lng_premium_summary_about_more_upload();
|
||||||
case PremiumPreview::FasterDownload:
|
case PremiumFeature::FasterDownload:
|
||||||
return tr::lng_premium_summary_about_faster_download();
|
return tr::lng_premium_summary_about_faster_download();
|
||||||
case PremiumPreview::VoiceToText:
|
case PremiumFeature::VoiceToText:
|
||||||
return tr::lng_premium_summary_about_voice_to_text();
|
return tr::lng_premium_summary_about_voice_to_text();
|
||||||
case PremiumPreview::NoAds:
|
case PremiumFeature::NoAds:
|
||||||
return tr::lng_premium_summary_about_no_ads();
|
return tr::lng_premium_summary_about_no_ads();
|
||||||
case PremiumPreview::EmojiStatus:
|
case PremiumFeature::EmojiStatus:
|
||||||
return tr::lng_premium_summary_about_emoji_status();
|
return tr::lng_premium_summary_about_emoji_status();
|
||||||
case PremiumPreview::InfiniteReactions:
|
case PremiumFeature::InfiniteReactions:
|
||||||
return tr::lng_premium_summary_about_infinite_reactions();
|
return tr::lng_premium_summary_about_infinite_reactions();
|
||||||
case PremiumPreview::TagsForMessages:
|
case PremiumFeature::TagsForMessages:
|
||||||
return tr::lng_premium_summary_about_tags_for_messages();
|
return tr::lng_premium_summary_about_tags_for_messages();
|
||||||
case PremiumPreview::LastSeen:
|
case PremiumFeature::LastSeen:
|
||||||
return tr::lng_premium_summary_about_last_seen();
|
return tr::lng_premium_summary_about_last_seen();
|
||||||
case PremiumPreview::MessagePrivacy:
|
case PremiumFeature::MessagePrivacy:
|
||||||
return tr::lng_premium_summary_about_message_privacy();
|
return tr::lng_premium_summary_about_message_privacy();
|
||||||
case PremiumPreview::Stickers:
|
case PremiumFeature::Stickers:
|
||||||
return tr::lng_premium_summary_about_premium_stickers();
|
return tr::lng_premium_summary_about_premium_stickers();
|
||||||
case PremiumPreview::AnimatedEmoji:
|
case PremiumFeature::AnimatedEmoji:
|
||||||
return tr::lng_premium_summary_about_animated_emoji();
|
return tr::lng_premium_summary_about_animated_emoji();
|
||||||
case PremiumPreview::AdvancedChatManagement:
|
case PremiumFeature::AdvancedChatManagement:
|
||||||
return tr::lng_premium_summary_about_advanced_chat_management();
|
return tr::lng_premium_summary_about_advanced_chat_management();
|
||||||
case PremiumPreview::ProfileBadge:
|
case PremiumFeature::ProfileBadge:
|
||||||
return tr::lng_premium_summary_about_profile_badge();
|
return tr::lng_premium_summary_about_profile_badge();
|
||||||
case PremiumPreview::AnimatedUserpics:
|
case PremiumFeature::AnimatedUserpics:
|
||||||
return tr::lng_premium_summary_about_animated_userpics();
|
return tr::lng_premium_summary_about_animated_userpics();
|
||||||
case PremiumPreview::RealTimeTranslation:
|
case PremiumFeature::RealTimeTranslation:
|
||||||
return tr::lng_premium_summary_about_translation();
|
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(
|
[[nodiscard]] object_ptr<Ui::RpWidget> ChatBackPreview(
|
||||||
|
@ -463,33 +494,40 @@ struct VideoPreviewDocument {
|
||||||
RectPart align = RectPart::Bottom;
|
RectPart align = RectPart::Bottom;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] bool VideoAlignToTop(PremiumPreview section) {
|
[[nodiscard]] bool VideoAlignToTop(PremiumFeature section) {
|
||||||
return (section == PremiumPreview::MoreUpload)
|
return (section == PremiumFeature::MoreUpload)
|
||||||
|| (section == PremiumPreview::NoAds)
|
|| (section == PremiumFeature::NoAds)
|
||||||
|| (section == PremiumPreview::AnimatedEmoji);
|
|| (section == PremiumFeature::AnimatedEmoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] DocumentData *LookupVideo(
|
[[nodiscard]] DocumentData *LookupVideo(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
PremiumPreview section) {
|
PremiumFeature section) {
|
||||||
const auto name = [&] {
|
const auto name = [&] {
|
||||||
switch (section) {
|
switch (section) {
|
||||||
case PremiumPreview::MoreUpload: return "more_upload";
|
case PremiumFeature::MoreUpload: return "more_upload";
|
||||||
case PremiumPreview::FasterDownload: return "faster_download";
|
case PremiumFeature::FasterDownload: return "faster_download";
|
||||||
case PremiumPreview::VoiceToText: return "voice_to_text";
|
case PremiumFeature::VoiceToText: return "voice_to_text";
|
||||||
case PremiumPreview::NoAds: return "no_ads";
|
case PremiumFeature::NoAds: return "no_ads";
|
||||||
case PremiumPreview::AnimatedEmoji: return "animated_emoji";
|
case PremiumFeature::AnimatedEmoji: return "animated_emoji";
|
||||||
case PremiumPreview::AdvancedChatManagement:
|
case PremiumFeature::AdvancedChatManagement:
|
||||||
return "advanced_chat_management";
|
return "advanced_chat_management";
|
||||||
case PremiumPreview::EmojiStatus: return "emoji_status";
|
case PremiumFeature::EmojiStatus: return "emoji_status";
|
||||||
case PremiumPreview::InfiniteReactions: return "infinite_reactions";
|
case PremiumFeature::InfiniteReactions: return "infinite_reactions";
|
||||||
case PremiumPreview::TagsForMessages: return "saved_tags";
|
case PremiumFeature::TagsForMessages: return "saved_tags";
|
||||||
case PremiumPreview::ProfileBadge: return "profile_badge";
|
case PremiumFeature::ProfileBadge: return "profile_badge";
|
||||||
case PremiumPreview::AnimatedUserpics: return "animated_userpics";
|
case PremiumFeature::AnimatedUserpics: return "animated_userpics";
|
||||||
case PremiumPreview::RealTimeTranslation: return "translations";
|
case PremiumFeature::RealTimeTranslation: return "translations";
|
||||||
case PremiumPreview::Wallpapers: return "wallpapers";
|
case PremiumFeature::Wallpapers: return "wallpapers";
|
||||||
case PremiumPreview::LastSeen: return "last_seen";
|
case PremiumFeature::LastSeen: return "last_seen";
|
||||||
case PremiumPreview::MessagePrivacy: return "message_privacy";
|
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 "";
|
return "";
|
||||||
}();
|
}();
|
||||||
|
@ -716,7 +754,7 @@ struct VideoPreviewDocument {
|
||||||
[[nodiscard]] not_null<Ui::RpWidget*> GenericPreview(
|
[[nodiscard]] not_null<Ui::RpWidget*> GenericPreview(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
PremiumPreview section,
|
PremiumFeature section,
|
||||||
Fn<void()> readyCallback) {
|
Fn<void()> readyCallback) {
|
||||||
const auto result = Ui::CreateChild<Ui::RpWidget>(parent.get());
|
const auto result = Ui::CreateChild<Ui::RpWidget>(parent.get());
|
||||||
result->show();
|
result->show();
|
||||||
|
@ -757,10 +795,10 @@ struct VideoPreviewDocument {
|
||||||
[[nodiscard]] not_null<Ui::RpWidget*> GenerateDefaultPreview(
|
[[nodiscard]] not_null<Ui::RpWidget*> GenerateDefaultPreview(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
PremiumPreview section,
|
PremiumFeature section,
|
||||||
Fn<void()> readyCallback) {
|
Fn<void()> readyCallback) {
|
||||||
switch (section) {
|
switch (section) {
|
||||||
case PremiumPreview::Stickers:
|
case PremiumFeature::Stickers:
|
||||||
return StickersPreview(parent, std::move(show), readyCallback);
|
return StickersPreview(parent, std::move(show), readyCallback);
|
||||||
default:
|
default:
|
||||||
return GenericPreview(
|
return GenericPreview(
|
||||||
|
@ -784,8 +822,8 @@ struct VideoPreviewDocument {
|
||||||
|
|
||||||
[[nodiscard]] object_ptr<Ui::RpWidget> CreateSwitch(
|
[[nodiscard]] object_ptr<Ui::RpWidget> CreateSwitch(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
not_null<rpl::variable<PremiumPreview>*> selected,
|
not_null<rpl::variable<PremiumFeature>*> selected,
|
||||||
std::vector<PremiumPreview> order) {
|
std::vector<PremiumFeature> order) {
|
||||||
const auto padding = st::premiumDotPadding;
|
const auto padding = st::premiumDotPadding;
|
||||||
const auto width = padding.left() + st::premiumDot + padding.right();
|
const auto width = padding.left() + st::premiumDot + padding.right();
|
||||||
const auto height = padding.top() + st::premiumDot + padding.bottom();
|
const auto height = padding.top() + st::premiumDot + padding.bottom();
|
||||||
|
@ -856,14 +894,20 @@ void PreviewBox(
|
||||||
Ui::Animations::Simple animation;
|
Ui::Animations::Simple animation;
|
||||||
Fn<void()> preload;
|
Fn<void()> preload;
|
||||||
std::vector<Hiding> hiding;
|
std::vector<Hiding> hiding;
|
||||||
rpl::variable<PremiumPreview> selected;
|
rpl::variable<PremiumFeature> selected;
|
||||||
std::vector<PremiumPreview> order;
|
std::vector<PremiumFeature> order;
|
||||||
};
|
};
|
||||||
const auto state = outer->lifetime().make_state<State>();
|
const auto state = outer->lifetime().make_state<State>();
|
||||||
state->selected = descriptor.section;
|
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);
|
const auto it = ranges::find(state->order, section);
|
||||||
return (it == end(state->order))
|
return (it == end(state->order))
|
||||||
? 0
|
? 0
|
||||||
|
@ -906,7 +950,7 @@ void PreviewBox(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto now = state->selected.current();
|
const auto now = state->selected.current();
|
||||||
if (now != PremiumPreview::Stickers && !state->stickersPreload) {
|
if (now != PremiumFeature::Stickers && !state->stickersPreload) {
|
||||||
const auto ready = [=] {
|
const auto ready = [=] {
|
||||||
if (state->stickersPreload) {
|
if (state->stickersPreload) {
|
||||||
state->stickersPreloadReady = true;
|
state->stickersPreloadReady = true;
|
||||||
|
@ -917,14 +961,14 @@ void PreviewBox(
|
||||||
state->stickersPreload = GenerateDefaultPreview(
|
state->stickersPreload = GenerateDefaultPreview(
|
||||||
outer,
|
outer,
|
||||||
show,
|
show,
|
||||||
PremiumPreview::Stickers,
|
PremiumFeature::Stickers,
|
||||||
ready);
|
ready);
|
||||||
state->stickersPreload->hide();
|
state->stickersPreload->hide();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (descriptor.section) {
|
switch (descriptor.section) {
|
||||||
case PremiumPreview::Stickers:
|
case PremiumFeature::Stickers:
|
||||||
state->content = media
|
state->content = media
|
||||||
? StickerPreview(outer, show, media, state->preload)
|
? StickerPreview(outer, show, media, state->preload)
|
||||||
: StickersPreview(outer, show, state->preload);
|
: StickersPreview(outer, show, state->preload);
|
||||||
|
@ -940,7 +984,7 @@ void PreviewBox(
|
||||||
|
|
||||||
state->selected.value(
|
state->selected.value(
|
||||||
) | rpl::combine_previous(
|
) | rpl::combine_previous(
|
||||||
) | rpl::start_with_next([=](PremiumPreview was, PremiumPreview now) {
|
) | rpl::start_with_next([=](PremiumFeature was, PremiumFeature now) {
|
||||||
const auto animationCallback = [=] {
|
const auto animationCallback = [=] {
|
||||||
if (!state->animation.animating()) {
|
if (!state->animation.animating()) {
|
||||||
for (const auto &hiding : base::take(state->hiding)) {
|
for (const auto &hiding : base::take(state->hiding)) {
|
||||||
|
@ -982,7 +1026,7 @@ void PreviewBox(
|
||||||
.leftTill = state->content->x() - start,
|
.leftTill = state->content->x() - start,
|
||||||
});
|
});
|
||||||
state->leftFrom = start;
|
state->leftFrom = start;
|
||||||
if (now == PremiumPreview::Stickers && state->stickersPreload) {
|
if (now == PremiumFeature::Stickers && state->stickersPreload) {
|
||||||
state->content = base::take(state->stickersPreload);
|
state->content = base::take(state->stickersPreload);
|
||||||
state->content->show();
|
state->content->show();
|
||||||
if (base::take(state->stickersPreloadReady)) {
|
if (base::take(state->stickersPreloadReady)) {
|
||||||
|
@ -1053,14 +1097,14 @@ void PreviewBox(
|
||||||
return Settings::LookupPremiumRef(state->selected.current());
|
return Settings::LookupPremiumRef(state->selected.current());
|
||||||
};
|
};
|
||||||
auto unlock = state->selected.value(
|
auto unlock = state->selected.value(
|
||||||
) | rpl::map([=](PremiumPreview section) {
|
) | rpl::map([=](PremiumFeature section) {
|
||||||
return (section == PremiumPreview::InfiniteReactions)
|
return (section == PremiumFeature::InfiniteReactions)
|
||||||
? tr::lng_premium_unlock_reactions()
|
? tr::lng_premium_unlock_reactions()
|
||||||
: (section == PremiumPreview::Stickers)
|
: (section == PremiumFeature::Stickers)
|
||||||
? tr::lng_premium_unlock_stickers()
|
? tr::lng_premium_unlock_stickers()
|
||||||
: (section == PremiumPreview::AnimatedEmoji)
|
: (section == PremiumFeature::AnimatedEmoji)
|
||||||
? tr::lng_premium_unlock_emoji()
|
? tr::lng_premium_unlock_emoji()
|
||||||
: (section == PremiumPreview::EmojiStatus)
|
: (section == PremiumFeature::EmojiStatus)
|
||||||
? tr::lng_premium_unlock_status()
|
? tr::lng_premium_unlock_status()
|
||||||
: tr::lng_premium_more_about();
|
: tr::lng_premium_more_about();
|
||||||
}) | rpl::flatten_latest();
|
}) | rpl::flatten_latest();
|
||||||
|
@ -1207,18 +1251,25 @@ void Show(
|
||||||
descriptor.shownCallback(raw);
|
descriptor.shownCallback(raw);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (descriptor.section == PremiumPreview::DoubleLimits) {
|
} else if (descriptor.section == PremiumFeature::DoubleLimits) {
|
||||||
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||||
DoubledLimitsPreviewBox(box, &show->session());
|
DoubledLimitsPreviewBox(box, &show->session());
|
||||||
DecorateListPromoBox(box, show, descriptor);
|
DecorateListPromoBox(box, show, descriptor);
|
||||||
}));
|
}));
|
||||||
return;
|
return;
|
||||||
} else if (descriptor.section == PremiumPreview::Stories) {
|
} else if (descriptor.section == PremiumFeature::Stories) {
|
||||||
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||||
UpgradedStoriesPreviewBox(box, &show->session());
|
UpgradedStoriesPreviewBox(box, &show->session());
|
||||||
DecorateListPromoBox(box, show, descriptor);
|
DecorateListPromoBox(box, show, descriptor);
|
||||||
}));
|
}));
|
||||||
return;
|
return;
|
||||||
|
} else if (descriptor.section == PremiumFeature::Business) {
|
||||||
|
const auto window = show->resolveWindow(
|
||||||
|
ChatHelpers::WindowUsage::PremiumPromo);
|
||||||
|
if (window) {
|
||||||
|
Settings::ShowBusiness(window);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
auto &list = Preloads();
|
auto &list = Preloads();
|
||||||
for (auto i = begin(list); i != end(list);) {
|
for (auto i = begin(list); i != end(list);) {
|
||||||
|
@ -1286,21 +1337,21 @@ void ShowStickerPreviewBox(
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
not_null<DocumentData*> document) {
|
not_null<DocumentData*> document) {
|
||||||
Show(std::move(show), Descriptor{
|
Show(std::move(show), Descriptor{
|
||||||
.section = PremiumPreview::Stickers,
|
.section = PremiumFeature::Stickers,
|
||||||
.requestedSticker = document,
|
.requestedSticker = document,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowPremiumPreviewBox(
|
void ShowPremiumPreviewBox(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
PremiumPreview section,
|
PremiumFeature section,
|
||||||
Fn<void(not_null<Ui::BoxContent*>)> shown) {
|
Fn<void(not_null<Ui::BoxContent*>)> shown) {
|
||||||
ShowPremiumPreviewBox(controller->uiShow(), section, std::move(shown));
|
ShowPremiumPreviewBox(controller->uiShow(), section, std::move(shown));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowPremiumPreviewBox(
|
void ShowPremiumPreviewBox(
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
PremiumPreview section,
|
PremiumFeature section,
|
||||||
Fn<void(not_null<Ui::BoxContent*>)> shown,
|
Fn<void(not_null<Ui::BoxContent*>)> shown,
|
||||||
bool hideSubscriptionButton) {
|
bool hideSubscriptionButton) {
|
||||||
Show(std::move(show), Descriptor{
|
Show(std::move(show), Descriptor{
|
||||||
|
@ -1312,7 +1363,7 @@ void ShowPremiumPreviewBox(
|
||||||
|
|
||||||
void ShowPremiumPreviewToBuy(
|
void ShowPremiumPreviewToBuy(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
PremiumPreview section,
|
PremiumFeature section,
|
||||||
Fn<void()> hiddenCallback) {
|
Fn<void()> hiddenCallback) {
|
||||||
Show(controller->uiShow(), Descriptor{
|
Show(controller->uiShow(), Descriptor{
|
||||||
.section = section,
|
.section = section,
|
||||||
|
|
|
@ -45,7 +45,8 @@ void UpgradedStoriesPreviewBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<Main::Session*> session);
|
not_null<Main::Session*> session);
|
||||||
|
|
||||||
enum class PremiumPreview {
|
enum class PremiumFeature {
|
||||||
|
// Premium features.
|
||||||
Stories,
|
Stories,
|
||||||
DoubleLimits,
|
DoubleLimits,
|
||||||
MoreUpload,
|
MoreUpload,
|
||||||
|
@ -64,24 +65,33 @@ enum class PremiumPreview {
|
||||||
TagsForMessages,
|
TagsForMessages,
|
||||||
LastSeen,
|
LastSeen,
|
||||||
MessagePrivacy,
|
MessagePrivacy,
|
||||||
|
Business,
|
||||||
|
|
||||||
|
// Business features.
|
||||||
|
BusinessLocation,
|
||||||
|
BusinessHours,
|
||||||
|
QuickReplies,
|
||||||
|
GreetingMessage,
|
||||||
|
AwayMessage,
|
||||||
|
BusinessBots,
|
||||||
|
|
||||||
kCount,
|
kCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
void ShowPremiumPreviewBox(
|
void ShowPremiumPreviewBox(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
PremiumPreview section,
|
PremiumFeature section,
|
||||||
Fn<void(not_null<Ui::BoxContent*>)> shown = nullptr);
|
Fn<void(not_null<Ui::BoxContent*>)> shown = nullptr);
|
||||||
|
|
||||||
void ShowPremiumPreviewBox(
|
void ShowPremiumPreviewBox(
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
PremiumPreview section,
|
PremiumFeature section,
|
||||||
Fn<void(not_null<Ui::BoxContent*>)> shown = nullptr,
|
Fn<void(not_null<Ui::BoxContent*>)> shown = nullptr,
|
||||||
bool hideSubscriptionButton = false);
|
bool hideSubscriptionButton = false);
|
||||||
|
|
||||||
void ShowPremiumPreviewToBuy(
|
void ShowPremiumPreviewToBuy(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
PremiumPreview section,
|
PremiumFeature section,
|
||||||
Fn<void()> hiddenCallback = nullptr);
|
Fn<void()> hiddenCallback = nullptr);
|
||||||
|
|
||||||
void PremiumUnavailableBox(not_null<Ui::GenericBox*> box);
|
void PremiumUnavailableBox(not_null<Ui::GenericBox*> box);
|
||||||
|
|
|
@ -77,20 +77,15 @@ AdminLog::OwnedItem GenerateItem(
|
||||||
const QString &text) {
|
const QString &text) {
|
||||||
Expects(history->peer->isUser());
|
Expects(history->peer->isUser());
|
||||||
|
|
||||||
const auto item = history->addNewLocalMessage(
|
const auto item = history->addNewLocalMessage({
|
||||||
history->nextNonHistoryEntryId(),
|
.id = history->nextNonHistoryEntryId(),
|
||||||
(MessageFlag::FakeHistoryItem
|
.flags = (MessageFlag::FakeHistoryItem
|
||||||
| MessageFlag::HasFromId
|
| MessageFlag::HasFromId
|
||||||
| MessageFlag::HasReplyInfo),
|
| MessageFlag::HasReplyInfo),
|
||||||
UserId(), // via
|
.from = from,
|
||||||
FullReplyTo{ .messageId = replyTo },
|
.replyTo = FullReplyTo{ .messageId = replyTo },
|
||||||
base::unixtime::now(), // date
|
.date = base::unixtime::now(),
|
||||||
from,
|
}, TextWithEntities{ .text = text }, MTP_messageMediaEmpty());
|
||||||
QString(), // postAuthor
|
|
||||||
TextWithEntities{ .text = text },
|
|
||||||
MTP_messageMediaEmpty(),
|
|
||||||
HistoryMessageMarkupData(),
|
|
||||||
uint64(0)); // groupedId
|
|
||||||
|
|
||||||
return AdminLog::OwnedItem(delegate, item);
|
return AdminLog::OwnedItem(delegate, item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,7 +327,7 @@ void RingtonesBox(
|
||||||
|
|
||||||
box->setWidth(st::boxWideWidth);
|
box->setWidth(st::boxWideWidth);
|
||||||
box->addButton(tr::lng_settings_save(), [=] {
|
box->addButton(tr::lng_settings_save(), [=] {
|
||||||
const auto value = state->group->value();
|
const auto value = state->group->current();
|
||||||
auto sound = (value == kDefaultValue)
|
auto sound = (value == kDefaultValue)
|
||||||
? Data::NotifySound()
|
? Data::NotifySound()
|
||||||
: (value == kNoSoundValue)
|
: (value == kNoSoundValue)
|
||||||
|
|
|
@ -95,7 +95,7 @@ void SelfDestructionBox::showContent() {
|
||||||
|
|
||||||
clearButtons();
|
clearButtons();
|
||||||
addButton(tr::lng_settings_save(), [=] {
|
addButton(tr::lng_settings_save(), [=] {
|
||||||
const auto value = _ttlGroup->value();
|
const auto value = _ttlGroup->current();
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case Type::Account:
|
case Type::Account:
|
||||||
_session->api().selfDestruct().updateAccountTTL(value);
|
_session->api().selfDestruct().updateAccountTTL(value);
|
||||||
|
|
|
@ -1172,7 +1172,7 @@ void SendFilesBox::setupEmojiPanel() {
|
||||||
_captionToPeer,
|
_captionToPeer,
|
||||||
data.document)
|
data.document)
|
||||||
: (_limits & SendFilesAllow::EmojiWithoutPremium))) {
|
: (_limits & SendFilesAllow::EmojiWithoutPremium))) {
|
||||||
ShowPremiumPreviewBox(_show, PremiumPreview::AnimatedEmoji);
|
ShowPremiumPreviewBox(_show, PremiumFeature::AnimatedEmoji);
|
||||||
} else {
|
} else {
|
||||||
Data::InsertCustomEmoji(_caption.data(), data.document);
|
Data::InsertCustomEmoji(_caption.data(), data.document);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/peer_list_controllers.h"
|
#include "boxes/peer_list_controllers.h"
|
||||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||||
#include "chat_helpers/share_message_phrase_factory.h"
|
#include "chat_helpers/share_message_phrase_factory.h"
|
||||||
|
#include "data/business/data_shortcut_messages.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_game.h"
|
#include "data/data_game.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
|
@ -1543,11 +1544,15 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
||||||
const auto threadHistory = thread->owningHistory();
|
const auto threadHistory = thread->owningHistory();
|
||||||
histories.sendRequest(threadHistory, requestType, [=](
|
histories.sendRequest(threadHistory, requestType, [=](
|
||||||
Fn<void()> finish) {
|
Fn<void()> finish) {
|
||||||
auto &api = threadHistory->session().api();
|
const auto session = &threadHistory->session();
|
||||||
|
auto &api = session->api();
|
||||||
const auto sendFlags = commonSendFlags
|
const auto sendFlags = commonSendFlags
|
||||||
| (topMsgId ? Flag::f_top_msg_id : Flag(0))
|
| (topMsgId ? Flag::f_top_msg_id : Flag(0))
|
||||||
| (ShouldSendSilent(peer, options)
|
| (ShouldSendSilent(peer, options)
|
||||||
? Flag::f_silent
|
? Flag::f_silent
|
||||||
|
: Flag(0))
|
||||||
|
| (options.shortcutId
|
||||||
|
? Flag::f_quick_reply_shortcut
|
||||||
: Flag(0));
|
: Flag(0));
|
||||||
threadHistory->sendRequestId = api.request(
|
threadHistory->sendRequestId = api.request(
|
||||||
MTPmessages_ForwardMessages(
|
MTPmessages_ForwardMessages(
|
||||||
|
@ -1558,7 +1563,8 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
||||||
peer->input,
|
peer->input,
|
||||||
MTP_int(topMsgId),
|
MTP_int(topMsgId),
|
||||||
MTP_int(options.scheduled),
|
MTP_int(options.scheduled),
|
||||||
MTP_inputPeerEmpty() // send_as
|
MTP_inputPeerEmpty(), // send_as
|
||||||
|
Data::ShortcutIdToMTP(session, options.shortcutId)
|
||||||
)).done([=](const MTPUpdates &updates, mtpRequestId reqId) {
|
)).done([=](const MTPUpdates &updates, mtpRequestId reqId) {
|
||||||
threadHistory->session().api().applyUpdates(updates);
|
threadHistory->session().api().applyUpdates(updates);
|
||||||
state->requests.remove(reqId);
|
state->requests.remove(reqId);
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
|
#include "data/data_premium_limits.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -40,8 +41,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/unread_badge_paint.h"
|
#include "ui/unread_badge_paint.h"
|
||||||
#include "media/clip/media_clip_reader.h"
|
#include "media/clip/media_clip_reader.h"
|
||||||
#include "main/main_account.h"
|
|
||||||
#include "main/main_app_config.h"
|
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
@ -2050,10 +2049,8 @@ void StickersBox::Inner::checkGroupLevel(Fn<void()> done) {
|
||||||
return std::optional<Ui::AskBoostReason>();
|
return std::optional<Ui::AskBoostReason>();
|
||||||
}
|
}
|
||||||
_checkingGroupLevel = false;
|
_checkingGroupLevel = false;
|
||||||
const auto appConfig = &peer->session().account().appConfig();
|
const auto required = Data::LevelLimits(
|
||||||
const auto required = appConfig->get<int>(
|
&peer->session()).groupEmojiStickersLevelMin();
|
||||||
"group_emoji_stickers_level_min",
|
|
||||||
4);
|
|
||||||
if (level >= required) {
|
if (level >= required) {
|
||||||
save();
|
save();
|
||||||
return std::optional<Ui::AskBoostReason>();
|
return std::optional<Ui::AskBoostReason>();
|
||||||
|
|
|
@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
|
#include "base/event_filter.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "base/power_save_blocker.h"
|
#include "base/power_save_blocker.h"
|
||||||
#include "media/streaming/media_streaming_utility.h"
|
#include "media/streaming/media_streaming_utility.h"
|
||||||
|
@ -147,17 +148,18 @@ void Panel::initWindow() {
|
||||||
window()->setTitle(_user->name());
|
window()->setTitle(_user->name());
|
||||||
window()->setTitleStyle(st::callTitle);
|
window()->setTitleStyle(st::callTitle);
|
||||||
|
|
||||||
window()->events(
|
base::install_event_filter(window().get(), [=](not_null<QEvent*> e) {
|
||||||
) | rpl::start_with_next([=](not_null<QEvent*> e) {
|
if (e->type() == QEvent::Close && handleClose()) {
|
||||||
if (e->type() == QEvent::Close) {
|
e->ignore();
|
||||||
handleClose();
|
return base::EventFilterResult::Cancel;
|
||||||
} else if (e->type() == QEvent::KeyPress) {
|
} else if (e->type() == QEvent::KeyPress) {
|
||||||
if ((static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Escape)
|
if ((static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Escape)
|
||||||
&& window()->isFullScreen()) {
|
&& window()->isFullScreen()) {
|
||||||
window()->showNormal();
|
window()->showNormal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, window()->lifetime());
|
return base::EventFilterResult::Continue;
|
||||||
|
});
|
||||||
|
|
||||||
window()->setBodyTitleArea([=](QPoint widgetPoint) {
|
window()->setBodyTitleArea([=](QPoint widgetPoint) {
|
||||||
using Flag = Ui::WindowTitleHitTestFlag;
|
using Flag = Ui::WindowTitleHitTestFlag;
|
||||||
|
@ -828,10 +830,12 @@ void Panel::paint(QRect clip) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::handleClose() {
|
bool Panel::handleClose() const {
|
||||||
if (_call) {
|
if (_call) {
|
||||||
_call->hangup();
|
window()->hide();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::RpWindow*> Panel::window() const {
|
not_null<Ui::RpWindow*> Panel::window() const {
|
||||||
|
|
|
@ -106,7 +106,7 @@ private:
|
||||||
void initLayout();
|
void initLayout();
|
||||||
void initGeometry();
|
void initGeometry();
|
||||||
|
|
||||||
void handleClose();
|
[[nodiscard]] bool handleClose() const;
|
||||||
|
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
void updateHangupGeometry();
|
void updateHangupGeometry();
|
||||||
|
|
|
@ -608,7 +608,7 @@ defaultComposeIcons: ComposeIcons {
|
||||||
|
|
||||||
stripBubble: icon{
|
stripBubble: icon{
|
||||||
{ "chat/reactions_bubble_shadow", windowShadowFg },
|
{ "chat/reactions_bubble_shadow", windowShadowFg },
|
||||||
{ "chat/reactions_bubble", windowBg },
|
{ "chat/reactions_bubble", emojiPanBg },
|
||||||
};
|
};
|
||||||
stripExpandPanel: icon{
|
stripExpandPanel: icon{
|
||||||
{ "chat/reactions_round_big", windowBgRipple },
|
{ "chat/reactions_round_big", windowBgRipple },
|
||||||
|
|
|
@ -23,6 +23,7 @@ struct ComposeFeatures {
|
||||||
bool autocompleteHashtags = true;
|
bool autocompleteHashtags = true;
|
||||||
bool autocompleteMentions = true;
|
bool autocompleteMentions = true;
|
||||||
bool autocompleteCommands = true;
|
bool autocompleteCommands = true;
|
||||||
|
bool commonTabbedPanel = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ChatHelpers
|
} // namespace ChatHelpers
|
||||||
|
|