Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0f54822e0 | ||
|
|
df4c9a0765 | ||
|
|
47e15d136d | ||
|
|
5aff4cca0e | ||
|
|
a064e836f2 | ||
|
|
81ed3acfa1 | ||
|
|
cc2dd31555 | ||
|
|
0ee6395022 | ||
|
|
1d2a18929a | ||
|
|
a0a3de125a | ||
|
|
1cf207671e | ||
|
|
c208b5dc58 | ||
|
|
6eb5d47c35 | ||
|
|
59977da2b4 | ||
|
|
4550b2a315 | ||
|
|
bcbab7ad8e | ||
|
|
b635a9d4a5 | ||
|
|
eadd7704ef | ||
|
|
e6f0c176f7 | ||
|
|
22d4331ead | ||
|
|
1247fde04e | ||
|
|
88a2f05c6d | ||
|
|
df15c67dab | ||
|
|
f59db10267 | ||
|
|
d29a1f5cd2 | ||
|
|
cd8d257c70 | ||
|
|
9dfc60026e | ||
|
|
e9a5c45f34 | ||
|
|
2c07bdd0e8 | ||
|
|
b106438de8 | ||
|
|
92b7afc5f5 |
@@ -354,6 +354,8 @@ PRIVATE
|
||||
data/data_abstract_sparse_ids.h
|
||||
data/data_abstract_structure.cpp
|
||||
data/data_abstract_structure.h
|
||||
data/data_audio_msg_id.cpp
|
||||
data/data_audio_msg_id.h
|
||||
data/data_auto_download.cpp
|
||||
data/data_auto_download.h
|
||||
data/data_chat.cpp
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 103 KiB |
BIN
Telegram/Resources/art/background.tgv
Normal file
BIN
Telegram/Resources/art/background.tgv
Normal file
Binary file not shown.
BIN
Telegram/Resources/art/bg_thumbnail.png
Normal file
BIN
Telegram/Resources/art/bg_thumbnail.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
@@ -1141,10 +1141,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_invite_users_and_one" = "{accumulated}, {user}";
|
||||
"lng_action_invite_users_and_last" = "{accumulated} and {user}";
|
||||
"lng_action_group_call_started_group" = "{from} started a voice chat";
|
||||
"lng_action_group_call_started_channel" = "Voice chat started";
|
||||
"lng_action_group_call_started_channel" = "Live stream started";
|
||||
"lng_action_group_call_scheduled_group" = "{from} scheduled a voice chat for {date}";
|
||||
"lng_action_group_call_scheduled_channel" = "Voice chat scheduled for {date}";
|
||||
"lng_action_group_call_finished" = "Voice chat finished ({duration})";
|
||||
"lng_action_group_call_scheduled_channel" = "Live stream scheduled for {date}";
|
||||
"lng_action_group_call_finished" = "Live stream finished ({duration})";
|
||||
"lng_action_group_call_finished_group" = "{from} ended the voice chat ({duration})";
|
||||
"lng_action_add_user" = "{from} added {user}";
|
||||
"lng_action_add_users_many" = "{from} added {users}";
|
||||
@@ -2004,6 +2004,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_call_bar_hangup" = "End call";
|
||||
"lng_call_leave_to_other_sure" = "Do you want to end your active call and join a voice chat in this group?";
|
||||
"lng_call_leave_to_other_sure_channel" = "Do you want to end your active call and join a live stream in this channel?";
|
||||
|
||||
"lng_call_box_title" = "Calls";
|
||||
"lng_call_box_about" = "You haven't made any Telegram calls yet.";
|
||||
@@ -2045,6 +2046,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_call_microphone_off" = "{user}'s microphone is off";
|
||||
|
||||
"lng_group_call_title" = "Voice Chat";
|
||||
"lng_group_call_title_channel" = "Live Stream";
|
||||
"lng_group_call_active" = "speaking";
|
||||
"lng_group_call_inactive" = "listening";
|
||||
"lng_group_call_raised_hand_status" = "wants to speak";
|
||||
@@ -2068,13 +2070,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_connecting" = "Connecting...";
|
||||
"lng_group_call_leave" = "Leave";
|
||||
"lng_group_call_leave_title" = "Leave voice chat";
|
||||
"lng_group_call_leave_title_channel" = "Leave live stream";
|
||||
"lng_group_call_leave_sure" = "Are you sure you want to leave this voice chat?";
|
||||
"lng_group_call_leave_sure_channel" = "Are you sure you want to leave this live stream?";
|
||||
"lng_group_call_close" = "Close";
|
||||
"lng_group_call_close_sure" = "Voice chat is scheduled. You can abort it or just close this panel.";
|
||||
"lng_group_call_close_sure_channel" = "Live stream is scheduled. You can abort it or just close this panel.";
|
||||
"lng_group_call_also_cancel" = "Abort voice chat";
|
||||
"lng_group_call_also_cancel_channel" = "Abort live stream";
|
||||
"lng_group_call_leave_to_other_sure" = "Do you want to leave your active voice chat and join a voice chat in this group?";
|
||||
"lng_group_call_leave_to_other_sure_channel" = "Do you want to leave your active voice chat and join a live stream in this channel?";
|
||||
"lng_group_call_leave_channel_to_other_sure" = "Do you want to leave your active live stream and join a voice chat in this group?";
|
||||
"lng_group_call_leave_channel_to_other_sure_channel" = "Do you want to leave your active live stream and join a live stream in this channel?";
|
||||
"lng_group_call_create_sure" = "Do you really want to start a voice chat in this group?";
|
||||
"lng_group_call_create_sure_channel" = "Are you sure you want to start a voice chat in this channel as your personal account?";
|
||||
"lng_group_call_create_sure_channel" = "Are you sure you want to start a live stream in this channel as your personal account?";
|
||||
"lng_group_call_join_sure_personal" = "Are you sure you want to join this voice chat as your personal account?";
|
||||
"lng_group_call_muted_no_camera" = "You can't turn on video while you're muted by admin.";
|
||||
"lng_group_call_muted_no_screen" = "You can't share your screen while you're muted by admin.";
|
||||
@@ -2089,6 +2098,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_tooltip_force_muted" = "Muted by admin. Click if you want to speak.";
|
||||
"lng_group_call_tooltip_raised_hand" = "You asked to speak. We let the speakers know.";
|
||||
"lng_group_call_also_end" = "End voice chat";
|
||||
"lng_group_call_also_end_channel" = "End live stream";
|
||||
"lng_group_call_settings_title" = "Settings";
|
||||
"lng_group_call_invite" = "Invite Member";
|
||||
"lng_group_call_invited_status" = "invited";
|
||||
@@ -2111,24 +2121,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_ptt_delay" = "Push to Talk release delay: {delay}";
|
||||
"lng_group_call_share" = "Share Invite Link";
|
||||
"lng_group_call_noise_suppression" = "Enable Noise Suppression";
|
||||
"lng_group_call_over_limit#one" = "The voice chat is over {count} member.\nNew participants only have access to audio stream.";
|
||||
"lng_group_call_over_limit#other" = "The voice chat is over {count} members.\nNew participants only have access to audio stream.";
|
||||
"lng_group_call_video_paused" = "Video is paused";
|
||||
"lng_group_call_share_speaker" = "Users with this link can speak";
|
||||
"lng_group_call_copy_speaker_link" = "Copy Speaker Link";
|
||||
"lng_group_call_copy_listener_link" = "Copy Listener Link";
|
||||
"lng_group_call_end" = "End Voice Chat";
|
||||
"lng_group_call_end_channel" = "End Live Stream";
|
||||
"lng_group_call_cancel" = "Abort Voice Chat";
|
||||
"lng_group_call_cancel_channel" = "Abort Live Stream";
|
||||
"lng_group_call_join" = "Join";
|
||||
"lng_group_call_join_confirm" = "Do you want to join the voice chat {chat}?";
|
||||
"lng_group_call_join_confirm_channel" = "Do you want to join the live stream {chat}?";
|
||||
"lng_group_call_invite_done_user" = "You invited {user} to the voice chat.";
|
||||
"lng_group_call_invite_done_many#one" = "You invited **{count} member** to the voice chat.";
|
||||
"lng_group_call_invite_done_many#other" = "You invited **{count} members** to the voice chat.";
|
||||
"lng_group_call_no_members" = "click to join";
|
||||
"lng_group_call_members#one" = "{count} participant";
|
||||
"lng_group_call_members#other" = "{count} participants";
|
||||
"lng_group_call_no_anonymous" = "Sorry, anonymous group admins can't join voice chats.";
|
||||
"lng_group_call_too_many" = "Sorry, there are too many members in this voice chat. Please try again later.";
|
||||
"lng_group_call_context_mute" = "Mute";
|
||||
"lng_group_call_context_unmute" = "Allow to speak";
|
||||
"lng_group_call_context_remove_hand" = "Cancel request to speak";
|
||||
@@ -2140,6 +2149,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_context_unpin_screen" = "Unpin screencast";
|
||||
"lng_group_call_context_remove" = "Remove";
|
||||
"lng_group_call_remove_channel" = "Remove {channel} from the voice chat?";
|
||||
"lng_group_call_remove_channel_from_channel" = "Remove {channel} from the live stream?";
|
||||
"lng_group_call_duration_days#one" = "{count} day";
|
||||
"lng_group_call_duration_days#other" = "{count} days";
|
||||
"lng_group_call_duration_hours#one" = "{count} hour";
|
||||
@@ -2156,18 +2166,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_mac_settings" = "Open Settings";
|
||||
|
||||
"lng_group_call_start_as_header" = "Start Voice Chat as...";
|
||||
"lng_group_call_start_as_header_channel" = "Start Live Stream as...";
|
||||
"lng_group_call_join_as_header" = "Join Voice Chat as...";
|
||||
"lng_group_call_join_as_header_channel" = "Join Live Stream as...";
|
||||
"lng_group_call_display_as_header" = "Display me as...";
|
||||
"lng_group_call_join_as_about" = "Choose whether you want to be displayed as your personal account or as your channel.";
|
||||
"lng_group_call_or_schedule" = "You can also {link}.";
|
||||
"lng_group_call_schedule" = "schedule a voice chat";
|
||||
"lng_group_call_schedule_channel" = "schedule a live stream";
|
||||
"lng_group_call_schedule_title" = "Schedule Voice Chat";
|
||||
"lng_group_call_schedule_title_channel" = "Schedule Live Stream";
|
||||
"lng_group_call_schedule_notified_group" = "The members of the group will be notified that the voice chat will start in {duration}.";
|
||||
"lng_group_call_schedule_notified_channel" = "The subscribers of the channel will be notified that the voice chat will start in {duration}.";
|
||||
"lng_group_call_schedule_notified_channel" = "The subscribers of the channel will be notified that the live stream will start in {duration}.";
|
||||
"lng_group_call_scheduled_status" = "Scheduled";
|
||||
"lng_group_call_scheduled_title" = "Scheduled Voice Chat";
|
||||
"lng_group_call_scheduled_title_channel" = "Scheduled Live Stream";
|
||||
"lng_group_call_starts_short" = "Starts {when}";
|
||||
"lng_group_call_starts" = "Voice Chat starts {when}";
|
||||
"lng_group_call_starts_channel" = "Live Stream starts {when}";
|
||||
"lng_group_call_starts_today" = "today at {time}";
|
||||
"lng_group_call_starts_tomorrow" = "tomorrow at {time}";
|
||||
"lng_group_call_starts_date" = "{date} at {time}";
|
||||
@@ -2178,16 +2194,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_starts_short_date" = "{date}, {time}";
|
||||
"lng_group_call_start_now" = "Start Now";
|
||||
"lng_group_call_start_now_sure" = "Are you sure you want to start the voice chat now?";
|
||||
"lng_group_call_start_now_sure_channel" = "Are you sure you want to start the live stream now?";
|
||||
"lng_group_call_set_reminder" = "Set Reminder";
|
||||
"lng_group_call_cancel_reminder" = "Cancel Reminder";
|
||||
"lng_group_call_join_as_personal" = "personal account";
|
||||
"lng_group_call_edit_title" = "Edit voice chat title";
|
||||
"lng_group_call_switch_done" = "Members of this voice chat will now see you as **{user}**";
|
||||
"lng_group_call_edit_title_header" = "Voice chat title";
|
||||
"lng_group_call_edit_title_channel" = "Edit live stream title";
|
||||
"lng_group_call_recording_start" = "Start recording";
|
||||
"lng_group_call_recording_stop" = "Stop recording";
|
||||
"lng_group_call_recording_started" = "Voice chat recording started.";
|
||||
"lng_group_call_recording_started_channel" = "Live stream recording started.";
|
||||
"lng_group_call_recording_stopped" = "Voice chat recording stopped.";
|
||||
"lng_group_call_recording_stopped_channel" = "Live stream recording stopped.";
|
||||
"lng_group_call_recording_saved" = "Audio saved to Saved Messages.";
|
||||
"lng_group_call_pinned_camera_me" = "Your video is pinned.";
|
||||
"lng_group_call_pinned_screen_me" = "Your screencast is pinned.";
|
||||
@@ -2203,18 +2221,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_recording_start_field" = "Recording Title";
|
||||
"lng_group_call_recording_start_button" = "Start";
|
||||
"lng_group_call_is_recorded" = "Voice chat is being recorded.";
|
||||
"lng_group_call_is_recorded_channel" = "Live stream is being recorded.";
|
||||
"lng_group_call_can_speak_here" = "You can now speak.";
|
||||
"lng_group_call_can_speak" = "You can now speak in {chat}.";
|
||||
"lng_group_call_title_changed" = "Voice chat title changed to {title}";
|
||||
"lng_group_call_title_changed_channel" = "Live stream title changed to {title}";
|
||||
"lng_group_call_join_as_changed" = "Members of this voice chat will now see you as {name}";
|
||||
"lng_group_call_join_as_changed_channel" = "Members of this live stream will now see you as {name}";
|
||||
|
||||
"lng_no_mic_permission" = "Telegram needs access to your microphone so that you can make calls and record voice messages.";
|
||||
|
||||
"lng_player_message_today" = "Today at {time}";
|
||||
"lng_player_message_yesterday" = "Yesterday at {time}";
|
||||
"lng_player_message_date" = "{date} at {time}";
|
||||
//"lng_player_cant_stream" = "This file can't be played before it is fully downloaded.\n\nWould you like to download it?";
|
||||
//"lng_player_download" = "Download";
|
||||
|
||||
"lng_rights_edit_admin" = "Manage permissions";
|
||||
"lng_rights_edit_admin_header" = "What can this admin do?";
|
||||
@@ -2270,6 +2289,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_channel_post" = "Post messages";
|
||||
"lng_rights_channel_edit" = "Edit messages of others";
|
||||
"lng_rights_channel_delete" = "Delete messages of others";
|
||||
"lng_rights_channel_manage_calls" = "Manage live streams";
|
||||
"lng_rights_group_info" = "Change group info";
|
||||
"lng_rights_group_ban" = "Ban users";
|
||||
"lng_rights_group_invite_link" = "Invite users via link";
|
||||
@@ -2359,6 +2379,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_filter_messages_edited" = "Edited messages";
|
||||
"lng_admin_log_filter_messages_pinned" = "Pinned messages";
|
||||
"lng_admin_log_filter_voice_chats" = "Voice chat";
|
||||
"lng_admin_log_filter_voice_chats_channel" = "Live stream";
|
||||
"lng_admin_log_filter_invite_links" = "Invite links";
|
||||
"lng_admin_log_filter_members_removed" = "Leaving members";
|
||||
"lng_admin_log_filter_all_admins" = "All users and admins";
|
||||
@@ -2431,12 +2452,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_changed_slow_mode" = "{from} changed slow mode to {duration}";
|
||||
"lng_admin_log_removed_slow_mode" = "{from} disabled slow mode";
|
||||
"lng_admin_log_started_group_call" = "{from} started a new voice chat";
|
||||
"lng_admin_log_started_group_call_channel" = "{from} started a new live stream";
|
||||
"lng_admin_log_discarded_group_call" = "{from} discarded a voice chat";
|
||||
"lng_admin_log_discarded_group_call_channel" = "{from} discarded a live stream";
|
||||
"lng_admin_log_muted_participant" = "{from} muted {user} in a voice chat";
|
||||
"lng_admin_log_muted_participant_channel" = "{from} muted {user} in a live stream";
|
||||
"lng_admin_log_unmuted_participant" = "{from} unmuted {user} in a voice chat";
|
||||
"lng_admin_log_unmuted_participant_channel" = "{from} unmuted {user} in a live stream";
|
||||
"lng_admin_log_allowed_unmute_self" = "{from} allowed new voice chat members to speak";
|
||||
"lng_admin_log_allowed_unmute_self_channel" = "{from} allowed new live stream members to speak";
|
||||
"lng_admin_log_disallowed_unmute_self" = "{from} started muting new voice chat members";
|
||||
"lng_admin_log_disallowed_unmute_self_channel" = "{from} started muting new live stream members";
|
||||
"lng_admin_log_participant_volume" = "{from} changed voice chat volume for {user} to {percent}";
|
||||
"lng_admin_log_participant_volume_channel" = "{from} changed live stream volume for {user} to {percent}";
|
||||
"lng_admin_log_user_with_username" = "{name} ({mention})";
|
||||
"lng_admin_log_messages_ttl_set" = "{from} enabled messages auto-delete after {duration}";
|
||||
"lng_admin_log_messages_ttl_changed" = "{from} changed messages auto-delete period from {previous} to {duration}";
|
||||
@@ -2461,6 +2489,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_admin_invite_link" = "Invite users via link";
|
||||
"lng_admin_log_admin_pin_messages" = "Pin messages";
|
||||
"lng_admin_log_admin_manage_calls" = "Manage voice chats";
|
||||
"lng_admin_log_admin_manage_calls_channel" = "Manage live streams";
|
||||
"lng_admin_log_admin_add_admins" = "Add new admins";
|
||||
|
||||
"lng_terms_signup" = "By signing up,\nyou agree to the {link}.";
|
||||
@@ -2482,6 +2511,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_date_input_month" = "Month";
|
||||
"lng_date_input_year" = "Year";
|
||||
|
||||
"lng_forward_title" = "Forward Message";
|
||||
"lng_forward_many_title#one" = "Forward {count} Message";
|
||||
"lng_forward_many_title#other" = "Forward {count} Messages";
|
||||
"lng_forward_about" = "You can remove the sender's name so that this message will look like it was sent by you.";
|
||||
"lng_forward_many_about" = "You can remove the senders’ names so that these messages will look like they were sent by you.";
|
||||
"lng_forward_show_sender" = "Show sender's name";
|
||||
"lng_forward_show_senders" = "Show senders' names";
|
||||
"lng_forward_show_caption" = "Show caption";
|
||||
"lng_forward_show_captions" = "Show captions";
|
||||
"lng_forward_change_recipient" = "Change recipient";
|
||||
"lng_forward_sender_names_removed" = "Sender names removed";
|
||||
|
||||
"lng_passport_title" = "Telegram passport";
|
||||
"lng_passport_request1" = "{bot} requests access to your personal data";
|
||||
"lng_passport_request2" = "to sign you up for their services";
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
<file alias="js/script.js">../../export_html/js/script.js</file>
|
||||
</qresource>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="art/background.jpg">../../art/background.jpg</file>
|
||||
<file alias="art/background.tgv">../../art/background.tgv</file>
|
||||
<file alias="art/bg_thumbnail.png">../../art/bg_thumbnail.png</file>
|
||||
<file alias="art/bg_initial.jpg">../../art/bg_initial.jpg</file>
|
||||
<file alias="art/logo_256.png">../../art/logo_256.png</file>
|
||||
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.9.13.0" />
|
||||
Version="3.0.1.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,9,13,0
|
||||
PRODUCTVERSION 2,9,13,0
|
||||
FILEVERSION 3,0,1,0
|
||||
PRODUCTVERSION 3,0,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "2.9.13.0"
|
||||
VALUE "FileVersion", "3.0.1.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.9.13.0"
|
||||
VALUE "ProductVersion", "3.0.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,9,13,0
|
||||
PRODUCTVERSION 2,9,13,0
|
||||
FILEVERSION 3,0,1,0
|
||||
PRODUCTVERSION 3,0,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "2.9.13.0"
|
||||
VALUE "FileVersion", "3.0.1.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.9.13.0"
|
||||
VALUE "ProductVersion", "3.0.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
class UserData;
|
||||
class ChannelData;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
@@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
class History;
|
||||
class PhotoData;
|
||||
class DocumentData;
|
||||
|
||||
@@ -3580,9 +3580,11 @@ void ApiWrap::sendAction(const SendAction &action) {
|
||||
|
||||
void ApiWrap::finishForwarding(const SendAction &action) {
|
||||
const auto history = action.history;
|
||||
auto toForward = history->validateForwardDraft();
|
||||
if (!toForward.empty()) {
|
||||
const auto error = GetErrorTextForSending(history->peer, toForward);
|
||||
auto toForward = history->resolveForwardDraft();
|
||||
if (!toForward.items.empty()) {
|
||||
const auto error = GetErrorTextForSending(
|
||||
history->peer,
|
||||
toForward.items);
|
||||
if (!error.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -3600,10 +3602,10 @@ void ApiWrap::finishForwarding(const SendAction &action) {
|
||||
}
|
||||
|
||||
void ApiWrap::forwardMessages(
|
||||
HistoryItemsList &&items,
|
||||
Data::ResolvedForwardDraft &&draft,
|
||||
const SendAction &action,
|
||||
FnMut<void()> &&successCallback) {
|
||||
Expects(!items.empty());
|
||||
Expects(!draft.items.empty());
|
||||
|
||||
auto &histories = _session->data().histories();
|
||||
|
||||
@@ -3618,8 +3620,10 @@ void ApiWrap::forwardMessages(
|
||||
shared->callback = std::move(successCallback);
|
||||
}
|
||||
|
||||
const auto count = int(items.size());
|
||||
const auto genClientSideMessage = action.generateLocal && (count < 2);
|
||||
const auto count = int(draft.items.size());
|
||||
const auto genClientSideMessage = action.generateLocal
|
||||
&& (count < 2)
|
||||
&& (draft.options == Data::ForwardOptions::PreserveInfo);
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
|
||||
@@ -3640,8 +3644,14 @@ void ApiWrap::forwardMessages(
|
||||
} else {
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
if (draft.options != Data::ForwardOptions::PreserveInfo) {
|
||||
sendFlags |= MTPmessages_ForwardMessages::Flag::f_drop_author;
|
||||
}
|
||||
if (draft.options == Data::ForwardOptions::NoNamesAndCaptions) {
|
||||
sendFlags |= MTPmessages_ForwardMessages::Flag::f_drop_media_captions;
|
||||
}
|
||||
|
||||
auto forwardFrom = items.front()->history()->peer;
|
||||
auto forwardFrom = draft.items.front()->history()->peer;
|
||||
auto ids = QVector<MTPint>();
|
||||
auto randomIds = QVector<MTPlong>();
|
||||
auto localIds = std::shared_ptr<base::flat_map<uint64, FullMsgId>>();
|
||||
@@ -3688,7 +3698,7 @@ void ApiWrap::forwardMessages(
|
||||
|
||||
ids.reserve(count);
|
||||
randomIds.reserve(count);
|
||||
for (const auto item : items) {
|
||||
for (const auto item : draft.items) {
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
if (genClientSideMessage) {
|
||||
if (const auto message = item->toHistoryMessage()) {
|
||||
|
||||
@@ -29,6 +29,7 @@ class Session;
|
||||
namespace Data {
|
||||
struct UpdatedFileReferences;
|
||||
class WallPaper;
|
||||
struct ResolvedForwardDraft;
|
||||
} // namespace Data
|
||||
|
||||
namespace InlineBots {
|
||||
@@ -319,7 +320,7 @@ public:
|
||||
void sendAction(const SendAction &action);
|
||||
void finishForwarding(const SendAction &action);
|
||||
void forwardMessages(
|
||||
HistoryItemsList &&items,
|
||||
Data::ResolvedForwardDraft &&draft,
|
||||
const SendAction &action,
|
||||
FnMut<void()> &&successCallback = nullptr);
|
||||
void shareContact(
|
||||
|
||||
@@ -242,6 +242,7 @@ void BackgroundBox::Inner::sortPapers() {
|
||||
night ? data.isDark() : !data.isDark(),
|
||||
Data::IsDefaultWallPaper(data),
|
||||
!data.isDefault() && !Data::IsLegacy1DefaultWallPaper(data),
|
||||
Data::IsLegacy3DefaultWallPaper(data),
|
||||
Data::IsLegacy2DefaultWallPaper(data),
|
||||
Data::IsLegacy1DefaultWallPaper(data));
|
||||
});
|
||||
@@ -379,6 +380,7 @@ void BackgroundBox::Inner::paintPaper(
|
||||
} else if (Data::IsCloudWallPaper(paper.data)
|
||||
&& !Data::IsDefaultWallPaper(paper.data)
|
||||
&& !Data::IsLegacy2DefaultWallPaper(paper.data)
|
||||
&& !Data::IsLegacy3DefaultWallPaper(paper.data)
|
||||
&& !v::is_null(over)
|
||||
&& (&paper == &_papers[getSelectionIndex(over)])) {
|
||||
const auto deleteSelected = v::is<DeleteSelected>(over);
|
||||
@@ -419,6 +421,7 @@ void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
&& Data::IsCloudWallPaper(data)
|
||||
&& !Data::IsDefaultWallPaper(data)
|
||||
&& !Data::IsLegacy2DefaultWallPaper(data)
|
||||
&& !Data::IsLegacy3DefaultWallPaper(data)
|
||||
&& (currentId != data.id());
|
||||
return (result >= _papers.size())
|
||||
? Selection()
|
||||
|
||||
@@ -150,7 +150,7 @@ std::vector<std::pair<ChatAdminRights, QString>> AdminRightLabels(
|
||||
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
|
||||
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
|
||||
{ Flag::InviteUsers, tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
|
||||
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
|
||||
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1902,14 +1902,17 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() {
|
||||
void StickersBox::Inner::rebuildMegagroupSet() {
|
||||
Expects(_megagroupSet != nullptr);
|
||||
|
||||
if (!_megagroupSetInput.id) {
|
||||
const auto clearCurrent = [&] {
|
||||
if (_megagroupSelectedSet) {
|
||||
_megagroupSetField->setText(QString());
|
||||
_megagroupSetField->finishAnimating();
|
||||
}
|
||||
_megagroupSelectedSet.reset();
|
||||
_megagroupSelectedSet = nullptr;
|
||||
_megagroupSelectedRemove.destroy();
|
||||
_megagroupSelectedShadow.destroy();
|
||||
};
|
||||
if (!_megagroupSetInput.id) {
|
||||
clearCurrent();
|
||||
return;
|
||||
}
|
||||
auto setId = _megagroupSetInput.id;
|
||||
@@ -1917,6 +1920,10 @@ void StickersBox::Inner::rebuildMegagroupSet() {
|
||||
auto it = sets.find(setId);
|
||||
if (it == sets.cend()
|
||||
|| (it->second->flags & SetFlag::NotLoaded)) {
|
||||
// It may have been in sets and stored in _megagroupSelectedSet
|
||||
// already, but then removed from sets. We need to clear the stored
|
||||
// pointer, otherwise we may crash in paint event while loading.
|
||||
clearCurrent();
|
||||
session().api().scheduleStickerSetRequest(
|
||||
_megagroupSetInput.id,
|
||||
_megagroupSetInput.accessHash);
|
||||
|
||||
@@ -126,6 +126,7 @@ void ScheduleGroupCallBox(
|
||||
copy.scheduleDate = date;
|
||||
done(std::move(copy));
|
||||
};
|
||||
const auto livestream = info.peer->isBroadcast();
|
||||
const auto duration = box->lifetime().make_state<
|
||||
rpl::variable<QString>>();
|
||||
auto description = (info.peer->isBroadcast()
|
||||
@@ -151,7 +152,9 @@ void ScheduleGroupCallBox(
|
||||
).addSecs(60 * 60 * (now.time().minute() < 30 ? 1 : 2));
|
||||
|
||||
auto descriptor = Ui::ChooseDateTimeBox(box, {
|
||||
.title = tr::lng_group_call_schedule_title(),
|
||||
.title = (livestream
|
||||
? tr::lng_group_call_schedule_title_channel()
|
||||
: tr::lng_group_call_schedule_title()),
|
||||
.submit = tr::lng_schedule_button(),
|
||||
.done = send,
|
||||
.min = min,
|
||||
@@ -194,11 +197,16 @@ void ChooseJoinAsBox(
|
||||
JoinInfo info,
|
||||
Fn<void(JoinInfo)> done) {
|
||||
box->setWidth(st::groupCallJoinAsWidth);
|
||||
const auto livestream = info.peer->isBroadcast();
|
||||
box->setTitle([&] {
|
||||
switch (context) {
|
||||
case Context::Create: return tr::lng_group_call_start_as_header();
|
||||
case Context::Create: return livestream
|
||||
? tr::lng_group_call_start_as_header_channel()
|
||||
: tr::lng_group_call_start_as_header();
|
||||
case Context::Join:
|
||||
case Context::JoinWithConfirm: return tr::lng_group_call_join_as_header();
|
||||
case Context::JoinWithConfirm: return livestream
|
||||
? tr::lng_group_call_join_as_header_channel()
|
||||
: tr::lng_group_call_join_as_header();
|
||||
case Context::Switch: return tr::lng_group_call_display_as_header();
|
||||
}
|
||||
Unexpected("Context in ChooseJoinAsBox.");
|
||||
@@ -243,7 +251,9 @@ void ChooseJoinAsBox(
|
||||
box,
|
||||
tr::lng_group_call_or_schedule(
|
||||
lt_link,
|
||||
tr::lng_group_call_schedule(makeLink),
|
||||
(livestream
|
||||
? tr::lng_group_call_schedule_channel
|
||||
: tr::lng_group_call_schedule)(makeLink),
|
||||
Ui::Text::WithEntities),
|
||||
labelSt));
|
||||
label->setClickHandlerFilter([=](const auto&...) {
|
||||
@@ -276,8 +286,7 @@ void ChooseJoinAsBox(
|
||||
const auto anonymouseAdmin = channel
|
||||
&& ((channel->isMegagroup() && channel->amAnonymous())
|
||||
|| (channel->isBroadcast()
|
||||
&& (channel->amCreator()
|
||||
|| channel->hasAdminRights())));
|
||||
&& (channel->amCreator() || channel->hasAdminRights())));
|
||||
if (anonymouseAdmin && !joinAsAlreadyUsed) {
|
||||
return { tr::lng_group_call_join_sure_personal(tr::now) };
|
||||
} else if (context != ChooseJoinAsProcess::Context::JoinWithConfirm) {
|
||||
@@ -286,7 +295,9 @@ void ChooseJoinAsBox(
|
||||
const auto name = !existing->title().isEmpty()
|
||||
? existing->title()
|
||||
: peer->name;
|
||||
return tr::lng_group_call_join_confirm(
|
||||
return (peer->isBroadcast()
|
||||
? tr::lng_group_call_join_confirm_channel
|
||||
: tr::lng_group_call_join_confirm)(
|
||||
tr::now,
|
||||
lt_chat,
|
||||
Ui::Text::Bold(name),
|
||||
@@ -402,6 +413,7 @@ void ChooseJoinAsProcess::start(
|
||||
finish(info);
|
||||
return;
|
||||
}
|
||||
const auto livestream = peer->isBroadcast();
|
||||
const auto creating = !peer->groupCall();
|
||||
if (creating) {
|
||||
confirmation
|
||||
@@ -409,7 +421,9 @@ void ChooseJoinAsProcess::start(
|
||||
.append(tr::lng_group_call_or_schedule(
|
||||
tr::now,
|
||||
lt_link,
|
||||
Ui::Text::Link(tr::lng_group_call_schedule(tr::now)),
|
||||
Ui::Text::Link((livestream
|
||||
? tr::lng_group_call_schedule_channel
|
||||
: tr::lng_group_call_schedule)(tr::now)),
|
||||
Ui::Text::WithEntities));
|
||||
}
|
||||
const auto guard = base::make_weak(&_request->guard);
|
||||
|
||||
@@ -979,11 +979,6 @@ void GroupCall::start(TimeId scheduleDate) {
|
||||
LOG(("Call Error: Could not create, error: %1"
|
||||
).arg(error.type()));
|
||||
hangup();
|
||||
if (error.type() == u"GROUPCALL_ANONYMOUS_FORBIDDEN"_q) {
|
||||
Ui::ShowMultilineToast({
|
||||
.text = { tr::lng_group_call_no_anonymous(tr::now) },
|
||||
});
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -1313,11 +1308,7 @@ void GroupCall::rejoin(not_null<PeerData*> as) {
|
||||
|
||||
hangup();
|
||||
Ui::ShowMultilineToast({
|
||||
.text = { type == u"GROUPCALL_ANONYMOUS_FORBIDDEN"_q
|
||||
? tr::lng_group_call_no_anonymous(tr::now)
|
||||
: type == u"GROUPCALL_PARTICIPANTS_TOO_MUCH"_q
|
||||
? tr::lng_group_call_too_many(tr::now)
|
||||
: type == u"GROUPCALL_FORBIDDEN"_q
|
||||
.text = { type == u"GROUPCALL_FORBIDDEN"_q
|
||||
? tr::lng_group_not_accessible(tr::now)
|
||||
: Lang::Hard::ServerError() },
|
||||
});
|
||||
|
||||
@@ -37,8 +37,11 @@ void EditGroupCallTitleBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
const QString &placeholder,
|
||||
const QString &title,
|
||||
bool livestream,
|
||||
Fn<void(QString)> done) {
|
||||
box->setTitle(tr::lng_group_call_edit_title());
|
||||
box->setTitle(livestream
|
||||
? tr::lng_group_call_edit_title_channel()
|
||||
: tr::lng_group_call_edit_title());
|
||||
const auto input = box->addRow(object_ptr<Ui::InputField>(
|
||||
box,
|
||||
st::groupCallField,
|
||||
@@ -492,25 +495,36 @@ void LeaveBox(
|
||||
not_null<GroupCall*> call,
|
||||
bool discardChecked,
|
||||
BoxContext context) {
|
||||
const auto livestream = call->peer()->isBroadcast();
|
||||
const auto scheduled = (call->scheduleDate() != 0);
|
||||
if (!scheduled) {
|
||||
box->setTitle(tr::lng_group_call_leave_title());
|
||||
box->setTitle(livestream
|
||||
? tr::lng_group_call_leave_title_channel()
|
||||
: tr::lng_group_call_leave_title());
|
||||
}
|
||||
const auto inCall = (context == BoxContext::GroupCallPanel);
|
||||
box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box.get(),
|
||||
(scheduled
|
||||
? tr::lng_group_call_close_sure()
|
||||
: tr::lng_group_call_leave_sure()),
|
||||
? (livestream
|
||||
? tr::lng_group_call_close_sure_channel()
|
||||
: tr::lng_group_call_close_sure())
|
||||
: (livestream
|
||||
? tr::lng_group_call_leave_sure_channel()
|
||||
: tr::lng_group_call_leave_sure())),
|
||||
(inCall ? st::groupCallBoxLabel : st::boxLabel)),
|
||||
scheduled ? st::boxPadding : st::boxRowPadding);
|
||||
const auto discard = call->peer()->canManageGroupCall()
|
||||
? box->addRow(object_ptr<Ui::Checkbox>(
|
||||
box.get(),
|
||||
(scheduled
|
||||
? tr::lng_group_call_also_cancel()
|
||||
: tr::lng_group_call_also_end()),
|
||||
? (livestream
|
||||
? tr::lng_group_call_also_cancel_channel()
|
||||
: tr::lng_group_call_also_cancel())
|
||||
: (livestream
|
||||
? tr::lng_group_call_also_end_channel()
|
||||
: tr::lng_group_call_also_end())),
|
||||
discardChecked,
|
||||
(inCall ? st::groupCallCheckbox : st::defaultBoxCheckbox),
|
||||
(inCall ? st::groupCallCheck : st::defaultCheck)),
|
||||
@@ -592,7 +606,11 @@ void FillMenu(
|
||||
menu->addSeparator();
|
||||
}
|
||||
if (addEditTitle) {
|
||||
menu->addAction(tr::lng_group_call_edit_title(tr::now), [=] {
|
||||
const auto livestream = call->peer()->isBroadcast();
|
||||
const auto text = (livestream
|
||||
? tr::lng_group_call_edit_title_channel
|
||||
: tr::lng_group_call_edit_title)(tr::now);
|
||||
menu->addAction(text, [=] {
|
||||
const auto done = [=](const QString &title) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->changeTitle(title);
|
||||
@@ -603,6 +621,7 @@ void FillMenu(
|
||||
EditGroupCallTitleBox,
|
||||
peer->name,
|
||||
real->title(),
|
||||
livestream,
|
||||
done));
|
||||
}
|
||||
});
|
||||
@@ -666,15 +685,18 @@ void FillMenu(
|
||||
BoxContext::GroupCallPanel));
|
||||
}
|
||||
};
|
||||
const auto livestream = real->peer()->isBroadcast();
|
||||
menu->addAction(MakeAttentionAction(
|
||||
menu->menu(),
|
||||
(real->scheduleDate()
|
||||
? (call->canManage()
|
||||
? tr::lng_group_call_cancel(tr::now)
|
||||
: tr::lng_group_call_leave(tr::now))
|
||||
: (call->canManage()
|
||||
? tr::lng_group_call_end(tr::now)
|
||||
: tr::lng_group_call_leave(tr::now))),
|
||||
(!call->canManage()
|
||||
? tr::lng_group_call_leave
|
||||
: real->scheduleDate()
|
||||
? (livestream
|
||||
? tr::lng_group_call_cancel_channel
|
||||
: tr::lng_group_call_cancel)
|
||||
: (livestream
|
||||
? tr::lng_group_call_end_channel
|
||||
: tr::lng_group_call_end))(tr::now),
|
||||
finish));
|
||||
}
|
||||
|
||||
|
||||
@@ -335,7 +335,9 @@ void Panel::startScheduledNow() {
|
||||
_call->startScheduledNow();
|
||||
};
|
||||
auto owned = ConfirmBox({
|
||||
.text = { tr::lng_group_call_start_now_sure(tr::now) },
|
||||
.text = { (_call->peer()->isBroadcast()
|
||||
? tr::lng_group_call_start_now_sure_channel
|
||||
: tr::lng_group_call_start_now_sure)(tr::now) },
|
||||
.button = tr::lng_group_call_start_now(),
|
||||
.callback = done,
|
||||
});
|
||||
@@ -973,6 +975,7 @@ void Panel::updateWideControlsVisibility() {
|
||||
}
|
||||
|
||||
void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||
const auto livestream = real->peer()->isBroadcast();
|
||||
const auto validateRecordingMark = [=](bool recording) {
|
||||
if (!recording && _recordingMark) {
|
||||
_recordingMark.destroy();
|
||||
@@ -989,7 +992,9 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||
const auto skip = st::groupCallRecordingMarkSkip;
|
||||
_recordingMark->resize(size + 2 * skip, size + 2 * skip);
|
||||
_recordingMark->setClickedCallback([=] {
|
||||
showToast({ tr::lng_group_call_is_recorded(tr::now) });
|
||||
showToast({ (livestream
|
||||
? tr::lng_group_call_is_recorded_channel
|
||||
: tr::lng_group_call_is_recorded)(tr::now) });
|
||||
});
|
||||
const auto animate = [=] {
|
||||
const auto opaque = state->opaque;
|
||||
@@ -1024,12 +1029,17 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||
_1 != 0
|
||||
) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool recorded) {
|
||||
const auto livestream = _call->peer()->isBroadcast();
|
||||
validateRecordingMark(recorded);
|
||||
showToast((recorded
|
||||
? tr::lng_group_call_recording_started
|
||||
? (livestream
|
||||
? tr::lng_group_call_recording_started_channel
|
||||
: tr::lng_group_call_recording_started)
|
||||
: _call->recordingStoppedByMe()
|
||||
? tr::lng_group_call_recording_saved
|
||||
: tr::lng_group_call_recording_stopped)(
|
||||
: (livestream
|
||||
? tr::lng_group_call_recording_stopped_channel
|
||||
: tr::lng_group_call_recording_stopped))(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue));
|
||||
}, lifetime());
|
||||
@@ -1277,16 +1287,18 @@ void Panel::kickParticipant(not_null<PeerData*> participantPeer) {
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box.get(),
|
||||
(!participantPeer->isUser()
|
||||
? tr::lng_group_call_remove_channel(
|
||||
tr::now,
|
||||
lt_channel,
|
||||
participantPeer->name)
|
||||
? (_peer->isBroadcast()
|
||||
? tr::lng_group_call_remove_channel_from_channel
|
||||
: tr::lng_group_call_remove_channel)(
|
||||
tr::now,
|
||||
lt_channel,
|
||||
participantPeer->name)
|
||||
: (_peer->isBroadcast()
|
||||
? tr::lng_profile_sure_kick_channel
|
||||
: tr::lng_profile_sure_kick)(
|
||||
tr::now,
|
||||
lt_user,
|
||||
participantPeer->asUser()->firstName)),
|
||||
tr::now,
|
||||
lt_user,
|
||||
participantPeer->asUser()->firstName)),
|
||||
st::groupCallBoxLabel),
|
||||
style::margins(
|
||||
st::boxRowPadding.left(),
|
||||
|
||||
@@ -49,7 +49,9 @@ void Toasts::setupJoinAsChanged() {
|
||||
return (state == State::Joined);
|
||||
}) | rpl::take(1);
|
||||
}) | rpl::flatten_latest() | rpl::start_with_next([=] {
|
||||
_panel->showToast(tr::lng_group_call_join_as_changed(
|
||||
_panel->showToast((_call->peer()->isBroadcast()
|
||||
? tr::lng_group_call_join_as_changed_channel
|
||||
: tr::lng_group_call_join_as_changed)(
|
||||
tr::now,
|
||||
lt_name,
|
||||
Ui::Text::Bold(_call->joinAs()->name),
|
||||
@@ -67,7 +69,9 @@ void Toasts::setupTitleChanged() {
|
||||
? peer->name
|
||||
: peer->groupCall()->title();
|
||||
}) | rpl::start_with_next([=](const QString &title) {
|
||||
_panel->showToast(tr::lng_group_call_title_changed(
|
||||
_panel->showToast((_call->peer()->isBroadcast()
|
||||
? tr::lng_group_call_title_changed_channel
|
||||
: tr::lng_group_call_title_changed)(
|
||||
tr::now,
|
||||
lt_title,
|
||||
Ui::Text::Bold(title),
|
||||
|
||||
@@ -199,6 +199,11 @@ auto FieldAutocomplete::stickerChosen() const
|
||||
return _inner->stickerChosen();
|
||||
}
|
||||
|
||||
auto FieldAutocomplete::choosingProcesses() const
|
||||
-> rpl::producer<FieldAutocomplete::Type> {
|
||||
return _scroll->scrollTopChanges() | rpl::map([=] { return _type; });
|
||||
}
|
||||
|
||||
FieldAutocomplete::~FieldAutocomplete() = default;
|
||||
|
||||
void FieldAutocomplete::paintEvent(QPaintEvent *e) {
|
||||
|
||||
@@ -87,6 +87,12 @@ public:
|
||||
Api::SendOptions options;
|
||||
ChooseMethod method;
|
||||
};
|
||||
enum class Type {
|
||||
Mentions,
|
||||
Hashtags,
|
||||
BotCommands,
|
||||
Stickers,
|
||||
};
|
||||
|
||||
bool chooseSelected(ChooseMethod method) const;
|
||||
|
||||
@@ -111,6 +117,7 @@ public:
|
||||
rpl::producer<HashtagChosen> hashtagChosen() const;
|
||||
rpl::producer<BotCommandChosen> botCommandChosen() const;
|
||||
rpl::producer<StickerChosen> stickerChosen() const;
|
||||
rpl::producer<Type> choosingProcesses() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void showAnimated();
|
||||
@@ -176,12 +183,6 @@ private:
|
||||
ChannelData *_channel = nullptr;
|
||||
EmojiPtr _emoji;
|
||||
uint64 _stickersSeed = 0;
|
||||
enum class Type {
|
||||
Mentions,
|
||||
Hashtags,
|
||||
BotCommands,
|
||||
Stickers,
|
||||
};
|
||||
Type _type = Type::Mentions;
|
||||
QString _filter;
|
||||
QRect _boundings;
|
||||
|
||||
@@ -140,7 +140,7 @@ QByteArray Settings::serialize() const {
|
||||
<< qint32(_askDownloadPath ? 1 : 0)
|
||||
<< _downloadPath.current()
|
||||
<< _downloadPathBookmark
|
||||
<< qint32(_voiceMsgPlaybackDoubled ? 1 : 0)
|
||||
<< qint32(0) // Old double voice playback speed.
|
||||
<< qint32(_soundNotify ? 1 : 0)
|
||||
<< qint32(_desktopNotify ? 1 : 0)
|
||||
<< qint32(_flashBounceNotify ? 1 : 0)
|
||||
@@ -219,7 +219,8 @@ QByteArray Settings::serialize() const {
|
||||
<< qint32(_hiddenGroupCallTooltips.value())
|
||||
<< qint32(_disableOpenGL ? 1 : 0)
|
||||
<< _photoEditorBrush
|
||||
<< qint32(_groupCallNoiseSuppression ? 1 : 0);
|
||||
<< qint32(_groupCallNoiseSuppression ? 1 : 0)
|
||||
<< qint32(_voicePlaybackSpeed * 100);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -240,7 +241,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
qint32 askDownloadPath = _askDownloadPath ? 1 : 0;
|
||||
QString downloadPath = _downloadPath.current();
|
||||
QByteArray downloadPathBookmark = _downloadPathBookmark;
|
||||
qint32 voiceMsgPlaybackDoubled = _voiceMsgPlaybackDoubled ? 1 : 0;
|
||||
qint32 oldVoiceMsgPlaybackDoubled = 0;
|
||||
qint32 soundNotify = _soundNotify ? 1 : 0;
|
||||
qint32 desktopNotify = _desktopNotify ? 1 : 0;
|
||||
qint32 flashBounceNotify = _flashBounceNotify ? 1 : 0;
|
||||
@@ -271,6 +272,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
qint32 suggestStickersByEmoji = _suggestStickersByEmoji ? 1 : 0;
|
||||
qint32 spellcheckerEnabled = _spellcheckerEnabled.current() ? 1 : 0;
|
||||
qint32 videoPlaybackSpeed = Core::Settings::SerializePlaybackSpeed(_videoPlaybackSpeed.current());
|
||||
qint32 voicePlaybackSpeed = _voicePlaybackSpeed * 100;
|
||||
QByteArray videoPipGeometry = _videoPipGeometry;
|
||||
qint32 dictionariesEnabledCount = 0;
|
||||
std::vector<int> dictionariesEnabled;
|
||||
@@ -312,7 +314,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
>> askDownloadPath
|
||||
>> downloadPath
|
||||
>> downloadPathBookmark
|
||||
>> voiceMsgPlaybackDoubled
|
||||
>> oldVoiceMsgPlaybackDoubled
|
||||
>> soundNotify
|
||||
>> desktopNotify
|
||||
>> flashBounceNotify
|
||||
@@ -455,6 +457,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
if (!stream.atEnd()) {
|
||||
stream >> groupCallNoiseSuppression;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
stream >> voicePlaybackSpeed;
|
||||
}
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for Core::Settings::constructFromSerialized()"));
|
||||
@@ -471,7 +476,6 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
_askDownloadPath = (askDownloadPath == 1);
|
||||
_downloadPath = downloadPath;
|
||||
_downloadPathBookmark = downloadPathBookmark;
|
||||
_voiceMsgPlaybackDoubled = (voiceMsgPlaybackDoubled == 1);
|
||||
_soundNotify = (soundNotify == 1);
|
||||
_desktopNotify = (desktopNotify == 1);
|
||||
_flashBounceNotify = (flashBounceNotify == 1);
|
||||
@@ -525,6 +529,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
_suggestStickersByEmoji = (suggestStickersByEmoji == 1);
|
||||
_spellcheckerEnabled = (spellcheckerEnabled == 1);
|
||||
_videoPlaybackSpeed = DeserializePlaybackSpeed(videoPlaybackSpeed);
|
||||
_voicePlaybackSpeed = oldVoiceMsgPlaybackDoubled
|
||||
? 2.0
|
||||
: voicePlaybackSpeed / 100.;
|
||||
_videoPipGeometry = (videoPipGeometry);
|
||||
_dictionariesEnabled = std::move(dictionariesEnabled);
|
||||
_autoDownloadDictionaries = (autoDownloadDictionaries == 1);
|
||||
@@ -782,7 +789,6 @@ void Settings::resetOnLastLogout() {
|
||||
_downloadPath = QString();
|
||||
_downloadPathBookmark = QByteArray();
|
||||
|
||||
_voiceMsgPlaybackDoubled = false;
|
||||
_soundNotify = true;
|
||||
_desktopNotify = true;
|
||||
_flashBounceNotify = true;
|
||||
@@ -826,6 +832,7 @@ void Settings::resetOnLastLogout() {
|
||||
_suggestStickersByEmoji = true;
|
||||
_spellcheckerEnabled = true;
|
||||
_videoPlaybackSpeed = 1.;
|
||||
_voicePlaybackSpeed = 1.;
|
||||
//_videoPipGeometry = QByteArray();
|
||||
_dictionariesEnabled = std::vector<int>();
|
||||
_autoDownloadDictionaries = true;
|
||||
|
||||
@@ -146,12 +146,6 @@ public:
|
||||
void setDownloadPathBookmark(const QByteArray &value) {
|
||||
_downloadPathBookmark = value;
|
||||
}
|
||||
[[nodiscard]] bool voiceMsgPlaybackDoubled() const {
|
||||
return _voiceMsgPlaybackDoubled;
|
||||
}
|
||||
void setVoiceMsgPlaybackDoubled(bool value) {
|
||||
_voiceMsgPlaybackDoubled = value;
|
||||
}
|
||||
[[nodiscard]] bool soundNotify() const {
|
||||
return _soundNotify;
|
||||
}
|
||||
@@ -427,6 +421,12 @@ public:
|
||||
void setVideoPlaybackSpeed(float64 speed) {
|
||||
_videoPlaybackSpeed = speed;
|
||||
}
|
||||
[[nodiscard]] float64 voicePlaybackSpeed() const {
|
||||
return _voicePlaybackSpeed;
|
||||
}
|
||||
void setVoicePlaybackSpeed(float64 speed) {
|
||||
_voicePlaybackSpeed = speed;
|
||||
}
|
||||
[[nodiscard]] QByteArray videoPipGeometry() const {
|
||||
return _videoPipGeometry;
|
||||
}
|
||||
@@ -633,7 +633,6 @@ private:
|
||||
bool _askDownloadPath = false;
|
||||
rpl::variable<QString> _downloadPath;
|
||||
QByteArray _downloadPathBookmark;
|
||||
bool _voiceMsgPlaybackDoubled = false;
|
||||
bool _soundNotify = true;
|
||||
bool _desktopNotify = true;
|
||||
bool _flashBounceNotify = true;
|
||||
@@ -670,6 +669,7 @@ private:
|
||||
bool _suggestStickersByEmoji = true;
|
||||
rpl::variable<bool> _spellcheckerEnabled = true;
|
||||
rpl::variable<float64> _videoPlaybackSpeed = 1.;
|
||||
float64 _voicePlaybackSpeed = 1.;
|
||||
QByteArray _videoPipGeometry;
|
||||
rpl::variable<std::vector<int>> _dictionariesEnabled;
|
||||
rpl::variable<bool> _autoDownloadDictionaries = true;
|
||||
|
||||
@@ -617,11 +617,3 @@ rpl::producer<> on_main_update_requests() {
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
namespace base {
|
||||
|
||||
void EnterFromEventLoop(FnMut<void()> &&method) {
|
||||
Core::Sandbox::Instance().customEnterFromEventLoop(std::move(method));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 2009013;
|
||||
constexpr auto AppVersionStr = "2.9.13";
|
||||
constexpr auto AppBetaVersion = true;
|
||||
constexpr auto AppVersion = 3000001;
|
||||
constexpr auto AppVersionStr = "3.0.1";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -260,6 +260,8 @@ const std::vector<Info> &CountriesInstance::list() {
|
||||
|
||||
void CountriesInstance::setList(std::vector<Info> &&infos) {
|
||||
_list = std::move(infos);
|
||||
_byCode.clear();
|
||||
_byISO2.clear();
|
||||
}
|
||||
|
||||
const CountriesInstance::Map &CountriesInstance::byCode() {
|
||||
@@ -355,6 +357,9 @@ FormatResult CountriesInstance::format(FormatArgs args) {
|
||||
? QVector<int>()
|
||||
: QVector<int>{ codeSize };
|
||||
auto groupSize = 0;
|
||||
if (bestCallingCodePtr->patterns.empty()) {
|
||||
return FormatResult{ .groups = std::move(groups) };
|
||||
}
|
||||
for (const auto &c : bestCallingCodePtr->patterns.front()) {
|
||||
if (c == ' ') {
|
||||
groups.push_back(base::take(groupSize));
|
||||
|
||||
103
Telegram/SourceFiles/data/data_audio_msg_id.cpp
Normal file
103
Telegram/SourceFiles/data/data_audio_msg_id.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/data_audio_msg_id.h"
|
||||
|
||||
#include "data/data_document.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMinLengthForChangeablePlaybackSpeed = 20 * TimeId(60); // 20 minutes.
|
||||
|
||||
} // namespace
|
||||
|
||||
AudioMsgId::AudioMsgId() {
|
||||
}
|
||||
|
||||
AudioMsgId::AudioMsgId(
|
||||
not_null<DocumentData*> audio,
|
||||
FullMsgId msgId,
|
||||
uint32 externalPlayId)
|
||||
: _audio(audio)
|
||||
, _contextId(msgId)
|
||||
, _externalPlayId(externalPlayId)
|
||||
, _changeablePlaybackSpeed(_audio->isVoiceMessage()
|
||||
|| _audio->isVideoMessage()
|
||||
|| (_audio->getDuration() >= kMinLengthForChangeablePlaybackSpeed)) {
|
||||
setTypeFromAudio();
|
||||
}
|
||||
|
||||
uint32 AudioMsgId::CreateExternalPlayId() {
|
||||
static auto Result = uint32(0);
|
||||
return ++Result ? Result : ++Result;
|
||||
}
|
||||
|
||||
AudioMsgId AudioMsgId::ForVideo() {
|
||||
auto result = AudioMsgId();
|
||||
result._externalPlayId = CreateExternalPlayId();
|
||||
result._type = Type::Video;
|
||||
return result;
|
||||
}
|
||||
|
||||
void AudioMsgId::setTypeFromAudio() {
|
||||
if (_audio->isVoiceMessage() || _audio->isVideoMessage()) {
|
||||
_type = Type::Voice;
|
||||
} else if (_audio->isVideoFile()) {
|
||||
_type = Type::Video;
|
||||
} else if (_audio->isAudioFile()) {
|
||||
_type = Type::Song;
|
||||
} else {
|
||||
_type = Type::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
AudioMsgId::Type AudioMsgId::type() const {
|
||||
return _type;
|
||||
}
|
||||
|
||||
DocumentData *AudioMsgId::audio() const {
|
||||
return _audio;
|
||||
}
|
||||
|
||||
FullMsgId AudioMsgId::contextId() const {
|
||||
return _contextId;
|
||||
}
|
||||
|
||||
uint32 AudioMsgId::externalPlayId() const {
|
||||
return _externalPlayId;
|
||||
}
|
||||
|
||||
bool AudioMsgId::changeablePlaybackSpeed() const {
|
||||
return _changeablePlaybackSpeed;
|
||||
}
|
||||
|
||||
AudioMsgId::operator bool() const {
|
||||
return (_audio != nullptr) || (_externalPlayId != 0);
|
||||
}
|
||||
|
||||
bool AudioMsgId::operator<(const AudioMsgId &other) const {
|
||||
if (quintptr(audio()) < quintptr(other.audio())) {
|
||||
return true;
|
||||
} else if (quintptr(other.audio()) < quintptr(audio())) {
|
||||
return false;
|
||||
} else if (contextId() < other.contextId()) {
|
||||
return true;
|
||||
} else if (other.contextId() < contextId()) {
|
||||
return false;
|
||||
}
|
||||
return (externalPlayId() < other.externalPlayId());
|
||||
}
|
||||
|
||||
bool AudioMsgId::operator==(const AudioMsgId &other) const {
|
||||
return (audio() == other.audio())
|
||||
&& (contextId() == other.contextId())
|
||||
&& (externalPlayId() == other.externalPlayId());
|
||||
}
|
||||
|
||||
bool AudioMsgId::operator!=(const AudioMsgId &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
50
Telegram/SourceFiles/data/data_audio_msg_id.h
Normal file
50
Telegram/SourceFiles/data/data_audio_msg_id.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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
|
||||
|
||||
class DocumentData;
|
||||
|
||||
class AudioMsgId final {
|
||||
public:
|
||||
enum class Type {
|
||||
Unknown,
|
||||
Voice,
|
||||
Song,
|
||||
Video,
|
||||
};
|
||||
|
||||
AudioMsgId();
|
||||
AudioMsgId(
|
||||
not_null<DocumentData*> audio,
|
||||
FullMsgId msgId,
|
||||
uint32 externalPlayId = 0);
|
||||
|
||||
[[nodiscard]] static uint32 CreateExternalPlayId();
|
||||
[[nodiscard]] static AudioMsgId ForVideo();
|
||||
|
||||
[[nodiscard]] Type type() const;
|
||||
[[nodiscard]] DocumentData *audio() const;
|
||||
[[nodiscard]] FullMsgId contextId() const;
|
||||
[[nodiscard]] uint32 externalPlayId() const;
|
||||
[[nodiscard]] bool changeablePlaybackSpeed() const;
|
||||
[[nodiscard]] explicit operator bool() const;
|
||||
|
||||
bool operator<(const AudioMsgId &other) const;
|
||||
bool operator==(const AudioMsgId &other) const;
|
||||
bool operator!=(const AudioMsgId &other) const;
|
||||
|
||||
private:
|
||||
void setTypeFromAudio();
|
||||
|
||||
DocumentData *_audio = nullptr;
|
||||
Type _type = Type::Unknown;
|
||||
FullMsgId _contextId;
|
||||
uint32 _externalPlayId = 0;
|
||||
bool _changeablePlaybackSpeed = false;
|
||||
|
||||
};
|
||||
@@ -17,6 +17,10 @@ namespace Dialogs {
|
||||
class Entry;
|
||||
} // namespace Dialogs
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Data {
|
||||
|
||||
namespace details {
|
||||
|
||||
@@ -201,7 +201,7 @@ bool Media::canBeGrouped() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString Media::chatListText() const {
|
||||
QString Media::chatListText(DrawInDialog way) const {
|
||||
auto result = notificationText();
|
||||
return result.isEmpty()
|
||||
? QString()
|
||||
@@ -341,10 +341,11 @@ QString MediaPhoto::notificationText() const {
|
||||
parent()->originalText().text);
|
||||
}
|
||||
|
||||
QString MediaPhoto::chatListText() const {
|
||||
return WithCaptionDialogsText(
|
||||
tr::lng_in_dlg_photo(tr::now),
|
||||
parent()->originalText().text);
|
||||
QString MediaPhoto::chatListText(DrawInDialog way) const {
|
||||
const auto caption = (way == DrawInDialog::WithoutSenderAndCaption)
|
||||
? QString()
|
||||
: parent()->originalText().text;
|
||||
return WithCaptionDialogsText(tr::lng_in_dlg_photo(tr::now), caption);
|
||||
}
|
||||
|
||||
QString MediaPhoto::pinnedTextSubstring() const {
|
||||
@@ -510,9 +511,9 @@ bool MediaFile::replyPreviewLoaded() const {
|
||||
return _document->replyPreviewLoaded();
|
||||
}
|
||||
|
||||
QString MediaFile::chatListText() const {
|
||||
QString MediaFile::chatListText(DrawInDialog way) const {
|
||||
if (const auto sticker = _document->sticker()) {
|
||||
return Media::chatListText();
|
||||
return Media::chatListText(way);
|
||||
}
|
||||
const auto type = [&] {
|
||||
using namespace Ui::Text;
|
||||
@@ -532,7 +533,10 @@ QString MediaFile::chatListText() const {
|
||||
}
|
||||
return tr::lng_in_dlg_file(tr::now);
|
||||
}();
|
||||
return WithCaptionDialogsText(type, parent()->originalText().text);
|
||||
const auto caption = (way == DrawInDialog::WithoutSenderAndCaption)
|
||||
? QString()
|
||||
: parent()->originalText().text;
|
||||
return WithCaptionDialogsText(type, caption);
|
||||
}
|
||||
|
||||
QString MediaFile::notificationText() const {
|
||||
@@ -851,7 +855,7 @@ Data::CloudImage *MediaLocation::location() const {
|
||||
return _location;
|
||||
}
|
||||
|
||||
QString MediaLocation::chatListText() const {
|
||||
QString MediaLocation::chatListText(DrawInDialog way) const {
|
||||
return WithCaptionDialogsText(tr::lng_maps_point(tr::now), _title);
|
||||
}
|
||||
|
||||
@@ -1045,7 +1049,7 @@ bool MediaWebPage::replyPreviewLoaded() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
QString MediaWebPage::chatListText() const {
|
||||
QString MediaWebPage::chatListText(DrawInDialog way) const {
|
||||
return notificationText();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace HistoryView {
|
||||
enum class Context : char;
|
||||
class Element;
|
||||
class Media;
|
||||
enum class DrawInDialog;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace Data {
|
||||
@@ -72,6 +73,8 @@ public:
|
||||
|
||||
not_null<HistoryItem*> parent() const;
|
||||
|
||||
using DrawInDialog = HistoryView::DrawInDialog;
|
||||
|
||||
virtual std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) = 0;
|
||||
|
||||
virtual DocumentData *document() const;
|
||||
@@ -92,7 +95,7 @@ public:
|
||||
virtual bool replyPreviewLoaded() const;
|
||||
// Returns text with link-start and link-end commands for service-color highlighting.
|
||||
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
|
||||
virtual QString chatListText() const;
|
||||
virtual QString chatListText(DrawInDialog way) const;
|
||||
virtual QString notificationText() const = 0;
|
||||
virtual QString pinnedTextSubstring() const = 0;
|
||||
virtual TextForMimeData clipboardText() const = 0;
|
||||
@@ -148,7 +151,7 @@ public:
|
||||
bool hasReplyPreview() const override;
|
||||
Image *replyPreview() const override;
|
||||
bool replyPreviewLoaded() const override;
|
||||
QString chatListText() const override;
|
||||
QString chatListText(DrawInDialog way) const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextForMimeData clipboardText() const override;
|
||||
@@ -186,7 +189,7 @@ public:
|
||||
bool hasReplyPreview() const override;
|
||||
Image *replyPreview() const override;
|
||||
bool replyPreviewLoaded() const override;
|
||||
QString chatListText() const override;
|
||||
QString chatListText(DrawInDialog way) const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextForMimeData clipboardText() const override;
|
||||
@@ -252,7 +255,7 @@ public:
|
||||
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
|
||||
|
||||
Data::CloudImage *location() const override;
|
||||
QString chatListText() const override;
|
||||
QString chatListText(DrawInDialog way) const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextForMimeData clipboardText() const override;
|
||||
@@ -320,7 +323,7 @@ public:
|
||||
bool hasReplyPreview() const override;
|
||||
Image *replyPreview() const override;
|
||||
bool replyPreviewLoaded() const override;
|
||||
QString chatListText() const override;
|
||||
QString chatListText(DrawInDialog way) const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextForMimeData clipboardText() const override;
|
||||
|
||||
@@ -1005,7 +1005,7 @@ PeerId PeerData::groupCallDefaultJoinAs() const {
|
||||
}
|
||||
|
||||
void PeerData::setThemeEmoji(const QString &emoji) {
|
||||
if (_themeEmoji == emoji) {
|
||||
if (true || _themeEmoji == emoji) {
|
||||
return;
|
||||
}
|
||||
_themeEmoji = emoji;
|
||||
|
||||
@@ -4054,10 +4054,18 @@ void Session::setWallpapers(const QVector<MTPWallPaper> &data, int32 hash) {
|
||||
ranges::rotate(begin(_wallpapers), legacy2, legacy2 + 1);
|
||||
}
|
||||
|
||||
// Put the legacy3 (static gradient) wallpaper to the front of the list.
|
||||
const auto legacy3 = ranges::find_if(
|
||||
_wallpapers,
|
||||
Data::IsLegacy3DefaultWallPaper);
|
||||
if (legacy3 != end(_wallpapers)) {
|
||||
ranges::rotate(begin(_wallpapers), legacy3, legacy3 + 1);
|
||||
}
|
||||
|
||||
if (ranges::none_of(_wallpapers, Data::IsDefaultWallPaper)) {
|
||||
_wallpapers.push_back(Data::DefaultWallPaper());
|
||||
_wallpapers.back().setLocalImageAsThumbnail(std::make_shared<Image>(
|
||||
u":/gui/art/background.jpg"_q));
|
||||
u":/gui/art/bg_thumbnail.png"_q));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/data_types.h"
|
||||
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "storage/cache/storage_cache_types.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
@@ -90,30 +87,6 @@ Storage::Cache::Key GeoPointCacheKey(const GeoPointLocation &location) {
|
||||
|
||||
} // namespace Data
|
||||
|
||||
uint32 AudioMsgId::CreateExternalPlayId() {
|
||||
static auto Result = uint32(0);
|
||||
return ++Result ? Result : ++Result;
|
||||
}
|
||||
|
||||
AudioMsgId AudioMsgId::ForVideo() {
|
||||
auto result = AudioMsgId();
|
||||
result._externalPlayId = CreateExternalPlayId();
|
||||
result._type = Type::Video;
|
||||
return result;
|
||||
}
|
||||
|
||||
void AudioMsgId::setTypeFromAudio() {
|
||||
if (_audio->isVoiceMessage() || _audio->isVideoMessage()) {
|
||||
_type = Type::Voice;
|
||||
} else if (_audio->isVideoFile()) {
|
||||
_type = Type::Video;
|
||||
} else if (_audio->isAudioFile()) {
|
||||
_type = Type::Song;
|
||||
} else {
|
||||
_type = Type::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageCursor::fillFrom(not_null<const Ui::InputField*> field) {
|
||||
const auto cursor = field->textCursor();
|
||||
position = cursor.position();
|
||||
|
||||
@@ -28,10 +28,6 @@ namespace Ui {
|
||||
class InputField;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Images {
|
||||
enum class Option;
|
||||
using Options = base::flags<Option>;
|
||||
@@ -192,8 +188,6 @@ struct WebPageData;
|
||||
struct GameData;
|
||||
struct PollData;
|
||||
|
||||
class AudioMsgId;
|
||||
|
||||
using PhotoId = uint64;
|
||||
using VideoId = uint64;
|
||||
using AudioId = uint64;
|
||||
@@ -246,78 +240,6 @@ inline constexpr auto kStickerSideSize = 512;
|
||||
|
||||
using MediaKey = QPair<uint64, uint64>;
|
||||
|
||||
class AudioMsgId {
|
||||
public:
|
||||
enum class Type {
|
||||
Unknown,
|
||||
Voice,
|
||||
Song,
|
||||
Video,
|
||||
};
|
||||
|
||||
AudioMsgId() = default;
|
||||
AudioMsgId(
|
||||
not_null<DocumentData*> audio,
|
||||
FullMsgId msgId,
|
||||
uint32 externalPlayId = 0)
|
||||
: _audio(audio)
|
||||
, _contextId(msgId)
|
||||
, _externalPlayId(externalPlayId) {
|
||||
setTypeFromAudio();
|
||||
}
|
||||
|
||||
[[nodiscard]] static uint32 CreateExternalPlayId();
|
||||
[[nodiscard]] static AudioMsgId ForVideo();
|
||||
|
||||
[[nodiscard]] Type type() const {
|
||||
return _type;
|
||||
}
|
||||
[[nodiscard]] DocumentData *audio() const {
|
||||
return _audio;
|
||||
}
|
||||
[[nodiscard]] FullMsgId contextId() const {
|
||||
return _contextId;
|
||||
}
|
||||
[[nodiscard]] uint32 externalPlayId() const {
|
||||
return _externalPlayId;
|
||||
}
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return (_audio != nullptr) || (_externalPlayId != 0);
|
||||
}
|
||||
|
||||
private:
|
||||
void setTypeFromAudio();
|
||||
|
||||
DocumentData *_audio = nullptr;
|
||||
Type _type = Type::Unknown;
|
||||
FullMsgId _contextId;
|
||||
uint32 _externalPlayId = 0;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator<(const AudioMsgId &a, const AudioMsgId &b) {
|
||||
if (quintptr(a.audio()) < quintptr(b.audio())) {
|
||||
return true;
|
||||
} else if (quintptr(b.audio()) < quintptr(a.audio())) {
|
||||
return false;
|
||||
} else if (a.contextId() < b.contextId()) {
|
||||
return true;
|
||||
} else if (b.contextId() < a.contextId()) {
|
||||
return false;
|
||||
}
|
||||
return (a.externalPlayId() < b.externalPlayId());
|
||||
}
|
||||
|
||||
inline bool operator==(const AudioMsgId &a, const AudioMsgId &b) {
|
||||
return (a.audio() == b.audio())
|
||||
&& (a.contextId() == b.contextId())
|
||||
&& (a.externalPlayId() == b.externalPlayId());
|
||||
}
|
||||
|
||||
inline bool operator!=(const AudioMsgId &a, const AudioMsgId &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
struct MessageCursor {
|
||||
MessageCursor() = default;
|
||||
MessageCursor(int position, int anchor, int scroll)
|
||||
|
||||
@@ -30,7 +30,9 @@ constexpr auto kThemeBackground = FromLegacyBackgroundId(-2);
|
||||
constexpr auto kCustomBackground = FromLegacyBackgroundId(-1);
|
||||
constexpr auto kLegacy1DefaultBackground = FromLegacyBackgroundId(0);
|
||||
constexpr auto kLegacy2DefaultBackground = 5947530738516623361;
|
||||
constexpr auto kDefaultBackground = 5778236420632084488;
|
||||
constexpr auto kLegacy3DefaultBackground = 5778236420632084488;
|
||||
constexpr auto kLegacy4DefaultBackground = 5945087215657811969;
|
||||
constexpr auto kDefaultBackground = 5933856211186221059;
|
||||
constexpr auto kIncorrectDefaultBackground = FromLegacyBackgroundId(105);
|
||||
|
||||
constexpr auto kVersionTag = qint32(0x7FFFFFFF);
|
||||
@@ -388,13 +390,16 @@ WallPaper WallPaper::withBackgroundColors(std::vector<QColor> colors) const {
|
||||
WallPaper WallPaper::withParamsFrom(const WallPaper &other) const {
|
||||
auto result = *this;
|
||||
result._blurred = other._blurred;
|
||||
if (!other._backgroundColors.empty() || ColorsFromString(_slug).empty()) {
|
||||
if (!other._backgroundColors.empty()) {
|
||||
result._backgroundColors = other._backgroundColors;
|
||||
if (!ColorsFromString(_slug).empty()) {
|
||||
result._slug = StringFromColors(result._backgroundColors);
|
||||
}
|
||||
}
|
||||
result._intensity = other._intensity;
|
||||
if (other.isPattern()) {
|
||||
result._flags |= WallPaperFlag::Pattern;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -632,6 +637,19 @@ std::optional<WallPaper> WallPaper::FromColorsSlug(const QString &slug) {
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::ConstructDefault() {
|
||||
auto result = WallPaper(
|
||||
kDefaultBackground
|
||||
).withPatternIntensity(50).withBackgroundColors({
|
||||
QColor(219, 221, 187),
|
||||
QColor(107, 165, 135),
|
||||
QColor(213, 216, 141),
|
||||
QColor(136, 184, 132),
|
||||
});
|
||||
result._flags |= WallPaperFlag::Default | WallPaperFlag::Pattern;
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper ThemeWallPaper() {
|
||||
return WallPaper(kThemeBackground);
|
||||
}
|
||||
@@ -661,8 +679,16 @@ bool IsLegacy2DefaultWallPaper(const WallPaper &paper) {
|
||||
|| (paper.id() == kIncorrectDefaultBackground);
|
||||
}
|
||||
|
||||
bool IsLegacy3DefaultWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kLegacy3DefaultBackground);
|
||||
}
|
||||
|
||||
bool IsLegacy4DefaultWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kLegacy4DefaultBackground);
|
||||
}
|
||||
|
||||
WallPaper DefaultWallPaper() {
|
||||
return WallPaper(kDefaultBackground);
|
||||
return WallPaper::ConstructDefault();
|
||||
}
|
||||
|
||||
bool IsDefaultWallPaper(const WallPaper &paper) {
|
||||
@@ -728,7 +754,9 @@ bool IsTestingThemeWallPaper(const WallPaper &paper) {
|
||||
}
|
||||
|
||||
WallPaper TestingDefaultWallPaper() {
|
||||
return WallPaper(kTestingDefaultBackground);
|
||||
return WallPaper(
|
||||
kTestingDefaultBackground
|
||||
).withParamsFrom(DefaultWallPaper());
|
||||
}
|
||||
|
||||
bool IsTestingDefaultWallPaper(const WallPaper &paper) {
|
||||
|
||||
@@ -90,6 +90,7 @@ public:
|
||||
qint32 legacyId);
|
||||
[[nodiscard]] static std::optional<WallPaper> FromColorsSlug(
|
||||
const QString &slug);
|
||||
[[nodiscard]] static WallPaper ConstructDefault();
|
||||
|
||||
private:
|
||||
static constexpr auto kDefaultIntensity = 50;
|
||||
@@ -117,6 +118,8 @@ private:
|
||||
[[nodiscard]] WallPaper Legacy1DefaultWallPaper();
|
||||
[[nodiscard]] bool IsLegacy1DefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] bool IsLegacy2DefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] bool IsLegacy3DefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] bool IsLegacy4DefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper DefaultWallPaper();
|
||||
[[nodiscard]] bool IsDefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] bool IsCloudWallPaper(const WallPaper &paper);
|
||||
|
||||
@@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
class History;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
@@ -271,8 +271,10 @@ void FilterBox::Inner::createActionsCheckboxes(const FilterValue &filter) {
|
||||
addFlag(Flag::f_edit, tr::lng_admin_log_filter_messages_edited(tr::now));
|
||||
if (isGroup) {
|
||||
addFlag(Flag::f_pinned, tr::lng_admin_log_filter_messages_pinned(tr::now));
|
||||
addFlag(Flag::f_group_call, tr::lng_admin_log_filter_voice_chats(tr::now));
|
||||
} else {
|
||||
addFlag(Flag::f_group_call, tr::lng_admin_log_filter_voice_chats_channel(tr::now));
|
||||
}
|
||||
addFlag(Flag::f_group_call, tr::lng_admin_log_filter_voice_chats(tr::now));
|
||||
addFlag(Flag::f_invites, tr::lng_admin_log_filter_invite_links(tr::now));
|
||||
addFlag(Flag::f_leave, tr::lng_admin_log_filter_members_removed(tr::now));
|
||||
}
|
||||
|
||||
@@ -165,10 +165,14 @@ TextWithEntities GenerateAdminChangeText(
|
||||
|
||||
auto result = tr::lng_admin_log_promoted(tr::now, lt_user, user, Ui::Text::WithEntities);
|
||||
|
||||
auto useInviteLinkPhrase = channel->isMegagroup() && channel->anyoneCanAddMembers();
|
||||
auto invitePhrase = useInviteLinkPhrase
|
||||
const auto useInviteLinkPhrase = channel->isMegagroup()
|
||||
&& channel->anyoneCanAddMembers();
|
||||
const auto invitePhrase = useInviteLinkPhrase
|
||||
? tr::lng_admin_log_admin_invite_link
|
||||
: tr::lng_admin_log_admin_invite_users;
|
||||
const auto callPhrase = channel->isBroadcast()
|
||||
? tr::lng_admin_log_admin_manage_calls_channel
|
||||
: tr::lng_admin_log_admin_manage_calls;
|
||||
static auto phraseMap = std::map<Flags, tr::phrase<>> {
|
||||
{ Flag::ChangeInfo, tr::lng_admin_log_admin_change_info },
|
||||
{ Flag::PostMessages, tr::lng_admin_log_admin_post_messages },
|
||||
@@ -181,6 +185,7 @@ TextWithEntities GenerateAdminChangeText(
|
||||
{ Flag::AddAdmins, tr::lng_admin_log_admin_add_admins },
|
||||
};
|
||||
phraseMap[Flag::InviteUsers] = invitePhrase;
|
||||
phraseMap[Flag::ManageCall] = callPhrase;
|
||||
|
||||
if (!channel->isMegagroup()) {
|
||||
// Don't display "Ban users" changes in channels.
|
||||
@@ -502,6 +507,7 @@ void GenerateItems(
|
||||
const auto id = event.vid().v;
|
||||
const auto from = history->owner().user(event.vuser_id().v);
|
||||
const auto channel = history->peer->asChannel();
|
||||
const auto broadcast = channel->isBroadcast();
|
||||
const auto &action = event.vaction();
|
||||
const auto date = event.vdate().v;
|
||||
const auto addPart = [&](
|
||||
@@ -825,7 +831,6 @@ void GenerateItems(
|
||||
};
|
||||
|
||||
auto createChangeLinkedChat = [&](const MTPDchannelAdminLogEventActionChangeLinkedChat &action) {
|
||||
const auto broadcast = channel->isBroadcast();
|
||||
const auto now = history->owner().channelLoaded(action.vnew_value().v);
|
||||
if (!now) {
|
||||
auto text = (broadcast
|
||||
@@ -901,12 +906,16 @@ void GenerateItems(
|
||||
};
|
||||
|
||||
auto createStartGroupCall = [&](const MTPDchannelAdminLogEventActionStartGroupCall &data) {
|
||||
const auto text = tr::lng_admin_log_started_group_call(tr::now, lt_from, fromLinkText);
|
||||
const auto text = (broadcast
|
||||
? tr::lng_admin_log_started_group_call_channel
|
||||
: tr::lng_admin_log_started_group_call)(tr::now, lt_from, fromLinkText);
|
||||
addSimpleServiceMessage(text);
|
||||
};
|
||||
|
||||
auto createDiscardGroupCall = [&](const MTPDchannelAdminLogEventActionDiscardGroupCall &data) {
|
||||
const auto text = tr::lng_admin_log_discarded_group_call(tr::now, lt_from, fromLinkText);
|
||||
const auto text = (broadcast
|
||||
? tr::lng_admin_log_discarded_group_call_channel
|
||||
: tr::lng_admin_log_discarded_group_call)(tr::now, lt_from, fromLinkText);
|
||||
addSimpleServiceMessage(text);
|
||||
};
|
||||
|
||||
@@ -932,7 +941,9 @@ void GenerateItems(
|
||||
const auto participantPeer = groupCallParticipantPeer(data.vparticipant());
|
||||
const auto participantPeerLink = participantPeer->createOpenLink();
|
||||
const auto participantPeerLinkText = textcmdLink(2, participantPeer->name);
|
||||
auto text = tr::lng_admin_log_muted_participant(
|
||||
auto text = (broadcast
|
||||
? tr::lng_admin_log_muted_participant_channel
|
||||
: tr::lng_admin_log_muted_participant)(
|
||||
tr::now,
|
||||
lt_from,
|
||||
fromLinkText,
|
||||
@@ -945,7 +956,9 @@ void GenerateItems(
|
||||
const auto participantPeer = groupCallParticipantPeer(data.vparticipant());
|
||||
const auto participantPeerLink = participantPeer->createOpenLink();
|
||||
const auto participantPeerLinkText = textcmdLink(2, participantPeer->name);
|
||||
auto text = tr::lng_admin_log_unmuted_participant(
|
||||
auto text = (broadcast
|
||||
? tr::lng_admin_log_unmuted_participant_channel
|
||||
: tr::lng_admin_log_unmuted_participant)(
|
||||
tr::now,
|
||||
lt_from,
|
||||
fromLinkText,
|
||||
@@ -955,9 +968,13 @@ void GenerateItems(
|
||||
};
|
||||
|
||||
auto createToggleGroupCallSetting = [&](const MTPDchannelAdminLogEventActionToggleGroupCallSetting &data) {
|
||||
const auto text = mtpIsTrue(data.vjoin_muted())
|
||||
? tr::lng_admin_log_disallowed_unmute_self(tr::now, lt_from, fromLinkText)
|
||||
: tr::lng_admin_log_allowed_unmute_self(tr::now, lt_from, fromLinkText);
|
||||
const auto text = (mtpIsTrue(data.vjoin_muted())
|
||||
? (broadcast
|
||||
? tr::lng_admin_log_disallowed_unmute_self_channel
|
||||
: tr::lng_admin_log_disallowed_unmute_self)
|
||||
: (broadcast
|
||||
? tr::lng_admin_log_allowed_unmute_self_channel
|
||||
: tr::lng_admin_log_allowed_unmute_self))(tr::now, lt_from, fromLinkText);
|
||||
addSimpleServiceMessage(text);
|
||||
};
|
||||
|
||||
@@ -1026,7 +1043,9 @@ void GenerateItems(
|
||||
return data.vvolume().value_or(10000);
|
||||
});
|
||||
const auto volumeText = QString::number(volume / 100) + '%';
|
||||
auto text = tr::lng_admin_log_participant_volume(
|
||||
auto text = (broadcast
|
||||
? tr::lng_admin_log_participant_volume_channel
|
||||
: tr::lng_admin_log_participant_volume)(
|
||||
tr::now,
|
||||
lt_from,
|
||||
fromLinkText,
|
||||
|
||||
@@ -336,16 +336,27 @@ void History::draftSavedToCloud() {
|
||||
session().local().writeDrafts(this);
|
||||
}
|
||||
|
||||
HistoryItemsList History::validateForwardDraft() {
|
||||
auto result = owner().idsToItems(_forwardDraft);
|
||||
if (result.size() != _forwardDraft.size()) {
|
||||
setForwardDraft(owner().itemsToIds(result));
|
||||
Data::ResolvedForwardDraft History::resolveForwardDraft(
|
||||
const Data::ForwardDraft &draft) const {
|
||||
return Data::ResolvedForwardDraft{
|
||||
.items = owner().idsToItems(draft.ids),
|
||||
.options = draft.options,
|
||||
};
|
||||
}
|
||||
|
||||
Data::ResolvedForwardDraft History::resolveForwardDraft() {
|
||||
auto result = resolveForwardDraft(_forwardDraft);
|
||||
if (result.items.size() != _forwardDraft.ids.size()) {
|
||||
setForwardDraft({
|
||||
.ids = owner().itemsToIds(result.items),
|
||||
.options = result.options,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void History::setForwardDraft(MessageIdsList &&items) {
|
||||
_forwardDraft = std::move(items);
|
||||
void History::setForwardDraft(Data::ForwardDraft &&draft) {
|
||||
_forwardDraft = std::move(draft);
|
||||
}
|
||||
|
||||
HistoryItem *History::createItem(
|
||||
|
||||
@@ -33,6 +33,23 @@ struct Draft;
|
||||
class Session;
|
||||
class Folder;
|
||||
class ChatFilter;
|
||||
|
||||
enum class ForwardOptions {
|
||||
PreserveInfo,
|
||||
NoSenderNames,
|
||||
NoNamesAndCaptions,
|
||||
};
|
||||
|
||||
struct ForwardDraft {
|
||||
MessageIdsList ids;
|
||||
ForwardOptions options = ForwardOptions::PreserveInfo;
|
||||
};
|
||||
|
||||
struct ResolvedForwardDraft {
|
||||
HistoryItemsList items;
|
||||
ForwardOptions options = ForwardOptions::PreserveInfo;
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
|
||||
namespace Dialogs {
|
||||
@@ -354,11 +371,13 @@ public:
|
||||
void applyCloudDraft();
|
||||
void draftSavedToCloud();
|
||||
|
||||
const MessageIdsList &forwardDraft() const {
|
||||
[[nodiscard]] const Data::ForwardDraft &forwardDraft() const {
|
||||
return _forwardDraft;
|
||||
}
|
||||
HistoryItemsList validateForwardDraft();
|
||||
void setForwardDraft(MessageIdsList &&items);
|
||||
[[nodiscard]] Data::ResolvedForwardDraft resolveForwardDraft(
|
||||
const Data::ForwardDraft &draft) const;
|
||||
[[nodiscard]] Data::ResolvedForwardDraft resolveForwardDraft();
|
||||
void setForwardDraft(Data::ForwardDraft &&draft);
|
||||
|
||||
History *migrateSibling() const;
|
||||
[[nodiscard]] bool useTopPromotion() const;
|
||||
@@ -598,7 +617,7 @@ private:
|
||||
Data::HistoryDrafts _drafts;
|
||||
TimeId _acceptCloudDraftsAfter = 0;
|
||||
int _savingCloudDraftRequests = 0;
|
||||
MessageIdsList _forwardDraft;
|
||||
Data::ForwardDraft _forwardDraft;
|
||||
|
||||
QString _topPromotedMessage;
|
||||
QString _topPromotedType;
|
||||
|
||||
@@ -936,20 +936,19 @@ QString HistoryItem::notificationText() const {
|
||||
}
|
||||
|
||||
QString HistoryItem::inDialogsText(DrawInDialog way) const {
|
||||
auto getText = [this]() {
|
||||
const auto plainText = [&] {
|
||||
if (_media) {
|
||||
if (_groupId) {
|
||||
return textcmdLink(1, TextUtilities::Clean(tr::lng_in_dlg_album(tr::now)));
|
||||
}
|
||||
return _media->chatListText();
|
||||
return _media->chatListText(way);
|
||||
} else if (!emptyText()) {
|
||||
return TextUtilities::Clean(_text.toString());
|
||||
}
|
||||
return QString();
|
||||
};
|
||||
const auto plainText = getText();
|
||||
}();
|
||||
const auto sender = [&]() -> PeerData* {
|
||||
if (isPost() || isEmpty() || (way == DrawInDialog::WithoutSender)) {
|
||||
if (isPost() || isEmpty() || (way != DrawInDialog::Normal)) {
|
||||
return nullptr;
|
||||
} else if (!_history->peer->isUser() || out()) {
|
||||
return displayFrom();
|
||||
|
||||
@@ -52,6 +52,11 @@ enum class CursorState : char;
|
||||
enum class PointState : char;
|
||||
enum class Context : char;
|
||||
class ElementDelegate;
|
||||
enum class DrawInDialog {
|
||||
Normal,
|
||||
WithoutSender,
|
||||
WithoutSenderAndCaption,
|
||||
};
|
||||
} // namespace HistoryView
|
||||
|
||||
struct HiddenSenderInfo;
|
||||
@@ -291,10 +296,7 @@ public:
|
||||
}
|
||||
[[nodiscard]] virtual QString notificationText() const;
|
||||
|
||||
enum class DrawInDialog {
|
||||
Normal,
|
||||
WithoutSender,
|
||||
};
|
||||
using DrawInDialog = HistoryView::DrawInDialog;
|
||||
|
||||
// Returns text with link-start and link-end commands for service-color highlighting.
|
||||
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
|
||||
|
||||
@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/chat/forward_options_box.h"
|
||||
#include "ui/chat/message_bar.h"
|
||||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
#include "ui/image/image.h"
|
||||
@@ -359,6 +360,18 @@ HistoryWidget::HistoryWidget(
|
||||
: _keyboard->moderateKeyActivate(key);
|
||||
});
|
||||
|
||||
_fieldAutocomplete->choosingProcesses(
|
||||
) | rpl::start_with_next([=](FieldAutocomplete::Type type) {
|
||||
if (!_history) {
|
||||
return;
|
||||
}
|
||||
if (type == FieldAutocomplete::Type::Stickers) {
|
||||
session().sendProgressManager().update(
|
||||
_history,
|
||||
Api::SendProgressType::ChooseSticker);
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
_fieldAutocomplete->setSendMenuType([=] { return sendMenuType(); });
|
||||
|
||||
if (_supportAutocomplete) {
|
||||
@@ -3285,7 +3298,7 @@ void HistoryWidget::send(Api::SendOptions options) {
|
||||
if (_canSendMessages) {
|
||||
const auto error = GetErrorTextForSending(
|
||||
_peer,
|
||||
_toForward,
|
||||
_toForward.items,
|
||||
message.textWithTags,
|
||||
options.scheduled);
|
||||
if (!error.isEmpty()) {
|
||||
@@ -3819,7 +3832,7 @@ QRect HistoryWidget::floatPlayerAvailableRect() {
|
||||
}
|
||||
|
||||
bool HistoryWidget::readyToForward() const {
|
||||
return _canSendMessages && !_toForward.empty();
|
||||
return _canSendMessages && !_toForward.items.empty();
|
||||
}
|
||||
|
||||
bool HistoryWidget::hasSilentToggle() const {
|
||||
@@ -4741,11 +4754,11 @@ void HistoryWidget::itemRemoved(not_null<const HistoryItem*> item) {
|
||||
toggleKeyboard();
|
||||
_kbReplyTo = nullptr;
|
||||
}
|
||||
auto found = ranges::find(_toForward, item);
|
||||
if (found != _toForward.end()) {
|
||||
_toForward.erase(found);
|
||||
auto found = ranges::find(_toForward.items, item);
|
||||
if (found != _toForward.items.end()) {
|
||||
_toForward.items.erase(found);
|
||||
updateForwardingTexts();
|
||||
if (_toForward.empty()) {
|
||||
if (_toForward.items.empty()) {
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
}
|
||||
@@ -5005,6 +5018,8 @@ void HistoryWidget::startItemRevealAnimations() {
|
||||
}
|
||||
|
||||
void HistoryWidget::updateListSize() {
|
||||
Expects(_list != nullptr);
|
||||
|
||||
_list->recountHistoryGeometry();
|
||||
auto washidden = _scroll->isHidden();
|
||||
if (washidden) {
|
||||
@@ -5020,6 +5035,16 @@ void HistoryWidget::updateListSize() {
|
||||
}
|
||||
|
||||
bool HistoryWidget::hasPendingResizedItems() const {
|
||||
if (!_list) {
|
||||
// Based on the crash reports there is a codepath (at least on macOS)
|
||||
// that leads from _list = _scroll->setOwnedWidget(...) right into
|
||||
// the HistoryWidget::paintEvent (by sending fake mouse move events
|
||||
// inside scroll area -> hiding tooltip window -> exposing the main
|
||||
// window -> syncing it backing store synchronously).
|
||||
//
|
||||
// So really we could get here with !_list && (_history != nullptr).
|
||||
return false;
|
||||
}
|
||||
return (_history && _history->hasPendingResizedItems())
|
||||
|| (_migrated && _migrated->hasPendingResizedItems());
|
||||
}
|
||||
@@ -5316,14 +5341,63 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||
updateField();
|
||||
} else if (_inReplyEditForward) {
|
||||
if (readyToForward()) {
|
||||
const auto items = std::move(_toForward);
|
||||
session().data().cancelForwarding(_history);
|
||||
auto list = ranges::views::all(
|
||||
items
|
||||
) | ranges::views::transform(
|
||||
&HistoryItem::fullId
|
||||
) | ranges::to_vector;
|
||||
Window::ShowForwardMessagesBox(controller(), std::move(list));
|
||||
using Options = Data::ForwardOptions;
|
||||
const auto now = _toForward.options;
|
||||
const auto count = _toForward.items.size();
|
||||
const auto dropNames = (now != Options::PreserveInfo);
|
||||
const auto hasCaptions = [&] {
|
||||
for (const auto item : _toForward.items) {
|
||||
if (const auto media = item->media()) {
|
||||
if (!item->originalText().text.isEmpty()
|
||||
&& (media->photo() || media->document())
|
||||
&& !media->webpage()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
const auto dropCaptions = (now == Options::NoNamesAndCaptions);
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto changeRecipient = crl::guard(weak, [=] {
|
||||
if (_toForward.items.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto draft = std::move(_toForward);
|
||||
session().data().cancelForwarding(_history);
|
||||
auto list = session().data().itemsToIds(draft.items);
|
||||
Window::ShowForwardMessagesBox(controller(), {
|
||||
.ids = session().data().itemsToIds(draft.items),
|
||||
.options = draft.options,
|
||||
});
|
||||
});
|
||||
const auto optionsChanged = crl::guard(weak, [=](
|
||||
Ui::ForwardOptions options) {
|
||||
const auto newOptions = (options.hasCaptions
|
||||
&& options.dropCaptions)
|
||||
? Options::NoNamesAndCaptions
|
||||
: options.dropNames
|
||||
? Options::NoSenderNames
|
||||
: Options::PreserveInfo;
|
||||
if (_history && _toForward.options != newOptions) {
|
||||
_toForward.options = newOptions;
|
||||
_history->setForwardDraft({
|
||||
.ids = session().data().itemsToIds(_toForward.items),
|
||||
.options = newOptions,
|
||||
});
|
||||
updateField();
|
||||
}
|
||||
});
|
||||
controller()->show(Box(
|
||||
Ui::ForwardOptionsBox,
|
||||
count,
|
||||
Ui::ForwardOptions{
|
||||
.dropNames = dropNames,
|
||||
.hasCaptions = hasCaptions,
|
||||
.dropCaptions = dropCaptions,
|
||||
},
|
||||
optionsChanged,
|
||||
changeRecipient));
|
||||
} else {
|
||||
Ui::showPeerHistory(_peer, _editMsgId ? _editMsgId : replyToId());
|
||||
}
|
||||
@@ -5964,7 +6038,7 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
||||
crl::guard(this, [=] {
|
||||
controller()->content()->setForwardDraft(
|
||||
_peer->id,
|
||||
{ 1, itemId });
|
||||
{ .ids = { 1, itemId } });
|
||||
})));
|
||||
}
|
||||
return;
|
||||
@@ -6617,10 +6691,10 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
|
||||
|
||||
void HistoryWidget::updateForwarding() {
|
||||
if (_history) {
|
||||
_toForward = _history->validateForwardDraft();
|
||||
_toForward = _history->resolveForwardDraft();
|
||||
updateForwardingTexts();
|
||||
} else {
|
||||
_toForward.clear();
|
||||
_toForward = {};
|
||||
}
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
@@ -6629,13 +6703,17 @@ void HistoryWidget::updateForwarding() {
|
||||
void HistoryWidget::updateForwardingTexts() {
|
||||
int32 version = 0;
|
||||
QString from, text;
|
||||
if (const auto count = int(_toForward.size())) {
|
||||
const auto keepNames = (_toForward.options
|
||||
== Data::ForwardOptions::PreserveInfo);
|
||||
const auto keepCaptions = (_toForward.options
|
||||
!= Data::ForwardOptions::NoNamesAndCaptions);
|
||||
if (const auto count = int(_toForward.items.size())) {
|
||||
auto insertedPeers = base::flat_set<not_null<PeerData*>>();
|
||||
auto insertedNames = base::flat_set<QString>();
|
||||
auto fullname = QString();
|
||||
auto names = std::vector<QString>();
|
||||
names.reserve(_toForward.size());
|
||||
for (const auto item : _toForward) {
|
||||
names.reserve(_toForward.items.size());
|
||||
for (const auto item : _toForward.items) {
|
||||
if (const auto from = item->senderOriginal()) {
|
||||
if (!insertedPeers.contains(from)) {
|
||||
insertedPeers.emplace(from);
|
||||
@@ -6654,7 +6732,9 @@ void HistoryWidget::updateForwardingTexts() {
|
||||
Unexpected("Corrupt forwarded information in message.");
|
||||
}
|
||||
}
|
||||
if (names.size() > 2) {
|
||||
if (!keepNames) {
|
||||
from = tr::lng_forward_sender_names_removed(tr::now);
|
||||
} else if (names.size() > 2) {
|
||||
from = tr::lng_forwarding_from(tr::now, lt_count, names.size() - 1, lt_user, names[0]);
|
||||
} else if (names.size() < 2) {
|
||||
from = fullname;
|
||||
@@ -6663,7 +6743,9 @@ void HistoryWidget::updateForwardingTexts() {
|
||||
}
|
||||
|
||||
if (count < 2) {
|
||||
text = _toForward.front()->inReplyText();
|
||||
text = _toForward.items.front()->inDialogsText(keepCaptions
|
||||
? HistoryItem::DrawInDialog::WithoutSender
|
||||
: HistoryItem::DrawInDialog::WithoutSenderAndCaption);
|
||||
} else {
|
||||
text = textcmdLink(1, tr::lng_forward_messages(tr::now, lt_count, count));
|
||||
}
|
||||
@@ -6673,19 +6755,25 @@ void HistoryWidget::updateForwardingTexts() {
|
||||
st::messageTextStyle,
|
||||
text,
|
||||
Ui::DialogTextOptions());
|
||||
_toForwardNameVersion = version;
|
||||
_toForwardNameVersion = keepNames ? version : keepCaptions ? -1 : -2;
|
||||
}
|
||||
|
||||
void HistoryWidget::checkForwardingInfo() {
|
||||
if (!_toForward.empty()) {
|
||||
auto version = 0;
|
||||
for (const auto item : _toForward) {
|
||||
if (const auto from = item->senderOriginal()) {
|
||||
version += from->nameVersion;
|
||||
} else if (const auto info = item->hiddenForwardedInfo()) {
|
||||
++version;
|
||||
} else {
|
||||
Unexpected("Corrupt forwarded information in message.");
|
||||
if (!_toForward.items.empty()) {
|
||||
const auto keepNames = (_toForward.options
|
||||
== Data::ForwardOptions::PreserveInfo);
|
||||
const auto keepCaptions = (_toForward.options
|
||||
!= Data::ForwardOptions::NoNamesAndCaptions);
|
||||
auto version = keepNames ? 0 : keepCaptions ? -1 : -2;
|
||||
if (keepNames) {
|
||||
for (const auto item : _toForward.items) {
|
||||
if (const auto from = item->senderOriginal()) {
|
||||
version += from->nameVersion;
|
||||
} else if (const auto info = item->hiddenForwardedInfo()) {
|
||||
++version;
|
||||
} else {
|
||||
Unexpected("Corrupt forwarded information in message.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (version != _toForwardNameVersion) {
|
||||
@@ -6772,9 +6860,9 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||
auto forwardLeft = st::historyReplySkip;
|
||||
st::historyForwardIcon.paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
||||
if (!drawWebPagePreview) {
|
||||
const auto firstItem = _toForward.front();
|
||||
const auto firstItem = _toForward.items.front();
|
||||
const auto firstMedia = firstItem->media();
|
||||
const auto preview = (_toForward.size() < 2 && firstMedia && firstMedia->hasReplyPreview())
|
||||
const auto preview = (_toForward.items.size() < 2 && firstMedia && firstMedia->hasReplyPreview())
|
||||
? firstMedia->replyPreview()
|
||||
: nullptr;
|
||||
if (preview) {
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
#include "mainwidget.h"
|
||||
#include "chat_helpers/bot_command.h"
|
||||
@@ -607,7 +608,7 @@ private:
|
||||
Ui::Text::String _replyToName;
|
||||
int _replyToNameVersion = 0;
|
||||
|
||||
HistoryItemsList _toForward;
|
||||
Data::ResolvedForwardDraft _toForward;
|
||||
Ui::Text::String _toForwardFrom, _toForwardText;
|
||||
int _toForwardNameVersion = 0;
|
||||
|
||||
|
||||
@@ -1236,6 +1236,15 @@ void ComposeControls::initAutocomplete() {
|
||||
});
|
||||
}, _autocomplete->lifetime());
|
||||
|
||||
_autocomplete->choosingProcesses(
|
||||
) | rpl::start_with_next([=](FieldAutocomplete::Type type) {
|
||||
if (type == FieldAutocomplete::Type::Stickers) {
|
||||
_sendActionUpdates.fire({
|
||||
.type = Api::SendProgressType::ChooseSticker,
|
||||
});
|
||||
}
|
||||
}, _autocomplete->lifetime());
|
||||
|
||||
_autocomplete->setSendMenuType([=] { return sendMenuType(); });
|
||||
|
||||
//_autocomplete->setModerateKeyActivateCallback([=](int key) {
|
||||
|
||||
@@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "base/unique_qptr.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
enum class ReportReason;
|
||||
|
||||
@@ -248,6 +248,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
||||
auto lifetime = rpl::lifetime();
|
||||
auto state = lifetime.make_state<State>();
|
||||
state->current.shown = true;
|
||||
state->current.livestream = call->peer()->isBroadcast();
|
||||
|
||||
const auto pushNext = [=] {
|
||||
if (state->scheduled) {
|
||||
|
||||
@@ -221,6 +221,7 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
|
||||
const auto wasSpeakingAnimation = !!_speakingAnimation;
|
||||
if (force || sendActionChanged || speakingChanged) {
|
||||
QString newTypingString;
|
||||
auto animationLeft = 0;
|
||||
auto typingCount = _typing.size();
|
||||
if (typingCount > 2) {
|
||||
newTypingString = tr::lng_many_typing(tr::now, lt_count, typingCount);
|
||||
@@ -295,7 +296,7 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
|
||||
const auto index = newTypingString.size()
|
||||
- lang.rightIndexChoosingStickerReplacement(
|
||||
isNamed);
|
||||
_animationLeft = _st.font->width(
|
||||
animationLeft = _st.font->width(
|
||||
newTypingString,
|
||||
0,
|
||||
index);
|
||||
@@ -310,8 +311,6 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
|
||||
Lang::kChoosingStickerReplacement.utf8().size(),
|
||||
QString().fill(' ', _spacesCount).constData(),
|
||||
_spacesCount);
|
||||
} else {
|
||||
_animationLeft = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -356,6 +355,9 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
|
||||
_sendActionString,
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
if (_animationLeft != animationLeft) {
|
||||
_animationLeft = animationLeft;
|
||||
}
|
||||
if (_speaking.empty()) {
|
||||
_speakingAnimation.tryToFinish();
|
||||
} else {
|
||||
|
||||
@@ -741,6 +741,14 @@ void Instance::applyValue(const QByteArray &key, const QByteArray &value) {
|
||||
} else if (!_derived->_nonDefaultSet[key]) {
|
||||
_derived->_values[key] = std::move(value);
|
||||
}
|
||||
if (key == tr::lng_send_action_choose_sticker.base
|
||||
|| key == tr::lng_user_action_choose_sticker.base) {
|
||||
if (!_derived) {
|
||||
updateChoosingStickerReplacement();
|
||||
} else {
|
||||
_derived->updateChoosingStickerReplacement();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -771,6 +779,14 @@ void Instance::resetValue(const QByteArray &key) {
|
||||
} else if (!_derived->_nonDefaultSet[keyIndex]) {
|
||||
_derived->_values[keyIndex] = GetOriginalValue(keyIndex);
|
||||
}
|
||||
if (keyIndex == tr::lng_send_action_choose_sticker.base
|
||||
|| keyIndex == tr::lng_user_action_choose_sticker.base) {
|
||||
if (!_derived) {
|
||||
updateChoosingStickerReplacement();
|
||||
} else {
|
||||
_derived->updateChoosingStickerReplacement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -502,20 +502,20 @@ void MainWidget::floatPlayerDoubleClickEvent(
|
||||
_controller->showPeerHistoryAtItem(item);
|
||||
}
|
||||
|
||||
bool MainWidget::setForwardDraft(PeerId peerId, MessageIdsList &&items) {
|
||||
bool MainWidget::setForwardDraft(PeerId peerId, Data::ForwardDraft &&draft) {
|
||||
Expects(peerId != 0);
|
||||
|
||||
const auto peer = session().data().peer(peerId);
|
||||
const auto error = GetErrorTextForSending(
|
||||
peer,
|
||||
session().data().idsToItems(items),
|
||||
session().data().idsToItems(draft.ids),
|
||||
true);
|
||||
if (!error.isEmpty()) {
|
||||
Ui::show(Box<InformBox>(error), Ui::LayerOption::KeepOther);
|
||||
return false;
|
||||
}
|
||||
|
||||
peer->owner().history(peer)->setForwardDraft(std::move(items));
|
||||
peer->owner().history(peer)->setForwardDraft(std::move(draft));
|
||||
_controller->showPeerHistory(
|
||||
peer,
|
||||
SectionShow::Way::Forward,
|
||||
@@ -603,7 +603,10 @@ void MainWidget::onFilesOrForwardDrop(
|
||||
Expects(peerId != 0);
|
||||
|
||||
if (data->hasFormat(qsl("application/x-td-forward"))) {
|
||||
if (!setForwardDraft(peerId, session().data().takeMimeForwardIds())) {
|
||||
auto draft = Data::ForwardDraft{
|
||||
.ids = session().data().takeMimeForwardIds(),
|
||||
};
|
||||
if (!setForwardDraft(peerId, std::move(draft))) {
|
||||
// We've already released the mouse button, so the forwarding is cancelled.
|
||||
if (_hider) {
|
||||
_hider->startHide();
|
||||
@@ -704,9 +707,9 @@ void MainWidget::hiderLayer(base::unique_qptr<Window::HistoryHider> hider) {
|
||||
floatPlayerCheckVisibility();
|
||||
}
|
||||
|
||||
void MainWidget::showForwardLayer(MessageIdsList &&items) {
|
||||
auto callback = [=, items = std::move(items)](PeerId peer) mutable {
|
||||
return setForwardDraft(peer, std::move(items));
|
||||
void MainWidget::showForwardLayer(Data::ForwardDraft &&draft) {
|
||||
auto callback = [=, draft = std::move(draft)](PeerId peer) mutable {
|
||||
return setForwardDraft(peer, std::move(draft));
|
||||
};
|
||||
hiderLayer(base::make_unique_q<Window::HistoryHider>(
|
||||
this,
|
||||
|
||||
@@ -39,6 +39,7 @@ class Session;
|
||||
|
||||
namespace Data {
|
||||
class WallPaper;
|
||||
struct ForwardDraft;
|
||||
} // namespace Data
|
||||
|
||||
namespace Dialogs {
|
||||
@@ -159,12 +160,12 @@ public:
|
||||
|
||||
int32 dlgsWidth() const;
|
||||
|
||||
void showForwardLayer(MessageIdsList &&items);
|
||||
void showForwardLayer(Data::ForwardDraft &&draft);
|
||||
void showSendPathsLayer();
|
||||
void shareUrlLayer(const QString &url, const QString &text);
|
||||
void inlineSwitchLayer(const QString &botAndQuery);
|
||||
void hiderLayer(base::unique_qptr<Window::HistoryHider> h);
|
||||
bool setForwardDraft(PeerId peer, MessageIdsList &&items);
|
||||
bool setForwardDraft(PeerId peer, Data::ForwardDraft &&draft);
|
||||
bool shareUrl(
|
||||
PeerId peerId,
|
||||
const QString &url,
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/effects/animation_value.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "core/file_location.h"
|
||||
#include "data/data_audio_msg_id.h"
|
||||
#include "base/bytes.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ void Instance::Inner::start(Fn<void(Update)> updated, Fn<void()> error) {
|
||||
av_opt_set_int(d->codecContext, "refcounted_frames", 1, 0);
|
||||
|
||||
d->codecContext->sample_fmt = AV_SAMPLE_FMT_FLTP;
|
||||
d->codecContext->bit_rate = 64000;
|
||||
d->codecContext->bit_rate = 32000;
|
||||
d->codecContext->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
d->codecContext->sample_rate = kCaptureFrequency;
|
||||
d->codecContext->channels = 1;
|
||||
|
||||
@@ -36,8 +36,6 @@ namespace {
|
||||
|
||||
Instance *SingleInstance = nullptr;
|
||||
|
||||
constexpr auto kVoicePlaybackSpeedMultiplier = 1.7;
|
||||
|
||||
// Preload X message ids before and after current.
|
||||
constexpr auto kIdsLimit = 32;
|
||||
|
||||
@@ -46,6 +44,10 @@ constexpr auto kIdsPreloadAfter = 28;
|
||||
|
||||
constexpr auto kMinLengthForSavePosition = 20 * TimeId(60); // 20 minutes.
|
||||
|
||||
auto VoicePlaybackSpeed() {
|
||||
return std::clamp(Core::App().settings().voicePlaybackSpeed(), 0.6, 1.7);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct Instance::Streamed {
|
||||
@@ -517,10 +519,8 @@ Streaming::PlaybackOptions Instance::streamingOptions(
|
||||
result.mode = (document && document->isVideoMessage())
|
||||
? Streaming::Mode::Both
|
||||
: Streaming::Mode::Audio;
|
||||
result.speed = (document
|
||||
&& (document->isVoiceMessage() || document->isVideoMessage())
|
||||
&& Core::App().settings().voiceMsgPlaybackDoubled())
|
||||
? kVoicePlaybackSpeedMultiplier
|
||||
result.speed = audioId.changeablePlaybackSpeed()
|
||||
? VoicePlaybackSpeed()
|
||||
: 1.;
|
||||
result.audioId = audioId;
|
||||
if (position >= 0) {
|
||||
@@ -676,11 +676,12 @@ void Instance::cancelSeeking(AudioMsgId::Type type) {
|
||||
}
|
||||
|
||||
void Instance::updateVoicePlaybackSpeed() {
|
||||
if (const auto data = getData(AudioMsgId::Type::Voice)) {
|
||||
if (const auto data = getData(getActiveType())) {
|
||||
if (!data->current.changeablePlaybackSpeed()) {
|
||||
return;
|
||||
}
|
||||
if (const auto streamed = data->streamed.get()) {
|
||||
streamed->instance.setSpeed(Core::App().settings().voiceMsgPlaybackDoubled()
|
||||
? kVoicePlaybackSpeedMultiplier
|
||||
: 1.);
|
||||
streamed->instance.setSpeed(VoicePlaybackSpeed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_audio_msg_id.h"
|
||||
#include "data/data_shared_media.h"
|
||||
|
||||
class AudioMsgId;
|
||||
|
||||
@@ -148,8 +148,9 @@ Widget::Widget(QWidget *parent, not_null<Main::Session*> session)
|
||||
|
||||
updatePlaybackSpeedIcon();
|
||||
_playbackSpeed->setClickedCallback([=] {
|
||||
const auto doubled = !Core::App().settings().voiceMsgPlaybackDoubled();
|
||||
Core::App().settings().setVoiceMsgPlaybackDoubled(doubled);
|
||||
const auto doubled = (Core::App().settings().voicePlaybackSpeed()
|
||||
== 2.);
|
||||
Core::App().settings().setVoicePlaybackSpeed(doubled ? 1. : 2.);
|
||||
instance()->updateVoicePlaybackSpeed();
|
||||
updatePlaybackSpeedIcon();
|
||||
Core::App().saveSettingsDelayed();
|
||||
@@ -163,6 +164,8 @@ Widget::Widget(QWidget *parent, not_null<Main::Session*> session)
|
||||
subscribe(instance()->trackChangedNotifier(), [this](AudioMsgId::Type type) {
|
||||
if (type == _type) {
|
||||
handleSongChange();
|
||||
updateControlsVisibility();
|
||||
updateLabelsGeometry();
|
||||
}
|
||||
});
|
||||
subscribe(instance()->tracksFinishedNotifier(), [this](AudioMsgId::Type type) {
|
||||
@@ -277,6 +280,10 @@ void Widget::handleSeekFinished(float64 progress) {
|
||||
}
|
||||
|
||||
void Widget::resizeEvent(QResizeEvent *e) {
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
void Widget::updateControlsGeometry() {
|
||||
auto right = st::mediaPlayerCloseRight;
|
||||
_close->moveToRight(right, st::mediaPlayerPlayTop); right += _close->width();
|
||||
if (hasPlaybackSpeedControl()) {
|
||||
@@ -370,7 +377,8 @@ int Widget::getLabelsRight() const {
|
||||
auto result = st::mediaPlayerCloseRight + _close->width();
|
||||
if (_type == AudioMsgId::Type::Song) {
|
||||
result += _repeatTrack->width() + _volumeToggle->width();
|
||||
} else if (hasPlaybackSpeedControl()) {
|
||||
}
|
||||
if (hasPlaybackSpeedControl()) {
|
||||
result += _playbackSpeed->width();
|
||||
}
|
||||
result += st::mediaPlayerPadding;
|
||||
@@ -396,8 +404,8 @@ void Widget::updateRepeatTrackIcon() {
|
||||
}
|
||||
|
||||
void Widget::updatePlaybackSpeedIcon() {
|
||||
const auto doubled = Core::App().settings().voiceMsgPlaybackDoubled();
|
||||
const auto isDefaultSpeed = !doubled;
|
||||
const auto speed = Core::App().settings().voicePlaybackSpeed();
|
||||
const auto isDefaultSpeed = (speed == 1.);
|
||||
_playbackSpeed->setIconOverride(
|
||||
isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIcon : nullptr,
|
||||
isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIconOver : nullptr);
|
||||
@@ -420,21 +428,26 @@ void Widget::checkForTypeChange() {
|
||||
}
|
||||
|
||||
bool Widget::hasPlaybackSpeedControl() const {
|
||||
return (_type == AudioMsgId::Type::Voice)
|
||||
return _lastSongId.changeablePlaybackSpeed()
|
||||
&& Media::Audio::SupportsSpeedControl();
|
||||
}
|
||||
|
||||
void Widget::updateControlsVisibility() {
|
||||
_repeatTrack->setVisible(_type == AudioMsgId::Type::Song);
|
||||
_volumeToggle->setVisible(_type == AudioMsgId::Type::Song);
|
||||
_playbackSpeed->setVisible(hasPlaybackSpeedControl());
|
||||
if (!_shadow->isHidden()) {
|
||||
_playbackSlider->setVisible(_type == AudioMsgId::Type::Song);
|
||||
}
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
void Widget::setType(AudioMsgId::Type type) {
|
||||
if (_type != type) {
|
||||
_type = type;
|
||||
_repeatTrack->setVisible(_type == AudioMsgId::Type::Song);
|
||||
_volumeToggle->setVisible(_type == AudioMsgId::Type::Song);
|
||||
_playbackSpeed->setVisible(hasPlaybackSpeedControl());
|
||||
if (!_shadow->isHidden()) {
|
||||
_playbackSlider->setVisible(_type == AudioMsgId::Type::Song);
|
||||
}
|
||||
updateLabelsGeometry();
|
||||
handleSongChange();
|
||||
updateControlsVisibility();
|
||||
updateLabelsGeometry();
|
||||
handleSongUpdate(instance()->getState(_type));
|
||||
updateOverLabelsState(_labelsOver);
|
||||
_playlistChangesLifetime = instance()->playlistChanges(
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_audio_msg_id.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "base/object_ptr.h"
|
||||
|
||||
@@ -74,6 +75,8 @@ private:
|
||||
void updatePlayPrevNextPositions();
|
||||
void updateLabelsGeometry();
|
||||
void updateRepeatTrackIcon();
|
||||
void updateControlsVisibility();
|
||||
void updateControlsGeometry();
|
||||
void updatePlaybackSpeedIcon();
|
||||
void createPrevNextButtons();
|
||||
void destroyPrevNextButtons();
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_audio_msg_id.h"
|
||||
#include "ui/rect_part.h"
|
||||
|
||||
enum class ImageRoundRadius;
|
||||
|
||||
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_audio_msg_id.h"
|
||||
|
||||
namespace base::Platform {
|
||||
class SystemMediaControls;
|
||||
} // namespace base::Platform
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
void setGoodProxyDomain(const QString &host, const QString &ip);
|
||||
void suggestMainDcId(DcId mainDcId);
|
||||
void setMainDcId(DcId mainDcId);
|
||||
[[nodiscard]] bool hasMainDcId() const;
|
||||
[[nodiscard]] DcId mainDcId() const;
|
||||
[[nodiscard]] rpl::producer<DcId> mainDcIdValue() const;
|
||||
|
||||
@@ -357,13 +358,13 @@ void Instance::Private::start() {
|
||||
for (const auto &[shiftedDcId, dc] : _dcenters) {
|
||||
startSession(shiftedDcId);
|
||||
}
|
||||
} else if (mainDcId() != Fields::kNoneMainDc) {
|
||||
} else if (hasMainDcId()) {
|
||||
_mainSession = startSession(mainDcId());
|
||||
}
|
||||
|
||||
_checkDelayedTimer.setCallback([this] { checkDelayedRequests(); });
|
||||
|
||||
Assert((mainDcId() == Fields::kNoneMainDc) == isKeysDestroyer());
|
||||
Assert(!hasMainDcId() == isKeysDestroyer());
|
||||
requestConfig();
|
||||
}
|
||||
|
||||
@@ -474,8 +475,12 @@ void Instance::Private::setMainDcId(DcId mainDcId) {
|
||||
_writeKeysRequests.fire({});
|
||||
}
|
||||
|
||||
bool Instance::Private::hasMainDcId() const {
|
||||
return (_mainDcId.current() != Fields::kNoneMainDc);
|
||||
}
|
||||
|
||||
DcId Instance::Private::mainDcId() const {
|
||||
Expects(_mainDcId.current() != Fields::kNoneMainDc);
|
||||
Expects(hasMainDcId());
|
||||
|
||||
return _mainDcId.current();
|
||||
}
|
||||
@@ -557,7 +562,7 @@ void Instance::Private::requestConfigIfExpired() {
|
||||
}
|
||||
|
||||
void Instance::Private::requestCDNConfig() {
|
||||
if (_cdnConfigLoadRequestId || mainDcId() == Fields::kNoneMainDc) {
|
||||
if (_cdnConfigLoadRequestId || !hasMainDcId()) {
|
||||
return;
|
||||
}
|
||||
_cdnConfigLoadRequestId = request(
|
||||
@@ -696,6 +701,8 @@ void Instance::Private::logout(Fn<void()> done) {
|
||||
}
|
||||
|
||||
void Instance::Private::logoutGuestDcs() {
|
||||
Expects(!isKeysDestroyer());
|
||||
|
||||
auto dcIds = std::vector<DcId>();
|
||||
dcIds.reserve(_keysForWrite.size());
|
||||
for (const auto &key : _keysForWrite) {
|
||||
@@ -1463,7 +1470,7 @@ bool Instance::Private::onErrorDefault(
|
||||
LOG(("MTP Error: unauthorized request without dc info, requestId %1").arg(requestId));
|
||||
}
|
||||
auto newdc = BareDcId(qAbs(dcWithShift));
|
||||
if (!newdc || newdc == mainDcId()) {
|
||||
if (!newdc || !hasMainDcId() || newdc == mainDcId()) {
|
||||
if (!badGuestDc && _globalFailHandler) {
|
||||
_globalFailHandler(error, response); // auth failed in main dc
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwindow.h"
|
||||
#include "windows_quiethours_h.h"
|
||||
|
||||
#include <QtCore/QOperatingSystemVersion>
|
||||
|
||||
#include <Shobjidl.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
@@ -261,21 +263,13 @@ DWORD QuietHoursValue = 0;
|
||||
|
||||
[[nodiscard]] bool UseQuietHoursRegistryEntry() {
|
||||
static const bool result = [] {
|
||||
// Taken from QSysInfo.
|
||||
OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0,{ '\0' } };
|
||||
if (const auto library = GetModuleHandle(L"ntdll.dll")) {
|
||||
using RtlGetVersionFunction = NTSTATUS(NTAPI*)(LPOSVERSIONINFO);
|
||||
const auto RtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
|
||||
GetProcAddress(library, "RtlGetVersion"));
|
||||
if (RtlGetVersion) {
|
||||
RtlGetVersion(&result);
|
||||
}
|
||||
}
|
||||
const auto version = QOperatingSystemVersion::current();
|
||||
|
||||
// At build 17134 (Redstone 4) the "Quiet hours" was replaced
|
||||
// by "Focus assist" and it looks like it doesn't use registry.
|
||||
return (result.dwMajorVersion == 10
|
||||
&& result.dwMinorVersion == 0
|
||||
&& result.dwBuildNumber < 17134);
|
||||
return (version.majorVersion() == 10)
|
||||
&& (version.minorVersion() == 0)
|
||||
&& (version.microVersion() < 17134);
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1112,7 +1112,9 @@ bool ReadSetting(
|
||||
stream >> v;
|
||||
if (!CheckStreamStatus(stream)) return false;
|
||||
|
||||
Core::App().settings().setVoiceMsgPlaybackDoubled(v == 2);
|
||||
if (v == 2) {
|
||||
Core::App().settings().setVoicePlaybackSpeed(2.);
|
||||
}
|
||||
context.legacyRead = true;
|
||||
} break;
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_common.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
constexpr auto kFileSizeLimit = 2000 * 1024 * 1024; // Load files up to 2000MB
|
||||
|
||||
enum class SendMediaType {
|
||||
|
||||
@@ -682,12 +682,13 @@ bool readBackground() {
|
||||
const auto isOldEmptyImage = (bg.stream.status() != QDataStream::Ok);
|
||||
if (isOldEmptyImage
|
||||
|| Data::IsLegacy1DefaultWallPaper(*paper)
|
||||
|| (Data::IsLegacy2DefaultWallPaper(*paper) && bg.version < 2008012)
|
||||
|| (Data::IsLegacy2DefaultWallPaper(*paper) && bg.version < 3000000)
|
||||
|| (Data::IsLegacy3DefaultWallPaper(*paper) && bg.version < 3000000)
|
||||
|| (Data::IsLegacy4DefaultWallPaper(*paper) && bg.version < 3000000)
|
||||
|| Data::IsDefaultWallPaper(*paper)) {
|
||||
_backgroundCanWrite = false;
|
||||
if (isOldEmptyImage || bg.version < 2008012) {
|
||||
if (isOldEmptyImage || bg.version < 3000000) {
|
||||
Window::Theme::Background()->set(Data::DefaultWallPaper());
|
||||
Window::Theme::Background()->setTile(false);
|
||||
} else {
|
||||
Window::Theme::Background()->set(*paper);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Serialize {
|
||||
|
||||
int storageImageLocationSize(const StorageImageLocation &location);
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Ui {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxChatEntryHistorySize = 50;
|
||||
constexpr auto kCacheBackgroundTimeout = 3 * crl::time(1000);
|
||||
constexpr auto kCacheBackgroundTimeout = 1 * crl::time(1000);
|
||||
constexpr auto kCacheBackgroundFastTimeout = crl::time(200);
|
||||
constexpr auto kBackgroundFadeDuration = crl::time(200);
|
||||
constexpr auto kMinimumTiledSize = 512;
|
||||
|
||||
104
Telegram/SourceFiles/ui/chat/forward_options_box.cpp
Normal file
104
Telegram/SourceFiles/ui/chat/forward_options_box.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "ui/chat/forward_options_box.h"
|
||||
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
void ForwardOptionsBox(
|
||||
not_null<GenericBox*> box,
|
||||
int count,
|
||||
ForwardOptions options,
|
||||
Fn<void(ForwardOptions)> optionsChanged,
|
||||
Fn<void()> changeRecipient) {
|
||||
Expects(optionsChanged != nullptr);
|
||||
Expects(changeRecipient != nullptr);
|
||||
|
||||
box->setTitle((count == 1)
|
||||
? tr::lng_forward_title()
|
||||
: tr::lng_forward_many_title(
|
||||
lt_count,
|
||||
rpl::single(count) | tr::to_count()));
|
||||
box->addButton(tr::lng_box_done(), [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box.get(),
|
||||
(count == 1
|
||||
? tr::lng_forward_about()
|
||||
: tr::lng_forward_many_about()),
|
||||
st::boxLabel),
|
||||
st::boxRowPadding);
|
||||
const auto checkboxPadding = style::margins(
|
||||
st::boxRowPadding.left(),
|
||||
st::boxRowPadding.left(),
|
||||
st::boxRowPadding.right(),
|
||||
st::boxRowPadding.bottom());
|
||||
const auto names = box->addRow(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
box.get(),
|
||||
(count == 1
|
||||
? tr::lng_forward_show_sender
|
||||
: tr::lng_forward_show_senders)(),
|
||||
!options.dropNames,
|
||||
st::defaultBoxCheckbox),
|
||||
checkboxPadding);
|
||||
const auto captions = options.hasCaptions
|
||||
? box->addRow(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
box.get(),
|
||||
(count == 1
|
||||
? tr::lng_forward_show_caption
|
||||
: tr::lng_forward_show_captions)(),
|
||||
!options.dropCaptions,
|
||||
st::defaultBoxCheckbox),
|
||||
checkboxPadding)
|
||||
: nullptr;
|
||||
const auto notify = [=] {
|
||||
optionsChanged({
|
||||
.dropNames = !names->checked(),
|
||||
.hasCaptions = options.hasCaptions,
|
||||
.dropCaptions = (captions && !captions->checked()),
|
||||
});
|
||||
};
|
||||
names->checkedChanges(
|
||||
) | rpl::start_with_next([=](bool showNames) {
|
||||
if (showNames && captions && !captions->checked()) {
|
||||
captions->setChecked(true);
|
||||
} else {
|
||||
notify();
|
||||
}
|
||||
}, names->lifetime());
|
||||
if (captions) {
|
||||
captions->checkedChanges(
|
||||
) | rpl::start_with_next([=](bool showCaptions) {
|
||||
if (!showCaptions && names->checked()) {
|
||||
names->setChecked(false);
|
||||
} else {
|
||||
notify();
|
||||
}
|
||||
}, captions->lifetime());
|
||||
}
|
||||
box->addRow(
|
||||
object_ptr<Ui::LinkButton>(
|
||||
box.get(),
|
||||
tr::lng_forward_change_recipient(tr::now)),
|
||||
checkboxPadding
|
||||
)->setClickedCallback([=] {
|
||||
box->closeBox();
|
||||
changeRecipient();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
27
Telegram/SourceFiles/ui/chat/forward_options_box.h
Normal file
27
Telegram/SourceFiles/ui/chat/forward_options_box.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
struct ForwardOptions {
|
||||
bool dropNames = false;
|
||||
bool hasCaptions = false;
|
||||
bool dropCaptions = false;
|
||||
};
|
||||
|
||||
void ForwardOptionsBox(
|
||||
not_null<GenericBox*> box,
|
||||
int count,
|
||||
ForwardOptions options,
|
||||
Fn<void(ForwardOptions)> optionsChanged,
|
||||
Fn<void()> changeRecipient);
|
||||
|
||||
} // namespace Ui
|
||||
@@ -275,9 +275,13 @@ void GroupCallBar::paint(Painter &p) {
|
||||
titleTop,
|
||||
width,
|
||||
(!_content.scheduleDate
|
||||
? tr::lng_group_call_title(tr::now)
|
||||
? (_content.livestream
|
||||
? tr::lng_group_call_title_channel
|
||||
: tr::lng_group_call_title)(tr::now)
|
||||
: _content.title.isEmpty()
|
||||
? tr::lng_group_call_scheduled_title(tr::now)
|
||||
? (_content.livestream
|
||||
? tr::lng_group_call_scheduled_title_channel
|
||||
: tr::lng_group_call_scheduled_title)(tr::now)
|
||||
: (titleWidth > available)
|
||||
? font->elided(_content.title, available)
|
||||
: _content.title));
|
||||
@@ -315,6 +319,8 @@ void GroupCallBar::paint(Painter &p) {
|
||||
(_content.scheduleDate
|
||||
? (_content.title.isEmpty()
|
||||
? tr::lng_group_call_starts_short
|
||||
: _content.livestream
|
||||
? tr::lng_group_call_starts_channel
|
||||
: tr::lng_group_call_starts)(tr::now, lt_when, when)
|
||||
: _content.count > 0
|
||||
? tr::lng_group_call_members(tr::now, lt_count, _content.count)
|
||||
|
||||
@@ -26,6 +26,7 @@ struct GroupCallBarContent {
|
||||
TimeId scheduleDate = 0;
|
||||
int count = 0;
|
||||
bool shown = false;
|
||||
bool livestream = false;
|
||||
std::vector<GroupCallUser> users;
|
||||
};
|
||||
|
||||
|
||||
@@ -73,7 +73,11 @@ AbstractSectionWidget::AbstractSectionWidget(
|
||||
peerForBackground
|
||||
) | rpl::map([=](PeerData *peer) -> rpl::producer<> {
|
||||
if (!peer) {
|
||||
return rpl::never<>();
|
||||
return rpl::single(
|
||||
rpl::empty_value()
|
||||
) | rpl::then(
|
||||
controller->defaultChatTheme()->repaintBackgroundRequests()
|
||||
);
|
||||
}
|
||||
return ChatThemeValueFromPeer(
|
||||
controller,
|
||||
|
||||
@@ -59,6 +59,13 @@ inline bool AreTestingTheme() {
|
||||
return !GlobalApplying.paletteForRevert.isEmpty();
|
||||
}
|
||||
|
||||
[[nodiscard]] QImage ReadDefaultImage() {
|
||||
return Ui::ReadBackgroundImage(
|
||||
u":/gui/art/background.tgv"_q,
|
||||
QByteArray(),
|
||||
true);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool GoodImageFormatAndSize(const QImage &image) {
|
||||
return !image.size().isEmpty()
|
||||
&& (image.format() == QImage::Format_ARGB32_Premultiplied
|
||||
@@ -432,8 +439,7 @@ bool InitializeFromSaved(Saved &&saved) {
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
image.setDevicePixelRatio(cRetinaFactor());
|
||||
if (Data::IsDefaultWallPaper(paper)
|
||||
|| Data::details::IsTestingDefaultWallPaper(paper)) {
|
||||
if (Data::IsLegacy3DefaultWallPaper(paper)) {
|
||||
return Images::DitherImage(std::move(image));
|
||||
}
|
||||
return image;
|
||||
@@ -659,13 +665,11 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
|| Data::details::IsTestingEditorWallPaper(_paper)) {
|
||||
if (Data::details::IsTestingDefaultWallPaper(_paper)
|
||||
|| image.isNull()) {
|
||||
image.load(qsl(":/gui/art/background.jpg"));
|
||||
image = ReadDefaultImage();
|
||||
setPaper(Data::details::TestingDefaultWallPaper());
|
||||
}
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPrepared(image, image, QImage());
|
||||
setPreparedAfterPaper(std::move(image));
|
||||
} else {
|
||||
const auto &bgColors = _paper.backgroundColors();
|
||||
if (Data::IsLegacy1DefaultWallPaper(_paper)) {
|
||||
image.load(qsl(":/gui/art/bg_initial.jpg"));
|
||||
const auto scale = cScale() * cIntRetinaFactor();
|
||||
@@ -675,9 +679,9 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
} else if (Data::IsDefaultWallPaper(_paper)
|
||||
|| (bgColors.empty() && image.isNull())) {
|
||||
|| (_paper.backgroundColors().empty() && image.isNull())) {
|
||||
setPaper(Data::DefaultWallPaper().withParamsFrom(_paper));
|
||||
image.load(qsl(":/gui/art/background.jpg"));
|
||||
image = ReadDefaultImage();
|
||||
}
|
||||
Local::writeBackground(
|
||||
_paper,
|
||||
@@ -685,36 +689,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
|| Data::IsLegacy1DefaultWallPaper(_paper))
|
||||
? QImage()
|
||||
: image));
|
||||
if (_paper.isPattern() && !image.isNull()) {
|
||||
if (bgColors.size() < 2) {
|
||||
auto prepared = postprocessBackgroundImage(
|
||||
Ui::PreparePatternImage(
|
||||
image,
|
||||
bgColors,
|
||||
_paper.gradientRotation(),
|
||||
_paper.patternOpacity()));
|
||||
setPrepared(
|
||||
std::move(image),
|
||||
std::move(prepared),
|
||||
QImage());
|
||||
} else {
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPrepared(
|
||||
image,
|
||||
image,
|
||||
Data::GenerateDitheredGradient(_paper));
|
||||
}
|
||||
} else if (bgColors.size() == 1) {
|
||||
setPrepared(QImage(), QImage(), QImage());
|
||||
} else if (!bgColors.empty()) {
|
||||
setPrepared(
|
||||
QImage(),
|
||||
QImage(),
|
||||
Data::GenerateDitheredGradient(_paper));
|
||||
} else {
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPrepared(image, image, QImage());
|
||||
}
|
||||
setPreparedAfterPaper(std::move(image));
|
||||
}
|
||||
Assert(colorForFill()
|
||||
|| !_gradient.isNull()
|
||||
@@ -730,6 +705,40 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
checkUploadWallPaper();
|
||||
}
|
||||
|
||||
void ChatBackground::setPreparedAfterPaper(QImage image) {
|
||||
const auto &bgColors = _paper.backgroundColors();
|
||||
if (_paper.isPattern() && !image.isNull()) {
|
||||
if (bgColors.size() < 2) {
|
||||
auto prepared = postprocessBackgroundImage(
|
||||
Ui::PreparePatternImage(
|
||||
image,
|
||||
bgColors,
|
||||
_paper.gradientRotation(),
|
||||
_paper.patternOpacity()));
|
||||
setPrepared(
|
||||
std::move(image),
|
||||
std::move(prepared),
|
||||
QImage());
|
||||
} else {
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPrepared(
|
||||
image,
|
||||
image,
|
||||
Data::GenerateDitheredGradient(_paper));
|
||||
}
|
||||
} else if (bgColors.size() == 1) {
|
||||
setPrepared(QImage(), QImage(), QImage());
|
||||
} else if (!bgColors.empty()) {
|
||||
setPrepared(
|
||||
QImage(),
|
||||
QImage(),
|
||||
Data::GenerateDitheredGradient(_paper));
|
||||
} else {
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPrepared(image, image, QImage());
|
||||
}
|
||||
}
|
||||
|
||||
void ChatBackground::setPrepared(
|
||||
QImage original,
|
||||
QImage prepared,
|
||||
|
||||
@@ -207,6 +207,7 @@ private:
|
||||
[[nodiscard]] bool started() const;
|
||||
void initialRead();
|
||||
void saveForRevert();
|
||||
void setPreparedAfterPaper(QImage image);
|
||||
void setPrepared(QImage original, QImage prepared, QImage gradient);
|
||||
void prepareImageForTiled();
|
||||
void writeNewBackgroundSettings();
|
||||
|
||||
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/chat/chat_theme.h"
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "styles/style_media_view.h"
|
||||
@@ -417,7 +418,16 @@ void Generator::paintHistoryBackground() {
|
||||
if (background.isNull()) {
|
||||
const auto fakePaper = Data::WallPaper(_current.backgroundId);
|
||||
if (Data::IsThemeWallPaper(fakePaper)) {
|
||||
background.load(qsl(":/gui/art/background.jpg"));
|
||||
background = Ui::ReadBackgroundImage(
|
||||
u":/gui/art/background.tgv"_q,
|
||||
QByteArray(),
|
||||
true);
|
||||
const auto paper = Data::DefaultWallPaper();
|
||||
background = Ui::PreparePatternImage(
|
||||
std::move(background),
|
||||
paper.backgroundColors(),
|
||||
paper.gradientRotation(),
|
||||
paper.patternOpacity());
|
||||
tiled = false;
|
||||
} else {
|
||||
background = std::move(_current.backgroundImage);
|
||||
|
||||
@@ -162,7 +162,7 @@ void AddChatMembers(
|
||||
}
|
||||
|
||||
bool PinnedLimitReached(Dialogs::Key key, FilterId filterId) {
|
||||
Expects(key.entry()->folderKnown());
|
||||
Expects(filterId != 0 || key.entry()->folderKnown());
|
||||
|
||||
const auto entry = key.entry();
|
||||
const auto owner = &entry->owner();
|
||||
@@ -963,27 +963,29 @@ void BlockSenderFromRepliesBox(
|
||||
|
||||
QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
MessageIdsList &&items,
|
||||
Data::ForwardDraft &&draft,
|
||||
FnMut<void()> &&successCallback) {
|
||||
const auto weak = std::make_shared<QPointer<PeerListBox>>();
|
||||
auto callback = [
|
||||
ids = std::move(items),
|
||||
draft = std::move(draft),
|
||||
callback = std::move(successCallback),
|
||||
weak,
|
||||
navigation
|
||||
](not_null<PeerData*> peer) mutable {
|
||||
const auto content = navigation->parentController()->content();
|
||||
if (peer->isSelf()) {
|
||||
auto items = peer->owner().idsToItems(ids);
|
||||
if (!items.empty()) {
|
||||
const auto history = peer->owner().history(peer);
|
||||
auto resolved = history->resolveForwardDraft(draft);
|
||||
if (!resolved.items.empty()) {
|
||||
const auto api = &peer->session().api();
|
||||
auto action = Api::SendAction(peer->owner().history(peer));
|
||||
action.clearDraft = false;
|
||||
action.generateLocal = false;
|
||||
api->forwardMessages(std::move(items), action, [] {
|
||||
api->forwardMessages(std::move(resolved), action, [] {
|
||||
Ui::Toast::Show(tr::lng_share_done(tr::now));
|
||||
});
|
||||
}
|
||||
} else if (!navigation->parentController()->content()->setForwardDraft(peer->id, std::move(ids))) {
|
||||
} else if (!content->setForwardDraft(peer->id, std::move(draft))) {
|
||||
return;
|
||||
}
|
||||
if (const auto strong = *weak) {
|
||||
@@ -1006,6 +1008,16 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
return weak->data();
|
||||
}
|
||||
|
||||
QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
MessageIdsList &&items,
|
||||
FnMut<void()> &&successCallback) {
|
||||
return ShowForwardMessagesBox(
|
||||
navigation,
|
||||
Data::ForwardDraft{ .ids = std::move(items) },
|
||||
std::move(successCallback));
|
||||
}
|
||||
|
||||
QPointer<Ui::RpWidget> ShowSendNowMessagesBox(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<History*> history,
|
||||
|
||||
@@ -21,6 +21,7 @@ class GenericBox;
|
||||
namespace Data {
|
||||
class Folder;
|
||||
class Session;
|
||||
struct ForwardDraft;
|
||||
} // namespace Data
|
||||
|
||||
namespace Dialogs {
|
||||
@@ -94,6 +95,10 @@ void ToggleHistoryArchived(not_null<History*> history, bool archived);
|
||||
Fn<void()> ClearHistoryHandler(not_null<PeerData*> peer);
|
||||
Fn<void()> DeleteAndLeaveHandler(not_null<PeerData*> peer);
|
||||
|
||||
QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
Data::ForwardDraft &&draft,
|
||||
FnMut<void()> &&successCallback = nullptr);
|
||||
QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
MessageIdsList &&items,
|
||||
|
||||
@@ -1066,17 +1066,26 @@ void SessionController::startOrJoinGroupCall(
|
||||
// Do you want to leave your active voice chat
|
||||
// to join a voice chat in this group?
|
||||
askConfirmation(
|
||||
tr::lng_call_leave_to_other_sure(tr::now),
|
||||
(peer->isBroadcast()
|
||||
? tr::lng_call_leave_to_other_sure_channel
|
||||
: tr::lng_call_leave_to_other_sure)(tr::now),
|
||||
tr::lng_call_bar_hangup(tr::now));
|
||||
} else if (confirm != GroupCallJoinConfirm::None
|
||||
&& calls.inGroupCall()) {
|
||||
if (calls.currentGroupCall()->peer() == peer) {
|
||||
const auto now = calls.currentGroupCall()->peer();
|
||||
if (now == peer) {
|
||||
calls.activateCurrentCall(joinHash);
|
||||
} else if (calls.currentGroupCall()->scheduleDate()) {
|
||||
calls.startOrJoinGroupCall(peer, joinHash);
|
||||
} else {
|
||||
askConfirmation(
|
||||
tr::lng_group_call_leave_to_other_sure(tr::now),
|
||||
((peer->isBroadcast() && now->isBroadcast())
|
||||
? tr::lng_group_call_leave_channel_to_other_sure_channel
|
||||
: now->isBroadcast()
|
||||
? tr::lng_group_call_leave_channel_to_other_sure
|
||||
: peer->isBroadcast()
|
||||
? tr::lng_group_call_leave_to_other_sure_channel
|
||||
: tr::lng_group_call_leave_to_other_sure)(tr::now),
|
||||
tr::lng_group_call_leave(tr::now));
|
||||
}
|
||||
} else {
|
||||
|
||||
2
Telegram/ThirdParty/tgcalls
vendored
2
Telegram/ThirdParty/tgcalls
vendored
Submodule Telegram/ThirdParty/tgcalls updated: 0c9ea366ca...c64036b69e
@@ -29,7 +29,7 @@ ENV LibrariesPath /usr/src/Libraries
|
||||
WORKDIR $LibrariesPath
|
||||
|
||||
FROM builder AS patches
|
||||
RUN git clone $GIT/desktop-app/patches.git && cd patches && git checkout 3ffe48e
|
||||
RUN git clone $GIT/desktop-app/patches.git && cd patches && git checkout d58ce6b2b0
|
||||
|
||||
FROM builder AS extra-cmake-modules
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AppVersion 2009013
|
||||
AppVersionStrMajor 2.9
|
||||
AppVersionStrSmall 2.9.13
|
||||
AppVersionStr 2.9.13
|
||||
BetaChannel 1
|
||||
AppVersion 3000001
|
||||
AppVersionStrMajor 3.0
|
||||
AppVersionStrSmall 3.0.1
|
||||
AppVersionStr 3.0.1
|
||||
BetaChannel 0
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 2.9.13.beta
|
||||
AppVersionOriginal 3.0.1
|
||||
|
||||
@@ -139,6 +139,8 @@ PRIVATE
|
||||
ui/chat/chat_style.h
|
||||
ui/chat/chat_theme.cpp
|
||||
ui/chat/chat_theme.h
|
||||
ui/chat/forward_options_box.cpp
|
||||
ui/chat/forward_options_box.h
|
||||
ui/chat/group_call_bar.cpp
|
||||
ui/chat/group_call_bar.h
|
||||
ui/chat/group_call_userpics.cpp
|
||||
|
||||
Submodule Telegram/lib_base updated: 9729d6fd98...e3591a6778
Submodule Telegram/lib_lottie updated: 06960b493d...25294ef8da
Submodule Telegram/lib_ui updated: 2e3eef52f7...ea570c07b6
@@ -1,6 +1,23 @@
|
||||
3.0.1 (01.09.21)
|
||||
|
||||
- Crash fixes.
|
||||
|
||||
3.0 (31.08.21)
|
||||
|
||||
- Broadcast video and share your screen to an unlimited number of viewers.
|
||||
- To begin, tap the Live Stream button in the title bar of a community where you are an admin.
|
||||
- Tap the "Forward Message" label above the input field to change how messages will be sent.
|
||||
- Hide or show the original sender's name.
|
||||
- Remove or keep captions from media messages.
|
||||
- See how many unread comments there are when opening a channel's comments.
|
||||
|
||||
2.9.14 beta (31.08.21)
|
||||
|
||||
- Fix crash in authorization after logout.
|
||||
|
||||
2.9.13 beta (31.08.21)
|
||||
|
||||
-
|
||||
- See unread comments count when scrolling discussions in channels.
|
||||
|
||||
2.9.12 beta (24.08.21)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ Go to ***BuildPath*** and run
|
||||
|
||||
git clone https://github.com/desktop-app/patches.git
|
||||
cd patches
|
||||
git checkout 87a2e9ee07
|
||||
git checkout d58ce6b2b0
|
||||
cd ../
|
||||
git clone https://chromium.googlesource.com/external/gyp
|
||||
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
@@ -58,7 +58,7 @@ Go to ***BuildPath*** and run
|
||||
|
||||
git clone https://github.com/desktop-app/patches.git
|
||||
cd patches
|
||||
git checkout 87a2e9ee07
|
||||
git checkout d58ce6b2b0
|
||||
cd ..
|
||||
|
||||
git clone https://git.tukaani.org/xz.git
|
||||
|
||||
@@ -34,7 +34,7 @@ Open **x64 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
|
||||
cd ThirdParty
|
||||
git clone https://github.com/desktop-app/patches.git
|
||||
cd patches
|
||||
git checkout 87a2e9ee07
|
||||
git checkout d58ce6b2b0
|
||||
cd ../
|
||||
git clone https://chromium.googlesource.com/external/gyp
|
||||
cd gyp
|
||||
@@ -65,7 +65,7 @@ Open **x64 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
|
||||
|
||||
git clone https://github.com/desktop-app/patches.git
|
||||
cd patches
|
||||
git checkout 87a2e9ee07
|
||||
git checkout d58ce6b2b0
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/desktop-app/lzma.git
|
||||
|
||||
@@ -34,7 +34,7 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
|
||||
cd ThirdParty
|
||||
git clone https://github.com/desktop-app/patches.git
|
||||
cd patches
|
||||
git checkout 87a2e9ee07
|
||||
git checkout d58ce6b2b0
|
||||
cd ..
|
||||
|
||||
git clone https://chromium.googlesource.com/external/gyp
|
||||
@@ -68,7 +68,7 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
|
||||
|
||||
git clone https://github.com/desktop-app/patches.git
|
||||
cd patches
|
||||
git checkout 87a2e9ee07
|
||||
git checkout d58ce6b2b0
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/desktop-app/lzma.git
|
||||
|
||||
Reference in New Issue
Block a user