Merge tag 'v4.10.0' into dev

# Conflicts:
#	README.md
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/apiwrap.cpp
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/data/data_stories.cpp
#	Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp
#	Telegram/lib_ui
#	snap/snapcraft.yaml
This commit is contained in:
ZavaruKitsu 2023-09-23 10:58:57 +03:00
commit 0502acc8a4
353 changed files with 7144 additions and 3482 deletions

View file

@ -41,7 +41,7 @@ on:
jobs: jobs:
linux: linux:
name: CentOS 7 name: Rocky Linux 8
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/${{ github.repository }}/centos_env image: ghcr.io/${{ github.repository }}/centos_env
@ -51,7 +51,7 @@ jobs:
defaults: defaults:
run: run:
shell: scl enable rh-python38 -- scl enable llvm-toolset-7.0 -- scl enable devtoolset-10 -- bash --noprofile --norc -eo pipefail {0} shell: scl enable gcc-toolset-12 -- bash --noprofile --norc -eo pipefail {0}
strategy: strategy:
matrix: matrix:

View file

@ -124,7 +124,7 @@ jobs:
echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV
API="-D TDESKTOP_API_TEST=ON" API="-D TDESKTOP_API_TEST=ON"
if [ ${{ github.ref == 'refs/heads/nightly' }} ]; then if [ $GITHUB_REF == 'refs/heads/nightly' ]; then
echo "Use the open credentials." echo "Use the open credentials."
API="-D TDESKTOP_API_ID=611335 -D TDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c" API="-D TDESKTOP_API_ID=611335 -D TDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c"
fi fi

3
.gitmodules vendored
View file

@ -58,9 +58,6 @@
[submodule "Telegram/ThirdParty/range-v3"] [submodule "Telegram/ThirdParty/range-v3"]
path = Telegram/ThirdParty/range-v3 path = Telegram/ThirdParty/range-v3
url = https://github.com/ericniebler/range-v3.git url = https://github.com/ericniebler/range-v3.git
[submodule "Telegram/ThirdParty/fcitx-qt5"]
path = Telegram/ThirdParty/fcitx-qt5
url = https://github.com/fcitx/fcitx-qt5.git
[submodule "Telegram/ThirdParty/nimf"] [submodule "Telegram/ThirdParty/nimf"]
path = Telegram/ThirdParty/nimf path = Telegram/ThirdParty/nimf
url = https://github.com/hamonikr/nimf.git url = https://github.com/hamonikr/nimf.git

View file

@ -61,7 +61,7 @@ if (NOT DESKTOP_APP_USE_PACKAGED)
if (WIN32) if (WIN32)
set(qt_version 5.15.10) set(qt_version 5.15.10)
elseif (APPLE) elseif (APPLE)
set(qt_version 6.3.2) set(qt_version 6.2.5)
endif() endif()
endif() endif()
include(cmake/external/qt/package.cmake) include(cmake/external/qt/package.cmake)

View file

@ -478,6 +478,7 @@ PRIVATE
core/crash_report_window.h core/crash_report_window.h
core/crash_reports.cpp core/crash_reports.cpp
core/crash_reports.h core/crash_reports.h
core/deadlock_detector.h
core/file_utilities.cpp core/file_utilities.cpp
core/file_utilities.h core/file_utilities.h
core/launcher.cpp core/launcher.cpp
@ -1541,6 +1542,7 @@ PRIVATE
qrc/emoji_5.qrc qrc/emoji_5.qrc
qrc/emoji_6.qrc qrc/emoji_6.qrc
qrc/emoji_7.qrc qrc/emoji_7.qrc
qrc/emoji_8.qrc
qrc/emoji_preview.qrc qrc/emoji_preview.qrc
qrc/telegram/animations.qrc qrc/telegram/animations.qrc
qrc/telegram/export.qrc qrc/telegram/export.qrc

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 KiB

After

Width:  |  Height:  |  Size: 832 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 B

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

View file

@ -548,6 +548,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_title_account_name" = "Show active account"; "lng_settings_title_account_name" = "Show active account";
"lng_settings_title_total_count" = "Total unread count"; "lng_settings_title_total_count" = "Total unread count";
"lng_settings_native_frame" = "Use system window frame"; "lng_settings_native_frame" = "Use system window frame";
"lng_settings_qt_frame" = "Use Qt window frame";
"lng_settings_auto_start" = "Launch Telegram when system starts"; "lng_settings_auto_start" = "Launch Telegram when system starts";
"lng_settings_start_min" = "Launch minimized"; "lng_settings_start_min" = "Launch minimized";
"lng_settings_auto_start_disabled_uwp" = "Starting with the system was disabled in Windows Settings.\n\nPlease enable Telegram Desktop in the Startup Apps Settings."; "lng_settings_auto_start_disabled_uwp" = "Starting with the system was disabled in Windows Settings.\n\nPlease enable Telegram Desktop in the Startup Apps Settings.";
@ -1182,6 +1183,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_loading" = "Loading..."; "lng_profile_loading" = "Loading...";
"lng_profile_saved_stories#one" = "{count} saved story"; "lng_profile_saved_stories#one" = "{count} saved story";
"lng_profile_saved_stories#other" = "{count} saved stories"; "lng_profile_saved_stories#other" = "{count} saved stories";
"lng_profile_posts#one" = "{count} post";
"lng_profile_posts#other" = "{count} posts";
"lng_profile_photos#one" = "{count} photo"; "lng_profile_photos#one" = "{count} photo";
"lng_profile_photos#other" = "{count} photos"; "lng_profile_photos#other" = "{count} photos";
"lng_profile_gifs#one" = "{count} GIF"; "lng_profile_gifs#one" = "{count} GIF";
@ -1611,6 +1614,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_suggested_video" = "{user} suggests you to use this profile video."; "lng_action_suggested_video" = "{user} suggests you to use this profile video.";
"lng_action_suggested_video_button" = "View Video"; "lng_action_suggested_video_button" = "View Video";
"lng_action_attach_menu_bot_allowed" = "You allowed this bot to message you when you added it in the attachment menu."; "lng_action_attach_menu_bot_allowed" = "You allowed this bot to message you when you added it in the attachment menu.";
"lng_action_webapp_bot_allowed" = "You allowed this bot to message you in his web-app.";
"lng_action_set_wallpaper_me" = "You set a new wallpaper for this chat"; "lng_action_set_wallpaper_me" = "You set a new wallpaper for this chat";
"lng_action_set_wallpaper" = "{user} set a new wallpaper for this chat"; "lng_action_set_wallpaper" = "{user} set a new wallpaper for this chat";
"lng_action_set_wallpaper_button" = "View Wallpaper"; "lng_action_set_wallpaper_button" = "View Wallpaper";
@ -1799,6 +1803,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_bot_share_location_unavailable" = "Sorry, location sharing is currently unavailable in Telegram Desktop."; "lng_bot_share_location_unavailable" = "Sorry, location sharing is currently unavailable in Telegram Desktop.";
"lng_bot_share_phone" = "Do you want to share your phone number with this bot?"; "lng_bot_share_phone" = "Do you want to share your phone number with this bot?";
"lng_bot_share_phone_confirm" = "Share"; "lng_bot_share_phone_confirm" = "Share";
"lng_bot_allow_write_title" = "Allow messaging";
"lng_bot_allow_write" = "Do you want to allow this bot writing you?";
"lng_bot_allow_write_confirm" = "Allow";
"lng_attach_failed" = "Failed"; "lng_attach_failed" = "Failed";
"lng_attach_file" = "File"; "lng_attach_file" = "File";
@ -1995,6 +2002,38 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_gift_terms" = "You can review the list of features and terms of use for Telegram Premium {link}."; "lng_premium_gift_terms" = "You can review the list of features and terms of use for Telegram Premium {link}.";
"lng_premium_gift_terms_link" = "here"; "lng_premium_gift_terms_link" = "here";
"lng_boost_channel_button" = "Boost Channel";
"lng_boost_level#one" = "Level {count}";
"lng_boost_level#other" = "Level {count}";
"lng_boost_channel_title_first" = "Enable stories for channel";
"lng_boost_channel_needs_first#one" = "{channel} needs **{count}** more boost to enable posting stories. Help make it possible!";
"lng_boost_channel_needs_first#other" = "{channel} needs **{count}** more boosts to enable posting stories. Help make it possible!";
"lng_boost_channel_title_more" = "Help upgrade channel";
"lng_boost_channel_needs_more#one" = "{channel} needs **{count}** more boost to be able to {post}.";
"lng_boost_channel_needs_more#other" = "{channel} needs **{count}** more boosts to be able to {post}.";
"lng_boost_channel_title_max" = "Maximum level reached";
"lng_boost_channel_you_title" = "You boosted {channel}!";
"lng_boost_channel_you_first#one" = "This channel needs **{count}** more boost\nto enable stories.";
"lng_boost_channel_you_first#other" = "This channel needs **{count}** more boosts\nto enable stories.";
"lng_boost_channel_you_more#one" = "This channel needs **{count}** more boost\nto be able to {post}.";
"lng_boost_channel_you_more#other" = "This channel needs **{count}** more boosts\nto be able to {post}.";
"lng_boost_channel_reached_first" = "This channel reached **Level 1** and can now post stories.";
"lng_boost_channel_reached_more#one" = "This channel reached **Level {count}** and can now {post}.";
"lng_boost_channel_reached_more#other" = "This channel reached **Level {count}** and can now {post}.";
"lng_boost_channel_post_stories#one" = "post **{count} story** per day";
"lng_boost_channel_post_stories#other" = "post **{count} stories** per day";
"lng_boost_error_gifted_title" = "Can't boost with gifted Premium!";
"lng_boost_error_gifted_text" = "Because your **Telegram Premium** subscription was gifted to you, you can't use it to boost channels.";
"lng_boost_error_already_title" = "Already Boosted!";
"lng_boost_error_already_text" = "You are already boosting this channel.";
"lng_boost_error_premium_title" = "Premium needed!";
"lng_boost_error_premium_text" = "Only **Telegram Premium** subscribers can boost channels. Do you want to subscribe to **Telegram Premium**?";
"lng_boost_error_premium_yes" = "Yes";
"lng_boost_error_flood_title" = "Can't boost too often!";
"lng_boost_error_flood_text" = "You can change the channel you boost only once a day. Next time you can boost is in {left}.";
"lng_boost_now_instead" = "You currently boost {channel}. Do you want to boost {other} instead?";
"lng_boost_now_replace" = "Replace";
"lng_accounts_limit_title" = "Limit Reached"; "lng_accounts_limit_title" = "Limit Reached";
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected accounts."; "lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected accounts.";
"lng_accounts_limit1#other" = "You have reached the limit of **{count}** connected accounts."; "lng_accounts_limit1#other" = "You have reached the limit of **{count}** connected accounts.";
@ -2256,17 +2295,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_bot_remove_from_menu" = "Remove From Menu"; "lng_bot_remove_from_menu" = "Remove From Menu";
"lng_bot_remove_from_menu_sure" = "Remove {bot} from the attachment menu?"; "lng_bot_remove_from_menu_sure" = "Remove {bot} from the attachment menu?";
"lng_bot_remove_from_menu_done" = "Bot removed from the menu."; "lng_bot_remove_from_menu_done" = "Bot removed from the menu.";
"lng_bot_remove_from_side_menu" = "Remove From Menu";
"lng_bot_remove_from_side_menu_sure" = "Remove {bot} from the main menu?";
"lng_bot_remove_from_side_menu_done" = "Bot removed from the main menu.";
"lng_bot_settings" = "Settings"; "lng_bot_settings" = "Settings";
"lng_bot_open" = "Open Bot"; "lng_bot_open" = "Open Bot";
"lng_bot_reload_page" = "Reload Page"; "lng_bot_reload_page" = "Reload Page";
"lng_bot_add_to_menu" = "{bot} asks your permission to be added as an option to your attachments menu so you can access it from any chat."; "lng_bot_add_to_menu" = "{bot} asks your permission to be added as an option to your attachments menu so you can access it from any chat.";
"lng_bot_add_to_menu_done" = "Bot added to the menu."; "lng_bot_add_to_menu_done" = "Bot added to the menu.";
"lng_bot_will_be_added" = "{bot} shortcuts will be added to the attachment options and the main menu.";
"lng_bot_side_menu_new" = "NEW";
"lng_bot_menu_not_supported" = "This bot isn't supported in the attach menu."; "lng_bot_menu_not_supported" = "This bot isn't supported in the attach menu.";
"lng_bot_menu_already_added" = "This bot is already added in your attach menu."; "lng_bot_menu_already_added" = "This bot is already added in your attach menu.";
"lng_bot_menu_button" = "Menu"; "lng_bot_menu_button" = "Menu";
"lng_bot_close_warning_title" = "Warning"; "lng_bot_close_warning_title" = "Warning";
"lng_bot_close_warning" = "Changes that you made may not be saved."; "lng_bot_close_warning" = "Changes that you made may not be saved.";
"lng_bot_close_warning_sure" = "Close anyway"; "lng_bot_close_warning_sure" = "Close anyway";
"lng_bot_add_to_side_menu" = "{bot} asks your permission to be added as an option to your main menu so you can access it any time.";
"lng_bot_add_to_side_menu_done" = "Bot added to the main menu.";
"lng_typing" = "typing"; "lng_typing" = "typing";
"lng_user_typing" = "{user} is typing"; "lng_user_typing" = "{user} is typing";
@ -2370,6 +2416,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_open_gif" = "Open GIF"; "lng_context_open_gif" = "Open GIF";
"lng_context_save_gif" = "Save GIF"; "lng_context_save_gif" = "Save GIF";
"lng_context_delete_gif" = "Delete GIF"; "lng_context_delete_gif" = "Delete GIF";
"lng_context_open_channel" = "Open Channel";
"lng_context_attached_stickers" = "Attached Stickers"; "lng_context_attached_stickers" = "Attached Stickers";
"lng_context_to_msg" = "Go To Message"; "lng_context_to_msg" = "Go To Message";
"lng_context_reply_msg" = "Reply"; "lng_context_reply_msg" = "Reply";
@ -2747,6 +2794,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_payments_terms_title" = "Terms of Service"; "lng_payments_terms_title" = "Terms of Service";
"lng_payments_terms_text" = "Subscribe and accept terms of service of {bot}?"; "lng_payments_terms_text" = "Subscribe and accept terms of service of {bot}?";
"lng_payments_terms_text_once" = "Are you accepting terms of service of {bot}?";
"lng_payments_terms_agree" = "I agree to {link}"; "lng_payments_terms_agree" = "I agree to {link}";
"lng_payments_terms_link" = "Terms of Service"; "lng_payments_terms_link" = "Terms of Service";
"lng_payments_terms_accept" = "Accept"; "lng_payments_terms_accept" = "Accept";
@ -3079,9 +3127,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gigagroup_suggest_more" = "Learn more"; "lng_gigagroup_suggest_more" = "Learn more";
"lng_rights_channel_info" = "Change channel info"; "lng_rights_channel_info" = "Change channel info";
"lng_rights_channel_manage" = "Manage messages";
"lng_rights_channel_post" = "Post messages"; "lng_rights_channel_post" = "Post messages";
"lng_rights_channel_edit" = "Edit messages of others"; "lng_rights_channel_edit" = "Edit messages of others";
"lng_rights_channel_delete" = "Delete messages of others"; "lng_rights_channel_delete" = "Delete messages of others";
"lng_rights_channel_manage_stories" = "Manage stories";
"lng_rights_channel_post_stories" = "Post stories";
"lng_rights_channel_edit_stories" = "Edit stories of others";
"lng_rights_channel_delete_stories" = "Delete stories of others";
"lng_rights_channel_manage_calls" = "Manage live streams"; "lng_rights_channel_manage_calls" = "Manage live streams";
"lng_rights_group_info" = "Change group info"; "lng_rights_group_info" = "Change group info";
"lng_rights_group_ban" = "Ban users"; "lng_rights_group_ban" = "Ban users";
@ -3340,6 +3393,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_admin_post_messages" = "Post messages"; "lng_admin_log_admin_post_messages" = "Post messages";
"lng_admin_log_admin_edit_messages" = "Edit messages"; "lng_admin_log_admin_edit_messages" = "Edit messages";
"lng_admin_log_admin_delete_messages" = "Delete messages"; "lng_admin_log_admin_delete_messages" = "Delete messages";
"lng_admin_log_admin_post_stories" = "Post stories";
"lng_admin_log_admin_edit_stories" = "Edit stories";
"lng_admin_log_admin_delete_stories" = "Delete stories";
"lng_admin_log_admin_remain_anonymous" = "Remain anonymous"; "lng_admin_log_admin_remain_anonymous" = "Remain anonymous";
"lng_admin_log_admin_ban_users" = "Ban users"; "lng_admin_log_admin_ban_users" = "Ban users";
"lng_admin_log_admin_invite_users" = "Add members"; "lng_admin_log_admin_invite_users" = "Add members";
@ -3555,6 +3611,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_export_option_choose_format" = "Choose export format"; "lng_export_option_choose_format" = "Choose export format";
"lng_export_option_html" = "Human-readable HTML"; "lng_export_option_html" = "Human-readable HTML";
"lng_export_option_json" = "Machine-readable JSON"; "lng_export_option_json" = "Machine-readable JSON";
"lng_export_option_html_and_json" = "Both";
"lng_export_limits" = "From: {from}, to: {till}"; "lng_export_limits" = "From: {from}, to: {till}";
"lng_export_beginning" = "the oldest message"; "lng_export_beginning" = "the oldest message";
"lng_export_end" = "present"; "lng_export_end" = "present";
@ -3819,6 +3876,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_view_button_voice_chat_channel" = "Live stream"; "lng_view_button_voice_chat_channel" = "Live stream";
"lng_view_button_request_join" = "Request to Join"; "lng_view_button_request_join" = "Request to Join";
"lng_view_button_external_link" = "Open link"; "lng_view_button_external_link" = "Open link";
"lng_view_button_boost" = "Boost";
"lng_sponsored_hide_ads" = "Hide"; "lng_sponsored_hide_ads" = "Hide";
"lng_sponsored_title" = "What are sponsored messages?"; "lng_sponsored_title" = "What are sponsored messages?";
@ -3829,6 +3887,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_telegram_features_url" = "https://t.me/TelegramTips"; "lng_telegram_features_url" = "https://t.me/TelegramTips";
"lng_mini_apps_disclaimer_title" = "Warning";
"lng_mini_apps_disclaimer_text" = "You are about to use a mini app operated by an independent party **not affiliated with Telegram**. You must agree to the Terms of Use of mini apps to continue.";
"lng_mini_apps_disclaimer_button" = "I agree to the {link}";
"lng_mini_apps_disclaimer_link" = "Terms of Use";
"lng_mini_apps_tos_url" = "https://telegram.org/tos/mini-apps";
"lng_ringtones_box_title" = "Notification Sound"; "lng_ringtones_box_title" = "Notification Sound";
"lng_ringtones_box_cloud_subtitle" = "Choose your tone"; "lng_ringtones_box_cloud_subtitle" = "Choose your tone";
"lng_ringtones_box_upload_choose" = "Choose ringtone"; "lng_ringtones_box_upload_choose" = "Choose ringtone";
@ -3946,6 +4010,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stories_recent_button" = "Recent Stories"; "lng_stories_recent_button" = "Recent Stories";
"lng_stories_archive_title" = "Stories Archive"; "lng_stories_archive_title" = "Stories Archive";
"lng_stories_archive_about" = "Only you can see archived stories unless you choose to save them to your profile."; "lng_stories_archive_about" = "Only you can see archived stories unless you choose to save them to your profile.";
"lng_stories_channel_archive_about" = "Only admins of the channel can see archived stories unless they are saved to the channel page.";
"lng_stories_reply_sent" = "Message Sent"; "lng_stories_reply_sent" = "Message Sent";
"lng_stories_hidden_to_contacts" = "Stories from {user} will now be shown in **Archived Chats**."; "lng_stories_hidden_to_contacts" = "Stories from {user} will now be shown in **Archived Chats**.";
"lng_stories_shown_in_chats" = "Stories from {user} will now be shown in the **Chats List**."; "lng_stories_shown_in_chats" = "Stories from {user} will now be shown in the **Chats List**.";
@ -3965,6 +4030,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stories_archive_done" = "This story is hidden from your profile."; "lng_stories_archive_done" = "This story is hidden from your profile.";
"lng_stories_archive_done_many#one" = "{count} story is hidden from your profile."; "lng_stories_archive_done_many#one" = "{count} story is hidden from your profile.";
"lng_stories_archive_done_many#other" = "{count} stories are hidden from your profile."; "lng_stories_archive_done_many#other" = "{count} stories are hidden from your profile.";
"lng_stories_channel_save_sure" = "Do you want to save this story to the channel page?";
"lng_stories_channel_save_sure_many#one" = "Do you want to save {count} story to the channel page?";
"lng_stories_channel_save_sure_many#other" = "Do you want to save {count} stories to the channel page?";
"lng_stories_channel_save_done" = "This story is saved to the channel page.";
"lng_stories_channel_save_done_many#one" = "{count} story is saved to the channel page.";
"lng_stories_channel_save_done_many#other" = "{count} stories are saved to the channel page.";
"lng_stories_channel_save_done_about" = "Saved stories can be viewed by others on the channel page until they are removed.";
"lng_stories_channel_archive_sure" = "Do you want to hide this story from the channel page?";
"lng_stories_channel_archive_sure_many#one" = "Do you want to hide {count} story from the channel page?";
"lng_stories_channel_archive_sure_many#other" = "Do you want to hide {count} stories from the channel page?";
"lng_stories_channel_archive_done" = "This story is hidden from the channel page.";
"lng_stories_channel_archive_done_many#one" = "{count} story is hidden from the channel page.";
"lng_stories_channel_archive_done_many#other" = "{count} stories are hidden from the channel page.";
"lng_stories_save_promo" = "Subscribe to {link} to download other people's unprotected stories to disk."; "lng_stories_save_promo" = "Subscribe to {link} to download other people's unprotected stories to disk.";
"lng_stealth_mode_menu_item" = "Stealth Mode"; "lng_stealth_mode_menu_item" = "Stealth Mode";

View file

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/gui">
<file alias="emoji/emoji_8.webp">../emoji/emoji_8.webp</file>
</qresource>
</RCC>

View 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.9.4.0" /> Version="4.10.0.0" />
<Properties> <Properties>
<DisplayName>Telegram Desktop</DisplayName> <DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName> <PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>

View file

@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,9,4,0 FILEVERSION 4,10,0,0
PRODUCTVERSION 4,9,4,0 PRODUCTVERSION 4,10,0,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.9.4.0" VALUE "FileVersion", "4.10.0.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop" VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.9.4.0" VALUE "ProductVersion", "4.10.0.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,9,4,0 FILEVERSION 4,10,0,0
PRODUCTVERSION 4,9,4,0 PRODUCTVERSION 4,10,0,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.9.4.0" VALUE "FileVersion", "4.10.0.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop" VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.9.4.0" VALUE "ProductVersion", "4.10.0.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -267,7 +267,7 @@ int main(int argc, char *argv[])
} }
QByteArray inner = f.readAll(); QByteArray inner = f.readAll();
stream << name << quint32(inner.size()) << inner; stream << name << quint32(inner.size()) << inner;
#ifdef Q_OS_UNIX #ifndef Q_OS_WIN
stream << (QFileInfo(fullName).isExecutable() ? true : false); stream << (QFileInfo(fullName).isExecutable() ? true : false);
#endif #endif
} }
@ -281,7 +281,7 @@ int main(int argc, char *argv[])
cout << "Compression start, size: " << resultSize << "\n"; cout << "Compression start, size: " << resultSize << "\n";
QByteArray compressed, resultCheck; QByteArray compressed, resultCheck;
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win #if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size
@ -496,10 +496,8 @@ int main(int argc, char *argv[])
QString outName((targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version)); QString outName((targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_MAC #elif defined Q_OS_MAC
QString outName((targetarmac ? QString("tarmacupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version)); QString outName((targetarmac ? QString("tarmacupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_UNIX
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
#else #else
#error Unknown platform! QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
#endif #endif
if (AlphaVersion) { if (AlphaVersion) {
outName += "_" + AlphaSignature; outName += "_" + AlphaSignature;

View file

@ -27,7 +27,7 @@ extern "C" {
#include <openssl/evp.h> #include <openssl/evp.h>
} // extern "C" } // extern "C"
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win #if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
#include <LzmaLib.h> #include <LzmaLib.h>
#else #else
#include <lzma.h> #include <lzma.h>

View file

@ -41,6 +41,7 @@ bool do_mkdir(const char *path) { // from http://stackoverflow.com/questions/675
} }
bool _debug = false; bool _debug = false;
bool writeprotected = false;
string updaterDir; string updaterDir;
string updaterName; string updaterName;
string workDir; string workDir;
@ -88,7 +89,7 @@ void writeLog(const char *format, ...) {
va_end(args); va_end(args);
} }
bool copyFile(const char *from, const char *to, bool writeprotected) { bool copyFile(const char *from, const char *to) {
FILE *ffrom = fopen(from, "rb"), *fto = fopen(to, "wb"); FILE *ffrom = fopen(from, "rb"), *fto = fopen(to, "wb");
if (!ffrom) { if (!ffrom) {
if (fto) fclose(fto); if (fto) fclose(fto);
@ -211,7 +212,7 @@ void delFolder() {
rmdir(delFolder.c_str()); rmdir(delFolder.c_str());
} }
bool update(bool writeprotected) { bool update() {
writeLog("Update started.."); writeLog("Update started..");
string updDir = workDir + "tupdates/temp", readyFilePath = workDir + "tupdates/temp/ready", tdataDir = workDir + "tupdates/temp/tdata"; string updDir = workDir + "tupdates/temp", readyFilePath = workDir + "tupdates/temp/ready", tdataDir = workDir + "tupdates/temp/tdata";
@ -324,7 +325,7 @@ bool update(bool writeprotected) {
writeLog("Copying file '%s' to '%s'..", fname.c_str(), tofname.c_str()); writeLog("Copying file '%s' to '%s'..", fname.c_str(), tofname.c_str());
int copyTries = 0, triesLimit = 30; int copyTries = 0, triesLimit = 30;
do { do {
if (!copyFile(fname.c_str(), tofname.c_str(), writeprotected)) { if (!copyFile(fname.c_str(), tofname.c_str())) {
++copyTries; ++copyTries;
usleep(100000); usleep(100000);
} else { } else {
@ -359,10 +360,10 @@ int main(int argc, char *argv[]) {
bool needupdate = true; bool needupdate = true;
bool autostart = false; bool autostart = false;
bool debug = false; bool debug = false;
bool writeprotected = false;
bool tosettings = false; bool tosettings = false;
bool startintray = false; bool startintray = false;
bool customWorkingDir = false; bool customWorkingDir = false;
bool justUpdate = false;
char *key = 0; char *key = 0;
char *workdir = 0; char *workdir = 0;
@ -381,6 +382,9 @@ int main(int argc, char *argv[]) {
customWorkingDir = true; customWorkingDir = true;
} else if (equal(argv[i], "-writeprotected")) { } else if (equal(argv[i], "-writeprotected")) {
writeprotected = true; writeprotected = true;
justUpdate = true;
} else if (equal(argv[i], "-justupdate")) {
justUpdate = true;
} else if (equal(argv[i], "-key") && ++i < argc) { } else if (equal(argv[i], "-key") && ++i < argc) {
key = argv[i]; key = argv[i];
} else if (equal(argv[i], "-workpath") && ++i < argc) { } else if (equal(argv[i], "-workpath") && ++i < argc) {
@ -455,7 +459,7 @@ int main(int argc, char *argv[]) {
} else { } else {
writeLog("Passed workpath is '%s'", workDir.c_str()); writeLog("Passed workpath is '%s'", workDir.c_str());
} }
update(writeprotected); update();
} }
} else { } else {
writeLog("Error: bad exe name!"); writeLog("Error: bad exe name!");
@ -464,36 +468,38 @@ int main(int argc, char *argv[]) {
writeLog("Error: short exe name!"); writeLog("Error: short exe name!");
} }
const auto fullBinaryPath = exePath + exeName;
auto values = vector<string>();
const auto push = [&](string arg) {
// Force null-terminated .data() call result.
values.push_back(arg + char(0));
};
push(!argv0.empty() ? argv0 : fullBinaryPath);
push("-noupdate");
if (autostart) push("-autostart");
if (debug) push("-debug");
if (startintray) push("-startintray");
if (tosettings) push("-tosettings");
if (key) {
push("-key");
push(key);
}
if (customWorkingDir && workdir) {
push("-workdir");
push(workdir);
}
auto args = vector<char*>();
for (auto &arg : values) {
args.push_back(arg.data());
}
args.push_back(nullptr);
// let the parent launch instead // let the parent launch instead
if (!writeprotected) { if (justUpdate) {
writeLog("Closing log and quitting..");
} else {
const auto fullBinaryPath = exePath + exeName;
auto values = vector<string>();
const auto push = [&](string arg) {
// Force null-terminated .data() call result.
values.push_back(arg + char(0));
};
push(!argv0.empty() ? argv0 : fullBinaryPath);
push("-noupdate");
if (autostart) push("-autostart");
if (debug) push("-debug");
if (startintray) push("-startintray");
if (tosettings) push("-tosettings");
if (key) {
push("-key");
push(key);
}
if (customWorkingDir && workdir) {
push("-workdir");
push(workdir);
}
auto args = vector<char*>();
for (auto &arg : values) {
args.push_back(arg.data());
}
args.push_back(nullptr);
pid_t pid = fork(); pid_t pid = fork();
switch (pid) { switch (pid) {
case -1: case -1:
@ -503,9 +509,10 @@ int main(int argc, char *argv[]) {
execv(fullBinaryPath.c_str(), args.data()); execv(fullBinaryPath.c_str(), args.data());
return 1; return 1;
} }
writeLog("Executed Telegram, closing log and quitting..");
} }
writeLog("Executed Telegram, closing log and quitting..");
closeLog(); closeLog();
return 0; return 0;

View file

@ -77,45 +77,59 @@ void BlockedPeers::block(not_null<PeerData*> peer) {
_session->changes().peerUpdated( _session->changes().peerUpdated(
peer, peer,
Data::PeerUpdate::Flag::IsBlocked); Data::PeerUpdate::Flag::IsBlocked);
} else if (_blockRequests.find(peer) == end(_blockRequests)) { return;
const auto requestId = _api.request(MTPcontacts_Block( } else if (blockAlreadySent(peer, true)) {
MTP_flags(0), return;
peer->input
)).done([=] {
_blockRequests.erase(peer);
peer->setIsBlocked(true);
if (_slice) {
_slice->list.insert(
_slice->list.begin(),
{ peer->id, base::unixtime::now() });
++_slice->total;
_changes.fire_copy(*_slice);
}
}).fail([=] {
_blockRequests.erase(peer);
}).send();
_blockRequests.emplace(peer, requestId);
} }
const auto requestId = _api.request(MTPcontacts_Block(
MTP_flags(0),
peer->input
)).done([=] {
const auto data = _blockRequests.take(peer);
peer->setIsBlocked(true);
if (_slice) {
_slice->list.insert(
_slice->list.begin(),
{ peer->id, base::unixtime::now() });
++_slice->total;
_changes.fire_copy(*_slice);
}
if (data) {
for (const auto &callback : data->callbacks) {
callback(false);
}
}
}).fail([=] {
if (const auto data = _blockRequests.take(peer)) {
for (const auto &callback : data->callbacks) {
callback(false);
}
}
}).send();
_blockRequests.emplace(peer, Request{
.requestId = requestId,
.blocking = true,
});
} }
void BlockedPeers::unblock( void BlockedPeers::unblock(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Fn<void()> onDone, Fn<void(bool success)> done,
bool force) { bool force) {
if (!force && !peer->isBlocked()) { if (!force && !peer->isBlocked()) {
_session->changes().peerUpdated( _session->changes().peerUpdated(
peer, peer,
Data::PeerUpdate::Flag::IsBlocked); Data::PeerUpdate::Flag::IsBlocked);
return; return;
} else if (_blockRequests.find(peer) != end(_blockRequests)) { } else if (blockAlreadySent(peer, false, done)) {
return; return;
} }
const auto requestId = _api.request(MTPcontacts_Unblock( const auto requestId = _api.request(MTPcontacts_Unblock(
MTP_flags(0), MTP_flags(0),
peer->input peer->input
)).done([=] { )).done([=] {
_blockRequests.erase(peer); const auto data = _blockRequests.take(peer);
peer->setIsBlocked(false); peer->setIsBlocked(false);
if (_slice) { if (_slice) {
auto &list = _slice->list; auto &list = _slice->list;
@ -130,13 +144,46 @@ void BlockedPeers::unblock(
} }
_changes.fire_copy(*_slice); _changes.fire_copy(*_slice);
} }
if (onDone) { if (data) {
onDone(); for (const auto &callback : data->callbacks) {
callback(true);
}
} }
}).fail([=] { }).fail([=] {
_blockRequests.erase(peer); if (const auto data = _blockRequests.take(peer)) {
for (const auto &callback : data->callbacks) {
callback(false);
}
}
}).send(); }).send();
_blockRequests.emplace(peer, requestId); const auto i = _blockRequests.emplace(peer, Request{
.requestId = requestId,
.blocking = false,
}).first;
if (done) {
i->second.callbacks.push_back(std::move(done));
}
}
bool BlockedPeers::blockAlreadySent(
not_null<PeerData*> peer,
bool blocking,
Fn<void(bool success)> done) {
const auto i = _blockRequests.find(peer);
if (i == end(_blockRequests)) {
return false;
} else if (i->second.blocking == blocking) {
if (done) {
i->second.callbacks.push_back(std::move(done));
}
return true;
}
const auto callbacks = base::take(i->second.callbacks);
_blockRequests.erase(i);
for (const auto &callback : callbacks) {
callback(false);
}
return false;
} }
void BlockedPeers::reload() { void BlockedPeers::reload() {
@ -160,7 +207,7 @@ auto BlockedPeers::slice() -> rpl::producer<BlockedPeers::Slice> {
: (_changes.events() | rpl::type_erased()); : (_changes.events() | rpl::type_erased());
} }
void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> onDone) { void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> done) {
if (_requestId) { if (_requestId) {
return; return;
} }
@ -170,7 +217,7 @@ void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> onDone) {
MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice) MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice)
)).done([=](const MTPcontacts_Blocked &result) { )).done([=](const MTPcontacts_Blocked &result) {
_requestId = 0; _requestId = 0;
onDone(TLToSlice(result, _session->data())); done(TLToSlice(result, _session->data()));
}).fail([=] { }).fail([=] {
_requestId = 0; _requestId = 0;
}).send(); }).send();

View file

@ -39,20 +39,31 @@ public:
void reload(); void reload();
rpl::producer<Slice> slice(); rpl::producer<Slice> slice();
void request(int offset, Fn<void(Slice)> onDone); void request(int offset, Fn<void(Slice)> done);
void block(not_null<PeerData*> peer); void block(not_null<PeerData*> peer);
void unblock( void unblock(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Fn<void()> onDone = nullptr, Fn<void(bool success)> done = nullptr,
bool force = false); bool force = false);
private: private:
struct Request {
std::vector<Fn<void(bool success)>> callbacks;
mtpRequestId requestId = 0;
bool blocking = false;
};
[[nodiscard]] bool blockAlreadySent(
not_null<PeerData*> peer,
bool blocking,
Fn<void(bool success)> done = nullptr);
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
MTP::Sender _api; MTP::Sender _api;
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests; base::flat_map<not_null<PeerData*>, Request> _blockRequests;
mtpRequestId _requestId = 0; mtpRequestId _requestId = 0;
std::optional<Slice> _slice; std::optional<Slice> _slice;
rpl::event_stream<Slice> _changes; rpl::event_stream<Slice> _changes;

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h" #include "apiwrap.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "info/profile/info_profile_badge.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "ui/empty_userpic.h" #include "ui/empty_userpic.h"
@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "boxes/premium_limits_box.h" #include "boxes/premium_limits_box.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
#include "styles/style_info.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
namespace Api { namespace Api {
@ -195,6 +197,13 @@ ConfirmInviteBox::ConfirmInviteBox(
: _session(session) : _session(session)
, _submit(std::move(submit)) , _submit(std::move(submit))
, _title(this, st::confirmInviteTitle) , _title(this, st::confirmInviteTitle)
, _badge(std::make_unique<Info::Profile::Badge>(
this,
st::infoPeerBadge,
_session,
rpl::single(Info::Profile::Badge::Content{ BadgeForInvite(invite) }),
nullptr,
[=] { return false; }))
, _status(this, st::confirmInviteStatus) , _status(this, st::confirmInviteStatus)
, _about(this, st::confirmInviteAbout) , _about(this, st::confirmInviteAbout)
, _aboutRequests(this, st::confirmInviteStatus) , _aboutRequests(this, st::confirmInviteStatus)
@ -275,9 +284,24 @@ ConfirmInviteBox::ChatInvite ConfirmInviteBox::Parse(
.isMegagroup = data.is_megagroup(), .isMegagroup = data.is_megagroup(),
.isBroadcast = data.is_broadcast(), .isBroadcast = data.is_broadcast(),
.isRequestNeeded = data.is_request_needed(), .isRequestNeeded = data.is_request_needed(),
.isFake = data.is_fake(),
.isScam = data.is_scam(),
.isVerified = data.is_verified(),
}; };
} }
[[nodiscard]] Info::Profile::BadgeType ConfirmInviteBox::BadgeForInvite(
const ChatInvite &invite) {
using Type = Info::Profile::BadgeType;
return invite.isVerified
? Type::Verified
: invite.isScam
? Type::Scam
: invite.isFake
? Type::Fake
: Type::None;
}
void ConfirmInviteBox::prepare() { void ConfirmInviteBox::prepare() {
addButton( addButton(
(_requestApprove (_requestApprove
@ -326,8 +350,26 @@ void ConfirmInviteBox::prepare() {
void ConfirmInviteBox::resizeEvent(QResizeEvent *e) { void ConfirmInviteBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e); BoxContent::resizeEvent(e);
_title->move((width() - _title->width()) / 2, st::confirmInviteTitleTop);
_status->move((width() - _status->width()) / 2, st::confirmInviteStatusTop); const auto padding = st::boxRowPadding;
auto nameWidth = width() - padding.left() - padding.right();
auto badgeWidth = 0;
if (const auto widget = _badge->widget()) {
badgeWidth = st::infoVerifiedCheckPosition.x() + widget->width();
nameWidth -= badgeWidth;
}
_title->resizeToWidth(std::min(nameWidth, _title->textMaxWidth()));
_title->moveToLeft(
(width() - _title->width() - badgeWidth) / 2,
st::confirmInviteTitleTop);
const auto badgeLeft = _title->x() + _title->width();
const auto badgeTop = _title->y();
const auto badgeBottom = _title->y() + _title->height();
_badge->move(badgeLeft, badgeTop, badgeBottom);
_status->move(
(width() - _status->width()) / 2,
st::confirmInviteStatusTop);
auto bottom = _status->y() auto bottom = _status->y()
+ _status->height() + _status->height()
+ st::boxPadding.bottom() + st::boxPadding.bottom()

View file

@ -12,6 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class UserData; class UserData;
class ChannelData; class ChannelData;
namespace Info::Profile {
class Badge;
enum class BadgeType;
} // namespace Info::Profile
namespace Main { namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
@ -66,10 +71,15 @@ private:
bool isMegagroup = false; bool isMegagroup = false;
bool isBroadcast = false; bool isBroadcast = false;
bool isRequestNeeded = false; bool isRequestNeeded = false;
bool isFake = false;
bool isScam = false;
bool isVerified = false;
}; };
[[nodiscard]] static ChatInvite Parse( [[nodiscard]] static ChatInvite Parse(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const MTPDchatInvite &data); const MTPDchatInvite &data);
[[nodiscard]] Info::Profile::BadgeType BadgeForInvite(
const ChatInvite &invite);
ConfirmInviteBox( ConfirmInviteBox(
not_null<Main::Session*> session, not_null<Main::Session*> session,
@ -81,12 +91,14 @@ private:
Fn<void()> _submit; Fn<void()> _submit;
object_ptr<Ui::FlatLabel> _title; object_ptr<Ui::FlatLabel> _title;
std::unique_ptr<Info::Profile::Badge> _badge;
object_ptr<Ui::FlatLabel> _status; object_ptr<Ui::FlatLabel> _status;
object_ptr<Ui::FlatLabel> _about; object_ptr<Ui::FlatLabel> _about;
object_ptr<Ui::FlatLabel> _aboutRequests; object_ptr<Ui::FlatLabel> _aboutRequests;
std::shared_ptr<Data::PhotoMedia> _photo; std::shared_ptr<Data::PhotoMedia> _photo;
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty; std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
std::vector<Participant> _participants; std::vector<Participant> _participants;
bool _isChannel = false; bool _isChannel = false;
bool _requestApprove = false; bool _requestApprove = false;

View file

@ -78,12 +78,8 @@ void SendReport(
MTP_string(comment) MTP_string(comment)
)).done(std::move(done)).send(); )).done(std::move(done)).send();
}, [&](StoryId id) { }, [&](StoryId id) {
const auto user = peer->asUser();
if (!user) {
return;
}
peer->session().api().request(MTPstories_Report( peer->session().api().request(MTPstories_Report(
user->inputUser, peer->input,
MTP_vector<MTPint>(1, MTP_int(id)), MTP_vector<MTPint>(1, MTP_int(id)),
ReasonToTL(reason), ReasonToTL(reason),
MTP_string(comment) MTP_string(comment)

View file

@ -17,11 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Api { namespace Api {
namespace { namespace {
constexpr auto TestApiId = 17349; [[nodiscard]] Websites::Entry ParseEntry(
constexpr auto SnapApiId = 611335;
constexpr auto DesktopApiId = 2040;
Websites::Entry ParseEntry(
not_null<Data::Session*> owner, not_null<Data::Session*> owner,
const MTPDwebAuthorization &data) { const MTPDwebAuthorization &data) {
auto result = Websites::Entry{ auto result = Websites::Entry{

View file

@ -100,8 +100,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/storage_media_prepare.h" #include "storage/storage_media_prepare.h"
#include "storage/storage_account.h" #include "storage/storage_account.h"
// AyuGram includes
#include "ayu/ayu_settings.h" #include "ayu/ayu_settings.h"
namespace { namespace {
// Save draft to the cloud with 1 sec extra delay. // Save draft to the cloud with 1 sec extra delay.
@ -791,7 +793,7 @@ QString ApiWrap::exportDirectStoryLink(not_null<Data::Story*> story) {
? i->second ? i->second
: fallback(); : fallback();
request(MTPstories_ExportStoryLink( request(MTPstories_ExportStoryLink(
story->peer()->asUser()->inputUser, story->peer()->input,
MTP_int(story->id()) MTP_int(story->id())
)).done([=](const MTPExportedStoryLink &result) { )).done([=](const MTPExportedStoryLink &result) {
const auto link = qs(result.data().vlink()); const auto link = qs(result.data().vlink());
@ -2535,14 +2537,9 @@ void ApiWrap::refreshFileReference(
}, [&](Data::FileOriginPremiumPreviews data) { }, [&](Data::FileOriginPremiumPreviews data) {
request(MTPhelp_GetPremiumPromo()); request(MTPhelp_GetPremiumPromo());
}, [&](Data::FileOriginStory data) { }, [&](Data::FileOriginStory data) {
const auto user = _session->data().peer(data.peerId)->asUser(); request(MTPstories_GetStoriesByID(
if (user) { _session->data().peer(data.peerId)->input,
request(MTPstories_GetStoriesByID( MTP_vector<MTPint>(1, MTP_int(data.storyId))));
user->inputUser,
MTP_vector<MTPint>(1, MTP_int(data.storyId))));
} else {
fail();
}
}, [&](v::null_t) { }, [&](v::null_t) {
fail(); fail();
}); });
@ -3322,25 +3319,37 @@ void ApiWrap::shareContact(
const QString &phone, const QString &phone,
const QString &firstName, const QString &firstName,
const QString &lastName, const QString &lastName,
const SendAction &action) { const SendAction &action,
Fn<void(bool)> done) {
const auto userId = UserId(0); const auto userId = UserId(0);
sendSharedContact(phone, firstName, lastName, userId, action); sendSharedContact(
phone,
firstName,
lastName,
userId,
action,
std::move(done));
} }
void ApiWrap::shareContact( void ApiWrap::shareContact(
not_null<UserData*> user, not_null<UserData*> user,
const SendAction &action) { const SendAction &action,
Fn<void(bool)> done) {
const auto userId = peerToUser(user->id); const auto userId = peerToUser(user->id);
const auto phone = _session->data().findContactPhone(user); const auto phone = _session->data().findContactPhone(user);
if (phone.isEmpty()) { if (phone.isEmpty()) {
if (done) {
done(false);
}
return; return;
} }
sendSharedContact( return sendSharedContact(
phone, phone,
user->firstName, user->firstName,
user->lastName, user->lastName,
userId, userId,
action); action,
std::move(done));
} }
void ApiWrap::sendSharedContact( void ApiWrap::sendSharedContact(
@ -3348,7 +3357,8 @@ void ApiWrap::sendSharedContact(
const QString &firstName, const QString &firstName,
const QString &lastName, const QString &lastName,
UserId userId, UserId userId,
const SendAction &action) { const SendAction &action,
Fn<void(bool)> done) {
sendAction(action); sendAction(action);
const auto history = action.history; const auto history = action.history;
@ -3399,7 +3409,7 @@ void ApiWrap::sendSharedContact(
MTP_string(firstName), MTP_string(firstName),
MTP_string(lastName), MTP_string(lastName),
MTP_string()); // vcard MTP_string()); // vcard
sendMedia(item, media, action.options); sendMedia(item, media, action.options, std::move(done));
_session->data().sendHistoryChangeNotifications(); _session->data().sendHistoryChangeNotifications();
_session->changes().historyUpdated( _session->changes().historyUpdated(
@ -3949,18 +3959,20 @@ void ApiWrap::uploadAlbumMedia(
void ApiWrap::sendMedia( void ApiWrap::sendMedia(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPInputMedia &media, const MTPInputMedia &media,
Api::SendOptions options) { Api::SendOptions options,
Fn<void(bool)> done) {
const auto randomId = base::RandomValue<uint64>(); const auto randomId = base::RandomValue<uint64>();
_session->data().registerMessageRandomId(randomId, item->fullId()); _session->data().registerMessageRandomId(randomId, item->fullId());
sendMediaWithRandomId(item, media, options, randomId); sendMediaWithRandomId(item, media, options, randomId, std::move(done));
} }
void ApiWrap::sendMediaWithRandomId( void ApiWrap::sendMediaWithRandomId(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPInputMedia &media, const MTPInputMedia &media,
Api::SendOptions options, Api::SendOptions options,
uint64 randomId) { uint64 randomId,
Fn<void(bool)> done) {
// AyuGram useScheduledMessages // AyuGram useScheduledMessages
const auto settings = &AyuSettings::getInstance(); const auto settings = &AyuSettings::getInstance();
if (settings->useScheduledMessages && !options.scheduled) if (settings->useScheduledMessages && !options.scheduled)
@ -3969,7 +3981,6 @@ void ApiWrap::sendMediaWithRandomId(
auto current = base::unixtime::now(); auto current = base::unixtime::now();
options.scheduled = current + 12; options.scheduled = current + 12;
} }
const auto history = item->history(); const auto history = item->history();
const auto replyTo = item->replyTo(); const auto replyTo = item->replyTo();
@ -4011,10 +4022,12 @@ void ApiWrap::sendMediaWithRandomId(
MTP_int(options.scheduled), MTP_int(options.scheduled),
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()) (options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty())
), [=](const MTPUpdates &result, const MTP::Response &response) { ), [=](const MTPUpdates &result, const MTP::Response &response) {
if (done) done(true);
if (updateRecentStickers) { if (updateRecentStickers) {
requestRecentStickersForce(true); requestRecentStickersForce(true);
} }
}, [=](const MTP::Error &error, const MTP::Response &response) { }, [=](const MTP::Error &error, const MTP::Response &response) {
if (done) done(false);
sendMessageFail(error, peer, randomId, itemId); sendMessageFail(error, peer, randomId, itemId);
}); });
} }

View file

@ -294,8 +294,12 @@ public:
const QString &phone, const QString &phone,
const QString &firstName, const QString &firstName,
const QString &lastName, const QString &lastName,
const SendAction &action); const SendAction &action,
void shareContact(not_null<UserData*> user, const SendAction &action); Fn<void(bool)> done = nullptr);
void shareContact(
not_null<UserData*> user,
const SendAction &action,
Fn<void(bool)> done = nullptr);
void applyAffectedMessages( void applyAffectedMessages(
not_null<PeerData*> peer, not_null<PeerData*> peer,
const MTPmessages_AffectedMessages &result); const MTPmessages_AffectedMessages &result);
@ -489,7 +493,8 @@ private:
const QString &firstName, const QString &firstName,
const QString &lastName, const QString &lastName,
UserId userId, UserId userId,
const SendAction &action); const SendAction &action,
Fn<void(bool)> done);
void deleteHistory( void deleteHistory(
not_null<PeerData*> peer, not_null<PeerData*> peer,
@ -516,12 +521,14 @@ private:
void sendMedia( void sendMedia(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPInputMedia &media, const MTPInputMedia &media,
Api::SendOptions options); Api::SendOptions options,
Fn<void(bool)> done = nullptr);
void sendMediaWithRandomId( void sendMediaWithRandomId(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPInputMedia &media, const MTPInputMedia &media,
Api::SendOptions options, Api::SendOptions options,
uint64 randomId); uint64 randomId,
Fn<void(bool)> done = nullptr);
FileLoadTo fileLoadTaskOptions(const SendAction &action) const; FileLoadTo fileLoadTaskOptions(const SendAction &action) const;
void getTopPromotionDelayed(TimeId now, TimeId next); void getTopPromotionDelayed(TimeId now, TimeId next);

View file

@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/fields/special_fields.h" #include "ui/widgets/fields/special_fields.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/text/format_values.h" #include "ui/text/format_values.h"
@ -297,8 +298,11 @@ void AddContactBox::prepare() {
: tr::lng_enter_contact_data()); : tr::lng_enter_contact_data());
updateButtons(); updateButtons();
connect(_first, &Ui::InputField::submitted, [=] { submit(); }); const auto submitted = [=] { submit(); };
connect(_last, &Ui::InputField::submitted, [=] { submit(); }); _first->submits(
) | rpl::start_with_next(submitted, _first->lifetime());
_last->submits(
) | rpl::start_with_next(submitted, _last->lifetime());
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); }); connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
setDimensions( setDimensions(
@ -567,23 +571,24 @@ void GroupInfoBox::prepare() {
_description->setSubmitSettings( _description->setSubmitSettings(
Core::App().settings().sendSubmitWay()); Core::App().settings().sendSubmitWay());
connect(_description, &Ui::InputField::resized, [=] { _description->heightChanges(
) | rpl::start_with_next([=] {
descriptionResized(); descriptionResized();
}); }, _description->lifetime());
connect(_description, &Ui::InputField::submitted, [=] { _description->submits(
submit(); ) | rpl::start_with_next([=] { submit(); }, _description->lifetime());
}); _description->cancelled(
connect(_description, &Ui::InputField::cancelled, [=] { ) | rpl::start_with_next([=] {
closeBox(); closeBox();
}); }, _description->lifetime());
Ui::Emoji::SuggestionsController::Init( Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(), getDelegate()->outerContainer(),
_description, _description,
&_navigation->session()); &_navigation->session());
} }
_title->submits(
connect(_title, &Ui::InputField::submitted, [=] { submitName(); }); ) | rpl::start_with_next([=] { submitName(); }, _title->lifetime());
addButton( addButton(
((_type != Type::Group || _canAddBot) ((_type != Type::Group || _canAddBot)
@ -1522,20 +1527,22 @@ void EditNameBox::prepare() {
_first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName); _first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
_last->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName); _last->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
connect(_first, &Ui::InputField::submitted, [=] { submit(); }); _first->submits(
connect(_last, &Ui::InputField::submitted, [=] { submit(); }); ) | rpl::start_with_next([=] { submit(); }, _first->lifetime());
_last->submits(
) | rpl::start_with_next([=] { submit(); }, _last->lifetime());
_first->customTab(true); _first->customTab(true);
_last->customTab(true); _last->customTab(true);
QObject::connect( _first->tabbed(
_first, ) | rpl::start_with_next([=] {
&Ui::InputField::tabbed, _last->setFocus();
[=] { _last->setFocus(); }); }, _first->lifetime());
QObject::connect( _last->tabbed(
_last, ) | rpl::start_with_next([=] {
&Ui::InputField::tabbed, _first->setFocus();
[=] { _first->setFocus(); }); }, _last->lifetime());
} }
void EditNameBox::setInnerFocus() { void EditNameBox::setInnerFocus() {

View file

@ -32,27 +32,27 @@ Data::ChatFilter ChangedFilter(
auto never = base::duplicate(filter.never()); auto never = base::duplicate(filter.never());
if (add) { if (add) {
never.remove(history); never.remove(history);
const auto result = Data::ChatFilter(
filter.id(),
filter.title(),
filter.iconEmoji(),
filter.flags(),
filter.always(),
filter.pinned(),
std::move(never));
if (result.contains(history)) {
return result;
} else {
never = base::duplicate(result.never());
always.insert(history);
}
} else { } else {
const auto alwaysIt = always.find(history); always.remove(history);
if (alwaysIt != end(always)) { }
always.erase(alwaysIt); const auto result = Data::ChatFilter(
} else { filter.id(),
never.insert(history); filter.title(),
} filter.iconEmoji(),
filter.flags(),
std::move(always),
filter.pinned(),
std::move(never));
const auto in = result.contains(history);
if (in == add) {
return result;
}
always = base::duplicate(result.always());
never = base::duplicate(result.never());
if (add) {
always.insert(history);
} else {
never.insert(history);
} }
return Data::ChatFilter( return Data::ChatFilter(
filter.id(), filter.id(),

View file

@ -18,7 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/facade.h" #include "mtproto/facade.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/fields/number_input.h"
#include "ui/widgets/fields/password_input.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/dropdown_menu.h" #include "ui/widgets/dropdown_menu.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"

View file

@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
@ -184,7 +184,8 @@ not_null<Ui::FlatLabel*> CreateWarningLabel(
QString(), QString(),
st::createPollWarning); st::createPollWarning);
result->setAttribute(Qt::WA_TransparentForMouseEvents); result->setAttribute(Qt::WA_TransparentForMouseEvents);
QObject::connect(field, &Ui::InputField::changed, [=] { field->changes(
) | rpl::start_with_next([=] {
Ui::PostponeCall(crl::guard(field, [=] { Ui::PostponeCall(crl::guard(field, [=] {
const auto length = field->getLastText().size(); const auto length = field->getLastText().size();
const auto value = valueLimit - length; const auto value = valueLimit - length;
@ -198,7 +199,7 @@ not_null<Ui::FlatLabel*> CreateWarningLabel(
} }
result->setVisible(shown); result->setVisible(shown);
})); }));
}); }, field->lifetime());
return result; return result;
} }
@ -243,13 +244,14 @@ Options::Option::Option(
_content->resize(_content->width(), height); _content->resize(_content->width(), height);
}, _field->lifetime()); }, _field->lifetime());
QObject::connect(_field, &Ui::InputField::changed, [=] { _field->changes(
) | rpl::start_with_next([=] {
Ui::PostponeCall(crl::guard(_field, [=] { Ui::PostponeCall(crl::guard(_field, [=] {
if (_hasCorrect) { if (_hasCorrect) {
_correct->toggle(isGood(), anim::type::normal); _correct->toggle(isGood(), anim::type::normal);
} }
})); }));
}); }, _field->lifetime());
createShadow(); createShadow();
createRemove(); createRemove();
@ -303,10 +305,11 @@ void Options::Option::createRemove() {
const auto toggle = lifetime.make_state<rpl::variable<bool>>(false); const auto toggle = lifetime.make_state<rpl::variable<bool>>(false);
_removeAlways = lifetime.make_state<rpl::variable<bool>>(false); _removeAlways = lifetime.make_state<rpl::variable<bool>>(false);
QObject::connect(field, &Ui::InputField::changed, [=] { field->changes(
) | rpl::start_with_next([field, toggle] {
// Don't capture 'this'! Because Option is a value type. // Don't capture 'this'! Because Option is a value type.
*toggle = !field->getLastText().isEmpty(); *toggle = !field->getLastText().isEmpty();
}); }, field->lifetime());
rpl::combine( rpl::combine(
toggle->value(), toggle->value(),
_removeAlways->value(), _removeAlways->value(),
@ -649,28 +652,32 @@ void Options::addEmptyOption() {
_position + _list.size() + _destroyed.size(), _position + _list.size() + _destroyed.size(),
_chooseCorrectGroup)); _chooseCorrectGroup));
const auto field = _list.back()->field(); const auto field = _list.back()->field();
QObject::connect(field, &Ui::InputField::submitted, [=] { field->submits(
) | rpl::start_with_next([=] {
const auto index = findField(field); const auto index = findField(field);
if (_list[index]->isGood() && index + 1 < _list.size()) { if (_list[index]->isGood() && index + 1 < _list.size()) {
_list[index + 1]->setFocus(); _list[index + 1]->setFocus();
} }
}); }, field->lifetime());
QObject::connect(field, &Ui::InputField::changed, [=] { field->changes(
) | rpl::start_with_next([=] {
Ui::PostponeCall(crl::guard(field, [=] { Ui::PostponeCall(crl::guard(field, [=] {
validateState(); validateState();
})); }));
}); }, field->lifetime());
QObject::connect(field, &Ui::InputField::focused, [=] { field->focusedChanges(
) | rpl::filter(rpl::mappers::_1) | rpl::start_with_next([=] {
_scrollToWidget.fire_copy(field); _scrollToWidget.fire_copy(field);
}); }, field->lifetime());
QObject::connect(field, &Ui::InputField::tabbed, [=] { field->tabbed(
) | rpl::start_with_next([=] {
const auto index = findField(field); const auto index = findField(field);
if (index + 1 < _list.size()) { if (index + 1 < _list.size()) {
_list[index + 1]->setFocus(); _list[index + 1]->setFocus();
} else { } else {
_tabbed.fire({}); _tabbed.fire({});
} }
}); }, field->lifetime());
base::install_event_filter(field, [=](not_null<QEvent*> event) { base::install_event_filter(field, [=](not_null<QEvent*> event) {
if (event->type() != QEvent::KeyPress if (event->type() != QEvent::KeyPress
|| !field->getLastText().isEmpty()) { || !field->getLastText().isEmpty()) {
@ -927,9 +934,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
st::boxDividerLabel), st::boxDividerLabel),
st::createPollLimitPadding)); st::createPollLimitPadding));
connect(question, &Ui::InputField::tabbed, [=] { question->tabbed(
) | rpl::start_with_next([=] {
options->focusFirst(); options->focusFirst();
}); }, question->lifetime());
AddSkip(container); AddSkip(container);
AddSubsectionTitle(container, tr::lng_polls_create_settings()); AddSubsectionTitle(container, tr::lng_polls_create_settings());
@ -975,9 +983,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
} }
}, question->lifetime()); }, question->lifetime());
connect(solution, &Ui::InputField::tabbed, [=] { solution->tabbed(
) | rpl::start_with_next([=] {
question->setFocus(); question->setFocus();
}); }, solution->lifetime());
quiz->setDisabled(_disabled & PollData::Flag::Quiz); quiz->setDisabled(_disabled & PollData::Flag::Quiz);
if (multiple) { if (multiple) {
@ -1009,12 +1018,12 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
const auto text = question->getLastText().trimmed(); const auto text = question->getLastText().trimmed();
return !text.isEmpty() && (text.size() <= kQuestionLimit); return !text.isEmpty() && (text.size() <= kQuestionLimit);
}; };
question->submits(
connect(question, &Ui::InputField::submitted, [=] { ) | rpl::start_with_next([=] {
if (isValidQuestion()) { if (isValidQuestion()) {
options->focusFirst(); options->focusFirst();
} }
}); }, question->lifetime());
_setInnerFocus = [=] { _setInnerFocus = [=] {
question->setFocusFast(); question->setFocusFast();

View file

@ -54,7 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
@ -488,9 +488,16 @@ void EditCaptionBox::setupField() {
Core::App().settings().sendSubmitWay()); Core::App().settings().sendSubmitWay());
_field->setMaxHeight(st::defaultComposeFiles.caption.heightMax); _field->setMaxHeight(st::defaultComposeFiles.caption.heightMax);
connect(_field, &Ui::InputField::submitted, [=] { save(); }); _field->submits(
connect(_field, &Ui::InputField::cancelled, [=] { closeBox(); }); ) | rpl::start_with_next([=] { save(); }, _field->lifetime());
connect(_field, &Ui::InputField::resized, [=] { captionResized(); }); _field->cancelled(
) | rpl::start_with_next([=] {
closeBox();
}, _field->lifetime());
_field->heightChanges(
) | rpl::start_with_next([=] {
captionResized();
}, _field->lifetime());
_field->setMimeDataHook([=]( _field->setMimeDataHook([=](
not_null<const QMimeData*> data, not_null<const QMimeData*> data,
Ui::InputField::MimeAction action) { Ui::InputField::MimeAction action) {
@ -522,10 +529,11 @@ void EditCaptionBox::setInitialText() {
setCloseByOutsideClick(true); setCloseByOutsideClick(true);
} }
}); });
connect(_field, &Ui::InputField::changed, [=] { _field->changes(
) | rpl::start_with_next([=] {
_checkChangedTimer.callOnce(kChangesDebounceTimeout); _checkChangedTimer.callOnce(kChangesDebounceTimeout);
setCloseByOutsideClick(false); setCloseByOutsideClick(false);
}); }, _field->lifetime());
} }
void EditCaptionBox::setupControls() { void EditCaptionBox::setupControls() {

View file

@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/text/text_options.h" #include "ui/text/text_options.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
#include "ui/effects/panel_animation.h" #include "ui/effects/panel_animation.h"
#include "ui/filter_icons.h" #include "ui/filter_icons.h"
@ -619,11 +619,12 @@ void EditFilterBox(
nameEditing->custom = true; nameEditing->custom = true;
}, box->lifetime()); }, box->lifetime());
QObject::connect(name, &Ui::InputField::changed, [=] { name->changes(
) | rpl::start_with_next([=] {
if (!nameEditing->settingDefault) { if (!nameEditing->settingDefault) {
nameEditing->custom = true; nameEditing->custom = true;
} }
}); }, name->lifetime());
const auto updateDefaultTitle = [=](const Data::ChatFilter &filter) { const auto updateDefaultTitle = [=](const Data::ChatFilter &filter) {
if (nameEditing->custom) { if (nameEditing->custom) {
return; return;

View file

@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/invite_link_label.h" #include "ui/controls/invite_link_label.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/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"

View file

@ -21,10 +21,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#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/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/fields/password_input.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/sent_code_field.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
#include "ui/painter.h" #include "ui/painter.h"
#include "passport/passport_encryption.h" #include "passport/passport_encryption.h"
@ -306,15 +305,26 @@ void PasscodeBox::prepare() {
connect(_oldPasscode, &Ui::MaskedInputField::changed, [=] { oldChanged(); }); connect(_oldPasscode, &Ui::MaskedInputField::changed, [=] { oldChanged(); });
connect(_newPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); }); connect(_newPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); });
connect(_reenterPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); }); connect(_reenterPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); });
connect(_passwordHint, &Ui::InputField::changed, [=] { newChanged(); }); _passwordHint->changes(
connect(_recoverEmail, &Ui::InputField::changed, [=] { emailChanged(); }); ) | rpl::start_with_next([=] {
newChanged();
}, _passwordHint->lifetime());
_recoverEmail->changes(
) | rpl::start_with_next([=] {
if (!_emailError.isEmpty()) {
_emailError = QString();
update();
}
}, _recoverEmail->lifetime());
const auto fieldSubmit = [=] { submit(); }; const auto fieldSubmit = [=] { submit(); };
connect(_oldPasscode, &Ui::MaskedInputField::submitted, fieldSubmit); connect(_oldPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
connect(_newPasscode, &Ui::MaskedInputField::submitted, fieldSubmit); connect(_newPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
connect(_reenterPasscode, &Ui::MaskedInputField::submitted, fieldSubmit); connect(_reenterPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
connect(_passwordHint, &Ui::InputField::submitted, fieldSubmit); _passwordHint->submits(
connect(_recoverEmail, &Ui::InputField::submitted, fieldSubmit); ) | rpl::start_with_next(fieldSubmit, _passwordHint->lifetime());
_recoverEmail->submits(
) | rpl::start_with_next(fieldSubmit, _recoverEmail->lifetime());
_recover->addClickHandler([=] { recoverByEmail(); }); _recover->addClickHandler([=] { recoverByEmail(); });
@ -1061,13 +1071,6 @@ void PasscodeBox::newChanged() {
} }
} }
void PasscodeBox::emailChanged() {
if (!_emailError.isEmpty()) {
_emailError = QString();
update();
}
}
void PasscodeBox::recoverByEmail() { void PasscodeBox::recoverByEmail() {
if (!_cloudFields.hasRecovery) { if (!_cloudFields.hasRecovery) {
Assert(_session != nullptr); Assert(_session != nullptr);
@ -1189,8 +1192,12 @@ void RecoverBox::prepare() {
+ _recoverCode->height() + _recoverCode->height()
+ st::passcodeTextLine)); + st::passcodeTextLine));
connect(_recoverCode, &Ui::InputField::changed, [=] { codeChanged(); }); _recoverCode->changes(
connect(_recoverCode, &Ui::InputField::submitted, [=] { submit(); }); ) | rpl::start_with_next([=] {
codeChanged();
}, _recoverCode->lifetime());
_recoverCode->submits(
) | rpl::start_with_next([=] { submit(); }, _recoverCode->lifetime());
} }
void RecoverBox::paintEvent(QPaintEvent *e) { void RecoverBox::paintEvent(QPaintEvent *e) {

View file

@ -90,7 +90,6 @@ private:
void closeReplacedBy(); void closeReplacedBy();
void oldChanged(); void oldChanged();
void newChanged(); void newChanged();
void emailChanged();
void save(bool force = false); void save(bool force = false);
void badOldPasscode(); void badOldPasscode();
void recoverByEmail(); void recoverByEmail();

View file

@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/text/format_values.h" // Ui::FormatPhone #include "ui/text/format_values.h" // Ui::FormatPhone
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "info/profile/info_profile_cover.h" #include "info/profile/info_profile_cover.h"
@ -239,8 +239,8 @@ void Controller::initNameFields(
_save(); _save();
} }
}; };
QObject::connect(first, &Ui::InputField::submitted, submit); first->submits() | rpl::start_with_next(submit, first->lifetime());
QObject::connect(last, &Ui::InputField::submitted, submit); last->submits() | rpl::start_with_next(submit, last->lifetime());
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName); first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName); first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
} }

View file

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "boxes/peers/edit_forum_topic_box.h" #include "boxes/peers/edit_forum_topic_box.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/effects/emoji_fly_animation.h" #include "ui/effects/emoji_fly_animation.h"
#include "ui/abstract_button.h" #include "ui/abstract_button.h"
@ -465,15 +465,13 @@ void EditForumTopicBox(
ChooseNextColorId(current.colorId, state->otherColorIds), ChooseNextColorId(current.colorId, state->otherColorIds),
}; };
}); });
base::qt_signal_producer( title->changes(
title,
&Ui::InputField::changed
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
state->defaultIcon = DefaultIcon{ state->defaultIcon = DefaultIcon{
title->getLastText().trimmed(), title->getLastText().trimmed(),
state->defaultIcon.current().colorId, state->defaultIcon.current().colorId,
}; };
}, box->lifetime()); }, title->lifetime());
if (!topic || !topic->isGeneral()) { if (!topic || !topic->isGeneral()) {
Settings::AddDividerText( Settings::AddDividerText(

View file

@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/box_content_divider.h" #include "ui/widgets/box_content_divider.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
@ -384,8 +384,11 @@ void EditAdminBox::prepare() {
if (!_saveCallback) { if (!_saveCallback) {
return; return;
} else if (_addAsAdmin && !_addAsAdmin->checked()) { } else if (_addAsAdmin && !_addAsAdmin->checked()) {
const auto weak = Ui::MakeWeak(this);
AddBotToGroup(user(), peer(), _addingBot->token); AddBotToGroup(user(), peer(), _addingBot->token);
getDelegate()->hideLayer(); if (const auto strong = weak.data()) {
strong->closeBox();
}
return; return;
} else if (_addingBot && !_addingBot->existing) { } else if (_addingBot && !_addingBot->existing) {
const auto phrase = peer()->isBroadcast() const auto phrase = peer()->isBroadcast()
@ -461,13 +464,14 @@ not_null<Ui::InputField*> EditAdminBox::addRankInput(
st::rightsAboutMargin); st::rightsAboutMargin);
result->setMaxLength(kAdminRoleLimit); result->setMaxLength(kAdminRoleLimit);
result->setInstantReplaces(Ui::InstantReplaces::TextOnly()); result->setInstantReplaces(Ui::InstantReplaces::TextOnly());
connect(result, &Ui::InputField::changed, [=] { result->changes(
) | rpl::start_with_next([=] {
const auto text = result->getLastText(); const auto text = result->getLastText();
const auto removed = TextUtilities::RemoveEmoji(text); const auto removed = TextUtilities::RemoveEmoji(text);
if (removed != text) { if (removed != text) {
result->setText(removed); result->setText(removed);
} }
}); }, result->lifetime());
container->add( container->add(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(

View file

@ -51,7 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/box_content_divider.h" #include "ui/widgets/box_content_divider.h"
#include "ui/wrap/padding_wrap.h" #include "ui/wrap/padding_wrap.h"
@ -519,10 +519,10 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
result->entity(), result->entity(),
&_peer->session()); &_peer->session());
QObject::connect( result->entity()->submits(
result->entity(), ) | rpl::start_with_next([=] {
&Ui::InputField::submitted, submitTitle();
[=] { submitTitle(); }); }, result->entity()->lifetime());
_controls.title = result->entity(); _controls.title = result->entity();
return result; return result;
@ -555,10 +555,10 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
result->entity(), result->entity(),
&_peer->session()); &_peer->session());
QObject::connect( result->entity()->submits(
result->entity(), ) | rpl::start_with_next([=] {
&Ui::InputField::submitted, submitDescription();
[=] { submitDescription(); }); }, result->entity()->lifetime());
_controls.description = result->entity(); _controls.description = result->entity();
return result; return result;

View file

@ -51,13 +51,14 @@ constexpr auto kForceDisableTooltipDuration = 3 * crl::time(1000);
} }
[[nodiscard]] auto NestedRestrictionLabelsList( [[nodiscard]] auto NestedRestrictionLabelsList(
Data::RestrictionsSetOptions options) { Data::RestrictionsSetOptions options)
-> std::vector<NestedEditFlagsLabels<ChatRestrictions>> {
using Flag = ChatRestriction; using Flag = ChatRestriction;
auto first = std::vector<RestrictionLabel>{ auto first = std::vector<RestrictionLabel>{
{ Flag::SendOther, tr::lng_rights_chat_send_text(tr::now) }, { Flag::SendOther, tr::lng_rights_chat_send_text(tr::now) },
}; };
auto inner = std::vector<RestrictionLabel>{ auto media = std::vector<RestrictionLabel>{
{ Flag::SendPhotos, tr::lng_rights_chat_photos(tr::now) }, { Flag::SendPhotos, tr::lng_rights_chat_photos(tr::now) },
{ Flag::SendVideos, tr::lng_rights_chat_videos(tr::now) }, { Flag::SendVideos, tr::lng_rights_chat_videos(tr::now) },
{ Flag::SendVideoMessages, tr::lng_rights_chat_video_messages(tr::now) }, { Flag::SendVideoMessages, tr::lng_rights_chat_video_messages(tr::now) },
@ -85,9 +86,64 @@ constexpr auto kForceDisableTooltipDuration = 3 * crl::time(1000);
&RestrictionLabel::flags), &RestrictionLabel::flags),
end(second)); end(second));
} }
return std::vector<NestedEditFlagsLabels<ChatRestrictions>>{ return {
{ std::nullopt, std::move(first) }, { std::nullopt, std::move(first) },
{ tr::lng_rights_chat_send_media(), std::move(inner) }, { tr::lng_rights_chat_send_media(), std::move(media) },
{ std::nullopt, std::move(second) },
};
}
[[nodiscard]] auto NestedAdminRightLabels(
Data::AdminRightsSetOptions options)
-> std::vector<NestedEditFlagsLabels<ChatAdminRights>> {
using Flag = ChatAdminRight;
if (options.isGroup) {
auto result = std::vector<AdminRightLabel>{
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
{ Flag::InviteByLinkOrAdd, options.anyoneCanAddMembers
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageTopics, tr::lng_rights_group_topics(tr::now) },
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
};
if (!options.isForum) {
result.erase(
ranges::remove(
result,
Flag::ManageTopics | Flag(),
&AdminRightLabel::flags),
end(result));
}
return { { std::nullopt, std::move(result) } };
}
auto first = std::vector<AdminRightLabel>{
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
};
auto messages = std::vector<AdminRightLabel>{
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
};
auto stories = std::vector<AdminRightLabel>{
{ Flag::PostStories, tr::lng_rights_channel_post_stories(tr::now) },
{ Flag::EditStories, tr::lng_rights_channel_edit_stories(tr::now) },
{ Flag::DeleteStories, tr::lng_rights_channel_delete_stories(tr::now) },
};
auto second = std::vector<AdminRightLabel>{
{ Flag::InviteByLinkOrAdd, tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
};
return {
{ std::nullopt, std::move(first) },
{ tr::lng_rights_channel_manage(), std::move(messages) },
{ tr::lng_rights_channel_manage_stories(), std::move(stories) },
{ std::nullopt, std::move(second) }, { std::nullopt, std::move(second) },
}; };
} }
@ -1031,42 +1087,11 @@ std::vector<RestrictionLabel> RestrictionLabels(
std::vector<AdminRightLabel> AdminRightLabels( std::vector<AdminRightLabel> AdminRightLabels(
Data::AdminRightsSetOptions options) { Data::AdminRightsSetOptions options) {
using Flag = ChatAdminRight; auto result = std::vector<AdminRightLabel>();
for (const auto &[_, r] : NestedAdminRightLabels(options)) {
if (options.isGroup) { result.insert(result.end(), r.begin(), r.end());
auto result = std::vector<AdminRightLabel>{
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
{ Flag::InviteByLinkOrAdd, options.anyoneCanAddMembers
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageTopics, tr::lng_rights_group_topics(tr::now) },
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
};
if (!options.isForum) {
result.erase(
ranges::remove(
result,
Flag::ManageTopics | Flag(),
&AdminRightLabel::flags),
end(result));
}
return result;
} else {
return {
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
{ Flag::InviteByLinkOrAdd, tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) }
};
} }
return result;
} }
EditFlagsControl<ChatRestrictions> CreateEditRestrictions( EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
@ -1107,7 +1132,7 @@ EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
rights, rights,
{ {
.header = std::move(header), .header = std::move(header),
.labels = { { std::nullopt, AdminRightLabels(options) } }, .labels = NestedAdminRightLabels(options),
.disabledMessages = std::move(disabledMessages), .disabledMessages = std::move(disabledMessages),
}); });
result.widget = std::move(widget); result.widget = std::move(widget);

View file

@ -32,7 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/userpic_button.h" #include "ui/controls/userpic_button.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/box_content_divider.h" #include "ui/widgets/box_content_divider.h"
#include "ui/wrap/padding_wrap.h" #include "ui/wrap/padding_wrap.h"

View file

@ -48,19 +48,6 @@ struct InfographicDescriptor {
bool complexRatio = false; bool complexRatio = false;
}; };
[[nodiscard]] rpl::producer<> BoxShowFinishes(not_null<Ui::GenericBox*> box) {
const auto singleShot = box->lifetime().make_state<rpl::lifetime>();
const auto showFinishes = singleShot->make_state<rpl::event_stream<>>();
box->setShowFinishedCallback([=] {
showFinishes->fire({});
singleShot->destroy();
box->setShowFinishedCallback(nullptr);
});
return showFinishes->events();
}
void AddSubsectionTitle( void AddSubsectionTitle(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text) { rpl::producer<QString> text) {
@ -423,8 +410,9 @@ void SimpleLimitBox(
Settings::AddSkip(top, st::premiumInfographicPadding.top()); Settings::AddSkip(top, st::premiumInfographicPadding.top());
Ui::Premium::AddBubbleRow( Ui::Premium::AddBubbleRow(
top, top,
st::defaultPremiumBubble,
BoxShowFinishes(box), BoxShowFinishes(box),
descriptor.defaultLimit, 0,
descriptor.current, descriptor.current,
descriptor.premiumLimit, descriptor.premiumLimit,
premiumPossible, premiumPossible,
@ -783,16 +771,18 @@ void FilterLinksLimitBox(
void FiltersLimitBox( void FiltersLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) { not_null<Main::Session*> session,
std::optional<int> filtersCountOverride) {
const auto premium = session->premium(); const auto premium = session->premium();
const auto premiumPossible = session->premiumPossible(); const auto premiumPossible = session->premiumPossible();
const auto limits = Data::PremiumLimits(session); const auto limits = Data::PremiumLimits(session);
const auto defaultLimit = float64(limits.dialogFiltersDefault()); const auto defaultLimit = float64(limits.dialogFiltersDefault());
const auto premiumLimit = float64(limits.dialogFiltersPremium()); const auto premiumLimit = float64(limits.dialogFiltersPremium());
const auto current = float64(ranges::count_if( const auto cloud = int(ranges::count_if(
session->data().chatsFilters().list(), session->data().chatsFilters().list(),
[](const Data::ChatFilter &f) { return f.id() != FilterId(); })); [](const Data::ChatFilter &f) { return f.id() != FilterId(); }));
const auto current = float64(filtersCountOverride.value_or(cloud));
auto text = rpl::combine( auto text = rpl::combine(
tr::lng_filters_limit1( tr::lng_filters_limit1(
@ -1092,6 +1082,7 @@ void AccountsLimitBox(
Settings::AddSkip(top, st::premiumInfographicPadding.top()); Settings::AddSkip(top, st::premiumInfographicPadding.top());
Ui::Premium::AddBubbleRow( Ui::Premium::AddBubbleRow(
top, top,
st::defaultPremiumBubble,
BoxShowFinishes(box), BoxShowFinishes(box),
0, 0,
current, current,

View file

@ -42,7 +42,8 @@ void FilterLinksLimitBox(
not_null<Main::Session*> session); not_null<Main::Session*> session);
void FiltersLimitBox( void FiltersLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session); not_null<Main::Session*> session,
std::optional<int> filtersCountOverride);
void ShareableFiltersLimitBox( void ShareableFiltersLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session); not_null<Main::Session*> session);

View file

@ -31,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/scroll_content_shadow.h" #include "ui/effects/scroll_content_shadow.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
@ -1033,17 +1033,21 @@ void SendFilesBox::setupCaption() {
Core::App().settings().sendSubmitWay()); Core::App().settings().sendSubmitWay());
_caption->setMaxLength(kMaxMessageLength); _caption->setMaxLength(kMaxMessageLength);
connect(_caption, &Ui::InputField::resized, [=] { _caption->heightChanges(
) | rpl::start_with_next([=] {
captionResized(); captionResized();
}); }, _caption->lifetime());
connect(_caption, &Ui::InputField::submitted, [=]( _caption->submits(
Qt::KeyboardModifiers modifiers) { ) | rpl::start_with_next([=](Qt::KeyboardModifiers modifiers) {
const auto ctrlShiftEnter = modifiers.testFlag(Qt::ShiftModifier) const auto ctrlShiftEnter = modifiers.testFlag(Qt::ShiftModifier)
&& (modifiers.testFlag(Qt::ControlModifier) && (modifiers.testFlag(Qt::ControlModifier)
|| modifiers.testFlag(Qt::MetaModifier)); || modifiers.testFlag(Qt::MetaModifier));
send({}, ctrlShiftEnter); send({}, ctrlShiftEnter);
}); }, _caption->lifetime());
connect(_caption, &Ui::InputField::cancelled, [=] { closeBox(); }); _caption->cancelled(
) | rpl::start_with_next([=] {
closeBox();
}, _caption->lifetime());
_caption->setMimeDataHook([=]( _caption->setMimeDataHook([=](
not_null<const QMimeData*> data, not_null<const QMimeData*> data,
Ui::InputField::MimeAction action) { Ui::InputField::MimeAction action) {

View file

@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
@ -144,7 +144,7 @@ void RenameBox(not_null<Ui::GenericBox*> box) {
Core::App().settings().setCustomDeviceModel(result); Core::App().settings().setCustomDeviceModel(result);
Core::App().saveSettingsDelayed(); Core::App().saveSettingsDelayed();
}; };
QObject::connect(name, &Ui::InputField::submitted, submit); name->submits() | rpl::start_with_next(submit, name->lifetime());
box->addButton(tr::lng_settings_save(), submit); box->addButton(tr::lng_settings_save(), submit);
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
} }

View file

@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/multi_select.h" #include "ui/widgets/multi_select.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
#include "ui/text/text_options.h" #include "ui/text/text_options.h"
@ -226,9 +226,8 @@ void ShareBox::prepareCommentField() {
const auto field = _comment->entity(); const auto field = _comment->entity();
connect(field, &Ui::InputField::submitted, [=] { field->submits(
submit({}); ) | rpl::start_with_next([=] { submit({}); }, field->lifetime());
});
if (const auto show = uiShow(); show->valid()) { if (const auto show = uiShow(); show->valid()) {
InitMessageFieldHandlers( InitMessageFieldHandlers(
_descriptor.session, _descriptor.session,
@ -249,6 +248,8 @@ void ShareBox::prepareCommentField() {
void ShareBox::prepare() { void ShareBox::prepare() {
prepareCommentField(); prepareCommentField();
setCloseByOutsideClick(false);
_select->resizeToWidth(st::boxWideWidth); _select->resizeToWidth(st::boxWideWidth);
Ui::SendPendingMoveResizeEvents(_select); Ui::SendPendingMoveResizeEvents(_select);

View file

@ -31,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/effects/slide_animation.h" #include "ui/effects/slide_animation.h"
#include "ui/widgets/discrete_sliders.h" #include "ui/widgets/discrete_sliders.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/cached_round_corners.h" #include "ui/cached_round_corners.h"
#include "ui/painter.h" #include "ui/painter.h"

View file

@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/menu/menu_action.h" #include "ui/widgets/menu/menu_action.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/painter.h" #include "ui/painter.h"

View file

@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/call_button.h" #include "ui/widgets/call_button.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/dropdown_menu.h" #include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/tooltip.h" #include "ui/widgets/tooltip.h"
#include "ui/widgets/rp_window.h" #include "ui/widgets/rp_window.h"
#include "ui/chat/group_call_bar.h" #include "ui/chat/group_call_bar.h"

View file

@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/continuous_sliders.h" #include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"

View file

@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image_prepare.h" #include "ui/image/image_prepare.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/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
@ -287,7 +287,7 @@ void EditGroupCallTitleBox(
box->closeBox(); box->closeBox();
done(result); done(result);
}; };
QObject::connect(input, &Ui::InputField::submitted, submit); input->submits() | rpl::start_with_next(submit, input->lifetime());
box->addButton(tr::lng_settings_save(), submit); box->addButton(tr::lng_settings_save(), submit);
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
} }
@ -346,7 +346,7 @@ void AddTitleGroupCallRecordingBox(
box->closeBox(); box->closeBox();
done(result); done(result);
}; };
QObject::connect(input, &Ui::InputField::submitted, submit); input->submits() | rpl::start_with_next(submit, input->lifetime());
box->addButton(tr::lng_group_call_recording_start_button(), submit); box->addButton(tr::lng_group_call_recording_start_button(), submit);
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
} }

View file

@ -41,9 +41,9 @@ inline auto PreviewPath(int i) {
const auto kSets = { const auto kSets = {
Set{ { 0, 0, 0, "Mac" }, PreviewPath(0) }, Set{ { 0, 0, 0, "Mac" }, PreviewPath(0) },
Set{ { 1, 1392, 8'184'590, "Android" }, PreviewPath(1) }, Set{ { 1, 1804, 8'115'639, "Android" }, PreviewPath(1) },
Set{ { 2, 1393, 5'413'219, "Twemoji" }, PreviewPath(2) }, Set{ { 2, 1805, 5'481'197, "Twemoji" }, PreviewPath(2) },
Set{ { 3, 1394, 6'967'218, "JoyPixels" }, PreviewPath(3) }, Set{ { 3, 1806, 7'047'594, "JoyPixels" }, PreviewPath(3) },
}; };
using Loading = MTP::DedicatedLoader::Progress; using Loading = MTP::DedicatedLoader::Progress;

View file

@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/widgets/inner_dropdown.h" #include "ui/widgets/inner_dropdown.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "ui/cached_round_corners.h" #include "ui/cached_round_corners.h"

View file

@ -31,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/clip/media_clip_reader.h" #include "media/clip/media_clip_reader.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/text/text_options.h" #include "ui/text/text_options.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/effects/path_shift_gradient.h" #include "ui/effects/path_shift_gradient.h"

View file

@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "ui/controls/tabbed_search.h" #include "ui/controls/tabbed_search.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/image/image.h" #include "ui/image/image.h"

View file

@ -190,16 +190,18 @@ void EditLinkBox(
} }
}; };
QObject::connect(text, &Ui::InputField::submitted, [=] { text->submits(
) | rpl::start_with_next([=] {
url->setFocusFast(); url->setFocusFast();
}); }, text->lifetime());
QObject::connect(url, &Ui::InputField::submitted, [=] { url->submits(
) | rpl::start_with_next([=] {
if (text->getLastText().isEmpty()) { if (text->getLastText().isEmpty()) {
text->setFocusFast(); text->setFocusFast();
} else { } else {
submit(); submit();
} }
}); }, url->lifetime());
box->setTitle(url->getLastText().isEmpty() box->setTitle(url->getLastText().isEmpty()
? tr::lng_formatting_link_create_title() ? tr::lng_formatting_link_create_title()
@ -223,8 +225,14 @@ void EditLinkBox(
url->customTab(true); url->customTab(true);
text->customTab(true); text->customTab(true);
QObject::connect(url, &Ui::InputField::tabbed, [=] { text->setFocus(); }); url->tabbed(
QObject::connect(text, &Ui::InputField::tabbed, [=] { url->setFocus(); }); ) | rpl::start_with_next([=] {
text->setFocus();
}, url->lifetime());
text->tabbed(
) | rpl::start_with_next([=] {
url->setFocus();
}, text->lifetime());
} }
TextWithEntities StripSupportHashtag(TextWithEntities text) { TextWithEntities StripSupportHashtag(TextWithEntities text) {
@ -590,7 +598,8 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery(
MessageLinksParser::MessageLinksParser(not_null<Ui::InputField*> field) MessageLinksParser::MessageLinksParser(not_null<Ui::InputField*> field)
: _field(field) : _field(field)
, _timer([=] { parse(); }) { , _timer([=] { parse(); }) {
_connection = QObject::connect(_field, &Ui::InputField::changed, [=] { _lifetime = _field->changes(
) | rpl::start_with_next([=] {
const auto length = _field->getTextWithTags().text.size(); const auto length = _field->getTextWithTags().text.size();
const auto timeout = (std::abs(length - _lastLength) > 2) const auto timeout = (std::abs(length - _lastLength) > 2)
? 0 ? 0

View file

@ -7,9 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "base/timer.h" #include "base/timer.h"
#include "base/qt_connection.h"
#include "chat_helpers/compose/compose_features.h" #include "chat_helpers/compose/compose_features.h"
#ifndef TDESKTOP_DISABLE_SPELLCHECK #ifndef TDESKTOP_DISABLE_SPELLCHECK
@ -132,7 +131,7 @@ private:
int _lastLength = 0; int _lastLength = 0;
bool _disabled = false; bool _disabled = false;
base::Timer _timer; base::Timer _timer;
base::qt_connection _connection; rpl::lifetime _lifetime;
}; };

View file

@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lottie/lottie_single_player.h" #include "lottie/lottie_single_player.h"
#include "ui/dpr/dpr_icon.h" #include "ui/dpr/dpr_icon.h"
#include "ui/dpr/dpr_image.h" #include "ui/dpr/dpr_image.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/rect_part.h" #include "ui/rect_part.h"

View file

@ -22,110 +22,6 @@ namespace {
std::map<int, const char*> BetaLogs() { std::map<int, const char*> BetaLogs() {
return { return {
{
4005004,
"- Allow wide range of interface scale options.\n"
"- Show opened chat name in the window title.\n"
"- Bug fixes and other minor improvements.\n"
"- Fix updating on macOS older than 10.14.\n"
},
{
4005006,
"- Try enabling non-fractional scale "
"High DPI support on Windows and Linux.\n"
"- Experimental setting for fractional scale "
"High DPI support on Windows and Linux.\n"
"- Fix navigation to bottom problems in groups you didn't join.\n"
"- Fix a crash in chat export settings changes.\n"
"- Fix a crash in sending some of JPEG images.\n"
"- Fix CJK fonts on Windows.\n"
},
{
4005007,
"- Fix glitches after moving window to another screen.\n",
},
{
4005008,
"- Allow opening another account in a new window "
"(see Settings > Advanced > Experimental Settings).\n"
"- A lot of bugfixes for working with more than one window.\n"
},
{
4006004,
"- Allow media viewer to exit fullscreen and become a normal window."
},
{
4006006,
"- Confirmation window before starting a call.\n"
"- New \"Battery and Animations\" settings section.\n"
"- \"Save Power on Low Battery\" option for laptops.\n"
"- Improved windowed mode support for media viewer.\n"
"- Hardware accelerated video playback fix on macOS.\n"
"- New application icon on macOS following the system guidelines.\n"
},
{
4006007,
"- Fix crash when accepting incoming calls.\n"
"- Remove sound when cancelling an unconfirmed call.\n"
},
{
4006008,
"- Improve quality of voice messages with changed playback speed.\n"
"- Show when your message was read in small groups.\n"
"- Fix pasting images from Firefox on Windows.\n"
"- Improve memory usage for custom emoji.\n"
},
{
4006010,
"- Suggest sending an invite link if user forbids "
"inviting him to groups.\n"
"- Show when a reaction was left on your message in small groups.\n"
"- Fix a crash in video chats on Windows.\n"
"- Fix a crash in audio speed change.\n"
},
{
4006011,
"- Allow larger interface scale values on high-dpi screens.\n"
"- Implement new voice and video speed change interface (up to 2.5x).\n"
"- Support global Fn+F shortcut to toggle fullscreen on macOS.\n"
"- Silent notification sound in Focus Mode on macOS.\n"
"- Fix media viewer on macOS with several screens.\n"
"- Fix a crash in connection type box.\n"
"- Fix possible crash on quit.\n"
},
{
4006012,
"- Fix several possible crashes.\n"
"- Deprecate macOS 10.12, Ubuntu 18.04 and CentOS 7 in July.\n"
},
{ {
4008011, 4008011,
"- Fix initial video playback speed.\n" "- Fix initial video playback speed.\n"

View file

@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/send_files_box.h" #include "boxes/send_files_box.h"
#include "history/view/history_view_quick_action.h" #include "history/view/history_view_quick_action.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "storage/serialize_common.h" #include "storage/serialize_common.h"
#include "window/section_widget.h" #include "window/section_widget.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"

View file

@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <new> #include <new>
#include <mutex> #include <mutex>
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <new.h> #include <new.h>
@ -25,7 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <client/windows/handler/exception_handler.h> #include <client/windows/handler/exception_handler.h>
#pragma warning(pop) #pragma warning(pop)
#elif defined Q_OS_UNIX // Q_OS_WIN #else // Q_OS_WIN
#include <execinfo.h> #include <execinfo.h>
#include <sys/syscall.h> #include <sys/syscall.h>
@ -48,7 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#endif // Q_OS_MAC #endif // Q_OS_MAC
#endif // Q_OS_WIN #endif // Q_OS_WIN
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // !TDESKTOP_DISABLE_CRASH_REPORTS
namespace CrashReports { namespace CrashReports {
namespace { namespace {
@ -59,7 +59,7 @@ using AnnotationRefs = std::map<std::string, const QString*>;
Annotations ProcessAnnotations; Annotations ProcessAnnotations;
AnnotationRefs ProcessAnnotationRefs; AnnotationRefs ProcessAnnotationRefs;
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
QString ReportPath; QString ReportPath;
FILE *ReportFile = nullptr; FILE *ReportFile = nullptr;
@ -197,13 +197,15 @@ const int HandledSignals[] = {
SIGABRT, SIGABRT,
SIGFPE, SIGFPE,
SIGILL, SIGILL,
#ifdef Q_OS_UNIX #ifndef Q_OS_WIN
SIGBUS, SIGBUS,
SIGTRAP, SIGTRAP,
#endif // Q_OS_UNIX #endif // !Q_OS_WIN
}; };
#ifdef Q_OS_UNIX #ifdef Q_OS_WIN
void SignalHandler(int signum) {
#else // Q_OS_WIN
struct sigaction OldSigActions[32]/* = { 0 }*/; struct sigaction OldSigActions[32]/* = { 0 }*/;
void RestoreSignalHandlers() { void RestoreSignalHandlers() {
@ -229,9 +231,7 @@ void InvokeOldSignalHandler(int signum, siginfo_t *info, void *ucontext) {
void SignalHandler(int signum, siginfo_t *info, void *ucontext) { void SignalHandler(int signum, siginfo_t *info, void *ucontext) {
RestoreSignalHandlers(); RestoreSignalHandlers();
#else // Q_OS_UNIX #endif // else for Q_OS_WIN
void SignalHandler(int signum) {
#endif // else for Q_OS_UNIX
const char* name = 0; const char* name = 0;
switch (signum) { switch (signum) {
@ -253,9 +253,9 @@ void SignalHandler(int signum) {
ReportingThreadId = nullptr; ReportingThreadId = nullptr;
} }
#ifdef Q_OS_UNIX #ifndef Q_OS_WIN
InvokeOldSignalHandler(signum, info, ucontext); InvokeOldSignalHandler(signum, info, ucontext);
#endif // Q_OS_UNIX #endif // !Q_OS_WIN
} }
bool SetSignalHandlers = true; bool SetSignalHandlers = true;
@ -267,9 +267,9 @@ google_breakpad::ExceptionHandler* BreakpadExceptionHandler = 0;
bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success) bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success)
#elif defined Q_OS_MAC // Q_OS_WIN #elif defined Q_OS_MAC // Q_OS_WIN
bool DumpCallback(const char* _dump_dir, const char* _minidump_id, void *context, bool success) bool DumpCallback(const char* _dump_dir, const char* _minidump_id, void *context, bool success)
#elif defined Q_OS_UNIX // Q_OS_MAC #else // Q_OS_MAC
bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success) bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success)
#endif // Q_OS_UNIX #endif // else for Q_OS_WIN || Q_OS_MAC
{ {
if (CrashLogged) return success; if (CrashLogged) return success;
CrashLogged = true; CrashLogged = true;
@ -290,7 +290,7 @@ bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context,
} }
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD #endif // !Q_OS_MAC || MAC_USE_BREAKPAD
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // !TDESKTOP_DISABLE_CRASH_REPORTS
} // namespace } // namespace
@ -314,7 +314,7 @@ QString PlatformString() {
} }
void StartCatching() { void StartCatching() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
ProcessAnnotations["Binary"] = cExeName().toUtf8().constData(); ProcessAnnotations["Binary"] = cExeName().toUtf8().constData();
ProcessAnnotations["ApiId"] = QString::number(ApiId).toUtf8().constData(); ProcessAnnotations["ApiId"] = QString::number(ApiId).toUtf8().constData();
ProcessAnnotations["Version"] = (cAlphaVersion() ProcessAnnotations["Version"] = (cAlphaVersion()
@ -370,7 +370,7 @@ void StartCatching() {
false)) { // asynchronous_start false)) { // asynchronous_start
} }
#endif // else for MAC_USE_BREAKPAD #endif // else for MAC_USE_BREAKPAD
#elif defined Q_OS_UNIX #else
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
google_breakpad::MinidumpDescriptor(QFile::encodeName(dumpspath).toStdString()), google_breakpad::MinidumpDescriptor(QFile::encodeName(dumpspath).toStdString()),
/*FilterCallback*/ 0, /*FilterCallback*/ 0,
@ -379,22 +379,22 @@ void StartCatching() {
true, true,
-1 -1
); );
#endif // Q_OS_UNIX #endif // else for Q_OS_WIN || Q_OS_MAC
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // !TDESKTOP_DISABLE_CRASH_REPORTS
} }
void FinishCatching() { void FinishCatching() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
#if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD #if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
delete base::take(BreakpadExceptionHandler); delete base::take(BreakpadExceptionHandler);
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD #endif // !Q_OS_MAC || MAC_USE_BREAKPAD
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // !TDESKTOP_DISABLE_CRASH_REPORTS
} }
StartResult Start() { StartResult Start() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
ReportPath = cWorkingDir() + u"tdata/working"_q; ReportPath = cWorkingDir() + u"tdata/working"_q;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@ -420,12 +420,12 @@ StartResult Start() {
return lastdump; return lastdump;
} }
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // !TDESKTOP_DISABLE_CRASH_REPORTS
return Restart(); return Restart();
} }
Status Restart() { Status Restart() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
if (ReportFile) { if (ReportFile) {
return Started; return Started;
} }
@ -470,13 +470,13 @@ Status Restart() {
LOG(("FATAL: Could not open '%1' for writing!").arg(ReportPath)); LOG(("FATAL: Could not open '%1' for writing!").arg(ReportPath));
return CantOpen; return CantOpen;
#else // !DESKTOP_APP_DISABLE_CRASH_REPORTS #else // !TDESKTOP_DISABLE_CRASH_REPORTS
return Started; return Started;
#endif // else for !DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // else for !TDESKTOP_DISABLE_CRASH_REPORTS
} }
void Finish() { void Finish() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
FinishCatching(); FinishCatching();
if (ReportFile) { if (ReportFile) {
@ -489,7 +489,7 @@ void Finish() {
unlink(ReportPath.toUtf8().constData()); unlink(ReportPath.toUtf8().constData());
#endif // else for Q_OS_WIN #endif // else for Q_OS_WIN
} }
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // !TDESKTOP_DISABLE_CRASH_REPORTS
} }
void SetAnnotation(const std::string &key, const QString &value) { void SetAnnotation(const std::string &key, const QString &value) {
@ -539,7 +539,7 @@ void SetAnnotationRef(const std::string &key, const QString *valuePtr) {
} }
} }
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
dump::~dump() { dump::~dump() {
if (ReportFile) { if (ReportFile) {
@ -604,6 +604,6 @@ const dump &operator<<(const dump &stream, double num) {
return stream; return stream;
} }
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // TDESKTOP_DISABLE_CRASH_REPORTS
} // namespace CrashReports } // namespace CrashReports

View file

@ -11,7 +11,7 @@ namespace CrashReports {
QString PlatformString(); QString PlatformString();
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
struct dump { struct dump {
~dump(); ~dump();
@ -24,7 +24,7 @@ const dump &operator<<(const dump &stream, unsigned long num);
const dump &operator<<(const dump &stream, unsigned long long num); const dump &operator<<(const dump &stream, unsigned long long num);
const dump &operator<<(const dump &stream, double num); const dump &operator<<(const dump &stream, double num);
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS #endif // TDESKTOP_DISABLE_CRASH_REPORTS
enum Status { enum Status {
CantOpen, CantOpen,

View file

@ -0,0 +1,83 @@
/*
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
namespace Core::DeadlockDetector {
class PingPongEvent : public QEvent {
public:
static auto Type() {
static const auto Result = QEvent::Type(QEvent::registerEventType());
return Result;
}
PingPongEvent(not_null<QObject*> sender)
: QEvent(Type())
, _sender(sender) {
}
[[nodiscard]] not_null<QObject*> sender() const {
return _sender;
}
private:
not_null<QObject*> _sender;
};
class Pinger : public QObject {
public:
Pinger(not_null<QObject*> receiver)
: _receiver(receiver)
, _abortTimer([] { Unexpected("Deadlock found!"); }) {
const auto callback = [=] {
QCoreApplication::postEvent(_receiver, new PingPongEvent(this));
_abortTimer.callOnce(30000);
};
_pingTimer.setCallback(callback);
_pingTimer.callEach(60000);
callback();
}
protected:
bool event(QEvent *e) override {
if (e->type() == PingPongEvent::Type()
&& static_cast<PingPongEvent*>(e)->sender() == _receiver) {
_abortTimer.cancel();
}
return QObject::event(e);
}
private:
not_null<QObject*> _receiver;
base::Timer _pingTimer;
base::Timer _abortTimer;
};
class PingThread : public QThread {
public:
PingThread(not_null<QObject*> parent)
: QThread(parent) {
start();
}
~PingThread() {
quit();
wait();
}
protected:
void run() override {
Pinger pinger(parent());
QThread::run();
}
};
} // namespace Core::DeadlockDetector

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/options.h" #include "base/options.h"
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
#include <QtCore/QStandardPaths>
namespace Core { namespace Core {
namespace { namespace {
@ -115,16 +116,26 @@ void ComputeDebugMode() {
} }
void ComputeExternalUpdater() { void ComputeExternalUpdater() {
QFile file(u"/etc/tdesktop/externalupdater"_q); auto locations = QStandardPaths::standardLocations(
QStandardPaths::AppDataLocation);
if (file.exists() && file.open(QIODevice::ReadOnly)) { if (locations.isEmpty()) {
QTextStream fileStream(&file); locations << QString();
while (!fileStream.atEnd()) { }
const auto path = fileStream.readLine(); locations[0] = QDir::cleanPath(cWorkingDir());
locations << QDir::cleanPath(cExeDir());
if (path == (cExeDir() + cExeName())) { for (const auto &location : locations) {
SetUpdaterDisabledAtStartup(); const auto dir = location + u"/externalupdater.d"_q;
return; for (const auto &info : QDir(dir).entryInfoList(QDir::Files)) {
QFile file(info.absoluteFilePath());
if (file.open(QIODevice::ReadOnly)) {
QTextStream fileStream(&file);
while (!fileStream.atEnd()) {
const auto path = fileStream.readLine();
if (path == (cExeDir() + cExeName())) {
SetUpdaterDisabledAtStartup();
return;
}
}
} }
} }
} }
@ -223,7 +234,7 @@ bool CheckPortableVersionFolder() {
if (cAlphaVersion()) { if (cAlphaVersion()) {
Assert(*AlphaPrivateKey != 0); Assert(*AlphaPrivateKey != 0);
cForceWorkingDir(portable + '/'); cForceWorkingDir(portable);
QDir().mkpath(cWorkingDir() + u"tdata"_q); QDir().mkpath(cWorkingDir() + u"tdata"_q);
cSetAlphaPrivateKey(QByteArray(AlphaPrivateKey)); cSetAlphaPrivateKey(QByteArray(AlphaPrivateKey));
if (!key.open(QIODevice::WriteOnly)) { if (!key.open(QIODevice::WriteOnly)) {
@ -239,7 +250,7 @@ bool CheckPortableVersionFolder() {
if (!QDir(portable).exists()) { if (!QDir(portable).exists()) {
return true; return true;
} }
cForceWorkingDir(portable + '/'); cForceWorkingDir(portable);
if (!key.exists()) { if (!key.exists()) {
return true; return true;
} }
@ -291,7 +302,8 @@ Launcher::Launcher(int argc, char *argv[])
: _argc(argc) : _argc(argc)
, _argv(argv) , _argv(argv)
, _arguments(readArguments(_argc, _argv)) , _arguments(readArguments(_argc, _argv))
, _baseIntegration(_argc, _argv) { , _baseIntegration(_argc, _argv)
, _initialWorkingDir(QDir::currentPath() + '/') {
crl::toggle_fp_exceptions(true); crl::toggle_fp_exceptions(true);
base::Integration::Set(&_baseIntegration); base::Integration::Set(&_baseIntegration);
@ -446,6 +458,10 @@ const QStringList &Launcher::arguments() const {
return _arguments; return _arguments;
} }
QString Launcher::initialWorkingDir() const {
return _initialWorkingDir;
}
bool Launcher::customWorkingDir() const { bool Launcher::customWorkingDir() const {
return !_customWorkingDir.isEmpty(); return !_customWorkingDir.isEmpty();
} }

View file

@ -29,6 +29,7 @@ public:
virtual int exec(); virtual int exec();
const QStringList &arguments() const; const QStringList &arguments() const;
QString initialWorkingDir() const;
bool customWorkingDir() const; bool customWorkingDir() const;
uint64 installationTag() const; uint64 installationTag() const;
@ -84,6 +85,7 @@ private:
QStringList _arguments; QStringList _arguments;
BaseIntegration _baseIntegration; BaseIntegration _baseIntegration;
QString _initialWorkingDir;
QString _customWorkingDir; QString _customWorkingDir;
}; };

View file

@ -378,6 +378,8 @@ bool ResolveUsernameOrPhone(
startToken = params.value(u"startgroup"_q); startToken = params.value(u"startgroup"_q);
} else if (params.contains(u"startchannel"_q)) { } else if (params.contains(u"startchannel"_q)) {
resolveType = ResolveType::AddToChannel; resolveType = ResolveType::AddToChannel;
} else if (params.contains(u"boost"_q)) {
resolveType = ResolveType::Boost;
} }
auto post = ShowAtUnreadMsgId; auto post = ShowAtUnreadMsgId;
auto adminRights = ChatAdminRights(); auto adminRights = ChatAdminRights();
@ -392,7 +394,6 @@ bool ResolveUsernameOrPhone(
const auto storyParam = params.value(u"story"_q); const auto storyParam = params.value(u"story"_q);
const auto storyId = storyParam.toInt(); const auto storyId = storyParam.toInt();
const auto appname = webChannelPreviewLink ? QString() : appnameParam; const auto appname = webChannelPreviewLink ? QString() : appnameParam;
const auto appstart = params.value(u"startapp"_q);
const auto commentParam = params.value(u"comment"_q); const auto commentParam = params.value(u"comment"_q);
const auto commentId = commentParam.toInt(); const auto commentId = commentParam.toInt();
const auto topicParam = params.value(u"topic"_q); const auto topicParam = params.value(u"topic"_q);
@ -404,11 +405,11 @@ bool ResolveUsernameOrPhone(
startToken = gameParam; startToken = gameParam;
resolveType = ResolveType::ShareGame; resolveType = ResolveType::ShareGame;
} }
if (startToken.isEmpty() && params.contains(u"startapp"_q)) {
startToken = params.value(u"startapp"_q);
}
if (!appname.isEmpty()) { if (!appname.isEmpty()) {
resolveType = ResolveType::BotApp; resolveType = ResolveType::BotApp;
if (startToken.isEmpty() && params.contains(u"startapp"_q)) {
startToken = params.value(u"startapp"_q);
}
} }
const auto myContext = context.value<ClickHandlerContext>(); const auto myContext = context.value<ClickHandlerContext>();
using Navigation = Window::SessionNavigation; using Navigation = Window::SessionNavigation;
@ -436,7 +437,11 @@ bool ResolveUsernameOrPhone(
.attachBotUsername = params.value(u"attach"_q), .attachBotUsername = params.value(u"attach"_q),
.attachBotToggleCommand = (params.contains(u"startattach"_q) .attachBotToggleCommand = (params.contains(u"startattach"_q)
? params.value(u"startattach"_q) ? params.value(u"startattach"_q)
: (appname.isEmpty() && params.contains(u"startapp"_q))
? params.value(u"startapp"_q)
: std::optional<QString>()), : std::optional<QString>()),
.attachBotMenuOpen = (appname.isEmpty()
&& params.contains(u"startapp"_q)),
.attachBotChooseTypes = InlineBots::ParseChooseTypes( .attachBotChooseTypes = InlineBots::ParseChooseTypes(
params.value(u"choose"_q)), params.value(u"choose"_q)),
.voicechatHash = (params.contains(u"livestream"_q) .voicechatHash = (params.contains(u"livestream"_q)
@ -839,6 +844,32 @@ bool ResolveLoginCode(
return true; return true;
} }
bool ResolveBoost(
Window::SessionController *controller,
const Match &match,
const QVariant &context) {
if (!controller) {
return false;
}
const auto params = url_parse_params(
match->captured(1),
qthelp::UrlParamNameTransform::ToLower);
const auto domainParam = params.value(u"domain"_q);
const auto channelParam = params.value(u"channel"_q);
const auto myContext = context.value<ClickHandlerContext>();
using Navigation = Window::SessionNavigation;
controller->window().activate();
controller->showPeerByLink(Navigation::PeerByLinkInfo{
.usernameOrId = (!domainParam.isEmpty()
? std::variant<QString, ChannelId>(domainParam)
: ChannelId(BareId(channelParam.toULongLong()))),
.resolveType = Window::ResolveType::Boost,
.clickFromMessageId = myContext.itemId,
});
return true;
}
} // namespace } // namespace
const std::vector<LocalUrlHandler> &LocalUrlHandlers() { const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
@ -919,6 +950,10 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
u"^login/?(\\?code=([0-9]+))(&|$)"_q, u"^login/?(\\?code=([0-9]+))(&|$)"_q,
ResolveLoginCode ResolveLoginCode
}, },
{
u"^boost/?\\?(.+)(#|$)"_q,
ResolveBoost,
},
{ {
u"^([^\\?]+)(\\?|#|$)"_q, u"^([^\\?]+)(\\?|#|$)"_q,
HandleUnknown HandleUnknown
@ -1022,8 +1057,13 @@ QString TryConvertUrlToLocal(QString url) {
"/\\d+/?(\\?|$)|" "/\\d+/?(\\?|$)|"
"/\\d+/\\d+/?(\\?|$)" "/\\d+/\\d+/?(\\?|$)"
")"_q, query, matchOptions)) { ")"_q, query, matchOptions)) {
const auto channel = privateMatch->captured(1);
const auto params = query.mid(privateMatch->captured(0).size()).toString(); const auto params = query.mid(privateMatch->captured(0).size()).toString();
const auto base = u"tg://privatepost?channel="_q + privateMatch->captured(1); if (params.indexOf("boost", 0, Qt::CaseInsensitive) >= 0
&& params.toLower().split('&').contains(u"boost"_q)) {
return u"tg://boost?channel="_q + channel;
}
const auto base = u"tg://privatepost?channel="_q + channel;
auto added = QString(); auto added = QString();
if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, privateMatch->captured(2))) { if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, privateMatch->captured(2))) {
added = u"&topic=%1&post=%2"_q.arg(threadPostMatch->captured(1)).arg(threadPostMatch->captured(2)); added = u"&topic=%1&post=%2"_q.arg(threadPostMatch->captured(1)).arg(threadPostMatch->captured(2));
@ -1041,7 +1081,12 @@ QString TryConvertUrlToLocal(QString url) {
"/s/\\d+/?(\\?|$)|" "/s/\\d+/?(\\?|$)|"
"/\\d+/\\d+/?(\\?|$)" "/\\d+/\\d+/?(\\?|$)"
")"_q, query, matchOptions)) { ")"_q, query, matchOptions)) {
const auto domain = usernameMatch->captured(1);
const auto params = query.mid(usernameMatch->captured(0).size()).toString(); const auto params = query.mid(usernameMatch->captured(0).size()).toString();
if (params.indexOf("boost", 0, Qt::CaseInsensitive) >= 0
&& params.toLower().split('&').contains(u"boost"_q)) {
return u"tg://boost?domain="_q + domain;
}
const auto base = u"tg://resolve?domain="_q + url_encode(usernameMatch->captured(1)); const auto base = u"tg://resolve?domain="_q + url_encode(usernameMatch->captured(1));
auto added = QString(); auto added = QString();
if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) { if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) {

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/launcher.h" #include "core/launcher.h"
#include "core/local_url_handlers.h" #include "core/local_url_handlers.h"
#include "core/update_checker.h" #include "core/update_checker.h"
#include "core/deadlock_detector.h"
#include "base/timer.h" #include "base/timer.h"
#include "base/concurrent_timer.h" #include "base/concurrent_timer.h"
#include "base/invoke_queued.h" #include "base/invoke_queued.h"
@ -202,6 +203,13 @@ void Sandbox::launchApplication() {
} }
setupScreenScale(); setupScreenScale();
#ifndef _DEBUG
if (Logs::DebugEnabled()) {
using DeadlockDetector::PingThread;
_deadlockDetector = std::make_unique<PingThread>(this);
}
#endif // !_DEBUG
_application = std::make_unique<Application>(); _application = std::make_unique<Application>();
// Ideally this should go to constructor. // Ideally this should go to constructor.
@ -271,6 +279,10 @@ bool Sandbox::event(QEvent *e) {
return false; return false;
} else if (e->type() == QEvent::Close) { } else if (e->type() == QEvent::Close) {
Quit(); Quit();
} else if (e->type() == DeadlockDetector::PingPongEvent::Type()) {
postEvent(
static_cast<DeadlockDetector::PingPongEvent*>(e)->sender(),
new DeadlockDetector::PingPongEvent(this));
} }
return QApplication::event(e); return QApplication::event(e);
} }

View file

@ -131,6 +131,8 @@ private:
rpl::event_stream<> _widgetUpdateRequests; rpl::event_stream<> _widgetUpdateRequests;
std::unique_ptr<QThread> _deadlockDetector;
}; };
} // namespace Core } // namespace Core

View file

@ -370,7 +370,6 @@ QString UiIntegration::phrasePanelCloseAnyway() {
return tr::lng_bot_close_warning_sure(tr::now); return tr::lng_bot_close_warning_sure(tr::now);
} }
#if 0 // disabled for now
QString UiIntegration::phraseBotSharePhone() { QString UiIntegration::phraseBotSharePhone() {
return tr::lng_bot_share_phone(tr::now); return tr::lng_bot_share_phone(tr::now);
} }
@ -382,7 +381,18 @@ QString UiIntegration::phraseBotSharePhoneTitle() {
QString UiIntegration::phraseBotSharePhoneConfirm() { QString UiIntegration::phraseBotSharePhoneConfirm() {
return tr::lng_bot_share_phone_confirm(tr::now); return tr::lng_bot_share_phone_confirm(tr::now);
} }
#endif
QString UiIntegration::phraseBotAllowWrite() {
return tr::lng_bot_allow_write(tr::now);
}
QString UiIntegration::phraseBotAllowWriteTitle() {
return tr::lng_bot_allow_write_title(tr::now);
}
QString UiIntegration::phraseBotAllowWriteConfirm() {
return tr::lng_bot_allow_write_confirm(tr::now);
}
bool OpenGLLastCheckFailed() { bool OpenGLLastCheckFailed() {
return QFile::exists(OpenGLCheckFilePath()); return QFile::exists(OpenGLCheckFilePath());

View file

@ -84,11 +84,12 @@ public:
QString phrasePanelCloseWarning() override; QString phrasePanelCloseWarning() override;
QString phrasePanelCloseUnsaved() override; QString phrasePanelCloseUnsaved() override;
QString phrasePanelCloseAnyway() override; QString phrasePanelCloseAnyway() override;
#if 0 // disabled for now
QString phraseBotSharePhone() override; QString phraseBotSharePhone() override;
QString phraseBotSharePhoneTitle() override; QString phraseBotSharePhoneTitle() override;
QString phraseBotSharePhoneConfirm() override; QString phraseBotSharePhoneConfirm() override;
#endif QString phraseBotAllowWrite() override;
QString phraseBotAllowWriteTitle() override;
QString phraseBotAllowWriteConfirm() override;
}; };

View file

@ -42,16 +42,16 @@ extern "C" {
} // extern "C" } // extern "C"
#ifndef TDESKTOP_DISABLE_AUTOUPDATE #ifndef TDESKTOP_DISABLE_AUTOUPDATE
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win #if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
#include <LzmaLib.h> #include <LzmaLib.h>
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED #else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
#include <lzma.h> #include <lzma.h>
#endif // else of Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED #endif // else of Q_OS_WIN && !TDESKTOP_USE_PACKAGED
#endif // !TDESKTOP_DISABLE_AUTOUPDATE #endif // !TDESKTOP_DISABLE_AUTOUPDATE
#ifdef Q_OS_UNIX #ifndef Q_OS_WIN
#include <unistd.h> #include <unistd.h>
#endif // Q_OS_UNIX #endif // !Q_OS_WIN
namespace Core { namespace Core {
namespace { namespace {
@ -275,11 +275,11 @@ bool UnpackUpdate(const QString &filepath) {
return false; return false;
} }
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win #if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED #else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header
#endif // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED #endif // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
QByteArray compressed = input.readAll(); QByteArray compressed = input.readAll();
int32 compressedLen = compressed.size() - hSize; int32 compressedLen = compressed.size() - hSize;
@ -330,14 +330,14 @@ bool UnpackUpdate(const QString &filepath) {
uncompressed.resize(uncompressedLen); uncompressed.resize(uncompressedLen);
size_t resultLen = uncompressed.size(); size_t resultLen = uncompressed.size();
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win #if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
SizeT srcLen = compressedLen; SizeT srcLen = compressedLen;
int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
if (uncompressRes != SZ_OK) { if (uncompressRes != SZ_OK) {
LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes)); LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
return false; return false;
} }
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED #else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
lzma_stream stream = LZMA_STREAM_INIT; lzma_stream stream = LZMA_STREAM_INIT;
lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED);
@ -380,7 +380,7 @@ bool UnpackUpdate(const QString &filepath) {
LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res)); LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res));
return false; return false;
} }
#endif // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED #endif // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
tempDir.mkdir(tempDir.absolutePath()); tempDir.mkdir(tempDir.absolutePath());
@ -428,9 +428,9 @@ bool UnpackUpdate(const QString &filepath) {
bool executable = false; bool executable = false;
stream >> relativeName >> fileSize >> fileInnerData; stream >> relativeName >> fileSize >> fileInnerData;
#ifdef Q_OS_UNIX #ifndef Q_OS_WIN
stream >> executable; stream >> executable;
#endif // Q_OS_UNIX #endif // !Q_OS_WIN
if (stream.status() != QDataStream::Ok) { if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status())); LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status()));
return false; return false;
@ -1539,10 +1539,10 @@ bool checkReadyUpdate() {
#elif defined Q_OS_MAC // Q_OS_WIN #elif defined Q_OS_MAC // Q_OS_WIN
QString curUpdater = (cExeDir() + cExeName() + u"/Contents/Frameworks/Updater"_q); QString curUpdater = (cExeDir() + cExeName() + u"/Contents/Frameworks/Updater"_q);
QFileInfo updater(cWorkingDir() + u"tupdates/temp/Telegram.app/Contents/Frameworks/Updater"_q); QFileInfo updater(cWorkingDir() + u"tupdates/temp/Telegram.app/Contents/Frameworks/Updater"_q);
#elif defined Q_OS_UNIX // Q_OS_MAC #else // Q_OS_MAC
QString curUpdater = (cExeDir() + u"Updater"_q); QString curUpdater = (cExeDir() + u"Updater"_q);
QFileInfo updater(cWorkingDir() + u"tupdates/temp/Updater"_q); QFileInfo updater(cWorkingDir() + u"tupdates/temp/Updater"_q);
#endif // Q_OS_UNIX #endif // else for Q_OS_WIN || Q_OS_MAC
if (!updater.exists()) { if (!updater.exists()) {
QFileInfo current(curUpdater); QFileInfo current(curUpdater);
if (!current.exists()) { if (!current.exists()) {
@ -1576,7 +1576,7 @@ bool checkReadyUpdate() {
ClearAll(); ClearAll();
return false; return false;
} }
#elif defined Q_OS_UNIX // Q_OS_MAC #else // Q_OS_MAC
// if the files in the directory are owned by user, while the directory is not, // if the files in the directory are owned by user, while the directory is not,
// update will still fail since it's not possible to remove files // update will still fail since it's not possible to remove files
if (QFile::exists(curUpdater) if (QFile::exists(curUpdater)
@ -1604,7 +1604,7 @@ bool checkReadyUpdate() {
return false; return false;
} }
} }
#endif // Q_OS_UNIX #endif // else for Q_OS_WIN || Q_OS_MAC
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
base::Platform::RemoveQuarantine(QFileInfo(curUpdater).absolutePath()); base::Platform::RemoveQuarantine(QFileInfo(curUpdater).absolutePath());

View file

@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
constexpr auto AppNameOld = "AyuGram for Windows"_cs; constexpr auto AppNameOld = "AyuGram for Windows"_cs;
constexpr auto AppName = "AyuGram Desktop"_cs; constexpr auto AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs; constexpr auto AppFile = "AyuGram"_cs;
constexpr auto AppVersion = 4009004; constexpr auto AppVersion = 4010000;
constexpr auto AppVersionStr = "4.9.4"; constexpr auto AppVersionStr = "4.10";
constexpr auto AppBetaVersion = false; constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View file

@ -24,4 +24,5 @@ struct BotAppData {
uint64 accessHash = 0; uint64 accessHash = 0;
uint64 hash = 0; uint64 hash = 0;
bool hasSettings = false;
}; };

View file

@ -221,14 +221,14 @@ struct StoryUpdate {
enum class Flag : uint32 { enum class Flag : uint32 {
None = 0, None = 0,
Edited = (1U << 0), Edited = (1U << 0),
Destroyed = (1U << 1), Destroyed = (1U << 1),
NewAdded = (1U << 2), NewAdded = (1U << 2),
ViewsAdded = (1U << 3), ViewsChanged = (1U << 3),
MarkRead = (1U << 4), MarkRead = (1U << 4),
Reaction = (1U << 5), Reaction = (1U << 5),
LastUsedBit = (1U << 5), LastUsedBit = (1U << 5),
}; };
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; } friend inline constexpr auto is_flag_type(Flag) { return true; }

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_chat.h" #include "data/data_chat.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_stories.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_forum.h" #include "data/data_forum.h"
#include "data/data_forum_icons.h" #include "data/data_forum_icons.h"
@ -530,6 +531,11 @@ bool ChannelData::canBanMembers() const {
|| (adminRights() & AdminRight::BanUsers); || (adminRights() & AdminRight::BanUsers);
} }
bool ChannelData::canPostMessages() const {
return amCreator()
|| (adminRights() & AdminRight::PostMessages);
}
bool ChannelData::canEditMessages() const { bool ChannelData::canEditMessages() const {
return amCreator() return amCreator()
|| (adminRights() & AdminRight::EditMessages); || (adminRights() & AdminRight::EditMessages);
@ -540,6 +546,30 @@ bool ChannelData::canDeleteMessages() const {
|| (adminRights() & AdminRight::DeleteMessages); || (adminRights() & AdminRight::DeleteMessages);
} }
bool ChannelData::canPostStories() const {
if (!isBroadcast()) {
return false;
}
return amCreator()
|| (adminRights() & AdminRight::PostStories);
}
bool ChannelData::canEditStories() const {
if (!isBroadcast()) {
return false;
}
return amCreator()
|| (adminRights() & AdminRight::EditStories);
}
bool ChannelData::canDeleteStories() const {
if (!isBroadcast()) {
return false;
}
return amCreator()
|| (adminRights() & AdminRight::DeleteStories);
}
bool ChannelData::anyoneCanAddMembers() const { bool ChannelData::anyoneCanAddMembers() const {
return !(defaultRestrictions() & Restriction::AddParticipants); return !(defaultRestrictions() & Restriction::AddParticipants);
} }
@ -559,11 +589,6 @@ bool ChannelData::canAddAdmins() const {
|| (adminRights() & AdminRight::AddAdmins); || (adminRights() & AdminRight::AddAdmins);
} }
bool ChannelData::canPublish() const {
return amCreator()
|| (adminRights() & AdminRight::PostMessages);
}
bool ChannelData::allowsForwarding() const { bool ChannelData::allowsForwarding() const {
return !(flags() & Flag::NoForwards); return !(flags() & Flag::NoForwards);
} }
@ -877,6 +902,38 @@ const Data::AllowedReactions &ChannelData::allowedReactions() const {
return _allowedReactions; return _allowedReactions;
} }
bool ChannelData::hasActiveStories() const {
return flags() & Flag::HasActiveStories;
}
bool ChannelData::hasUnreadStories() const {
return flags() & Flag::HasUnreadStories;
}
void ChannelData::setStoriesState(StoriesState state) {
Expects(state != StoriesState::Unknown);
const auto was = flags();
switch (state) {
case StoriesState::None:
_flags.remove(Flag::HasActiveStories | Flag::HasUnreadStories);
break;
case StoriesState::HasRead:
_flags.set(
(flags() & ~Flag::HasUnreadStories) | Flag::HasActiveStories);
break;
case StoriesState::HasUnread:
_flags.add(Flag::HasActiveStories | Flag::HasUnreadStories);
break;
}
if (flags() != was) {
if (const auto history = owner().historyLoaded(this)) {
history->updateChatListEntryPostponed();
}
session().changes().peerUpdated(this, UpdateFlag::StoriesState);
}
}
void ChannelData::processTopics(const MTPVector<MTPForumTopic> &topics) { void ChannelData::processTopics(const MTPVector<MTPForumTopic> &topics) {
if (const auto forum = this->forum()) { if (const auto forum = this->forum()) {
forum->applyReceivedTopics(topics); forum->applyReceivedTopics(topics);
@ -1046,6 +1103,7 @@ void ApplyChannelUpdate(
} else { } else {
channel->setAllowedReactions({}); channel->setAllowedReactions({});
} }
channel->owner().stories().apply(channel, update.vstories());
channel->fullUpdated(); channel->fullUpdated();
channel->setPendingRequestsCount( channel->setPendingRequestsCount(
update.vrequests_pending().value_or_empty(), update.vrequests_pending().value_or_empty(),

View file

@ -59,6 +59,9 @@ enum class ChannelDataFlag {
Forum = (1 << 23), Forum = (1 << 23),
AntiSpam = (1 << 24), AntiSpam = (1 << 24),
ParticipantsHidden = (1 << 25), ParticipantsHidden = (1 << 25),
StoriesHidden = (1 << 26),
HasActiveStories = (1 << 27),
HasUnreadStories = (1 << 28),
}; };
inline constexpr bool is_flag_type(ChannelDataFlag) { return true; }; inline constexpr bool is_flag_type(ChannelDataFlag) { return true; };
using ChannelDataFlags = base::flags<ChannelDataFlag>; using ChannelDataFlags = base::flags<ChannelDataFlag>;
@ -226,6 +229,9 @@ public:
[[nodiscard]] bool isFake() const { [[nodiscard]] bool isFake() const {
return flags() & Flag::Fake; return flags() & Flag::Fake;
} }
[[nodiscard]] bool hasStoriesHidden() const {
return flags() & Flag::StoriesHidden;
}
[[nodiscard]] static ChatRestrictionsInfo KickedRestrictedRights( [[nodiscard]] static ChatRestrictionsInfo KickedRestrictedRights(
not_null<PeerData*> participant); not_null<PeerData*> participant);
@ -329,10 +335,13 @@ public:
[[nodiscard]] bool canBanMembers() const; [[nodiscard]] bool canBanMembers() const;
[[nodiscard]] bool anyoneCanAddMembers() const; [[nodiscard]] bool anyoneCanAddMembers() const;
[[nodiscard]] bool canPostMessages() const;
[[nodiscard]] bool canEditMessages() const; [[nodiscard]] bool canEditMessages() const;
[[nodiscard]] bool canDeleteMessages() const; [[nodiscard]] bool canDeleteMessages() const;
[[nodiscard]] bool canPostStories() const;
[[nodiscard]] bool canEditStories() const;
[[nodiscard]] bool canDeleteStories() const;
[[nodiscard]] bool hiddenPreHistory() const; [[nodiscard]] bool hiddenPreHistory() const;
[[nodiscard]] bool canPublish() const;
[[nodiscard]] bool canViewMembers() const; [[nodiscard]] bool canViewMembers() const;
[[nodiscard]] bool canViewAdmins() const; [[nodiscard]] bool canViewAdmins() const;
[[nodiscard]] bool canViewBanned() const; [[nodiscard]] bool canViewBanned() const;
@ -437,6 +446,10 @@ public:
void setAllowedReactions(Data::AllowedReactions value); void setAllowedReactions(Data::AllowedReactions value);
[[nodiscard]] const Data::AllowedReactions &allowedReactions() const; [[nodiscard]] const Data::AllowedReactions &allowedReactions() const;
[[nodiscard]] bool hasActiveStories() const;
[[nodiscard]] bool hasUnreadStories() const;
void setStoriesState(StoriesState state);
[[nodiscard]] Data::Forum *forum() const { [[nodiscard]] Data::Forum *forum() const {
return mgInfo ? mgInfo->forum() : nullptr; return mgInfo ? mgInfo->forum() : nullptr;
} }

View file

@ -146,7 +146,7 @@ bool CanSendAnyOf(
&& !(channel->flags() & Flag::JoinToWrite)); && !(channel->flags() & Flag::JoinToWrite));
if (!allowed || (forbidInForums && channel->isForum())) { if (!allowed || (forbidInForums && channel->isForum())) {
return false; return false;
} else if (channel->canPublish()) { } else if (channel->canPostMessages()) {
return true; return true;
} else if (channel->isBroadcast()) { } else if (channel->isBroadcast()) {
return false; return false;

View file

@ -25,6 +25,9 @@ enum class ChatAdminRight {
ManageCall = (1 << 11), ManageCall = (1 << 11),
Other = (1 << 12), Other = (1 << 12),
ManageTopics = (1 << 13), ManageTopics = (1 << 13),
PostStories = (1 << 14),
EditStories = (1 << 15),
DeleteStories = (1 << 16),
}; };
inline constexpr bool is_flag_type(ChatAdminRight) { return true; } inline constexpr bool is_flag_type(ChatAdminRight) { return true; }
using ChatAdminRights = base::flags<ChatAdminRight>; using ChatAdminRights = base::flags<ChatAdminRight>;

View file

@ -159,14 +159,7 @@ wv xm xml ym yuv").split(' ');
bool IsExecutableName(const QString &filepath) { bool IsExecutableName(const QString &filepath) {
static const auto kExtensions = [] { static const auto kExtensions = [] {
const auto joined = const auto joined =
#ifdef Q_OS_MAC #ifdef Q_OS_WIN
u"\
applescript action app bin command csh osx workflow terminal url caction \
mpkg pkg scpt scptd xhtm webarchive"_q;
#elif defined Q_OS_UNIX // Q_OS_MAC
u"bin csh deb desktop ksh out pet pkg pup rpm run sh shar \
slp zsh"_q;
#else // Q_OS_MAC || Q_OS_UNIX
u"\ u"\
ad ade adp app application appref-ms asp asx bas bat bin cab cdxml cer cfg \ ad ade adp app application appref-ms asp asx bas bat bin cab cdxml cer cfg \
chi chm cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget \ chi chm cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget \
@ -179,7 +172,14 @@ psd1 psm1 pssc pst py py3 pyc pyd pyi pyo pyw pywz pyz rb reg rgs scf scr \
sct search-ms settingcontent-ms sh shb shs slk sys t tmp u3p url vb vbe vbp \ sct search-ms settingcontent-ms sh shb shs slk sys t tmp u3p url vb vbe vbp \
vbs vbscript vdx vsmacros vsd vsdm vsdx vss vssm vssx vst vstm vstx vsw vsx \ vbs vbscript vdx vsmacros vsd vsdm vsdx vss vssm vssx vst vstm vstx vsw vsx \
vtx website ws wsc wsf wsh xbap xll xnk xs"_q; vtx website ws wsc wsf wsh xbap xll xnk xs"_q;
#endif // !Q_OS_MAC && !Q_OS_UNIX #elif defined Q_OS_MAC // Q_OS_MAC
u"\
applescript action app bin command csh osx workflow terminal url caction \
mpkg pkg scpt scptd xhtm webarchive"_q;
#else // Q_OS_WIN || Q_OS_MAC
u"bin csh deb desktop ksh out pet pkg pup rpm run sh shar \
slp zsh"_q;
#endif // !Q_OS_WIN && !Q_OS_MAC
const auto list = joined.split(' '); const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end()); return base::flat_set<QString>(list.begin(), list.end());
}(); }();

View file

@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_drafts.h" #include "data/data_drafts.h"
#include "api/api_text_entities.h" #include "api/api_text_entities.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "chat_helpers/message_field.h" #include "chat_helpers/message_field.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_widget.h" #include "history/history_widget.h"

View file

@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "core/application.h" #include "core/application.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/fields/input_field.h"
#include "storage/storage_facade.h" #include "storage/storage_facade.h"
#include "storage/storage_shared_media.h" #include "storage/storage_shared_media.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"

View file

@ -73,7 +73,7 @@ struct FullReplyTo {
FullStoryId storyId; FullStoryId storyId;
[[nodiscard]] bool valid() const { [[nodiscard]] bool valid() const {
return msgId || storyId; return msgId || (storyId && peerIsUser(storyId.peer));
} }
explicit operator bool() const { explicit operator bool() const {
return valid(); return valid();

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