Compare commits

..

119 Commits

Author SHA1 Message Date
John Preston
b5bc567eb8 Beta version 3.7.5: Fix MSVC x64 Release build. 2022-05-13 12:26:26 +04:00
John Preston
5f91a97778 Beta version 3.7.5.
- Improve cloud password management design.
- Fix a crash in shared media search.
- Fix audio recording on macOS.
2022-05-12 18:02:52 +04:00
John Preston
63aa3576d8 Append correct RtcServer-s and RtcServer ids. 2022-05-12 18:02:52 +04:00
John Preston
7749794d6b Update OpenAL to fix macOS audio recording. 2022-05-12 17:26:30 +04:00
John Preston
368468447f Fix possible crash on bad data. 2022-05-12 16:29:12 +04:00
John Preston
54fa16424d Update API to layer 142. 2022-05-12 15:31:53 +04:00
John Preston
fc7f1991dd Allow more attempts to finalize section geometry. 2022-05-12 14:43:24 +04:00
23rd
910d0a7e47 Unified element sizes in all cloud password sections. 2022-05-12 03:51:41 +03:00
23rd
6e8fb2ec06 Returned ability to copy phone number from main settings. 2022-05-10 08:53:31 +03:00
23rd
94d943f3af Fixed style of icons in info peer box. 2022-05-10 08:53:31 +03:00
23rd
41e6e32962 Fixed closing of box for passport authorization. 2022-05-10 08:53:31 +03:00
23rd
2f58a7d3c4 Added auto-close timer for cloud password management section. 2022-05-10 08:53:31 +03:00
23rd
e364b80d0a Added ability to validate expired cloud password in management section. 2022-05-10 08:53:31 +03:00
23rd
f3efa85206 Added short comments for cloud password settings sections. 2022-05-10 08:53:31 +03:00
23rd
42f2f3c99f Slightly improved style of buttons in security and privacy settings. 2022-05-10 08:53:31 +03:00
23rd
a6d0367d71 Added some error handles for recovery email settings section. 2022-05-10 08:53:31 +03:00
23rd
bcbf009a62 Added ability to reset cloud password without recovery email. 2022-05-10 08:53:31 +03:00
23rd
fedd8bece3 Added ability to clear cloud password from recover state. 2022-05-10 08:53:31 +03:00
23rd
031525e7e3 Added ability to recover cloud password with email from settings. 2022-05-10 08:53:31 +03:00
23rd
4d5cb6398e Moved creation of link button in cloud password settings to common file. 2022-05-10 08:53:31 +03:00
23rd
3ef352b63c Added ability to recover cloud password from Api::CloudPassword. 2022-05-10 08:53:31 +03:00
23rd
9809c12fb8 Added initial entry point for new cloud password to settings privacy. 2022-05-10 08:53:30 +03:00
23rd
3e4ac35913 Added ability to set recovery email from cloud password management. 2022-05-10 08:53:30 +03:00
23rd
a72953411b Added step section of email confirm to cloud password settings. 2022-05-10 08:53:30 +03:00
23rd
3967e58627 Improved step section of password input for checking cloud password. 2022-05-10 08:53:30 +03:00
23rd
db46f84f2c Added initial implementation of cloud password management to settings. 2022-05-10 08:53:30 +03:00
23rd
9a57347973 Added step section of email input to cloud password settings. 2022-05-10 08:53:30 +03:00
23rd
c9c988e5f4 Added step section of hint input to cloud password settings. 2022-05-10 08:53:30 +03:00
23rd
5e2acdeaa3 Added step section of password input to cloud password settings. 2022-05-10 08:53:30 +03:00
23rd
5a4d1a1e85 Added first step section to cloud password settings. 2022-05-10 08:53:30 +03:00
23rd
fbd9437775 Added ability to transfer variant data between nearest setting sections. 2022-05-10 08:53:30 +03:00
23rd
2eaa17b938 Moved creation of flexible bottom content of password section to module. 2022-05-10 08:53:30 +03:00
23rd
01eacadca5 Added ability to set recovery email from Api::CloudPassword. 2022-05-10 08:53:30 +03:00
23rd
9f155e0053 Added ability to confirm recovery email from Api::CloudPassword. 2022-05-10 08:53:30 +03:00
23rd
2f9dc6ca2a Added ability to check cloud password from Api::CloudPassword. 2022-05-10 08:53:30 +03:00
23rd
3d6f6cdd8f Added ability to set cloud password from Api::CloudPassword. 2022-05-10 08:53:30 +03:00
23rd
7e3c54f8d0 Added common initial helpers for steps of cloud password settings. 2022-05-10 08:53:29 +03:00
23rd
540ee0bc44 Moved out mtp fields from PasscodeBox::CloudFields to nested struct. 2022-05-10 08:53:29 +03:00
23rd
627170520a Moved out mtp fields from CloudPasswordState to nested struct. 2022-05-08 23:13:45 +03:00
23rd
77d50d9177 Moved out template classes for local passcode from header. 2022-05-05 20:31:17 +03:00
23rd
c47140c62d Fixed window activation by clicking on tray icon for macOS. 2022-05-05 16:52:09 +03:00
23rd
546dfb08ef Moved out info in Folders settings from pinned content. 2022-05-05 16:52:09 +03:00
23rd
376b592e5a Replaced boxes for local passcode settings with section. 2022-05-05 16:52:09 +03:00
23rd
c27db754a7 Added initial implementation of first screen for local passcode. 2022-05-05 16:52:09 +03:00
23rd
5fb71cb165 Added ability to append pinned to bottom content to settings sections. 2022-05-05 16:52:09 +03:00
23rd
972666440e Added ability to remove previous sections from stack in info widget. 2022-05-05 16:52:09 +03:00
23rd
549d7c77e5 Added to settings support of showing back section from stack. 2022-05-05 16:51:17 +03:00
23rd
de3b30ed7d Added support of focus handle to sections of settings. 2022-05-05 16:51:17 +03:00
23rd
a4f5e3f411 Removed display of strings with tiny formats with huge values. 2022-05-05 16:51:17 +03:00
23rd
df19b62e92 Replaced json of lottie icon for filters with binary file. 2022-05-05 16:51:16 +03:00
Ilya Fedin
caf2be13b3 Move pipewire stubs initialization to Media::Audio::Start 2022-05-04 14:34:33 +04:00
John Preston
e206f42e4e Beta version 3.7.4: Update tg_owt in snap. 2022-05-04 12:34:22 +04:00
John Preston
3f60410190 Beta version 3.7.4: Fix build with GCC in Release. 2022-05-04 11:49:11 +04:00
John Preston
3cdd8558db Beta version 3.7.4: Fix build with GCC. 2022-05-04 11:42:54 +04:00
John Preston
f2b89445ae Allow playing single lottie icon repeatedly or once. 2022-05-04 11:39:53 +04:00
23rd
3ff4bf77e7 Removed repeated animation from some settings lottie icons. 2022-05-04 07:32:52 +03:00
John Preston
d16ccf0d9e Beta version 3.7.4: Fix build with Xcode. 2022-05-03 23:33:41 +04:00
John Preston
fc7d9b264f Add webview-debug-enabled option. 2022-05-03 23:30:54 +04:00
John Preston
b28d5a63d1 Handle alert/confirm/prompt with custom dialog on Linux. 2022-05-03 23:30:42 +04:00
John Preston
043ba4ff04 Handle alert/confirm/prompt with custom dialog on macOS. 2022-05-03 23:30:21 +04:00
John Preston
d6c3bf4168 Use EdgeChromium by default on Windows. 2022-05-03 23:29:04 +04:00
John Preston
7bf7a8feff Beta version 3.7.4.
- Improve some more sections design.
- Update the OpenAL library to 1.22.0.
2022-05-03 23:09:26 +04:00
John Preston
3413ad1d22 Add some more icons for folders. 2022-05-03 23:09:26 +04:00
John Preston
84af084a3b Update tg_owt to WebRTC M101. 2022-05-03 23:09:26 +04:00
23rd
cd50008429 Moved plus icon to settings style file. 2022-05-03 21:59:38 +03:00
23rd
767459ab57 Slightly improved style of button in settings of blocked peers. 2022-05-03 21:59:38 +03:00
23rd
3b45a120e6 Slightly improved style of buttons and icons in Folders settings. 2022-05-03 21:59:38 +03:00
23rd
b04aaba8d0 Slightly improved style of box for edit folder. 2022-05-03 21:59:38 +03:00
23rd
bfa3655c7b Removed unused code of box for filters choosing. 2022-05-03 21:59:38 +03:00
CrisMystik
8642eb23a7 Removed unneeded part of code 2022-05-03 16:35:54 +04:00
CrisMystik
ef8ecc546b Use ::Settings::Main::Id() as fallback 2022-05-03 16:35:54 +04:00
CrisMystik
fafbbb4996 Suggested code improvements 2022-05-03 16:35:54 +04:00
CrisMystik
3a021f4e49 Make type variable const 2022-05-03 16:35:54 +04:00
CrisMystik
2788c19c85 Add some missing includes 2022-05-03 16:35:54 +04:00
CrisMystik
300cc3dbca Support all Settings links 2022-05-03 16:35:54 +04:00
GitHub Action
62516e264d Update User-Agent for DNS to Chrome 100.0.4896.127. 2022-05-03 16:24:54 +04:00
John Preston
8b89cfc4cb Fix custom notification sounds for all chats. 2022-05-03 16:23:39 +04:00
Ilya Fedin
e3f65d2346 Convet font point size to pixel size more like Qt does in the crash reporter 2022-05-03 15:16:20 +04:00
Andrew Krasavin
2b383a4236 Explicitly specify QVector element type to fix build with clang13+rangev3+qt6
More info:
https://github.com/telegramdesktop/tdesktop/issues/24385
https://github.com/telegramdesktop/tdesktop/issues/24014
https://github.com/ericniebler/range-v3/issues/1691
2022-05-03 15:15:20 +04:00
John Preston
a8426bd6da Update submodules. 2022-05-03 14:58:13 +04:00
John Preston
39a02e649d Fix crash on invalid data in local cache. 2022-05-03 14:52:08 +04:00
John Preston
276fe2169a Use SeparatePanel / ShowMultilineToast from lib_ui. 2022-05-03 14:52:08 +04:00
23rd
8fae56bee8 Improved style of Folders settings. 2022-05-03 04:25:36 +03:00
23rd
0e16a50bbc Completely removed common and platform code for tray from main window. 2022-05-03 04:25:36 +03:00
23rd
9de372d715 Replaced macOS Qt tray with native implementation. 2022-05-03 04:25:36 +03:00
23rd
fbae5bdbcf Removed macOS tray implementation from main window. 2022-05-03 04:25:36 +03:00
23rd
aee1ef78da Moved out static job for Linux tray icon to separated class. 2022-05-03 04:25:36 +03:00
23rd
27c5c4b8f2 Removed Linux tray implementation from main window. 2022-05-03 04:25:36 +03:00
23rd
94e06c6846 Removed Windows tray implementation from main window. 2022-05-03 04:25:36 +03:00
23rd
7948d971e8 Added initial implementation of Linux tray. 2022-05-03 04:25:36 +03:00
23rd
70acc7a0e3 Added initial implementation of Windows tray. 2022-05-03 04:25:36 +03:00
23rd
56fdc7d39a Added common and macOS tray implementations. 2022-05-03 04:25:36 +03:00
23rd
f67c3bbf65 Added placeholders for platform dependent implementations of tray. 2022-05-03 04:25:35 +03:00
23rd
de194c4aa2 Initialized empty files for tray implementations. 2022-05-03 04:25:35 +03:00
23rd
511805199f Added ability to check are windows active for tray menu. 2022-05-03 04:25:35 +03:00
23rd
aa241a1f62 Removed duplicated icons. 2022-05-03 04:25:35 +03:00
23rd
4125a45503 Slightly improved format of mute time in menu. 2022-05-03 04:25:35 +03:00
23rd
1349989494 Moved settings of blocked peers to section. 2022-05-03 04:25:35 +03:00
23rd
639ed8b973 Added ability to append pinned to top content to settings sections. 2022-05-02 22:31:05 +03:00
23rd
2f5db08c9b Fixed double scroll in reactions settings when height is small. 2022-05-02 22:31:05 +03:00
Ilya Fedin
4c6814def6 Replace style sheet in PreLaunchInput 2022-05-02 16:01:36 +04:00
Ilya Fedin
387914be31 Replace style sheet in Editor::Paint 2022-05-02 16:01:36 +04:00
Ilya Fedin
2f2003c89b Fix media viewer on Unity
This could be a regression for tiling WMs, though...
2022-05-02 16:00:56 +04:00
Ilya Fedin
48589b721d Update openal to 1.22.0 2022-05-02 15:33:56 +04:00
23rd
3bdf1634a9 Added ability to copy phone number from main menu. 2022-04-28 17:41:34 +03:00
23rd
1878061c9a Fixed color of attention menu items for account buttons. 2022-04-28 17:16:58 +03:00
23rd
774c3b5ba0 Fixed tab order in EditNameBox. 2022-04-28 17:10:13 +03:00
23rd
a64b8d4181 Slightly improved style of section for group stickers. 2022-04-28 16:27:39 +03:00
23rd
e3e380124d Removed ttl menu from inaccessible groups and channels. 2022-04-28 15:13:58 +03:00
John Preston
823fc25fa8 Fix layer height updating in poll results. 2022-04-27 15:20:19 +04:00
23rd
4062912a98 Added missed icon for join requests in manage of groups / channels. 2022-04-26 22:16:41 +04:00
23rd
62b5192f24 Added missed icon for channel type in manage of channels. 2022-04-26 22:16:39 +04:00
23rd
058717532a Replaced title static reaction icon in manage of groups / channels. 2022-04-26 22:16:38 +04:00
Sergey A. Osokin
d117a72e6e Fix -Wunused-const-variable warnings by removing unused variables
Fixes #24432
2022-04-26 21:25:05 +04:00
Sergey A. Osokin
3ba5b825e5 Fix -Wunused-const-variable warnings by removing unused variables
Fixes #24432
2022-04-26 21:25:05 +04:00
John Preston
075ab20e5b Version 3.7.3: Don't copy text from a restricted post. 2022-04-26 14:13:16 +04:00
John Preston
deeea0aaed Version 3.7.3: Update lib_webview. 2022-04-26 13:06:42 +04:00
John Preston
8113117cc4 Version 3.7.3.
- Fix a crash in the pinned bar bot button refresh.
2022-04-26 10:38:58 +04:00
John Preston
7bfe096f3b Fix possible crashes in pinned bar button. 2022-04-26 10:24:36 +04:00
188 changed files with 6534 additions and 2633 deletions

View File

@@ -990,6 +990,8 @@ PRIVATE
platform/linux/notifications_manager_linux.h
platform/linux/specific_linux.cpp
platform/linux/specific_linux.h
platform/linux/tray_linux.cpp
platform/linux/tray_linux.h
platform/mac/file_utilities_mac.mm
platform/mac/file_utilities_mac.h
platform/mac/launcher_mac.mm
@@ -1005,6 +1007,8 @@ PRIVATE
platform/mac/specific_mac.h
platform/mac/specific_mac_p.mm
platform/mac/specific_mac_p.h
platform/mac/tray_mac.mm
platform/mac/tray_mac.h
platform/mac/window_title_mac.mm
platform/mac/touchbar/items/mac_formatter_item.h
platform/mac/touchbar/items/mac_formatter_item.mm
@@ -1038,6 +1042,8 @@ PRIVATE
platform/win/notifications_manager_win.h
platform/win/specific_win.cpp
platform/win/specific_win.h
platform/win/tray_win.cpp
platform/win/tray_win.h
platform/win/windows_app_user_model_id.cpp
platform/win/windows_app_user_model_id.h
platform/win/windows_dlls.cpp
@@ -1054,6 +1060,7 @@ PRIVATE
platform/platform_main_window.h
platform/platform_notifications_manager.h
platform/platform_specific.h
platform/platform_tray.h
platform/platform_window_title.h
profile/profile_back_button.cpp
profile/profile_back_button.h
@@ -1065,8 +1072,24 @@ PRIVATE
profile/profile_block_widget.h
profile/profile_cover_drop_area.cpp
profile/profile_cover_drop_area.h
settings/cloud_password/settings_cloud_password_common.cpp
settings/cloud_password/settings_cloud_password_common.h
settings/cloud_password/settings_cloud_password_email.cpp
settings/cloud_password/settings_cloud_password_email.h
settings/cloud_password/settings_cloud_password_email_confirm.cpp
settings/cloud_password/settings_cloud_password_email_confirm.h
settings/cloud_password/settings_cloud_password_hint.cpp
settings/cloud_password/settings_cloud_password_hint.h
settings/cloud_password/settings_cloud_password_input.cpp
settings/cloud_password/settings_cloud_password_input.h
settings/cloud_password/settings_cloud_password_manage.cpp
settings/cloud_password/settings_cloud_password_manage.h
settings/cloud_password/settings_cloud_password_start.cpp
settings/cloud_password/settings_cloud_password_start.h
settings/settings_advanced.cpp
settings/settings_advanced.h
settings/settings_blocked_peers.cpp
settings/settings_blocked_peers.h
settings/settings_chat.cpp
settings/settings_chat.h
settings/settings_calls.cpp
@@ -1083,6 +1106,8 @@ PRIVATE
settings/settings_information.h
settings/settings_intro.cpp
settings/settings_intro.h
settings/settings_local_passcode.cpp
settings/settings_local_passcode.h
settings/settings_main.cpp
settings/settings_main.h
settings/settings_notifications.cpp
@@ -1258,6 +1283,8 @@ PRIVATE
settings.cpp
settings.h
stdafx.h
tray.cpp
tray.h
)
if (NOT build_winstore)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

View File

@@ -490,8 +490,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_forwards_privacy" = "Forwarded messages";
"lng_settings_profile_photo_privacy" = "Profile photo";
"lng_settings_sessions_about" = "Control your sessions on other devices.";
"lng_settings_passcode_disable" = "Disable passcode";
"lng_settings_password_disable" = "Disable cloud password";
"lng_settings_passcode_disable" = "Disable Passcode";
"lng_settings_passcode_disable_sure" = "Are you sure you want to disable passcode?";
"lng_settings_password_disable" = "Disable Cloud Password";
"lng_settings_password_abort" = "Abort two-step verification setup";
"lng_settings_password_reenter_email" = "Re-enter recovery email";
"lng_settings_about_bio" = "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco";
@@ -540,6 +541,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_security_bots" = "Bots and websites";
"lng_settings_clear_payment_info" = "Clear Payment and Shipping Info";
"lng_settings_cloud_password_on" = "On";
"lng_settings_cloud_password_off" = "Off";
"lng_settings_cloud_password_start_title" = "Two-Step Verification";
"lng_settings_cloud_password_password_title" = "Password";
"lng_settings_cloud_password_hint_title" = "Password Hint";
"lng_settings_cloud_password_email_title" = "Recovery Email";
"lng_settings_cloud_password_start_about" = "Protect your Telegram account with an additional password.";
"lng_settings_cloud_password_hint_about" = "You can create a hint for your password.";
"lng_settings_cloud_password_email_about" = "Please enter your new recovery email. It is the only way to recover a forgotten password.";
"lng_settings_cloud_password_password_subtitle" = "Create Password";
"lng_settings_cloud_password_check_subtitle" = "Your Password";
"lng_settings_cloud_password_hint_subtitle" = "Add Password Hint";
"lng_settings_cloud_password_email_subtitle" = "Add Recovery Email";
"lng_settings_cloud_password_email_recovery_subtitle" = "Password Recovery";
"lng_settings_cloud_password_manage_about1" = "You have Two-Step Verification enabled, so your account is protected with an additional password.";
"lng_settings_cloud_password_manage_about2" = "This email is the only way to recover a forgotten password.";
"lng_settings_cloud_password_manage_disable_sure" = "Are you sure you want to disable your password?";
"lng_settings_cloud_password_manage_email_new" = "Set Recovery Email";
"lng_settings_cloud_password_manage_email_change" = "Change Recovery Email";
"lng_settings_cloud_password_manage_password_change" = "Change Password";
"lng_settings_cloud_password_skip_hint" = "Skip hint";
"lng_settings_cloud_password_save" = "Save and Finish";
"lng_settings_cloud_password_email_confirm" = "Confirm and Finish";
"lng_settings_cloud_password_reset_in" = "You can reset your password in {duration}.";
"lng_clear_payment_info_title" = "Clear payment info";
"lng_clear_payment_info_sure" = "Are you sure you want to clear your payment and shipping info?";
"lng_clear_payment_info_shipping" = "Shipping info";
@@ -634,7 +660,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passcode_remove_button" = "Remove";
"lng_passcode_turn_on" = "Turn on local passcode";
"lng_passcode_change" = "Change local passcode";
"lng_passcode_change" = "Change Passcode";
"lng_passcode_create" = "Local passcode";
"lng_passcode_remove" = "Remove local passcode";
"lng_passcode_turn_off" = "Turn off";
@@ -647,6 +673,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passcode_enter_new" = "Enter new passcode";
"lng_passcode_confirm_new" = "Re-enter new passcode";
"lng_passcode_about" = "When a local passcode is set, a lock icon appears at the top of your chats list. Click it to lock the app.\n\nNote: if you forget your local passcode, you'll need to relogin in Telegram Desktop.";
"lng_passcode_about1" = "When a local passcode is set, a lock icon appears at the top of your chats list.";
"lng_passcode_about2" = "Click it to lock Telegram Desktop.";
"lng_passcode_about3" = "Note: if you forget your passcode, you'll need to log out of Telegram Desktop and log in again.";
"lng_passcode_differ" = "Passcodes are different";
"lng_passcode_wrong" = "Wrong passcode";
"lng_passcode_is_same" = "Passcode was not changed";
@@ -655,6 +684,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passcode_submit" = "Submit";
"lng_passcode_logout" = "Log out";
"lng_passcode_need_unblock" = "You need to unlock me first.";
"lng_passcode_create_button" = "Save Passcode";
"lng_passcode_check_button" = "Submit";
"lng_passcode_change_button" = "Save Passcode";
"lng_passcode_create_title" = "Create Local Passcode";
"lng_passcode_check_title" = "Enter Passcode";
"lng_passcode_change_title" = "Enter Passcode";
"lng_cloud_password_waiting_code" = "Confirmation code sent to {email}...";
"lng_cloud_password_confirm" = "Confirm recovery email";
@@ -668,12 +703,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_cloud_password_reset_cancel" = "Cancel password reset";
"lng_cloud_password_enter_old" = "Enter current password";
"lng_cloud_password_enter_first" = "Enter a password";
"lng_cloud_password_enter_new" = "Enter new password";
"lng_cloud_password_confirm_new" = "Re-enter new password";
"lng_cloud_password_hint" = "Enter password hint";
"lng_cloud_password_enter_new" = "Enter password";
"lng_cloud_password_confirm_new" = "Re-enter password";
"lng_cloud_password_hint" = "Enter Password Hint";
"lng_cloud_password_change_hint" = "Enter new password hint";
"lng_cloud_password_bad" = "Password and hint cannot be the same.";
"lng_cloud_password_email" = "Enter recovery email";
"lng_cloud_password_email" = "Enter Email";
"lng_cloud_password_bad_email" = "Incorrect email, please try other.";
"lng_cloud_password_about" = "This password will be asked when you log in on a new device in addition to the SMS code.";
"lng_cloud_password_about_recover" = "Warning! Are you sure you don't want to\nadd a password recovery email?\n\nIf you forget your password, you will\nlose access to your Telegram account.";
@@ -695,6 +730,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_cloud_password_reset_cancel_title" = "Cancel reset";
"lng_cloud_password_reset_cancel_sure" = "Cancel the password reset process? If you request a new reset later, it will take another 7 days.";
"lng_cloud_password_reset_later" = "You recently requested a password reset that was cancelled. Please wait {duration} before making a new request.";
"lng_cloud_password_expired" = "Please re-enter your password.";
"lng_connection_auto_connecting" = "Default (connecting...)";
"lng_connection_auto" = "Default ({transport} used)";
@@ -799,6 +835,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_blocked_list_confirm_text" = "Do you want to block {name} from messaging and calling you on Telegram?";
"lng_blocked_list_confirm_clear" = "Delete this chat";
"lng_blocked_list_confirm_ok" = "Block";
"lng_blocked_list_empty_title" = "No blocked users";
"lng_blocked_list_empty_description" = "You haven't blocked anyone yet.";
"lng_blocked_list_subtitle#one" = "{count} blocked user";
"lng_blocked_list_subtitle#other" = "{count} blocked users";
"lng_edit_privacy_everyone" = "Everybody";
"lng_edit_privacy_contacts" = "My contacts";

View File

@@ -1,5 +1,12 @@
<RCC>
<qresource prefix="/animations">
<file alias="change_number.tgs">../../animations/change_number.tgs</file>
<file alias="blocked_peers_empty.tgs">../../animations/blocked_peers_empty.tgs</file>
<file alias="filters.tgs">../../animations/filters.tgs</file>
<file alias="local_passcode_enter.tgs">../../animations/local_passcode_enter.tgs</file>
<file alias="cloud_password/intro.tgs">../../animations/cloud_password/intro.tgs</file>
<file alias="cloud_password/password_input.tgs">../../animations/cloud_password/password_input.tgs</file>
<file alias="cloud_password/hint.tgs">../../animations/cloud_password/hint.tgs</file>
<file alias="cloud_password/email.tgs">../../animations/cloud_password/email.tgs</file>
</qresource>
</RCC>

View File

@@ -125,7 +125,7 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#29562865 id:long = Chat;
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
chatForbidden#6592a1a7 id:long title:string = Chat;
channel#8261ac61 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
channel#8261ac61 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#d18ee226 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?Vector<string> = ChatFull;
@@ -414,9 +414,9 @@ photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File;
dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int pinned_infolder_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int pinned_infolder_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@@ -874,7 +874,7 @@ phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long d
phoneCall#967f7c67 flags:# p2p_allowed:flags.5?true video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection;
phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector<string> = PhoneCallProtocol;
@@ -1227,7 +1227,7 @@ messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> use
messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
messageReplyHeader#a6d57763 flags:# reply_to_msg_id:int reply_to_peer_id:flags.0?Peer reply_to_top_id:flags.1?int = MessageReplyHeader;
messageReplyHeader#a6d57763 flags:# reply_to_scheduled:flags.2?true reply_to_msg_id:int reply_to_peer_id:flags.0?Peer reply_to_top_id:flags.1?int = MessageReplyHeader;
messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;
@@ -1295,7 +1295,7 @@ account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordR
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
sponsoredMessage#3a836df8 flags:# random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> = SponsoredMessage;
sponsoredMessage#3a836df8 flags:# recommended:flags.5?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> = SponsoredMessage;
messages.sponsoredMessages#65a4c7d5 messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
@@ -1807,6 +1807,7 @@ phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = U
phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates;
phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels;
phone.getGroupCallStreamRtmpUrl#deb3abbf peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl;
phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool;
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
@@ -1823,4 +1824,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
// LAYER 140
// LAYER 142

View File

@@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="3.7.2.0" />
Version="3.7.5.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 3,7,2,0
PRODUCTVERSION 3,7,2,0
FILEVERSION 3,7,5,0
PRODUCTVERSION 3,7,5,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "3.7.2.0"
VALUE "FileVersion", "3.7.5.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "3.7.2.0"
VALUE "ProductVersion", "3.7.5.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,7,2,0
PRODUCTVERSION 3,7,2,0
FILEVERSION 3,7,5,0
PRODUCTVERSION 3,7,5,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", "3.7.2.0"
VALUE "FileVersion", "3.7.5.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "3.7.2.0"
VALUE "ProductVersion", "3.7.5.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -7,18 +7,37 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_cloud_password.h"
#include "apiwrap.h"
#include "base/random.h"
#include "core/core_cloud_password.h"
#include "apiwrap.h"
#include "passport/passport_encryption.h"
namespace Api {
namespace {
// #TODO Add ability to set recovery email separately.
[[nodiscard]] Core::CloudPasswordState ProcessMtpState(
const MTPaccount_password &state) {
return state.match([&](const MTPDaccount_password &data) {
base::RandomAddSeed(bytes::make_span(data.vsecure_random().v));
return Core::ParseCloudPasswordState(data);
});
}
} // namespace
CloudPassword::CloudPassword(not_null<ApiWrap*> api)
: _api(&api->instance()) {
}
void CloudPassword::apply(Core::CloudPasswordState state) {
if (_state) {
*_state = std::move(state);
} else {
_state = std::make_unique<Core::CloudPasswordState>(std::move(state));
}
_stateChanges.fire_copy(*_state);
}
void CloudPassword::reload() {
if (_requestId) {
return;
@@ -26,16 +45,7 @@ void CloudPassword::reload() {
_requestId = _api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
_requestId = 0;
result.match([&](const MTPDaccount_password &data) {
base::RandomAddSeed(bytes::make_span(data.vsecure_random().v));
if (_state) {
*_state = Core::ParseCloudPasswordState(data);
} else {
_state = std::make_unique<Core::CloudPasswordState>(
Core::ParseCloudPasswordState(data));
}
_stateChanges.fire_copy(*_state);
});
apply(ProcessMtpState(result));
}).fail([=] {
_requestId = 0;
}).send();
@@ -109,4 +119,426 @@ auto CloudPassword::cancelResetPassword()
};
}
rpl::producer<CloudPassword::SetOk, QString> CloudPassword::set(
const QString &oldPassword,
const QString &newPassword,
const QString &hint,
bool hasRecoveryEmail,
const QString &recoveryEmail) {
const auto generatePasswordCheck = [=](
const Core::CloudPasswordState &latestState) {
if (oldPassword.isEmpty() || !latestState.hasPassword) {
return Core::CloudPasswordResult{
MTP_inputCheckPasswordEmpty()
};
}
const auto hash = Core::ComputeCloudPasswordHash(
latestState.mtp.request.algo,
bytes::make_span(oldPassword.toUtf8()));
return Core::ComputeCloudPasswordCheck(
latestState.mtp.request,
hash);
};
const auto finish = [=](auto consumer, int unconfirmedEmailLengthCode) {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
apply(ProcessMtpState(result));
if (unconfirmedEmailLengthCode) {
consumer.put_next(SetOk{ unconfirmedEmailLengthCode });
} else {
consumer.put_done();
}
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).handleFloodErrors().send();
};
const auto sendMTPaccountUpdatePasswordSettings = [=](
const Core::CloudPasswordState &latestState,
const QByteArray &secureSecret,
auto consumer) {
const auto newPasswordBytes = newPassword.toUtf8();
const auto newPasswordHash = Core::ComputeCloudPasswordDigest(
latestState.mtp.newPassword,
bytes::make_span(newPasswordBytes));
if (!newPassword.isEmpty() && newPasswordHash.modpow.empty()) {
consumer.put_error("INTERNAL_SERVER_ERROR");
return;
}
using Flag = MTPDaccount_passwordInputSettings::Flag;
const auto flags = Flag::f_new_algo
| Flag::f_new_password_hash
| Flag::f_hint
| (secureSecret.isEmpty() ? Flag(0) : Flag::f_new_secure_settings)
| ((!hasRecoveryEmail) ? Flag(0) : Flag::f_email);
auto newSecureSecret = bytes::vector();
auto newSecureSecretId = 0ULL;
if (!secureSecret.isEmpty()) {
newSecureSecretId = Passport::CountSecureSecretId(
bytes::make_span(secureSecret));
newSecureSecret = Passport::EncryptSecureSecret(
bytes::make_span(secureSecret),
Core::ComputeSecureSecretHash(
latestState.mtp.newSecureSecret,
bytes::make_span(newPasswordBytes)));
}
const auto settings = MTP_account_passwordInputSettings(
MTP_flags(flags),
Core::PrepareCloudPasswordAlgo(newPassword.isEmpty()
? v::null
: latestState.mtp.newPassword),
newPassword.isEmpty()
? MTP_bytes()
: MTP_bytes(newPasswordHash.modpow),
MTP_string(hint),
MTP_string(recoveryEmail),
MTP_secureSecretSettings(
Core::PrepareSecureSecretAlgo(
latestState.mtp.newSecureSecret),
MTP_bytes(newSecureSecret),
MTP_long(newSecureSecretId)));
_api.request(MTPaccount_UpdatePasswordSettings(
generatePasswordCheck(latestState).result,
settings
)).done([=] {
finish(consumer, 0);
}).fail([=](const MTP::Error &error) {
const auto &type = error.type();
const auto prefix = u"EMAIL_UNCONFIRMED_"_q;
if (type.startsWith(prefix)) {
const auto codeLength = base::StringViewMid(
type,
prefix.size()).toInt();
finish(consumer, codeLength);
} else {
consumer.put_error_copy(type);
}
}).handleFloodErrors().send();
};
return [=](auto consumer) {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
const auto latestState = ProcessMtpState(result);
if (latestState.hasPassword
&& !oldPassword.isEmpty()
&& !newPassword.isEmpty()) {
_api.request(MTPaccount_GetPasswordSettings(
generatePasswordCheck(latestState).result
)).done([=](const MTPaccount_PasswordSettings &result) {
using Settings = MTPDaccount_passwordSettings;
const auto &data = result.match([&](
const Settings &data) -> const Settings & {
return data;
});
auto secureSecret = QByteArray();
if (const auto wrapped = data.vsecure_settings()) {
using Secure = MTPDsecureSecretSettings;
const auto &settings = wrapped->match([](
const Secure &data) -> const Secure & {
return data;
});
const auto passwordUtf = oldPassword.toUtf8();
const auto secret = Passport::DecryptSecureSecret(
bytes::make_span(settings.vsecure_secret().v),
Core::ComputeSecureSecretHash(
Core::ParseSecureSecretAlgo(
settings.vsecure_algo()),
bytes::make_span(passwordUtf)));
if (secret.empty()) {
LOG(("API Error: "
"Failed to decrypt secure secret."));
consumer.put_error("SUGGEST_SECRET_RESET");
return;
} else if (Passport::CountSecureSecretId(secret)
!= settings.vsecure_secret_id().v) {
LOG(("API Error: Wrong secure secret id."));
consumer.put_error("SUGGEST_SECRET_RESET");
return;
} else {
secureSecret = QByteArray(
reinterpret_cast<const char*>(secret.data()),
secret.size());
}
}
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
const auto latestState = ProcessMtpState(result);
sendMTPaccountUpdatePasswordSettings(
latestState,
secureSecret,
consumer);
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
} else {
sendMTPaccountUpdatePasswordSettings(
latestState,
QByteArray(),
consumer);
}
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return rpl::lifetime();
};
}
rpl::producer<rpl::no_value, QString> CloudPassword::check(
const QString &password) {
return [=](auto consumer) {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
const auto latestState = ProcessMtpState(result);
const auto input = [&] {
if (password.isEmpty()) {
return Core::CloudPasswordResult{
MTP_inputCheckPasswordEmpty()
};
}
const auto hash = Core::ComputeCloudPasswordHash(
latestState.mtp.request.algo,
bytes::make_span(password.toUtf8()));
return Core::ComputeCloudPasswordCheck(
latestState.mtp.request,
hash);
}();
_api.request(MTPaccount_GetPasswordSettings(
input.result
)).done([=](const MTPaccount_PasswordSettings &result) {
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return rpl::lifetime();
};
}
rpl::producer<rpl::no_value, QString> CloudPassword::confirmEmail(
const QString &code) {
return [=](auto consumer) {
_api.request(MTPaccount_ConfirmPasswordEmail(
MTP_string(code)
)).done([=] {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
apply(ProcessMtpState(result));
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).handleFloodErrors().send();
return rpl::lifetime();
};
}
rpl::producer<rpl::no_value, QString> CloudPassword::resendEmailCode() {
return [=](auto consumer) {
_api.request(MTPaccount_ResendPasswordEmail(
)).done([=] {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
apply(ProcessMtpState(result));
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).handleFloodErrors().send();
return rpl::lifetime();
};
}
rpl::producer<CloudPassword::SetOk, QString> CloudPassword::setEmail(
const QString &oldPassword,
const QString &recoveryEmail) {
const auto generatePasswordCheck = [=](
const Core::CloudPasswordState &latestState) {
if (oldPassword.isEmpty() || !latestState.hasPassword) {
return Core::CloudPasswordResult{
MTP_inputCheckPasswordEmpty()
};
}
const auto hash = Core::ComputeCloudPasswordHash(
latestState.mtp.request.algo,
bytes::make_span(oldPassword.toUtf8()));
return Core::ComputeCloudPasswordCheck(
latestState.mtp.request,
hash);
};
const auto finish = [=](auto consumer, int unconfirmedEmailLengthCode) {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
apply(ProcessMtpState(result));
if (unconfirmedEmailLengthCode) {
consumer.put_next(SetOk{ unconfirmedEmailLengthCode });
} else {
consumer.put_done();
}
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).handleFloodErrors().send();
};
const auto sendMTPaccountUpdatePasswordSettings = [=](
const Core::CloudPasswordState &latestState,
auto consumer) {
const auto settings = MTP_account_passwordInputSettings(
MTP_flags(MTPDaccount_passwordInputSettings::Flag::f_email),
MTP_passwordKdfAlgoUnknown(),
MTP_bytes(),
MTP_string(),
MTP_string(recoveryEmail),
MTPSecureSecretSettings());
_api.request(MTPaccount_UpdatePasswordSettings(
generatePasswordCheck(latestState).result,
settings
)).done([=] {
finish(consumer, 0);
}).fail([=](const MTP::Error &error) {
const auto &type = error.type();
const auto prefix = u"EMAIL_UNCONFIRMED_"_q;
if (type.startsWith(prefix)) {
const auto codeLength = base::StringViewMid(
type,
prefix.size()).toInt();
finish(consumer, codeLength);
} else {
consumer.put_error_copy(type);
}
}).handleFloodErrors().send();
};
return [=](auto consumer) {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
const auto latestState = ProcessMtpState(result);
sendMTPaccountUpdatePasswordSettings(latestState, consumer);
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return rpl::lifetime();
};
}
rpl::producer<rpl::no_value, QString> CloudPassword::recoverPassword(
const QString &code,
const QString &newPassword,
const QString &newHint) {
const auto finish = [=](auto consumer) {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
apply(ProcessMtpState(result));
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).handleFloodErrors().send();
};
const auto sendMTPaccountUpdatePasswordSettings = [=](
const Core::CloudPasswordState &latestState,
auto consumer) {
const auto newPasswordBytes = newPassword.toUtf8();
const auto newPasswordHash = Core::ComputeCloudPasswordDigest(
latestState.mtp.newPassword,
bytes::make_span(newPasswordBytes));
if (!newPassword.isEmpty() && newPasswordHash.modpow.empty()) {
consumer.put_error("INTERNAL_SERVER_ERROR");
return;
}
using Flag = MTPDaccount_passwordInputSettings::Flag;
const auto flags = Flag::f_new_algo
| Flag::f_new_password_hash
| Flag::f_hint;
const auto settings = MTP_account_passwordInputSettings(
MTP_flags(flags),
Core::PrepareCloudPasswordAlgo(newPassword.isEmpty()
? v::null
: latestState.mtp.newPassword),
newPassword.isEmpty()
? MTP_bytes()
: MTP_bytes(newPasswordHash.modpow),
MTP_string(newHint),
MTP_string(),
MTPSecureSecretSettings());
_api.request(MTPauth_RecoverPassword(
MTP_flags(newPassword.isEmpty()
? MTPauth_RecoverPassword::Flags(0)
: MTPauth_RecoverPassword::Flag::f_new_settings),
MTP_string(code),
settings
)).done([=](const MTPauth_Authorization &result) {
finish(consumer);
}).fail([=](const MTP::Error &error) {
const auto &type = error.type();
consumer.put_error_copy(type);
}).handleFloodErrors().send();
};
return [=](auto consumer) {
_api.request(MTPaccount_GetPassword(
)).done([=](const MTPaccount_Password &result) {
const auto latestState = ProcessMtpState(result);
sendMTPaccountUpdatePasswordSettings(latestState, consumer);
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return rpl::lifetime();
};
}
rpl::producer<QString, QString> CloudPassword::requestPasswordRecovery() {
return [=](auto consumer) {
_api.request(MTPauth_RequestPasswordRecovery(
)).done([=](const MTPauth_PasswordRecovery &result) {
result.match([&](const MTPDauth_passwordRecovery &data) {
consumer.put_next(qs(data.vemail_pattern().v));
});
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return rpl::lifetime();
};
}
auto CloudPassword::checkRecoveryEmailAddressCode(const QString &code)
-> rpl::producer<rpl::no_value, QString> {
return [=](auto consumer) {
_api.request(MTPauth_CheckRecoveryPassword(
MTP_string(code)
)).done([=] {
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).handleFloodErrors().send();
return rpl::lifetime();
};
}
} // namespace Api

View File

@@ -23,6 +23,10 @@ namespace Api {
class CloudPassword final {
public:
struct SetOk {
int unconfirmedEmailLengthCode = 0;
};
using ResetRetryDate = int;
explicit CloudPassword(not_null<ApiWrap*> api);
@@ -34,7 +38,31 @@ public:
rpl::producer<ResetRetryDate, QString> resetPassword();
rpl::producer<rpl::no_value, QString> cancelResetPassword();
rpl::producer<SetOk, QString> set(
const QString &oldPassword,
const QString &newPassword,
const QString &hint,
bool hasRecoveryEmail,
const QString &recoveryEmail);
rpl::producer<rpl::no_value, QString> check(const QString &password);
rpl::producer<rpl::no_value, QString> confirmEmail(const QString &code);
rpl::producer<rpl::no_value, QString> resendEmailCode();
rpl::producer<SetOk, QString> setEmail(
const QString &oldPassword,
const QString &recoveryEmail);
rpl::producer<rpl::no_value, QString> recoverPassword(
const QString &code,
const QString &newPassword,
const QString &newHint);
rpl::producer<QString, QString> requestPasswordRecovery();
rpl::producer<rpl::no_value, QString> checkRecoveryEmailAddressCode(
const QString &code);
private:
void apply(Core::CloudPasswordState state);
MTP::Sender _api;
mtpRequestId _requestId = 0;
std::unique_ptr<Core::CloudPasswordState> _state;

View File

@@ -83,7 +83,7 @@ MTPInputMedia PrepareUploadedPhoto(RemoteFileInfo info) {
MTP_flags(flags),
info.file,
MTP_vector<MTPInputDocument>(
ranges::to<QVector>(info.attachedStickers)),
ranges::to<QVector<MTPInputDocument>>(info.attachedStickers)),
MTP_int(0));
}
@@ -107,7 +107,7 @@ MTPInputMedia PrepareUploadedDocument(
MTP_string(document->mimeString()),
ComposeSendingDocumentAttributes(document),
MTP_vector<MTPInputDocument>(
ranges::to<QVector>(info.attachedStickers)),
ranges::to<QVector<MTPInputDocument>>(info.attachedStickers)),
MTP_int(0));
}

View File

@@ -1393,6 +1393,18 @@ void EditNameBox::prepare() {
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
_first->customTab(true);
_last->customTab(true);
QObject::connect(
_first,
&Ui::InputField::tabbed,
[=] { _last->setFocus(); });
QObject::connect(
_last,
&Ui::InputField::tabbed,
[=] { _first->setFocus(); });
}
void EditNameBox::setInnerFocus() {

View File

@@ -602,6 +602,9 @@ changePhoneError: FlatLabel(changePhoneLabel) {
textFg: boxTextFgError;
}
blockedUsersListSubtitleAddPadding: margins(0px, 1px, 0px, -14px);
blockedUsersListIconPadding: margins(0px, 34px, 0px, 5px);
adminLogFilterUserpicLeft: 15px;
adminLogFilterLittleSkip: 16px;
adminLogFilterCheckbox: Checkbox(defaultBoxCheckbox) {

View File

@@ -510,7 +510,7 @@ void ChangePhone::setupContent() {
}
void ChangePhone::showFinished() {
_animate();
_animate(anim::repeat::loop);
}
} // namespace Settings

View File

@@ -36,7 +36,7 @@ private:
void setupContent();
const not_null<Window::SessionController*> _controller;
Fn<void()> _animate;
Fn<void(anim::repeat)> _animate;
};

View File

@@ -15,7 +15,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/filter_icons.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h" // Ui::Text::Bold
#include "ui/toast/toast.h"
#include "ui/widgets/buttons.h"
@@ -27,46 +26,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
class FolderButton : public Ui::SettingsButton {
public:
FolderButton(
not_null<Ui::RpWidget*> parent,
const Data::ChatFilter &filter);
protected:
void paintEvent(QPaintEvent *e) override;
private:
const Ui::FilterIcon _icon;
};
FolderButton::FolderButton(
not_null<Ui::RpWidget*> parent,
const Data::ChatFilter &filter)
: SettingsButton(
parent,
rpl::single(filter.title()),
st::paymentsSectionButton)
, _icon(Ui::ComputeFilterIcon(filter)) {
}
void FolderButton::paintEvent(QPaintEvent *e) {
SettingsButton::paintEvent(e);
Painter p(this);
const auto over = isOver() || isDown();
const auto icon = Ui::LookupFilterIcon(_icon).normal;
icon->paint(
p,
st::settingsFilterIconLeft,
(height() - icon->height()) / 2,
width(),
(over
? st::dialogsUnreadBgMutedOver
: st::dialogsUnreadBgMuted)->c);
}
Data::ChatFilter ChangedFilter(
const Data::ChatFilter &filter,
not_null<History*> history,
@@ -165,47 +124,6 @@ void ChooseFilterValidator::remove(FilterId filterId) const {
ChangeFilterById(filterId, _history, false);
}
void ChooseFilterBox(
not_null<Ui::GenericBox*> box,
not_null<History*> history) {
box->setTitle(tr::lng_filters_add_box_title());
const auto validator = ChooseFilterValidator(history);
const auto container = box->verticalLayout()->add(
object_ptr<Ui::VerticalLayout>(box->verticalLayout()));
const auto rebuild = [=] {
while (container->count()) {
delete container->widgetAt(0);
}
for (const auto &filter : history->owner().chatsFilters().list()) {
if (filter.contains(history)) {
continue;
}
container->add(
object_ptr<FolderButton>(box, filter),
style::margins()
)->setClickedCallback([=, id = filter.id()] {
validator.add(id);
box->closeBox();
});
}
container->resizeToWidth(box->verticalLayout()->width());
if (!container->count()) {
box->closeBox();
}
};
history->owner().chatsFilters().changed(
) | rpl::start_with_next([=] {
rebuild();
}, box->lifetime());
rebuild();
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
}
void FillChooseFilterMenu(
not_null<Ui::PopupMenu*> menu,
not_null<History*> history) {

View File

@@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
namespace Ui {
class GenericBox;
class PopupMenu;
} // namespace Ui
@@ -29,10 +28,6 @@ private:
};
void ChooseFilterBox(
not_null<Ui::GenericBox*> box,
not_null<History*> history);
void FillChooseFilterMenu(
not_null<Ui::PopupMenu*> menu,
not_null<History*> history);

View File

@@ -500,6 +500,7 @@ void EditFilterBox(
const Data::ChatFilter &filter,
Fn<void(const Data::ChatFilter &)> doneCallback) {
const auto creating = filter.title().isEmpty();
box->setWidth(st::boxWideWidth);
box->setTitle(creating ? tr::lng_filters_new() : tr::lng_filters_edit());
box->setCloseByOutsideClick(false);
@@ -571,8 +572,9 @@ void EditFilterBox(
const auto includeAdd = AddButton(
content,
tr::lng_filters_add_chats() | Ui::Text::ToUpper(),
st::settingsUpdate);
tr::lng_filters_add_chats(),
st::settingsButtonActive,
{ &st::settingsIconAdd, 0, IconType::Round, &st::windowBgActive });
const auto include = SetupChatsPreview(
content,
@@ -582,21 +584,16 @@ void EditFilterBox(
&Data::ChatFilter::always);
AddSkip(content);
content->add(
object_ptr<Ui::FlatLabel>(
content,
tr::lng_filters_include_about(),
st::boxDividerLabel),
st::windowFilterAboutPadding);
AddDivider(content);
AddDividerText(content, tr::lng_filters_include_about());
AddSkip(content);
AddSubsectionTitle(content, tr::lng_filters_exclude());
const auto excludeAdd = AddButton(
content,
tr::lng_filters_remove_chats() | Ui::Text::ToUpper(),
st::settingsUpdate);
tr::lng_filters_remove_chats(),
st::settingsButtonActive,
{ &st::settingsIconRemove, 0, IconType::Round, &st::windowBgActive });
const auto exclude = SetupChatsPreview(
content,
@@ -606,12 +603,7 @@ void EditFilterBox(
&Data::ChatFilter::never);
AddSkip(content);
content->add(
object_ptr<Ui::FlatLabel>(
content,
tr::lng_filters_exclude_about(),
st::boxDividerLabel),
st::windowFilterAboutPadding);
AddDividerText(content, tr::lng_filters_exclude_about());
const auto refreshPreviews = [=] {
include->updateData(

View File

@@ -154,9 +154,10 @@ void StartPendingReset(
PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
const Core::CloudPasswordState &current) {
auto result = CloudFields();
result.curRequest = current.request;
result.newAlgo = current.newPassword;
result.newSecureSecretAlgo = current.newSecureSecret;
result.hasPassword = current.hasPassword;
result.mtp.curRequest = current.mtp.request;
result.mtp.newAlgo = current.mtp.newPassword;
result.mtp.newSecureSecretAlgo = current.mtp.newSecureSecret;
result.hasRecovery = current.hasRecovery;
result.notEmptyPassport = current.notEmptyPassport;
result.hint = current.hint;
@@ -200,21 +201,21 @@ PasscodeBox::PasscodeBox(
, _newPasscode(
this,
st::defaultInputField,
(fields.curRequest
(fields.hasPassword
? tr::lng_cloud_password_enter_new()
: tr::lng_cloud_password_enter_first()))
, _reenterPasscode(this, st::defaultInputField, tr::lng_cloud_password_confirm_new())
, _passwordHint(
this,
st::defaultInputField,
(fields.curRequest
(fields.hasPassword
? tr::lng_cloud_password_change_hint()
: tr::lng_cloud_password_hint()))
, _recoverEmail(this, st::defaultInputField, tr::lng_cloud_password_email())
, _recover(this, tr::lng_signin_recover(tr::now))
, _showRecoverLink(_cloudFields.hasRecovery || !_cloudFields.pendingResetDate) {
Expects(session != nullptr || !fields.fromRecoveryCode.isEmpty());
Expects(!_turningOff || _cloudFields.curRequest);
Expects(!_turningOff || _cloudFields.hasPassword);
if (!_cloudFields.hint.isEmpty()) {
_hintText.setText(
@@ -248,7 +249,7 @@ rpl::producer<MTPauth_Authorization> PasscodeBox::newAuthorization() const {
bool PasscodeBox::currentlyHave() const {
return _cloudPwd
? (!!_cloudFields.curRequest)
? _cloudFields.hasPassword
: _session->domain().local().hasLocalPasscode();
}
@@ -609,7 +610,7 @@ void PasscodeBox::handleSrpIdInvalid() {
const auto now = crl::now();
if (_lastSrpIdInvalidTime > 0
&& now - _lastSrpIdInvalidTime < Core::kHandleSrpIdInvalidTimeout) {
_cloudFields.curRequest.id = 0;
_cloudFields.mtp.curRequest.id = 0;
_oldError = Lang::Hard::ServerError();
update();
} else {
@@ -743,14 +744,14 @@ void PasscodeBox::checkPassword(
CheckPasswordCallback callback) {
const auto passwordUtf = oldPassword.toUtf8();
_checkPasswordHash = Core::ComputeCloudPasswordHash(
_cloudFields.curRequest.algo,
_cloudFields.mtp.curRequest.algo,
bytes::make_span(passwordUtf));
checkPasswordHash(std::move(callback));
}
void PasscodeBox::checkPasswordHash(CheckPasswordCallback callback) {
_checkPasswordCallback = std::move(callback);
if (_cloudFields.curRequest.id) {
if (_cloudFields.mtp.curRequest.id) {
passwordChecked();
} else {
requestPasswordData();
@@ -758,16 +759,16 @@ void PasscodeBox::checkPasswordHash(CheckPasswordCallback callback) {
}
void PasscodeBox::passwordChecked() {
if (!_cloudFields.curRequest || !_cloudFields.curRequest.id || !_checkPasswordCallback) {
if (!_cloudFields.mtp.curRequest || !_cloudFields.mtp.curRequest.id || !_checkPasswordCallback) {
return serverError();
}
const auto check = Core::ComputeCloudPasswordCheck(
_cloudFields.curRequest,
_cloudFields.mtp.curRequest,
_checkPasswordHash);
if (!check) {
return serverError();
}
_cloudFields.curRequest.id = 0;
_cloudFields.mtp.curRequest.id = 0;
_checkPasswordCallback(check);
}
@@ -782,7 +783,7 @@ void PasscodeBox::requestPasswordData() {
).done([=](const MTPaccount_Password &result) {
_setRequest = 0;
result.match([&](const MTPDaccount_password &data) {
_cloudFields.curRequest = Core::ParseCloudPasswordCheckRequest(data);
_cloudFields.mtp.curRequest = Core::ParseCloudPasswordCheckRequest(data);
passwordChecked();
});
}).send();
@@ -820,7 +821,7 @@ void PasscodeBox::sendClearCloudPassword(
check.result,
MTP_account_passwordInputSettings(
MTP_flags(flags),
Core::PrepareCloudPasswordAlgo(_cloudFields.newAlgo),
Core::PrepareCloudPasswordAlgo(_cloudFields.mtp.newAlgo),
MTP_bytes(), // new_password_hash
MTP_string(hint),
MTP_string(email),
@@ -835,7 +836,7 @@ void PasscodeBox::sendClearCloudPassword(
void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
const auto newPasswordBytes = newPassword.toUtf8();
const auto newPasswordHash = Core::ComputeCloudPasswordDigest(
_cloudFields.newAlgo,
_cloudFields.mtp.newAlgo,
bytes::make_span(newPasswordBytes));
if (newPasswordHash.modpow.empty()) {
return serverError();
@@ -851,7 +852,7 @@ void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
const auto settings = MTP_account_passwordInputSettings(
MTP_flags(flags),
Core::PrepareCloudPasswordAlgo(_cloudFields.newAlgo),
Core::PrepareCloudPasswordAlgo(_cloudFields.mtp.newAlgo),
MTP_bytes(newPasswordHash.modpow),
MTP_string(hint),
MTP_string(email),
@@ -989,7 +990,7 @@ void PasscodeBox::sendChangeCloudPassword(
const QByteArray &secureSecret) {
const auto newPasswordBytes = newPassword.toUtf8();
const auto newPasswordHash = Core::ComputeCloudPasswordDigest(
_cloudFields.newAlgo,
_cloudFields.mtp.newAlgo,
bytes::make_span(newPasswordBytes));
if (newPasswordHash.modpow.empty()) {
return serverError();
@@ -1007,19 +1008,19 @@ void PasscodeBox::sendChangeCloudPassword(
newSecureSecret = Passport::EncryptSecureSecret(
bytes::make_span(secureSecret),
Core::ComputeSecureSecretHash(
_cloudFields.newSecureSecretAlgo,
_cloudFields.mtp.newSecureSecretAlgo,
bytes::make_span(newPasswordBytes)));
}
_setRequest = _api.request(MTPaccount_UpdatePasswordSettings(
check.result,
MTP_account_passwordInputSettings(
MTP_flags(flags),
Core::PrepareCloudPasswordAlgo(_cloudFields.newAlgo),
Core::PrepareCloudPasswordAlgo(_cloudFields.mtp.newAlgo),
MTP_bytes(newPasswordHash.modpow),
MTP_string(hint),
MTPstring(), // email is not changing
MTP_secureSecretSettings(
Core::PrepareSecureSecretAlgo(_cloudFields.newSecureSecretAlgo),
Core::PrepareSecureSecretAlgo(_cloudFields.mtp.newSecureSecretAlgo),
MTP_bytes(newSecureSecret),
MTP_long(newSecureSecretId)))
)).done([=] {
@@ -1294,7 +1295,8 @@ void RecoverBox::proceedToChange(const QString &code) {
fields.hasRecovery = false;
// we could've been turning off, no need to force new password then
// like if (_cloudFields.turningOff) { just RecoverPassword else Check }
fields.curRequest = {};
fields.mtp.curRequest = {};
fields.hasPassword = false;
auto box = Box<PasscodeBox>(_session, fields);
box->boxClosing(

View File

@@ -36,13 +36,17 @@ public:
struct CloudFields {
static CloudFields From(const Core::CloudPasswordState &current);
Core::CloudPasswordCheckRequest curRequest;
Core::CloudPasswordAlgo newAlgo;
struct Mtp {
Core::CloudPasswordCheckRequest curRequest;
Core::CloudPasswordAlgo newAlgo;
Core::SecureSecretAlgo newSecureSecretAlgo;
};
Mtp mtp;
bool hasPassword = false;
bool hasRecovery = false;
QString fromRecoveryCode;
bool notEmptyPassport = false;
QString hint;
Core::SecureSecretAlgo newSecureSecretAlgo;
bool turningOff = false;
TimeId pendingResetDate = 0;

View File

@@ -544,38 +544,36 @@ object_ptr<Ui::RpWidget> Controller::createStickersEdit() {
Expects(_wrap != nullptr);
const auto channel = _peer->asChannel();
const auto bottomSkip = st::editPeerTopButtonsLayoutSkipCustomBottom;
auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_wrap,
object_ptr<Ui::VerticalLayout>(_wrap),
st::editPeerInvitesMargins);
object_ptr<Ui::VerticalLayout>(_wrap));
const auto container = result->entity();
container->add(object_ptr<Ui::FlatLabel>(
Settings::AddSubsectionTitle(
container,
tr::lng_group_stickers(),
st::editPeerSectionLabel));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerInviteLinkSkip));
{ 0, st::settingsSubsectionTitlePadding.top() - bottomSkip, 0, 0 });
container->add(object_ptr<Ui::FlatLabel>(
AddButtonWithCount(
container,
tr::lng_group_stickers_description(),
st::editPeerPrivacyLabel));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerInviteLinkSkip));
tr::lng_group_stickers_add(),
rpl::single(QString()), //Empty count.
[=, controller = _navigation->parentController()] {
controller->show(
Box<StickersBox>(controller, channel),
Ui::LayerOption::KeepOther);
},
{ &st::settingsIconStickers, Settings::kIconLightOrange });
container->add(object_ptr<Ui::LinkButton>(
_wrap,
tr::lng_group_stickers_add(tr::now),
st::editPeerInviteLinkButton)
)->addClickHandler([=] {
_navigation->parentController()->show(
Box<StickersBox>(_navigation->parentController(), channel),
Ui::LayerOption::KeepOther);
});
Settings::AddSkip(container, bottomSkip);
Settings::AddDividerText(
container,
tr::lng_group_stickers_description());
Settings::AddSkip(container, bottomSkip);
return result;
}
@@ -707,6 +705,9 @@ void Controller::fillPrivacyTypeButton() {
_noForwardsSavedValue = !_peer->allowsForwarding();
const auto isGroup = (_peer->isChat() || _peer->isMegagroup());
const auto icon = isGroup
? &st::settingsIconGroup
: &st::settingsIconChannel;
AddButtonWithText(
_controls.buttonsLayout,
(hasLocation
@@ -729,7 +730,7 @@ void Controller::fillPrivacyTypeButton() {
: tr::lng_manage_private_peer_title)();
}) | rpl::flatten_latest(),
[=] { showEditPeerTypeBox(); },
{ &st::infoIconGroupType, Settings::kIconLightBlue });
{ icon, Settings::kIconLightBlue });
_privacyTypeUpdates.fire_copy(*_privacySavedValue);
}
@@ -803,7 +804,7 @@ void Controller::fillSignaturesButton() {
tr::lng_edit_sign_messages(),
rpl::single(QString()),
[] {},
{ &st::infoIconSignature, Settings::kIconLightBlue }
{ &st::infoRoundedIconSignature, Settings::kIconLightBlue }
)->toggleOn(rpl::single(channel->addsSignature())
)->toggledValue(
) | rpl::start_with_next([=](bool toggled) {
@@ -1008,7 +1009,7 @@ void Controller::fillManageSection() {
*Data::PeerAllowedReactions(_peer),
done));
},
{ &st::infoIconReactions, Settings::kIconRed });
{ &st::infoRoundedIconReactions, Settings::kIconRed });
}
if (canEditPermissions) {
AddButtonWithCount(
@@ -1057,7 +1058,7 @@ void Controller::fillManageSection() {
0),
Ui::LayerOption::KeepOther);
},
{ &st::infoIconInviteLinks, Settings::kIconLightOrange });
{ &st::infoRoundedIconInviteLinks, Settings::kIconLightOrange });
if (_privacySavedValue) {
_privacyTypeUpdates.events_starting_with_copy(
@@ -1085,7 +1086,7 @@ void Controller::fillManageSection() {
_peer,
ParticipantsBoxController::Role::Admins);
},
{ &st::infoIconAdministrators, Settings::kIconLightBlue });
{ &st::infoRoundedIconAdministrators, Settings::kIconLightBlue });
}
if (canViewMembers) {
AddButtonWithCount(
@@ -1134,7 +1135,7 @@ void Controller::fillManageSection() {
tr::lng_manage_peer_recent_actions(),
rpl::single(QString()), //Empty count.
std::move(callback),
{ &st::infoIconRecentActions, Settings::kIconPurple });
{ &st::infoRoundedIconRecentActions, Settings::kIconPurple });
}
if (canEditStickers || canDeleteChannel) {
@@ -1176,7 +1177,7 @@ void Controller::fillPendingRequestsButton() {
: tr::lng_manage_peer_requests_channel()),
rpl::duplicate(pendingRequestsCount) | ToPositiveNumberString(),
[=] { RequestsBoxController::Start(_navigation, _peer); },
{ &st::infoIconRequests, Settings::kIconRed });
{ &st::infoRoundedIconRequests, Settings::kIconRed });
std::move(
pendingRequestsCount
) | rpl::start_with_next([=](int count) {

View File

@@ -18,7 +18,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "ui/layers/generic_box.h"
#include "ui/widgets/buttons.h"
#include "info/profile/info_profile_icon.h"
#include "settings/settings_common.h"
#include "styles/style_settings.h"
#include "styles/style_info.h"
@@ -29,6 +28,7 @@ void EditAllowedReactionsBox(
const std::vector<Data::Reaction> &list,
const base::flat_set<QString> &selected,
Fn<void(const std::vector<QString> &)> callback) {
const auto iconHeight = st::editPeerReactionsPreview;
box->setTitle(tr::lng_manage_peer_reactions());
struct State {
@@ -57,10 +57,21 @@ void EditAllowedReactionsBox(
container,
tr::lng_manage_peer_reactions_enable(),
st::manageGroupButton.button);
Ui::CreateChild<Info::Profile::FloatingIcon>(
enabled.get(),
st::infoIconReactions,
st::manageGroupButton.iconPosition);
if (!list.empty()) {
AddReactionLottieIcon(
enabled,
enabled->sizeValue(
) | rpl::map([=](const QSize &size) {
return QPoint(
st::manageGroupButton.iconPosition.x(),
(size.height() - iconHeight) / 2);
}),
iconHeight,
list.front(),
rpl::never<>(),
rpl::never<>(),
&enabled->lifetime());
}
enabled->toggleOn(state->anyToggled.value());
enabled->toggledChanges(
) | rpl::filter([=](bool value) {
@@ -87,7 +98,6 @@ void EditAllowedReactionsBox(
container,
rpl::single(entry.title),
st::manageGroupButton.button);
const auto iconHeight = st::editPeerReactionsPreview;
AddReactionLottieIcon(
button,
button->sizeValue(
@@ -138,7 +148,7 @@ void SaveAllowedReactions(
const std::vector<QString> &allowed) {
auto ids = allowed | ranges::views::transform([=](QString value) {
return MTP_string(value);
}) | ranges::to<QVector>;
}) | ranges::to<QVector<MTPstring>>;
peer->session().api().request(MTPmessages_SetChatAvailableReactions(
peer->input,

View File

@@ -199,7 +199,7 @@ void Controller::createContent() {
Ui::LayerOption::KeepOther);
},
st::manageGroupButton,
{ &st::infoIconInviteLinks, Settings::kIconLightOrange }));
{ &st::infoRoundedIconInviteLinks, Settings::kIconLightOrange }));
AddSkip(_wrap.get());
AddDividerText(_wrap.get(), tr::lng_group_invite_manage_about());

View File

@@ -89,12 +89,13 @@ AdminLog::OwnedItem GenerateItem(
}
void AddMessage(
not_null<Ui::GenericBox*> box,
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller,
rpl::producer<QString> &&emojiValue) {
rpl::producer<QString> &&emojiValue,
int width) {
const auto widget = box->addRow(
object_ptr<Ui::RpWidget>(box),
const auto widget = container->add(
object_ptr<Ui::RpWidget>(container),
style::margins(
0,
st::settingsSectionSkip,
@@ -121,7 +122,7 @@ void AddMessage(
bool flag = false;
} icons;
};
const auto state = box->lifetime().make_state<State>();
const auto state = container->lifetime().make_state<State>();
state->delegate = std::make_unique<Delegate>(
controller,
crl::guard(widget, [=] { widget->update(); }));
@@ -150,16 +151,18 @@ void AddMessage(
const auto padding = st::settingsForwardPrivacyPadding;
widget->widthValue(
) | rpl::filter(
rpl::mappers::_1 >= (st::historyMinimalWidth / 2)
) | rpl::start_with_next([=](int width) {
const auto updateWidgetSize = [=](int width) {
const auto height = view->resizeGetHeight(width);
const auto top = view->marginTop();
const auto bottom = view->marginBottom();
const auto full = padding + top + height + bottom + padding;
widget->resize(width, full);
}, widget->lifetime());
};
widget->widthValue(
) | rpl::filter(
rpl::mappers::_1 >= (st::historyMinimalWidth / 2)
) | rpl::start_with_next(updateWidgetSize, widget->lifetime());
updateWidgetSize(width);
const auto rightSize = st::settingsReactionCornerSize;
const auto rightRect = [=] {
@@ -224,7 +227,7 @@ void AddMessage(
const auto index = state->icons.flag ? 1 : 0;
state->icons.lifetimes[index] = rpl::lifetime();
AddReactionLottieIcon(
box->verticalLayout(),
container,
widget->geometryValue(
) | rpl::map([=](const QRect &r) {
return widget->pos()
@@ -388,34 +391,19 @@ void ReactionsSettingsBox(
const auto state = box->lifetime().make_state<State>();
state->selectedEmoji = reactions.favorite();
AddMessage(box, controller, state->selectedEmoji.value());
const auto pinnedToTop = box->setPinnedToTopContent(
object_ptr<Ui::VerticalLayout>(box));
auto emojiValue = state->selectedEmoji.value();
AddMessage(pinnedToTop, controller, std::move(emojiValue), box->width());
const auto container = box->verticalLayout();
Settings::AddSubsectionTitle(
container,
pinnedToTop,
tr::lng_settings_chat_reactions_subtitle());
const auto &stButton = st::settingsButton;
const auto scrollContainer = box->addRow(
object_ptr<Ui::FixedHeightWidget>(
box,
kVisibleButtonsCount
* (stButton.height
+ stButton.padding.top()
+ stButton.padding.bottom())),
style::margins());
const auto scroll = Ui::CreateChild<Ui::ScrollArea>(
scrollContainer,
st::boxScroll);
const auto buttonsContainer = scroll->setOwnedWidget(
object_ptr<Ui::VerticalLayout>(scroll));
scrollContainer->sizeValue(
) | rpl::start_with_next([=](const QSize &s) {
scroll->resize(s.width(), s.height());
buttonsContainer->resizeToWidth(s.width());
}, scroll->lifetime());
const auto container = box->verticalLayout();
const auto check = Ui::CreateChild<Ui::RpWidget>(buttonsContainer.data());
const auto check = Ui::CreateChild<Ui::RpWidget>(container.get());
check->resize(st::settingsReactionCornerSize);
check->setAttribute(Qt::WA_TransparentForMouseEvents);
check->paintRequest(
@@ -432,9 +420,9 @@ void ReactionsSettingsBox(
auto firstCheckedButton = (Ui::RpWidget*)(nullptr);
for (const auto &r : reactions.list(Data::Reactions::Type::Active)) {
const auto button = Settings::AddButton(
buttonsContainer,
container,
rpl::single<QString>(base::duplicate(r.title)),
stButton);
st::settingsButton);
const auto iconSize = st::settingsReactionSize;
AddReactionLottieIcon(
@@ -472,11 +460,6 @@ void ReactionsSettingsBox(
}
check->raise();
Ui::SetupShadowsToScrollContent(
scrollContainer,
scroll,
buttonsContainer->heightValue());
box->setTitle(tr::lng_settings_chat_reactions_title());
box->setWidth(st::boxWideWidth);
box->addButton(tr::lng_settings_save(), [=] {

View File

@@ -39,7 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_menu_icons.h"
#include "styles/style_boxes.h"
#include "styles/style_layers.h"
#include "styles/style_window.h"
#include "styles/style_settings.h"
namespace {
@@ -276,7 +276,7 @@ void RingtonesBox(
tr::lng_ringtones_box_upload_button(),
st::ringtonesBoxButton,
{
&st::mainMenuAddAccount,
&st::settingsIconAdd,
0,
Settings::IconType::Round,
&st::windowBgActive

View File

@@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace tgcalls {
class InstanceImpl;
class InstanceV2Impl;
class InstanceV2ReferenceImpl;
class InstanceV2_4_0_0Impl;
class InstanceImplLegacy;
void SetLegacyGlobalServerConfig(const std::string &serverConfig);
@@ -53,14 +54,28 @@ const auto kDefaultVersion = "2.4.4"_q;
const auto Register = tgcalls::Register<tgcalls::InstanceImpl>();
const auto RegisterV2 = tgcalls::Register<tgcalls::InstanceV2Impl>();
const auto RegV2Ref = tgcalls::Register<tgcalls::InstanceV2ReferenceImpl>();
const auto RegisterV240 = tgcalls::Register<tgcalls::InstanceV2_4_0_0Impl>();
const auto RegisterLegacy = tgcalls::Register<tgcalls::InstanceImplLegacy>();
[[nodiscard]] base::flat_set<int64> CollectEndpointIds(
const QVector<MTPPhoneConnection> &list) {
auto result = base::flat_set<int64>();
result.reserve(list.size());
for (const auto &connection : list) {
connection.match([&](const MTPDphoneConnection &data) {
result.emplace(int64(data.vid().v));
}, [](const MTPDphoneConnectionWebrtc &) {
});
}
return result;
}
void AppendEndpoint(
std::vector<tgcalls::Endpoint> &list,
const MTPPhoneConnection &connection) {
connection.match([&](const MTPDphoneConnection &data) {
if (data.vpeer_tag().v.length() != 16) {
if (data.vpeer_tag().v.length() != 16 || data.is_tcp()) {
return;
}
tgcalls::Endpoint endpoint = {
@@ -82,8 +97,41 @@ void AppendEndpoint(
void AppendServer(
std::vector<tgcalls::RtcServer> &list,
const MTPPhoneConnection &connection) {
const MTPPhoneConnection &connection,
const base::flat_set<int64> &ids) {
connection.match([&](const MTPDphoneConnection &data) {
const auto hex = [](const QByteArray &value) {
const auto digit = [](uchar c) {
return char((c < 10) ? ('0' + c) : ('a' + c - 10));
};
auto result = std::string();
result.reserve(value.size() * 2);
for (const auto ch : value) {
result += digit(uchar(ch) / 16);
result += digit(uchar(ch) % 16);
}
return result;
};
const auto host = data.vip().v;
const auto hostv6 = data.vipv6().v;
const auto port = uint16_t(data.vport().v);
const auto username = std::string("reflector");
const auto password = hex(data.vpeer_tag().v);
const auto i = ids.find(int64(data.vid().v));
Assert(i != end(ids));
const auto id = uint8_t((i - begin(ids)) + 1);
const auto pushTurn = [&](const QString &host) {
list.push_back(tgcalls::RtcServer{
.id = id,
.host = host.toStdString(),
.port = port,
.login = username,
.password = password,
.isTurn = true,
});
};
pushTurn(host);
pushTurn(hostv6);
}, [&](const MTPDphoneConnectionWebrtc &data) {
const auto host = qs(data.vip());
const auto hostv6 = qs(data.vipv6());
@@ -780,10 +828,20 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
kAuthKeySize>>();
memcpy(encryptionKeyValue->data(), _authKey.data(), kAuthKeySize);
const auto &settings = Core::App().settings();
const auto version = call.vprotocol().match([&](
const MTPDphoneCallProtocol &data) {
return data.vlibrary_versions().v;
}).value(0, MTP_bytes(kDefaultVersion)).v;
LOG(("Call Info: Creating instance with version '%1', allowP2P: %2").arg(
QString::fromUtf8(version),
Logs::b(call.is_p2p_allowed())));
const auto versionString = version.toStdString();
const auto &settings = Core::App().settings();
const auto weak = base::make_weak(this);
tgcalls::Descriptor descriptor = {
.version = versionString,
.config = tgcalls::Config{
.initializationTimeout =
serverConfig.callConnectTimeoutMs / 1000.,
@@ -849,11 +907,12 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
QDir().mkpath(callLogFolder);
}
const auto ids = CollectEndpointIds(call.vconnections().v);
for (const auto &connection : call.vconnections().v) {
AppendEndpoint(descriptor.endpoints, connection);
}
for (const auto &connection : call.vconnections().v) {
AppendServer(descriptor.rtcServers, connection);
AppendServer(descriptor.rtcServers, connection, ids);
}
{
@@ -871,18 +930,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
}
}
}
const auto version = call.vprotocol().match([&](
const MTPDphoneCallProtocol &data) {
return data.vlibrary_versions().v;
}).value(0, MTP_bytes(kDefaultVersion)).v;
LOG(("Call Info: Creating instance with version '%1', allowP2P: %2").arg(
QString::fromUtf8(version),
Logs::b(descriptor.config.enableP2P)));
_instance = tgcalls::Meta::Create(
version.toStdString(),
std::move(descriptor));
_instance = tgcalls::Meta::Create(versionString, std::move(descriptor));
if (!_instance) {
LOG(("Call Error: Wrong library version: %1."
).arg(QString::fromUtf8(version)));

View File

@@ -46,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_instance.h"
#include "inline_bots/bot_attach_web_view.h"
#include "mainwidget.h"
#include "tray.h"
#include "core/file_utilities.h"
#include "core/click_handler_types.h" // ClickHandlerContext.
#include "core/crash_reports.h"
@@ -149,6 +150,7 @@ Application::Application(not_null<Launcher*> launcher)
, _langpack(std::make_unique<Lang::Instance>())
, _langCloudManager(std::make_unique<Lang::CloudManager>(langpack()))
, _emojiKeywords(std::make_unique<ChatHelpers::EmojiKeywords>())
, _tray(std::make_unique<Tray>())
, _autoLockTimer([=] { checkAutoLock(); }) {
Ui::Integration::Set(&_private->uiIntegration);
@@ -300,6 +302,8 @@ void Application::run() {
startShortcuts();
startDomain();
startTray();
_primaryWindow->widget()->show();
const auto currentGeometry = _primaryWindow->widget()->geometry();
@@ -409,6 +413,38 @@ void Application::startSystemDarkModeViewer() {
}, _lifetime);
}
void Application::startTray() {
using WindowRaw = not_null<Window::Controller*>;
const auto enumerate = [=](Fn<void(WindowRaw)> c) {
if (_primaryWindow) {
c(_primaryWindow.get());
}
for (const auto &window : ranges::views::values(_secondaryWindows)) {
c(window.get());
}
};
_tray->create();
_tray->aboutToShowRequests(
) | rpl::start_with_next([=] {
enumerate([&](WindowRaw w) { w->updateIsActive(); });
_tray->updateMenuText();
}, _primaryWindow->widget()->lifetime());
_tray->showFromTrayRequests(
) | rpl::start_with_next([=] {
const auto last = _lastActiveWindow;
enumerate([&](WindowRaw w) { w->widget()->showFromTray(); });
if (last) {
last->widget()->showFromTray();
}
}, _primaryWindow->widget()->lifetime());
_tray->hideToTrayRequests(
) | rpl::start_with_next([=] {
enumerate([&](WindowRaw w) { w->widget()->minimizeToTray(); });
}, _primaryWindow->widget()->lifetime());
}
auto Application::prepareEmojiSourceImages()
-> std::shared_ptr<Ui::Emoji::UniversalImages> {
const auto &images = Ui::Emoji::SourceImages();
@@ -427,6 +463,16 @@ void Application::clearEmojiSourceImages() {
});
}
bool Application::isActiveForTrayMenu() const {
if (_primaryWindow && _primaryWindow->widget()->isActiveForTrayMenu()) {
return true;
}
return ranges::any_of(ranges::views::values(_secondaryWindows), [=](
const std::unique_ptr<Window::Controller> &controller) {
return controller->widget()->isActiveForTrayMenu();
});
}
bool Application::hideMediaView() {
if (_mediaView && !_mediaView->isHidden()) {
_mediaView->hide();

View File

@@ -103,6 +103,7 @@ namespace Core {
class Launcher;
struct LocalUrlHandler;
class Tray;
enum class LaunchState {
Running,
@@ -147,6 +148,9 @@ public:
[[nodiscard]] Data::DownloadManager &downloadManager() const {
return *_downloadManager;
}
[[nodiscard]] Tray &tray() const {
return *_tray;
}
// Windows interface.
bool hasActiveWindow(not_null<Main::Session*> session) const;
@@ -163,6 +167,7 @@ public:
[[nodiscard]] QWidget *getFileDialogParent();
void notifyFileDialogShown(bool shown);
void checkSystemDarkMode();
[[nodiscard]] bool isActiveForTrayMenu() const;
// Media view interface.
void checkMediaViewActivation();
@@ -316,6 +321,7 @@ private:
void startDomain();
void startEmojiImageLoader();
void startSystemDarkModeViewer();
void startTray();
friend void QuitAttempt();
void quitDelayed();
@@ -376,6 +382,8 @@ private:
std::unique_ptr<Lang::Translator> _translator;
QPointer<Ui::BoxContent> _badProxyDisableBox;
const std::unique_ptr<Tray> _tray;
std::unique_ptr<Media::Player::FloatController> _floatPlayers;
Media::Player::FloatDelegate *_defaultFloatPlayerDelegate = nullptr;
Media::Player::FloatDelegate *_replacementFloatPlayerDelegate = nullptr;

View File

@@ -121,6 +121,14 @@ std::map<int, const char*> BetaLogs() {
"- Fix group and channel photo upload.\n"
"- Test hardware video decoding.\n"
},
{
3007004,
"- More icons for chat folders.\n"
"- Improve some more sections design.\n"
"- Update the OpenAL library to 1.22.0.\n"
}
};
};

View File

@@ -303,18 +303,53 @@ bytes::vector ComputeSecureSecretHash(
CloudPasswordState ParseCloudPasswordState(
const MTPDaccount_password &data) {
auto result = CloudPasswordState();
result.request = ParseCloudPasswordCheckRequest(data);
result.unknownAlgorithm = data.vcurrent_algo() && !result.request;
result.mtp.request = ParseCloudPasswordCheckRequest(data);
result.hasPassword = (!!result.mtp.request);
result.mtp.unknownAlgorithm = data.vcurrent_algo() && !result.hasPassword;
result.hasRecovery = data.is_has_recovery();
result.notEmptyPassport = data.is_has_secure_values();
result.hint = qs(data.vhint().value_or_empty());
result.newPassword = ValidateNewCloudPasswordAlgo(
result.mtp.newPassword = ValidateNewCloudPasswordAlgo(
ParseCloudPasswordAlgo(data.vnew_algo()));
result.newSecureSecret = ValidateNewSecureSecretAlgo(
result.mtp.newSecureSecret = ValidateNewSecureSecretAlgo(
ParseSecureSecretAlgo(data.vnew_secure_algo()));
result.unconfirmedPattern =
qs(data.vemail_unconfirmed_pattern().value_or_empty());
result.pendingResetDate = data.vpending_reset_date().value_or_empty();
result.outdatedClient = [&] {
const auto badSecureAlgo = data.vnew_secure_algo().match([](
const MTPDsecurePasswordKdfAlgoUnknown &) {
return true;
}, [](const auto &) {
return false;
});
if (badSecureAlgo) {
return true;
}
if (data.vcurrent_algo()) {
const auto badCurrentAlgo = data.vcurrent_algo()->match([](
const MTPDpasswordKdfAlgoUnknown &) {
return true;
}, [](const auto &) {
return false;
});
if (badCurrentAlgo) {
return true;
}
}
const auto badNewAlgo = data.vnew_algo().match([](
const MTPDpasswordKdfAlgoUnknown &) {
return true;
}, [](const auto &) {
return false;
});
if (badNewAlgo) {
return true;
}
return false;
}();
return result;
}

View File

@@ -122,13 +122,18 @@ bytes::vector ComputeSecureSecretHash(
bytes::const_span password);
struct CloudPasswordState {
CloudPasswordCheckRequest request;
bool unknownAlgorithm = false;
struct Mtp {
CloudPasswordCheckRequest request;
bool unknownAlgorithm = false;
CloudPasswordAlgo newPassword;
SecureSecretAlgo newSecureSecret;
};
Mtp mtp;
bool hasPassword = false;
bool hasRecovery = false;
bool notEmptyPassport = false;
bool outdatedClient = false;
QString hint;
CloudPasswordAlgo newPassword;
SecureSecretAlgo newSecureSecret;
QString unconfirmedPattern;
TimeId pendingResetDate = 0;
};

View File

@@ -44,17 +44,9 @@ PreLaunchWindow::PreLaunchWindow(QString title) {
p.setColor(QPalette::Window, QColor(255, 255, 255));
setPalette(p);
constexpr auto processDpi = [](const QDpi &dpi) {
return (dpi.first + dpi.second) * 0.5;
};
const auto screen = QGuiApplication::primaryScreen();
const auto scale = processDpi(screen->handle()->logicalDpi())
/ processDpi(screen->handle()->logicalBaseDpi());
auto font = QGuiApplication::font();
font.setPixelSize(base::SafeRound(font.pointSize() * scale));
const auto dpi = screen()->handle()->logicalDpi().second;
auto font = this->font();
font.setPixelSize(base::SafeRound(std::floor(font.pointSizeF() * dpi / 72. * 100. + 0.5) / 100.));
_size = QFontMetrics(font).height();
int paddingVertical = (_size / 2);
@@ -110,12 +102,12 @@ PreLaunchInput::PreLaunchInput(QWidget *parent, bool password) : QLineEdit(paren
setFont(logFont);
QPalette p(palette());
p.setColor(QPalette::Window, QColor(255, 255, 255));
p.setColor(QPalette::Base, QColor(255, 255, 255));
p.setColor(QPalette::WindowText, QColor(0, 0, 0));
p.setColor(QPalette::Text, QColor(0, 0, 0));
setPalette(p);
setStyleSheet("QLineEdit { background-color: white; }");
QLineEdit::setTextMargins(0, 0, 0, 0);
setContentsMargins(0, 0, 0, 0);
if (password) {

View File

@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/sticker_set_box.h"
#include "boxes/sessions_box.h"
#include "boxes/language_box.h"
#include "boxes/change_phone_box.h"
#include "passport/passport_form_controller.h"
#include "window/window_session_controller.h"
#include "ui/toast/toast.h"
@@ -40,6 +41,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "settings/settings_common.h"
#include "settings/settings_folders.h"
#include "settings/settings_main.h"
#include "settings/settings_privacy_security.h"
#include "settings/settings_chat.h"
#include "mainwidget.h"
#include "main/main_session.h"
#include "main/main_session_settings.h"
@@ -444,22 +447,30 @@ bool ResolveSettings(
}
controller->window().activate();
const auto section = match->captured(1).mid(1).toLower();
if (section.isEmpty()) {
controller->window().showSettings();
return true;
} else if (section == qstr("language")) {
ShowLanguagesBox();
return true;
} else if (section == qstr("devices")) {
controller->session().api().authorizations().reload();
const auto type = [&]() -> std::optional<::Settings::Type> {
if (section == qstr("language")) {
ShowLanguagesBox();
return {};
} else if (section == qstr("devices")) {
controller->session().api().authorizations().reload();
return ::Settings::Sessions::Id();
} else if (section == qstr("folders")) {
return ::Settings::Folders::Id();
} else if (section == qstr("privacy")) {
return ::Settings::PrivacySecurity::Id();
} else if (section == qstr("themes")) {
return ::Settings::Chat::Id();
} else if (section == qstr("change_number")) {
return ::Settings::ChangePhone::Id();
}
return ::Settings::Main::Id();
}();
if (type.has_value()) {
controller->showSettings(*type);
controller->window().activate();
}
const auto type = (section == qstr("folders"))
? ::Settings::Folders::Id()
: (section == qstr("devices"))
? ::Settings::Sessions::Id()
: ::Settings::Main::Id();
controller->showSettings(type);
controller->window().activate();
return true;
}
@@ -760,7 +771,7 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
ResolvePrivatePost
},
{
qsl("^settings(/folders|/devices|/language)?$"),
qsl("^settings(/language|/devices|/folders|/privacy|/themes|/change_number)?$"),
ResolveSettings
},
{

View File

@@ -324,6 +324,14 @@ QString UiIntegration::phraseFormattingSpoiler() {
return tr::lng_menu_formatting_spoiler(tr::now);
}
QString UiIntegration::phraseButtonOk() {
return tr::lng_box_ok(tr::now);
}
QString UiIntegration::phraseButtonCancel() {
return tr::lng_cancel(tr::now);
}
bool OpenGLLastCheckFailed() {
return QFile::exists(OpenGLCheckFilePath());
}

View File

@@ -71,6 +71,8 @@ public:
QString phraseFormattingStrikeOut() override;
QString phraseFormattingMonospace() override;
QString phraseFormattingSpoiler() override;
QString phraseButtonOk() override;
QString phraseButtonCancel() override;
};

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 = 3007002;
constexpr auto AppVersionStr = "3.7.2";
constexpr auto AppBetaVersion = false;
constexpr auto AppVersion = 3007005;
constexpr auto AppVersionStr = "3.7.5";
constexpr auto AppBetaVersion = true;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View File

@@ -1194,7 +1194,9 @@ bool DocumentData::hasRemoteLocation() const {
}
bool DocumentData::useStreamingLoader() const {
if (const auto info = sticker()) {
if (size <= 0) {
return false;
} else if (const auto info = sticker()) {
return info->isWebm();
}
return isAnimation()

View File

@@ -161,25 +161,7 @@ void NotifySettings::updateLocal(not_null<PeerData*> peer) {
} else {
_mutedPeers.erase(peer);
}
if (const auto sound = peer->notifySound(); sound && sound->id) {
if (const auto doc = _owner->document(sound->id); !doc->isNull()) {
cacheSound(doc);
} else {
_ringtones.pendingIds.push_back(sound->id);
if (!_ringtones.pendingLifetime) {
// Not requested yet.
_owner->session().api().ringtones().listUpdates(
) | rpl::start_with_next([=] {
for (const auto id : base::take(_ringtones.pendingIds)) {
cacheSound(id);
}
_ringtones.pendingLifetime.destroy();
}, _ringtones.pendingLifetime);
_owner->session().api().ringtones().requestList();
}
}
}
cacheSound(peer->notifySound());
}
void NotifySettings::cacheSound(DocumentId id) {
@@ -196,6 +178,28 @@ void NotifySettings::cacheSound(not_null<DocumentData*> document) {
document->save(Data::FileOriginRingtones(), QString());
}
void NotifySettings::cacheSound(const std::optional<NotifySound> &sound) {
if (!sound || !sound->id) {
return;
} else if (const auto doc = _owner->document(sound->id); !doc->isNull()) {
cacheSound(doc);
return;
}
_ringtones.pendingIds.push_back(sound->id);
if (_ringtones.pendingLifetime) {
return;
}
// Not requested yet.
_owner->session().api().ringtones().listUpdates(
) | rpl::start_with_next([=] {
for (const auto id : base::take(_ringtones.pendingIds)) {
cacheSound(id);
}
_ringtones.pendingLifetime.destroy();
}, _ringtones.pendingLifetime);
_owner->session().api().ringtones().requestList();
}
void NotifySettings::updateLocal(DefaultNotify type) {
defaultValue(type).updates.fire({});
@@ -220,6 +224,7 @@ void NotifySettings::updateLocal(DefaultNotify type) {
_owner->enumerateBroadcasts(callback);
break;
}
cacheSound(defaultValue(type).settings.sound());
}
std::shared_ptr<DocumentMedia> NotifySettings::lookupRingtone(

View File

@@ -71,6 +71,8 @@ private:
rpl::event_stream<> updates;
};
void cacheSound(const std::optional<NotifySound> &sound);
[[nodiscard]] bool isMuted(
not_null<const PeerData*> peer,
crl::time *changesIn) const;

View File

@@ -27,11 +27,6 @@ namespace {
constexpr auto kMaxBrush = 25.;
constexpr auto kMinBrush = 1.;
constexpr auto kViewStyle = "QGraphicsView {\
background-color: transparent;\
border: 0px\
}"_cs;
std::shared_ptr<Scene> EnsureScene(
PhotoModifications &mods,
const QSize &size) {
@@ -62,7 +57,8 @@ Paint::Paint(
_view->show();
_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_view->setStyleSheet(kViewStyle.utf8());
_view->setFrameStyle(int(QFrame::NoFrame) | QFrame::Plain);
_view->viewport()->setAutoFillBackground(false);
// Undo / Redo.
controllers->undoController->performRequestChanges(

View File

@@ -1243,6 +1243,11 @@ bool ListWidget::hasCopyRestrictionForSelected() const {
if (hasCopyRestriction()) {
return true;
}
if (_selected.empty()) {
if (_selectedTextItem && _selectedTextItem->forbidsForward()) {
return true;
}
}
for (const auto &[itemId, selection] : _selected) {
if (const auto item = session().data().message(itemId)) {
if (item->forbidsForward()) {
@@ -1254,6 +1259,11 @@ bool ListWidget::hasCopyRestrictionForSelected() const {
}
bool ListWidget::showCopyRestrictionForSelected() {
if (_selected.empty()) {
if (_selectedTextItem && showCopyRestriction(_selectedTextItem)) {
return true;
}
}
for (const auto &[itemId, selection] : _selected) {
if (showCopyRestriction(session().data().message(itemId))) {
return true;

View File

@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_pinned_tracker.h"
#include "history/history_item.h"
#include "history/history.h"
#include "base/weak_ptr.h"
#include "apiwrap.h"
#include "styles/style_chat.h"
@@ -163,27 +164,32 @@ rpl::producer<HistoryItem*> PinnedBarItemWithReplyMarkup(
consumer.put_next(nullptr);
struct State {
HistoryMessageReplyMarkup *previousReplyMarkup = nullptr;
bool hasReplyMarkup = false;
base::has_weak_ptr guard;
rpl::lifetime lifetime;
FullMsgId resolvedId;
};
const auto state = lifetime.make_state<State>();
const auto pushUnique = [=](not_null<HistoryItem*> item) {
const auto replyMarkup = item->inlineReplyMarkup();
if (state->previousReplyMarkup == replyMarkup) {
if (!state->hasReplyMarkup && !replyMarkup) {
return;
}
state->hasReplyMarkup = (replyMarkup != nullptr);
consumer.put_next(item.get());
state->previousReplyMarkup = replyMarkup;
};
rpl::duplicate(
id
) | rpl::start_with_next([=](PinnedId current) {
) | rpl::filter([=](PinnedId current) {
return current.message && (current.message != state->resolvedId);
}) | rpl::start_with_next([=](PinnedId current) {
const auto fullId = current.message;
if (!fullId) {
return;
}
state->lifetime.destroy();
state->resolvedId = fullId;
invalidate_weak_ptrs(&state->guard);
const auto messageFlag = [=](not_null<HistoryItem*> item) {
using Update = Data::MessageUpdate;
session->changes().messageFlagsValue(
@@ -195,12 +201,17 @@ rpl::producer<HistoryItem*> PinnedBarItemWithReplyMarkup(
};
if (const auto item = session->data().message(fullId)) {
messageFlag(item);
} else {
session->api().requestMessageData(
session->data().peer(fullId.peer),
fullId.msg,
[=] { messageFlag(session->data().message(fullId)); });
return;
}
const auto resolved = crl::guard(&state->guard, [=] {
if (const auto item = session->data().message(fullId)) {
messageFlag(item);
}
});
session->api().requestMessageData(
session->data().peer(fullId.peer),
fullId.msg,
resolved);
}, lifetime);
return lifetime;
});

View File

@@ -316,7 +316,7 @@ infoProfileSeparatorPadding: margins(
infoIconFg: windowBoldFg;
infoIconInformation: icon {{ "info/info_information", infoIconFg }};
infoIconRequests: icon {{ "info/info_add_member", infoIconFg }};
infoIconAddMember: icon {{ "info/info_add_member", infoIconFg }};
infoIconNotifications: icon {{ "info/info_notifications", infoIconFg }};
infoIconMediaPhoto: icon {{ "info/info_media_photo", infoIconFg }};
infoIconMediaVideo: icon {{ "info/info_media_video", infoIconFg }};
@@ -327,12 +327,14 @@ infoIconMediaLink: icon {{ "info/info_media_link", infoIconFg }};
infoIconMediaGroup: icon {{ "info/info_common_groups", infoIconFg }};
infoIconMediaVoice: icon {{ "info/info_media_voice", infoIconFg }};
infoIconMediaRound: icon {{ "info/info_media_round", infoIconFg }};
infoIconRecentActions: icon {{ "info/edit/group_manage_actions", settingsIconFg }};
infoIconAdministrators: icon {{ "info/edit/group_manage_admins", settingsIconFg }};
infoIconInviteLinks: icon {{ "info/edit/group_manage_links", settingsIconFg }};
infoIconReactions: icon {{ "info/edit/group_manage_reactions", settingsIconFg }};
infoIconGroupType: icon {{ "info/edit/group_manage_type", settingsIconFg }};
infoIconSignature: icon {{ "info/edit/channel_manage_signature", settingsIconFg }};
infoRoundedIconRequests: icon {{ "info/edit/group_manage_join_requests", settingsIconFg }};
infoRoundedIconRecentActions: icon {{ "info/edit/group_manage_actions", settingsIconFg }};
infoRoundedIconAdministrators: icon {{ "info/edit/group_manage_admins", settingsIconFg }};
infoRoundedIconInviteLinks: icon {{ "info/edit/group_manage_links", settingsIconFg }};
infoRoundedIconReactions: icon {{ "info/edit/group_manage_reactions", settingsIconFg }};
infoRoundedIconSignature: icon {{ "info/edit/channel_manage_signature", settingsIconFg }};
infoIconShare: icon {{ "info/info_share", infoIconFg }};
infoIconEdit: icon {{ "info/info_edit", infoIconFg }};
infoIconDelete: icon {{ "info/info_delete", infoIconFg }};
@@ -622,13 +624,6 @@ editPeerPrivacyBoxCheckbox: Checkbox(defaultBoxCheckbox) {
editPeerHistoryVisibilityLabelMargins: margins(34px, 0px, 48px, 0px);
editPeerPrivacyLabelMargins: margins(42px, 0px, 34px, 0px);
editPeerPreHistoryLabelMargins: margins(34px, 0px, 34px, 0px);
editPeerSectionLabel: FlatLabel(boxTitle) {
style: TextStyle(defaultTextStyle) {
font: font(15px semibold);
linkFont: font(15px semibold);
linkFontOver: font(15px semibold underline);
}
}
editPeerUsernameTitleLabelMargins: margins(22px, 17px, 22px, 10px);
editPeerUsernameFieldMargins: margins(22px, 0px, 22px, 20px);
editPeerUsername: setupChannelLink;
@@ -637,7 +632,6 @@ editPeerInviteLink: FlatLabel(defaultFlatLabel) {
minWidth: 1px; // for break everywhere
style: boxTextStyle;
}
editPeerInviteLinkButton: boxLinkButton;
editPeerUsernameGood: FlatLabel(defaultFlatLabel) {
textFg: boxTextFgGood;
style: boxTextStyle;
@@ -646,11 +640,6 @@ editPeerUsernameError: FlatLabel(editPeerUsernameGood) {
textFg: boxTextFgError;
}
editPeerUsernamePosition: point(22px, 18px);
editPeerInviteLinkSkip: 10px;
editPeerInvitesMargins: margins(22px, 17px, 22px, 16px);
editPeerInvitesTopSkip: 10px;
editPeerInvitesSkip: 10px;
editPeerInviteLinkBoxBottomSkip: 15px;
editPeerReactionsButton: SettingsButton(infoProfileButton) {
padding: margins(59px, 13px, 8px, 11px);
@@ -752,36 +741,6 @@ topBarConnectingAnimation: InfiniteRadialAnimation(defaultInfiniteRadialAnimatio
infoFeedLeaveIconMargins: margins(10px, 12px, 20px, 10px);
separatePanelBorderCacheSize: 60px;
separatePanelTitleHeight: 62px;
separatePanelClose: IconButton(boxTitleClose) {
width: 60px;
height: 60px;
rippleAreaPosition: point(8px, 8px);
rippleAreaSize: 44px;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}
separatePanelTitleFont: font(18px semibold);
separatePanelTitle: FlatLabel(defaultFlatLabel) {
textFg: boxTitleFg;
maxHeight: 26px;
style: TextStyle(defaultTextStyle) {
font: separatePanelTitleFont;
linkFont: separatePanelTitleFont;
linkFontOver: font(18px semibold underline);
}
}
separatePanelTitleTop: 18px;
separatePanelTitleLeft: 22px;
separatePanelTitleSkip: 0px;
separatePanelBack: IconButton(separatePanelClose) {
icon: infoTopBarBackIcon;
iconOver: infoTopBarBackIconOver;
}
inviteLinkField: FlatInput(defaultFlatInput) {
font: font(fsize);

View File

@@ -61,7 +61,9 @@ ContentWidget::ContentWidget(
refreshSearchField(shown);
}, lifetime());
}
_scrollTopSkip.changes(
rpl::merge(
_scrollTopSkip.changes(),
_scrollBottomSkip.changes()
) | rpl::start_with_next([this] {
updateControlsGeometry();
}, lifetime());
@@ -79,7 +81,7 @@ void ContentWidget::updateControlsGeometry() {
auto newScrollTop = _scroll->scrollTop() + _topDelta;
auto scrollGeometry = rect().marginsRemoved(
QMargins(0, _scrollTopSkip.current(), 0, 0));
{ 0, _scrollTopSkip.current(), 0, _scrollBottomSkip.current() });
if (_scroll->geometry() != scrollGeometry) {
_scroll->setGeometry(scrollGeometry);
}
@@ -159,9 +161,11 @@ Ui::RpWidget *ContentWidget::doSetInnerWidget(
}
int ContentWidget::scrollTillBottom(int forHeight) const {
auto scrollHeight = forHeight - _scrollTopSkip.current();
auto scrollBottom = _scroll->scrollTop() + scrollHeight;
auto desired = _innerDesiredHeight;
const auto scrollHeight = forHeight
- _scrollTopSkip.current()
- _scrollBottomSkip.current();
const auto scrollBottom = _scroll->scrollTop() + scrollHeight;
const auto desired = _innerDesiredHeight;
return std::max(desired - scrollBottom, 0);
}
@@ -173,6 +177,10 @@ void ContentWidget::setScrollTopSkip(int scrollTopSkip) {
_scrollTopSkip = scrollTopSkip;
}
void ContentWidget::setScrollBottomSkip(int scrollBottomSkip) {
_scrollBottomSkip = scrollBottomSkip;
}
rpl::producer<int> ContentWidget::scrollHeightValue() const {
return _scroll->heightValue();
}
@@ -187,8 +195,9 @@ rpl::producer<int> ContentWidget::desiredHeightValue() const {
using namespace rpl::mappers;
return rpl::combine(
_innerWrap->entity()->desiredHeightValue(),
_scrollTopSkip.value()
) | rpl::map(_1 + _2);
_scrollTopSkip.value(),
_scrollBottomSkip.value()
) | rpl::map(_1 + _2 + _3);
}
rpl::producer<bool> ContentWidget::desiredShadowVisibility() const {

View File

@@ -94,6 +94,7 @@ protected:
void paintEvent(QPaintEvent *e) override;
void setScrollTopSkip(int scrollTopSkip);
void setScrollBottomSkip(int scrollBottomSkip);
int scrollTopSave() const;
void scrollTopRestore(int scrollTop);
void scrollTo(const Ui::ScrollToRequest &request);
@@ -109,6 +110,7 @@ private:
style::color _bg;
rpl::variable<int> _scrollTopSkip = -1;
rpl::variable<int> _scrollBottomSkip = -1;
rpl::event_stream<int> _scrollTillBottomChanges;
object_ptr<Ui::ScrollArea> _scroll;
Ui::PaddingWrap<Ui::RpWidget> *_innerWrap = nullptr;

View File

@@ -290,6 +290,10 @@ void Controller::showBackFromStack(const Window::SectionShow &params) {
}
}
void Controller::removeFromStack(const std::vector<Section> &sections) const {
_widget->removeFromStack(sections);
}
auto Controller::produceSearchQuery(
const QString &query) const -> SearchQuery {
Expects(_key.peer() != nullptr);
@@ -338,6 +342,14 @@ rpl::producer<SparseIdsMergedSlice> Controller::mediaSource(
limitAfter);
}
std::any &Controller::stepDataReference() {
return _stepData;
}
void Controller::takeStepData(not_null<Controller*> another) {
_stepData = base::take(another->_stepData);
}
Controller::~Controller() = default;
} // namespace Info

View File

@@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/variable.h>
#include "data/data_search_controller.h"
#include "window/window_session_controller.h"
#include "settings/settings_common.h"
namespace Ui {
class SearchFieldController;
@@ -212,6 +211,11 @@ public:
void showBackFromStack(
const Window::SectionShow &params = Window::SectionShow()) override;
void removeFromStack(const std::vector<Section> &sections) const;
void takeStepData(not_null<Controller*> another);
std::any &stepDataReference();
rpl::lifetime &lifetime() {
return _lifetime;
}
@@ -236,8 +240,11 @@ private:
rpl::variable<bool> _seachEnabledByContent = false;
bool _searchStartsFocused = false;
// Data between sections based on steps.
std::any _stepData;
rpl::lifetime _lifetime;
};
} // namespace Info
} // namespace Info

View File

@@ -82,7 +82,11 @@ void LayerWidget::setupHeightConsumers() {
_content->scrollTillBottomChanges(
) | rpl::filter([this] {
return !_inResize;
if (!_inResize) {
return true;
}
_pendingResize = true;
return false;
}) | rpl::start_with_next([this] {
resizeToWidth(width());
}, lifetime());
@@ -125,8 +129,11 @@ void LayerWidget::setContentHeight(int height) {
if (_contentHeight == height) {
return;
}
_contentHeight = height;
if (_content && !_inResize) {
if (_inResize) {
_pendingResize = true;
} else if (_content) {
resizeToWidth(width());
}
}
@@ -240,9 +247,29 @@ int LayerWidget::resizeGetHeight(int newWidth) {
if (!parentWidget() || !_content) {
return 0;
}
_inResize = true;
auto guard = gsl::finally([&] { _inResize = false; });
constexpr auto kMaxAttempts = 16;
auto attempts = 0;
while (true) {
_inResize = true;
const auto newGeometry = countGeometry(newWidth);
_inResize = false;
if (!_pendingResize) {
const auto oldGeometry = geometry();
if (newGeometry != oldGeometry) {
_content->forceContentRepaint();
}
if (newGeometry.topLeft() != oldGeometry.topLeft()) {
move(newGeometry.topLeft());
}
floatPlayerUpdatePositions();
return newGeometry.height();
}
_pendingResize = false;
Assert(attempts++ < kMaxAttempts);
}
}
QRect LayerWidget::countGeometry(int newWidth) {
auto parentSize = parentWidget()->size();
auto windowWidth = parentSize.width();
auto windowHeight = parentSize.height();
@@ -282,16 +309,7 @@ int LayerWidget::resizeGetHeight(int newWidth) {
contentHeight,
}, expanding, additionalScroll);
auto newGeometry = QRect(newLeft, newTop, newWidth, desiredHeight);
if (newGeometry != geometry()) {
_content->forceContentRepaint();
}
if (newGeometry.topLeft() != geometry().topLeft()) {
move(newGeometry.topLeft());
}
floatPlayerUpdatePositions();
return desiredHeight;
return QRect(newLeft, newTop, newWidth, desiredHeight);
}
void LayerWidget::doSetInnerFocus() {

View File

@@ -69,6 +69,7 @@ private:
void setupHeightConsumers();
void setContentHeight(int height);
[[nodiscard]] QRect countGeometry(int newWidth);
not_null<Window::SessionController*> _controller;
object_ptr<WrapWidget> _content;
@@ -80,6 +81,7 @@ private:
Ui::Animations::Simple _savedHeightAnimation;
bool _heightAnimated = false;
bool _inResize = false;
bool _pendingResize = false;
bool _tillBottom = false;
bool _floatPlayerDelegateRestored = false;

View File

@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/info_controller.h"
#include "info/info_memento.h"
#include "info/info_top_bar.h"
#include "settings/cloud_password/settings_cloud_password_email_confirm.h"
#include "settings/settings_chat.h"
#include "settings/settings_main.h"
#include "ui/widgets/discrete_sliders.h"
@@ -395,7 +396,9 @@ void WrapWidget::createTopBar() {
addTopBarMenuButton();
addProfileCallsButton();
} else if (section.type() == Section::Type::Settings
&& (section.settingsType() == ::Settings::Main::Id()
&& (section.settingsType()
== ::Settings::CloudPasswordEmailConfirmId()
|| section.settingsType() == ::Settings::Main::Id()
|| section.settingsType() == ::Settings::Chat::Id())) {
addTopBarMenuButton();
} else if (section.type() == Section::Type::Downloads) {
@@ -596,6 +599,26 @@ bool WrapWidget::showBackFromStackInternal(
return (wrap() == Wrap::Layer);
}
void WrapWidget::removeFromStack(const std::vector<Section> &sections) {
for (const auto &section : sections) {
const auto it = ranges::find_if(_historyStack, [&](
const StackItem &item) {
const auto &s = item.section->section();
if (s.type() != section.type()) {
return false;
} else if (s.type() == Section::Type::Media) {
return (s.mediaType() == section.mediaType());
} else if (s.type() == Section::Type::Settings) {
return (s.settingsType() == section.settingsType());
}
return false;
});
if (it != end(_historyStack)) {
_historyStack.erase(it);
}
}
}
not_null<Ui::RpWidget*> WrapWidget::topWidget() const {
// This was done for tabs support.
//
@@ -900,6 +923,9 @@ void WrapWidget::showNewContent(
auto newController = createController(
_controller->parentController(),
memento);
if (_controller && newController) {
newController->takeStepData(_controller.get());
}
auto newContent = object_ptr<ContentWidget>(nullptr);
if (needAnimation) {
newContent = createContent(memento, newController.get());

View File

@@ -106,6 +106,7 @@ public:
not_null<Window::SectionMemento*> memento,
const Window::SectionShow &params) override;
bool showBackFromStackInternal(const Window::SectionShow &params);
void removeFromStack(const std::vector<Section> &sections);
std::shared_ptr<Window::SectionMemento> createMemento() override;
rpl::producer<int> desiredHeightValue() const override;

View File

@@ -529,7 +529,7 @@ void ActionsFiller::addInviteToGroupAction(
InviteToChatButton(user) | rpl::filter(notEmpty),
InviteToChatButton(user) | rpl::map(notEmpty),
[=] { AddBotToGroupBoxController::Start(user); },
&st::infoIconRequests);
&st::infoIconAddMember);
const auto about = _wrap->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_wrap.data(),
@@ -719,7 +719,7 @@ void ActionsFiller::addJoinChannelAction(
tr::lng_profile_join_channel(),
rpl::duplicate(joinVisible),
[=] { channel->session().api().joinChannel(channel); },
&st::infoIconRequests);
&st::infoIconAddMember);
_wrap->add(object_ptr<Ui::SlideWrap<Ui::FixedHeightWidget>>(
_wrap,
CreateSkipWidget(

View File

@@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/settings/info_settings_widget.h"
#include "info/info_memento.h"
#include "info/info_controller.h"
#include "settings/settings_common.h"
#include "settings/settings_main.h"
#include "settings/settings_information.h"
@@ -47,11 +46,63 @@ Widget::Widget(
, _type(controller->section().settingsType())
, _inner(
setInnerWidget(
_type()->create(this, controller->parentController()))) {
_type()->create(this, controller->parentController())))
, _pinnedToTop(_inner->createPinnedToTop(this))
, _pinnedToBottom(_inner->createPinnedToBottom(this)) {
_inner->sectionShowOther(
) | rpl::start_with_next([=](Type type) {
controller->showSettings(type);
}, _inner->lifetime());
_inner->sectionShowBack(
) | rpl::start_with_next([=] {
controller->showBackFromStack();
}, _inner->lifetime());
_inner->setStepDataReference(controller->stepDataReference());
_removesFromStack.events(
) | rpl::start_with_next([=](const std::vector<Type> &types) {
const auto sections = ranges::views::all(
types
) | ranges::views::transform([](Type type) {
return Section(type);
}) | ranges::to_vector;
controller->removeFromStack(sections);
}, _inner->lifetime());
if (_pinnedToTop) {
_inner->widthValue(
) | rpl::start_with_next([=](int w) {
_pinnedToTop->resizeToWidth(w);
setScrollTopSkip(_pinnedToTop->height());
}, _pinnedToTop->lifetime());
_pinnedToTop->heightValue(
) | rpl::start_with_next([=](int h) {
setScrollTopSkip(h);
}, _pinnedToTop->lifetime());
}
if (_pinnedToBottom) {
const auto processHeight = [=](int bottomHeight, int height) {
setScrollBottomSkip(bottomHeight);
_pinnedToBottom->moveToLeft(
_pinnedToBottom->x(),
height - bottomHeight);
};
_inner->sizeValue(
) | rpl::start_with_next([=](const QSize &s) {
_pinnedToBottom->resizeToWidth(s.width());
processHeight(_pinnedToBottom->height(), height());
}, _pinnedToBottom->lifetime());
rpl::combine(
_pinnedToBottom->heightValue(),
heightValue()
) | rpl::start_with_next(processHeight, _pinnedToBottom->lifetime());
}
}
Widget::~Widget() = default;
@@ -85,6 +136,13 @@ void Widget::saveChanges(FnMut<void()> done) {
void Widget::showFinished() {
_inner->showFinished();
_inner->removeFromStack(
) | rpl::start_to_stream(_removesFromStack, lifetime());
}
void Widget::setInnerFocus() {
_inner->setInnerFocus();
}
rpl::producer<bool> Widget::desiredShadowVisibility() const {

View File

@@ -66,6 +66,7 @@ public:
void saveChanges(FnMut<void()> done) override;
void showFinished() override;
void setInnerFocus() override;
rpl::producer<bool> desiredShadowVisibility() const override;
@@ -81,6 +82,10 @@ private:
Type _type = Type();
not_null<::Settings::AbstractSection*> _inner;
QPointer<Ui::RpWidget> _pinnedToTop;
QPointer<Ui::RpWidget> _pinnedToBottom;
rpl::event_stream<std::vector<Type>> _removesFromStack;
};

View File

@@ -346,7 +346,7 @@ void CodeWidget::gotPassword(const MTPaccount_Password &result) {
LOG(("API Error: No current password received on login."));
_code->setFocus();
return;
} else if (!getData()->pwdState.request) {
} else if (!getData()->pwdState.hasPassword) {
const auto callback = [=](Fn<void()> &&close) {
Core::UpdateApplication();
close();

View File

@@ -36,7 +36,7 @@ PasswordCheckWidget::PasswordCheckWidget(
, _codeField(this, st::introPassword, tr::lng_signin_code())
, _toRecover(this, tr::lng_signin_recover(tr::now))
, _toPassword(this, tr::lng_signin_try_password(tr::now)) {
Expects(!!_passwordState.request);
Expects(_passwordState.hasPassword);
Lang::Updated(
) | rpl::start_with_next([=] {
@@ -169,7 +169,7 @@ void PasswordCheckWidget::handleSrpIdInvalid() {
const auto now = crl::now();
if (_lastSrpIdInvalidTime > 0
&& now - _lastSrpIdInvalidTime < Core::kHandleSrpIdInvalidTimeout) {
_passwordState.request.id = 0;
_passwordState.mtp.request.id = 0;
showError(rpl::single(Lang::Hard::ServerError()));
} else {
_lastSrpIdInvalidTime = now;
@@ -178,7 +178,7 @@ void PasswordCheckWidget::handleSrpIdInvalid() {
}
void PasswordCheckWidget::checkPasswordHash() {
if (_passwordState.request.id) {
if (_passwordState.mtp.request.id) {
passwordChecked();
} else {
requestPasswordData();
@@ -201,12 +201,12 @@ void PasswordCheckWidget::requestPasswordData() {
void PasswordCheckWidget::passwordChecked() {
const auto check = Core::ComputeCloudPasswordCheck(
_passwordState.request,
_passwordState.mtp.request,
_passwordHash);
if (!check) {
return serverError();
}
_passwordState.request.id = 0;
_passwordState.mtp.request.id = 0;
_sentRequest = api().request(
MTPauth_CheckPassword(check.result)
).done([=](const MTPauth_Authorization &result) {
@@ -226,7 +226,8 @@ void PasswordCheckWidget::codeSubmitDone(
auto fields = PasscodeBox::CloudFields::From(_passwordState);
fields.fromRecoveryCode = code;
fields.hasRecovery = false;
fields.curRequest = {};
fields.mtp.curRequest = {};
fields.hasPassword = false;
auto box = Box<PasscodeBox>(&api().instance(), nullptr, fields);
const auto boxShared = std::make_shared<QPointer<PasscodeBox>>();
@@ -391,7 +392,7 @@ void PasswordCheckWidget::submit() {
const auto password = _pwdField->getLastText().toUtf8();
_passwordHash = Core::ComputeCloudPasswordHash(
_passwordState.request.algo,
_passwordState.mtp.request.algo,
bytes::make_span(password));
checkPasswordHash();
}

View File

@@ -394,7 +394,7 @@ void QrWidget::sendCheckPasswordRequest() {
LOG(("API Error: No current password received on login."));
goReplace<QrWidget>(Animate::Forward);
return;
} else if (!getData()->pwdState.request) {
} else if (!getData()->pwdState.hasPassword) {
const auto callback = [=](Fn<void()> &&close) {
Core::UpdateApplication();
close();

View File

@@ -123,55 +123,6 @@ void MainWindow::initHook() {
}
}
void MainWindow::createTrayIconMenu() {
#ifdef Q_OS_WIN
trayIconMenu = new Ui::PopupMenu(nullptr);
trayIconMenu->deleteOnHide(false);
#else // Q_OS_WIN
trayIconMenu = new QMenu(this);
connect(trayIconMenu, &QMenu::aboutToShow, [=] {
updateIsActive();
updateTrayMenu();
});
#endif // else for Q_OS_WIN
const auto minimizeAction = trayIconMenu->addAction(QString(), [=] {
if (_activeForTrayIconAction) {
minimizeToTray();
} else {
showFromTrayMenu();
}
});
const auto notificationAction = trayIconMenu->addAction(QString(), [=] {
toggleDisplayNotifyFromTray();
});
trayIconMenu->addAction(tr::lng_quit_from_tray(tr::now), [=] {
quitFromTray();
});
_updateTrayMenuTextActions.events(
) | rpl::start_with_next([=] {
if (!trayIconMenu) {
return;
}
_activeForTrayIconAction = isActiveForTrayMenu();
minimizeAction->setText(_activeForTrayIconAction
? tr::lng_minimize_to_tray(tr::now)
: tr::lng_open_from_tray(tr::now));
auto notificationActionText = Core::App().settings().desktopNotify()
? tr::lng_disable_notifications_from_tray(tr::now)
: tr::lng_enable_notifications_from_tray(tr::now);
notificationAction->setText(notificationActionText);
}, lifetime());
_updateTrayMenuTextActions.fire({});
initTrayMenuHook();
}
void MainWindow::applyInitialWorkMode() {
const auto workMode = Core::App().settings().workMode();
workmodeUpdated(workMode);
@@ -196,7 +147,6 @@ void MainWindow::applyInitialWorkMode() {
}
void MainWindow::finishFirstShow() {
createTrayIconMenu();
applyInitialWorkMode();
createGlobalMenu();
@@ -680,15 +630,6 @@ bool MainWindow::eventFilter(QObject *object, QEvent *e) {
return Platform::MainWindow::eventFilter(object, e);
}
void MainWindow::updateTrayMenu() {
if (!trayIconMenu) {
return;
}
_updateTrayMenuTextActions.fire({});
psTrayMenuUpdated();
}
bool MainWindow::takeThirdSectionFromLayer() {
return _layer ? _layer->takeToThirdSection() : false;
}
@@ -700,91 +641,6 @@ void MainWindow::fixOrder() {
if (_testingThemeWarning) _testingThemeWarning->raise();
}
void MainWindow::handleTrayIconActication(
QSystemTrayIcon::ActivationReason reason) {
updateIsActive();
if (Platform::IsMac() && isActive()) {
if (trayIcon && !trayIcon->contextMenu()) {
showFromTray();
}
return;
}
if (reason == QSystemTrayIcon::Context) {
updateTrayMenu();
InvokeQueued(this, [=] {
psShowTrayMenu();
});
} else if (!skipTrayClick()) {
if (isActiveForTrayMenu()) {
minimizeToTray();
} else {
showFromTray();
}
_lastTrayClickTime = crl::now();
}
}
bool MainWindow::skipTrayClick() const {
return (_lastTrayClickTime > 0)
&& (crl::now() - _lastTrayClickTime
< QApplication::doubleClickInterval());
}
void MainWindow::toggleDisplayNotifyFromTray() {
if (controller().locked()) {
if (!isActive()) showFromTray();
Ui::show(Ui::MakeInformBox(tr::lng_passcode_need_unblock()));
return;
}
if (!sessionController()) {
return;
}
auto soundNotifyChanged = false;
auto flashBounceNotifyChanged = false;
auto &settings = Core::App().settings();
settings.setDesktopNotify(!settings.desktopNotify());
if (settings.desktopNotify()) {
if (settings.rememberedSoundNotifyFromTray()
&& !settings.soundNotify()) {
settings.setSoundNotify(true);
settings.setRememberedSoundNotifyFromTray(false);
soundNotifyChanged = true;
}
if (settings.rememberedFlashBounceNotifyFromTray()
&& !settings.flashBounceNotify()) {
settings.setFlashBounceNotify(true);
settings.setRememberedFlashBounceNotifyFromTray(false);
flashBounceNotifyChanged = true;
}
} else {
if (settings.soundNotify()) {
settings.setSoundNotify(false);
settings.setRememberedSoundNotifyFromTray(true);
soundNotifyChanged = true;
} else {
settings.setRememberedSoundNotifyFromTray(false);
}
if (settings.flashBounceNotify()) {
settings.setFlashBounceNotify(false);
settings.setRememberedFlashBounceNotifyFromTray(true);
flashBounceNotifyChanged = true;
} else {
settings.setRememberedFlashBounceNotifyFromTray(false);
}
}
Core::App().saveSettingsDelayed();
using Change = Window::Notifications::ChangeType;
auto &notifications = Core::App().notifications();
notifications.notifySettingsChanged(Change::DesktopEnabled);
if (soundNotifyChanged) {
notifications.notifySettingsChanged(Change::SoundEnabled);
}
if (flashBounceNotifyChanged) {
notifications.notifySettingsChanged(Change::FlashBounceEnabled);
}
}
void MainWindow::closeEvent(QCloseEvent *e) {
if (Core::Sandbox::Instance().isSavingSession() || Core::Quitting()) {
e->accept();
@@ -853,10 +709,7 @@ void MainWindow::activeChangedHook() {
}
}
MainWindow::~MainWindow() {
delete trayIcon;
delete trayIconMenu;
}
MainWindow::~MainWindow() = default;
namespace App {

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