Compare commits

...

31 Commits

Author SHA1 Message Date
John Preston
b0f54822e0 Version 3.0.1.
- Crash fixes.
2021-09-01 19:41:57 +03:00
John Preston
df4c9a0765 Cache correct background faster. 2021-09-01 19:38:36 +03:00
John Preston
47e15d136d Fix background update with all chats closed. 2021-09-01 19:28:02 +03:00
John Preston
5aff4cca0e Fix rare crash in message history resizing. 2021-09-01 19:21:39 +03:00
John Preston
a064e836f2 Removed redundant "base::EnterFromEventLoop". 2021-09-01 19:08:56 +03:00
John Preston
81ed3acfa1 Attempt to fix a crash in event loop nesting tracking. 2021-09-01 19:08:23 +03:00
John Preston
cc2dd31555 Attempt to fix a possible crash in InputField. 2021-09-01 18:50:11 +03:00
John Preston
0ee6395022 Try to a fix crash after lost OpenGL context. 2021-09-01 18:38:12 +03:00
John Preston
1d2a18929a Use QOperatingSystemVersion. 2021-09-01 18:33:53 +03:00
John Preston
a0a3de125a Detect Windows 11 by build number 22000. 2021-09-01 18:33:43 +03:00
John Preston
1cf207671e Fix crash in countries list refresh. 2021-09-01 18:33:24 +03:00
John Preston
c208b5dc58 Couple more of crash fixes. 2021-09-01 13:45:45 +03:00
John Preston
6eb5d47c35 Couple of crash fixes. 2021-09-01 13:27:36 +03:00
23rd
59977da2b4 Added choosing sticker action to field autocomplete. 2021-09-01 01:23:20 +03:00
23rd
4550b2a315 Decreased record bitrate of voice messages.
Fixed #6708.
2021-09-01 01:23:20 +03:00
23rd
bcbab7ad8e Added ability to change playback speed for long audio files. 2021-09-01 01:23:20 +03:00
23rd
b635a9d4a5 Changed voice playback speed setting to storage value of speed. 2021-09-01 01:23:20 +03:00
23rd
eadd7704ef Removed Main::Session forward declaration from data_types. 2021-09-01 01:23:20 +03:00
23rd
e6f0c176f7 Moved AudioMsgId to separated file. 2021-09-01 01:23:20 +03:00
John Preston
22d4331ead Version 3.0: Update tgcalls submodule. 2021-09-01 01:15:49 +03:00
John Preston
1247fde04e Version 3.0.
- 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.
2021-08-31 22:26:06 +03:00
John Preston
88a2f05c6d Fix crash in new phone formatting. 2021-08-31 22:26:06 +03:00
John Preston
df15c67dab Improve phrase in forwarding options box. 2021-08-31 22:10:56 +03:00
John Preston
f59db10267 Update default chat background. 2021-08-31 22:10:39 +03:00
John Preston
d29a1f5cd2 Refresh choose sticker animation data on lang update. 2021-08-31 20:47:08 +03:00
John Preston
cd8d257c70 Disable chat themes. 2021-08-31 19:51:56 +03:00
John Preston
9dfc60026e Add simple forwarding options on bar click. 2021-08-31 19:47:38 +03:00
John Preston
e9a5c45f34 Use separate strings for channel voice chats. 2021-08-31 17:59:29 +03:00
John Preston
2c07bdd0e8 Beta version 2.9.14.
- Fix crash in authorization after logout.
2021-08-31 14:07:42 +03:00
John Preston
b106438de8 Fix crash in stale authorization keys destruction. 2021-08-31 14:06:12 +03:00
23rd
92b7afc5f5 Fixed position of send action animation. 2021-08-31 14:06:11 +03:00
92 changed files with 1078 additions and 432 deletions

View File

@@ -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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -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";

View File

@@ -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>

View 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>

View File

@@ -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"

View File

@@ -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"

View File

@@ -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

View File

@@ -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;

View File

@@ -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()) {

View File

@@ -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(

View File

@@ -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()

View File

@@ -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) }
};
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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() },
});

View File

@@ -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));
}

View File

@@ -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(),

View File

@@ -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),

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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));

View 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);
}

View 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;
};

View File

@@ -17,6 +17,10 @@ namespace Dialogs {
class Entry;
} // namespace Dialogs
namespace Main {
class Session;
} // namespace Main
namespace Data {
namespace details {

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -1005,7 +1005,7 @@ PeerId PeerData::groupCallDefaultJoinAs() const {
}
void PeerData::setThemeEmoji(const QString &emoji) {
if (_themeEmoji == emoji) {
if (true || _themeEmoji == emoji) {
return;
}
_themeEmoji = emoji;

View File

@@ -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));
}
}

View File

@@ -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();

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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,

View File

@@ -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(

View File

@@ -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;

View File

@@ -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();

View File

@@ -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"

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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();
}
}
}
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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"

View File

@@ -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;

View File

@@ -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());
}
}
}

View File

@@ -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;

View File

@@ -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(

View File

@@ -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();

View File

@@ -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;

View File

@@ -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

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View 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

View 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

View File

@@ -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)

View File

@@ -26,6 +26,7 @@ struct GroupCallBarContent {
TimeId scheduleDate = 0;
int count = 0;
bool shown = false;
bool livestream = false;
std::vector<GroupCallUser> users;
};

View File

@@ -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,

View File

@@ -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,

View File

@@ -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();

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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