Compare commits

..

260 Commits

Author SHA1 Message Date
John Preston
9717a8b5fa Version 2.4.4.
- Fix application quit on call end with main window hidden in tray.
- Update OpenAL library on Windows.
- Several crash fixes.
2020-10-23 19:40:48 +03:00
John Preston
aff4f69b64 Don't quit on call end with window hidden in tray.
Fixes #8585.
2020-10-23 19:37:58 +03:00
John Preston
9de4c42555 Keep sending typings up to 30s after offline. 2020-10-23 18:25:55 +03:00
John Preston
1de144a48d Show transfer ownership button for non-anonymous admins. 2020-10-23 17:37:27 +03:00
John Preston
0690d14f1b Don't send typings to bots and offline users. 2020-10-23 17:28:11 +03:00
John Preston
53ac4c00ad Track deleted messages carefully.
Fixes #8855.
2020-10-23 16:35:43 +03:00
John Preston
f064692e57 Close media viewer when photo message is deleted. 2020-10-23 15:28:20 +03:00
John Preston
3d54a263b8 Stop playing documents when items are deleted. 2020-10-23 15:22:38 +03:00
23rd
47bb8ec687 Added Github Action that updates user-agent for DNS. 2020-10-23 15:13:20 +03:00
23rd
3a2b772a5d Added spellchecker to Replies / Scheduled messages sections.
Fixed #8793.
2020-10-23 13:32:44 +03:00
23rd
bc8f8bc68c Added auto-closing to some boxes which depend on certain message. 2020-10-23 13:32:44 +03:00
23rd
bc7975ece7 Fixed crash when user reschedules already sent message.
Fixed #8867.
2020-10-23 13:32:43 +03:00
23rd
52cca98144 Fixed replies button display in section of scheduled messages. 2020-10-23 13:32:43 +03:00
23rd
5540b0bb8b Fixed glitch for scheduled messages with elapsed date in channels. 2020-10-23 13:32:32 +03:00
23rd
7de9bcad03 Added ability to open contacts with shortcut.
Fixed #8775.
2020-10-23 13:31:24 +03:00
23rd
367b028094 Moved contacts box preparing to single place. 2020-10-23 13:31:24 +03:00
John Preston
8b27aa5331 Update cmake_helpers submodule. 2020-10-23 13:11:42 +03:00
John Preston
9697567b8d Add some more open file warnings. 2020-10-23 13:10:43 +03:00
Ilya Fedin
1fdfa94497 Remove explicit Opus clone step from macos action
Since no longer needed
2020-10-23 12:51:52 +03:00
John Preston
1373bd0af1 Use OpenAL 1.20.1 with bugfix backport on Windows. 2020-10-23 12:47:41 +03:00
Ilya Fedin
4f2b0531f8 Replace GDBusProxy with GDBusConnection in NotificationData 2020-10-23 11:29:35 +03:00
Ilya Fedin
ca67ac913f Check for KDE portal backend when using portals on KDE 2020-10-23 11:28:18 +03:00
Ilya Fedin
4033a091b5 Hide mark as read button in notifications when app is pass-code locked 2020-10-23 11:25:18 +03:00
Ilya Fedin
0179a2ca10 Rename InstallMainDesktopFile to InstallLauncher 2020-10-23 11:25:18 +03:00
Ilya Fedin
f58874572d Check actual socket path length rather than InSnap/InFlatpak 2020-10-23 11:25:18 +03:00
Ilya Fedin
143b9682a4 Get rid of lxqt-qtplugin
It is stil impossible to build it statically and it seems that reading icon theme from gtk is pretty enough
2020-10-23 11:24:37 +03:00
John Preston
00c962e557 Bump cmake_helpers submodule. 2020-10-23 11:24:02 +03:00
John Preston
1cabfaa6a4 Fix cancel / crash in sending album to scheduled messages.
Fixes #8788
2020-10-23 11:22:38 +03:00
Ilya Fedin
b788ae0ae4 Add stale bot configuration 2020-10-23 11:18:14 +03:00
Ilya Fedin
3f6399f13d Log getting GTK settings 2020-10-21 10:57:40 +03:00
Ilya Fedin
b6fc418d32 01org/libva -> intel/libva 2020-10-20 09:37:56 +03:00
Ilya Fedin
245d644cd7 Add always on top hint for media view window
To avoid overlapping by panels in KDE
2020-10-20 09:37:31 +03:00
Ilya Fedin
2aa0b674cd Use new XCB methods from lib_base 2020-10-16 16:12:38 +03:00
Ilya Fedin
654784ce9f Use external_xcb and external_glib 2020-10-16 16:12:38 +03:00
John Preston
744eccc51e Version 2.4.3: Fix build for OS X 10.10-10.11. 2020-10-07 18:18:58 +03:00
Ilya Fedin
ce49714533 Use FindALSA instead of pkg-config 2020-10-07 17:10:27 +03:00
John Preston
ae2c858dc9 Version 2.4.3: Update lib_ui submodule. 2020-10-07 15:10:31 +03:00
John Preston
f0b5dc42f9 Version 2.4.3.
- Fix sending voice messages in scheduled messages section.
- Fix deleting profile / group / channel photos.
- Several crash fixes.
2020-10-07 15:08:52 +03:00
John Preston
9c213bf1c0 Warn when launching .sh on Windows.
Fixes #8753.
2020-10-07 14:41:21 +03:00
John Preston
0c1175f9cd Fix broadcast field placeholder update. 2020-10-07 14:41:21 +03:00
23rd
0c1312419a Fixed crash when user schedules message with elapsed date.
Fixed #8764.
2020-10-07 14:30:29 +03:00
23rd
7e9695b213 Added missed *.mov extension to dialog files filter for album items. 2020-10-07 13:09:15 +03:00
Ilya Fedin
093fcc3821 Subscribe to StatusNotifierHostRegistered signal 2020-10-07 13:06:06 +03:00
Ilya Fedin
6f89598a7b Clean old attempts to register url scheme on scheme registration 2020-10-07 12:55:34 +03:00
John Preston
6ccd53689d Fix crash in shared media search message delete.
Fixes #8237.
2020-10-06 14:20:49 +03:00
John Preston
cd506dfff5 Fix reply_to_top_id in local sent stickers.
Fixes #8758.
2020-10-06 14:01:19 +03:00
John Preston
5a3733b5b6 Fix selecting stickers in Replies section. 2020-10-06 13:46:19 +03:00
John Preston
22a85016e3 Show rank in anonymous outgoing messages. 2020-10-06 10:23:58 +03:00
John Preston
26c7a95a9f Use network-manager-observe in snap version. 2020-10-06 10:15:22 +03:00
John Preston
9acf617c9f Show full cached song as downloaded. 2020-10-06 10:10:22 +03:00
John Preston
72af170484 Force call panel to be a separate window.
I hope this fixes #8715.
2020-10-05 18:30:08 +03:00
John Preston
4db2505f5d Fix deleting profile photos.
Fixes #8720.
2020-10-05 18:26:29 +03:00
23rd
4d40336be0 Fixed voice recording cancel. 2020-10-05 17:08:52 +03:00
John Preston
616531b0d0 Fix author signature in discussion posts. 2020-10-05 16:21:34 +03:00
John Preston
473803edb8 Fix comments button getState / remove. 2020-10-05 16:21:34 +03:00
Ilya Fedin
a33ca97298 Find taskbar window on the same monitor 2020-10-05 13:50:03 +03:00
John Preston
a711c89409 Fix crash on wrong server response.
Fixes #8724.
2020-10-05 12:58:12 +03:00
John Preston
24ec0e0866 Fix recording stop in voice messages. 2020-10-05 12:58:12 +03:00
John Preston
e6df927e30 Correctly use alcGetIntegerv. 2020-10-05 12:58:12 +03:00
Ilya Fedin
638ea3111f Fallback to D-Bus methods if XCB-based LastUserInputTime failed 2020-10-05 10:10:40 +03:00
John Preston
983d9e6eee Version 2.4.2.
- Allow block, report and delete all message from user
in "user joined" service message context menu.
- Fix admin badge display in groups.
- Fix loading and opening of comments in channels.
2020-10-02 19:32:20 +03:00
John Preston
4b6d74dd9b Fix opening Replies section on unread bar. 2020-10-02 19:29:29 +03:00
23rd
8d70a62ee8 Fixed crash in OverlayWidget when user opens attached stickers.
Fixed #8710.
2020-10-02 19:29:29 +03:00
Ilya Fedin
a0af748fc5 Update SNI state even if tray is deactivated 2020-10-02 19:19:16 +03:00
John Preston
f10ef26226 Fix message right badge refresh.
Fixes #8669.
2020-10-02 17:46:27 +03:00
John Preston
4ebc62afd2 Fix build on Linux. 2020-10-02 17:29:28 +03:00
John Preston
18cb26fed6 Change flags / attributes when changing window frame. 2020-10-02 16:17:53 +03:00
John Preston
d965385356 Fix loading comments. 2020-10-02 16:10:50 +03:00
Ilya Fedin
5cc4066b65 Don't change window flags in Window::MainWindow::recountGeometryConstraints 2020-10-02 16:10:38 +03:00
John Preston
6b084301be Allow delete all from service message. 2020-10-02 16:02:09 +03:00
23rd
498e82b804 Added ability to scroll to replying message on reply header click. 2020-10-02 15:57:17 +03:00
John Preston
8c224f7aca Allow block & report from service message. 2020-10-02 15:52:26 +03:00
John Preston
f3a2460a54 Version 2.4.1: Fix build for Linux. 2020-10-01 20:06:00 +03:00
John Preston
04212140cc Version 2.4.1: Fix capture error reporting. 2020-10-01 18:46:22 +03:00
John Preston
4e1904b137 Version 2.4.1.
- Move by PageUp and PageDown in channel comments.
- Several layout bugfixes.
- Several crashfixes.
2020-10-01 18:24:29 +03:00
John Preston
0299ba4873 Allow in groups to delete service messages for everyone.
Fixes #8690.
2020-10-01 18:21:39 +03:00
23rd
46ce0df832 Fixed crash in SessionsBox when list of sessions is empty. 2020-10-01 18:14:09 +03:00
John Preston
d66debd802 Fix crash on bad message in Replies section. 2020-10-01 18:08:27 +03:00
John Preston
454fe8cdf7 Fix crash in calls box. 2020-10-01 17:52:02 +03:00
John Preston
c4dfc634d0 Fix crash in main window destruction. 2020-10-01 17:45:25 +03:00
John Preston
b08fa069b4 Fix assertion violation in case of bad messages. 2020-10-01 17:38:49 +03:00
John Preston
3d20958bb4 Remove assertion about taskbar position. 2020-10-01 17:33:59 +03:00
John Preston
c693fcb2b0 Reopen third column in Replies section.
Fixes #8674, fixes #8687.
2020-10-01 17:20:08 +03:00
John Preston
ddad42d80e Add report button to comments context menu.
Fixes #8679.
2020-10-01 17:06:04 +03:00
John Preston
c6f66e83ee Fix restriction label display.
Fixes #8680.
2020-10-01 16:53:39 +03:00
John Preston
8bb3b7fada Handle some errors on comments open.
Fixes #8682.
2020-10-01 16:42:31 +03:00
Ilya Fedin
1d24d29afa Little cleanup for Linux platform code & build
CheckCXXSourceCompiles is not needed anymore

Material wayland decorations could be checked just with IsQtPluginsBundled
2020-10-01 16:34:01 +03:00
Ilya Fedin
0536a479f9 Use startSystemMove/startSystemResize instead of platform code on Wayland with Qt 5.15 2020-10-01 16:30:53 +03:00
Ilya Fedin
7fef7e6315 Don't add shadow on Wayland
It was implemented like a hack and worked like a hack... Looks like it is better to wait until Qt give a way to create shadows.
2020-10-01 16:30:53 +03:00
John Preston
c6ef2b057e Fix couple of visual glitches.
Fixes #8676.
2020-10-01 16:29:09 +03:00
John Preston
784f10678c Fix root comments post layout. 2020-10-01 15:12:57 +03:00
John Preston
92dbd7089b Fix comments layout bug for narrow photos. 2020-10-01 14:05:26 +03:00
John Preston
415990c913 Show View thread button only in discussions for now. 2020-10-01 13:38:36 +03:00
John Preston
e42af74dd2 Don't try to open comments in invite peek channel. 2020-10-01 13:15:10 +03:00
John Preston
bd1a46252d Show admin rank for anonymous posts. 2020-10-01 12:57:03 +03:00
John Preston
874e5e0a61 Fix export of discussion messages. 2020-10-01 12:42:35 +03:00
John Preston
81457693f1 Don't add comments button for inline markup messages.
Fixes #8664.
2020-10-01 11:44:08 +03:00
John Preston
3a700650be Remove comments info if no info in server data. 2020-10-01 11:34:59 +03:00
John Preston
d642c3f3b5 Hide bot about header for Replies chat. 2020-10-01 11:19:14 +03:00
John Preston
4be03ffc25 Fix PageUp/PageDown scrolling in Replies section.
Fixes #8666.
2020-10-01 11:00:29 +03:00
Ilya Fedin
dcac3146c7 Fix Linux GitHub action 2020-10-01 10:54:42 +03:00
Ilya Fedin
10012d6b31 Handle launcher basename compile-time for snap
Just like for flatpak
2020-10-01 10:54:42 +03:00
John Preston
3aa1b1e9ae Fix recent commenters userpics border. 2020-10-01 10:52:53 +03:00
John Preston
4e8a1f8d29 Fix voice messages sending. 2020-10-01 10:47:03 +03:00
John Preston
11e03a181d Version 2.4: Fix crash in typing animations. 2020-09-30 21:11:24 +03:00
John Preston
4e366dc86e Fix widget order in compose controls. 2020-09-30 21:11:24 +03:00
23rd
015277c4d3 Disabled top moving of dialogs when window has normal adaptive layout.
Fixed #8370.
2020-09-30 21:11:24 +03:00
John Preston
745bbfe268 Fix fast reply from message corner in Replies section. 2020-09-30 21:11:24 +03:00
John Preston
e8a58c4c8d Fix crash in replies list management. 2020-09-30 21:11:24 +03:00
John Preston
d4f2c96322 Version 2.4: Fix build on macOS. 2020-09-30 19:58:30 +03:00
John Preston
bd1d0417a9 Version 2.4: Fix submodules. 2020-09-30 19:20:08 +03:00
John Preston
4a78eb100a Version 2.4.
- Turn on "Remain Anonymous" in an admin's Permissions to let them post
on behalf of the group and become invisible in the list of members.
- Comment on posts in channels that have a discussion group.
- Get notified about replies to your comments via the new Replies chat
(if you are not a member of the discussion group).
2020-09-30 19:15:43 +03:00
Ilya Fedin
7fa5ca192b Fix showing autohidden taskbar with maximized window 2020-09-30 19:14:51 +03:00
John Preston
371510cfe2 Fix layout bug in box title with right button. 2020-09-30 19:01:54 +03:00
23rd
622c1a910b Moved text changes of QAction in peer menu to single place. 2020-09-30 19:00:53 +03:00
23rd
ce3279143d Connected popup menu display to archive button display in main menu. 2020-09-30 19:00:53 +03:00
23rd
3e6ba53a04 Reduced number of requests for authorizations list in SessionsBox. 2020-09-30 18:48:35 +03:00
23rd
41cb37b091 Added labels update in privacy box by timer. 2020-09-30 18:48:35 +03:00
23rd
264dd0c1d2 Refactored row painting in sessions box. 2020-09-30 18:48:34 +03:00
23rd
163e549708 Added count of active sessions as label of button in settings. 2020-09-30 18:48:34 +03:00
23rd
035a19b41e Removed authorizations check form Data::Session. 2020-09-30 18:48:34 +03:00
23rd
6ac5f32796 Moved other authorizations api request to separated file. 2020-09-30 18:48:34 +03:00
23rd
0c4c4b2fcf Added ability to move content of SessionsBox to Section. 2020-09-30 18:48:34 +03:00
23rd
a106d6e804 Moved content of SessionsBox to separate inner class. 2020-09-30 18:48:34 +03:00
23rd
6b7c33f0ee Moved same parts of code of terminating in SessionsBox to single place. 2020-09-30 18:48:34 +03:00
23rd
8d2cacac80 Replaced variable of loading in SessionsBox with rpl::variable. 2020-09-30 18:48:34 +03:00
John Preston
cc9eb7f893 Support write restrictions in Replies section. 2020-09-30 18:38:58 +03:00
John Preston
94c2969f8b Support slowmode restrictions in Replies section. 2020-09-30 16:29:32 +03:00
John Preston
719bed6e85 Move some text formatting to tg_ui:ui/text/format_values. 2020-09-30 16:29:17 +03:00
John Preston
8634c1f7f3 Move lang keys to td_lang library. 2020-09-30 12:18:52 +03:00
John Preston
def1266216 Rename td-specific libs from lib_ to td_. 2020-09-30 10:51:17 +03:00
23rd
2e02f27a5c Fixed tabbed selector display in Replies / Scheduled messages sections. 2020-09-29 23:44:03 +03:00
John Preston
04855f1697 Fix instructions for Qt build without ICU. 2020-09-29 23:43:22 +03:00
John Preston
c29730650e Closed alpha version 2.3.2.2. 2020-09-29 20:20:31 +03:00
John Preston
6257445d5e Fix build on Xcode 12. 2020-09-29 20:20:21 +03:00
John Preston
405c8125da Allow sending voice messages in Replies / Scheduled. 2020-09-29 19:03:30 +03:00
John Preston
62da24c20b Improve scroll to unread bar. 2020-09-29 19:03:30 +03:00
John Preston
e8df47c926 Show send action animations in Replies thread. 2020-09-29 19:03:30 +03:00
John Preston
433c147dd0 Show message from Replies bot inside thread. 2020-09-29 19:03:30 +03:00
John Preston
8f4fdb6d0d Fix crash in mark folder as read. 2020-09-29 19:03:30 +03:00
23rd
aecdc01e41 Added ability to mark all chats as read. 2020-09-29 19:03:29 +03:00
23rd
bdce2d5e25 Added ability to mark as read chats from folder from context menu.
Fixed #7507.
Fixed #6004.
2020-09-29 19:03:29 +03:00
23rd
5968219fe4 Added ability to mark as read selected chat with shortcut. 2020-09-29 19:03:29 +03:00
23rd
f81271d1fe Simplified confirmed callback for ConfirmBox instances. 2020-09-29 19:03:29 +03:00
23rd
9f3af7234e Added ability to pass confirm callback with close to ConfirmBox. 2020-09-29 19:03:29 +03:00
John Preston
90c0929407 Load Rstrtmgr dynamically. 2020-09-29 19:03:29 +03:00
John Preston
1e31cda78d Fix root comments post layout. 2020-09-29 19:03:29 +03:00
John Preston
f7e4f18e9b Fix a crash in failed-sent scheduled messages. 2020-09-29 19:03:29 +03:00
John Preston
0fb42ed82a Use special method for blocking from Replies. 2020-09-29 19:03:29 +03:00
John Preston
c535a7c564 Use MaskedInputField for URL input. 2020-09-29 19:03:29 +03:00
John Preston
c32f2e71e8 Update fast action icons. 2020-09-29 19:03:28 +03:00
John Preston
a38f7b357c Closed alpha version 2.3.2.1. 2020-09-29 19:03:28 +03:00
John Preston
438f69e1b2 Improve root comments message layout. 2020-09-29 19:03:28 +03:00
John Preston
891b4a91a3 Generate correct links to replies section. 2020-09-29 19:03:28 +03:00
John Preston
889139f31f Handle links to replies section. 2020-09-29 19:03:28 +03:00
John Preston
247b1f64ca Show correct outbox ticks in replies section. 2020-09-29 19:03:27 +03:00
John Preston
13ad590a51 Track inbox/outbox comments/replies read state. 2020-09-29 19:03:27 +03:00
John Preston
e021e0beb3 Resize scroll area together with pinned root message. 2020-09-29 19:03:27 +03:00
John Preston
b097bd7225 Report spam from Replies reports messages. 2020-09-29 19:03:27 +03:00
John Preston
27f85df562 Click on root pinned bar throws to replies start. 2020-09-29 19:03:27 +03:00
John Preston
e484bc78d0 Update API scheme on layer 119. 2020-09-29 19:03:27 +03:00
John Preston
d89be1d1d4 Don't read messages in channels I'm not in. 2020-09-29 19:03:27 +03:00
John Preston
ab429212e5 Respect global group read position in replies. 2020-09-29 19:03:27 +03:00
John Preston
f53f934001 Handle new typing update in channels. 2020-09-29 19:03:27 +03:00
John Preston
a287dec242 Allow sending typing/send actions for Replies section. 2020-09-29 19:03:27 +03:00
John Preston
f73b0f0b0d Update API scheme on layer 119. 2020-09-29 19:03:27 +03:00
John Preston
61d89113d4 Handle correctly comment links for public channels. 2020-09-29 19:03:26 +03:00
John Preston
7862443fcb Show comments button for unwrapped medias. 2020-09-29 19:03:26 +03:00
John Preston
1a40f2b3ef Fix userpics display for min-loaded users. 2020-09-29 19:03:26 +03:00
John Preston
4c1213ce9e Allow blocking users from Replies chat. 2020-09-29 19:03:26 +03:00
John Preston
afbc0c498f Use service message instead of unread bar. 2020-09-29 19:03:26 +03:00
John Preston
a91c078fb1 Count attachments only on visible items. 2020-09-29 19:03:26 +03:00
John Preston
6eedeb3852 Inject full album to the Replies section. 2020-09-29 19:03:26 +03:00
John Preston
8af559e711 Use first message of album as the leader. 2020-09-29 19:03:26 +03:00
John Preston
7f928a92ea Show root as pinned when not visible as message. 2020-09-29 19:03:26 +03:00
John Preston
22dc7601f5 Fix root message pinned bar shadow. 2020-09-29 19:03:26 +03:00
John Preston
9abca29f4c Show comments bar when no unread bar. 2020-09-29 19:03:25 +03:00
John Preston
cf48152853 Inject discussed message when no comments. 2020-09-29 19:03:25 +03:00
John Preston
883c3ecf65 Improve root message layout in Replies section. 2020-09-29 19:03:25 +03:00
John Preston
9a96298ef7 Disable revoke all history for bots. 2020-09-29 19:03:25 +03:00
John Preston
a1a845dbf1 Improve Replies chat design. 2020-09-29 19:03:25 +03:00
John Preston
40e925d3f9 Remove redundant read comments thread requests. 2020-09-29 19:03:25 +03:00
John Preston
808e8dcf4f Inject discussed message in Replies section. 2020-09-29 19:03:25 +03:00
John Preston
c2bb2526d3 Handle updateReadDiscussion. 2020-09-29 19:03:25 +03:00
John Preston
59abe95754 Show comments unread status. 2020-09-29 19:03:25 +03:00
John Preston
040f29abe6 Remove some options from Replies three-dot menu. 2020-09-29 19:03:25 +03:00
John Preston
e9dffe78e3 Fix minimal width of message bubble with comments. 2020-09-29 19:03:25 +03:00
John Preston
3a51303fb0 Add go to original button to Replies chat. 2020-09-29 19:03:25 +03:00
John Preston
008a301755 Paint some sort of replies icon. 2020-09-29 19:03:24 +03:00
John Preston
be14456290 Show correct reply in Replies bot. 2020-09-29 19:03:24 +03:00
John Preston
4a94a0c438 Show replies dialog correctly. 2020-09-29 19:03:24 +03:00
John Preston
608d8307d9 Scroll to bottom when sending a comment. 2020-09-29 19:03:24 +03:00
John Preston
6f9ea1cc01 Allow posting comments being not in group. 2020-09-29 19:03:24 +03:00
John Preston
47170da813 Show comments button using 'has_link' flag. 2020-09-29 19:03:24 +03:00
John Preston
01ab6e6d4d Support anonymous group admins. 2020-09-29 19:03:24 +03:00
John Preston
b8424b1d89 Add read status tracking to comments. 2020-09-29 19:03:24 +03:00
John Preston
78d83a2c69 Show local sending messages in replies section. 2020-09-29 19:03:24 +03:00
John Preston
beb623bee2 Add root message display in replies section. 2020-09-29 19:03:23 +03:00
John Preston
d42ce87c09 Move discussion group link to three-dot menu. 2020-09-29 19:03:23 +03:00
John Preston
60002555c3 Track comments count correctly. 2020-09-29 19:03:23 +03:00
John Preston
fb20be3e6c Open channel comments, not replies. 2020-09-29 19:03:23 +03:00
John Preston
31e1ed216a Add comments button to channel posts. 2020-09-29 19:03:23 +03:00
John Preston
ce91caa820 Fix build on macOS. 2020-09-29 19:03:23 +03:00
John Preston
95a579f25f Clear text box when sending media in replies. 2020-09-29 19:03:23 +03:00
John Preston
9fe82480e1 Reply in replies by double click. 2020-09-29 19:03:23 +03:00
John Preston
17549ad5ea Allow replying inside replies section. 2020-09-29 19:03:23 +03:00
John Preston
f22a804220 Add navigation through reply stack. 2020-09-29 19:03:22 +03:00
John Preston
c563df7d9d Fix navigation in a message replies section. 2020-09-29 19:03:22 +03:00
John Preston
1849f01b15 Jump to near reply inside a replies thread. 2020-09-29 19:03:22 +03:00
John Preston
f8b83dd186 Remove mapbox::variant dependency. 2020-09-29 19:03:22 +03:00
John Preston
f0e1d2fd02 'base::optional_variant<' -> 'std::variant<v::null_t,' 2020-09-29 19:03:19 +03:00
John Preston
734d834a20 Replace mapbox variant with std::variant. 2020-09-29 19:03:19 +03:00
John Preston
b3eb41b989 Fix build instructions for old OS X versions. 2020-09-29 19:03:19 +03:00
John Preston
45419205c6 Simple sending from replies section. 2020-09-29 19:03:19 +03:00
John Preston
204645a715 Stick to bottom on new messages. 2020-09-29 19:03:19 +03:00
John Preston
50a0429786 Hide root reply info in replies thread. 2020-09-29 19:03:19 +03:00
John Preston
00cdae0369 Implement replies list request. 2020-09-29 19:03:18 +03:00
John Preston
437c9320cd Implement progressive jpeg loading and sending. 2020-09-29 19:03:18 +03:00
John Preston
0888901d79 Try using progressive jpeg photo size. 2020-09-29 19:03:18 +03:00
John Preston
55edb3bdfe Update API scheme to layer 119. Count replies. 2020-09-29 19:03:18 +03:00
John Preston
fcdc4cd465 Handle bot callback buttons with password. 2020-09-29 19:03:18 +03:00
John Preston
49c230b898 Update API scheme to layer 118. 2020-09-29 19:03:18 +03:00
John Preston
883a62c0a2 Return 'testmode' code when no authed accounts. 2020-09-29 19:03:18 +03:00
23rd
58008ab7b0 Removed App::wnd from local_url_handlers. 2020-09-29 19:02:52 +03:00
23rd
94468ecf6d Added ability to copy link of not installed sticker pack. 2020-09-29 19:02:52 +03:00
23rd
91118bf087 Removed App::wnd from history_view_context_menu. 2020-09-29 19:02:52 +03:00
Ilya Fedin
6805085bbc Use unique desktop file name for static binary 2020-09-29 18:54:01 +03:00
Ilya Fedin
78d874e9a3 Disable OpenAL WASAPI backend 2020-09-29 18:28:42 +03:00
BugLight
8d5e356733 Add custom host input that replaces commas with dots 2020-09-29 18:27:36 +03:00
Ilya Fedin
4c2779bbaf Fix saving maximized state on Linux 2020-09-29 18:25:57 +03:00
Ilya Fedin
70c993774a Get rid of redudant cmake options 2020-09-29 18:24:16 +03:00
Ilya Fedin
f128665f6b Fix -debug argument
processArguments is called before ComputeDebugMode gets called, Logs::DebugEnabled gets overriden that way.
Fix that by setting gDebugMode variable and checking it in ComputeDebugMode.
2020-09-20 16:51:01 +03:00
Ilya Fedin
0cd68f866d Get icon theme from gtk if qt5ct is unconfigured 2020-09-20 16:51:01 +03:00
Ilya Fedin
242ced4022 Write icon theme names to debug log 2020-09-20 16:51:01 +03:00
Vitaly Kryukov
23aef6c365 Update mtproto_domain_resolver.cpp 2020-09-10 19:46:48 +03:00
Vitaly Kryukov
210e3f0cb6 Bump DNS User-Agent 2020-09-10 19:46:48 +03:00
Ilya Fedin
d86b4659d6 Create OpenAL context without attributes 2020-09-10 19:45:43 +03:00
Ilya Fedin
f1cf6b4896 Move snap action to ubuntu-latest since it uses lxd 2020-09-10 19:39:52 +03:00
Ilya Fedin
8fd1253266 GNOME Wayland doesn't support native decorations 2020-09-10 19:39:21 +03:00
Ilya Fedin
5991cd4350 Add missed no-tests in release openssl build for Windows 2020-09-10 19:38:23 +03:00
Ilya Fedin
309372164c Cache make install calls in macos action 2020-09-10 19:38:23 +03:00
John Preston
f1cdc7e3f9 Update qt5ct submodule. 2020-08-31 17:40:03 +04:00
Ilya Fedin
dfad68a0b8 Fix tg_owt url 2020-08-31 12:01:43 +04:00
Ilya Fedin
0f887b3432 Update submodules 2020-08-31 12:01:43 +04:00
Ilya Fedin
077f0c393e No need to rebuild ffmpeg without NEON optimizations anymore 2020-08-31 12:01:43 +04:00
Ilya Fedin
7d29f9ce17 Don't check sws_scale return value
To workaround ffmpeg bug: https://gitlab.alpinelinux.org/alpine/aports/-/issues/11722
2020-08-31 12:01:43 +04:00
Ilya Fedin
6635d03818 Check if xcb-screensaver extension present 2020-08-30 17:00:43 +04:00
Ilya Fedin
e523492de0 Add missed methods to specific_mac.h and specific_win.h 2020-08-30 17:00:43 +04:00
Ilya Fedin
c77f1bf082 Add UnsetWindowExtents method 2020-08-30 17:00:43 +04:00
Ilya Fedin
3c8c059447 Eliminate the need of Q_OBJECT in main_window_linux and main_window_win 2020-08-30 17:00:43 +04:00
Ilya Fedin
612e0d4a10 Update window shadow size on window state change 2020-08-30 17:00:43 +04:00
Ilya Fedin
78a2835bbf Extents should be updated on each event only on Wayland 2020-08-30 17:00:43 +04:00
Ilya Fedin
ea8e256a23 Revert "Revert "Add main window shadow for Linux""
This reverts commit b7f5cfe083.
2020-08-30 17:00:43 +04:00
Ilya Fedin
2f2de84b43 Fix d-bus type in MutterDBusLastUserInputTime 2020-08-30 16:57:51 +04:00
John Preston
ead6892857 Update cmake_helpers submodule. 2020-08-30 16:54:47 +04:00
Ilya Fedin
2b642d4da9 -Wno-register is defined in options_linux.cmake now 2020-08-30 16:28:50 +04:00
Ilya Fedin
a474074705 Adapt snap build for tg_owt 2020-08-30 16:28:50 +04:00
John Preston
d34eabdc11 Fix crash in poll view destruction. 2020-08-24 17:59:44 +04:00
John Preston
f9be304e54 Fix crash in logout from passcoded screen. 2020-08-24 16:57:36 +04:00
John Preston
39b0662a2c Fix article inline results with long titles. 2020-08-24 16:34:55 +04:00
410 changed files with 13105 additions and 6325 deletions

21
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels: []
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: |
Hey there!
This issue will be automatically closed in 7 days if there would be no activity. We therefore assume that the user has lost interest or resolved the problem on their own.
Don't worry though; if this is an error, let us know with a comment and we'll be happy to reopen the issue.
Thanks!
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# Process only issues
only: issues

View File

@@ -182,7 +182,7 @@ jobs:
run: |
cd $LibrariesPath
git clone $GIT/01org/libva.git
git clone $GIT/intel/libva.git
cd libva
./autogen.sh --enable-static
make -j$(nproc)
@@ -222,7 +222,6 @@ jobs:
--disable-network \
--disable-autodetect \
--disable-everything \
--disable-neon \
--disable-alsa \
--disable-iconv \
--enable-libopus \
@@ -444,6 +443,7 @@ jobs:
-qt-harfbuzz \
-qt-pcre \
-qt-xcb \
-no-icu \
-no-gtk \
-static \
-dbus-runtime \

View File

@@ -167,7 +167,7 @@ jobs:
id: cache-opus
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/opus
path: ${{ env.LibrariesPath }}/opus-cache
key: ${{ runner.OS }}-opus-${{ env.CACHE_KEY }}
- name: Opus.
if: steps.cache-opus.outputs.cache-hit != 'true'
@@ -180,16 +180,17 @@ jobs:
./autogen.sh
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
make -j$(nproc)
sudo make DESTDIR="$LibrariesPath/opus-cache" install
- name: Opus install.
run: |
cd $LibrariesPath/opus
sudo make install
cd $LibrariesPath
sudo cp -R opus-cache/. /
- name: Libiconv cache.
id: cache-libiconv
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/${{ env.LIBICONV_VER }}
path: ${{ env.LibrariesPath }}/libiconv-cache
key: ${{ runner.OS }}-${{ env.LIBICONV_VER }}-${{ env.CACHE_KEY }}
- name: Libiconv.
if: steps.cache-libiconv.outputs.cache-hit != 'true'
@@ -201,10 +202,11 @@ jobs:
cd $LIBICONV_VER
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --enable-static --prefix=$PREFIX
make -j$(nproc)
sudo make DESTDIR="$LibrariesPath/libiconv-cache" install
- name: Libiconv install.
run: |
cd $LibrariesPath/$LIBICONV_VER
sudo make install
cd $LibrariesPath
sudo cp -R libiconv-cache/. /
- name: FFmpeg cache.
id: cache-ffmpeg

View File

@@ -12,7 +12,6 @@ on:
- '!.github/workflows/snap.yml'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/ffmpeg.diff'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
@@ -31,7 +30,6 @@ on:
- '!.github/workflows/snap.yml'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/ffmpeg.diff'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
@@ -43,8 +41,8 @@ on:
jobs:
linux:
name: Ubuntu 20.04
runs-on: ubuntu-20.04
name: Ubuntu
runs-on: ubuntu-latest
env:
UPLOAD_ARTIFACT: "false"
@@ -57,7 +55,10 @@ jobs:
- name: First set up.
run: |
sudo apt-get purge --autoremove lxd
sudo snap install --classic snapcraft
sudo snap install lxd
# Workaround for snapcraft
# See https://forum.snapcraft.io/t/13258

View File

@@ -0,0 +1,90 @@
name: User-agent updater.
on:
repository_dispatch:
types: ["Restart user_agent_updater workflow."]
schedule:
# At 00:00 on day-of-month 1.
- cron: '0 0 1 * *'
jobs:
User-agent:
runs-on: ubuntu-latest
env:
code_file: "Telegram/SourceFiles/mtproto/details/mtproto_domain_resolver.cpp"
skip: "0"
steps:
- name: Clone.
if: env.skip == '0'
uses: actions/checkout@v2
- name: Write a new version of Google Chrome to the user-agent for DNS.
if: env.skip == '0'
shell: python
run: |
import subprocess, os, re;
regExpVersion = "[0-9]+.[0-9]+.[0-9]+.[0-9]+";
chrome = "Chrome/";
def newVersion():
output = subprocess.check_output(["google-chrome", "--version"]);
version = re.search(regExpVersion, output);
if not version:
print("Can't find a Chrome version.");
exit();
return version.group(0);
newChromeVersion = newVersion();
print(newChromeVersion);
def writeUserAgent():
p = os.environ['code_file'];
w = open(p, "r");
content = w.read();
w.close();
regExpChrome = chrome + regExpVersion;
version = re.search(regExpChrome, content);
if not version:
print("Can't find an user-agent in the code.");
exit();
content = re.sub(regExpChrome, chrome + newChromeVersion, content);
w = open(p, "w");
w.write(content);
print("::set-env name=ChromeVersion::" + newChromeVersion);
writeUserAgent();
- name: Push to the current branch.
if: env.skip == '0' && env.ChromeVersion != ''
run: |
token=${{ secrets.TOKEN_FOR_MASTER_UPDATER }}
if [ -z "${token}" ]; then
echo "Token is unset. Nothing to do."
exit 0
fi
url=https://x-access-token:$token@github.com/$GITHUB_REPOSITORY
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git diff > git_diff.txt
if [[ ! -s git_diff.txt ]]; then
echo "Nothing to commit."
exit 0
fi
git add $code_file
git commit -m "Update User-Agent for DNS to Chrome $ChromeVersion."
git remote set-url origin $url
git push origin HEAD:$GITHUB_REF
echo "Done!"

View File

@@ -169,7 +169,7 @@ jobs:
move ossl_static.pdb out32.dbg\ossl_static
nmake clean
move out32.dbg\ossl_static out32.dbg\ossl_static.pdb
perl Configure no-shared VC-WIN32
perl Configure no-shared no-tests VC-WIN32
nmake
mkdir out32
move libcrypto.lib out32
@@ -206,11 +206,12 @@ jobs:
cd openal-soft
git checkout fix_capture
cd build
cmake ^
cmake .. ^
-G "Visual Studio 16 2019" ^
-A Win32 ^
-D LIBTYPE:STRING=STATIC ^
-D FORCE_STATIC_VCRT:STRING=ON ..
-D FORCE_STATIC_VCRT=ON ^
-D ALSOFT_BACKEND_WASAPI=OFF
msbuild -m OpenAL.vcxproj /property:Configuration=Debug

9
.gitmodules vendored
View File

@@ -1,9 +1,6 @@
[submodule "Telegram/ThirdParty/libtgvoip"]
path = Telegram/ThirdParty/libtgvoip
url = https://github.com/telegramdesktop/libtgvoip
[submodule "Telegram/ThirdParty/variant"]
path = Telegram/ThirdParty/variant
url = https://github.com/desktop-app/variant.git
[submodule "Telegram/ThirdParty/GSL"]
path = Telegram/ThirdParty/GSL
url = https://github.com/Microsoft/GSL.git
@@ -85,12 +82,6 @@
[submodule "Telegram/ThirdParty/qt5ct"]
path = Telegram/ThirdParty/qt5ct
url = https://github.com/desktop-app/qt5ct.git
[submodule "Telegram/ThirdParty/lxqt-qtplugin"]
path = Telegram/ThirdParty/lxqt-qtplugin
url = https://github.com/lxqt/lxqt-qtplugin.git
[submodule "Telegram/ThirdParty/libqtxdg"]
path = Telegram/ThirdParty/libqtxdg
url = https://github.com/lxqt/libqtxdg.git
[submodule "Telegram/ThirdParty/fcitx5-qt"]
path = Telegram/ThirdParty/fcitx5-qt
url = https://github.com/fcitx/fcitx5-qt.git

View File

@@ -36,5 +36,9 @@ include(cmake/options.cmake)
include(cmake/external/qt/package.cmake)
set(desktop_app_skip_libs
variant
)
add_subdirectory(cmake)
add_subdirectory(Telegram)

View File

@@ -34,6 +34,7 @@ Version **1.8.15** was the last that supports older systems
* Qt 5.12.8, 5.6.2 and 5.3.2 slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html))
* OpenSSL 1.1.1 and 1.0.1 ([OpenSSL License](https://www.openssl.org/source/license.html))
* WebRTC ([New BSD License](https://github.com/desktop-app/tg_owt/blob/master/src/LICENSE))
* zlib 1.2.11 ([zlib License](http://www.zlib.net/zlib_license.html))
* LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html))
* liblzma ([public domain](http://tukaani.org/xz/))
@@ -45,7 +46,6 @@ Version **1.8.15** was the last that supports older systems
* Opus codec ([BSD License](http://www.opus-codec.org/license/))
* FFmpeg ([LGPL](https://www.ffmpeg.org/legal.html))
* Guideline Support Library ([MIT License](https://github.com/Microsoft/GSL/blob/master/LICENSE))
* Mapbox Variant ([BSD License](https://github.com/mapbox/variant/blob/master/LICENSE))
* Range-v3 ([Boost License](https://github.com/ericniebler/range-v3/blob/master/LICENSE.txt))
* Open Sans font ([Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html))
* Vazir font ([License](https://github.com/rastikerdar/vazir-font/blob/master/LICENSE))

View File

@@ -21,21 +21,21 @@ add_subdirectory(lib_qr)
add_subdirectory(lib_webrtc)
add_subdirectory(codegen)
include(CheckCXXSourceCompiles)
include(lib_ui/cmake/generate_styles.cmake)
include(cmake/generate_lang.cmake)
include(cmake/generate_numbers.cmake)
get_filename_component(src_loc SourceFiles REALPATH)
get_filename_component(res_loc Resources REALPATH)
include(cmake/telegram_options.cmake)
include(cmake/lib_export.cmake)
include(cmake/lib_ffmpeg.cmake)
include(cmake/lib_mtproto.cmake)
include(cmake/lib_scheme.cmake)
include(cmake/lib_tgvoip.cmake)
include(cmake/lib_tgcalls.cmake)
include(cmake/td_export.cmake)
include(cmake/td_mtproto.cmake)
include(cmake/td_lang.cmake)
include(cmake/td_scheme.cmake)
include(cmake/td_ui.cmake)
set(style_files
boxes/boxes.style
@@ -61,10 +61,10 @@ set(dependent_style_files
${submodules_loc}/lib_ui/ui/basic.style
${submodules_loc}/lib_ui/ui/layers/layers.style
${submodules_loc}/lib_ui/ui/widgets/widgets.style
${src_loc}/ui/td_common.style
)
generate_styles(Telegram ${src_loc} "${style_files}" "${dependent_style_files}")
generate_lang(Telegram ${res_loc}/langs/lang.strings)
generate_numbers(Telegram ${res_loc}/numbers.txt)
set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON)
@@ -74,9 +74,11 @@ PRIVATE
tdesktop::lib_tgcalls_legacy
tdesktop::lib_tgcalls
tdesktop::lib_tgvoip
tdesktop::lib_mtproto
tdesktop::lib_scheme
tdesktop::lib_export
tdesktop::td_export
tdesktop::td_mtproto
tdesktop::td_lang
tdesktop::td_scheme
tdesktop::td_ui
desktop-app::lib_webrtc
desktop-app::lib_base
desktop-app::lib_crl
@@ -104,17 +106,12 @@ if (LINUX)
desktop-app::external_materialdecoration
desktop-app::external_nimf_qt5
desktop-app::external_qt5ct_support
desktop-app::external_xcb_screensaver
desktop-app::external_xcb
desktop-app::external_glib
)
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
# conflicts with Qt static link
if (DESKTOP_APP_USE_PACKAGED_LAZY_PLATFORMTHEMES)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_lxqt_qtplugin
)
endif()
target_link_libraries(Telegram
PRIVATE
desktop-app::external_statusnotifieritem
@@ -135,36 +132,6 @@ if (LINUX)
)
endif()
if (DESKTOP_APP_USE_PACKAGED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(XCB_SCREENSAVER REQUIRED IMPORTED_TARGET xcb-screensaver)
pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb)
target_link_libraries(Telegram
PRIVATE
PkgConfig::XCB_SCREENSAVER
PkgConfig::XCB
)
else()
target_link_static_libraries(Telegram PRIVATE xcb-screensaver)
target_link_libraries(Telegram PRIVATE xcb)
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(GLIB2 REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GOBJECT REQUIRED IMPORTED_TARGET gobject-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
target_link_libraries(Telegram
PRIVATE
PkgConfig::GLIB2
PkgConfig::GOBJECT
PkgConfig::GIO
)
target_compile_definitions(Telegram PRIVATE G_LOG_DOMAIN="Telegram")
target_compile_options(Telegram PRIVATE -Wno-register)
if (NOT TDESKTOP_DISABLE_GTK_INTEGRATION)
find_package(PkgConfig REQUIRED)
@@ -190,6 +157,8 @@ nice_target_sources(Telegram ${src_loc}
PRIVATE
${style_files}
api/api_authorizations.cpp
api/api_authorizations.h
api/api_bot.cpp
api/api_bot.h
api/api_chat_filters.cpp
@@ -468,6 +437,8 @@ PRIVATE
data/data_poll.h
data/data_pts_waiter.cpp
data/data_pts_waiter.h
data/data_replies_list.cpp
data/data_replies_list.h
data/data_reply_preview.cpp
data/data_reply_preview.h
data/data_search_controller.cpp
@@ -589,10 +560,14 @@ PRIVATE
history/view/history_view_message.cpp
history/view/history_view_message.h
history/view/history_view_object.h
history/view/history_view_replies_section.cpp
history/view/history_view_replies_section.h
history/view/history_view_schedule_box.cpp
history/view/history_view_schedule_box.h
history/view/history_view_scheduled_section.cpp
history/view/history_view_scheduled_section.h
history/view/history_view_send_action.cpp
history/view/history_view_send_action.h
history/view/history_view_service_message.cpp
history/view/history_view_service_message.h
history/view/history_view_top_bar_widget.cpp
@@ -712,23 +687,12 @@ PRIVATE
intro/intro_widget.h
lang/lang_cloud_manager.cpp
lang/lang_cloud_manager.h
lang/lang_file_parser.cpp
lang/lang_file_parser.h
lang/lang_hardcoded.h
lang/lang_instance.cpp
lang/lang_instance.h
lang/lang_keys.cpp
lang/lang_keys.h
lang/lang_numbers_animation.cpp
lang/lang_numbers_animation.h
lang/lang_tag.cpp
lang/lang_tag.h
lang/lang_text_entity.cpp
lang/lang_text_entity.h
lang/lang_translator.cpp
lang/lang_translator.h
lang/lang_values.cpp
lang/lang_values.h
main/main_account.cpp
main/main_account.h
main/main_app_config.cpp
@@ -1142,6 +1106,7 @@ PRIVATE
qt_static_plugins.cpp
settings.cpp
settings.h
stdafx.h
)
if (NOT LINUX)
@@ -1291,6 +1256,7 @@ target_compile_definitions(Telegram
PRIVATE
TDESKTOP_API_ID=${TDESKTOP_API_ID}
TDESKTOP_API_HASH=${TDESKTOP_API_HASH}
G_LOG_DOMAIN="Telegram"
)
if (APPLE OR NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL "" OR NOT "${output_name}" STREQUAL "Telegram")

View File

@@ -1,225 +0,0 @@
diff --git a/libavcodec/aarch64/Makefile b/libavcodec/aarch64/Makefile
index 00f93bf59f..52da7036f3 100644
--- a/libavcodec/aarch64/Makefile
+++ b/libavcodec/aarch64/Makefile
@@ -6,6 +6,7 @@ OBJS-$(CONFIG_H264DSP) += aarch64/h264dsp_init_aarch64.o
OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_init.o
OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_init_aarch64.o
OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o
+OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o
OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o
OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o
OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp_init.o
@@ -21,6 +22,7 @@ OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_init_aarch64.o
OBJS-$(CONFIG_VORBIS_DECODER) += aarch64/vorbisdsp_init.o
OBJS-$(CONFIG_VP9_DECODER) += aarch64/vp9dsp_init_10bpp_aarch64.o \
aarch64/vp9dsp_init_12bpp_aarch64.o \
+ aarch64/vp9mc_aarch64.o \
aarch64/vp9dsp_init_aarch64.o
# ARMv8 optimizations
@@ -41,8 +43,7 @@ NEON-OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_neon.o
NEON-OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_neon.o \
aarch64/hpeldsp_neon.o
NEON-OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_neon.o
-NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o \
- aarch64/simple_idct_neon.o
+NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/simple_idct_neon.o
NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o
NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o
NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o
diff --git a/libavcodec/aarch64/idctdsp_init_aarch64.c b/libavcodec/aarch64/idctdsp_init_aarch64.c
index 0406e60830..742a3372e3 100644
--- a/libavcodec/aarch64/idctdsp_init_aarch64.c
+++ b/libavcodec/aarch64/idctdsp_init_aarch64.c
@@ -21,6 +21,8 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/arm/cpu.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/idctdsp.h"
#include "idct.h"
@@ -28,7 +30,9 @@
av_cold void ff_idctdsp_init_aarch64(IDCTDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth)
{
- if (!avctx->lowres && !high_bit_depth) {
+ int cpu_flags = av_get_cpu_flags();
+
+ if (have_neon(cpu_flags) && !avctx->lowres && !high_bit_depth) {
if (avctx->idct_algo == FF_IDCT_AUTO ||
avctx->idct_algo == FF_IDCT_SIMPLEAUTO ||
avctx->idct_algo == FF_IDCT_SIMPLENEON) {
diff --git a/libavcodec/aarch64/vp9mc_16bpp_neon.S b/libavcodec/aarch64/vp9mc_16bpp_neon.S
index cac6428709..53b372c262 100644
--- a/libavcodec/aarch64/vp9mc_16bpp_neon.S
+++ b/libavcodec/aarch64/vp9mc_16bpp_neon.S
@@ -25,31 +25,6 @@
// const uint8_t *ref, ptrdiff_t ref_stride,
// int h, int mx, int my);
-function ff_vp9_copy128_aarch64, export=1
-1:
- ldp x5, x6, [x2]
- ldp x7, x8, [x2, #16]
- stp x5, x6, [x0]
- ldp x9, x10, [x2, #32]
- stp x7, x8, [x0, #16]
- subs w4, w4, #1
- ldp x11, x12, [x2, #48]
- stp x9, x10, [x0, #32]
- stp x11, x12, [x0, #48]
- ldp x5, x6, [x2, #64]
- ldp x7, x8, [x2, #80]
- stp x5, x6, [x0, #64]
- ldp x9, x10, [x2, #96]
- stp x7, x8, [x0, #80]
- ldp x11, x12, [x2, #112]
- stp x9, x10, [x0, #96]
- stp x11, x12, [x0, #112]
- add x2, x2, x3
- add x0, x0, x1
- b.ne 1b
- ret
-endfunc
-
function ff_vp9_avg64_16_neon, export=1
mov x5, x0
sub x1, x1, #64
diff --git a/libavcodec/aarch64/vp9mc_aarch64.S b/libavcodec/aarch64/vp9mc_aarch64.S
new file mode 100644
index 0000000000..f17a8cf04a
--- /dev/null
+++ b/libavcodec/aarch64/vp9mc_aarch64.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/aarch64/asm.S"
+
+// All public functions in this file have the following signature:
+// typedef void (*vp9_mc_func)(uint8_t *dst, ptrdiff_t dst_stride,
+// const uint8_t *ref, ptrdiff_t ref_stride,
+// int h, int mx, int my);
+
+function ff_vp9_copy128_aarch64, export=1
+1:
+ ldp x5, x6, [x2]
+ ldp x7, x8, [x2, #16]
+ stp x5, x6, [x0]
+ ldp x9, x10, [x2, #32]
+ stp x7, x8, [x0, #16]
+ subs w4, w4, #1
+ ldp x11, x12, [x2, #48]
+ stp x9, x10, [x0, #32]
+ stp x11, x12, [x0, #48]
+ ldp x5, x6, [x2, #64]
+ ldp x7, x8, [x2, #80]
+ stp x5, x6, [x0, #64]
+ ldp x9, x10, [x2, #96]
+ stp x7, x8, [x0, #80]
+ ldp x11, x12, [x2, #112]
+ stp x9, x10, [x0, #96]
+ stp x11, x12, [x0, #112]
+ add x2, x2, x3
+ add x0, x0, x1
+ b.ne 1b
+ ret
+endfunc
+
+function ff_vp9_copy64_aarch64, export=1
+1:
+ ldp x5, x6, [x2]
+ ldp x7, x8, [x2, #16]
+ stp x5, x6, [x0]
+ ldp x9, x10, [x2, #32]
+ stp x7, x8, [x0, #16]
+ subs w4, w4, #1
+ ldp x11, x12, [x2, #48]
+ stp x9, x10, [x0, #32]
+ stp x11, x12, [x0, #48]
+ add x2, x2, x3
+ add x0, x0, x1
+ b.ne 1b
+ ret
+endfunc
+
+function ff_vp9_copy32_aarch64, export=1
+1:
+ ldp x5, x6, [x2]
+ ldp x7, x8, [x2, #16]
+ stp x5, x6, [x0]
+ subs w4, w4, #1
+ stp x7, x8, [x0, #16]
+ add x2, x2, x3
+ add x0, x0, x1
+ b.ne 1b
+ ret
+endfunc
diff --git a/libavcodec/aarch64/vp9mc_neon.S b/libavcodec/aarch64/vp9mc_neon.S
index f67624ca04..abf2bae9db 100644
--- a/libavcodec/aarch64/vp9mc_neon.S
+++ b/libavcodec/aarch64/vp9mc_neon.S
@@ -25,23 +25,6 @@
// const uint8_t *ref, ptrdiff_t ref_stride,
// int h, int mx, int my);
-function ff_vp9_copy64_aarch64, export=1
-1:
- ldp x5, x6, [x2]
- ldp x7, x8, [x2, #16]
- stp x5, x6, [x0]
- ldp x9, x10, [x2, #32]
- stp x7, x8, [x0, #16]
- subs w4, w4, #1
- ldp x11, x12, [x2, #48]
- stp x9, x10, [x0, #32]
- stp x11, x12, [x0, #48]
- add x2, x2, x3
- add x0, x0, x1
- b.ne 1b
- ret
-endfunc
-
function ff_vp9_avg64_neon, export=1
mov x5, x0
1:
@@ -64,19 +47,6 @@ function ff_vp9_avg64_neon, export=1
ret
endfunc
-function ff_vp9_copy32_aarch64, export=1
-1:
- ldp x5, x6, [x2]
- ldp x7, x8, [x2, #16]
- stp x5, x6, [x0]
- subs w4, w4, #1
- stp x7, x8, [x0, #16]
- add x2, x2, x3
- add x0, x0, x1
- b.ne 1b
- ret
-endfunc
-
function ff_vp9_avg32_neon, export=1
1:
ld1 {v2.16b, v3.16b}, [x2], x3

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 B

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 661 B

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -812,6 +812,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_set_group_photo" = "Set Photo";
"lng_profile_add_participant" = "Add Members";
"lng_profile_view_channel" = "View Channel";
"lng_profile_view_discussion" = "View discussion";
"lng_profile_join_channel" = "Join Channel";
"lng_profile_join_group" = "Join Group";
"lng_profile_delete_and_exit" = "Leave";
@@ -1319,6 +1320,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_message_ph" = "Write a message...";
"lng_broadcast_ph" = "Broadcast a message...";
"lng_broadcast_silent_ph" = "Silent broadcast...";
"lng_send_anonymous_ph" = "Send anonymously...";
"lng_record_cancel" = "Release outside this field to cancel";
"lng_will_be_notified" = "Members will be notified when you post";
"lng_wont_be_notified" = "Members will not be notified when you post";
@@ -1330,7 +1332,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_restart_button" = "Restart";
"lng_channel_mute" = "Mute";
"lng_channel_unmute" = "Unmute";
"lng_channel_discuss" = "Discuss";
"lng_saved_messages" = "Saved Messages";
"lng_saved_short" = "Save";
"lng_saved_forward_here" = "Forward messages here for quick access";
@@ -1344,6 +1345,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_scheduled_send_now_many#one" = "Send {count} message now?";
"lng_scheduled_send_now_many#other" = "Send {count} messages now?";
"lng_replies_view#one" = "View {count} Reply";
"lng_replies_view#other" = "View {count} Replies";
"lng_replies_view_thread" = "View Thread";
"lng_replies_header#one" = "{count} reply";
"lng_replies_header#other" = "{count} replies";
"lng_replies_header_none" = "Replies";
"lng_comments_header#one" = "{count} comment";
"lng_comments_header#other" = "{count} comments";
"lng_comments_header_none" = "Comments";
"lng_comments_open_count#one" = "{count} comment";
"lng_comments_open_count#other" = "{count} comments";
"lng_comments_open_none" = "Leave a comment";
"lng_replies_view_original" = "View in chat";
"lng_replies_messages" = "Replies";
"lng_replies_discussion_started" = "Discussion started";
"lng_replies_no_comments" = "No comments here yet...";
"lng_archived_name" = "Archived chats";
"lng_archived_add" = "Archive";
"lng_archived_remove" = "Unarchive";
@@ -1439,6 +1457,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_unpin_from_top" = "Unpin from top";
"lng_context_mark_unread" = "Mark as unread";
"lng_context_mark_read" = "Mark as read";
"lng_context_mark_read_sure" = "Are you sure you want to mark all chats from this folder as read?";
"lng_context_mark_read_all" = "Mark all chats as read";
"lng_context_mark_read_all_sure" = "Are you sure you want to mark all chats as read?";
"lng_context_archive_expand" = "Expand";
"lng_context_archive_collapse" = "Collapse";
"lng_context_archive_to_menu" = "Move to main menu";
@@ -1821,6 +1842,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_rights_group_invite" = "Add users";
"lng_rights_group_pin" = "Pin messages";
"lng_rights_group_delete" = "Delete messages";
"lng_rights_group_anonymous" = "Remain Anonymous";
"lng_rights_add_admins" = "Add new admins";
"lng_rights_chat_read" = "Read messages";
"lng_rights_chat_send_text" = "Send messages";
@@ -1853,6 +1875,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_rights_transfer_done_group" = "{user} is now the owner of the group.";
"lng_rights_transfer_done_channel" = "{user} is now the owner of the channel.";
"lng_bots_password_confirm_check_about" = "You can finish this action only if you have:";
"lng_bots_password_confirm_title" = "Two-step verification";
"lng_bots_password_confirm_description" = "Please enter your password to confirm the action.";
"lng_restricted_send_message" = "The admins of this group restricted you from writing here.";
"lng_restricted_send_media" = "The admins of this group restricted you from posting media content here.";
"lng_restricted_send_stickers" = "The admins of this group restricted you from posting stickers here.";
@@ -2245,6 +2271,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_language_not_ready_link" = "translations platform";
"lng_launch_exe_warning" = "This file has a {extension} extension.\nAre you sure you want to run it?";
"lng_launch_svg_warning" = "Opening this file can potentially expose your IP address to its sender. Continue?";
"lng_launch_exe_sure" = "Run";
"lng_launch_exe_dont_ask" = "Don't ask me again";

View File

@@ -128,7 +128,7 @@ channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull;
channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
@@ -141,8 +141,8 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#d20b9f3c flags:# has_video:flags.0?true photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#452c0e65 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
message#58ae39c9 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
messageService#286fa604 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
@@ -192,6 +192,7 @@ photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
photoSizeProgressive#5aa86a51 type:string location:FileLocation w:int h:int sizes:Vector<int> = PhotoSize;
geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
@@ -231,8 +232,6 @@ contact#f911c994 user_id:int mutual:Bool = Contact;
importedContact#d0028438 user_id:int client_id:long = ImportedContact;
contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
@@ -240,8 +239,8 @@ contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector
contacts.importedContacts#77d01c3b imported:Vector<ImportedContact> popular_invites:Vector<PopularContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts;
contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.blocked#ade1591 blocked:Vector<PeerBlocked> chats:Vector<Chat> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#e1664194 count:int blocked:Vector<PeerBlocked> chats:Vector<Chat> users:Vector<User> = contacts.Blocked;
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
@@ -292,7 +291,6 @@ updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update;
updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update;
updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update;
updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
updateUserBlocked#80ece81a user_id:int blocked:Bool = Update;
updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update;
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
@@ -358,6 +356,11 @@ updateDialogFilterOrder#a5d72105 order:Vector<int> = Update;
updateDialogFilters#3504914f = Update;
updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update;
updateChannelParticipant#65d2b464 flags:# channel_id:int date:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant qts:int = Update;
updateChannelMessageForwards#6e8a84df channel_id:int id:int forwards:int = Update;
updateReadChannelDiscussionInbox#1cc7de54 flags:# channel_id:int top_msg_id:int read_max_id:int broadcast_id:flags.0?int broadcast_post:flags.0?int = Update;
updateReadChannelDiscussionOutbox#4638a26c channel_id:int top_msg_id:int read_max_id:int = Update;
updatePeerBlocked#246a4b22 peer_id:Peer blocked:Bool = Update;
updateChannelUserTyping#ff2abe9f flags:# channel_id:int top_msg_id:flags.0?int user_id:int action:SendMessageAction = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@@ -367,8 +370,8 @@ updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_mess
updates.differenceTooLong#4afe8f6d pts:int = updates.Difference;
updatesTooLong#e317af7e = Updates;
updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
updateShortMessage#2296d2c8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> = Updates;
updateShortChatMessage#402d5dbb flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> = Updates;
updateShort#78d4dec1 update:Update date:int = Updates;
updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
@@ -547,7 +550,7 @@ botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = Bo
keyboardButton#a2fa4880 text:string = KeyboardButton;
keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
keyboardButtonCallback#35bbdb6b flags:# requires_password:flags.0?true text:string data:bytes = KeyboardButton;
keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
@@ -601,7 +604,7 @@ channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantCreator#808d15a4 flags:# user_id:int rank:flags.0?string = ChannelParticipant;
channelParticipantCreator#447dca4b flags:# user_id:int admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant;
channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
@@ -648,7 +651,7 @@ messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_off
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
messageFwdHeader#353a686b flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader;
messageFwdHeader#5f777dce flags:# from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader;
auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType;
@@ -1029,7 +1032,7 @@ chatOnlines#f041e250 onlines:int = ChatOnlines;
statsURL#47a971e0 url:string = StatsURL;
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights;
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true = ChatAdminRights;
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
@@ -1150,6 +1153,27 @@ stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAnd
globalPrivacySettings#bea2f424 flags:# archive_and_mute_new_noncontact_peers:flags.0?Bool = GlobalPrivacySettings;
help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector<string> patterns:flags.1?Vector<string> = help.CountryCode;
help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector<help.CountryCode> = help.Country;
help.countriesListNotModified#93cc1f32 = help.CountriesList;
help.countriesList#87d0759e countries:Vector<help.Country> hash:int = help.CountriesList;
messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews;
messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> users:Vector<User> = messages.MessageViews;
stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats;
messages.discussionMessage#f5dd8f9d flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?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;
messageReplies#4128faac flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?int max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;
peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -1257,8 +1281,8 @@ contacts.getContacts#c023849f hash:int = contacts.Contacts;
contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts;
contacts.deleteContacts#96a0e00 id:Vector<InputUser> = Updates;
contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool;
contacts.block#332b49fc id:InputUser = Bool;
contacts.unblock#e54100bd id:InputUser = Bool;
contacts.block#68cc1411 id:InputPeer = Bool;
contacts.unblock#bea65d50 id:InputPeer = Bool;
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
contacts.search#11f812d8 q:string limit:int = contacts.Found;
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
@@ -1270,19 +1294,20 @@ contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
contacts.addContact#e8f463d0 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string = Updates;
contacts.acceptContact#f831a20f id:InputUser = Updates;
contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates;
contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates;
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.search#4e17810b flags:# peer:InputPeer q:string from_id:flags.0?InputUser top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool;
@@ -1299,8 +1324,8 @@ messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerp
messages.discardEncryption#edd923c5 chat_id:int = Bool;
messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
@@ -1315,10 +1340,10 @@ messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet
messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult;
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector<int> increment:Bool = messages.MessageViews;
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
messages.searchGlobal#4bc6589a flags:# folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
@@ -1329,7 +1354,7 @@ messages.sendInlineBotResult#220815b0 flags:# silent:flags.5?true background:fla
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer;
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
@@ -1394,6 +1419,9 @@ messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
messages.getOldFeaturedStickers#5fe7025b offset:int limit:int hash:int = messages.FeaturedStickers;
messages.getReplies#24b581ba peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage;
messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@@ -1434,6 +1462,7 @@ help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<Mess
help.getPromoData#c0977421 = help.PromoData;
help.hidePromoData#1e251c95 peer:InputPeer = Bool;
help.dismissSuggestion#77fa99f suggestion:string = Bool;
help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
@@ -1454,7 +1483,7 @@ channels.joinChannel#24b524c5 channel:InputChannel = Updates;
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink;
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats;
channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates;
@@ -1511,5 +1540,7 @@ folders.deleteFolder#1c295881 folder_id:int = Updates;
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats;
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 117
// LAYER 119

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="2.3.2.0" />
Version="2.4.4.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>

View File

@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,3,2,0
PRODUCTVERSION 2,3,2,0
FILEVERSION 2,4,4,0
PRODUCTVERSION 2,4,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "2.3.2.0"
VALUE "FileVersion", "2.4.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.3.2.0"
VALUE "ProductVersion", "2.4.4.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,3,2,0
PRODUCTVERSION 2,3,2,0
FILEVERSION 2,4,4,0
PRODUCTVERSION 2,4,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop Updater"
VALUE "FileVersion", "2.3.2.0"
VALUE "FileVersion", "2.4.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.3.2.0"
VALUE "ProductVersion", "2.4.4.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -0,0 +1,166 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_authorizations.h"
#include "apiwrap.h"
#include "base/unixtime.h"
#include "core/changelogs.h"
#include "lang/lang_keys.h"
namespace Api {
namespace {
constexpr auto TestApiId = 17349;
constexpr auto DesktopApiId = 2040;
Authorizations::Entry ParseEntry(const MTPDauthorization &data) {
auto result = Authorizations::Entry();
result.hash = data.is_current() ? 0 : data.vhash().v;
result.incomplete = data.is_password_pending();
const auto apiId = data.vapi_id().v;
const auto isTest = (apiId == TestApiId);
const auto isDesktop = (apiId == DesktopApiId) || isTest;
const auto appName = isDesktop
? QString("Telegram Desktop%1").arg(isTest ? " (GitHub)" : QString())
: qs(data.vapp_name());// +qsl(" for ") + qs(d.vplatform());
const auto appVer = [&] {
const auto version = qs(data.vapp_version());
if (isDesktop) {
const auto verInt = version.toInt();
if (version == QString::number(verInt)) {
return Core::FormatVersionDisplay(verInt);
}
} else {
if (const auto index = version.indexOf('('); index >= 0) {
return version.mid(index);
}
}
return version;
}();
result.name = QString("%1%2")
.arg(appName)
.arg(appVer.isEmpty() ? QString() : (' ' + appVer));
const auto country = qs(data.vcountry());
const auto platform = qs(data.vplatform());
//const auto &countries = countriesByISO2();
//const auto j = countries.constFind(country);
//if (j != countries.cend()) {
// country = QString::fromUtf8(j.value()->name);
//}
result.activeTime = data.vdate_active().v
? data.vdate_active().v
: data.vdate_created().v;
result.info = QString("%1, %2%3")
.arg(qs(data.vdevice_model()))
.arg(platform.isEmpty() ? QString() : platform + ' ')
.arg(qs(data.vsystem_version()));
result.ip = qs(data.vip())
+ (country.isEmpty()
? QString()
: QString::fromUtf8(" \xe2\x80\x93 ") + country);
if (!result.hash) {
result.active = tr::lng_status_online(tr::now);
} else {
const auto now = QDateTime::currentDateTime();
const auto lastTime = base::unixtime::parse(result.activeTime);
const auto nowDate = now.date();
const auto lastDate = lastTime.date();
if (lastDate == nowDate) {
result.active = lastTime.toString(cTimeFormat());
} else if (lastDate.year() == nowDate.year()
&& lastDate.weekNumber() == nowDate.weekNumber()) {
result.active = langDayOfWeek(lastDate);
} else {
result.active = lastDate.toString(qsl("d.MM.yy"));
}
}
return result;
}
} // namespace
Authorizations::Authorizations(not_null<ApiWrap*> api)
: _api(&api->instance()) {
}
void Authorizations::reload() {
if (_requestId) {
return;
}
_requestId = _api.request(MTPaccount_GetAuthorizations(
)).done([=](const MTPaccount_Authorizations &result) {
_requestId = 0;
_lastReceived = crl::now();
result.match([&](const MTPDaccount_authorizations &auths) {
_list = (
auths.vauthorizations().v
) | ranges::view::transform([](const MTPAuthorization &d) {
return ParseEntry(d.c_authorization());
}) | ranges::to<List>;
_listChanges.fire({});
});
}).fail([=](const RPCError &error) {
_requestId = 0;
}).send();
}
void Authorizations::cancelCurrentRequest() {
_api.request(base::take(_requestId)).cancel();
}
void Authorizations::requestTerminate(
Fn<void(const MTPBool &result)> &&done,
Fn<void(const RPCError &error)> &&fail,
std::optional<uint64> hash) {
auto request = hash
? MTPaccount_ResetAuthorization(MTP_long(*hash))
: MTPaccount_ResetAuthorization();
_api.request(std::move(request))
.done(std::move(done))
.fail(std::move(fail))
.send();
}
Authorizations::List Authorizations::list() const {
return _list;
}
auto Authorizations::listChanges() const
-> rpl::producer<Authorizations::List> {
return rpl::single(
list()
) | rpl::then(
_listChanges.events() | rpl::map([=] { return list(); }));
}
rpl::producer<int> Authorizations::totalChanges() const {
return rpl::single(
total()
) | rpl::then(
_listChanges.events() | rpl::map([=] { return total(); }));
}
int Authorizations::total() const {
return ranges::count_if(
_list,
ranges::not_fn(&Entry::incomplete));
}
crl::time Authorizations::lastReceivedTime() {
return _lastReceived;
}
} // namespace Api

View File

@@ -0,0 +1,54 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/sender.h"
class ApiWrap;
namespace Api {
class Authorizations final {
public:
explicit Authorizations(not_null<ApiWrap*> api);
struct Entry {
uint64 hash = 0;
bool incomplete = false;
TimeId activeTime = 0;
QString name, active, info, ip;
};
using List = std::vector<Entry>;
void reload();
void cancelCurrentRequest();
void requestTerminate(
Fn<void(const MTPBool &result)> &&done,
Fn<void(const RPCError &error)> &&fail,
std::optional<uint64> hash = std::nullopt);
[[nodiscard]] crl::time lastReceivedTime();
[[nodiscard]] List list() const;
[[nodiscard]] rpl::producer<List> listChanges() const;
[[nodiscard]] int total() const;
[[nodiscard]] rpl::producer<int> totalChanges() const;
private:
MTP::Sender _api;
mtpRequestId _requestId = 0;
List _list;
rpl::event_stream<> _listChanges;
crl::time _lastReceived = 0;
};
} // namespace Api

View File

@@ -8,9 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_bot.h"
#include "apiwrap.h"
#include "core/core_cloud_password.h"
#include "api/api_send_progress.h"
#include "boxes/confirm_box.h"
#include "boxes/share_box.h"
#include "boxes/passcode_box.h"
#include "lang/lang_keys.h"
#include "core/click_handler_types.h"
#include "data/data_changes.h"
#include "data/data_peer.h"
@@ -20,10 +23,129 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_components.h"
#include "main/main_session.h"
#include "ui/toast/toast.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
namespace Api {
namespace {
void SendBotCallbackData(
not_null<HistoryItem*> item,
int row,
int column,
std::optional<MTPInputCheckPasswordSRP> password = std::nullopt,
Fn<void(const RPCError &)> handleError = nullptr) {
if (!IsServerMsgId(item->id)) {
return;
}
const auto history = item->history();
const auto session = &history->session();
const auto owner = &history->owner();
const auto api = &session->api();
const auto bot = item->getMessageBot();
const auto fullId = item->fullId();
const auto getButton = [=] {
return HistoryMessageMarkupButton::Get(
owner,
fullId,
row,
column);
};
const auto button = getButton();
if (!button || button->requestId) {
return;
}
using ButtonType = HistoryMessageMarkupButton::Type;
const auto isGame = (button->type == ButtonType::Game);
auto flags = MTPmessages_GetBotCallbackAnswer::Flags(0);
QByteArray sendData;
if (isGame) {
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_game;
} else if (button->type == ButtonType::Callback
|| button->type == ButtonType::CallbackWithPassword) {
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data;
sendData = button->data;
}
const auto withPassword = password.has_value();
if (withPassword) {
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_password;
}
button->requestId = api->request(MTPmessages_GetBotCallbackAnswer(
MTP_flags(flags),
history->peer->input,
MTP_int(item->id),
MTP_bytes(sendData),
password.value_or(MTP_inputCheckPasswordEmpty())
)).done([=](const MTPmessages_BotCallbackAnswer &result) {
const auto item = owner->message(fullId);
if (!item) {
return;
}
if (const auto button = getButton()) {
button->requestId = 0;
owner->requestItemRepaint(item);
}
result.match([&](const MTPDmessages_botCallbackAnswer &data) {
if (const auto message = data.vmessage()) {
if (data.is_alert()) {
Ui::show(Box<InformBox>(qs(*message)));
} else {
if (withPassword) {
Ui::hideLayer();
}
Ui::Toast::Show(qs(*message));
}
} else if (const auto url = data.vurl()) {
const auto link = qs(*url);
if (!isGame) {
UrlClickHandler::Open(link);
return;
}
const auto scoreLink = AppendShareGameScoreUrl(
session,
link,
item->fullId());
BotGameUrlClickHandler(bot, scoreLink).onClick({});
session->sendProgressManager().update(
history,
Api::SendProgressType::PlayGame);
} else if (withPassword) {
Ui::hideLayer();
}
});
}).fail([=](const RPCError &error) {
const auto item = owner->message(fullId);
if (!item) {
return;
}
// Show error?
if (const auto button = getButton()) {
button->requestId = 0;
owner->requestItemRepaint(item);
}
if (handleError) {
handleError(error);
}
}).send();
session->changes().messageUpdated(
item,
Data::MessageUpdate::Flag::BotCallbackSent
);
}
} // namespace
void SendBotCallbackData(
not_null<HistoryItem*> item,
int row,
int column) {
SendBotCallbackData(item, row, column, MTP_inputCheckPasswordEmpty());
}
void SendBotCallbackDataWithPassword(
not_null<HistoryItem*> item,
int row,
int column) {
@@ -44,74 +166,63 @@ void SendBotCallbackData(
column);
};
const auto button = getButton();
if (!button) {
if (!button || button->requestId) {
return;
}
using ButtonType = HistoryMessageMarkupButton::Type;
const auto isGame = (button->type == ButtonType::Game);
auto flags = MTPmessages_GetBotCallbackAnswer::Flags(0);
QByteArray sendData;
if (isGame) {
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_game;
} else if (button->type == ButtonType::Callback) {
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data;
sendData = button->data;
}
button->requestId = api->request(MTPmessages_GetBotCallbackAnswer(
MTP_flags(flags),
history->peer->input,
MTP_int(item->id),
MTP_bytes(sendData)
)).done([=](const MTPmessages_BotCallbackAnswer &result) {
const auto item = owner->message(fullId);
if (!item) {
return;
}
if (const auto button = getButton()) {
button->requestId = 0;
owner->requestItemRepaint(item);
}
result.match([&](const MTPDmessages_botCallbackAnswer &data) {
if (const auto message = data.vmessage()) {
if (data.is_alert()) {
Ui::show(Box<InformBox>(qs(*message)));
} else {
Ui::Toast::Show(qs(*message));
api->reloadPasswordState();
SendBotCallbackData(item, row, column, MTP_inputCheckPasswordEmpty(), [=](const RPCError &error) {
auto box = PrePasswordErrorBox(
error,
session,
tr::lng_bots_password_confirm_check_about(
tr::now,
Ui::Text::WithEntities));
if (box) {
Ui::show(std::move(box));
} else {
auto lifetime = std::make_shared<rpl::lifetime>();
button->requestId = -1;
api->passwordState(
) | rpl::take(
1
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) mutable {
if (lifetime) {
base::take(lifetime)->destroy();
}
} else if (const auto url = data.vurl()) {
const auto link = qs(*url);
if (!isGame) {
UrlClickHandler::Open(link);
if (const auto button = getButton()) {
if (button->requestId == -1) {
button->requestId = 0;
}
} else {
return;
}
const auto scoreLink = AppendShareGameScoreUrl(
session,
link,
item->fullId());
BotGameUrlClickHandler(bot, scoreLink).onClick({});
session->sendProgressManager().update(
history,
Api::SendProgressType::PlayGame);
}
});
}).fail([=](const RPCError &error) {
const auto item = owner->message(fullId);
if (!item) {
return;
const auto box = std::make_shared<QPointer<PasscodeBox>>();
auto fields = PasscodeBox::CloudFields::From(state);
fields.customTitle = tr::lng_bots_password_confirm_title();
fields.customDescription
= tr::lng_bots_password_confirm_description(tr::now);
fields.customSubmitButton = tr::lng_passcode_submit();
fields.customCheckCallback = [=](
const Core::CloudPasswordResult &result) {
if (const auto button = getButton()) {
if (button->requestId) {
return;
}
} else {
return;
}
if (const auto item = owner->message(fullId)) {
SendBotCallbackData(item, row, column, result.result, [=](const RPCError &error) {
if (*box) {
(*box)->handleCustomCheckError(error);
}
});
}
};
*box = Ui::show(Box<PasscodeBox>(session, fields));
}, *lifetime);
}
// Show error?
if (const auto button = getButton()) {
button->requestId = 0;
owner->requestItemRepaint(item);
}
}).send();
session->changes().messageUpdated(
item,
Data::MessageUpdate::Flag::BotCallbackSent
);
});
}
} // namespace Api

View File

@@ -16,4 +16,9 @@ void SendBotCallbackData(
int row,
int column);
void SendBotCallbackDataWithPassword(
not_null<HistoryItem*> item,
int row,
int column);
} // namespace Api

View File

@@ -10,12 +10,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "history/history.h"
#include "data/data_peer.h"
#include "data/data_user.h"
#include "base/unixtime.h"
#include "data/data_peer_values.h"
#include "apiwrap.h"
namespace Api {
namespace {
constexpr auto kCancelTypingActionTimeout = crl::time(5000);
constexpr auto kSetMyActionForMs = 10 * crl::time(1000);
constexpr auto kSendTypingsToOfflineFor = TimeId(30);
} // namespace
@@ -27,7 +32,14 @@ SendProgressManager::SendProgressManager(not_null<Main::Session*> session)
void SendProgressManager::cancel(
not_null<History*> history,
SendProgressType type) {
const auto i = _requests.find({ history, type });
cancel(history, 0, type);
}
void SendProgressManager::cancel(
not_null<History*> history,
MsgId topMsgId,
SendProgressType type) {
const auto i = _requests.find(Key{ history, topMsgId, type });
if (i != _requests.end()) {
_session->api().request(i->second).cancel();
_requests.erase(i);
@@ -42,29 +54,61 @@ void SendProgressManager::cancelTyping(not_null<History*> history) {
void SendProgressManager::update(
not_null<History*> history,
SendProgressType type,
int32 progress) {
int progress) {
update(history, 0, type, progress);
}
void SendProgressManager::update(
not_null<History*> history,
MsgId topMsgId,
SendProgressType type,
int progress) {
const auto peer = history->peer;
if (peer->isSelf() || (peer->isChannel() && !peer->isMegagroup())) {
return;
}
const auto doing = (progress >= 0);
if (history->mySendActionUpdated(type, doing)) {
cancel(history, type);
const auto key = Key{ history, topMsgId, type };
if (updated(key, doing)) {
cancel(history, topMsgId, type);
if (doing) {
send(history, type, progress);
send(key, progress);
}
}
}
void SendProgressManager::send(
not_null<History*> history,
SendProgressType type,
int32 progress) {
bool SendProgressManager::updated(const Key &key, bool doing) {
const auto now = crl::now();
const auto i = _updated.find(key);
if (doing) {
if (i == end(_updated)) {
_updated.emplace(key, now + kSetMyActionForMs);
} else if (i->second > now + (kSetMyActionForMs / 2)) {
return false;
} else {
i->second = now + kSetMyActionForMs;
}
} else {
if (i == end(_updated)) {
return false;
} else if (i->second <= now) {
return false;
} else {
_updated.erase(i);
}
}
return true;
}
void SendProgressManager::send(const Key &key, int progress) {
if (skipRequest(key)) {
return;
}
using Type = SendProgressType;
const auto action = [&]() -> MTPsendMessageAction {
const auto p = MTP_int(progress);
switch (type) {
switch (key.type) {
case Type::Typing: return MTP_sendMessageTypingAction();
case Type::RecordVideo: return MTP_sendMessageRecordVideoAction();
case Type::UploadVideo: return MTP_sendMessageUploadVideoAction(p);
@@ -81,19 +125,36 @@ void SendProgressManager::send(
}
}();
const auto requestId = _session->api().request(MTPmessages_SetTyping(
history->peer->input,
MTP_flags(key.topMsgId
? MTPmessages_SetTyping::Flag::f_top_msg_id
: MTPmessages_SetTyping::Flag(0)),
key.history->peer->input,
MTP_int(key.topMsgId),
action
)).done([=](const MTPBool &result, mtpRequestId requestId) {
done(result, requestId);
}).send();
_requests.emplace(Key{ history, type }, requestId);
_requests.emplace(key, requestId);
if (type == Type::Typing) {
_stopTypingHistory = history;
if (key.type == Type::Typing) {
_stopTypingHistory = key.history;
_stopTypingTimer.callOnce(kCancelTypingActionTimeout);
}
}
bool SendProgressManager::skipRequest(const Key &key) const {
const auto user = key.history->peer->asUser();
if (!user) {
return false;
} else if (user->isSelf()) {
return true;
} else if (user->isBot() && !user->isSupport()) {
return true;
}
const auto recently = base::unixtime::now() - kSendTypingsToOfflineFor;
return !Data::OnlineTextActive(user->onlineTill, recently);
}
void SendProgressManager::done(
const MTPBool &result,
mtpRequestId requestId) {

View File

@@ -55,7 +55,16 @@ public:
void update(
not_null<History*> history,
SendProgressType type,
int32 progress = 0);
int progress = 0);
void update(
not_null<History*> history,
MsgId topMsgId,
SendProgressType type,
int progress = 0);
void cancel(
not_null<History*> history,
MsgId topMsgId,
SendProgressType type);
void cancel(
not_null<History*> history,
SendProgressType type);
@@ -64,22 +73,28 @@ public:
private:
struct Key {
not_null<History*> history;
MsgId topMsgId = 0;
SendProgressType type = SendProgressType();
inline bool operator<(const Key &other) const {
return (history < other.history)
|| (history == other.history && type < other.type);
|| (history == other.history && topMsgId < other.topMsgId)
|| (history == other.history
&& topMsgId == other.topMsgId
&& type < other.type);
}
};
void send(
not_null<History*> history,
SendProgressType type,
int32 progress);
bool updated(const Key &key, bool doing);
void send(const Key &key, int progress);
void done(const MTPBool &result, mtpRequestId requestId);
[[nodiscard]] bool skipRequest(const Key &key) const;
const not_null<Main::Session*> _session;
base::flat_map<Key, mtpRequestId> _requests;
base::flat_map<Key, crl::time> _updated;
base::Timer _stopTypingTimer;
History *_stopTypingHistory = nullptr;

View File

@@ -39,10 +39,12 @@ void InnerFillMessagePostFlags(
const Api::SendOptions &options,
not_null<PeerData*> peer,
MTPDmessage::Flags &flags) {
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
if (!channelPost) {
const auto anonymousPost = peer->amAnonymous();
if (!anonymousPost) {
flags |= MTPDmessage::Flag::f_from_id;
return;
} else if (peer->asMegagroup()) {
return;
}
flags |= MTPDmessage::Flag::f_post;
// Don't display views and author of a new post when it's scheduled.
@@ -79,18 +81,18 @@ void SendExistingMedia(
auto clientFlags = NewMessageClientFlags();
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
flags |= MTPDmessage::Flag::f_reply_to;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = message.action.options.silent
|| (channelPost && session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && session->data().notifySilentPosts(peer));
InnerFillMessagePostFlags(message.action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
auto messageFromId = channelPost ? 0 : session->userId();
auto messagePostAuthor = channelPost ? session->user()->name : QString();
auto messageFromId = anonymousPost ? 0 : session->userPeerId();
auto messagePostAuthor = peer->isBroadcast() ? session->user()->name : QString();
auto caption = TextWithEntities{
message.textWithTags.text,
@@ -249,18 +251,19 @@ bool SendDice(Api::MessageToSend &message) {
auto clientFlags = NewMessageClientFlags();
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
flags |= MTPDmessage::Flag::f_reply_to;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto replyHeader = NewMessageReplyHeader(message.action);
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = message.action.options.silent
|| (channelPost && session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && session->data().notifySilentPosts(peer));
InnerFillMessagePostFlags(message.action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
auto messageFromId = channelPost ? 0 : session->userId();
auto messagePostAuthor = channelPost ? session->user()->name : QString();
auto messageFromId = anonymousPost ? 0 : session->userPeerId();
auto messagePostAuthor = peer->isBroadcast() ? session->user()->name : QString();
const auto replyTo = message.action.replyTo;
if (message.action.options.scheduled) {
@@ -272,23 +275,27 @@ bool SendDice(Api::MessageToSend &message) {
session->data().registerMessageRandomId(randomId, newId);
const auto views = 1;
const auto forwards = 0;
history->addNewMessage(
MTP_message(
MTP_flags(flags),
MTP_int(newId.msg),
MTP_int(messageFromId),
peerToMTP(messageFromId),
peerToMTP(history->peer->id),
MTPMessageFwdHeader(),
MTP_int(0),
MTP_int(replyTo),
MTPint(), // via_bot_id
replyHeader,
MTP_int(HistoryItem::NewMessageDate(
message.action.options.scheduled)),
MTP_string(),
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
MTPReplyMarkup(),
MTP_vector<MTPMessageEntity>(),
MTP_int(1),
MTPint(),
MTP_int(views),
MTP_int(forwards),
MTPMessageReplies(),
MTPint(), // edit_date
MTP_string(messagePostAuthor),
MTPlong(),
//MTPMessageReactions(),
@@ -387,9 +394,10 @@ void SendConfirmedFile(
| MTPDmessage::Flag::f_media;
auto clientFlags = NewMessageClientFlags();
if (file->to.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
flags |= MTPDmessage::Flag::f_reply_to;
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto replyHeader = NewMessageReplyHeader(action);
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = file->to.options.silent;
Api::FillMessagePostFlags(action, peer, flags);
if (silentPost) {
@@ -406,11 +414,13 @@ void SendConfirmedFile(
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
const auto messageFromId = channelPost ? 0 : session->userId();
const auto messagePostAuthor = channelPost
const auto messageFromId = anonymousPost ? 0 : session->userPeerId();
const auto messagePostAuthor = peer->isBroadcast()
? session->user()->name
: QString();
const auto views = 1;
const auto forwards = 0;
if (file->type == SendMediaType::Photo) {
const auto photoFlags = MTPDmessageMediaPhoto::Flag::f_photo | 0;
const auto photo = MTP_messageMediaPhoto(
@@ -421,18 +431,20 @@ void SendConfirmedFile(
const auto mtpMessage = MTP_message(
MTP_flags(flags),
MTP_int(newId.msg),
MTP_int(messageFromId),
peerToMTP(messageFromId),
peerToMTP(file->to.peer),
MTPMessageFwdHeader(),
MTPint(),
MTP_int(file->to.replyTo),
replyHeader,
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
MTP_string(caption.text),
photo,
MTPReplyMarkup(),
localEntities,
MTP_int(1),
MTPint(),
MTP_int(views),
MTP_int(forwards),
MTPMessageReplies(),
MTPint(), // edit_date
MTP_string(messagePostAuthor),
MTP_long(groupId),
//MTPMessageReactions(),
@@ -457,18 +469,20 @@ void SendConfirmedFile(
const auto mtpMessage = MTP_message(
MTP_flags(flags),
MTP_int(newId.msg),
MTP_int(messageFromId),
peerToMTP(messageFromId),
peerToMTP(file->to.peer),
MTPMessageFwdHeader(),
MTPint(),
MTP_int(file->to.replyTo),
replyHeader,
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
MTP_string(caption.text),
document,
MTPReplyMarkup(),
localEntities,
MTP_int(1),
MTPint(),
MTP_int(views),
MTP_int(forwards),
MTPMessageReplies(),
MTPint(), // edit_date
MTP_string(messagePostAuthor),
MTP_long(groupId),
//MTPMessageReactions(),
@@ -496,19 +510,21 @@ void SendConfirmedFile(
MTP_message(
MTP_flags(flags),
MTP_int(newId.msg),
MTP_int(messageFromId),
peerToMTP(messageFromId),
peerToMTP(file->to.peer),
MTPMessageFwdHeader(),
MTPint(),
MTP_int(file->to.replyTo),
replyHeader,
MTP_int(
HistoryItem::NewMessageDate(file->to.options.scheduled)),
MTP_string(caption.text),
document,
MTPReplyMarkup(),
localEntities,
MTP_int(1),
MTPint(),
MTP_int(views),
MTP_int(forwards),
MTPMessageReplies(),
MTPint(), // edit_date
MTP_string(messagePostAuthor),
MTP_long(groupId),
//MTPMessageReactions(),

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_updates.h"
#include "api/api_authorizations.h"
#include "api/api_text_entities.h"
#include "main/main_session.h"
#include "main/main_account.h"
@@ -62,6 +63,22 @@ enum class DataIsLoadedResult {
Ok = 3,
};
void ProcessScheduledMessageWithElapsedTime(
not_null<Main::Session*> session,
bool needToAdd,
const MTPDmessage &data) {
if (needToAdd && !data.is_from_scheduled()) {
// If we still need to add a new message,
// we should first check if this message is in
// the list of scheduled messages.
// This is necessary to correctly update the file reference.
// Note that when a message is scheduled until online
// while the recipient is already online, the server sends
// an ordinary new message with skipped "from_scheduled" flag.
session->data().scheduledMessages().checkEntitiesAndUpdate(data);
}
}
bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
return qs(data.vtype()).startsWith(qstr("AUTH_KEY_DROP_"));
}
@@ -97,20 +114,9 @@ bool ForwardedInfoDataLoaded(
not_null<Main::Session*> session,
const MTPMessageFwdHeader &header) {
return header.match([&](const MTPDmessageFwdHeader &data) {
if (const auto channelId = data.vchannel_id()) {
if (!session->data().channelLoaded(channelId->v)) {
return false;
}
if (const auto fromId = data.vfrom_id()) {
const auto from = session->data().user(fromId->v);
// Minimal loaded is fine in this case.
if (from->loadedStatus == PeerData::NotLoaded) {
return false;
}
}
} else if (const auto fromId = data.vfrom_id()) {
if (const auto fromId = data.vfrom_id()) {
// Fully loaded is required in this case.
if (!session->data().userLoaded(fromId->v)) {
if (!session->data().peerLoaded(peerFromMTP(*fromId))) {
return false;
}
}
@@ -145,7 +151,7 @@ DataIsLoadedResult AllDataLoadedForMessage(
return message.match([&](const MTPDmessage &message) {
if (const auto fromId = message.vfrom_id()) {
if (!message.is_post()
&& !session->data().userLoaded(fromId->v)) {
&& !session->data().peerLoaded(peerFromMTP(*fromId))) {
return DataIsLoadedResult::FromNotLoaded;
}
}
@@ -168,7 +174,7 @@ DataIsLoadedResult AllDataLoadedForMessage(
}, [&](const MTPDmessageService &message) {
if (const auto fromId = message.vfrom_id()) {
if (!message.is_post()
&& !session->data().userLoaded(fromId->v)) {
&& !session->data().peerLoaded(peerFromMTP(*fromId))) {
return DataIsLoadedResult::FromNotLoaded;
}
}
@@ -890,23 +896,26 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
const auto peerUserId = d.is_out()
? d.vuser_id()
: MTP_int(_session->userId());
const auto fwd = d.vfwd_from();
_session->data().addNewMessage(
MTP_message(
MTP_flags(flags),
d.vid(),
d.is_out() ? MTP_int(_session->userId()) : d.vuser_id(),
MTP_peerUser(peerUserId),
fwd ? (*fwd) : MTPMessageFwdHeader(),
(d.is_out()
? peerToMTP(_session->userPeerId())
: MTP_peerUser(d.vuser_id())),
MTP_peerUser(d.vuser_id()),
d.vfwd_from() ? *d.vfwd_from() : MTPMessageFwdHeader(),
MTP_int(d.vvia_bot_id().value_or_empty()),
MTP_int(d.vreply_to_msg_id().value_or_empty()),
d.vreply_to() ? *d.vreply_to() : MTPMessageReplyHeader(),
d.vdate(),
d.vmessage(),
MTP_messageMediaEmpty(),
MTPReplyMarkup(),
MTP_vector<MTPMessageEntity>(d.ventities().value_or_empty()),
MTPint(),
MTPint(),
MTPint(), // views
MTPint(), // forwards
MTPMessageReplies(),
MTPint(), // edit_date
MTPstring(),
MTPlong(),
//MTPMessageReactions(),
@@ -917,24 +926,26 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
case mtpc_updateShortChatMessage: {
const auto &d = updates.c_updateShortChatMessage();
const auto flags = mtpCastFlags(d.vflags().v) | MTPDmessage::Flag::f_from_id;
const auto fwd = d.vfwd_from();
const auto flags = mtpCastFlags(d.vflags().v)
| MTPDmessage::Flag::f_from_id;
_session->data().addNewMessage(
MTP_message(
MTP_flags(flags),
d.vid(),
d.vfrom_id(),
MTP_peerUser(d.vfrom_id()),
MTP_peerChat(d.vchat_id()),
fwd ? (*fwd) : MTPMessageFwdHeader(),
d.vfwd_from() ? *d.vfwd_from() : MTPMessageFwdHeader(),
MTP_int(d.vvia_bot_id().value_or_empty()),
MTP_int(d.vreply_to_msg_id().value_or_empty()),
d.vreply_to() ? *d.vreply_to() : MTPMessageReplyHeader(),
d.vdate(),
d.vmessage(),
MTP_messageMediaEmpty(),
MTPReplyMarkup(),
MTP_vector<MTPMessageEntity>(d.ventities().value_or_empty()),
MTPint(),
MTPint(),
MTPint(), // views
MTPint(), // forwards
MTPMessageReplies(),
MTPint(), // edit_date
MTPstring(),
MTPlong(),
//MTPMessageReactions(),
@@ -963,17 +974,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
LOG(("Skipping message, because it is already in blocks!"));
needToAdd = false;
}
if (needToAdd && !data.is_from_scheduled()) {
// If we still need to add a new message,
// we should first check if this message is in
// the list of scheduled messages.
// This is necessary to correctly update the file reference.
// Note that when a message is scheduled until online
// while the recipient is already online, the server sends
// an ordinary new message with skipped "from_scheduled" flag.
_session->data().scheduledMessages().checkEntitiesAndUpdate(
data);
}
ProcessScheduledMessageWithElapsedTime(_session, needToAdd, data);
}
if (needToAdd) {
_session->data().addNewMessage(
@@ -1062,10 +1063,12 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
auto &d = update.c_updateNewChannelMessage();
auto needToAdd = true;
if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview
if (_session->data().checkEntitiesAndViewsUpdate(d.vmessage().c_message())) { // already in blocks
const auto &data = d.vmessage().c_message();
if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks
LOG(("Skipping message, because it is already in blocks!"));
needToAdd = false;
}
ProcessScheduledMessageWithElapsedTime(_session, needToAdd, data);
}
if (needToAdd) {
_session->data().addNewMessage(
@@ -1541,26 +1544,51 @@ void Updates::feedUpdate(const MTPUpdate &update) {
const auto user = session().data().userLoaded(d.vuser_id().v);
if (history && user) {
const auto when = requestingDifference() ? 0 : base::unixtime::now();
session().data().registerSendAction(history, user, d.vaction(), when);
session().data().registerSendAction(
history,
MsgId(),
user,
d.vaction(),
when);
}
} break;
case mtpc_updateChatUserTyping: {
auto &d = update.c_updateChatUserTyping();
const auto history = [&]() -> History* {
if (const auto chat = session().data().chatLoaded(d.vchat_id().v)) {
return session().data().historyLoaded(chat->id);
} else if (const auto channel = session().data().channelLoaded(d.vchat_id().v)) {
return session().data().historyLoaded(channel->id);
}
return nullptr;
}();
const auto history = session().data().historyLoaded(
peerFromChat(d.vchat_id()));
const auto user = (d.vuser_id().v == session().userId())
? nullptr
: session().data().userLoaded(d.vuser_id().v);
if (history && user) {
const auto when = requestingDifference() ? 0 : base::unixtime::now();
session().data().registerSendAction(history, user, d.vaction(), when);
session().data().registerSendAction(
history,
MsgId(),
user,
d.vaction(),
when);
}
} break;
case mtpc_updateChannelUserTyping: {
const auto &d = update.c_updateChannelUserTyping();
const auto history = session().data().historyLoaded(
peerFromChannel(d.vchannel_id()));
const auto user = (d.vuser_id().v == session().userId())
? nullptr
: session().data().userLoaded(d.vuser_id().v);
if (history && user) {
const auto when = requestingDifference()
? 0
: base::unixtime::now();
const auto rootId = d.vtop_msg_id().value_or_empty();
session().data().registerSendAction(
history,
rootId,
user,
d.vaction(),
when);
}
} break;
@@ -1731,10 +1759,10 @@ void Updates::feedUpdate(const MTPUpdate &update) {
Core::App().calls().handleUpdate(&session(), update);
} break;
case mtpc_updateUserBlocked: {
const auto &d = update.c_updateUserBlocked();
if (const auto user = session().data().userLoaded(d.vuser_id().v)) {
user->setIsBlocked(mtpIsTrue(d.vblocked()));
case mtpc_updatePeerBlocked: {
const auto &d = update.c_updatePeerBlocked();
if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer_id()))) {
peer->setIsBlocked(mtpIsTrue(d.vblocked()));
}
} break;
@@ -1753,7 +1781,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
}
} else {
session().data().serviceNotification(text, d.vmedia());
session().data().checkNewAuthorization();
session().api().authorizations().reload();
}
} break;
@@ -1912,12 +1940,54 @@ void Updates::feedUpdate(const MTPUpdate &update) {
} break;
case mtpc_updateChannelMessageViews: {
auto &d = update.c_updateChannelMessageViews();
if (auto item = session().data().message(d.vchannel_id().v, d.vid().v)) {
const auto &d = update.c_updateChannelMessageViews();
if (const auto item = session().data().message(d.vchannel_id().v, d.vid().v)) {
item->setViewsCount(d.vviews().v);
}
} break;
case mtpc_updateChannelMessageForwards: {
const auto &d = update.c_updateChannelMessageForwards();
if (const auto item = session().data().message(d.vchannel_id().v, d.vid().v)) {
item->setForwardsCount(d.vforwards().v);
}
} break;
case mtpc_updateReadChannelDiscussionInbox: {
const auto &d = update.c_updateReadChannelDiscussionInbox();
const auto channelId = d.vchannel_id().v;
const auto msgId = d.vtop_msg_id().v;
const auto readTillId = d.vread_max_id().v;
const auto item = session().data().message(channelId, msgId);
if (item) {
item->setRepliesInboxReadTill(readTillId);
if (const auto post = item->lookupDiscussionPostOriginal()) {
post->setRepliesInboxReadTill(readTillId);
}
}
if (const auto broadcastId = d.vbroadcast_id()) {
if (const auto post = session().data().message(
broadcastId->v,
d.vbroadcast_post()->v)) {
post->setRepliesInboxReadTill(readTillId);
}
}
} break;
case mtpc_updateReadChannelDiscussionOutbox: {
const auto &d = update.c_updateReadChannelDiscussionOutbox();
const auto channelId = d.vchannel_id().v;
const auto msgId = d.vtop_msg_id().v;
const auto readTillId = d.vread_max_id().v;
const auto item = session().data().message(channelId, msgId);
if (item) {
item->setRepliesOutboxReadTill(readTillId);
if (const auto post = item->lookupDiscussionPostOriginal()) {
post->setRepliesOutboxReadTill(readTillId);
}
}
} break;
case mtpc_updateChannelAvailableMessages: {
auto &d = update.c_updateChannelAvailableMessages();
if (const auto channel = session().data().channelLoaded(d.vchannel_id().v)) {

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "apiwrap.h"
#include "api/api_authorizations.h"
#include "api/api_hash.h"
#include "api/api_media.h"
#include "api/api_sending.h"
@@ -158,19 +159,19 @@ std::optional<ApiWrap::Privacy::Key> ApiWrap::Privacy::KeyFromMTP(
return std::nullopt;
}
bool ApiWrap::BlockedUsersSlice::Item::operator==(const Item &other) const {
return (user == other.user) && (date == other.date);
bool ApiWrap::BlockedPeersSlice::Item::operator==(const Item &other) const {
return (peer == other.peer) && (date == other.date);
}
bool ApiWrap::BlockedUsersSlice::Item::operator!=(const Item &other) const {
bool ApiWrap::BlockedPeersSlice::Item::operator!=(const Item &other) const {
return !(*this == other);
}
bool ApiWrap::BlockedUsersSlice::operator==(const BlockedUsersSlice &other) const {
bool ApiWrap::BlockedPeersSlice::operator==(const BlockedPeersSlice &other) const {
return (total == other.total) && (list == other.list);
}
bool ApiWrap::BlockedUsersSlice::operator!=(const BlockedUsersSlice &other) const {
bool ApiWrap::BlockedPeersSlice::operator!=(const BlockedPeersSlice &other) const {
return !(*this == other);
}
@@ -186,6 +187,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
//, _feedReadTimer([=] { readFeeds(); }) // #feed
, _topPromotionTimer([=] { refreshTopPromotion(); })
, _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); })
, _authorizations(std::make_unique<Api::Authorizations>(this))
, _selfDestruct(std::make_unique<Api::SelfDestruct>(this))
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this))
, _globalPrivacy(std::make_unique<Api::GlobalPrivacy>(this)) {
@@ -683,17 +685,57 @@ void ApiWrap::finalizeMessageDataRequest(
}
}
QString ApiWrap::exportDirectMessageLink(not_null<HistoryItem*> item) {
QString ApiWrap::exportDirectMessageLink(
not_null<HistoryItem*> item,
bool inRepliesContext) {
Expects(item->history()->peer->isChannel());
const auto itemId = item->fullId();
const auto channel = item->history()->peer->asChannel();
const auto fallback = [&] {
const auto base = channel->hasUsername()
? channel->username
: "c/" + QString::number(channel->bareId());
const auto query = base + '/' + QString::number(item->id);
if (channel->hasUsername() && !channel->isMegagroup()) {
auto linkChannel = channel;
auto linkItemId = item->id;
auto linkCommentId = 0;
auto linkThreadId = 0;
if (inRepliesContext) {
if (const auto rootId = item->replyToTop()) {
const auto root = item->history()->owner().message(
channel->bareId(),
rootId);
const auto sender = root
? root->discussionPostOriginalSender()
: nullptr;
if (sender && sender->hasUsername()) {
// Comment to a public channel.
const auto forwarded = root->Get<HistoryMessageForwarded>();
linkItemId = forwarded->savedFromMsgId;
if (linkItemId) {
linkChannel = sender;
linkCommentId = item->id;
} else {
linkItemId = item->id;
}
} else {
// Reply in a thread, maybe comment in a private channel.
linkThreadId = rootId;
}
}
}
const auto base = linkChannel->hasUsername()
? linkChannel->username
: "c/" + QString::number(linkChannel->bareId());
const auto query = base
+ '/'
+ QString::number(linkItemId)
+ (linkCommentId
? "?comment=" + QString::number(linkCommentId)
: linkThreadId
? "?thread=" + QString::number(linkThreadId)
: "");
if (linkChannel->hasUsername()
&& !linkChannel->isMegagroup()
&& !linkCommentId
&& !linkThreadId) {
if (const auto media = item->media()) {
if (const auto document = media->document()) {
if (document->isVideoMessage()) {
@@ -709,9 +751,11 @@ QString ApiWrap::exportDirectMessageLink(not_null<HistoryItem*> item) {
? i->second
: fallback();
request(MTPchannels_ExportMessageLink(
MTP_flags(inRepliesContext
? MTPchannels_ExportMessageLink::Flag::f_thread
: MTPchannels_ExportMessageLink::Flag(0)),
channel->inputChannel,
MTP_int(item->id),
MTP_bool(false)
MTP_int(item->id)
)).done([=](const MTPExportedMessageLink &result) {
const auto link = result.match([&](const auto &data) {
return qs(data.vlink());
@@ -1495,9 +1539,13 @@ void ApiWrap::applyLastParticipantsList(
});
const auto adminCanEdit = (p.type() == mtpc_channelParticipantAdmin)
? p.c_channelParticipantAdmin().is_can_edit()
: (p.type() == mtpc_channelParticipantCreator)
? channel->amCreator()
: false;
const auto adminRights = (p.type() == mtpc_channelParticipantAdmin)
? p.c_channelParticipantAdmin().vadmin_rights()
: (p.type() == mtpc_channelParticipantCreator)
? p.c_channelParticipantCreator().vadmin_rights()
: emptyAdminRights;
const auto restrictedRights = (p.type() == mtpc_channelParticipantBanned)
? p.c_channelParticipantBanned().vbanned_rights()
@@ -2003,64 +2051,66 @@ void ApiWrap::leaveChannel(not_null<ChannelData*> channel) {
}
}
void ApiWrap::blockUser(not_null<UserData*> user) {
if (user->isBlocked()) {
void ApiWrap::blockPeer(not_null<PeerData*> peer) {
if (peer->isBlocked()) {
session().changes().peerUpdated(
user,
peer,
Data::PeerUpdate::Flag::IsBlocked);
} else if (_blockRequests.find(user) == end(_blockRequests)) {
const auto requestId = request(MTPcontacts_Block(user->inputUser)).done([this, user](const MTPBool &result) {
_blockRequests.erase(user);
user->setIsBlocked(true);
if (_blockedUsersSlice) {
_blockedUsersSlice->list.insert(
_blockedUsersSlice->list.begin(),
{ user, base::unixtime::now() });
++_blockedUsersSlice->total;
_blockedUsersChanges.fire_copy(*_blockedUsersSlice);
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
const auto requestId = request(MTPcontacts_Block(
peer->input
)).done([=](const MTPBool &result) {
_blockRequests.erase(peer);
peer->setIsBlocked(true);
if (_blockedPeersSlice) {
_blockedPeersSlice->list.insert(
_blockedPeersSlice->list.begin(),
{ peer, base::unixtime::now() });
++_blockedPeersSlice->total;
_blockedPeersChanges.fire_copy(*_blockedPeersSlice);
}
}).fail([this, user](const RPCError &error) {
_blockRequests.erase(user);
}).fail([=](const RPCError &error) {
_blockRequests.erase(peer);
}).send();
_blockRequests.emplace(user, requestId);
_blockRequests.emplace(peer, requestId);
}
}
void ApiWrap::unblockUser(not_null<UserData*> user, Fn<void()> onDone) {
if (!user->isBlocked()) {
void ApiWrap::unblockPeer(not_null<PeerData*> peer, Fn<void()> onDone) {
if (!peer->isBlocked()) {
session().changes().peerUpdated(
user,
peer,
Data::PeerUpdate::Flag::IsBlocked);
return;
} else if (_blockRequests.find(user) != end(_blockRequests)) {
} else if (_blockRequests.find(peer) != end(_blockRequests)) {
return;
}
const auto requestId = request(MTPcontacts_Unblock(
user->inputUser
peer->input
)).done([=](const MTPBool &result) {
_blockRequests.erase(user);
user->setIsBlocked(false);
if (_blockedUsersSlice) {
auto &list = _blockedUsersSlice->list;
_blockRequests.erase(peer);
peer->setIsBlocked(false);
if (_blockedPeersSlice) {
auto &list = _blockedPeersSlice->list;
for (auto i = list.begin(); i != list.end(); ++i) {
if (i->user == user) {
if (i->peer == peer) {
list.erase(i);
break;
}
}
if (_blockedUsersSlice->total > list.size()) {
--_blockedUsersSlice->total;
if (_blockedPeersSlice->total > list.size()) {
--_blockedPeersSlice->total;
}
_blockedUsersChanges.fire_copy(*_blockedUsersSlice);
_blockedPeersChanges.fire_copy(*_blockedPeersSlice);
}
if (onDone) {
onDone();
}
}).fail([=](const RPCError &error) {
_blockRequests.erase(user);
_blockRequests.erase(peer);
}).send();
_blockRequests.emplace(user, requestId);
_blockRequests.emplace(peer, requestId);
}
void ApiWrap::exportInviteLink(not_null<PeerData*> peer) {
@@ -2203,7 +2253,7 @@ void ApiWrap::handlePrivacyChange(
void ApiWrap::updatePrivacyLastSeens(const QVector<MTPPrivacyRule> &rules) {
const auto now = base::unixtime::now();
_session->data().enumerateUsers([&](UserData *user) {
if (user->isSelf() || user->loadedStatus != PeerData::FullLoaded) {
if (user->isSelf() || !user->isFullLoaded()) {
return;
}
if (user->onlineTill <= 0) {
@@ -2682,14 +2732,14 @@ void ApiWrap::requestFileReference(
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87122
const auto &origin = p.first;
const auto &reference = p.second;
const auto documentId = base::get_if<DocumentFileLocationId>(
const auto documentId = std::get_if<DocumentFileLocationId>(
&origin);
if (documentId) {
_session->data().document(
documentId->id
)->refreshFileReference(reference);
}
const auto photoId = base::get_if<PhotoFileLocationId>(&origin);
const auto photoId = std::get_if<PhotoFileLocationId>(&origin);
if (photoId) {
_session->data().photo(
photoId->id
@@ -2748,7 +2798,7 @@ void ApiWrap::refreshFileReference(
const auto fail = [&] {
handler(UpdatedFileReferences());
};
origin.data.match([&](Data::FileOriginMessage data) {
v::match(origin.data, [&](Data::FileOriginMessage data) {
if (const auto item = _session->data().message(data)) {
if (item->isScheduled()) {
const auto &scheduled = _session->data().scheduledMessages();
@@ -2824,7 +2874,7 @@ void ApiWrap::refreshFileReference(
MTP_long(data.themeId),
MTP_long(data.accessHash)),
MTP_long(0)));
}, [&](std::nullopt_t) {
}, [&](v::null_t) {
fail();
});
}
@@ -3896,9 +3946,9 @@ void ApiWrap::forwardMessages(
histories.readInbox(history);
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
auto flags = MTPDmessage::Flags(0);
auto clientFlags = MTPDmessage_ClientFlags();
@@ -3915,7 +3965,6 @@ void ApiWrap::forwardMessages(
}
auto forwardFrom = items.front()->history()->peer;
auto currentGroupId = items.front()->groupId();
auto ids = QVector<MTPint>();
auto randomIds = QVector<MTPlong>();
auto localIds = std::shared_ptr<base::flat_map<uint64, FullMsgId>>();
@@ -3924,14 +3973,10 @@ void ApiWrap::forwardMessages(
if (shared) {
++shared->requestsLeft;
}
const auto finalFlags = sendFlags
| (currentGroupId == MessageGroupId()
? MTPmessages_ForwardMessages::Flag(0)
: MTPmessages_ForwardMessages::Flag::f_grouped);
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
history->sendRequestId = request(MTPmessages_ForwardMessages(
MTP_flags(finalFlags),
MTP_flags(sendFlags),
forwardFrom->input,
MTP_vector<MTPint>(ids),
MTP_vector<MTPlong>(randomIds),
@@ -3973,10 +4018,10 @@ void ApiWrap::forwardMessages(
peerToChannel(peer->id),
_session->data().nextLocalMessageId());
const auto self = _session->user();
const auto messageFromId = channelPost
? UserId(0)
: peerToUser(self->id);
const auto messagePostAuthor = channelPost
const auto messageFromId = anonymousPost
? PeerId(0)
: self->id;
const auto messagePostAuthor = peer->isBroadcast()
? self->name
: QString();
history->addNewLocalMessage(
@@ -3996,11 +4041,9 @@ void ApiWrap::forwardMessages(
}
const auto newFrom = item->history()->peer;
const auto newGroupId = item->groupId();
if (forwardFrom != newFrom
|| currentGroupId != newGroupId) {
if (forwardFrom != newFrom) {
sendAccumulated();
forwardFrom = newFrom;
currentGroupId = newGroupId;
}
ids.push_back(MTP_int(item->id));
randomIds.push_back(MTP_long(randomId));
@@ -4048,34 +4091,36 @@ void ApiWrap::sendSharedContact(
const auto newId = FullMsgId(
history->channelId(),
_session->data().nextLocalMessageId());
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto clientFlags = NewMessageClientFlags();
if (action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
flags |= MTPDmessage::Flag::f_reply_to;
}
const auto replyHeader = NewMessageReplyHeader(action);
FillMessagePostFlags(action, peer, flags);
if (action.options.scheduled) {
flags |= MTPDmessage::Flag::f_from_scheduled;
} else {
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
const auto messageFromId = channelPost ? 0 : _session->userId();
const auto messagePostAuthor = channelPost
const auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
const auto messagePostAuthor = peer->isBroadcast()
? _session->user()->name
: QString();
const auto vcard = QString();
const auto views = 1;
const auto forwards = 0;
const auto item = history->addNewMessage(
MTP_message(
MTP_flags(flags),
MTP_int(newId.msg),
MTP_int(messageFromId),
peerToMTP(messageFromId),
peerToMTP(peer->id),
MTPMessageFwdHeader(),
MTPint(),
MTP_int(action.replyTo),
MTPint(), // via_bot_id
replyHeader,
MTP_int(HistoryItem::NewMessageDate(action.options.scheduled)),
MTP_string(),
MTP_messageMediaContact(
@@ -4087,7 +4132,9 @@ void ApiWrap::sendSharedContact(
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(views),
MTPint(),
MTP_int(forwards),
MTPMessageReplies(),
MTPint(), // edit_date
MTP_string(messagePostAuthor),
MTPlong(),
//MTPMessageReactions(),
@@ -4101,7 +4148,9 @@ void ApiWrap::sendSharedContact(
MTP_string(lastName),
MTP_string(vcard));
auto options = action.options;
options.silent = _session->data().notifySilentPosts(peer);
if (_session->data().notifySilentPosts(peer)) {
options.silent = true;
}
sendMedia(item, media, options);
_session->data().sendHistoryChangeNotifications();
@@ -4309,9 +4358,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
auto clientFlags = NewMessageClientFlags();
auto sendFlags = MTPmessages_SendMessage::Flags(0);
if (action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
flags |= MTPDmessage::Flag::f_reply_to;
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
}
const auto replyHeader = NewMessageReplyHeader(action);
MTPMessageMedia media = MTP_messageMediaEmpty();
if (message.webPageId == CancelledWebPageId) {
sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage;
@@ -4323,9 +4373,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
MTP_int(page->pendingTill)));
flags |= MTPDmessage::Flag::f_media;
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
@@ -4345,8 +4395,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
history->clearCloudDraft();
history->setSentDraftText(QString());
}
auto messageFromId = channelPost ? 0 : _session->userId();
auto messagePostAuthor = channelPost
auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
auto messagePostAuthor = peer->isBroadcast()
? _session->user()->name
: QString();
if (action.options.scheduled) {
@@ -4355,23 +4405,27 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
} else {
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
const auto views = 1;
const auto forwards = 0;
lastMessage = history->addNewMessage(
MTP_message(
MTP_flags(flags),
MTP_int(newId.msg),
MTP_int(messageFromId),
peerToMTP(messageFromId),
peerToMTP(peer->id),
MTPMessageFwdHeader(),
MTPint(),
MTP_int(action.replyTo),
MTPint(), // via_bot_id
replyHeader,
MTP_int(
HistoryItem::NewMessageDate(action.options.scheduled)),
msgText,
media,
MTPReplyMarkup(),
localEntities,
MTP_int(1),
MTPint(),
MTP_int(views),
MTP_int(forwards),
MTPMessageReplies(),
MTPint(), // edit_date
MTP_string(messagePostAuthor),
MTPlong(),
//MTPMessageReactions(),
@@ -4458,12 +4512,12 @@ void ApiWrap::sendInlineResult(
auto clientFlags = NewMessageClientFlags();
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
if (action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
flags |= MTPDmessage::Flag::f_reply_to;
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
}
bool channelPost = peer->isChannel() && !peer->isMegagroup();
bool silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = action.options.silent
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
@@ -4478,8 +4532,8 @@ void ApiWrap::sendInlineResult(
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
const auto messageFromId = channelPost ? 0 : _session->userId();
const auto messagePostAuthor = channelPost
const auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
const auto messagePostAuthor = peer->isBroadcast()
? _session->user()->name
: QString();
@@ -5118,34 +5172,34 @@ auto ApiWrap::privacyValue(Privacy::Key key) -> rpl::producer<Privacy> {
}
}
void ApiWrap::reloadBlockedUsers() {
if (_blockedUsersRequestId) {
void ApiWrap::reloadBlockedPeers() {
if (_blockedPeersRequestId) {
return;
}
_blockedUsersRequestId = request(MTPcontacts_GetBlocked(
_blockedPeersRequestId = request(MTPcontacts_GetBlocked(
MTP_int(0),
MTP_int(kBlockedFirstSlice)
)).done([=](const MTPcontacts_Blocked &result) {
_blockedUsersRequestId = 0;
_blockedPeersRequestId = 0;
const auto push = [&](
int count,
const QVector<MTPContactBlocked> &list) {
auto slice = BlockedUsersSlice();
const QVector<MTPPeerBlocked> &list) {
auto slice = BlockedPeersSlice();
slice.total = std::max(count, list.size());
slice.list.reserve(list.size());
for (const auto &contact : list) {
contact.match([&](const MTPDcontactBlocked &data) {
const auto user = _session->data().userLoaded(
data.vuser_id().v);
if (user) {
user->setIsBlocked(true);
slice.list.push_back({ user, data.vdate().v });
contact.match([&](const MTPDpeerBlocked &data) {
const auto peer = _session->data().peerLoaded(
peerFromMTP(data.vpeer_id()));
if (peer) {
peer->setIsBlocked(true);
slice.list.push_back({ peer, data.vdate().v });
}
});
}
if (!_blockedUsersSlice || *_blockedUsersSlice != slice) {
_blockedUsersSlice = slice;
_blockedUsersChanges.fire(std::move(slice));
if (!_blockedPeersSlice || *_blockedPeersSlice != slice) {
_blockedPeersSlice = slice;
_blockedPeersChanges.fire(std::move(slice));
}
};
result.match([&](const MTPDcontacts_blockedSlice &data) {
@@ -5156,17 +5210,21 @@ void ApiWrap::reloadBlockedUsers() {
push(0, data.vblocked().v);
});
}).fail([=](const RPCError &error) {
_blockedUsersRequestId = 0;
_blockedPeersRequestId = 0;
}).send();
}
auto ApiWrap::blockedUsersSlice() -> rpl::producer<BlockedUsersSlice> {
if (!_blockedUsersSlice) {
reloadBlockedUsers();
auto ApiWrap::blockedPeersSlice() -> rpl::producer<BlockedPeersSlice> {
if (!_blockedPeersSlice) {
reloadBlockedPeers();
}
return _blockedUsersSlice
? _blockedUsersChanges.events_starting_with_copy(*_blockedUsersSlice)
: (_blockedUsersChanges.events() | rpl::type_erased());
return _blockedPeersSlice
? _blockedPeersChanges.events_starting_with_copy(*_blockedPeersSlice)
: (_blockedPeersChanges.events() | rpl::type_erased());
}
Api::Authorizations &ApiWrap::authorizations() {
return *_authorizations;
}
Api::SelfDestruct &ApiWrap::selfDestruct() {
@@ -5199,9 +5257,8 @@ void ApiWrap::createPoll(
history->clearLocalDraft();
history->clearCloudDraft();
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}

View File

@@ -52,6 +52,7 @@ struct CloudPasswordState;
namespace Api {
class Updates;
class Authorizations;
class SelfDestruct;
class SensitiveContent;
class GlobalPrivacy;
@@ -121,9 +122,9 @@ public:
static std::optional<Key> KeyFromMTP(mtpTypeId type);
};
struct BlockedUsersSlice {
struct BlockedPeersSlice {
struct Item {
UserData *user = nullptr;
PeerData *peer = nullptr;
TimeId date = 0;
bool operator==(const Item &other) const;
@@ -133,8 +134,8 @@ public:
QVector<Item> list;
int total = 0;
bool operator==(const BlockedUsersSlice &other) const;
bool operator!=(const BlockedUsersSlice &other) const;
bool operator==(const BlockedPeersSlice &other) const;
bool operator!=(const BlockedPeersSlice &other) const;
};
explicit ApiWrap(not_null<Main::Session*> session);
@@ -172,7 +173,9 @@ public:
ChannelData *channel,
MsgId msgId,
RequestMessageDataCallback callback);
QString exportDirectMessageLink(not_null<HistoryItem*> item);
QString exportDirectMessageLink(
not_null<HistoryItem*> item,
bool inRepliesContext);
void requestContacts();
void requestDialogs(Data::Folder *folder = nullptr);
@@ -279,8 +282,8 @@ public:
void joinChannel(not_null<ChannelData*> channel);
void leaveChannel(not_null<ChannelData*> channel);
void blockUser(not_null<UserData*> user);
void unblockUser(not_null<UserData*> user, Fn<void()> onDone = nullptr);
void blockPeer(not_null<PeerData*> peer);
void unblockPeer(not_null<PeerData*> peer, Fn<void()> onDone = nullptr);
void exportInviteLink(not_null<PeerData*> peer);
void requestNotifySettings(const MTPInputNotifyPeer &peer);
@@ -448,9 +451,10 @@ public:
void reloadPrivacy(Privacy::Key key);
rpl::producer<Privacy> privacyValue(Privacy::Key key);
void reloadBlockedUsers();
rpl::producer<BlockedUsersSlice> blockedUsersSlice();
void reloadBlockedPeers();
rpl::producer<BlockedPeersSlice> blockedPeersSlice();
[[nodiscard]] Api::Authorizations &authorizations();
[[nodiscard]] Api::SelfDestruct &selfDestruct();
[[nodiscard]] Api::SensitiveContent &sensitiveContent();
[[nodiscard]] Api::GlobalPrivacy &globalPrivacy();
@@ -690,7 +694,7 @@ private:
QMap<uint64, QPair<uint64, mtpRequestId> > _stickerSetRequests;
QMap<ChannelData*, mtpRequestId> _channelAmInRequests;
base::flat_map<not_null<UserData*>, mtpRequestId> _blockRequests;
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests;
base::flat_map<not_null<PeerData*>, mtpRequestId> _exportInviteRequests;
base::flat_map<PeerId, mtpRequestId> _notifySettingRequests;
base::flat_map<not_null<History*>, mtpRequestId> _draftsSaveRequestIds;
@@ -809,10 +813,11 @@ private:
base::flat_map<Privacy::Key, Privacy> _privacyValues;
std::map<Privacy::Key, rpl::event_stream<Privacy>> _privacyChanges;
mtpRequestId _blockedUsersRequestId = 0;
std::optional<BlockedUsersSlice> _blockedUsersSlice;
rpl::event_stream<BlockedUsersSlice> _blockedUsersChanges;
mtpRequestId _blockedPeersRequestId = 0;
std::optional<BlockedPeersSlice> _blockedPeersSlice;
rpl::event_stream<BlockedPeersSlice> _blockedPeersChanges;
const std::unique_ptr<Api::Authorizations> _authorizations;
const std::unique_ptr<Api::SelfDestruct> _selfDestruct;
const std::unique_ptr<Api::SensitiveContent> _sensitiveContent;
const std::unique_ptr<Api::GlobalPrivacy> _globalPrivacy;

View File

@@ -125,7 +125,7 @@ QString telegramFaqLink() {
const auto langpacked = [&](const char *language) {
return result + '/' + language;
};
const auto current = Lang::Current().id();
const auto current = Lang::Id();
for (const auto language : { "de", "es", "it", "ko" }) {
if (current.startsWith(QLatin1String(language))) {
return langpacked(language);

View File

@@ -244,7 +244,6 @@ private:
Fn<void()> _revokeCallback;
mtpRequestId _revokeRequestId = 0;
QPointer<ConfirmBox> _weakRevokeConfirmBox;
};
@@ -1417,21 +1416,21 @@ void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
lt_group,
pressed->name);
auto confirmText = tr::lng_channels_too_much_public_revoke(tr::now);
_weakRevokeConfirmBox = Ui::show(Box<ConfirmBox>(text, confirmText, crl::guard(this, [this, pressed]() {
auto callback = crl::guard(this, [=](Fn<void()> &&close) {
if (_revokeRequestId) return;
_revokeRequestId = _api.request(MTPchannels_UpdateUsername(
pressed->asChannel()->inputChannel,
MTP_string()
)).done([=](const MTPBool &result) {
const auto callback = _revokeCallback;
if (_weakRevokeConfirmBox) {
_weakRevokeConfirmBox->closeBox();
}
if (callback) {
)).done([=, close = std::move(close)](const MTPBool &result) {
close();
if (const auto callback = _revokeCallback) {
callback();
}
}).send();
})), Ui::LayerOption::KeepOther);
});
Ui::show(
Box<ConfirmBox>(text, confirmText, std::move(callback)),
Ui::LayerOption::KeepOther);
}
}

View File

@@ -103,7 +103,7 @@ private:
return !(*this == other);
}
};
using Selection = base::optional_variant<Selected, DeleteSelected>;
using Selection = std::variant<v::null_t, Selected, DeleteSelected>;
int getSelectionIndex(const Selection &selection) const;
void repaintPaper(int index);
@@ -163,12 +163,9 @@ void BackgroundBox::prepare() {
}
void BackgroundBox::removePaper(const Data::WallPaper &paper) {
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto session = &_controller->session();
const auto remove = [=, weak = Ui::MakeWeak(this)]{
if (*box) {
(*box)->closeBox();
}
const auto remove = [=, weak = Ui::MakeWeak(this)](Fn<void()> &&close) {
close();
if (weak) {
weak->_inner->removePaper(paper);
}
@@ -179,7 +176,7 @@ void BackgroundBox::removePaper(const Data::WallPaper &paper) {
paper.mtpSettings()
)).send();
};
*box = Ui::show(
Ui::show(
Box<ConfirmBox>(
tr::lng_background_sure_delete(tr::now),
tr::lng_selected_delete(tr::now),
@@ -358,16 +355,16 @@ void BackgroundBox::Inner::paintPaper(
p.drawPixmap(x, y, paper.thumbnail);
}
const auto over = _overDown ? _overDown : _over;
const auto over = !v::is_null(_overDown) ? _overDown : _over;
if (paper.data.id() == Window::Theme::Background()->id()) {
const auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
const auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
_check->paint(p, checkLeft, checkTop, width());
} else if (Data::IsCloudWallPaper(paper.data)
&& !Data::IsDefaultWallPaper(paper.data)
&& over.has_value()
&& !v::is_null(over)
&& (&paper == &_papers[getSelectionIndex(over)])) {
const auto deleteSelected = over.is<DeleteSelected>();
const auto deleteSelected = v::is<DeleteSelected>(over);
const auto deletePos = QPoint(x + st::backgroundSize.width() - st::stickerPanDeleteIconBg.width(), y);
p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityBgOver : st::stickerPanDeleteOpacityBg);
st::stickerPanDeleteIconBg.paint(p, deletePos, width());
@@ -414,7 +411,7 @@ void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
repaintPaper(getSelectionIndex(_over));
_over = newOver;
repaintPaper(getSelectionIndex(_over));
setCursor((_over.has_value() || _overDown.has_value())
setCursor((!v::is_null(_over) || !v::is_null(_overDown))
? style::cur_pointer
: style::cur_default);
}
@@ -442,22 +439,22 @@ void BackgroundBox::Inner::mousePressEvent(QMouseEvent *e) {
int BackgroundBox::Inner::getSelectionIndex(
const Selection &selection) const {
return selection.match([](const Selected &data) {
return v::match(selection, [](const Selected &data) {
return data.index;
}, [](const DeleteSelected &data) {
return data.index;
}, [](std::nullopt_t) {
}, [](v::null_t) {
return -1;
});
}
void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
if (base::take(_overDown) == _over && _over.has_value()) {
if (base::take(_overDown) == _over && !v::is_null(_over)) {
const auto index = getSelectionIndex(_over);
if (index >= 0 && index < _papers.size()) {
if (base::get_if<DeleteSelected>(&_over)) {
if (std::get_if<DeleteSelected>(&_over)) {
_backgroundRemove.fire_copy(_papers[index].data);
} else if (base::get_if<Selected>(&_over)) {
} else if (std::get_if<Selected>(&_over)) {
auto &paper = _papers[index];
if (!paper.dataMedia) {
if (const auto document = paper.data.document()) {
@@ -468,7 +465,7 @@ void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
_backgroundChosen.fire_copy(paper.data);
}
}
} else if (!_over.has_value()) {
} else if (v::is_null(_over)) {
setCursor(style::cur_default);
}
}

View File

@@ -348,6 +348,7 @@ sessionInfoFont: msgFont;
sessionInfoFg: windowSubTextFg;
sessionTerminateTop: 28px;
sessionTerminateSkip: 22px;
sessionNamePadding: margins(0px, 0px, 5px, 0px);
sessionTerminate: IconButton {
width: 20px;
height: 20px;
@@ -366,6 +367,15 @@ sessionTerminateAllButton: LinkButton(boxLinkButton) {
color: attentionButtonFg;
overColor: attentionButtonFg;
}
sessionNameStyle: TextStyle(defaultTextStyle) {
font: sessionNameFont;
}
sessionWhenStyle: TextStyle(defaultTextStyle) {
font: sessionWhenFont;
}
sessionInfoStyle: TextStyle(defaultTextStyle) {
font: sessionInfoFont;
}
passcodeHeaderFont: font(19px);
passcodeHeaderHeight: 80px;

View File

@@ -74,7 +74,7 @@ TextParseOptions kMarkedTextBoxOptions = {
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
FnMut<void()> confirmedCallback,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(tr::lng_box_ok(tr::now))
, _cancelText(tr::lng_cancel(tr::now))
@@ -89,7 +89,7 @@ ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
FnMut<void()> confirmedCallback,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(tr::lng_cancel(tr::now))
@@ -104,7 +104,7 @@ ConfirmBox::ConfirmBox(
QWidget*,
const TextWithEntities &text,
const QString &confirmText,
FnMut<void()> confirmedCallback,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(tr::lng_cancel(tr::now))
@@ -120,7 +120,7 @@ ConfirmBox::ConfirmBox(
const QString &text,
const QString &confirmText,
const style::RoundButton &confirmStyle,
FnMut<void()> confirmedCallback,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(tr::lng_cancel(tr::now))
@@ -136,7 +136,7 @@ ConfirmBox::ConfirmBox(
const QString &text,
const QString &confirmText,
const QString &cancelText,
FnMut<void()> confirmedCallback,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(cancelText)
@@ -153,7 +153,7 @@ ConfirmBox::ConfirmBox(
const QString &confirmText,
const style::RoundButton &confirmStyle,
const QString &cancelText,
FnMut<void()> confirmedCallback,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(cancelText)
@@ -256,8 +256,16 @@ void ConfirmBox::textUpdated() {
void ConfirmBox::confirmed() {
if (!_confirmed) {
_confirmed = true;
if (auto callback = std::move(_confirmedCallback)) {
callback();
const auto confirmed = &_confirmedCallback;
if (const auto callbackPtr = std::get_if<1>(confirmed)) {
if (auto callback = base::take(*callbackPtr)) {
callback();
}
} else if (const auto callbackPtr = std::get_if<2>(confirmed)) {
if (auto callback = base::take(*callbackPtr)) {
callback([=] { closeBox(); });
}
}
}
}
@@ -808,53 +816,7 @@ void DeleteMessagesBox::deleteAndClear() {
_deleteConfirmedCallback();
}
auto remove = std::vector<not_null<HistoryItem*>>();
remove.reserve(_ids.size());
base::flat_map<not_null<History*>, QVector<MTPint>> idsByPeer;
base::flat_map<not_null<PeerData*>, QVector<MTPint>> scheduledIdsByPeer;
for (const auto itemId : _ids) {
if (const auto item = _session->data().message(itemId)) {
const auto history = item->history();
if (item->isScheduled()) {
const auto wasOnServer = !item->isSending()
&& !item->hasFailed();
if (wasOnServer) {
scheduledIdsByPeer[history->peer].push_back(MTP_int(
_session->data().scheduledMessages().lookupId(item)));
} else {
_session->data().scheduledMessages().removeSending(item);
}
continue;
}
remove.push_back(item);
if (IsServerMsgId(item->id)) {
idsByPeer[history].push_back(MTP_int(itemId.msg));
}
}
}
for (const auto &[history, ids] : idsByPeer) {
history->owner().histories().deleteMessages(history, ids, revoke);
}
for (const auto &[peer, ids] : scheduledIdsByPeer) {
peer->session().api().request(MTPmessages_DeleteScheduledMessages(
peer->input,
MTP_vector<MTPint>(ids)
)).done([peer=peer](const MTPUpdates &result) {
peer->session().api().applyUpdates(result);
}).send();
}
for (const auto item : remove) {
const auto history = item->history();
const auto wasLast = (history->lastMessage() == item);
const auto wasInChats = (history->chatListMessage() == item);
item->destroy();
if (wasLast || wasInChats) {
history->requestChatListMessage();
}
}
_session->data().histories().deleteMessages(_ids, revoke);
const auto session = _session;
Ui::hideLayer();

View File

@@ -28,12 +28,51 @@ class EmptyUserpic;
class InformBox;
class ConfirmBox : public Ui::BoxContent, public ClickHandlerHost {
public:
ConfirmBox(QWidget*, const QString &text, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(QWidget*, const QString &text, const QString &confirmText, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const QString &cancelText, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, const QString &cancelText, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(QWidget*, const TextWithEntities &text, const QString &confirmText, FnMut<void()> confirmedCallback = nullptr, FnMut<void()> cancelledCallback = nullptr);
using ConfirmedCallback = std::variant<
v::null_t,
FnMut<void()>,
FnMut<void(Fn<void()>)>>;
ConfirmBox(
QWidget*,
const QString &text,
ConfirmedCallback confirmedCallback = FnMut<void()>(),
FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
ConfirmedCallback confirmedCallback = FnMut<void()>(),
FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const style::RoundButton &confirmStyle,
ConfirmedCallback confirmedCallback = FnMut<void()>(),
FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const QString &cancelText,
ConfirmedCallback confirmedCallback = FnMut<void()>(),
FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const style::RoundButton &confirmStyle,
const QString &cancelText,
ConfirmedCallback confirmedCallback = FnMut<void()>(),
FnMut<void()> cancelledCallback = FnMut<void()>());
ConfirmBox(
QWidget*,
const TextWithEntities &text,
const QString &confirmText,
ConfirmedCallback confirmedCallback = v::null,
FnMut<void()> cancelledCallback = nullptr);
void updateLink();
@@ -87,7 +126,7 @@ private:
bool _confirmed = false;
bool _cancelled = false;
bool _strictCancel = false;
FnMut<void()> _confirmedCallback;
ConfirmBox::ConfirmedCallback _confirmedCallback;
FnMut<void()> _cancelledCallback;
};

View File

@@ -41,6 +41,48 @@ constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000);
using ProxyData = MTP::ProxyData;
class HostInput : public Ui::MaskedInputField {
public:
HostInput(
QWidget *parent,
const style::InputField &st,
rpl::producer<QString> placeholder,
const QString &val);
protected:
void correctValue(
const QString &was,
int wasCursor,
QString &now,
int &nowCursor) override;
};
HostInput::HostInput(
QWidget *parent,
const style::InputField &st,
rpl::producer<QString> placeholder,
const QString &val)
: MaskedInputField(parent, st, std::move(placeholder), val) {
}
void HostInput::correctValue(
const QString &was,
int wasCursor,
QString &now,
int &nowCursor) {
QString newText;
int newCursor = nowCursor;
newText.reserve(now.size());
for (auto i = 0, l = now.size(); i < l; ++i) {
if (now[i] == ',') {
newText.append('.');
} else {
newText.append(now[i]);
}
}
setCorrectedText(now, nowCursor, newText, newCursor);
}
class Base64UrlInput : public Ui::MaskedInputField {
public:
Base64UrlInput(
@@ -209,7 +251,7 @@ private:
std::shared_ptr<Ui::RadioenumGroup<Type>> _type;
QPointer<Ui::SlideWrap<>> _aboutSponsored;
QPointer<Ui::InputField> _host;
QPointer<HostInput> _host;
QPointer<Ui::PortInput> _port;
QPointer<Ui::InputField> _user;
QPointer<Ui::PasswordInput> _password;
@@ -767,12 +809,12 @@ ProxyBox::ProxyBox(
void ProxyBox::prepare() {
setTitle(tr::lng_proxy_edit());
connect(_host.data(), &Ui::InputField::changed, [=] {
connect(_host.data(), &HostInput::changed, [=] {
Ui::PostponeCall(_host, [=] {
const auto host = _host->getLastText().trimmed();
static const auto mask = u"^\\d+\\.\\d+\\.\\d+\\.\\d+:(\\d*)$"_q;
const auto match = QRegularExpression(mask).match(host);
if (_host->textCursor().position() == host.size()
if (_host->cursorPosition() == host.size()
&& match.hasMatch()) {
const auto port = match.captured(1);
_port->setText(port);
@@ -881,7 +923,7 @@ void ProxyBox::setupSocketAddress(const ProxyData &data) {
_content,
st::connectionHostInputField.heightMin),
st::proxyEditInputPadding);
_host = Ui::CreateChild<Ui::InputField>(
_host = Ui::CreateChild<HostInput>(
address,
st::connectionHostInputField,
tr::lng_connection_host_ph(),
@@ -1043,7 +1085,6 @@ void ProxiesBoxController::ShowApplyConfirmation(
proxy.password = fields.value(qsl("secret"));
}
if (proxy) {
const auto box = std::make_shared<QPointer<ConfirmBox>>();
const auto text = tr::lng_sure_enable_socks(
tr::now,
lt_server,
@@ -1053,7 +1094,7 @@ void ProxiesBoxController::ShowApplyConfirmation(
+ (proxy.type == Type::Mtproto
? "\n\n" + tr::lng_proxy_sponsor_warning(tr::now)
: QString());
*box = Ui::show(Box<ConfirmBox>(text, tr::lng_sure_enable(tr::now), [=] {
auto callback = [=](Fn<void()> &&close) {
auto &proxies = Global::RefProxiesList();
if (!ranges::contains(proxies, proxy)) {
proxies.push_back(proxy);
@@ -1062,10 +1103,14 @@ void ProxiesBoxController::ShowApplyConfirmation(
proxy,
ProxyData::Settings::Enabled);
Local::writeSettings();
if (const auto strong = box->data()) {
strong->closeBox();
}
}), Ui::LayerOption::KeepOther);
close();
};
Ui::show(
Box<ConfirmBox>(
text,
tr::lng_sure_enable(tr::now),
std::move(callback)),
Ui::LayerOption::KeepOther);
} else {
Ui::show(Box<InformBox>(
(proxy.status() == ProxyData::Status::Unsupported

View File

@@ -225,7 +225,7 @@ auto AddButtonWithLoader(
buttonState->value(
) | rpl::start_with_next([=](const DictState &state) {
const auto isToggledSet = state.is<Active>();
const auto isToggledSet = v::is<Active>(state);
const auto toggled = isToggledSet ? 1. : 0.;
const auto over = !button->isDisabled()
&& (button->isDown() || button->isOver());
@@ -252,7 +252,7 @@ auto AddButtonWithLoader(
dictionaryRemoved->events(),
buttonState->value(
) | rpl::filter([](const DictState &state) {
return state.is<Failed>();
return v::is<Failed>(state);
}) | rpl::to_empty
) | rpl::map_to(false)
)
@@ -276,13 +276,14 @@ auto AddButtonWithLoader(
});
}) | rpl::flatten_latest(
) | rpl::filter([=](const DictState &state) {
return !buttonState->current().is<Failed>() || !state.is<Available>();
return !v::is<Failed>(buttonState->current())
|| !v::is<Available>(state);
});
button->toggledValue(
) | rpl::start_with_next([=](bool toggled) {
const auto &state = buttonState->current();
if (toggled && (state.is<Available>() || state.is<Failed>())) {
if (toggled && (v::is<Available>(state) || v::is<Failed>(state))) {
const auto weak = Ui::MakeWeak(button);
setLocalLoader(base::make_unique_q<Loader>(
QCoreApplication::instance(),
@@ -292,7 +293,7 @@ auto AddButtonWithLoader(
Spellchecker::DictPathByLangId(id),
Spellchecker::GetDownloadSize(id),
crl::guard(weak, destroyLocalLoader)));
} else if (!toggled && state.is<Loading>()) {
} else if (!toggled && v::is<Loading>(state)) {
if (const auto g = rawGlobalLoaderPtr()) {
g->destroy();
return;

View File

@@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "platform/platform_specific.h"
#include "lang/lang_keys.h"
#include "layout.h"
#include "media/streaming/media_streaming_instance.h"
#include "media/streaming/media_streaming_player.h"
#include "media/streaming/media_streaming_document.h"
@@ -47,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/checkbox.h"
#include "ui/text/format_values.h"
#include "ui/special_buttons.h"
#include "ui/text_options.h"
#include "window/window_session_controller.h"
@@ -363,6 +363,12 @@ EditCaptionBox::EditCaptionBox(
) | rpl::start_with_next([&](bool checked) {
_asFile = checked;
}, _wayWrap->lifetime());
_controller->session().data().itemRemoved(
_msgId
) | rpl::start_with_next([=] {
closeBox();
}, lifetime());
}
EditCaptionBox::~EditCaptionBox() = default;
@@ -431,7 +437,7 @@ void EditCaptionBox::setupStreamedPreview(std::shared_ptr<Document> shared) {
}
void EditCaptionBox::handleStreamingUpdate(Update &&update) {
update.data.match([&](Information &update) {
v::match(update.data, [&](Information &update) {
streamingReady(std::move(update));
}, [&](const PreloadedVideo &update) {
}, [&](const UpdateVideo &update) {
@@ -489,7 +495,7 @@ void EditCaptionBox::updateEditPreview() {
auto isGif = false;
auto shouldAsDoc = true;
auto docPhotoSize = QSize();
if (const auto image = base::get_if<Info::Image>(fileMedia)) {
if (const auto image = std::get_if<Info::Image>(fileMedia)) {
shouldAsDoc = !Storage::ValidateThumbDimensions(
image->data.width(),
image->data.height());
@@ -501,14 +507,14 @@ void EditCaptionBox::updateEditPreview() {
_animated = isGif;
_photo = !isGif && !shouldAsDoc;
_isImage = true;
} else if (const auto video = base::get_if<Info::Video>(fileMedia)) {
} else if (const auto video = std::get_if<Info::Video>(fileMedia)) {
isGif = video->isGifv;
_animated = true;
shouldAsDoc = false;
}
if (shouldAsDoc) {
auto nameString = filename;
if (const auto song = base::get_if<Info::Song>(fileMedia)) {
if (const auto song = std::get_if<Info::Song>(fileMedia)) {
nameString = DocumentData::ComposeNameString(
filename,
song->title,
@@ -684,7 +690,7 @@ bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
const auto imageAsDoc = [&] {
using Info = FileMediaInformation;
const auto fileMedia = &file->information->media;
if (const auto image = base::get_if<Info::Image>(fileMedia)) {
if (const auto image = std::get_if<Info::Image>(fileMedia)) {
return !Storage::ValidateThumbDimensions(
image->data.width(),
image->data.height());
@@ -1030,7 +1036,7 @@ void EditCaptionBox::setName(QString nameString, qint64 size) {
st::semiboldTextStyle,
nameString,
Ui::NameTextOptions());
_status = formatSizeText(size);
_status = Ui::FormatSizeText(size);
}
void EditCaptionBox::keyPressEvent(QKeyEvent *e) {

View File

@@ -86,7 +86,7 @@ void PrivacyExceptionsBoxController::rowClicked(not_null<PeerListRow*> row) {
}
std::unique_ptr<PrivacyExceptionsBoxController::Row> PrivacyExceptionsBoxController::createRow(not_null<History*> history) {
if (history->peer->isSelf()) {
if (history->peer->isSelf() || history->peer->isRepliesChat()) {
return nullptr;
} else if (!history->peer->isUser()
&& !history->peer->isChat()

View File

@@ -241,19 +241,31 @@ void FilterChatsPreview::paintEvent(QPaintEvent *e) {
}
for (auto &[history, userpic, button] : _removePeer) {
const auto savedMessages = history->peer->isSelf();
if (savedMessages) {
Ui::EmptyUserpic::PaintSavedMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
const auto repliesMessages = history->peer->isRepliesChat();
if (savedMessages || repliesMessages) {
if (savedMessages) {
Ui::EmptyUserpic::PaintSavedMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
} else {
Ui::EmptyUserpic::PaintRepliesMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
}
p.setPen(st::contactsNameFg);
p.drawTextLeft(
nameLeft,
top + nameTop,
width(),
tr::lng_saved_messages(tr::now));
(savedMessages
? tr::lng_saved_messages(tr::now)
: tr::lng_replies_messages(tr::now)));
} else {
history->peer->paintUserpicLeft(
p,

View File

@@ -170,6 +170,8 @@ ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
QString ExceptionRow::generateName() {
return peer()->isSelf()
? tr::lng_saved_messages(tr::now)
: peer()->isRepliesChat()
? tr::lng_replies_messages(tr::now)
: Row::generateName();
}
@@ -180,10 +182,13 @@ QString ExceptionRow::generateShortName() {
PaintRoundImageCallback ExceptionRow::generatePaintUserpicCallback() {
const auto peer = this->peer();
const auto saved = peer->isSelf();
const auto replies = peer->isRepliesChat();
auto userpic = saved ? nullptr : ensureUserpicView();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else if (replies) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}

View File

@@ -105,7 +105,7 @@ private:
return (index == other.index);
}
};
using Selection = base::optional_variant<RowSelection, MenuSelection>;
using Selection = std::variant<v::null_t, RowSelection, MenuSelection>;
void updateSelected(Selection selected);
void updatePressed(Selection pressed);
@@ -196,7 +196,7 @@ std::pair<Languages, Languages> PrepareLists() {
const auto projId = [](const Language &language) {
return language.id;
};
const auto current = Lang::LanguageIdOrDefault(Lang::Current().id());
const auto current = Lang::LanguageIdOrDefault(Lang::Id());
auto official = Lang::CurrentCloudManager().languageList();
auto recent = Local::readRecentLanguages();
ranges::stable_partition(recent, [&](const Language &language) {
@@ -207,13 +207,13 @@ std::pair<Languages, Languages> PrepareLists() {
const auto generate = [&] {
const auto name = (current == "#custom")
? "Custom lang pack"
: Lang::Current().name();
: Lang::GetInstance().name();
return Language{
current,
QString(),
QString(),
name,
Lang::Current().nativeName()
Lang::GetInstance().nativeName()
};
};
const auto i = ranges::find(official, current, projId);
@@ -327,7 +327,7 @@ void Rows::mouseMoveEvent(QMouseEvent *e) {
void Rows::mousePressEvent(QMouseEvent *e) {
updatePressed(_selected);
if (_pressed.has_value()
if (!v::is_null(_pressed)
&& !rowBySelection(_pressed).menuToggleForceRippled) {
addRipple(_pressed, e->pos());
}
@@ -348,11 +348,11 @@ QRect Rows::menuToggleArea(not_null<const Row*> row) const {
}
void Rows::addRipple(Selection selected, QPoint position) {
Expects(selected.has_value());
Expects(!v::is_null(selected));
ensureRippleBySelection(selected);
const auto menu = selected.is<MenuSelection>();
const auto menu = v::is<MenuSelection>(selected);
const auto &row = rowBySelection(selected);
const auto menuArea = menuToggleArea(&row);
auto &ripple = rippleBySelection(&row, selected);
@@ -369,7 +369,7 @@ void Rows::ensureRippleBySelection(not_null<Row*> row, Selection selected) {
if (ripple) {
return;
}
const auto menu = selected.is<MenuSelection>();
const auto menu = v::is<MenuSelection>(selected);
const auto menuArea = menuToggleArea(row);
auto mask = menu
? Ui::RippleAnimation::ellipseMask(menuArea.size())
@@ -391,11 +391,11 @@ void Rows::mouseReleaseEvent(QMouseEvent *e) {
const auto pressed = _pressed;
updatePressed({});
if (pressed == _selected) {
pressed.match([&](RowSelection data) {
v::match(pressed, [&](RowSelection data) {
activateByIndex(data.index);
}, [&](MenuSelection data) {
showMenu(data.index);
}, [](std::nullopt_t) {});
}, [](v::null_t) {});
}
}
@@ -597,11 +597,11 @@ int Rows::count() const {
}
int Rows::indexFromSelection(Selection selected) const {
return selected.match([&](RowSelection data) {
return v::match(selected, [&](RowSelection data) {
return data.index;
}, [&](MenuSelection data) {
return data.index;
}, [](std::nullopt_t) {
}, [](v::null_t) {
return -1;
});
}
@@ -648,7 +648,7 @@ rpl::producer<bool> Rows::isEmpty() const {
}
void Rows::repaint(Selection selected) {
selected.match([](std::nullopt_t) {
v::match(selected, [](v::null_t) {
}, [&](const auto &data) {
repaint(data.index);
});
@@ -672,17 +672,17 @@ void Rows::repaintChecked(not_null<const Row*> row) {
}
void Rows::updateSelected(Selection selected) {
const auto changed = (_selected.has_value() != selected.has_value());
const auto changed = (v::is_null(_selected) != v::is_null(selected));
repaint(_selected);
_selected = selected;
repaint(_selected);
if (changed) {
_hasSelection.fire(_selected.has_value());
_hasSelection.fire(!v::is_null(_selected));
}
}
void Rows::updatePressed(Selection pressed) {
if (_pressed.has_value()) {
if (!v::is_null(_pressed)) {
if (!rowBySelection(_pressed).menuToggleForceRippled) {
if (const auto ripple = rippleBySelection(_pressed).get()) {
ripple->lastStop();
@@ -725,7 +725,7 @@ const std::unique_ptr<Ui::RippleAnimation> &Rows::rippleBySelection(
std::unique_ptr<Ui::RippleAnimation> &Rows::rippleBySelection(
not_null<Row*> row,
Selection selected) {
return selected.is<MenuSelection>()
return v::is<MenuSelection>(selected)
? row->menuToggleRipple
: row->ripple;
}
@@ -796,7 +796,7 @@ void Rows::paintEvent(QPaintEvent *e) {
const auto menu = menuToggleArea();
const auto selectedIndex = (_menuShownIndex >= 0)
? _menuShownIndex
: indexFromSelection(_pressed.has_value() ? _pressed : _selected);
: indexFromSelection(!v::is_null(_pressed) ? _pressed : _selected);
for (auto i = 0, till = count(); i != till; ++i) {
const auto &row = rowByIndex(i);
if (row.top + row.height <= clip.y()) {
@@ -867,7 +867,7 @@ void Content::setupContent(
const Languages &official) {
using namespace rpl::mappers;
const auto current = Lang::LanguageIdOrDefault(Lang::Current().id());
const auto current = Lang::LanguageIdOrDefault(Lang::Id());
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
const auto add = [&](const Languages &list, bool areOfficial) {
if (list.empty()) {
@@ -1101,7 +1101,7 @@ void LanguageBox::prepare() {
// "#custom" is applied each time it's passed to switchToLanguage().
// So we check that the language really has changed.
const auto currentId = [] {
return Lang::LanguageIdOrDefault(Lang::Current().id());
return Lang::LanguageIdOrDefault(Lang::Id());
};
if (language.id != currentId()) {
Lang::CurrentCloudManager().switchToLanguage(language);

View File

@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/shadow.h"
#include "ui/widgets/continuous_sliders.h"
#include "ui/effects/radial_animation.h"
#include "ui/text/format_values.h"
#include "ui/emoji_config.h"
#include "storage/storage_account.h"
#include "storage/cache/storage_cache_database.h"
@@ -21,7 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "main/main_session.h"
#include "layout.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
@@ -260,7 +260,7 @@ QString LocalStorageBox::Row::titleText(const Database::TaggedSummary &data) con
QString LocalStorageBox::Row::sizeText(const Database::TaggedSummary &data) const {
return data.totalSize
? formatSizeText(data.totalSize)
? Ui::FormatSizeText(data.totalSize)
: tr::lng_local_storage_empty(tr::now);
}

View File

@@ -17,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_domain.h"
#include "core/application.h"
#include "storage/storage_domain.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h"
@@ -24,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/fade_wrap.h"
#include "passport/passport_encryption.h"
#include "passport/passport_panel_edit_contact.h"
#include "settings/settings_privacy_security.h"
#include "facades.h"
#include "styles/style_layers.h"
#include "styles/style_passport.h"
@@ -31,6 +34,68 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
enum class PasswordErrorType {
None,
NoPassword,
Later,
};
void SetCloudPassword(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) {
session->api().passwordState(
) | rpl::start_with_next([=] {
using namespace Settings;
const auto weak = Ui::MakeWeak(box);
if (CheckEditCloudPassword(session)) {
box->getDelegate()->show(
EditCloudPasswordBox(session));
} else {
box->getDelegate()->show(CloudPasswordAppOutdatedBox());
}
if (weak) {
weak->closeBox();
}
}, box->lifetime());
}
void TransferPasswordError(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session,
TextWithEntities &&about,
PasswordErrorType error) {
box->setTitle(tr::lng_rights_transfer_check());
box->setWidth(st::transferCheckWidth);
auto text = std::move(about).append('\n').append('\n').append(
tr::lng_rights_transfer_check_password(
tr::now,
Ui::Text::RichLangValue)
).append('\n').append('\n').append(
tr::lng_rights_transfer_check_session(
tr::now,
Ui::Text::RichLangValue)
);
if (error == PasswordErrorType::Later) {
text.append('\n').append('\n').append(
tr::lng_rights_transfer_check_later(
tr::now,
Ui::Text::RichLangValue));
}
box->addRow(object_ptr<Ui::FlatLabel>(
box,
rpl::single(text),
st::boxLabel));
if (error == PasswordErrorType::Later) {
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
} else {
box->addButton(tr::lng_rights_transfer_set_password(), [=] {
SetCloudPassword(box, session);
});
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}
}
} // namespace
PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
@@ -537,14 +602,11 @@ void PasscodeBox::submitOnlyCheckCloudPassword(const QString &oldPassword) {
if (_cloudFields.turningOff && _cloudFields.notEmptyPassport) {
Assert(!_cloudFields.customCheckCallback);
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto confirmed = [=] {
const auto confirmed = [=](Fn<void()> &&close) {
send();
if (*box) {
(*box)->closeBox();
}
close();
};
*box = getDelegate()->show(Box<ConfirmBox>(
getDelegate()->show(Box<ConfirmBox>(
tr::lng_cloud_password_passport_losing(tr::now),
tr::lng_continue(tr::now),
confirmed));
@@ -744,20 +806,16 @@ void PasscodeBox::changeCloudPassword(
}
void PasscodeBox::suggestSecretReset(const QString &newPassword) {
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto resetSecretAndSave = [=] {
checkPasswordHash([=](const Core::CloudPasswordResult &check) {
resetSecret(check, newPassword, [=] {
if (*box) {
(*box)->closeBox();
}
});
auto resetSecretAndSave = [=](Fn<void()> &&close) {
checkPasswordHash([=, close = std::move(close)](
const Core::CloudPasswordResult &check) {
resetSecret(check, newPassword, std::move(close));
});
};
*box = getDelegate()->show(Box<ConfirmBox>(
getDelegate()->show(Box<ConfirmBox>(
Lang::Hard::PassportCorruptedChange(),
Lang::Hard::PassportCorruptedReset(),
[=] { resetSecretAndSave(); }));
std::move(resetSecretAndSave)));
}
void PasscodeBox::resetSecret(
@@ -1002,14 +1060,11 @@ void RecoverBox::submit() {
}).handleFloodErrors().send();
});
if (_notEmptyPassport) {
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto confirmed = [=] {
const auto confirmed = [=](Fn<void()> &&close) {
send();
if (*box) {
(*box)->closeBox();
}
close();
};
*box = getDelegate()->show(Box<ConfirmBox>(
getDelegate()->show(Box<ConfirmBox>(
tr::lng_cloud_password_passport_losing(tr::now),
tr::lng_continue(tr::now),
confirmed));
@@ -1139,3 +1194,28 @@ RecoveryEmailValidation ConfirmRecoveryEmail(
*weak = box.data();
return { std::move(box), reloads->events(), cancels->events() };
}
[[nodiscard]] object_ptr<Ui::GenericBox> PrePasswordErrorBox(
const RPCError &error,
not_null<Main::Session*> session,
TextWithEntities &&about) {
const auto type = [&] {
const auto &type = error.type();
if (type == qstr("PASSWORD_MISSING")) {
return PasswordErrorType::NoPassword;
} else if (type.startsWith(qstr("PASSWORD_TOO_FRESH_"))
|| type.startsWith(qstr("SESSION_TOO_FRESH_"))) {
return PasswordErrorType::Later;
}
return PasswordErrorType::None;
}();
if (type == PasswordErrorType::None) {
return nullptr;
}
return Box(
TransferPasswordError,
session,
std::move(about),
type);
}

View File

@@ -214,3 +214,8 @@ struct RecoveryEmailValidation {
[[nodiscard]] RecoveryEmailValidation ConfirmRecoveryEmail(
not_null<Main::Session*> session,
const QString &pattern);
[[nodiscard]] object_ptr<Ui::GenericBox> PrePasswordErrorBox(
const RPCError &error,
not_null<Main::Session*> session,
TextWithEntities &&about);

View File

@@ -36,10 +36,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
PaintRoundImageCallback PaintUserpicCallback(
not_null<PeerData*> peer,
bool respectSavedMessagesChat) {
if (respectSavedMessagesChat && peer->isSelf()) {
return [](Painter &p, int x, int y, int outerWidth, int size) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
};
if (respectSavedMessagesChat) {
if (peer->isSelf()) {
return [](Painter &p, int x, int y, int outerWidth, int size) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
};
} else if (peer->isRepliesChat()) {
return [](Painter &p, int x, int y, int outerWidth, int size) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
};
}
}
auto userpic = std::shared_ptr<Data::CloudImageView>();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
@@ -318,6 +324,8 @@ void PeerListBox::addSelectItem(
const auto respect = _controller->respectSavedMessagesChat();
const auto text = (respect && peer->isSelf())
? tr::lng_saved_short(tr::now)
: (respect && peer->isRepliesChat())
? tr::lng_replies_messages(tr::now)
: peer->shortName();
addSelectItem(
peer->id,
@@ -400,14 +408,16 @@ PeerListRow::PeerListRow(not_null<PeerData*> peer, PeerListRowId id)
, _peer(peer)
, _initialized(false)
, _isSearchResult(false)
, _isSavedMessagesChat(false) {
, _isSavedMessagesChat(false)
, _isRepliesMessagesChat(false) {
}
PeerListRow::PeerListRow(PeerListRowId id)
: _id(id)
, _initialized(false)
, _isSearchResult(false)
, _isSavedMessagesChat(false) {
, _isSavedMessagesChat(false)
, _isRepliesMessagesChat(false) {
}
PeerListRow::~PeerListRow() = default;
@@ -470,6 +480,8 @@ void PeerListRow::refreshName(const style::PeerListItem &st) {
}
const auto text = _isSavedMessagesChat
? tr::lng_saved_messages(tr::now)
: _isRepliesMessagesChat
? tr::lng_replies_messages(tr::now)
: generateName();
_name.setText(st.nameStyle, text, Ui::NameTextOptions());
}
@@ -481,6 +493,8 @@ QString PeerListRow::generateName() {
QString PeerListRow::generateShortName() {
return _isSavedMessagesChat
? tr::lng_saved_short(tr::now)
: _isRepliesMessagesChat
? tr::lng_replies_messages(tr::now)
: peer()->shortName();
}
@@ -493,11 +507,14 @@ std::shared_ptr<Data::CloudImageView> PeerListRow::ensureUserpicView() {
PaintRoundImageCallback PeerListRow::generatePaintUserpicCallback() {
const auto saved = _isSavedMessagesChat;
const auto replies = _isRepliesMessagesChat;
const auto peer = this->peer();
auto userpic = saved ? nullptr : ensureUserpicView();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else if (replies) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}
@@ -603,6 +620,8 @@ void PeerListRow::paintDisabledCheckUserpic(
if (_isSavedMessagesChat) {
Ui::EmptyUserpic::PaintSavedMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
} else if (_isRepliesMessagesChat) {
Ui::EmptyUserpic::PaintRepliesMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
} else {
peer()->paintUserpicLeft(p, _userpic, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
}
@@ -731,10 +750,12 @@ void PeerListContent::changeCheckState(
}
void PeerListContent::addRowEntry(not_null<PeerListRow*> row) {
if (_controller->respectSavedMessagesChat()
&& !row->special()
&& row->peer()->isSelf()) {
row->setIsSavedMessagesChat(true);
if (_controller->respectSavedMessagesChat() && !row->special()) {
if (row->peer()->isSelf()) {
row->setIsSavedMessagesChat(true);
} else if (row->peer()->isRepliesChat()) {
row->setIsRepliesMessagesChat(true);
}
}
_rowsById.emplace(row->id(), row);
if (!row->special()) {

View File

@@ -146,12 +146,12 @@ public:
void setIsSearchResult(bool isSearchResult) {
_isSearchResult = isSearchResult;
}
bool isSavedMessagesChat() const {
return _isSavedMessagesChat;
}
void setIsSavedMessagesChat(bool isSavedMessagesChat) {
_isSavedMessagesChat = isSavedMessagesChat;
}
void setIsRepliesMessagesChat(bool isRepliesMessagesChat) {
_isRepliesMessagesChat = isRepliesMessagesChat;
}
template <typename UpdateCallback>
void setChecked(
@@ -234,6 +234,7 @@ private:
bool _initialized : 1;
bool _isSearchResult : 1;
bool _isSavedMessagesChat : 1;
bool _isRepliesMessagesChat : 1;
};

View File

@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_histories.h"
#include "apiwrap.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "lang/lang_keys.h"
#include "history/history.h"
#include "dialogs/dialogs_main_list.h"
@@ -104,6 +105,20 @@ void AddBotToGroup(not_null<UserData*> bot, not_null<PeerData*> chat) {
// return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
//}
object_ptr<Ui::BoxContent> PrepareContactsBox(
not_null<Window::SessionController*> sessionController) {
const auto controller = sessionController;
auto delegate = [=](not_null<PeerListBox*> box) {
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
box->addLeftButton(
tr::lng_profile_add_contact(),
[=] { controller->widget()->onShowAddContact(); });
};
return Box<PeerListBox>(
std::make_unique<ContactsBoxController>(controller),
std::move(delegate));
}
void PeerListRowWithLink::setActionLink(const QString &action) {
_action = action;
refreshActionLink();
@@ -584,8 +599,7 @@ void ChooseRecipientBoxController::rowClicked(not_null<PeerListRow*> row) {
auto ChooseRecipientBoxController::createRow(
not_null<History*> history) -> std::unique_ptr<Row> {
const auto peer = history->peer;
const auto skip = peer->isChannel()
&& !peer->isMegagroup()
&& !peer->canWrite();
const auto skip = (peer->isBroadcast() && !peer->canWrite())
|| peer->isRepliesChat();
return skip ? nullptr : std::make_unique<Row>(history);
}

View File

@@ -31,9 +31,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History;
namespace Window {
class SessionController;
class SessionNavigation;
} // namespace Window
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareContactsBox(
not_null<Window::SessionController*> sessionController);
class PeerListRowWithLink : public PeerListRow {
public:
using PeerListRow::PeerListRow;
@@ -203,8 +207,7 @@ public:
protected:
void prepareViewHook() override;
std::unique_ptr<Row> createRow(
not_null<History*> history) override;
std::unique_ptr<Row> createRow(not_null<History*> history) override;
private:
const not_null<Window::SessionNavigation*> _navigation;

View File

@@ -576,11 +576,7 @@ void AddSpecialBoxController::showAdmin(
}
// Finally show the admin.
const auto currentRights = _additional.isCreator(user)
? MTPChatAdminRights(MTP_chatAdminRights(
MTP_flags(~MTPDchatAdminRights::Flag::f_add_admins
| MTPDchatAdminRights::Flag::f_add_admins)))
: adminRights
const auto currentRights = adminRights
? *adminRights
: MTPChatAdminRights(MTP_chatAdminRights(MTP_flags(0)));
auto box = Box<EditAdminBox>(
@@ -618,6 +614,7 @@ void AddSpecialBoxController::editAdminDone(
_additional.applyParticipant(MTP_channelParticipantCreator(
MTP_flags(rank.isEmpty() ? Flag(0) : Flag::f_rank),
MTP_int(user->bareId()),
rights,
MTP_string(rank)));
} else if (rights.c_chatAdminRights().vflags().v == 0) {
_additional.applyParticipant(MTP_channelParticipant(
@@ -665,7 +662,7 @@ void AddSpecialBoxController::showRestricted(
} else if (_additional.adminRights(user).has_value()
|| _additional.isCreator(user)) {
// The user is an admin or creator.
if (_additional.canEditAdmin(user)) {
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
if (!sure) {
_editBox = Ui::show(
Box<ConfirmBox>(
@@ -755,7 +752,7 @@ void AddSpecialBoxController::kickUser(
if (_additional.adminRights(user).has_value()
|| _additional.isCreator(user)) {
// The user is an admin or creator.
if (_additional.canEditAdmin(user)) {
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
if (!sure) {
_editBox = Ui::show(
Box<ConfirmBox>(

View File

@@ -146,15 +146,12 @@ void Controller::choose(not_null<ChannelData*> chat) {
Ui::Text::RichLangValue));
}
}
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto sure = [=] {
if (*box) {
(*box)->closeBox();
}
const auto sure = [=](Fn<void()> &&close) {
close();
const auto onstack = _callback;
onstack(chat);
};
*box = Ui::show(
Ui::show(
Box<ConfirmBox>(
text,
tr::lng_manage_discussion_group_link(tr::now),
@@ -178,18 +175,15 @@ void Controller::choose(not_null<ChatData*> chat) {
text.append(tr::lng_manage_discussion_group_warning(
tr::now,
Ui::Text::RichLangValue));
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto sure = [=] {
if (*box) {
(*box)->closeBox();
}
const auto sure = [=](Fn<void()> &&close) {
close();
const auto done = [=](not_null<ChannelData*> chat) {
const auto onstack = _callback;
onstack(chat);
};
chat->session().api().migrateChat(chat, crl::guard(this, done));
};
*box = Ui::show(
Ui::show(
Box<ConfirmBox>(
text,
tr::lng_manage_discussion_group_link(tr::now),

View File

@@ -47,70 +47,6 @@ constexpr auto kSecondsInDay = 24 * 60 * 60;
constexpr auto kSecondsInWeek = 7 * kSecondsInDay;
constexpr auto kAdminRoleLimit = 16;
enum class PasswordErrorType {
None,
NoPassword,
Later,
};
void SetCloudPassword(not_null<Ui::GenericBox*> box, not_null<UserData*> user) {
user->session().api().passwordState(
) | rpl::start_with_next([=] {
using namespace Settings;
const auto weak = Ui::MakeWeak(box);
if (CheckEditCloudPassword(&user->session())) {
box->getDelegate()->show(
EditCloudPasswordBox(&user->session()));
} else {
box->getDelegate()->show(CloudPasswordAppOutdatedBox());
}
if (weak) {
weak->closeBox();
}
}, box->lifetime());
}
void TransferPasswordError(
not_null<Ui::GenericBox*> box,
not_null<UserData*> user,
PasswordErrorType error) {
box->setTitle(tr::lng_rights_transfer_check());
box->setWidth(st::transferCheckWidth);
auto text = tr::lng_rights_transfer_check_about(
tr::now,
lt_user,
Ui::Text::Bold(user->shortName()),
Ui::Text::WithEntities
).append('\n').append('\n').append(
tr::lng_rights_transfer_check_password(
tr::now,
Ui::Text::RichLangValue)
).append('\n').append('\n').append(
tr::lng_rights_transfer_check_session(
tr::now,
Ui::Text::RichLangValue)
);
if (error == PasswordErrorType::Later) {
text.append('\n').append('\n').append(
tr::lng_rights_transfer_check_later(
tr::now,
Ui::Text::RichLangValue));
}
box->addRow(object_ptr<Ui::FlatLabel>(
box,
rpl::single(text),
st::boxLabel));
if (error == PasswordErrorType::Later) {
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
} else {
box->addButton(tr::lng_rights_transfer_set_password(), [=] {
SetCloudPassword(box, user);
});
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}
}
} // namespace
class EditParticipantBox::Inner : public Ui::RpWidget {
@@ -318,7 +254,7 @@ void EditAdminBox::prepare() {
const auto disabledMessages = [&] {
auto result = std::map<Flags, QString>();
if (!canSave() || (amCreator() && user()->isSelf())) {
if (!canSave()) {
result.emplace(
~Flags(0),
tr::lng_rights_about_admin_cant_edit(tr::now));
@@ -327,7 +263,11 @@ void EditAdminBox::prepare() {
disabledByDefaults,
tr::lng_rights_permission_for_all(tr::now));
if (const auto channel = peer()->asChannel()) {
if (!channel->amCreator()) {
if (amCreator() && user()->isSelf()) {
result.emplace(
~Flag::f_anonymous,
tr::lng_rights_permission_cant_edit(tr::now));
} else if (!channel->amCreator()) {
result.emplace(
~channel->adminRights(),
tr::lng_rights_permission_cant_edit(tr::now));
@@ -368,7 +308,7 @@ void EditAdminBox::prepare() {
}, lifetime());
if (canTransferOwnership()) {
const auto allFlags = FullAdminRights(isGroup);
const auto allFlags = AdminRightsForOwnershipTransfer(isGroup);
setupTransferButton(
isGroup
)->toggleOn(rpl::duplicate(
@@ -520,22 +460,17 @@ void EditAdminBox::transferOwnership() {
}
bool EditAdminBox::handleTransferPasswordError(const RPCError &error) {
const auto type = [&] {
const auto &type = error.type();
if (type == qstr("PASSWORD_MISSING")) {
return PasswordErrorType::NoPassword;
} else if (type.startsWith(qstr("PASSWORD_TOO_FRESH_"))
|| type.startsWith(qstr("SESSION_TOO_FRESH_"))) {
return PasswordErrorType::Later;
}
return PasswordErrorType::None;
}();
if (type == PasswordErrorType::None) {
return false;
const auto session = &user()->session();
auto about = tr::lng_rights_transfer_check_about(
tr::now,
lt_user,
Ui::Text::Bold(user()->shortName()),
Ui::Text::WithEntities);
if (auto box = PrePasswordErrorBox(error, session, std::move(about))) {
getDelegate()->show(std::move(box));
return true;
}
getDelegate()->show(Box(TransferPasswordError, user(), type));
return true;
return false;
}
void EditAdminBox::transferOwnershipChecked() {
@@ -639,7 +574,9 @@ void EditAdminBox::sendTransferRequestFrom(
void EditAdminBox::refreshAboutAddAdminsText(bool canAddAdmins) {
_aboutAddAdmins->setText([&] {
if (!canSave() || (amCreator() && user()->isSelf())) {
if (amCreator() && user()->isSelf()) {
return QString();
} else if (!canSave()) {
return tr::lng_rights_about_admin_cant_edit(tr::now);
} else if (canAddAdmins) {
return tr::lng_rights_about_add_admins_yes(tr::now);

View File

@@ -564,6 +564,12 @@ UserData *ParticipantsAdditionalData::applyCreator(
const MTPDchannelParticipantCreator &data) {
if (const auto user = applyRegular(data.vuser_id())) {
_creator = user;
_adminRights[user] = data.vadmin_rights();
if (user->isSelf()) {
_adminCanEdit.emplace(user);
} else {
_adminCanEdit.erase(user);
}
if (const auto rank = data.vrank()) {
_adminRanks[user] = qs(*rank);
} else {
@@ -1459,11 +1465,7 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
void ParticipantsBoxController::showAdmin(not_null<UserData*> user) {
const auto adminRights = _additional.adminRights(user);
const auto currentRights = _additional.isCreator(user)
? MTPChatAdminRights(MTP_chatAdminRights(
MTP_flags(~MTPDchatAdminRights::Flag::f_add_admins
| MTPDchatAdminRights::Flag::f_add_admins)))
: adminRights
const auto currentRights = adminRights
? *adminRights
: MTPChatAdminRights(MTP_chatAdminRights(MTP_flags(0)));
auto box = Box<EditAdminBox>(
@@ -1504,6 +1506,7 @@ void ParticipantsBoxController::editAdminDone(
_additional.applyParticipant(MTP_channelParticipantCreator(
MTP_flags(rank.isEmpty() ? Flag(0) : Flag::f_rank),
MTP_int(user->bareId()),
rights,
MTP_string(rank)));
} else if (rights.c_chatAdminRights().vflags().v == 0) {
_additional.applyParticipant(MTP_channelParticipant(
@@ -1783,6 +1786,7 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
auto row = std::make_unique<PeerListRowWithLink>(user);
refreshCustomStatus(row.get());
if (_role == Role::Admins
&& !_additional.isCreator(user)
&& _additional.adminRights(user).has_value()
&& _additional.canEditAdmin(user)) {
row->setActionLink(tr::lng_profile_kick(tr::now));

View File

@@ -135,6 +135,7 @@ std::vector<std::pair<ChatAdminRights, QString>> AdminRightLabels(
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::f_pin_messages, tr::lng_rights_group_pin(tr::now) },
{ Flag::f_anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::f_add_admins, tr::lng_rights_add_admins(tr::now) },
};
} else {
@@ -297,10 +298,12 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) {
return restrictions;
}
ChatAdminRights FullAdminRights(bool isGroup) {
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup) {
auto result = ChatAdminRights();
for (const auto &[flag, label] : AdminRightLabels(isGroup, true)) {
result |= flag;
if (!(flag & ChatAdminRight::f_anonymous)) {
result |= flag;
}
}
return result;
}

View File

@@ -71,4 +71,4 @@ EditFlagsControl<MTPDchatAdminRights::Flags> CreateEditAdminRights(
ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer);
ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions);
ChatAdminRights FullAdminRights(bool isGroup);
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup);

View File

@@ -546,17 +546,14 @@ void Controller::revokeInviteLink() {
}
void Controller::exportInviteLink(const QString &confirmation) {
const auto boxPointer = std::make_shared<QPointer<ConfirmBox>>();
const auto callback = crl::guard(this, [=] {
if (const auto strong = *boxPointer) {
strong->closeBox();
}
const auto callback = crl::guard(this, [=](Fn<void()> &&close) {
close();
_peer->session().api().exportInviteLink(_peer->migrateToOrMe());
});
auto box = Box<ConfirmBox>(
confirmation,
std::move(callback));
*boxPointer = Ui::show(std::move(box), Ui::LayerOption::KeepOther);
Ui::show(std::move(box), Ui::LayerOption::KeepOther);
}
bool Controller::canEditInviteLink() const {

View File

@@ -9,8 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "main/main_session.h"
#include "boxes/confirm_box.h"
#include "history/history_item.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
@@ -18,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h"
#include "core/core_settings.h"
#include "core/application.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_profile.h"
@@ -207,3 +211,18 @@ void ReportBox::updateMaxHeight() {
}
setDimensions(st::boxWidth, newHeight);
}
void BlockSenderFromRepliesBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
FullMsgId id) {
const auto item = controller->session().data().message(id);
Assert(item != nullptr);
PeerMenuBlockUserBox(
box,
&controller->window(),
item->senderOriginal(),
true,
Window::ClearReply{ id });
}

View File

@@ -8,8 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/abstract_box.h"
#include "ui/layers/generic_box.h"
#include "mtproto/sender.h"
namespace Window {
class SessionController;
} // namespace Window
namespace Ui {
template <typename Enum>
class RadioenumGroup;
@@ -60,3 +65,8 @@ private:
mtpRequestId _requestId = 0;
};
void BlockSenderFromRepliesBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
FullMsgId id);

View File

@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h"
#include "ui/widgets/scroll_area.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/text/format_values.h"
#include "ui/grouped_layout.h"
#include "ui/text_options.h"
#include "ui/special_buttons.h"
@@ -41,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "layout.h"
#include "facades.h" // App::LambdaDelayed.
#include "app.h"
#include "styles/style_history.h"
@@ -352,7 +352,7 @@ AlbumThumb::AlbumThumb(
} else {
auto fileinfo = QFileInfo(filepath);
_name = fileinfo.fileName();
_status = formatSizeText(fileinfo.size());
_status = Ui::FormatSizeText(fileinfo.size());
}
_nameWidth = st::semiboldFont->width(_name);
if (_nameWidth > availableFileWidth) {
@@ -766,11 +766,11 @@ SingleMediaPreview *SingleMediaPreview::Create(
auto preview = QImage();
bool animated = false;
bool animationPreview = false;
if (const auto image = base::get_if<FileMediaInformation::Image>(
if (const auto image = std::get_if<FileMediaInformation::Image>(
&file.information->media)) {
preview = image->data;
animated = animationPreview = image->animated;
} else if (const auto video = base::get_if<FileMediaInformation::Video>(
} else if (const auto video = std::get_if<FileMediaInformation::Video>(
&file.information->media)) {
preview = video->thumbnail;
animated = true;
@@ -1004,10 +1004,10 @@ void SingleFilePreview::prepareThumb(const QImage &preview) {
void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) {
auto preview = QImage();
if (const auto image = base::get_if<FileMediaInformation::Image>(
if (const auto image = std::get_if<FileMediaInformation::Image>(
&file.information->media)) {
preview = image->data;
} else if (const auto video = base::get_if<FileMediaInformation::Video>(
} else if (const auto video = std::get_if<FileMediaInformation::Video>(
&file.information->media)) {
preview = video->thumbnail;
}
@@ -1034,7 +1034,7 @@ void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) {
auto songTitle = QString();
auto songPerformer = QString();
if (file.information) {
if (const auto song = base::get_if<FileMediaInformation::Song>(
if (const auto song = std::get_if<FileMediaInformation::Song>(
&file.information->media)) {
songTitle = song->title;
songPerformer = song->performer;
@@ -1050,7 +1050,7 @@ void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) {
st::semiboldTextStyle,
nameString,
Ui::NameTextOptions());
_statusText = formatSizeText(fileinfo.size());
_statusText = Ui::FormatSizeText(fileinfo.size());
_statusWidth = qMax(
_nameText.maxWidth(),
st::normalFont->width(_statusText));

View File

@@ -7,24 +7,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/sessions_box.h"
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "apiwrap.h"
#include "api/api_authorizations.h"
#include "base/timer.h"
#include "base/unixtime.h"
#include "boxes/confirm_box.h"
#include "settings/settings_common.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "styles/style_layers.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h"
#include "styles/style_layers.h"
#include "styles/style_settings.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/scroll_area.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
namespace {
@@ -32,7 +31,63 @@ constexpr auto kSessionsShortPollTimeout = 60 * crl::time(1000);
} // namespace
class SessionsBox::List : public Ui::RpWidget {
class SessionsContent : public Ui::RpWidget {
public:
SessionsContent(QWidget*, not_null<Main::Session*> session);
void setupContent();
protected:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
private:
struct Entry {
Entry() = default;
Entry(const Api::Authorizations::Entry &entry)
: hash(entry.hash)
, incomplete(entry.incomplete)
, activeTime(entry.activeTime)
, name(st::sessionNameStyle, entry.name)
, active(st::sessionWhenStyle, entry.active)
, info(st::sessionInfoStyle, entry.info)
, ip(st::sessionInfoStyle, entry.ip) {
};
uint64 hash = 0;
bool incomplete = false;
TimeId activeTime = 0;
Ui::Text::String name, active, info, ip;
};
struct Full {
Entry current;
std::vector<Entry> incomplete;
std::vector<Entry> list;
};
class Inner;
class List;
void shortPollSessions();
void parse(const Api::Authorizations::List &list);
void terminate(Fn<void()> terminateRequest, QString message);
void terminateOne(uint64 hash);
void terminateAll();
const not_null<Api::Authorizations*> _authorizations;
rpl::variable<bool> _loading = false;
Full _data;
object_ptr<Inner> _inner;
QPointer<ConfirmBox> _terminateBox;
base::Timer _shortPollTimer;
};
class SessionsContent::List : public Ui::RpWidget {
public:
List(QWidget *parent);
@@ -43,11 +98,20 @@ public:
void terminating(uint64 hash, bool terminating);
protected:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
int resizeGetHeight(int newWidth) override;
private:
struct RowWidth {
int available = 0;
int info = 0;
};
RowWidth _rowWidth;
void computeRowWidth();
std::vector<Entry> _items;
std::map<uint64, std::unique_ptr<Ui::IconButton>> _terminateButtons;
rpl::event_stream<uint64> _terminate;
@@ -55,7 +119,7 @@ private:
};
class SessionsBox::Inner : public Ui::RpWidget {
class SessionsContent::Inner : public Ui::RpWidget {
public:
Inner(QWidget *parent);
@@ -75,22 +139,21 @@ private:
};
SessionsBox::SessionsBox(QWidget*, not_null<Main::Session*> session)
: _session(session)
, _api(&_session->mtp())
SessionsContent::SessionsContent(QWidget*, not_null<Main::Session*> session)
: _authorizations(&session->api().authorizations())
, _inner(this)
, _shortPollTimer([=] { shortPollSessions(); }) {
}
void SessionsBox::prepare() {
setTitle(tr::lng_sessions_other_header());
addButton(tr::lng_close(), [=] { closeBox(); });
setDimensions(st::boxWideWidth, st::sessionsHeight);
_inner = setInnerWidget(object_ptr<Inner>(this), st::sessionsScroll);
void SessionsContent::setupContent() {
_inner->resize(width(), st::noContactsHeight);
_inner->heightValue(
) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](int height) {
resize(width(), height);
}, _inner->lifetime());
_inner->terminateOne(
) | rpl::start_with_next([=](uint64 hash) {
terminateOne(hash);
@@ -101,34 +164,58 @@ void SessionsBox::prepare() {
terminateAll();
}, lifetime());
_session->data().newAuthorizationChecks(
) | rpl::start_with_next([=] {
shortPollSessions();
_loading.changes(
) | rpl::start_with_next([=](bool value) {
_inner->setVisible(!value);
}, lifetime());
setLoading(true);
_authorizations->listChanges(
) | rpl::start_with_next([=](const Api::Authorizations::List &list) {
parse(list);
}, lifetime());
_loading = true;
shortPollSessions();
}
void SessionsBox::setLoading(bool loading) {
if (_loading != loading) {
_loading = loading;
setInnerVisible(!_loading);
void SessionsContent::parse(const Api::Authorizations::List &list) {
if (list.empty()) {
return;
}
_data = Full();
for (const auto &auth : list) {
auto entry = Entry(auth);
if (!entry.hash) {
_data.current = std::move(entry);
} else if (entry.incomplete) {
_data.incomplete.push_back(std::move(entry));
} else {
_data.list.push_back(std::move(entry));
}
}
_loading = false;
ranges::sort(_data.list, std::greater<>(), &Entry::activeTime);
ranges::sort(_data.incomplete, std::greater<>(), &Entry::activeTime);
_inner->showData(_data);
_shortPollTimer.callOnce(kSessionsShortPollTimeout);
}
void SessionsBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
void SessionsContent::resizeEvent(QResizeEvent *e) {
RpWidget::resizeEvent(e);
_inner->resize(width(), _inner->height());
}
void SessionsBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
void SessionsContent::paintEvent(QPaintEvent *e) {
RpWidget::paintEvent(e);
Painter p(this);
if (_loading) {
if (_loading.current()) {
p.setFont(st::noContactsFont);
p.setPen(st::noContactsColor);
p.drawText(
@@ -138,166 +225,43 @@ void SessionsBox::paintEvent(QPaintEvent *e) {
}
}
void SessionsBox::got(const MTPaccount_Authorizations &result) {
_shortPollRequest = 0;
setLoading(false);
_data = Full();
result.match([&](const MTPDaccount_authorizations &data) {
const auto &list = data.vauthorizations().v;
for (const auto &auth : list) {
auth.match([&](const MTPDauthorization &data) {
auto entry = ParseEntry(data);
if (!entry.hash) {
_data.current = std::move(entry);
} else if (entry.incomplete) {
_data.incomplete.push_back(std::move(entry));
} else {
_data.list.push_back(std::move(entry));
}
});
}
});
const auto getActiveTime = [](const Entry &entry) {
return entry.activeTime;
};
ranges::sort(_data.list, std::greater<>(), getActiveTime);
ranges::sort(_data.incomplete, std::greater<>(), getActiveTime);
_inner->showData(_data);
_shortPollTimer.callOnce(kSessionsShortPollTimeout);
}
SessionsBox::Entry SessionsBox::ParseEntry(const MTPDauthorization &data) {
auto result = Entry();
result.hash = data.is_current() ? 0 : data.vhash().v;
result.incomplete = data.is_password_pending();
auto appName = QString();
auto appVer = qs(data.vapp_version());
const auto systemVer = qs(data.vsystem_version());
const auto deviceModel = qs(data.vdevice_model());
const auto apiId = data.vapi_id().v;
if (apiId == 2040 || apiId == 17349) {
appName = (apiId == 2040)
? qstr("Telegram Desktop")
: qstr("Telegram Desktop (GitHub)");
//if (systemVer == qstr("windows")) {
// deviceModel = qsl("Windows");
//} else if (systemVer == qstr("os x")) {
// deviceModel = qsl("OS X");
//} else if (systemVer == qstr("linux")) {
// deviceModel = qsl("Linux");
//}
if (appVer == QString::number(appVer.toInt())) {
const auto ver = appVer.toInt();
appVer = QString("%1.%2"
).arg(ver / 1000000
).arg((ver % 1000000) / 1000)
+ ((ver % 1000)
? ('.' + QString::number(ver % 1000))
: QString());
//} else {
// appVer = QString();
}
void SessionsContent::shortPollSessions() {
const auto left = kSessionsShortPollTimeout
- (crl::now() - _authorizations->lastReceivedTime());
if (left > 0) {
parse(_authorizations->list());
_shortPollTimer.cancel();
_shortPollTimer.callOnce(left);
} else {
appName = qs(data.vapp_name());// +qsl(" for ") + qs(d.vplatform());
if (appVer.indexOf('(') >= 0) {
appVer = appVer.mid(appVer.indexOf('('));
}
_authorizations->reload();
}
result.name = appName;
if (!appVer.isEmpty()) {
result.name += ' ' + appVer;
}
const auto country = qs(data.vcountry());
const auto platform = qs(data.vplatform());
//const auto &countries = countriesByISO2();
//const auto j = countries.constFind(country);
//if (j != countries.cend()) {
// country = QString::fromUtf8(j.value()->name);
//}
result.activeTime = data.vdate_active().v
? data.vdate_active().v
: data.vdate_created().v;
result.info = qs(data.vdevice_model()) + qstr(", ") + (platform.isEmpty() ? QString() : platform + ' ') + qs(data.vsystem_version());
result.ip = qs(data.vip()) + (country.isEmpty() ? QString() : QString::fromUtf8(" \xe2\x80\x93 ") + country);
if (!result.hash) {
result.active = tr::lng_status_online(tr::now);
result.activeWidth = st::sessionWhenFont->width(tr::lng_status_online(tr::now));
} else {
const auto now = QDateTime::currentDateTime();
const auto lastTime = base::unixtime::parse(result.activeTime);
const auto nowDate = now.date();
const auto lastDate = lastTime.date();
if (lastDate == nowDate) {
result.active = lastTime.toString(cTimeFormat());
} else if (lastDate.year() == nowDate.year()
&& lastDate.weekNumber() == nowDate.weekNumber()) {
result.active = langDayOfWeek(lastDate);
} else {
result.active = lastDate.toString(qsl("d.MM.yy"));
}
result.activeWidth = st::sessionWhenFont->width(result.active);
}
ResizeEntry(result);
return result;
}
void SessionsBox::ResizeEntry(Entry &entry) {
const auto available = st::boxWideWidth
- st::sessionPadding.left()
- st::sessionTerminateSkip;
const auto availableInList = available
- st::sessionTerminate.iconPosition.x();
const auto availableListInfo = available - st::sessionTerminate.width;
const auto resize = [](
const style::font &font,
QString &string,
int &stringWidth,
int available) {
stringWidth = font->width(string);
if (stringWidth > available) {
string = font->elided(string, available);
stringWidth = font->width(string);
}
};
const auto forName = entry.hash ? availableInList : available;
const auto forInfo = entry.hash ? availableListInfo : available;
resize(st::sessionNameFont, entry.name, entry.nameWidth, forName);
resize(st::sessionInfoFont, entry.info, entry.infoWidth, forInfo);
resize(st::sessionInfoFont, entry.ip, entry.ipWidth, available);
}
void SessionsBox::shortPollSessions() {
if (_shortPollRequest) {
return;
}
_shortPollRequest = _api.request(MTPaccount_GetAuthorizations(
)).done([=](const MTPaccount_Authorizations &result) {
got(result);
}).send();
update();
}
void SessionsBox::terminateOne(uint64 hash) {
if (_terminateBox) _terminateBox->deleteLater();
void SessionsContent::terminate(Fn<void()> terminateRequest, QString message) {
if (_terminateBox) {
_terminateBox->deleteLater();
}
const auto callback = crl::guard(this, [=] {
if (_terminateBox) {
_terminateBox->closeBox();
_terminateBox = nullptr;
}
_api.request(MTPaccount_ResetAuthorization(
MTP_long(hash)
)).done([=](const MTPBool &result) {
terminateRequest();
});
_terminateBox = Ui::show(
Box<ConfirmBox>(
message,
tr::lng_settings_reset_button(tr::now),
st::attentionBoxButton,
callback),
Ui::LayerOption::KeepOther);
}
void SessionsContent::terminateOne(uint64 hash) {
const auto weak = Ui::MakeWeak(this);
auto callback = [=] {
auto done = crl::guard(weak, [=](const MTPBool &result) {
_inner->terminatingOne(hash, false);
const auto getHash = [](const Entry &entry) {
return entry.hash;
@@ -310,52 +274,40 @@ void SessionsBox::terminateOne(uint64 hash) {
removeByHash(_data.incomplete);
removeByHash(_data.list);
_inner->showData(_data);
}).fail([=](const RPCError &error) {
});
auto fail = crl::guard(weak, [=](const RPCError &error) {
_inner->terminatingOne(hash, false);
}).send();
});
_authorizations->requestTerminate(
std::move(done),
std::move(fail),
hash);
_inner->terminatingOne(hash, true);
});
_terminateBox = Ui::show(
Box<ConfirmBox>(
tr::lng_settings_reset_one_sure(tr::now),
tr::lng_settings_reset_button(tr::now),
st::attentionBoxButton,
callback),
Ui::LayerOption::KeepOther);
};
terminate(std::move(callback), tr::lng_settings_reset_one_sure(tr::now));
}
void SessionsBox::terminateAll() {
if (_terminateBox) _terminateBox->deleteLater();
const auto callback = crl::guard(this, [=] {
if (_terminateBox) {
_terminateBox->closeBox();
_terminateBox = nullptr;
}
_api.request(MTPauth_ResetAuthorizations(
)).done([=](const MTPBool &result) {
_api.request(base::take(_shortPollRequest)).cancel();
void SessionsContent::terminateAll() {
const auto weak = Ui::MakeWeak(this);
auto callback = [=] {
const auto reset = crl::guard(weak, [=] {
_authorizations->cancelCurrentRequest();
shortPollSessions();
}).fail([=](const RPCError &result) {
_api.request(base::take(_shortPollRequest)).cancel();
shortPollSessions();
}).send();
setLoading(true);
});
_terminateBox = Ui::show(
Box<ConfirmBox>(
tr::lng_settings_reset_sure(tr::now),
tr::lng_settings_reset_button(tr::now),
st::attentionBoxButton,
callback),
Ui::LayerOption::KeepOther);
});
_authorizations->requestTerminate(
[=](const MTPBool &result) { reset(); },
[=](const RPCError &result) { reset(); });
_loading = true;
};
terminate(std::move(callback), tr::lng_settings_reset_sure(tr::now));
}
SessionsBox::Inner::Inner(QWidget *parent)
SessionsContent::Inner::Inner(QWidget *parent)
: RpWidget(parent) {
setupContent();
}
void SessionsBox::Inner::setupContent() {
void SessionsContent::Inner::setupContent() {
using namespace Settings;
using namespace rpl::mappers;
@@ -418,32 +370,40 @@ void SessionsBox::Inner::setupContent() {
Ui::ResizeFitChild(this, content);
}
void SessionsBox::Inner::showData(const Full &data) {
void SessionsContent::Inner::showData(const Full &data) {
_current->showData({ &data.current, &data.current + 1 });
_list->showData(data.list);
_incomplete->showData(data.incomplete);
}
rpl::producer<> SessionsBox::Inner::terminateAll() const {
rpl::producer<> SessionsContent::Inner::terminateAll() const {
return _terminateAll->clicks() | rpl::to_empty;
}
rpl::producer<uint64> SessionsBox::Inner::terminateOne() const {
rpl::producer<uint64> SessionsContent::Inner::terminateOne() const {
return rpl::merge(
_incomplete->terminate(),
_list->terminate());
}
void SessionsBox::Inner::terminatingOne(uint64 hash, bool terminating) {
void SessionsContent::Inner::terminatingOne(uint64 hash, bool terminating) {
_incomplete->terminating(hash, terminating);
_list->terminating(hash, terminating);
}
SessionsBox::List::List(QWidget *parent) : RpWidget(parent) {
SessionsContent::List::List(QWidget *parent) : RpWidget(parent) {
setAttribute(Qt::WA_OpaquePaintEvent);
}
void SessionsBox::List::showData(gsl::span<const Entry> items) {
void SessionsContent::List::resizeEvent(QResizeEvent *e) {
RpWidget::resizeEvent(e);
computeRowWidth();
}
void SessionsContent::List::showData(gsl::span<const Entry> items) {
computeRowWidth();
auto buttons = base::take(_terminateButtons);
_items.clear();
_items.insert(begin(_items), items.begin(), items.end());
@@ -466,24 +426,27 @@ void SessionsBox::List::showData(gsl::span<const Entry> items) {
_terminate.fire_copy(hash);
});
button->show();
button->moveToRight(
st::sessionTerminateSkip,
((_terminateButtons.size() - 1) * st::sessionHeight
+ st::sessionTerminateTop));
const auto number = _terminateButtons.size() - 1;
widthValue(
) | rpl::start_with_next([=] {
button->moveToRight(
st::sessionTerminateSkip,
(number * st::sessionHeight + st::sessionTerminateTop));
}, lifetime());
}
resizeToWidth(width());
_itemsCount.fire(_items.size());
}
rpl::producer<int> SessionsBox::List::itemsCount() const {
rpl::producer<int> SessionsContent::List::itemsCount() const {
return _itemsCount.events_starting_with(_items.size());
}
rpl::producer<uint64> SessionsBox::List::terminate() const {
rpl::producer<uint64> SessionsContent::List::terminate() const {
return _terminate.events();
}
void SessionsBox::List::terminating(uint64 hash, bool terminating) {
void SessionsContent::List::terminating(uint64 hash, bool terminating) {
const auto i = _terminateButtons.find(hash);
if (i != _terminateButtons.cend()) {
if (terminating) {
@@ -495,11 +458,21 @@ void SessionsBox::List::terminating(uint64 hash, bool terminating) {
}
}
int SessionsBox::List::resizeGetHeight(int newWidth) {
int SessionsContent::List::resizeGetHeight(int newWidth) {
return _items.size() * st::sessionHeight;
}
void SessionsBox::List::paintEvent(QPaintEvent *e) {
void SessionsContent::List::computeRowWidth() {
const auto available = width()
- st::sessionPadding.left()
- st::sessionTerminateSkip;
_rowWidth = {
.available = available,
.info = available - st::sessionTerminate.width,
};
}
void SessionsContent::List::paintEvent(QPaintEvent *e) {
QRect r(e->rect());
Painter p(this);
@@ -513,6 +486,7 @@ void SessionsBox::List::paintEvent(QPaintEvent *e) {
0,
count);
const auto available = _rowWidth.available;
const auto x = st::sessionPadding.left();
const auto y = st::sessionPadding.top();
const auto w = width();
@@ -522,23 +496,66 @@ void SessionsBox::List::paintEvent(QPaintEvent *e) {
for (auto i = from; i != till; ++i) {
const auto &entry = _items[i];
p.setFont(st::sessionNameFont);
const auto activeW = entry.active.maxWidth();
const auto nameW = available
- activeW
- st::sessionNamePadding.right();
const auto nameH = entry.name.style()->font->height;
const auto infoW = entry.hash ? _rowWidth.info : available;
const auto infoH = entry.info.style()->font->height;
p.setPen(entry.hash ? st::sessionWhenFg : st::contactsStatusFgOnline);
entry.active.drawRight(p, xact, y, activeW, w);
p.setPen(st::sessionNameFg);
p.drawTextLeft(x, y, w, entry.name, entry.nameWidth);
entry.name.drawLeftElided(p, x, y, nameW, w);
p.setFont(st::sessionWhenFont);
p.setPen(st::sessionWhenFg);
p.drawTextRight(xact, y, w, entry.active, entry.activeWidth);
const auto name = st::sessionNameFont->height;
p.setFont(st::sessionInfoFont);
p.setPen(st::boxTextFg);
p.drawTextLeft(x, y + name, w, entry.info, entry.infoWidth);
entry.info.drawLeftElided(p, x, y + nameH, infoW, w);
const auto info = st::sessionInfoFont->height;
p.setPen(st::sessionInfoFg);
p.drawTextLeft(x, y + name + info, w, entry.ip, entry.ipWidth);
entry.ip.drawLeftElided(p, x, y + nameH + infoH, available, w);
p.translate(0, st::sessionHeight);
}
}
SessionsBox::SessionsBox(QWidget*, not_null<Main::Session*> session)
: _session(session) {
}
void SessionsBox::prepare() {
setTitle(tr::lng_sessions_other_header());
addButton(tr::lng_close(), [=] { closeBox(); });
const auto w = st::boxWideWidth;
const auto content = setInnerWidget(
object_ptr<SessionsContent>(this, _session),
st::sessionsScroll);
content->resize(w, st::noContactsHeight);
content->setupContent();
setDimensions(w, st::sessionsHeight);
}
namespace Settings {
Sessions::Sessions(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent) {
setupContent(controller);
}
void Sessions::setupContent(not_null<Window::SessionController*> controller) {
const auto container = Ui::CreateChild<Ui::VerticalLayout>(this);
const auto content = container->add(
object_ptr<SessionsContent>(container, &controller->session()));
content->setupContent();
Ui::ResizeFitChild(this, container);
}
} // namespace Settings

View File

@@ -8,20 +8,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/abstract_box.h"
#include "mtproto/sender.h"
#include "base/timer.h"
class ConfirmBox;
namespace Ui {
class IconButton;
class LinkButton;
} // namespace Ui
#include "settings/settings_common.h"
namespace Main {
class Session;
} // namespace Main
namespace Settings {
class Sessions : public Section {
public:
Sessions(
QWidget *parent,
not_null<Window::SessionController*> controller);
private:
void setupContent(not_null<Window::SessionController*> controller);
};
} // namespace Settings
class SessionsBox : public Ui::BoxContent {
public:
SessionsBox(QWidget*, not_null<Main::Session*> session);
@@ -29,46 +36,7 @@ public:
protected:
void prepare() override;
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
private:
struct Entry {
uint64 hash = 0;
bool incomplete = false;
TimeId activeTime = 0;
int nameWidth, activeWidth, infoWidth, ipWidth;
QString name, active, info, ip;
};
struct Full {
Entry current;
std::vector<Entry> incomplete;
std::vector<Entry> list;
};
class Inner;
class List;
static Entry ParseEntry(const MTPDauthorization &data);
static void ResizeEntry(Entry &entry);
void setLoading(bool loading);
void shortPollSessions();
void got(const MTPaccount_Authorizations &result);
void terminateOne(uint64 hash);
void terminateAll();
const not_null<Main::Session*> _session;
MTP::Sender _api;
bool _loading = false;
Full _data;
QPointer<Inner> _inner;
QPointer<ConfirmBox> _terminateBox;
base::Timer _shortPollTimer;
mtpRequestId _shortPollRequest = 0;
};

View File

@@ -635,7 +635,11 @@ void ShareBox::Inner::updateChat(not_null<PeerData*> peer) {
void ShareBox::Inner::updateChatName(
not_null<Chat*> chat,
not_null<PeerData*> peer) {
const auto text = peer->isSelf() ? tr::lng_saved_messages(tr::now) : peer->name;
const auto text = peer->isSelf()
? tr::lng_saved_messages(tr::now)
: peer->isRepliesChat()
? tr::lng_replies_messages(tr::now)
: peer->name;
chat->name.setText(st::shareNameStyle, text, Ui::NameTextOptions());
}

View File

@@ -24,6 +24,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image_location_factory.h"
#include "ui/text/text_utilities.h"
#include "ui/emoji_config.h"
#include "ui/toast/toast.h"
#include "ui/widgets/popup_menu.h"
#include "lottie/lottie_multi_player.h"
#include "lottie/lottie_animation.h"
#include "chat_helpers/stickers_lottie.h"
@@ -36,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "app.h"
#include "styles/style_layers.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_info.h"
#include <QtWidgets/QApplication>
#include <QtGui/QClipboard>
@@ -189,11 +192,10 @@ void StickerSetBox::addStickers() {
_inner->install();
}
void StickerSetBox::shareStickers() {
void StickerSetBox::copyStickersLink() {
const auto url = _controller->session().createInternalLinkFull(
qsl("addstickers/") + _inner->shortName());
QGuiApplication::clipboard()->setText(url);
Ui::show(Box<InformBox>(tr::lng_stickers_copied(tr::now)));
}
void StickerSetBox::updateTitleAndButtons() {
@@ -207,10 +209,33 @@ void StickerSetBox::updateButtons() {
if (_inner->notInstalled()) {
addButton(tr::lng_stickers_add_pack(), [=] { addStickers(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });
if (!_inner->shortName().isEmpty()) {
const auto top = addTopButton(st::infoTopBarMenu);
const auto share = [=] {
copyStickersLink();
Ui::Toast::Show(tr::lng_stickers_copied(tr::now));
closeBox();
};
const auto menu =
std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
top->setClickedCallback([=] {
*menu = base::make_unique_q<Ui::PopupMenu>(top);
(*menu)->addAction(
tr::lng_stickers_share_pack(tr::now),
share);
(*menu)->popup(QCursor::pos());
return true;
});
}
} else if (_inner->official()) {
addButton(tr::lng_about_done(), [=] { closeBox(); });
} else {
addButton(tr::lng_stickers_share_pack(), [=] { shareStickers(); });
auto share = [=] {
copyStickersLink();
Ui::Toast::Show(tr::lng_stickers_copied(tr::now));
};
addButton(tr::lng_stickers_share_pack(), std::move(share));
addButton(tr::lng_cancel(), [=] { closeBox(); });
}
} else {

View File

@@ -41,7 +41,7 @@ private:
void updateTitleAndButtons();
void updateButtons();
void addStickers();
void shareStickers();
void copyStickersLink();
const not_null<Window::SessionController*> _controller;
MTPInputStickerSet _set;

View File

@@ -179,7 +179,7 @@ private:
return false;
}
};
using SelectedRow = base::optional_variant<MegagroupSet, int>;
using SelectedRow = std::variant<v::null_t, MegagroupSet, int>;
class AddressField : public Ui::UsernameInput {
public:
using UsernameInput::UsernameInput;
@@ -1101,7 +1101,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
if (_megagroupSet) {
auto selectedIndex = [&] {
if (auto index = base::get_if<int>(&_selected)) {
if (auto index = std::get_if<int>(&_selected)) {
return *index;
}
return -1;
@@ -1341,7 +1341,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) {
if (_actionSel >= 0) {
setActionDown(_actionSel);
update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
} else if (auto selectedIndex = base::get_if<int>(&_selected)) {
} else if (auto selectedIndex = std::get_if<int>(&_selected)) {
if (_section == Section::Installed && !_rows[*selectedIndex]->isRecentSet() && _inDragArea) {
_above = _dragging = _started = *selectedIndex;
_dragStart = mapFromGlobal(_mouse);
@@ -1394,7 +1394,7 @@ void StickersBox::Inner::setSelected(SelectedRow selected) {
return;
}
auto countSelectedIndex = [&] {
if (auto index = base::get_if<int>(&_selected)) {
if (auto index = std::get_if<int>(&_selected)) {
return *index;
}
return -1;
@@ -1416,7 +1416,7 @@ void StickersBox::Inner::setPressed(SelectedRow pressed) {
return;
}
auto countPressedIndex = [&] {
if (auto index = base::get_if<int>(&_pressed)) {
if (auto index = std::get_if<int>(&_pressed)) {
return *index;
}
return -1;
@@ -1544,7 +1544,7 @@ void StickersBox::Inner::updateCursor() {
? ((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel))
? style::cur_pointer
: style::cur_default)
: (_selected.has_value() || _pressed.has_value())
: (!v::is_null(_selected) || !v::is_null(_pressed))
? style::cur_pointer
: style::cur_default);
}
@@ -1582,7 +1582,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
_dragging = _started = -1;
} else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) {
const auto selectedIndex = [&] {
if (auto index = base::get_if<int>(&_selected)) {
if (auto index = std::get_if<int>(&_selected)) {
return *index;
}
return -1;
@@ -1602,7 +1602,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
showSetByRow(*row);
}
}
} else if (_megagroupSelectedSet && _selected.is<MegagroupSet>()) {
} else if (_megagroupSelectedSet && v::is<MegagroupSet>(_selected)) {
showSetByRow(*_megagroupSelectedSet);
}
}

View File

@@ -272,8 +272,11 @@ void BoxController::prepare() {
}, lifetime());
session().changes().messageUpdates(
Data::MessageUpdate::Flag::CallAdded
) | rpl::start_with_next([=](const Data::MessageUpdate &update) {
Data::MessageUpdate::Flag::NewAdded
) | rpl::filter([=](const Data::MessageUpdate &update) {
const auto media = update.item->media();
return (media != nullptr) && (media->call() != nullptr);
}) | rpl::start_with_next([=](const Data::MessageUpdate &update) {
insertRow(update.item, InsertWay::Prepend);
}, lifetime());
@@ -294,6 +297,7 @@ void BoxController::loadMoreRows() {
MTP_inputPeerEmpty(),
MTP_string(),
MTP_inputUserEmpty(),
MTPint(), // top_msg_id
MTP_inputMessagesFilterPhoneCalls(MTP_flags(0)),
MTP_int(0),
MTP_int(0),

View File

@@ -1082,7 +1082,8 @@ void Call::handleControllerError(const QString &error) {
void Call::destroyController() {
if (_instance) {
const auto state = _instance->stop();
_instance->stop([](tgcalls::FinalState) {
});
DEBUG_LOG(("Call Info: Destroying call controller.."));
_instance.reset();

View File

@@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/window.h"
#include "ui/effects/ripple_animation.h"
#include "ui/image/image.h"
#include "ui/text/format_values.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/platform/ui_platform_utility.h"
@@ -38,7 +39,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/platform_specific.h"
#include "base/platform/base_platform_info.h"
#include "window/main_window.h"
#include "layout.h"
#include "app.h"
#include "webrtc/webrtc_video_track.h"
#include "styles/style_calls.h"
@@ -1070,7 +1070,7 @@ void Panel::updateStatusText(State state) {
auto durationMs = _call->getDurationMs();
auto durationSeconds = durationMs / 1000;
startDurationUpdateTimer(durationMs);
return formatDurationText(durationSeconds);
return Ui::FormatDurationText(durationSeconds);
}
return tr::lng_call_status_ended(tr::now);
} break;

View File

@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/text/format_values.h"
#include "lang/lang_keys.h"
#include "core/application.h"
#include "calls/calls_call.h"
@@ -20,7 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "boxes/abstract_box.h"
#include "base/timer.h"
#include "layout.h"
#include "app.h"
#include "styles/style_calls.h"
#include "styles/style_layers.h"
@@ -162,7 +162,7 @@ void TopBar::updateDurationText() {
auto durationMs = _call->getDurationMs();
auto durationSeconds = durationMs / 1000;
startDurationUpdateTimer(durationMs);
_durationLabel->setText(formatDurationText(durationSeconds));
_durationLabel->setText(Ui::FormatDurationText(durationSeconds));
if (_durationLabel->width() != wasWidth) {
updateControlsGeometry();
}

View File

@@ -569,7 +569,7 @@ std::vector<QString> EmojiKeywords::languages() {
const auto yieldList = [&](const QStringList &list) {
result.insert(end(result), list.begin(), list.end());
};
yield(Lang::Current().id());
yield(Lang::Id());
yield(Lang::DefaultLanguageId());
yield(Lang::CurrentCloudManager().suggestedLanguage());
yield(Platform::SystemLanguage());

View File

@@ -263,8 +263,8 @@ void Row::paintRadio(Painter &p) {
const auto loading = _loading
? _loading->computeState()
: Ui::RadialState{ 0., 0, FullArcLength };
const auto isToggledSet = _state.current().is<Active>();
const auto isActiveSet = isToggledSet || _state.current().is<Loading>();
const auto isToggledSet = v::is<Active>(_state.current());
const auto isActiveSet = isToggledSet || v::is<Loading>(_state.current());
const auto toggled = _toggled.value(isToggledSet ? 1. : 0.);
const auto active = _active.value(isActiveSet ? 1. : 0.);
const auto _st = &st::defaultRadio;
@@ -345,7 +345,7 @@ void Row::onStateChanged(State was, StateChangeSource source) {
}
void Row::updateStatusColorOverride() {
const auto isToggledSet = _state.current().is<Active>();
const auto isToggledSet = v::is<Active>(_state.current());
const auto toggled = _toggled.value(isToggledSet ? 1. : 0.);
const auto over = showOver();
if (toggled == 0. && !over) {
@@ -373,7 +373,8 @@ void Row::setupContent(const Set &set) {
});
}) | rpl::flatten_latest(
) | rpl::filter([=](const SetState &state) {
return !_state.current().is<Failed>() || !state.is<Available>();
return !v::is<Failed>(_state.current())
|| !v::is<Available>(state);
});
setupLabels(set);
@@ -390,9 +391,10 @@ void Row::setupHandler() {
clicks(
) | rpl::filter([=] {
const auto &state = _state.current();
return !_switching && (state.is<Ready>() || state.is<Available>());
return !_switching && (v::is<Ready>(state)
|| v::is<Available>(state));
}) | rpl::start_with_next([=] {
if (_state.current().is<Available>()) {
if (v::is<Available>(_state.current())) {
load();
return;
}
@@ -409,7 +411,7 @@ void Row::setupHandler() {
_state.value(
) | rpl::map([=](const SetState &state) {
return state.is<Ready>() || state.is<Available>();
return v::is<Ready>(state) || v::is<Available>(state);
}) | rpl::start_with_next([=](bool active) {
setDisabled(!active);
setPointerCursor(active);
@@ -463,7 +465,7 @@ void Row::setupPreview(const Set &set) {
void Row::updateLoadingToFinished() {
_loading->update(
_state.current().is<Failed>() ? 0. : 1.,
v::is<Failed>(_state.current()) ? 0. : 1.,
true,
crl::now());
}
@@ -471,7 +473,7 @@ void Row::updateLoadingToFinished() {
void Row::radialAnimationCallback(crl::time now) {
const auto updated = [&] {
const auto state = _state.current();
if (const auto loading = base::get_if<Loading>(&state)) {
if (const auto loading = std::get_if<Loading>(&state)) {
return _loading->update(CountProgress(loading), false, now);
} else {
updateLoadingToFinished();
@@ -493,7 +495,7 @@ void Row::setupAnimation() {
_state.value(
) | rpl::map(
_1 == Active()
_1 == SetState{ Active() }
) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](bool toggled) {
_toggled.start(
@@ -505,7 +507,7 @@ void Row::setupAnimation() {
_state.value(
) | rpl::map([](const SetState &state) {
return state.is<Loading>() || state.is<Active>();
return v::is<Loading>(state) || v::is<Active>(state);
}) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](bool active) {
_active.start(
@@ -517,7 +519,7 @@ void Row::setupAnimation() {
_state.value(
) | rpl::map([](const SetState &state) {
return base::get_if<Loading>(&state);
return std::get_if<Loading>(&state);
}) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](const Loading *loading) {
if (loading && !_loading) {

View File

@@ -150,13 +150,26 @@ void EditLinkBox::prepare() {
session);
InitSpellchecker(_controller, text);
const auto url = content->add(
object_ptr<Ui::InputField>(
const auto placeholder = content->add(
object_ptr<Ui::RpWidget>(content),
st::markdownLinkFieldPadding);
placeholder->setAttribute(Qt::WA_TransparentForMouseEvents);
const auto url = Ui::AttachParentChild(
content,
object_ptr<Ui::MaskedInputField>(
content,
st::defaultInputField,
tr::lng_formatting_link_url(),
_startLink.trimmed()),
st::markdownLinkFieldPadding);
_startLink.trimmed()));
url->heightValue(
) | rpl::start_with_next([placeholder](int height) {
placeholder->resize(placeholder->width(), height);
}, placeholder->lifetime());
placeholder->widthValue(
) | rpl::start_with_next([=](int width) {
url->resize(width, url->height());
}, placeholder->lifetime());
url->move(placeholder->pos());
const auto submit = [=] {
const auto linkText = text->getLastText();
@@ -178,7 +191,7 @@ void EditLinkBox::prepare() {
connect(text, &Ui::InputField::submitted, [=] {
url->setFocusFast();
});
connect(url, &Ui::InputField::submitted, [=] {
connect(url, &Ui::MaskedInputField::submitted, [=] {
if (text->getLastText().isEmpty()) {
text->setFocusFast();
} else {
@@ -198,7 +211,11 @@ void EditLinkBox::prepare() {
setDimensions(st::boxWidth, content->height());
_setInnerFocus = [=] {
(_startText.isEmpty() ? text : url)->setFocusFast();
if (_startText.isEmpty()) {
text->setFocusFast();
} else {
url->setFocusFast();
}
};
}

View File

@@ -366,7 +366,7 @@ std::vector<int> DefaultLanguages() {
append(method->locale());
}
append(QLocale(Platform::SystemLanguage()));
append(QLocale(Lang::LanguageIdOrDefault(Lang::Current().id())));
append(QLocale(Lang::LanguageIdOrDefault(Lang::Id())));
return langs;
}

View File

@@ -143,7 +143,7 @@ private:
Search,
Settings,
};
using OverState = base::variant<SpecialOver, int>;
using OverState = std::variant<SpecialOver, int>;
template <typename Callback>
void enumerateVisibleIcons(Callback callback);
@@ -548,7 +548,7 @@ void StickersListWidget::Footer::mouseMoveEvent(QMouseEvent *e) {
if (!_iconsDragging
&& !_icons.empty()
&& base::get_if<int>(&_iconDown) != nullptr) {
&& v::is<int>(_iconDown)) {
if ((_iconsMousePos - _iconsMouseDown).manhattanLength() >= QApplication::startDragDistance()) {
_iconsDragging = true;
}
@@ -579,7 +579,7 @@ void StickersListWidget::Footer::mouseReleaseEvent(QMouseEvent *e) {
updateSelected();
if (wasDown == _iconOver) {
if (const auto index = base::get_if<int>(&_iconOver)) {
if (const auto index = std::get_if<int>(&_iconOver)) {
_iconSelX = anim::value(
*index * st::stickerIconWidth,
*index * st::stickerIconWidth);
@@ -604,7 +604,7 @@ bool StickersListWidget::Footer::eventHook(QEvent *e) {
if (e->type() == QEvent::TouchBegin) {
} else if (e->type() == QEvent::Wheel) {
if (!_icons.empty()
&& (base::get_if<int>(&_iconOver) != nullptr)
&& v::is<int>(_iconOver)
&& (_iconDown == SpecialOver::None)) {
scrollByWheelEvent(static_cast<QWheelEvent*>(e));
}
@@ -635,7 +635,7 @@ void StickersListWidget::Footer::scrollByWheelEvent(
}
void StickersListWidget::Footer::updateSelected() {
if (_iconDown >= 0) {
if (_iconDown != SpecialOver::None) {
return;
}
@@ -1509,8 +1509,10 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
}
auto &sets = shownSets();
auto selectedSticker = base::get_if<OverSticker>(&_selected);
auto selectedButton = base::get_if<OverButton>(_pressed ? &_pressed : &_selected);
auto selectedSticker = std::get_if<OverSticker>(&_selected);
auto selectedButton = std::get_if<OverButton>(!v::is_null(_pressed)
? &_pressed
: &_selected);
if (sets.empty() && _section == Section::Search) {
paintEmptySearchResults(p);
@@ -1625,7 +1627,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
if (clip.top() + clip.height() <= info.rowsTop) {
return true;
} else if (set.id == Data::Stickers::MegagroupSetId && set.stickers.empty()) {
auto buttonSelected = (base::get_if<OverGroupAdd>(&_selected) != nullptr);
auto buttonSelected = (std::get_if<OverGroupAdd>(&_selected) != nullptr);
paintMegagroupEmptySet(p, info.rowsTop, buttonSelected);
return true;
}
@@ -1971,20 +1973,20 @@ void StickersListWidget::mousePressEvent(QMouseEvent *e) {
}
void StickersListWidget::setPressed(OverState newPressed) {
if (auto button = base::get_if<OverButton>(&_pressed)) {
if (auto button = std::get_if<OverButton>(&_pressed)) {
auto &sets = shownSets();
Assert(button->section >= 0 && button->section < sets.size());
auto &set = sets[button->section];
if (set.ripple) {
set.ripple->lastStop();
}
} else if (base::get_if<OverGroupAdd>(&_pressed)) {
} else if (std::get_if<OverGroupAdd>(&_pressed)) {
if (_megagroupSetButtonRipple) {
_megagroupSetButtonRipple->lastStop();
}
}
_pressed = newPressed;
if (auto button = base::get_if<OverButton>(&_pressed)) {
if (auto button = std::get_if<OverButton>(&_pressed)) {
auto &sets = shownSets();
Assert(button->section >= 0 && button->section < sets.size());
auto &set = sets[button->section];
@@ -1992,7 +1994,7 @@ void StickersListWidget::setPressed(OverState newPressed) {
set.ripple = createButtonRipple(button->section);
}
set.ripple->add(mapFromGlobal(QCursor::pos()) - buttonRippleTopLeft(button->section));
} else if (base::get_if<OverGroupAdd>(&_pressed)) {
} else if (std::get_if<OverGroupAdd>(&_pressed)) {
if (!_megagroupSetButtonRipple) {
auto maskSize = _megagroupSetButtonRect.size();
auto mask = Ui::RippleAnimation::roundRectMask(maskSize, st::buttonRadius);
@@ -2059,10 +2061,10 @@ void StickersListWidget::fillContextMenu(
SendMenu::Type type) {
auto selected = _selected;
auto &sets = shownSets();
if (!selected || _pressed) {
if (v::is_null(selected) || !v::is_null(_pressed)) {
return;
}
if (auto sticker = base::get_if<OverSticker>(&selected)) {
if (auto sticker = std::get_if<OverSticker>(&selected)) {
Assert(sticker->section >= 0 && sticker->section < sets.size());
auto &set = sets[sticker->section];
Assert(sticker->index >= 0 && sticker->index < set.stickers.size());
@@ -2109,7 +2111,7 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
_previewTimer.cancel();
auto pressed = _pressed;
setPressed(std::nullopt);
setPressed(v::null);
if (pressed != _selected) {
update();
}
@@ -2124,8 +2126,8 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
updateSelected();
auto &sets = shownSets();
if (pressed && pressed == _selected) {
if (auto sticker = base::get_if<OverSticker>(&pressed)) {
if (!v::is_null(pressed) && pressed == _selected) {
if (auto sticker = std::get_if<OverSticker>(&pressed)) {
Assert(sticker->section >= 0 && sticker->section < sets.size());
auto &set = sets[sticker->section];
Assert(sticker->index >= 0 && sticker->index < set.stickers.size());
@@ -2145,10 +2147,10 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
} else {
_chosen.fire_copy({ .document = document });
}
} else if (auto set = base::get_if<OverSet>(&pressed)) {
} else if (auto set = std::get_if<OverSet>(&pressed)) {
Assert(set->section >= 0 && set->section < sets.size());
displaySet(sets[set->section].id);
} else if (auto button = base::get_if<OverButton>(&pressed)) {
} else if (auto button = std::get_if<OverButton>(&pressed)) {
Assert(button->section >= 0 && button->section < sets.size());
if (sets[button->section].externalLayout) {
installSet(sets[button->section].id);
@@ -2159,7 +2161,7 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
} else {
removeSet(sets[button->section].id);
}
} else if (base::get_if<OverGroupAdd>(&pressed)) {
} else if (std::get_if<OverGroupAdd>(&pressed)) {
Ui::show(Box<StickersBox>(controller(), _megagroupSet));
}
}
@@ -2271,8 +2273,8 @@ void StickersListWidget::enterFromChildEvent(QEvent *e, QWidget *child) {
}
void StickersListWidget::clearSelection() {
setPressed(std::nullopt);
setSelected(std::nullopt);
setPressed(v::null);
setSelected(v::null);
update();
}
@@ -2750,11 +2752,11 @@ bool StickersListWidget::preventAutoHide() {
}
void StickersListWidget::updateSelected() {
if (_pressed && !_previewShown) {
if (!v::is_null(_pressed) && !_previewShown) {
return;
}
auto newSelected = OverState { std::nullopt };
auto newSelected = OverState { v::null };
auto p = mapFromGlobal(_lastMousePosition);
if (!rect().contains(p)
|| p.y() < getVisibleTop() || p.y() >= getVisibleBottom()
@@ -2827,13 +2829,15 @@ bool StickersListWidget::stickerHasDeleteButton(const Set &set, int index) const
void StickersListWidget::setSelected(OverState newSelected) {
if (_selected != newSelected) {
setCursor(newSelected ? style::cur_pointer : style::cur_default);
setCursor(!v::is_null(newSelected)
? style::cur_pointer
: style::cur_default);
auto &sets = shownSets();
auto updateSelected = [&]() {
if (auto sticker = base::get_if<OverSticker>(&_selected)) {
if (auto sticker = std::get_if<OverSticker>(&_selected)) {
rtlupdate(stickerRect(sticker->section, sticker->index));
} else if (auto button = base::get_if<OverButton>(&_selected)) {
} else if (auto button = std::get_if<OverButton>(&_selected)) {
if (button->section >= 0
&& button->section < sets.size()
&& sets[button->section].externalLayout) {
@@ -2841,7 +2845,7 @@ void StickersListWidget::setSelected(OverState newSelected) {
} else {
rtlupdate(removeButtonRect(button->section));
}
} else if (base::get_if<OverGroupAdd>(&_selected)) {
} else if (std::get_if<OverGroupAdd>(&_selected)) {
rtlupdate(megagroupSetButtonRectFinal());
}
};
@@ -2850,7 +2854,7 @@ void StickersListWidget::setSelected(OverState newSelected) {
updateSelected();
if (_previewShown && _pressed != _selected) {
if (const auto sticker = base::get_if<OverSticker>(&_selected)) {
if (const auto sticker = std::get_if<OverSticker>(&_selected)) {
_pressed = _selected;
Assert(sticker->section >= 0 && sticker->section < sets.size());
const auto &set = sets[sticker->section];
@@ -2865,7 +2869,7 @@ void StickersListWidget::setSelected(OverState newSelected) {
}
void StickersListWidget::showPreview() {
if (const auto sticker = base::get_if<OverSticker>(&_pressed)) {
if (const auto sticker = std::get_if<OverSticker>(&_pressed)) {
const auto &sets = shownSets();
Assert(sticker->section >= 0 && sticker->section < sets.size());
const auto &set = sets[sticker->section];

View File

@@ -121,30 +121,46 @@ private:
int section = 0;
int index = 0;
bool overDelete = false;
inline bool operator==(OverSticker other) const {
return (section == other.section)
&& (index == other.index)
&& (overDelete == other.overDelete);
}
inline bool operator!=(OverSticker other) const {
return !(*this == other);
}
};
struct OverSet {
int section = 0;
inline bool operator==(OverSet other) const {
return (section == other.section);
}
inline bool operator!=(OverSet other) const {
return !(*this == other);
}
};
struct OverButton {
int section = 0;
inline bool operator==(OverButton other) const {
return (section == other.section);
}
inline bool operator!=(OverButton other) const {
return !(*this == other);
}
};
struct OverGroupAdd {
inline bool operator==(OverGroupAdd other) const {
return true;
}
inline bool operator!=(OverGroupAdd other) const {
return !(*this == other);
}
};
friend inline bool operator==(OverSticker a, OverSticker b) {
return (a.section == b.section)
&& (a.index == b.index)
&& (a.overDelete == b.overDelete);
}
friend inline bool operator==(OverSet a, OverSet b) {
return (a.section == b.section);
}
friend inline bool operator==(OverButton a, OverButton b) {
return (a.section == b.section);
}
friend inline bool operator==(OverGroupAdd a, OverGroupAdd b) {
return true;
}
using OverState = base::optional_variant<
using OverState = std::variant<
v::null_t,
OverSticker,
OverSet,
OverButton,

View File

@@ -53,6 +53,7 @@ generate({
'ipPortSecret#37982646',
'accessPointRule#4679b65f',
'help.configSimple#5a592a6c',
'messageReplies#81834865',
],
'renamedTypes': {

View File

@@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_translator.h"
#include "lang/lang_cloud_manager.h"
#include "lang/lang_hardcoded.h"
#include "lang/lang_instance.h"
#include "mainwidget.h"
#include "core/file_utilities.h"
#include "main/main_account.h"

View File

@@ -98,20 +98,6 @@ std::map<int, const char*> BetaLogs() {
};
};
QString FormatVersionDisplay(int version) {
return QString::number(version / 1000000)
+ '.' + QString::number((version % 1000000) / 1000)
+ ((version % 1000)
? ('.' + QString::number(version % 1000))
: QString());
}
QString FormatVersionPrecise(int version) {
return QString::number(version / 1000000)
+ '.' + QString::number((version % 1000000) / 1000)
+ '.' + QString::number(version % 1000);
}
} // namespace
Changelogs::Changelogs(not_null<Main::Session*> session, int oldVersion)
@@ -216,4 +202,18 @@ void Changelogs::addBetaLog(int changeVersion, const char *changes) {
addLocalLog(log);
}
QString FormatVersionDisplay(int version) {
return QString::number(version / 1000000)
+ '.' + QString::number((version % 1000000) / 1000)
+ ((version % 1000)
? ('.' + QString::number(version % 1000))
: QString());
}
QString FormatVersionPrecise(int version) {
return QString::number(version / 1000000)
+ '.' + QString::number((version % 1000000) / 1000)
+ '.' + QString::number(version % 1000);
}
} // namespace Core

View File

@@ -15,6 +15,9 @@ class Session;
namespace Core {
[[nodiscard]] QString FormatVersionDisplay(int version);
[[nodiscard]] QString FormatVersionPrecise(int version);
class Changelogs : public base::has_weak_ptr, private base::Subscriber {
public:
Changelogs(not_null<Main::Session*> session, int oldVersion);

View File

@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "window/window_session_controller.h"
#include "facades.h"
#include "app.h"
@@ -112,7 +113,11 @@ void MentionClickHandler::onClick(ClickContext context) const {
const auto button = context.button;
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
if (const auto m = App::main()) { // multi good
m->openPeerByName(_tag.mid(1), ShowAtProfileMsgId);
using Info = Window::SessionNavigation::PeerByLinkInfo;
m->controller()->showPeerByLink(Info{
.usernameOrId = _tag.mid(1),
.messageId = ShowAtProfileMsgId
});
}
}
}

View File

@@ -157,7 +157,7 @@ CloudPasswordResult ComputeCheck(
}
bytes::vector ComputeHash(
std::nullopt_t,
v::null_t,
bytes::const_span password) {
Unexpected("Bad secure secret algorithm.");
}
@@ -199,10 +199,10 @@ CloudPasswordCheckRequest ParseCloudPasswordCheckRequest(
}
CloudPasswordAlgo ValidateNewCloudPasswordAlgo(CloudPasswordAlgo &&parsed) {
if (!parsed.is<CloudPasswordAlgoModPow>()) {
return std::nullopt;
if (!v::is<CloudPasswordAlgoModPow>(parsed)) {
return v::null;
}
auto &value = parsed.get_unchecked<CloudPasswordAlgoModPow>();
auto &value = v::get<CloudPasswordAlgoModPow>(parsed);
const auto already = value.salt1.size();
value.salt1.resize(already + kAdditionalSalt);
bytes::set_random(bytes::make_span(value.salt1).subspan(already));
@@ -210,13 +210,13 @@ CloudPasswordAlgo ValidateNewCloudPasswordAlgo(CloudPasswordAlgo &&parsed) {
}
MTPPasswordKdfAlgo PrepareCloudPasswordAlgo(const CloudPasswordAlgo &data) {
return data.match([](const CloudPasswordAlgoModPow &data) {
return v::match(data, [](const CloudPasswordAlgoModPow &data) {
return MTP_passwordKdfAlgoModPow(
MTP_bytes(data.salt1),
MTP_bytes(data.salt2),
MTP_int(data.g),
MTP_bytes(data.p));
}, [](std::nullopt_t) {
}, [](v::null_t) {
return MTP_passwordKdfAlgoUnknown();
});
}
@@ -228,9 +228,9 @@ CloudPasswordResult::operator bool() const {
bytes::vector ComputeCloudPasswordHash(
const CloudPasswordAlgo &algo,
bytes::const_span password) {
return algo.match([&](const CloudPasswordAlgoModPow &data) {
return v::match(algo, [&](const CloudPasswordAlgoModPow &data) {
return ComputeHash(data, password);
}, [](std::nullopt_t) -> bytes::vector {
}, [](v::null_t) -> bytes::vector {
Unexpected("Bad cloud password algorithm.");
});
}
@@ -238,9 +238,9 @@ bytes::vector ComputeCloudPasswordHash(
CloudPasswordDigest ComputeCloudPasswordDigest(
const CloudPasswordAlgo &algo,
bytes::const_span password) {
return algo.match([&](const CloudPasswordAlgoModPow &data) {
return v::match(algo, [&](const CloudPasswordAlgoModPow &data) {
return ComputeDigest(data, password);
}, [](std::nullopt_t) -> CloudPasswordDigest {
}, [](v::null_t) -> CloudPasswordDigest {
Unexpected("Bad cloud password algorithm.");
});
}
@@ -248,9 +248,9 @@ CloudPasswordDigest ComputeCloudPasswordDigest(
CloudPasswordResult ComputeCloudPasswordCheck(
const CloudPasswordCheckRequest &request,
bytes::const_span hash) {
return request.algo.match([&](const CloudPasswordAlgoModPow &data) {
return v::match(request.algo, [&](const CloudPasswordAlgoModPow &data) {
return ComputeCheck(request, data, hash);
}, [](std::nullopt_t) -> CloudPasswordResult {
}, [](v::null_t) -> CloudPasswordResult {
Unexpected("Bad cloud password algorithm.");
});
}
@@ -270,10 +270,10 @@ SecureSecretAlgo ParseSecureSecretAlgo(
}
SecureSecretAlgo ValidateNewSecureSecretAlgo(SecureSecretAlgo &&parsed) {
if (!parsed.is<SecureSecretAlgoPBKDF2>()) {
return std::nullopt;
if (!v::is<SecureSecretAlgoPBKDF2>(parsed)) {
return v::null;
}
auto &value = parsed.get_unchecked<SecureSecretAlgoPBKDF2>();
auto &value = v::get<SecureSecretAlgoPBKDF2>(parsed);
const auto already = value.salt.size();
value.salt.resize(already + kAdditionalSalt);
bytes::set_random(bytes::make_span(value.salt).subspan(already));
@@ -282,12 +282,12 @@ SecureSecretAlgo ValidateNewSecureSecretAlgo(SecureSecretAlgo &&parsed) {
MTPSecurePasswordKdfAlgo PrepareSecureSecretAlgo(
const SecureSecretAlgo &data) {
return data.match([](const SecureSecretAlgoPBKDF2 &data) {
return v::match(data, [](const SecureSecretAlgoPBKDF2 &data) {
return MTP_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(
MTP_bytes(data.salt));
}, [](const SecureSecretAlgoSHA512 &data) {
return MTP_securePasswordKdfAlgoSHA512(MTP_bytes(data.salt));
}, [](std::nullopt_t) {
}, [](v::null_t) {
return MTP_securePasswordKdfAlgoUnknown();
});
}
@@ -295,7 +295,7 @@ MTPSecurePasswordKdfAlgo PrepareSecureSecretAlgo(
bytes::vector ComputeSecureSecretHash(
const SecureSecretAlgo &algo,
bytes::const_span password) {
return algo.match([&](const auto &data) {
return v::match(algo, [&](const auto &data) {
return ComputeHash(data, password);
});
}
@@ -317,4 +317,4 @@ CloudPasswordState ParseCloudPasswordState(
return result;
}
} // namespace Core
} // namespace Core

View File

@@ -31,7 +31,7 @@ inline bool operator==(
&& (a.p == b.p);
}
using CloudPasswordAlgo = base::optional_variant<CloudPasswordAlgoModPow>;
using CloudPasswordAlgo = std::variant<v::null_t, CloudPasswordAlgoModPow>;
CloudPasswordAlgo ParseCloudPasswordAlgo(const MTPPasswordKdfAlgo &data);
CloudPasswordAlgo ValidateNewCloudPasswordAlgo(CloudPasswordAlgo &&parsed);
@@ -43,7 +43,7 @@ struct CloudPasswordCheckRequest {
CloudPasswordAlgo algo;
explicit operator bool() const {
return !!algo;
return !v::is_null(algo);
}
};
@@ -106,7 +106,8 @@ inline bool operator==(
return (a.salt == b.salt);
}
using SecureSecretAlgo = base::optional_variant<
using SecureSecretAlgo = std::variant<
v::null_t,
SecureSecretAlgoSHA512,
SecureSecretAlgoPBKDF2>;

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