Compare commits

...

290 Commits

Author SHA1 Message Date
John Preston
31f15a2f09 Beta version 3.1.10.
- Native support for M1 on macOS.
2021-10-29 16:11:15 +04:00
John Preston
45b5e1241c Show device model in sessions list on Windows / Linux. 2021-10-29 16:11:15 +04:00
John Preston
43d42b54f8 Closed alpha version 3.1.9.5: Separate macOS updates. 2021-10-29 16:10:07 +04:00
John Preston
090277d7a1 Upload a separate macOS ARM update. 2021-10-29 16:10:07 +04:00
John Preston
766b393295 On macOS build autoupdates single-arch + universal setup. 2021-10-29 16:10:07 +04:00
John Preston
b2d647b579 Add support for fcitx-qt5 on Qt 6.2. 2021-10-29 16:10:07 +04:00
John Preston
1ed6844247 Use Qt resources from a file on macOS. 2021-10-29 16:10:07 +04:00
John Preston
5276e5b4ae Build minidump_stackwalk separately.
On macOS gyp is no longer required for non-official builds.
2021-10-29 16:10:07 +04:00
John Preston
6587f89db1 Update Breakpad to the latest commit. 2021-10-29 16:10:07 +04:00
John Preston
fb262b265b Link a single crashpad_client library. 2021-10-29 16:10:07 +04:00
John Preston
95074ef304 Closed alpha version 3.1.9.2 for macOS. 2021-10-29 16:10:07 +04:00
John Preston
4ac93806aa Fix emoji in the input fields on macOS with Qt 6.2. 2021-10-29 16:10:07 +04:00
John Preston
92b3149cdd Pass CMAKE_OSX_ARCHITECTURES from command line to configure. 2021-10-29 16:10:07 +04:00
John Preston
98c87d4a16 Dump symbols for both macOS builds. 2021-10-29 16:10:07 +04:00
John Preston
9a93d5811a Closed alpha version 3.1.9.1: Universal 2 macOS build. 2021-10-29 16:10:07 +04:00
John Preston
759e3270cc Fix popup menu transparency on macOS with Qt 6.2. 2021-10-29 16:10:07 +04:00
John Preston
746b72166f Fix main window drag-by-title on macOS with Qt 6.2. 2021-10-29 16:10:07 +04:00
John Preston
0292df12ef Working Universal 2 build. 2021-10-29 16:10:07 +04:00
John Preston
1e86c07505 Build FFMpeg as Universal 2 binaries. 2021-10-29 16:10:07 +04:00
John Preston
47b6956be9 Update crashpad to a new revision. 2021-10-29 16:10:07 +04:00
John Preston
df8708ef1e Build some dependencies as Universal 2 binaries. 2021-10-29 16:10:07 +04:00
John Preston
20c0be0df6 Use python from a correct folder. 2021-10-29 16:10:07 +04:00
23rd
cefdc29a7f Fixed release build of Breakpad on clean macOS. 2021-10-29 16:10:07 +04:00
23rd
70e9b4a332 Moved type of call id to alias. 2021-10-29 16:10:07 +04:00
23rd
08939ac51d Fixed display of edit badge in albums. 2021-10-29 16:10:07 +04:00
23rd
b5d9947408 Slightly improved code style in Calls:Call. 2021-10-29 16:10:07 +04:00
23rd
78f0cf908e Moved RateCallBox to td_ui. 2021-10-29 16:10:07 +04:00
23rd
93ae5e71f7 Guarded timers for online processing in touchbar's PinnedDialogButton. 2021-10-29 16:10:07 +04:00
Ilya Fedin
b8b268c7cc Add build architecture to version on other systems with non-x86_64 2021-10-29 16:02:41 +04:00
Ilya Fedin
c991bbc7e3 Reduce obtrusiveness of the lock bot 2021-10-29 16:02:15 +04:00
Ilya Fedin
45bbe33929 Multiple scale values in UI by device pixel ratio on non-Mac
To avoid confusion
2021-10-25 19:55:11 +04:00
John Preston
5aaa72e8cd Fix crash in scheduled emoji interactions.
Fixes #17093.
2021-10-25 09:43:22 +04:00
John Preston
57345cec3b Discard incoming calls by ring_timeout (1.5 minutes). 2021-10-25 09:43:12 +04:00
John Preston
fba17a8c25 Update description in lib/xdg/telegramdesktop.appdata.xml.in. 2021-10-25 09:23:36 +04:00
Ilya Fedin
70147922ae Re-enable kwayland with Qt 6 2021-10-25 08:59:43 +04:00
Ilya Fedin
44cc3c7809 Update submodules 2021-10-24 20:01:55 +04:00
Ilya Fedin
c50a5db277 Restore dbusmenu-qt dependent functionality with Qt 6 2021-10-24 20:01:55 +04:00
John Preston
389ea2af83 Fix compilation error on Linux. 2021-10-22 18:34:59 +04:00
John Preston
4cf9bf18e9 Fix clearing of macOS native notifications. 2021-10-21 23:37:14 +04:00
John Preston
7bc4b2c595 Add StickersSet::thumbnailBigFileBaseCacheKey. 2021-10-21 23:01:14 +04:00
John Preston
9075489c18 Use last history item date for jump-to-date. 2021-10-21 23:01:13 +04:00
John Preston
d361f5c6b0 Hide native notifications of deleted messages. 2021-10-21 23:01:13 +04:00
John Preston
1f95e00793 Fix "Copy Selected Text" appearing outside of selection. 2021-10-21 22:59:49 +04:00
John Preston
3d8899b9dc Update tg_owt revision. 2021-10-21 22:53:12 +04:00
John Preston
dba9aa30f7 Fix build action on macOS. 2021-10-21 21:01:33 +04:00
John Preston
3626943fc9 Use Qt 6.2 build on macOS GitHub action. 2021-10-21 20:20:35 +04:00
John Preston
1f6a9ab556 Fix prepare libraries on macOS with Qt 6.2. 2021-10-21 20:19:56 +04:00
John Preston
f7085b40b1 Support building macOS version with Qt 6.2. 2021-10-21 19:49:48 +04:00
Ilya Fedin
7222bc63f7 Update MozJPEG 2021-10-21 19:31:22 +04:00
Ilya Fedin
3dacbc6bf6 Ignore changes to Dockerfile on mac 2021-10-21 19:31:22 +04:00
Ilya Fedin
9dfa29ff0f Avoid using scl binary since it breaks conditions 2021-10-21 18:31:08 +04:00
Ilya Fedin
a1e67b6177 Fix failing on exit code check 2021-10-21 15:51:36 +04:00
Ilya Fedin
03a687c200 Adapt Dockerfile for Qt 6 2021-10-21 15:43:59 +04:00
Ilya Fedin
847c01d605 Add Qt 6 support
Tested only on Linux so far
2021-10-21 13:15:00 +04:00
23rd
ea10cf5758 Moved api polls processing to separated file. 2021-10-20 22:56:19 +03:00
23rd
159beb138a Moved api peer photo processing to separated file.
Removed MainWidget::deletePhotoLayer.
2021-10-20 22:56:19 +03:00
23rd
36d6682122 Improved code style in ChangePhoneBox. 2021-10-20 04:06:17 +03:00
23rd
25f6bea66e Moved ConfirmPhoneBox to td_ui. 2021-10-19 06:34:28 +03:00
23rd
80461bd9fe Moved ConfirmBox to Ui namespace. 2021-10-19 06:34:27 +03:00
23rd
6148edbc7d Moved ConfirmBox to td_ui. 2021-10-19 06:34:27 +03:00
23rd
3fa529d858 Extracted MaxInviteBox to separated file. 2021-10-19 06:34:27 +03:00
23rd
9117b3cdfa Extracted DeleteMessagesBox to separated file. 2021-10-19 06:34:27 +03:00
23rd
d4fe5f7a83 Extracted PinMessageBox to separated file. 2021-10-19 06:34:27 +03:00
23rd
fa6725c54a Extracted api code from ConfirmPhoneBox to separated file. 2021-10-19 06:34:27 +03:00
23rd
f9976005f7 Moved ShowPhoneBannedError to separated file. 2021-10-19 06:34:27 +03:00
23rd
c6e1b14429 Added Window::SessionController to ChangePhoneBox. 2021-10-19 06:34:27 +03:00
23rd
30681e2e58 Moved widget sliders to td_ui. 2021-10-19 06:34:27 +03:00
23rd
c15ba7d23a Moved SentCodeField to td_ui. 2021-10-19 06:34:27 +03:00
23rd
94d5d20281 Simplified saving self bio. 2021-10-19 06:34:27 +03:00
23rd
b776308fd7 Moved some constants for peer editing to separated file. 2021-10-19 06:34:27 +03:00
23rd
2d37920a4c Improved code style in some peer boxes. 2021-10-19 06:34:27 +03:00
23rd
ee05e0af06 Improved code style in UsernameBox. 2021-10-19 06:34:27 +03:00
23rd
2efd735243 Removed static storing of passport config. 2021-10-14 17:41:52 +03:00
John Preston
adb0a9b6f0 Fix document filenames.
Regression was introduced in 2b11e45692.
2021-10-11 22:58:24 +04:00
CoderTimZ
c9e24c2283 Display dates with the system date format 2021-10-11 21:56:29 +04:00
John Preston
041c922451 Add non-MTP ParseWebPageType. 2021-10-11 21:54:07 +04:00
John Preston
01c1096c62 Save Data::Session* in GameData. 2021-10-11 21:53:18 +04:00
John Preston
2b11e45692 Add DocumentData::setFileName. 2021-10-11 21:52:49 +04:00
23rd
6163e922b3 Added view button to webpages. 2021-10-10 19:30:38 +03:00
John Preston
1613495425 Version 3.1.9.
- Fix crash in chat closing while scrolling (macOS only).
2021-10-08 22:37:36 +04:00
23rd
455c7280a4 Fixed possible crash in scroll of empty HistoryWidget. 2021-10-08 19:10:39 +03:00
John Preston
746f8d835d Version 3.1.8.
- Show small media previews in chats list.
- Show media album previews and caption text in chats list.
- Add "Quick Reply" and "Mark as Read" to native Windows notifications.
2021-10-08 13:51:22 +04:00
John Preston
d66e9a1b00 Remove -pie linker flag.
See https://gitlab.gnome.org/GNOME/nautilus/-/issues/1601
2021-10-08 13:50:27 +04:00
John Preston
8cca75da5c Handle foreign instance in COM toast activator. 2021-10-08 13:46:52 +04:00
John Preston
8d0ff1b61d Try setting current window as foreground on activate. 2021-10-08 12:20:24 +04:00
John Preston
dd856b9e4a Use real QWindow for taskbar icon hider.
Fixes #17081.
2021-10-08 12:19:41 +04:00
23rd
eb5ba12ba3 Fixed ability to copy original caption in admin log.
Fixed #17076.
2021-10-08 10:39:36 +04:00
23rd
e2c5995a2e Fixed timestamp highlighting in albums.
Fixed #17078.
2021-10-08 10:39:36 +04:00
23rd
ef10bb2bd6 Fixed editing caption of album from context menu.
Fixed #17077.
2021-10-08 10:39:36 +04:00
23rd
64aa5480ad Fixed display edited badge in scheduled albums.
Moved hideEditedBadge from HistoryMessage to HistoryItem.
2021-10-08 10:39:36 +04:00
23rd
816f422e21 Removed MTP* from applying message edition.
Fixed #17073.
2021-10-08 10:39:36 +04:00
23rd
6c0dccd9ff Fixed replying in replies by double click.
Fixed #16645.
2021-10-08 10:39:36 +04:00
23rd
c2b505b78c Added ability to open specific post from sponsored messages. 2021-10-08 10:39:27 +04:00
23rd
d8fb5be9b5 Moved opening peer from PeerClickHandler to SessionController. 2021-10-07 23:32:10 +03:00
23rd
51b259fdea Updated ad description. 2021-10-07 23:32:10 +03:00
John Preston
d532b65d1c Don't use MTP* for replies data. 2021-10-07 22:57:44 +04:00
John Preston
bef35b9bc3 Don't use MTP* in call and invoice media data. 2021-10-07 18:22:28 +04:00
John Preston
ae261fcede Beta version 3.1.7.
- Fix channel message views and comments counter updates.
- Sponsored messages support.
- Crash fix.
2021-10-07 11:42:24 +04:00
John Preston
c04cdff7f7 Disable group call logs to console. 2021-10-07 11:42:24 +04:00
John Preston
466aa5a14d Fix view button style. 2021-10-07 11:38:07 +04:00
John Preston
4aac633413 Fix views increment.
Regression was introduced in 21aa1f49d7.

Fixes #17069.
2021-10-07 11:29:30 +04:00
23rd
ad328d35a2 Added box for ad description. 2021-10-07 11:09:09 +04:00
23rd
c5140f34a7 Added view button to sponsored messages. 2021-10-07 11:09:09 +04:00
23rd
419f6345b3 Added sponsored messages to HistoryWidget. 2021-10-07 11:09:09 +04:00
23rd
c2c53df886 Added new Ui::СontinuousScroll. 2021-10-07 11:09:09 +04:00
23rd
b3f73bb6a9 Added badge for sponsored messages. 2021-10-07 11:09:08 +04:00
23rd
eda5cd47ad Added manager of sponsored messages. 2021-10-07 11:09:08 +04:00
John Preston
0c906a5e6d Fix crash in local changelog messages. 2021-10-07 10:58:24 +04:00
John Preston
352768053d Beta version 3.1.6: Fix build on Linux. 2021-10-06 21:07:18 +04:00
John Preston
79b1cec4f3 Beta version 3.1.6: Remove -z,all from linker flags on Linux.
I hope it fixes #17037.
2021-10-06 20:37:39 +04:00
John Preston
8d09190439 Build ffmpeg without --disable-alsa/iconv on Linux. 2021-10-06 20:37:30 +04:00
John Preston
5cd0a3719e Beta version 3.1.6: Detach FastReply from MarkAsRead. 2021-10-06 19:24:30 +04:00
John Preston
8b7cd4a0c7 Beta version 3.1.6: Fix crash on old Windows 10 versions. 2021-10-06 17:36:30 +04:00
John Preston
937c2d3dce Beta version 3.1.6: Update patches revision. 2021-10-06 13:44:28 +04:00
23rd
1fa5d273cc Fixed scroll in Dialogs::Widget.
Regression was introduced in cb8f49aea0.
2021-10-06 13:40:26 +04:00
John Preston
24fa3dbf8f Beta version 3.1.6: Fix build on macOS. 2021-10-06 11:10:06 +04:00
John Preston
c9b782fd63 Beta version 3.1.6.
- Show small media previews in chats list.
- Show media album previews and caption text in chats list.
- Add "Quick Reply" and "Mark as Read" to native Windows notifications.
2021-10-06 11:07:38 +04:00
John Preston
e7cf560da0 Handle toast activations by COM activator. 2021-10-06 11:02:57 +04:00
John Preston
86e07518ad Fix clearing notifications from Action Center.
Regression was introduced in 997913be25.
2021-10-05 16:53:36 +04:00
John Preston
8c71d03959 Add reply from Windows native notifications. 2021-10-05 16:52:46 +04:00
John Preston
967e86f4ab Rewrite Windows native notifications using C++/WinRT. 2021-10-05 12:09:15 +04:00
John Preston
730412fefe Load albums of last chat messages. 2021-10-04 23:47:33 +04:00
John Preston
576883ddc8 Make mini preview radius 2px. 2021-10-04 23:47:33 +04:00
John Preston
992d636680 Generate album mini previews with up-to-three images. 2021-10-04 23:47:33 +04:00
John Preston
8cdd2f113f Add play icon to video mini previews. 2021-10-04 23:47:33 +04:00
John Preston
d5f935b73d Put mini-previews after sender name. 2021-10-04 23:47:33 +04:00
John Preston
84f561b251 Don't use MTP* in the image editor. 2021-10-04 23:47:33 +04:00
John Preston
21ac2b8f3a Don't use MTP* for reply markup data. 2021-10-04 23:47:30 +04:00
John Preston
1790828b01 Dump symbols from the binary instead of dSYM.
For some reason dump_syms from dSYM now fails with an error:

Telegram.app.dSYM/Contents/Resources/DWARF/Telegram:
the section '__text' in segment '__TEXT' claims its contents lie outside the segment's contents
2021-10-04 23:45:21 +04:00
John Preston
792b9090a7 Generate mini-previews for photos and files. 2021-10-04 23:45:21 +04:00
John Preston
8c21fad642 Move preview paint to Dialogs::Ui::MessageView. 2021-10-04 23:45:21 +04:00
John Preston
5136cc3c9c Rename Dialogs::Layout to Dialogs::Ui. 2021-10-04 23:45:21 +04:00
John Preston
b78b27f517 Move dialogs_layout to dialogs/ui/. 2021-10-04 23:45:21 +04:00
John Preston
85760ea92c Fix repeated attempt to transfer ownership.
Fixes #8570.
2021-10-04 23:45:21 +04:00
Ilya Fedin
c2212c719e Inform Qt about taskbar hider
This allows the feature to work without patching Qt
2021-10-04 23:23:50 +04:00
GitHub Action
fc8a0d0efd Update User-Agent for DNS to Chrome 94.0.4606.61. 2021-10-04 23:23:20 +04:00
23rd
c052c37621 Fixed build for non-Windows. 2021-09-30 21:04:43 +03:00
23rd
21f7cec781 Fixed build for macOS. 2021-09-30 21:21:07 +04:00
23rd
64af456d29 Fixed build for macOS. 2021-09-30 21:16:45 +04:00
John Preston
7751c4ac1f Port PQ factorization from TDLib. 2021-09-30 21:14:00 +04:00
23rd
ececdcb9c0 Removed Q_SLOTS from HistoryInner. 2021-09-30 18:45:38 +03:00
23rd
cb8f49aea0 Removed Q_OBJECT from ScrollArea. 2021-09-30 18:45:38 +03:00
23rd
e3ef7d6631 Removed MainWidget::highlightStartTime. 2021-09-30 18:45:38 +03:00
23rd
21aa1f49d7 Moved views increment scheduler from MainWidget to separate file. 2021-09-30 18:45:38 +03:00
John Preston
51e80170e2 Always clear passcode lock widget on reset.
Fixes #17016.
2021-09-30 19:37:42 +04:00
John Preston
b2526ab7f6 Make sure special MsgId-s are always outside ServerMaxMsgId range. 2021-09-30 19:31:03 +04:00
John Preston
e220447bdd Put the "N Seen" context menu item always first. 2021-09-30 15:36:14 +04:00
John Preston
ead695b101 Don't pass wide fake MsgId through MTPMessage. 2021-09-30 15:30:39 +04:00
John Preston
4ea72f8f89 Don't add "Change colors" to profile menu. 2021-09-30 15:30:29 +04:00
John Preston
4ef550da9b Hide webview while showing a box in payments. 2021-09-30 14:53:18 +04:00
John Preston
1e660fc2a2 Allocate 64 bits for message ids. 2021-09-30 13:49:37 +04:00
Ilya Fedin
6adf791b3b Update cmake_helpers 2021-09-29 09:04:23 +04:00
Ilya Fedin
d2a41a42e0 Move applicationDidFinishLaunching code to init
This should make the Qt patch catching the event unneeded
2021-09-29 09:04:23 +04:00
John Preston
315549b5f8 Beta version 3.1.5: Fix build on Linux. 2021-09-28 23:48:37 +04:00
John Preston
fd4a543bab Beta version 3.1.5: Fix theme change UI on Retina screens. 2021-09-28 22:27:41 +04:00
John Preston
d525e56053 Beta version 3.1.5: Fix build on Linux. 2021-09-28 22:08:28 +04:00
John Preston
dab5d1f994 Beta version 3.1.5.
- Choose one of 8 new preset themes for any individual private chat.
- Click on '...' menu > 'Change Colors' to pick a theme.
- Both chat participants will see the same theme
in that chat – on all their devices.
- Each new theme features colorful gradient message bubbles,
beautifully animated backgrounds and unique background patterns.
- All chat themes have day and night versions
and will follow your overall dark mode settings.
- Implement main window rounded corners on Windows 11.
- Fix audio capture from AirPods on macOS.
2021-09-28 22:00:51 +04:00
23rd
de3b52425c Removed unused HistoryInner::setFirstLoading. 2021-09-28 21:14:33 +04:00
John Preston
844fd58a97 Support Windows 11 rounded corners and themeable title bar. 2021-09-28 21:11:35 +04:00
John Preston
de2bad51d3 Scroll to currently selected theme. 2021-09-28 19:27:41 +04:00
John Preston
1424ea3540 Allow scrolling themes list. 2021-09-28 19:27:41 +04:00
John Preston
a8efd0ef3d Show chosen element in custom theme selector. 2021-09-28 19:27:41 +04:00
John Preston
1204e282d3 Fix attach icon in theme preview. 2021-09-28 19:27:41 +04:00
John Preston
6588242793 Prepare correct custom chat theme preview. 2021-09-28 19:27:41 +04:00
John Preston
b1ba9a42c6 Use Ui::GenerateBackgroundImage for preview in Settings. 2021-09-28 19:27:41 +04:00
John Preston
ab0d2bf9c6 Initial chat theme changing. 2021-09-28 19:27:41 +04:00
John Preston
80028e41f3 Bump OpenAL version in prepare script. 2021-09-28 19:25:39 +04:00
John Preston
2c581adc55 Add some hardening compiler / linker flags to dependencies. 2021-09-28 18:44:52 +04:00
John Preston
f0e8c1e325 Update lib_webview and docker patches revision. 2021-09-28 12:23:54 +04:00
John Preston
a2db9de4d7 Remove debug code. 2021-09-28 11:30:18 +04:00
John Preston
a228c62286 Fix "Nobody Viewed / Watched / Listened" seen state. 2021-09-27 18:51:50 +04:00
John Preston
37d940eca6 Beta version 3.1.4.
- Fix crash in network availability init.
- Fix assertion violation after a NaN-resulting std::round call.
2021-09-27 13:29:11 +04:00
John Preston
f7c24c54a1 Fix crash in failed network availability init. 2021-09-27 13:25:04 +04:00
John Preston
19ce1edc16 Use base::SafeRound instead of std::round.
Previous assertion violations because of NaN from std::round were
in video streaming, see commits 27d58ba07b, 8f5830d520.

Now the crashes happened in the ConvertScale() call from a background
thread when preparing an image from clipboard for sending to a chat.
2021-09-27 12:13:57 +04:00
John Preston
21b10cebe0 Beta version 3.1.3.
- Fix illegal instruction crash in opus encoder.
2021-09-27 10:28:29 +04:00
John Preston
50435f7783 Allow creating links with Ip addresses. 2021-09-27 10:28:29 +04:00
Ilya Fedin
1b789de4f4 Cherry-pick a opus fix for detecting CPU instructions on Windows 2021-09-27 08:50:51 +04:00
John Preston
a50310f0c1 Beta version 3.1.2 (Windows only).
- Control video in fullscreen mode using arrows and numbers.
- Open locations in browser if default Bing Maps is not installed.
- Reconnect without timeout when network availability changes.
- Crash fixes.
2021-09-26 17:24:09 +04:00
John Preston
eb02a7861a Add modern C++/WinRT headers path to Telegram project. 2021-09-26 17:20:22 +04:00
John Preston
8759ca4577 Rewrite bingmaps check to C++/WinRT. 2021-09-26 17:17:57 +04:00
Hermesis
d5c6d9a231 Open map in browser if default "bingmaps:" handler is not found 2021-09-26 17:16:38 +04:00
John Preston
63f179e93e Add Windows network reachability backend. 2021-09-26 14:31:54 +04:00
Hermesis
cfcc1b1ce7 Control video in fullscreen mode using arrows and numbers 2021-09-26 14:07:02 +04:00
John Preston
da1945d0ca Add some more information for an assertion violation. 2021-09-25 22:49:51 +04:00
John Preston
12252ef1aa One more attempt of OpenGL context loss crash fix. 2021-09-25 22:39:49 +04:00
John Preston
1eef94e8d9 Fix possible crash in delayed typing updates. 2021-09-25 22:39:11 +04:00
Ilya Fedin
0984e631fa Use opus built with cmake on Windows 2021-09-25 15:35:32 +04:00
John Preston
ec064a904d Version 3.1.1.
- Crash fixes.
2021-09-24 08:47:02 +04:00
John Preston
b47692e920 Update patches revision. 2021-09-24 08:46:52 +04:00
John Preston
132f127f3f Add some assertions to debug a crash. 2021-09-24 08:44:22 +04:00
John Preston
5c44b851fe One more attempt to fix crashes on context loss. 2021-09-23 17:39:39 +04:00
John Preston
2f5bed2899 Skip "contact joined" toast if disabled in Settings.
The chats still appear (they are server-side), but skip the toast.
2021-09-23 17:37:29 +04:00
John Preston
cf76933352 Fix saving tray "Toggle notifications" on relaunch.
Fixes https://bugs.telegram.org/c/9509
2021-09-22 14:03:41 +04:00
John Preston
eaa4c5e5b1 Fix caching by making a fake dir ThirdParty/gyp. 2021-09-22 12:42:59 +04:00
John Preston
a4b5b6e370 Fix crash in lottie destructor.
Fixes #16985.
2021-09-21 21:29:59 +04:00
John Preston
c1be1ca4ae Add ./build/prepare/linux.sh which builds docker. 2021-09-21 18:11:24 +04:00
Ilya Fedin
b2df781b76 Fix icon for Quit Telegram taskbar item in snap 2021-09-20 15:09:42 +03:00
Ilya Fedin
38815c1ca8 Backport fonts hook from snapcraft extensions 2021-09-20 11:40:03 +03:00
John Preston
2ec92f541c Version 3.1: Fix building Qt for Release. 2021-09-19 18:42:29 +03:00
John Preston
7ce8b42216 Version 3.1.
- Some animated emoji now have extra effects.
- Send 🎆 🎉, 🎈, :like:, 💩 or ❤️
to any private chat, then click on the animated emoji
to launch the effect.
- If your chat partner also has the chat open,
you will both see the effects.
- See the "Watching" status
when your chat partner is enjoying emoji effects with you.
- More interactive emoji coming soon.
- Right click one of your outgoing messages in small groups
to see who recently viewed it.
- To protect privacy, read receipts are only stored for 7 days
after the message was sent.
- Record video and audio from live broadcasts in your group or channel.
- Admins can start recording from the '...' menu.
- Choose between recording in portrait or landscape orientation.
- Finished recordings are sent to the admin's Saved Messages
and can be easily shared.
2021-09-19 18:21:31 +03:00
John Preston
17511749de Hold only last 5 custom themes in memory. 2021-09-19 18:15:46 +03:00
John Preston
4f6c7657bf Fix comments root pinned view disappearing. 2021-09-19 17:48:00 +03:00
John Preston
54085c70a4 Select light / dark custom theme based on dialogsBg value. 2021-09-19 17:39:29 +03:00
John Preston
e6c4b96c54 Just close SendFilesBox on last item remove.
Fixes https://bugs.telegram.org/c/2298
2021-09-19 17:36:31 +03:00
John Preston
b75221737a Make history-down button scale better. 2021-09-19 17:29:42 +03:00
John Preston
c336d725ea Fix media controls hiding workaround. 2021-09-19 16:55:55 +03:00
John Preston
d0fcc40d25 Don't play interactions in an inactive window. 2021-09-19 15:12:37 +03:00
John Preston
422bfd973b Don't play interactions without large emoji. 2021-09-19 15:12:20 +03:00
John Preston
d4db679ce8 Base custom chat themes on a separate light theme. 2021-09-19 14:43:09 +03:00
John Preston
2c7d8858c0 Base custom chat themes on a separate dark theme. 2021-09-19 14:43:09 +03:00
John Preston
155bbed3f4 Show correct video recording status. 2021-09-19 14:42:56 +03:00
John Preston
b1517c68fb Colorize outgoing selected state in light custom themes. 2021-09-19 14:42:51 +03:00
John Preston
d206ba7e1d Always underline links if color is the same as text. 2021-09-19 14:42:46 +03:00
John Preston
af100c2d13 Fix poll answer check in custom chat themes. 2021-09-19 14:40:43 +03:00
John Preston
1f25777929 Update watching emoji interaction phrase. 2021-09-19 14:40:43 +03:00
John Preston
a566405598 Show correct emoticon in interaction-seen status. 2021-09-19 14:40:43 +03:00
John Preston
b02967a44e Update tg_angle in prepare script. 2021-09-19 14:40:43 +03:00
John Preston
e0135e509d Allow exporting test chat themes. 2021-09-19 14:40:43 +03:00
John Preston
8274fddcbc Revert build-in Tinted theme.
Fixes #16969.
2021-09-19 14:40:43 +03:00
John Preston
82c45871c7 Fix build with Xcode. 2021-09-19 14:40:43 +03:00
23rd
2164caaab7 Fixed formatting of comments count. 2021-09-19 14:40:07 +03:00
Ilya Fedin
f4b162cbaf Update submodules 2021-09-19 13:22:38 +03:00
Ilya Fedin
4bc4584868 Build glibmm with LTO
In combination with https://github.com/desktop-app/cmake_helpers/pull/126 gets rid of unused glib symbols
2021-09-19 13:22:38 +03:00
John Preston
890a126423 Use shared provider for interaction animations. 2021-09-18 20:29:56 +03:00
John Preston
42cc24e167 Cache interactions in four cache keys. 2021-09-17 19:23:52 +03:00
John Preston
26b9146c32 Beta version 3.0.5: Try fixing messages skipping. 2021-09-17 14:27:34 +03:00
John Preston
ab6f5ae2ac Optimize bubble gradient background painting. 2021-09-17 13:22:33 +03:00
John Preston
559d4cf4da Update theme preview. 2021-09-17 13:22:33 +03:00
23rd
449f2d2f94 Migrated dependencies in Github CI for macOS. 2021-09-17 13:12:07 +03:00
John Preston
038f19d055 Beta version 3.0.5: Fix build on Linux. 2021-09-17 11:45:05 +03:00
John Preston
10d405aef4 Beta version 3.0.5: Add in-app changelog. 2021-09-17 10:57:42 +03:00
John Preston
efd4cceb19 Beta version 3.0.5.
- Add support for Emoji 13.1.
2021-09-17 10:56:16 +03:00
John Preston
822a3b69b5 Update libtgvoip. 2021-09-17 10:27:10 +03:00
John Preston
a632798383 Preserve alpha value in colorizer. 2021-09-17 10:25:37 +03:00
John Preston
cca08e3946 Fix crash in emoji interactions. 2021-09-17 10:25:36 +03:00
John Preston
4d267327b8 Update built-in Tinted dark theme. 2021-09-17 10:25:36 +03:00
John Preston
06798adce4 Accept skin colors and heart colors. 2021-09-17 10:25:36 +03:00
John Preston
34c0d97c54 Show emoji interaction seen status. 2021-09-17 10:25:36 +03:00
John Preston
4b7f594b0e Send emoji interaction seen requests. 2021-09-17 10:25:36 +03:00
John Preston
cfb43081c7 Play incoming interactions. 2021-09-17 10:25:36 +03:00
John Preston
703ea9aacd Apply scale keeping window center in place. 2021-09-17 10:25:36 +03:00
John Preston
de9b21e436 Correctly render interactions on inbox messages. 2021-09-17 10:25:36 +03:00
John Preston
73c0ea4b7d Don't mark as read when forwarding to scheduled. 2021-09-17 10:25:36 +03:00
John Preston
3e681e5449 Always force window frame inside screen geometry.
I hope this fixes #16934.
2021-09-17 10:25:36 +03:00
John Preston
bc2f96251f Limit amount of playing interactions. 2021-09-17 10:25:36 +03:00
John Preston
15f83892a1 Start emoji interactions playback. 2021-09-17 10:25:36 +03:00
John Preston
b6fafdd8f7 Limit emoji size to half of sticker size. 2021-09-17 10:25:36 +03:00
John Preston
139b9723d7 Accumulate and send emoji interactions. 2021-09-17 10:25:36 +03:00
John Preston
d152782115 Load and reload interaction stickers. 2021-09-17 10:25:36 +03:00
John Preston
35356a1736 Update API scheme. 2021-09-17 10:25:35 +03:00
Gleb Smirnoff
ef27670954 Fix compilation in presence of libzip installed.
When both minizip [1] and libzip [2] are present in the build
environment we have two <zip.h> includes. We are interested in
the minizip. Unfortunately, libzip usually installs its zip.h
straight into ${PREFIX}/include where lots of other headers reside.
We pick up ${PREFIX}/include into the include path with the
desktop-app::lib_base target, which is also dependency of
of tdesktop::td_* targets. To fix compilation in presence of
conflicting zip.h we need to put minizip's include directory
before ${PREFIX}/include, thus record its dependency before
all other dependencies that can bring desktop-app::lib_base.

[1] http://www.winimage.com/zLibDll/minizip.html
[2] https://libzip.org
2021-09-17 09:47:48 +03:00
Gleb Smirnoff
8cf9dc3319 Pull up to recent cmake_helpers and tg_owt that bring FreeBSD fixes. 2021-09-15 23:24:39 +03:00
Gleb Smirnoff
59f2f750b4 On FreeBSD the system malloc is jemalloc and non-portable
extensions are enabled including malloc_np.h.
2021-09-15 23:24:39 +03:00
John Preston
8069fdd873 Use base/random.h instead of openssl::RandomValue. 2021-09-15 13:42:22 +03:00
John Preston
52721847f4 Fix outgoing voice message unread mark. 2021-09-15 13:42:22 +03:00
John Preston
e492bbb883 Fix delayed pattern-with-negative-intensity appearance. 2021-09-14 16:36:30 +03:00
John Preston
7f20cc7b44 Update emoji to 13.1. 2021-09-14 15:14:25 +03:00
John Preston
7fbce765c9 Apply uniform-color palette to webpage preview titles. 2021-09-14 15:14:12 +03:00
John Preston
f771ad8cb1 Beta version 3.0.4: Fix build for Windows. 2021-09-13 20:13:15 +03:00
John Preston
6a53fc7edc Beta version 3.0.4: Add some theme loading logging. 2021-09-13 20:09:55 +03:00
John Preston
889c3293e7 Fix PathShiftGradient colors with custom palettes. 2021-09-13 20:09:23 +03:00
23rd
fa4b7145f5 Added extra space to choosing sticker animation in left position. 2021-09-13 18:13:50 +03:00
23rd
a5be9d78d8 Fixed animation for grouped userpics in who read context menu item. 2021-09-13 18:13:50 +03:00
John Preston
21c562fcb7 Make "set_version.py" working with Python 2.7 as well. 2021-09-13 18:03:43 +03:00
John Preston
626c062bf0 Beta version 3.0.4.
- Fix a crash when joining video chat or live broadcast.
- Add a "Close to Taskbar" option when tray icon is disabled
(Windows and Linux).
2021-09-13 18:01:39 +03:00
Ilya Fedin
e92ae40ecb Implement close to taskbar option 2021-09-13 17:46:53 +03:00
John Preston
ce256161f1 Couple of crash fixes. 2021-09-13 17:39:17 +03:00
John Preston
3bf9a1c70b Build minidump_stackwalk as part of macOS prepare. 2021-09-13 16:59:10 +03:00
John Preston
3202a5f081 Fix prepare getch for macOS. 2021-09-13 16:50:44 +03:00
John Preston
e99f650eaa Change default autoupdate URL. 2021-09-13 16:33:31 +03:00
John Preston
c6097d3d11 Accept "livestream" and "videochat" link params. 2021-09-13 16:19:59 +03:00
John Preston
58b5b3deec Update main built-in palette values. 2021-09-13 15:40:02 +03:00
John Preston
5a63428093 Improve messages in preparep.py. 2021-09-13 15:39:44 +03:00
John Preston
0c42bca111 Ask before rebuilding in prepare.py. 2021-09-13 15:01:52 +03:00
John Preston
13bf089672 Update patches revision. 2021-09-13 14:21:56 +03:00
John Preston
f73264025d Fix a crash after joining broadcasts. 2021-09-13 14:21:01 +03:00
Ilya Fedin
0a6fb696a3 Build Qt without egl-extension-platform-wayland 2021-09-13 10:51:35 +03:00
John Preston
bc2e6c4fd1 Accept uppercase hex values in theme testing links. 2021-09-12 23:18:37 +03:00
John Preston
d822f8e9ff Improve colorizing more. 2021-09-12 23:16:23 +03:00
John Preston
86362875dd Beta version 3.0.3.
- Try fixing crashes in allocator on Linux.
2021-09-12 01:53:04 +03:00
John Preston
0a4a96d4cd Fix action build on Linux. 2021-09-12 01:39:28 +03:00
John Preston
1c33eee80a Update hime to 0.9.11. 2021-09-12 00:33:35 +03:00
Ilya Fedin
4f5558d28c Move new dependencies to the beginning of Dockerfile, update patches
The reason was to not to do a full rebuild, but looks like the cache is already cleaned
2021-09-12 00:25:01 +03:00
Ilya Fedin
3fbd68cff9 Don't link glib with DESKTOP_APP_DISABLE_DBUS_INTEGRATION 2021-09-12 00:12:13 +03:00
Ilya Fedin
ee8c6f68d7 Use clang to build jemalloc since it crashes with gcc 2021-09-12 00:11:47 +03:00
John Preston
8d4174afb5 Fix macOS build in GitHub Actions. 2021-09-11 20:13:18 +03:00
John Preston
9150cc77f9 Improve colorizing of custom themes. 2021-09-11 12:26:35 +03:00
John Preston
8d31769846 Fix build with Xcode. 2021-09-11 00:02:15 +03:00
John Preston
13c00949ed Add a simple way of testing color themes. 2021-09-10 22:29:30 +03:00
John Preston
c4d822ba02 Fix action build on Windows. 2021-09-10 16:19:07 +03:00
549 changed files with 14860 additions and 7386 deletions

View File

@@ -53,7 +53,7 @@ jobs:
defaults:
run:
shell: scl enable devtoolset-9 -- bash --noprofile --norc -eo pipefail {0}
shell: scl enable llvm-toolset-7.0 -- scl enable devtoolset-9 -- bash --noprofile --norc -eo pipefail {0}
strategy:
matrix:

View File

@@ -13,11 +13,3 @@ jobs:
github-token: ${{ github.token }}
issue-lock-inactive-days: 45
pr-lock-inactive-days: 45
issue-lock-comment: >
This issue has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.
pr-lock-comment: >
This pull request has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.

View File

@@ -13,7 +13,7 @@ on:
- '!.github/workflows/mac.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/build/docker/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
@@ -31,7 +31,7 @@ on:
- '!.github/workflows/mac.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/build/docker/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
@@ -49,19 +49,8 @@ jobs:
defines:
- ""
env:
MIN_MAC: "-mmacosx-version-min=10.12"
UNGUARDED: "-Werror=unguarded-availability-new"
GIT: "https://github.com"
MACOSX_DEPLOYMENT_TARGET: "10.12"
XZ: "xz-5.2.5"
QT: "5_15_2"
OPENSSL_VER: "1_1_1"
LIBICONV_VER: "libiconv-1.16"
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
MANUAL_CACHING: "2"
DOC_PATH: "docs/building-mac.md"
AUTO_CACHING: "1"
steps:
- name: Get repository name.
@@ -84,433 +73,23 @@ jobs:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
xcodebuild -version > CACHE_KEY.txt
echo $MIN_MAC >> CACHE_KEY.txt
echo $MANUAL_CACHING >> CACHE_KEY.txt
echo "$GITHUB_WORKSPACE" >> CACHE_KEY.txt
if [ "$AUTO_CACHING" == "1" ]; then
thisFile=$REPO_NAME/.github/workflows/mac.yml
echo `md5 -q $thisFile` >> CACHE_KEY.txt
fi
echo "CACHE_KEY=`md5 -q CACHE_KEY.txt`" >> $GITHUB_ENV
echo "$PWD/Libraries/depot_tools" >> $GITHUB_PATH
mkdir -p Libraries
cd Libraries
echo "LibrariesPath=`pwd`" >> $GITHUB_ENV
echo "PREFIX=`pwd`/local" >> $GITHUB_ENV
echo "QT_PREFIX=`pwd`/local/Qt-5.15.2" >> $GITHUB_ENV
curl -o tg_owt-version.json https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master
- name: Patches.
run: |
echo "Find necessary commit from doc."
checkoutCommit=$(grep -A 1 "cd patches" $REPO_NAME/$DOC_PATH | sed -n 2p)
cd $LibrariesPath
git clone $GIT/desktop-app/patches.git
cd Patches
eval $checkoutCommit
- name: XZ.
run: |
cd $LibrariesPath
wget https://tukaani.org/xz/$XZ.tar.gz
tar -xvzf $XZ.tar.gz
cd $XZ
CFLAGS="$MIN_MAC" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
make -j$(nproc)
make install
- name: Zlib.
run: |
cd $LibrariesPath
git clone $GIT/desktop-app/zlib.git
cd zlib
CFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
make -j$(nproc)
make install
- name: MozJPEG.
run: |
cd $LibrariesPath
git clone -b v4.0.1-rc2 $GIT/mozilla/mozjpeg.git
cd mozjpeg
cmake -B build . \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DWITH_JPEG8=ON \
-DPNG_SUPPORTED=OFF
cmake --build build -j$(nproc)
cmake --install build
- name: OpenSSL cache.
id: cache-openssl
- name: ThirdParty cache.
id: cache-third-party
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/openssl_${{ env.OPENSSL_VER }}
key: ${{ runner.OS }}-${{ env.OPENSSL_VER }}-${{ env.CACHE_KEY }}
- name: OpenSSL.
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
path: ThirdParty
key: ${{ runner.OS }}-third-party
git clone $GIT/openssl/openssl openssl
cd openssl
git checkout OpenSSL_"$OPENSSL_VER"-stable
./Configure \
--prefix=$PREFIX \
no-tests \
darwin64-x86_64-cc \
-static \
$MIN_MAC
make build_libs -j$(nproc)
SSL_DIR=$LibrariesPath/openssl_$OPENSSL_VER
mkdir -p $SSL_DIR/include
copyLib() {
cp $1.a $SSL_DIR/$1.a
}
copyLib libssl
copyLib libcrypto
cp -R include/. $SSL_DIR/include/
- name: Opus cache.
id: cache-opus
- name: Libraries cache.
id: cache-libs
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/opus-cache
key: ${{ runner.OS }}-opus-${{ env.CACHE_KEY }}
- name: Opus.
if: steps.cache-opus.outputs.cache-hit != 'true'
path: Libraries
key: ${{ runner.OS }}-libs
- name: Libraries.
run: |
cd $LibrariesPath
git clone $GIT/xiph/opus
cd opus
git checkout v1.3
./autogen.sh
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
make -j$(nproc)
make DESTDIR="$LibrariesPath/opus-cache" install
- name: Opus install.
run: |
cd $LibrariesPath
cp -R opus-cache/. /
- name: Rnnoise.
run: |
cd $LibrariesPath
git clone $GIT/desktop-app/rnnoise.git
mkdir -p rnnoise/out/Debug
cd rnnoise/out/Debug
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../..
ninja
- name: Libiconv cache.
id: cache-libiconv
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/libiconv-cache
key: ${{ runner.OS }}-${{ env.LIBICONV_VER }}-${{ env.CACHE_KEY }}
- name: Libiconv.
if: steps.cache-libiconv.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
wget https://ftp.gnu.org/pub/gnu/libiconv/"$LIBICONV_VER".tar.gz
tar -xvzf "$LIBICONV_VER".tar.gz
cd $LIBICONV_VER
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --enable-static --prefix=$PREFIX
make -j$(nproc)
make DESTDIR="$LibrariesPath/libiconv-cache" install
- name: Libiconv install.
run: |
cd $LibrariesPath
cp -R libiconv-cache/. /
- name: FFmpeg cache.
id: cache-ffmpeg
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/ffmpeg-cache
key: ${{ runner.OS }}-ffmpeg-${{ env.CACHE_KEY }}
- name: FFmpeg.
if: steps.cache-ffmpeg.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
git clone $GIT/FFmpeg/FFmpeg.git ffmpeg
cd ffmpeg
git checkout release/4.4
CFLAGS=`freetype-config --cflags`
LDFLAGS=`freetype-config --libs`
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:/usr/X11/lib/pkgconfig
./configure --prefix=$LibrariesPath/ffmpeg-cache \
--extra-cflags="$MIN_MAC $UNGUARDED" \
--extra-cxxflags="$MIN_MAC $UNGUARDED" \
--extra-ldflags="$MIN_MAC" \
--x86asmexe=`pwd`/macos_yasm_wrap.sh \
--enable-protocol=file \
--enable-libopus \
--disable-programs \
--disable-doc \
--disable-network \
--disable-everything \
--enable-hwaccel=h264_videotoolbox \
--enable-hwaccel=hevc_videotoolbox \
--enable-hwaccel=mpeg1_videotoolbox \
--enable-hwaccel=mpeg2_videotoolbox \
--enable-hwaccel=mpeg4_videotoolbox \
--enable-decoder=aac \
--enable-decoder=aac_at \
--enable-decoder=aac_fixed \
--enable-decoder=aac_latm \
--enable-decoder=aasc \
--enable-decoder=alac \
--enable-decoder=alac_at \
--enable-decoder=flac \
--enable-decoder=gif \
--enable-decoder=h264 \
--enable-decoder=hevc \
--enable-decoder=mp1 \
--enable-decoder=mp1float \
--enable-decoder=mp2 \
--enable-decoder=mp2float \
--enable-decoder=mp3 \
--enable-decoder=mp3adu \
--enable-decoder=mp3adufloat \
--enable-decoder=mp3float \
--enable-decoder=mp3on4 \
--enable-decoder=mp3on4float \
--enable-decoder=mpeg4 \
--enable-decoder=msmpeg4v2 \
--enable-decoder=msmpeg4v3 \
--enable-decoder=opus \
--enable-decoder=pcm_alaw \
--enable-decoder=pcm_alaw_at \
--enable-decoder=pcm_f32be \
--enable-decoder=pcm_f32le \
--enable-decoder=pcm_f64be \
--enable-decoder=pcm_f64le \
--enable-decoder=pcm_lxf \
--enable-decoder=pcm_mulaw \
--enable-decoder=pcm_mulaw_at \
--enable-decoder=pcm_s16be \
--enable-decoder=pcm_s16be_planar \
--enable-decoder=pcm_s16le \
--enable-decoder=pcm_s16le_planar \
--enable-decoder=pcm_s24be \
--enable-decoder=pcm_s24daud \
--enable-decoder=pcm_s24le \
--enable-decoder=pcm_s24le_planar \
--enable-decoder=pcm_s32be \
--enable-decoder=pcm_s32le \
--enable-decoder=pcm_s32le_planar \
--enable-decoder=pcm_s64be \
--enable-decoder=pcm_s64le \
--enable-decoder=pcm_s8 \
--enable-decoder=pcm_s8_planar \
--enable-decoder=pcm_u16be \
--enable-decoder=pcm_u16le \
--enable-decoder=pcm_u24be \
--enable-decoder=pcm_u24le \
--enable-decoder=pcm_u32be \
--enable-decoder=pcm_u32le \
--enable-decoder=pcm_u8 \
--enable-decoder=vorbis \
--enable-decoder=wavpack \
--enable-decoder=wmalossless \
--enable-decoder=wmapro \
--enable-decoder=wmav1 \
--enable-decoder=wmav2 \
--enable-decoder=wmavoice \
--enable-encoder=libopus \
--enable-parser=aac \
--enable-parser=aac_latm \
--enable-parser=flac \
--enable-parser=h264 \
--enable-parser=hevc \
--enable-parser=mpeg4video \
--enable-parser=mpegaudio \
--enable-parser=opus \
--enable-parser=vorbis \
--enable-demuxer=aac \
--enable-demuxer=flac \
--enable-demuxer=gif \
--enable-demuxer=h264 \
--enable-demuxer=hevc \
--enable-demuxer=m4v \
--enable-demuxer=mov \
--enable-demuxer=mp3 \
--enable-demuxer=ogg \
--enable-demuxer=wav \
--enable-muxer=ogg \
--enable-muxer=opus
make -j$(nproc)
make install
- name: FFmpeg install.
run: |
cd $LibrariesPath
# List of files from cmake/external/ffmpeg/CMakeLists.txt.
copyLib() {
mkdir -p ffmpeg/$1
\cp -fR ffmpeg-cache/lib/$1.a ffmpeg/$1/$1.a
}
copyLib libavformat
copyLib libavcodec
copyLib libswresample
copyLib libswscale
copyLib libavutil
cp -R ffmpeg-cache/. $PREFIX
cp -R ffmpeg-cache/include/. ffmpeg/
- name: OpenAL Soft.
run: |
cd $LibrariesPath
git clone --branch capture_with_webrtc $GIT/telegramdesktop/openal-soft.git
cd openal-soft/build
CFLAGS="$UNGUARDED" CPPFLAGS="$UNGUARDED" cmake \
-D CMAKE_INSTALL_PREFIX:PATH=$PREFIX \
-D ALSOFT_EXAMPLES=OFF \
-D LIBTYPE:STRING=STATIC \
-D CMAKE_OSX_DEPLOYMENT_TARGET:STRING=$MACOSX_DEPLOYMENT_TARGET ..
make -j$(nproc)
make install
- name: Crashpad cache.
id: cache-crashpad
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/crashpad
key: ${{ runner.OS }}-crashpad-${{ env.CACHE_KEY }}-${{ hashFiles('**/crashpad.diff') }}-${{ hashFiles('**/mini_chromium.diff') }}
- name: Crashpad.
if: steps.cache-crashpad.outputs.cache-hit != 'true'
run: |
cd Libraries
echo Install GYP for Crashpad.
git clone https://chromium.googlesource.com/external/gyp
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
cd gyp
git checkout 9f2a7bb1
git apply $LibrariesPath/patches/gyp.diff
./setup.py build
sudo ./setup.py install
cd $LibrariesPath
git clone https://chromium.googlesource.com/crashpad/crashpad.git
cd crashpad
git checkout feb3aa3923
git apply ../patches/crashpad.diff
cd third_party/mini_chromium
git clone https://chromium.googlesource.com/chromium/mini_chromium
cd mini_chromium
git checkout 7c5b0c1ab4
git apply ../../../../patches/mini_chromium.diff
cd ../../gtest
git clone https://chromium.googlesource.com/external/github.com/google/googletest gtest
cd gtest
git checkout d62d6c6556
cd ../../..
build/gyp_crashpad.py -Dmac_deployment_target=10.10
ninja -C out/Debug
- name: Qt 5.15.2 cache.
id: cache-qt
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/qt-cache
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_15_2/*') }}
- name: Use cached Qt 5.15.2.
if: steps.cache-qt.outputs.cache-hit == 'true'
run: |
cd $LibrariesPath
mv qt-cache Qt-5.15.2
mkdir -p $QT_PREFIX
mv -f Qt-5.15.2 "$(dirname "$QT_PREFIX")"/
- name: Qt 5.15.2 build.
if: steps.cache-qt.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
git clone git://code.qt.io/qt/qt5.git qt_$QT
cd qt_$QT
perl init-repository --module-subset=qtbase,qtimageformats,qtsvg
git checkout v5.15.2
git submodule update qtbase
git submodule update qtimageformats
git submodule update qtsvg
cd qtbase
find ../../patches/qtbase_$QT -type f -print0 | sort -z | xargs -0 git apply
cd ..
./configure \
-prefix "$QT_PREFIX" \
-debug \
-force-debug-info \
-opensource \
-confirm-license \
-static \
-opengl desktop \
-no-openssl \
-securetransport \
-nomake examples \
-nomake tests \
-platform macx-clang \
-I "$PREFIX/include" \
LIBJPEG_LIBS="$PREFIX/lib/libjpeg.a" \
ZLIB_LIBS="$PREFIX/lib/libz.a"
make -j$(nproc)
make install
make clean
cp -r $QT_PREFIX $LibrariesPath/qt-cache
- name: WebRTC cache.
id: cache-webrtc
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/tg_owt
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }}
- name: WebRTC.
if: steps.cache-webrtc.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
git clone --recursive $GIT/desktop-app/tg_owt.git
mkdir -p tg_owt/out/Debug
cd tg_owt/out/Debug
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DTG_OWT_SPECIAL_TARGET=mac \
-DTG_OWT_BUILD_AUDIO_BACKENDS=OFF \
-DTG_OWT_LIBJPEG_INCLUDE_PATH=$PREFIX/include \
-DTG_OWT_OPENSSL_INCLUDE_PATH=`pwd`/../../../openssl_$OPENSSL_VER/include \
-DTG_OWT_OPUS_INCLUDE_PATH=$PREFIX/include/opus \
-DTG_OWT_FFMPEG_INCLUDE_PATH=$PREFIX/include \
../..
ninja
# Cleanup.
cd $LibrariesPath/tg_owt
mv out/Debug/libtg_owt.a libtg_owt.a
rm -rf out
mkdir -p out/Debug
mv libtg_owt.a out/Debug/libtg_owt.a
./$REPO_NAME/Telegram/build/prepare/mac.sh skip-release silent skip-qt5 qt6
- name: Telegram Desktop build.
if: env.ONLY_CACHE == 'false'
@@ -530,6 +109,7 @@ jobs:
-D CMAKE_C_FLAGS="-Werror" \
-D CMAKE_CXX_FLAGS="-Werror" \
-D TDESKTOP_API_TEST=ON \
-D DESKTOP_APP_QT6=ON \
-D DESKTOP_APP_USE_PACKAGED=OFF \
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF \
$DEFINE

View File

@@ -58,7 +58,7 @@ jobs:
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
MANUAL_CACHING: "0"
DOC_PATH: "docs/building-win.md"
PREPARE_PATH: "Telegram/build/prepare/prepare.py"
AUTO_CACHING: "1"
defaults:
@@ -132,24 +132,12 @@ jobs:
working-directory: ${{ github.workspace }}
run: |
echo "Find necessary commit from doc."
checkoutCommit=$(grep -A 1 "cd patches" $REPO_NAME/$DOC_PATH | sed -n 2p)
checkoutCommit=$(grep -A 1 "cd patches" $REPO_NAME/$PREPARE_PATH | sed -n 2p)
cd $LibrariesPath
git clone $GIT/desktop-app/patches.git
cd Patches
cd patches
eval $checkoutCommit
- name: Find any version of Python 2.
shell: bash
run: |
echo "Find any version of Python 2."
p=`ls /c/hostedtoolcache/windows/python | grep "^2" | tail -1`
if [ -z "$p" ]; then
echo "Python 2 is not found."
exit 1
fi
echo "PY2=C:\\hostedtoolcache\\windows\\Python\\$p\\x64" >> $GITHUB_ENV
echo "Found $p."
- name: LZMA.
run: |
git clone %GIT%/telegramdesktop/lzma.git
@@ -161,28 +149,27 @@ jobs:
id: cache-openssl
uses: actions/cache@v2
with:
path: ${{ env.LibrariesPath }}/openssl_${{ env.OPENSSL_VER }}
path: ${{ env.LibrariesPath }}/openssl
key: ${{ runner.OS }}-${{ env.CACHE_KEY }}-${{ env.OPENSSL_VER }}
- name: OpenSSL.
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: |
git clone %GIT%/openssl/openssl.git openssl_%OPENSSL_VER%
cd openssl_%OPENSSL_VER%
git checkout OpenSSL_%OPENSSL_VER%-stable
git clone -b OpenSSL_%OPENSSL_VER%-stable %GIT%/openssl/openssl.git
cd openssl
perl Configure no-shared no-tests debug-VC-WIN32
nmake
mkdir out32.dbg
move libcrypto.lib out32.dbg
move libssl.lib out32.dbg
move ossl_static.pdb out32.dbg\ossl_static
mkdir out.dbg
move libcrypto.lib out.dbg
move libssl.lib out.dbg
move ossl_static.pdb out.dbg\ossl_static
nmake clean
move out32.dbg\ossl_static out32.dbg\ossl_static.pdb
move out.dbg\ossl_static out.dbg\ossl_static.pdb
perl Configure no-shared no-tests VC-WIN32
nmake
mkdir out32
move libcrypto.lib out32
move libssl.lib out32
move ossl_static.pdb out32
mkdir out
move libcrypto.lib out
move libssl.lib out
move ossl_static.pdb out
rmdir /S /Q test
rmdir /S /Q .git
@@ -198,7 +185,7 @@ jobs:
- name: MozJPEG.
shell: cmd
run: |
git clone -b v4.0.1-rc2 %GIT%/mozilla/mozjpeg.git
git clone -b v4.0.3 %GIT%/mozilla/mozjpeg.git
cd mozjpeg
cmake . ^
-G "Visual Studio 16 2019" ^
@@ -239,16 +226,17 @@ jobs:
GYP_MSVS_VERSION: 2019
if: steps.cache-breakpad.outputs.cache-hit != 'true'
run: |
git clone %GIT%/telegramdesktop/gyp.git
git clone https://chromium.googlesource.com/external/gyp
cd gyp
SET PATH=%PY2%;%cd%;%PATH%
git checkout tdesktop
SET PATH=%cd%;%PATH%
git checkout d6c5dd51dc
git apply ../patches/gyp.diff
cd %LibrariesPath%
git clone %GIT%/google/breakpad
git clone https://chromium.googlesource.com/breakpad/breakpad
cd breakpad
git checkout a1dbcdcb43
git checkout bc8fb886
git apply ../patches/breakpad.diff
cd src
git clone %GIT%/google/googletest testing
@@ -258,10 +246,9 @@ jobs:
ninja -C out/Debug common crash_generation_client exception_handler
ninja -C out/Release common crash_generation_client exception_handler
cd tools\windows\dump_syms
call gyp dump_syms.gyp
call vcvars32.bat
msbuild -m dump_syms.vcxproj /property:Configuration=Release
call gyp dump_syms.gyp --format=ninja
cd ..\..\..
ninja -C out/Release dump_syms
- name: Opus cache.
id: cache-opus
@@ -272,12 +259,17 @@ jobs:
- name: Opus.
if: steps.cache-opus.outputs.cache-hit != 'true'
run: |
git clone %GIT%/telegramdesktop/opus.git
git clone -b v1.3.1 %GIT%/xiph/opus.git
cd opus
git checkout tdesktop
cd win32\VS2015
msbuild -m opus.sln /property:Configuration=Debug /property:Platform="Win32"
msbuild -m opus.sln /property:Configuration=Release /property:Platform="Win32"
git cherry-pick 927de8453c
cmake -B out . ^
-A Win32 ^
-DCMAKE_INSTALL_PREFIX=%LibrariesPath%/local/opus ^
-DCMAKE_C_FLAGS_DEBUG="/MTd /Zi /Ob0 /Od /RTC1" ^
-DCMAKE_C_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"
cmake --build out --config Debug
cmake --build out --config Release
cmake --install out --config Release
- name: Rnnoise.
run: |
@@ -352,7 +344,7 @@ jobs:
for /r %%i in (..\..\patches\qtbase_%QT%\*) do git apply %%i
cd ..
SET SSL=%LibrariesPath%\openssl_%OPENSSL_VER%
SET SSL=%LibrariesPath%\openssl
SET SSL_LIBS=libcrypto.lib Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib
SET ANGLE=%LibrariesPath%\tg_angle
@@ -380,8 +372,8 @@ jobs:
QMAKE_LIBS_EGL_RELEASE="%ANGLE%\out\Release\tg_angle.lib %ZLIB%\ZlibStatReleaseWithoutAsm\zlibstat.lib %ANGLE_LIBS% Gdi32.lib User32.lib" ^
-openssl-linked ^
-I "%SSL%\include" ^
OPENSSL_LIBS_DEBUG="%SSL%\out32.dbg\libssl.lib %SSL%\out32.dbg\%SSL_LIBS%" ^
OPENSSL_LIBS_RELEASE="%SSL%\out32\libssl.lib %SSL%\out32\%SSL_LIBS%" ^
OPENSSL_LIBS_DEBUG="%SSL%\out.dbg\libssl.lib %SSL%\out.dbg\%SSL_LIBS%" ^
OPENSSL_LIBS_RELEASE="%SSL%\out\libssl.lib %SSL%\out\%SSL_LIBS%" ^
-I "%LibrariesPath%\mozjpeg" ^
LIBJPEG_LIBS_DEBUG="%LibrariesPath%\mozjpeg\Debug\jpeg-static.lib" ^
LIBJPEG_LIBS_RELEASE="%LibrariesPath%\mozjpeg\Release\jpeg-static.lib" ^
@@ -418,7 +410,7 @@ jobs:
-DTG_OWT_SPECIAL_TARGET=win ^
-DTG_OWT_BUILD_AUDIO_BACKENDS=OFF ^
-DTG_OWT_LIBJPEG_INCLUDE_PATH=%cd%/../../../mozjpeg ^
-DTG_OWT_OPENSSL_INCLUDE_PATH=%cd%/../../../openssl_%OPENSSL_VER%/include ^
-DTG_OWT_OPENSSL_INCLUDE_PATH=%cd%/../../../openssl/include ^
-DTG_OWT_OPUS_INCLUDE_PATH=%cd%/../../../opus/include ^
-DTG_OWT_FFMPEG_INCLUDE_PATH=%cd%/../../../ffmpeg ^
../..

View File

@@ -39,6 +39,7 @@ include(cmake/init_target.cmake)
include(cmake/generate_target.cmake)
include(cmake/nuget.cmake)
include(cmake/validate_d3d_compiler.cmake)
include(cmake/target_prepare_qrc.cmake)
include(cmake/options.cmake)

View File

@@ -5,7 +5,7 @@
# https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
add_executable(Telegram WIN32 MACOSX_BUNDLE)
init_target(Telegram)
init_non_host_target(Telegram)
add_subdirectory(lib_rpl)
add_subdirectory(lib_crl)
@@ -42,16 +42,30 @@ include(cmake/generate_appdata_changelog.cmake)
if (WIN32)
include(cmake/generate_midl.cmake)
generate_midl(Telegram ${src_loc}/platform/win/windows_quiethours.idl)
generate_midl(Telegram ${src_loc}
platform/win/windows_quiethours.idl
platform/win/windows_toastactivator.idl
)
nuget_add_winrt(Telegram)
endif()
set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON)
set_target_properties(Telegram PROPERTIES AUTOMOC ON)
target_prepare_qrc(Telegram)
target_link_libraries(Telegram
PRIVATE
tdesktop::lib_tgcalls_legacy
tdesktop::lib_tgcalls
tdesktop::lib_tgvoip
# Order in this list defines the order of include paths in command line.
# We need to place desktop-app::external_minizip this early to have its
# include paths (usually ${PREFIX}/include/minizip) before any depend that
# would add ${PREFIX}/include. This path may have a different <zip.h>,
# for example installed by libzip (https://libzip.org).
desktop-app::external_minizip
tdesktop::td_export
tdesktop::td_mtproto
tdesktop::td_lang
@@ -71,7 +85,6 @@ PRIVATE
desktop-app::external_lz4
desktop-app::external_rlottie
desktop-app::external_zlib
desktop-app::external_minizip
desktop-app::external_qt_static_plugins
desktop-app::external_qt
desktop-app::external_qr_code_generator
@@ -102,6 +115,8 @@ PRIVATE
api/api_cloud_password.cpp
api/api_cloud_password.h
api/api_common.h
api/api_confirm_phone.cpp
api/api_confirm_phone.h
api/api_editing.cpp
api/api_editing.h
api/api_global_privacy.cpp
@@ -112,6 +127,10 @@ PRIVATE
api/api_invite_links.h
api/api_media.cpp
api/api_media.h
api/api_peer_photo.cpp
api/api_peer_photo.h
api/api_polls.cpp
api/api_polls.h
api/api_self_destruct.cpp
api/api_self_destruct.h
api/api_send_progress.cpp
@@ -130,6 +149,8 @@ PRIVATE
api/api_updates.h
api/api_user_privacy.cpp
api/api_user_privacy.h
api/api_views.cpp
api/api_views.h
api/api_who_read.cpp
api/api_who_read.h
boxes/filters/edit_filter_box.cpp
@@ -146,6 +167,7 @@ PRIVATE
boxes/peers/edit_participant_box.h
boxes/peers/edit_participants_box.cpp
boxes/peers/edit_participants_box.h
boxes/peers/edit_peer_common.h
boxes/peers/edit_peer_info_box.cpp
boxes/peers/edit_peer_info_box.h
boxes/peers/edit_peer_invite_link.cpp
@@ -160,6 +182,8 @@ PRIVATE
boxes/peers/edit_peer_permissions_box.h
boxes/about_box.cpp
boxes/about_box.h
boxes/about_sponsored_box.cpp
boxes/about_sponsored_box.h
boxes/abstract_box.cpp
boxes/abstract_box.h
boxes/add_contact_box.cpp
@@ -174,14 +198,12 @@ PRIVATE
boxes/background_preview_box.h
boxes/change_phone_box.cpp
boxes/change_phone_box.h
boxes/confirm_box.cpp
boxes/confirm_box.h
boxes/confirm_phone_box.cpp
boxes/confirm_phone_box.h
boxes/connection_box.cpp
boxes/connection_box.h
boxes/create_poll_box.cpp
boxes/create_poll_box.h
boxes/delete_messages_box.cpp
boxes/delete_messages_box.h
boxes/dictionaries_manager.cpp
boxes/dictionaries_manager.h
boxes/download_path_box.cpp
@@ -196,6 +218,8 @@ PRIVATE
boxes/language_box.h
boxes/local_storage_box.cpp
boxes/local_storage_box.h
boxes/max_invite_box.cpp
boxes/max_invite_box.h
boxes/mute_settings_box.cpp
boxes/mute_settings_box.h
boxes/peer_list_box.cpp
@@ -206,8 +230,10 @@ PRIVATE
boxes/peer_lists_box.h
boxes/passcode_box.cpp
boxes/passcode_box.h
boxes/rate_call_box.cpp
boxes/rate_call_box.h
boxes/phone_banned_box.cpp
boxes/phone_banned_box.h
boxes/pin_messages_box.cpp
boxes/pin_messages_box.h
boxes/self_destruction_box.cpp
boxes/self_destruction_box.h
boxes/send_files_box.cpp
@@ -278,6 +304,8 @@ PRIVATE
chat_helpers/bot_command.h
chat_helpers/bot_keyboard.cpp
chat_helpers/bot_keyboard.h
chat_helpers/emoji_interactions.cpp
chat_helpers/emoji_interactions.h
chat_helpers/emoji_keywords.cpp
chat_helpers/emoji_keywords.h
chat_helpers/emoji_list_widget.cpp
@@ -389,6 +417,7 @@ PRIVATE
data/data_file_origin.cpp
data/data_file_origin.h
data/data_flags.h
data/data_game.cpp
data/data_game.h
data/data_group_call.cpp
data/data_group_call.h
@@ -404,6 +433,7 @@ PRIVATE
data/data_media_types.h
data/data_messages.cpp
data/data_messages.h
data/data_msg_id.h
data/data_notify_settings.cpp
data/data_notify_settings.h
data/data_peer.cpp
@@ -436,6 +466,8 @@ PRIVATE
data/data_shared_media.h
data/data_sparse_ids.cpp
data/data_sparse_ids.h
data/data_sponsored_messages.cpp
data/data_sponsored_messages.h
data/data_streaming.cpp
data/data_streaming.h
data/data_types.cpp
@@ -456,8 +488,6 @@ PRIVATE
dialogs/dialogs_inner_widget.h
dialogs/dialogs_key.cpp
dialogs/dialogs_key.h
dialogs/dialogs_layout.cpp
dialogs/dialogs_layout.h
dialogs/dialogs_list.cpp
dialogs/dialogs_list.h
dialogs/dialogs_main_list.cpp
@@ -470,6 +500,10 @@ PRIVATE
dialogs/dialogs_search_from_controllers.h
dialogs/dialogs_widget.cpp
dialogs/dialogs_widget.h
dialogs/ui/dialogs_layout.cpp
dialogs/ui/dialogs_layout.h
dialogs/ui/dialogs_message_view.cpp
dialogs/ui/dialogs_message_view.h
editor/color_picker.cpp
editor/color_picker.h
editor/controllers/controllers.h
@@ -581,6 +615,8 @@ PRIVATE
history/view/history_view_cursor_state.h
history/view/history_view_element.cpp
history/view/history_view_element.h
history/view/history_view_emoji_interactions.cpp
history/view/history_view_emoji_interactions.h
history/view/history_view_empty_list_bubble.cpp
history/view/history_view_empty_list_bubble.h
history/view/history_view_group_call_tracker.cpp
@@ -608,6 +644,8 @@ PRIVATE
history/view/history_view_service_message.h
history/view/history_view_top_bar_widget.cpp
history/view/history_view_top_bar_widget.h
history/view/history_view_view_button.cpp
history/view/history_view_view_button.h
history/view/history_view_webpage_preview.cpp
history/view/history_view_webpage_preview.h
history/history.cpp
@@ -618,6 +656,10 @@ PRIVATE
history/history_item.h
history/history_item_components.cpp
history/history_item_components.h
history/history_item_edition.cpp
history/history_item_edition.h
history/history_item_reply_markup.cpp
history/history_item_reply_markup.h
history/history_item_text.cpp
history/history_item_text.h
history/history_inner_widget.cpp
@@ -930,6 +972,8 @@ PRIVATE
platform/win/windows_dlls.h
platform/win/windows_event_filter.cpp
platform/win/windows_event_filter.h
platform/win/windows_toast_activator.cpp
platform/win/windows_toast_activator.h
platform/platform_audio.h
platform/platform_file_utilities.h
platform/platform_launcher.h
@@ -1027,6 +1071,8 @@ PRIVATE
ui/chat/attach/attach_item_single_file_preview.h
ui/chat/attach/attach_item_single_media_preview.cpp
ui/chat/attach/attach_item_single_media_preview.h
ui/chat/choose_theme_controller.cpp
ui/chat/choose_theme_controller.h
ui/effects/fireworks_animation.cpp
ui/effects/fireworks_animation.h
ui/effects/round_checkbox.cpp
@@ -1039,10 +1085,6 @@ PRIVATE
ui/image/image_location.h
ui/image/image_location_factory.cpp
ui/image/image_location_factory.h
ui/widgets/continuous_sliders.cpp
ui/widgets/continuous_sliders.h
ui/widgets/discrete_sliders.cpp
ui/widgets/discrete_sliders.h
ui/widgets/level_meter.cpp
ui/widgets/level_meter.h
ui/widgets/multi_select.cpp
@@ -1208,8 +1250,7 @@ elseif (APPLE)
endif()
set(icons_path ${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Images.xcassets)
set_target_properties(Telegram PROPERTIES RESOURCE ${icons_path})
target_sources(Telegram PRIVATE ${icons_path})
target_add_resource(Telegram ${icons_path})
set(lang_packs
en
@@ -1235,27 +1276,30 @@ elseif (APPLE)
PRE_LINK
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Frameworks
COMMAND cp $<TARGET_FILE:Updater> $<TARGET_FILE_DIR:Telegram>/../Frameworks/
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Resources
COMMAND cp ${CMAKE_BINARY_DIR}/lib_ui.rcc $<TARGET_FILE_DIR:Telegram>/../Resources
)
if (NOT DESKTOP_APP_DISABLE_CRASH_REPORTS)
if (DESKTOP_APP_MAC_ARCH STREQUAL "x86_64" OR DESKTOP_APP_MAC_ARCH STREQUAL "arm64")
set(crashpad_dir_part ".${DESKTOP_APP_MAC_ARCH}")
else()
set(crashpad_dir_part "")
endif()
add_custom_command(TARGET Telegram
PRE_LINK
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Helpers
COMMAND cp ${libs_loc}/crashpad/out/$<IF:$<CONFIG:Debug>,Debug,Release>/crashpad_handler $<TARGET_FILE_DIR:Telegram>/../Helpers/
COMMAND cp ${libs_loc}/crashpad/out/$<IF:$<CONFIG:Debug>,Debug,Release>${crashpad_dir_part}/crashpad_handler $<TARGET_FILE_DIR:Telegram>/../Helpers/
)
endif()
endif()
else()
target_link_libraries(Telegram
PRIVATE
desktop-app::external_glibmm
desktop-app::external_glib
)
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_statusnotifieritem
desktop-app::external_dbusmenu_qt
desktop-app::external_glibmm
desktop-app::external_glib
)
endif()
@@ -1359,18 +1403,20 @@ if (WIN32)
/DELAYLOAD:gdiplus.dll
/DELAYLOAD:version.dll
/DELAYLOAD:dwmapi.dll
/DELAYLOAD:uxtheme.dll
/DELAYLOAD:crypt32.dll
/DELAYLOAD:bcrypt.dll
/DELAYLOAD:imm32.dll
/DELAYLOAD:netapi32.dll
/DELAYLOAD:userenv.dll
/DELAYLOAD:wtsapi32.dll
/DELAYLOAD:propsys.dll
)
endif()
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT build_winstore)
add_executable(Updater WIN32)
init_target(Updater)
init_non_host_target(Updater)
add_dependencies(Telegram Updater)
@@ -1382,7 +1428,9 @@ if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT
_other/updater.h
)
set_target_properties(Updater PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
set_target_properties(Updater PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${output_folder}
)
if (WIN32)
get_filename_component(lib_base_loc lib_base REALPATH)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 594 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 717 B

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 651 B

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -357,6 +357,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_update_fail" = "Update check failed :(";
"lng_settings_workmode_tray" = "Show tray icon";
"lng_settings_workmode_window" = "Show taskbar icon";
"lng_settings_close_to_taskbar" = "Close to taskbar";
"lng_settings_native_frame" = "Use system window frame";
"lng_settings_auto_start" = "Launch Telegram when system starts";
"lng_settings_start_min" = "Launch minimized";
@@ -1334,6 +1335,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_forwarded_imported" = "This message was imported from another app. It may not be real.";
"lng_signed_author" = "Author: {user}";
"lng_in_reply_to" = "In reply to";
"lng_sponsored" = "sponsored";
"lng_edited" = "edited";
"lng_edited_date" = "Edited: {date}";
"lng_sent_date" = "Sent: {date}";
@@ -1617,6 +1619,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_user_action_upload_file" = "{user} is sending a file";
"lng_send_action_choose_sticker" = "choosing a sticker";
"lng_user_action_choose_sticker" = "{user} is choosing a sticker";
"lng_user_action_watching_animations" = "watching {emoji}";
"lng_unread_bar#one" = "{count} unread message";
"lng_unread_bar#other" = "{count} unread messages";
"lng_unread_bar_some" = "Unread messages";
@@ -2237,7 +2240,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_recording_start_checkbox" = "Also record video";
"lng_group_call_recording_start_audio_subtitle" = "This chat will be recorded into an audio file";
"lng_group_call_recording_start_video_subtitle" = "Choose video orientation";
"lng_group_call_is_recorded" = "Voice chat is being recorded.";
"lng_group_call_is_recorded" = "The audio stream is being recorded.";
"lng_group_call_is_recorded_video" = "The video stream is being recorded.";
"lng_group_call_is_recorded_channel" = "Live stream is being recorded.";
"lng_group_call_can_speak_here" = "You can now speak.";
"lng_group_call_can_speak" = "You can now speak in {chat}.";
@@ -2868,6 +2872,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_filters_remove_sure" = "This will remove the folder, your chats will not be deleted.";
"lng_filters_remove_yes" = "Remove";
"lng_chat_theme_change" = "Change colors";
"lng_chat_theme_none" = "No\nTheme";
"lng_chat_theme_apply" = "Apply Theme";
"lng_chat_theme_reset" = "Reset Theme";
"lng_chat_theme_dont" = "Do Not Set Theme";
"lng_chat_theme_title" = "Select theme";
"lng_chat_theme_cant_voice" = "Sorry, you can't change the chat theme while you're having an unsent voice message.";
"lng_photo_editor_menu_delete" = "Delete";
"lng_photo_editor_menu_flip" = "Flip";
"lng_photo_editor_menu_duplicate" = "Duplicate";
@@ -2877,6 +2889,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_voice_speed_fast" = "Fast";
"lng_voice_speed_very_fast" = "Very fast";
"lng_view_button_user" = "View user";
"lng_view_button_bot" = "View bot";
"lng_view_button_group" = "View group";
"lng_view_button_channel" = "View channel";
"lng_view_button_background" = "View background";
"lng_view_button_theme" = "View theme";
"lng_view_button_message" = "View message";
"lng_view_button_voice_chat" = "Voice chat";
"lng_view_button_voice_chat_channel" = "Live stream";
"lng_sponsored_title" = "What are sponsored messages?";
"lng_sponsored_info_description1" = "Unlike other apps, Telegram never uses your private data to target ads. Sponsored messages on Telegram are based solely on the topic of the public channels in which they are shown. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored messages.\n\nUnlike other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties cant spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers a free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible advertisers at:";
"lng_sponsored_info_description2" = "Sponsored Messages are currently in test mode. Once they are fully launched and allow Telegram to cover its basic costs, we will start sharing ad revenue with the owners of public channels in which sponsored messages are displayed.\n\nOnline ads should no longer be synonymous with abuse of user privacy. Let us redefine how a tech company should operate together.";
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";

Binary file not shown.

View File

@@ -47,7 +47,7 @@
<file alias="art/bg_initial.jpg">../../art/bg_initial.jpg</file>
<file alias="art/logo_256.png">../../art/logo_256.png</file>
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
<file alias="art/sunrise.jpg">../../art/sunrise.jpg</file>
<file alias="art/themeimage.jpg">../../art/themeimage.jpg</file>
<file alias="art/dice_idle.tgs">../../art/dice_idle.tgs</file>
<file alias="art/dart_idle.tgs">../../art/dart_idle.tgs</file>
<file alias="art/bball_idle.tgs">../../art/bball_idle.tgs</file>
@@ -60,6 +60,8 @@
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
<file alias="day-custom-base.tdesktop-theme">../../day-custom-base.tdesktop-theme</file>
<file alias="night-custom-base.tdesktop-theme">../../night-custom-base.tdesktop-theme</file>
<file alias="icons/calls/hands.lottie">../../icons/calls/hands.lottie</file>
<file alias="icons/calls/voice.lottie">../../icons/calls/voice.lottie</file>
<file alias="recording/info_audio.svg">../../art/recording/recording_info_audio.svg</file>

View File

@@ -467,7 +467,7 @@ sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction;
speakingInGroupCallAction#d92c2285 = SendMessageAction;
sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction;
sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction;
sendMessageEmojiInteraction#6a3233b6 emoticon:string interaction:DataJSON = SendMessageAction;
sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction;
sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction;
contacts.found#b3134d9d my_results:Vector<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
@@ -560,6 +560,7 @@ inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet;
stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet;
@@ -907,7 +908,6 @@ channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvit
channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeTheme#fe69018d prev_value:string new_value:string = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;

View File

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

View File

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

View File

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

View File

@@ -161,6 +161,7 @@ int main(int argc, char *argv[])
QString remove;
int version = 0;
[[maybe_unused]] bool targetwin64 = false;
[[maybe_unused]] bool targetarmac = false;
QFileInfoList files;
for (int i = 0; i < argc; ++i) {
if (string("-path") == argv[i] && i + 1 < argc) {
@@ -170,6 +171,12 @@ int main(int argc, char *argv[])
if (remove.isEmpty()) remove = info.canonicalPath() + "/";
} else if (string("-target") == argv[i] && i + 1 < argc) {
targetwin64 = (string("win64") == argv[i + 1]);
} else if (string("-arch") == argv[i] && i + 1 < argc) {
targetarmac = (string("arm64") == argv[i + 1]);
if (!targetarmac && string("x86_64") != argv[i + 1]) {
cout << "Bad -arch param value passed: " << argv[i + 1] << "\n";
return -1;
}
} else if (string("-version") == argv[i] && i + 1 < argc) {
version = QString(argv[i + 1]).toInt();
} else if (string("-beta") == argv[i]) {
@@ -494,7 +501,7 @@ int main(int argc, char *argv[])
#ifdef Q_OS_WIN
QString outName((targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_MAC
QString outName(QString("tmacupd%1").arg(AlphaVersion ? AlphaVersion : version));
QString outName((targetarmac ? QString("tarmacupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_UNIX
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
#else

View File

@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_attached_stickers.h"
#include "apiwrap.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/sticker_set_box.h"
#include "boxes/stickers_box.h"
#include "data/data_document.h"
@@ -37,7 +37,7 @@ void AttachedStickers::request(
}
if (result.v.isEmpty()) {
strongController->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
Box<Ui::InformBox>(tr::lng_stickers_not_found(tr::now)));
return;
} else if (result.v.size() > 1) {
strongController->show(
@@ -63,7 +63,7 @@ void AttachedStickers::request(
_requestId = 0;
if (const auto strongController = weak.get()) {
strongController->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
Box<Ui::InformBox>(tr::lng_stickers_not_found(tr::now)));
}
}).send();
}

View File

@@ -82,7 +82,7 @@ Authorizations::Entry ParseEntry(const MTPDauthorization &data) {
&& lastDate.weekNumber() == nowDate.weekNumber()) {
result.active = langDayOfWeek(lastDate);
} else {
result.active = lastDate.toString(qsl("d.MM.yy"));
result.active = lastDate.toString(cDateFormat());
}
}

View File

@@ -26,7 +26,7 @@ BlockedPeers::Slice TLToSlice(
Data::Session &owner) {
const auto create = [&](int count, const QVector<MTPPeerBlocked> &list) {
auto slice = BlockedPeers::Slice();
slice.total = std::max(count, list.size());
slice.total = std::max(count, int(list.size()));
slice.list.reserve(list.size());
for (const auto &contact : list) {
contact.match([&](const MTPDpeerBlocked &data) {

View File

@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_cloud_password.h"
#include "core/core_cloud_password.h"
#include "api/api_send_progress.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/share_box.h"
#include "boxes/passcode_box.h"
#include "lang/lang_keys.h"
@@ -91,7 +91,7 @@ void SendBotCallbackData(
result.match([&](const MTPDmessages_botCallbackAnswer &data) {
if (const auto message = data.vmessage()) {
if (data.is_alert()) {
Ui::show(Box<InformBox>(qs(*message)));
Ui::show(Box<Ui::InformBox>(qs(*message)));
} else {
if (withPassword) {
Ui::hideLayer();

View File

@@ -18,7 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h"
#include "data/data_user.h"
#include "data/data_file_origin.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/abstract_box.h"
#include "styles/style_boxes.h"
#include "styles/style_layers.h"
@@ -86,7 +86,7 @@ void CheckChatInvite(
Core::App().hideMediaView();
if (const auto strong = weak.get()) {
strong->show(
Box<InformBox>(tr::lng_group_invite_bad_link(tr::now)));
Box<Ui::InformBox>(tr::lng_group_invite_bad_link(tr::now)));
}
});
}

View File

@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_cloud_password.h"
#include "base/openssl_help.h"
#include "base/random.h"
#include "core/core_cloud_password.h"
#include "apiwrap.h"
@@ -27,7 +27,7 @@ void CloudPassword::reload() {
)).done([=](const MTPaccount_Password &result) {
_requestId = 0;
result.match([&](const MTPDaccount_password &data) {
openssl::AddRandomSeed(bytes::make_span(data.vsecure_random().v));
base::RandomAddSeed(bytes::make_span(data.vsecure_random().v));
if (_state) {
*_state = Core::ParseCloudPasswordState(data);
} else {

View File

@@ -0,0 +1,125 @@
/*
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_confirm_phone.h"
#include "apiwrap.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/boxes/confirm_box.h"
#include "ui/boxes/confirm_phone_box.h"
#include "ui/text/format_values.h" // Ui::FormatPhone
#include "window/window_session_controller.h"
namespace Api {
ConfirmPhone::ConfirmPhone(not_null<ApiWrap*> api)
: _api(&api->instance()) {
}
void ConfirmPhone::resolve(
not_null<Window::SessionController*> controller,
const QString &phone,
const QString &hash) {
if (_sendRequestId) {
return;
}
_sendRequestId = _api.request(MTPaccount_SendConfirmPhoneCode(
MTP_string(hash),
MTP_codeSettings(MTP_flags(0))
)).done([=](const MTPauth_SentCode &result) {
_sendRequestId = 0;
result.match([&](const MTPDauth_sentCode &data) {
const auto sentCodeLength = data.vtype().match([&](
const MTPDauth_sentCodeTypeApp &data) {
LOG(("Error: should not be in-app code!"));
return 0;
}, [&](const MTPDauth_sentCodeTypeSms &data) {
return data.vlength().v;
}, [&](const MTPDauth_sentCodeTypeCall &data) {
return data.vlength().v;
}, [&](const MTPDauth_sentCodeTypeFlashCall &data) {
LOG(("Error: should not be flashcall!"));
return 0;
});
const auto phoneHash = qs(data.vphone_code_hash());
const auto timeout = [&]() -> std::optional<int> {
if (const auto nextType = data.vnext_type()) {
if (nextType->type() == mtpc_auth_codeTypeCall) {
return data.vtimeout().value_or(60);
}
}
return std::nullopt;
}();
auto box = Box<Ui::ConfirmPhoneBox>(
phone,
sentCodeLength,
timeout);
const auto boxWeak = Ui::MakeWeak(box.data());
box->resendRequests(
) | rpl::start_with_next([=] {
_api.request(MTPauth_ResendCode(
MTP_string(phone),
MTP_string(phoneHash)
)).done([=](const MTPauth_SentCode &result) {
if (boxWeak) {
boxWeak->callDone();
}
}).send();
}, box->lifetime());
box->checkRequests(
) | rpl::start_with_next([=](const QString &code) {
if (_checkRequestId) {
return;
}
_checkRequestId = _api.request(MTPaccount_ConfirmPhone(
MTP_string(phoneHash),
MTP_string(code)
)).done([=](const MTPBool &result) {
_checkRequestId = 0;
controller->show(
Box<Ui::InformBox>(
tr::lng_confirm_phone_success(
tr::now,
lt_phone,
Ui::FormatPhone(phone))),
Ui::LayerOption::CloseOther);
}).fail([=](const MTP::Error &error) {
_checkRequestId = 0;
if (!boxWeak) {
return;
}
const auto errorText = MTP::IsFloodError(error)
? tr::lng_flood_error(tr::now)
: (error.type() == (u"PHONE_CODE_EMPTY"_q)
|| error.type() == (u"PHONE_CODE_INVALID"_q))
? tr::lng_bad_code(tr::now)
: Lang::Hard::ServerError();
boxWeak->showServerError(errorText);
}).handleFloodErrors().send();
}, box->lifetime());
controller->show(std::move(box), Ui::LayerOption::CloseOther);
});
}).fail([=](const MTP::Error &error) {
_sendRequestId = 0;
_checkRequestId = 0;
const auto errorText = MTP::IsFloodError(error)
? tr::lng_flood_error(tr::now)
: (error.code() == 400)
? tr::lng_confirm_phone_link_invalid(tr::now)
: Lang::Hard::ServerError();
controller->show(
Box<Ui::InformBox>(errorText),
Ui::LayerOption::CloseOther);
}).handleFloodErrors().send();
}
} // namespace Api

View File

@@ -0,0 +1,36 @@
/*
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 Window {
class SessionController;
} // namespace Window
namespace Api {
class ConfirmPhone final {
public:
explicit ConfirmPhone(not_null<ApiWrap*> api);
void resolve(
not_null<Window::SessionController*> controller,
const QString &phone,
const QString &hash);
private:
MTP::Sender _api;
mtpRequestId _sendRequestId = 0;
mtpRequestId _checkRequestId = 0;
};
} // namespace Api

View File

@@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "api/api_media.h"
#include "api/api_text_entities.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "data/data_scheduled_messages.h"
#include "data/data_session.h"
#include "history/history.h"
@@ -149,7 +149,8 @@ void EditMessageWithUploadedMedia(
session->data().sendHistoryChangeNotifications();
if (mediaInvalid) {
Ui::show(
Box<InformBox>(tr::lng_edit_media_invalid_file(tr::now)),
Box<Ui::InformBox>(
tr::lng_edit_media_invalid_file(tr::now)),
Ui::LayerOption::KeepOther);
}
} else {

View File

@@ -0,0 +1,212 @@
/*
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_peer_photo.h"
#include "api/api_updates.h"
#include "apiwrap.h"
#include "base/random.h"
#include "base/unixtime.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "history/history.h"
#include "main/main_session.h"
#include "storage/file_upload.h"
#include "storage/localimageloader.h"
#include "storage/storage_user_photos.h"
#include <QtCore/QBuffer>
namespace Api {
namespace {
SendMediaReady PreparePeerPhoto(
MTP::DcId dcId,
PeerId peerId,
QImage &&image) {
PreparedPhotoThumbs photoThumbs;
QVector<MTPPhotoSize> photoSizes;
QByteArray jpeg;
QBuffer jpegBuffer(&jpeg);
image.save(&jpegBuffer, "JPG", 87);
const auto scaled = [&](int size) {
return image.scaled(
size,
size,
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
};
const auto push = [&](
const char *type,
QImage &&image,
QByteArray bytes = QByteArray()) {
photoSizes.push_back(MTP_photoSize(
MTP_string(type),
MTP_int(image.width()),
MTP_int(image.height()), MTP_int(0)));
photoThumbs.emplace(type[0], PreparedPhotoThumb{
.image = std::move(image),
.bytes = std::move(bytes)
});
};
push("a", scaled(160));
push("b", scaled(320));
push("c", std::move(image), jpeg);
const auto id = base::RandomValue<PhotoId>();
const auto photo = MTP_photo(
MTP_flags(0),
MTP_long(id),
MTP_long(0),
MTP_bytes(),
MTP_int(base::unixtime::now()),
MTP_vector<MTPPhotoSize>(photoSizes),
MTPVector<MTPVideoSize>(),
MTP_int(dcId));
QString file, filename;
int32 filesize = 0;
QByteArray data;
return SendMediaReady(
SendMediaType::Photo,
file,
filename,
filesize,
data,
id,
id,
u"jpg"_q,
peerId,
photo,
photoThumbs,
MTP_documentEmpty(MTP_long(0)),
jpeg,
0);
}
} // namespace
PeerPhoto::PeerPhoto(not_null<ApiWrap*> api)
: _session(&api->session())
, _api(&api->instance()) {
crl::on_main(_session, [=] {
// You can't use _session->lifetime() in the constructor,
// only queued, because it is not constructed yet.
_session->uploader().photoReady(
) | rpl::start_with_next([=](const Storage::UploadedPhoto &data) {
ready(data.fullId, data.file);
}, _session->lifetime());
});
}
void PeerPhoto::upload(not_null<PeerData*> peer, QImage &&image) {
peer = peer->migrateToOrMe();
const auto ready = PreparePeerPhoto(
_api.instance().mainDcId(),
peer->id,
std::move(image));
const auto fakeId = FullMsgId(
peerToChannel(peer->id),
_session->data().nextLocalMessageId());
const auto already = ranges::find(
_uploads,
peer,
[](const auto &pair) { return pair.second; });
if (already != end(_uploads)) {
_session->uploader().cancel(already->first);
_uploads.erase(already);
}
_uploads.emplace(fakeId, peer);
_session->uploader().uploadMedia(fakeId, ready);
}
void PeerPhoto::clear(not_null<PhotoData*> photo) {
const auto self = _session->user();
if (self->userpicPhotoId() == photo->id) {
_api.request(MTPphotos_UpdateProfilePhoto(
MTP_inputPhotoEmpty()
)).done([=](const MTPphotos_Photo &result) {
self->setPhoto(MTP_userProfilePhotoEmpty());
}).send();
} else if (photo->peer && photo->peer->userpicPhotoId() == photo->id) {
const auto applier = [=](const MTPUpdates &result) {
_session->updates().applyUpdates(result);
};
if (const auto chat = photo->peer->asChat()) {
_api.request(MTPmessages_EditChatPhoto(
chat->inputChat,
MTP_inputChatPhotoEmpty()
)).done(applier).send();
} else if (const auto channel = photo->peer->asChannel()) {
_api.request(MTPchannels_EditPhoto(
channel->inputChannel,
MTP_inputChatPhotoEmpty()
)).done(applier).send();
}
} else {
_api.request(MTPphotos_DeletePhotos(
MTP_vector<MTPInputPhoto>(1, photo->mtpInput())
)).send();
_session->storage().remove(Storage::UserPhotosRemoveOne(
peerToUser(self->id),
photo->id));
}
}
void PeerPhoto::ready(const FullMsgId &msgId, const MTPInputFile &file) {
const auto maybePeer = _uploads.take(msgId);
if (!maybePeer) {
return;
}
const auto peer = *maybePeer;
const auto applier = [=](const MTPUpdates &result) {
_session->updates().applyUpdates(result);
};
if (peer->isSelf()) {
_api.request(MTPphotos_UploadProfilePhoto(
MTP_flags(MTPphotos_UploadProfilePhoto::Flag::f_file),
file,
MTPInputFile(), // video
MTPdouble() // video_start_ts
)).done([=](const MTPphotos_Photo &result) {
result.match([&](const MTPDphotos_photo &data) {
_session->data().processPhoto(data.vphoto());
_session->data().processUsers(data.vusers());
});
}).send();
} else if (const auto chat = peer->asChat()) {
const auto history = _session->data().history(chat);
history->sendRequestId = _api.request(MTPmessages_EditChatPhoto(
chat->inputChat,
MTP_inputChatUploadedPhoto(
MTP_flags(MTPDinputChatUploadedPhoto::Flag::f_file),
file,
MTPInputFile(), // video
MTPdouble()) // video_start_ts
)).done(applier).afterRequest(history->sendRequestId).send();
} else if (const auto channel = peer->asChannel()) {
const auto history = _session->data().history(channel);
history->sendRequestId = _api.request(MTPchannels_EditPhoto(
channel->inputChannel,
MTP_inputChatUploadedPhoto(
MTP_flags(MTPDinputChatUploadedPhoto::Flag::f_file),
file,
MTPInputFile(), // video
MTPdouble()) // video_start_ts
)).done(applier).afterRequest(history->sendRequestId).send();
}
}
} // namespace Api

View File

@@ -0,0 +1,38 @@
/*
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;
class PeerData;
namespace Main {
class Session;
} // namespace Main
namespace Api {
class PeerPhoto final {
public:
explicit PeerPhoto(not_null<ApiWrap*> api);
void upload(not_null<PeerData*> peer, QImage &&image);
void clear(not_null<PhotoData*> photo);
private:
void ready(const FullMsgId &msgId, const MTPInputFile &file);
const not_null<Main::Session*> _session;
MTP::Sender _api;
base::flat_map<FullMsgId, not_null<PeerData*>> _uploads;
};
} // namespace Api

View File

@@ -0,0 +1,201 @@
/*
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_polls.h"
#include "api/api_common.h"
#include "api/api_updates.h"
#include "apiwrap.h"
#include "base/random.h"
#include "data/data_changes.h"
#include "data/data_histories.h"
#include "data/data_poll.h"
#include "data/data_session.h"
#include "history/history.h"
#include "history/history_message.h" // ShouldSendSilent
#include "main/main_session.h"
namespace Api {
namespace {
[[nodiscard]] TimeId UnixtimeFromMsgId(mtpMsgId msgId) {
return TimeId(msgId >> 32);
}
} // namespace
Polls::Polls(not_null<ApiWrap*> api)
: _session(&api->session())
, _api(&api->instance()) {
}
void Polls::create(
const PollData &data,
const SendAction &action,
Fn<void()> done,
Fn<void(const MTP::Error &error)> fail) {
_session->api().sendAction(action);
const auto history = action.history;
const auto peer = history->peer;
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (action.replyTo) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
const auto clearCloudDraft = action.clearDraft;
if (clearCloudDraft) {
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
history->clearLocalDraft();
history->clearCloudDraft();
history->startSavingCloudDraft();
}
const auto silentPost = ShouldSendSilent(peer, action.options);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
if (action.options.scheduled) {
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
const auto replyTo = action.replyTo;
history->sendRequestId = _api.request(MTPmessages_SendMedia(
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
PollDataToInputMedia(&data),
MTP_string(),
MTP_long(base::RandomValue<uint64>()),
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(action.options.scheduled)
)).done([=](
const MTPUpdates &result,
const MTP::Response &response) mutable {
_session->updates().applyUpdates(result);
if (clearCloudDraft) {
history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
}
_session->changes().historyUpdated(
history,
(action.options.scheduled
? Data::HistoryUpdate::Flag::ScheduledSent
: Data::HistoryUpdate::Flag::MessageSent));
done();
finish();
}).fail([=](
const MTP::Error &error,
const MTP::Response &response) mutable {
if (clearCloudDraft) {
history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
}
fail(error);
finish();
}).afterRequest(history->sendRequestId
).send();
return history->sendRequestId;
});
}
void Polls::sendVotes(
FullMsgId itemId,
const std::vector<QByteArray> &options) {
if (_pollVotesRequestIds.contains(itemId)) {
return;
}
const auto item = _session->data().message(itemId);
const auto media = item ? item->media() : nullptr;
const auto poll = media ? media->poll() : nullptr;
if (!item) {
return;
}
const auto showSending = poll && !options.empty();
const auto hideSending = [=] {
if (showSending) {
if (const auto item = _session->data().message(itemId)) {
poll->sendingVotes.clear();
_session->data().requestItemRepaint(item);
}
}
};
if (showSending) {
poll->sendingVotes = options;
_session->data().requestItemRepaint(item);
}
auto prepared = QVector<MTPbytes>();
prepared.reserve(options.size());
ranges::transform(
options,
ranges::back_inserter(prepared),
[](const QByteArray &option) { return MTP_bytes(option); });
const auto requestId = _api.request(MTPmessages_SendVote(
item->history()->peer->input,
MTP_int(item->id),
MTP_vector<MTPbytes>(prepared)
)).done([=](const MTPUpdates &result) {
_pollVotesRequestIds.erase(itemId);
hideSending();
_session->updates().applyUpdates(result);
}).fail([=](const MTP::Error &error) {
_pollVotesRequestIds.erase(itemId);
hideSending();
}).send();
_pollVotesRequestIds.emplace(itemId, requestId);
}
void Polls::close(not_null<HistoryItem*> item) {
const auto itemId = item->fullId();
if (_pollCloseRequestIds.contains(itemId)) {
return;
}
const auto media = item ? item->media() : nullptr;
const auto poll = media ? media->poll() : nullptr;
if (!poll) {
return;
}
const auto requestId = _api.request(MTPmessages_EditMessage(
MTP_flags(MTPmessages_EditMessage::Flag::f_media),
item->history()->peer->input,
MTP_int(item->id),
MTPstring(),
PollDataToInputMedia(poll, true),
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(0) // schedule_date
)).done([=](const MTPUpdates &result) {
_pollCloseRequestIds.erase(itemId);
_session->updates().applyUpdates(result);
}).fail([=](const MTP::Error &error) {
_pollCloseRequestIds.erase(itemId);
}).send();
_pollCloseRequestIds.emplace(itemId, requestId);
}
void Polls::reloadResults(not_null<HistoryItem*> item) {
const auto itemId = item->fullId();
if (!IsServerMsgId(item->id)
|| _pollReloadRequestIds.contains(itemId)) {
return;
}
const auto requestId = _api.request(MTPmessages_GetPollResults(
item->history()->peer->input,
MTP_int(item->id)
)).done([=](const MTPUpdates &result) {
_pollReloadRequestIds.erase(itemId);
_session->updates().applyUpdates(result);
}).fail([=](const MTP::Error &error) {
_pollReloadRequestIds.erase(itemId);
}).send();
_pollReloadRequestIds.emplace(itemId, requestId);
}
} // namespace Api

View File

@@ -0,0 +1,49 @@
/*
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;
class HistoryItem;
struct PollData;
namespace Main {
class Session;
} // namespace Main
namespace Api {
struct SendAction;
class Polls final {
public:
explicit Polls(not_null<ApiWrap*> api);
void create(
const PollData &data,
const SendAction &action,
Fn<void()> done,
Fn<void(const MTP::Error &error)> fail);
void sendVotes(
FullMsgId itemId,
const std::vector<QByteArray> &options);
void close(not_null<HistoryItem*> item);
void reloadResults(not_null<HistoryItem*> item);
private:
const not_null<Main::Session*> _session;
MTP::Sender _api;
base::flat_map<FullMsgId, mtpRequestId> _pollVotesRequestIds;
base::flat_map<FullMsgId, mtpRequestId> _pollCloseRequestIds;
base::flat_map<FullMsgId, mtpRequestId> _pollReloadRequestIds;
};
} // namespace Api

View File

@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_sending.h"
#include "api/api_text_entities.h"
#include "base/openssl_help.h"
#include "base/random.h"
#include "base/unixtime.h"
#include "data/data_document.h"
#include "data/data_photo.h"
@@ -76,7 +76,7 @@ void SendExistingMedia(
const auto newId = FullMsgId(
peerToChannel(peer->id),
session->data().nextLocalMessageId());
const auto randomId = openssl::RandomValue<uint64>();
const auto randomId = base::RandomValue<uint64>();
auto flags = NewMessageFlags(peer);
auto sendFlags = MTPmessages_SendMedia::Flags(0);
@@ -128,7 +128,7 @@ void SendExistingMedia(
messagePostAuthor,
media,
caption,
MTPReplyMarkup());
HistoryMessageMarkupData());
auto performRequest = [=](const auto &repeatRequest) -> void {
auto &histories = history->owner().histories();
@@ -212,7 +212,7 @@ void SendExistingPhoto(
}
bool SendDice(Api::MessageToSend &message) {
const auto full = message.textWithTags.text.midRef(0).trimmed();
const auto full = QStringView(message.textWithTags.text).trimmed();
auto length = 0;
if (!Ui::Emoji::Find(full.data(), full.data() + full.size(), &length)
|| length != full.size()) {
@@ -248,7 +248,7 @@ bool SendDice(Api::MessageToSend &message) {
const auto newId = FullMsgId(
peerToChannel(peer->id),
session->data().nextLocalMessageId());
const auto randomId = openssl::RandomValue<uint64>();
const auto randomId = base::RandomValue<uint64>();
auto &histories = history->owner().histories();
auto flags = NewMessageFlags(peer);
@@ -288,7 +288,7 @@ bool SendDice(Api::MessageToSend &message) {
messagePostAuthor,
TextWithEntities(),
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
MTPReplyMarkup());
HistoryMessageMarkupData());
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
@@ -335,7 +335,7 @@ void SendConfirmedFile(
isEditing
? file->to.replaceMediaOf
: session->data().nextLocalMessageId());
auto groupId = file->album ? file->album->groupId : uint64(0);
const auto groupId = file->album ? file->album->groupId : uint64(0);
if (file->album) {
const auto proj = [](const SendingAlbum::Item &item) {
return item.taskId;
@@ -370,13 +370,6 @@ void SendConfirmedFile(
session->user()).flags;
TextUtilities::PrepareForSending(caption, prepareFlags);
TextUtilities::Trim(caption);
auto localEntities = Api::EntitiesToMTP(session, caption.entities);
if (itemToEdit) {
if (const auto id = itemToEdit->groupId()) {
groupId = id.value;
}
}
auto flags = isEditing ? MessageFlags() : NewMessageFlags(peer);
if (file->to.replyTo) {
@@ -397,13 +390,18 @@ void SendConfirmedFile(
} else {
flags |= MessageFlag::LocalHistoryEntry;
}
if (file->type == SendMediaType::Audio) {
if (!peer->isChannel() || peer->isMegagroup()) {
flags |= MessageFlag::MediaIsUnread;
}
}
const auto messageFromId = anonymousPost ? 0 : session->userPeerId();
const auto messagePostAuthor = peer->isBroadcast()
? session->user()->name
: QString();
const auto media = [&] {
const auto media = MTPMessageMedia([&] {
if (file->type == SendMediaType::Photo) {
return MTP_messageMediaPhoto(
MTP_flags(MTPDmessageMediaPhoto::Flag::f_photo),
@@ -422,38 +420,21 @@ void SendConfirmedFile(
} else {
Unexpected("Type in sendFilesConfirmed.");
}
}();
}());
if (itemToEdit) {
itemToEdit->savePreviousMedia();
itemToEdit->applyEdition(MTP_message(
MTP_flags(MTPDmessage::Flag::f_media
| ((flags & MessageFlag::HideEdited)
? MTPDmessage::Flag::f_edit_hide
: MTPDmessage::Flag())
| (localEntities.v.isEmpty()
? MTPDmessage::Flag()
: MTPDmessage::Flag::f_entities)),
MTP_int(newId.msg),
peerToMTP(messageFromId),
peerToMTP(file->to.peer),
MTPMessageFwdHeader(),
MTPlong(), // via_bot_id
replyHeader,
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
MTP_string(caption.text),
media,
MTPReplyMarkup(),
localEntities,
MTPint(), // views
MTPint(), // forwards
MTPMessageReplies(),
MTPint(), // edit_date
MTP_string(messagePostAuthor),
MTP_long(groupId),
//MTPMessageReactions(),
MTPVector<MTPRestrictionReason>(),
MTPint()).c_message());
auto edition = HistoryMessageEdition();
edition.isEditHide = (flags & MessageFlag::HideEdited);
edition.editDate = 0;
edition.views = 0;
edition.forwards = 0;
edition.ttl = 0;
edition.mtpMedia = &media;
edition.textWithEntities = caption;
edition.useSameMarkup = true;
edition.useSameReplies = true;
itemToEdit->applyEdition(std::move(edition));
} else {
const auto viaBotId = UserId();
history->addNewLocalMessage(
@@ -466,7 +447,7 @@ void SendConfirmedFile(
messagePostAuthor,
caption,
media,
MTPReplyMarkup(),
HistoryMessageMarkupData(),
groupId);
}

View File

@@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_folder.h"
#include "data/data_scheduled_messages.h"
#include "data/data_send_action.h"
#include "chat_helpers/emoji_interactions.h"
#include "lang/lang_cloud_manager.h"
#include "history/history.h"
#include "history/history_item.h"
@@ -41,7 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "window/window_session_controller.h"
#include "window/window_controller.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "apiwrap.h"
#include "ui/text/format_values.h" // Ui::FormatPhone
#include "app.h" // App::quitting
@@ -984,36 +985,18 @@ void Updates::handleSendActionUpdate(
const auto from = (fromId == session().userPeerId())
? session().user().get()
: session().data().peerLoaded(fromId);
const auto isSpeakingInCall = (action.type()
== mtpc_speakingInGroupCallAction);
if (isSpeakingInCall) {
if (!peer->isChat() && !peer->isChannel()) {
return;
}
const auto call = peer->groupCall();
const auto now = crl::now();
if (call) {
call->applyActiveUpdate(
fromId,
Data::LastSpokeTimes{ .anything = now, .voice = now },
from);
} else {
const auto chat = peer->asChat();
const auto channel = peer->asChannel();
const auto active = chat
? (chat->flags() & ChatDataFlag::CallActive)
: (channel->flags() & ChannelDataFlag::CallActive);
if (active) {
_pendingSpeakingCallParticipants.emplace(
peer).first->second[fromId] = now;
if (peerIsUser(fromId)) {
session().api().requestFullPeer(peer);
}
}
}
if (action.type() == mtpc_speakingInGroupCallAction) {
handleSpeakingInCall(peer, fromId, from);
}
if (!from || !from->isUser() || from->isSelf()) {
return;
} else if (action.type() == mtpc_sendMessageEmojiInteraction) {
handleEmojiInteraction(peer, action.c_sendMessageEmojiInteraction());
return;
} else if (action.type() == mtpc_sendMessageEmojiInteractionSeen) {
const auto &data = action.c_sendMessageEmojiInteractionSeen();
handleEmojiInteraction(peer, qs(data.vemoticon()));
return;
}
const auto when = requestingDifference()
? 0
@@ -1026,6 +1009,76 @@ void Updates::handleSendActionUpdate(
when);
}
void Updates::handleEmojiInteraction(
not_null<PeerData*> peer,
const MTPDsendMessageEmojiInteraction &data) {
const auto json = data.vinteraction().match([&](
const MTPDdataJSON &data) {
return data.vdata().v;
});
handleEmojiInteraction(
peer,
data.vmsg_id().v,
qs(data.vemoticon()),
ChatHelpers::EmojiInteractions::Parse(json));
}
void Updates::handleSpeakingInCall(
not_null<PeerData*> peer,
PeerId participantPeerId,
PeerData *participantPeerLoaded) {
if (!peer->isChat() && !peer->isChannel()) {
return;
}
const auto call = peer->groupCall();
const auto now = crl::now();
if (call) {
call->applyActiveUpdate(
participantPeerId,
Data::LastSpokeTimes{ .anything = now, .voice = now },
participantPeerLoaded);
} else {
const auto chat = peer->asChat();
const auto channel = peer->asChannel();
const auto active = chat
? (chat->flags() & ChatDataFlag::CallActive)
: (channel->flags() & ChannelDataFlag::CallActive);
if (active) {
_pendingSpeakingCallParticipants.emplace(
peer).first->second[participantPeerId] = now;
if (peerIsUser(participantPeerId)) {
session().api().requestFullPeer(peer);
}
}
}
}
void Updates::handleEmojiInteraction(
not_null<PeerData*> peer,
MsgId messageId,
const QString &emoticon,
ChatHelpers::EmojiInteractionsBunch bunch) {
if (session().windows().empty()) {
return;
}
const auto window = session().windows().front();
window->emojiInteractions().startIncoming(
peer,
messageId,
emoticon,
std::move(bunch));
}
void Updates::handleEmojiInteraction(
not_null<PeerData*> peer,
const QString &emoticon) {
if (session().windows().empty()) {
return;
}
const auto window = session().windows().front();
window->emojiInteractions().seenOutgoing(peer, emoticon);
}
void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
switch (updates.type()) {
case mtpc_updateShortMessage: {
@@ -1923,7 +1976,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
} else if (d.is_popup()) {
const auto &windows = session().windows();
if (!windows.empty()) {
windows.front()->window().show(Box<InformBox>(text));
windows.front()->window().show(Box<Ui::InformBox>(text));
}
} else {
session().data().serviceNotification(text, d.vmedia());

View File

@@ -21,6 +21,10 @@ namespace Main {
class Session;
} // namespace Main
namespace ChatHelpers {
struct EmojiInteractionsBunch;
} // namespace ChatHelpers
namespace Api {
class Updates final {
@@ -139,6 +143,21 @@ private:
MsgId rootId,
PeerId fromId,
const MTPSendMessageAction &action);
void handleEmojiInteraction(
not_null<PeerData*> peer,
const MTPDsendMessageEmojiInteraction &data);
void handleSpeakingInCall(
not_null<PeerData*> peer,
PeerId participantPeerId,
PeerData *participantPeerLoaded);
void handleEmojiInteraction(
not_null<PeerData*> peer,
MsgId messageId,
const QString &emoticon,
ChatHelpers::EmojiInteractionsBunch bunch);
void handleEmojiInteraction(
not_null<PeerData*> peer,
const QString &emoticon);
const not_null<Main::Session*> _session;

View File

@@ -0,0 +1,136 @@
/*
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_views.h"
#include "apiwrap.h"
#include "data/data_peer.h"
#include "data/data_peer_id.h"
#include "data/data_session.h"
#include "history/history.h"
#include "history/history_item.h"
#include "main/main_session.h"
namespace Api {
namespace {
// Send channel views each second.
constexpr auto kSendViewsTimeout = crl::time(1000);
} // namespace
ViewsManager::ViewsManager(not_null<ApiWrap*> api)
: _session(&api->session())
, _api(&api->instance())
, _incrementTimer([=] { viewsIncrement(); }) {
}
void ViewsManager::scheduleIncrement(not_null<HistoryItem*> item) {
auto peer = item->history()->peer;
auto i = _incremented.find(peer);
if (i != _incremented.cend()) {
if (i->second.contains(item->id)) {
return;
}
} else {
i = _incremented.emplace(peer).first;
}
i->second.emplace(item->id);
auto j = _toIncrement.find(peer);
if (j == _toIncrement.cend()) {
j = _toIncrement.emplace(peer).first;
_incrementTimer.callOnce(kSendViewsTimeout);
}
j->second.emplace(item->id);
}
void ViewsManager::removeIncremented(not_null<PeerData*> peer) {
_incremented.remove(peer);
}
void ViewsManager::viewsIncrement() {
for (auto i = _toIncrement.begin(); i != _toIncrement.cend();) {
if (_incrementRequests.contains(i->first)) {
++i;
continue;
}
QVector<MTPint> ids;
ids.reserve(i->second.size());
for (const auto &msgId : i->second) {
ids.push_back(MTP_int(msgId));
}
const auto requestId = _api.request(MTPmessages_GetMessagesViews(
i->first->input,
MTP_vector<MTPint>(ids),
MTP_bool(true)
)).done([=](
const MTPmessages_MessageViews &result,
mtpRequestId requestId) {
done(ids, result, requestId);
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
fail(error, requestId);
}).afterDelay(5).send();
_incrementRequests.emplace(i->first, requestId);
i = _toIncrement.erase(i);
}
}
void ViewsManager::done(
QVector<MTPint> ids,
const MTPmessages_MessageViews &result,
mtpRequestId requestId) {
const auto &data = result.c_messages_messageViews();
auto &owner = _session->data();
owner.processUsers(data.vusers());
owner.processChats(data.vchats());
auto &v = data.vviews().v;
if (ids.size() == v.size()) {
for (const auto &[peer, id] : _incrementRequests) {
if (id != requestId) {
continue;
}
const auto channel = peerToChannel(peer->id);
for (auto j = 0, l = int(ids.size()); j < l; ++j) {
if (const auto item = owner.message(channel, ids[j].v)) {
v[j].match([&](const MTPDmessageViews &data) {
if (const auto views = data.vviews()) {
item->setViewsCount(views->v);
}
if (const auto forwards = data.vforwards()) {
item->setForwardsCount(forwards->v);
}
if (const auto replies = data.vreplies()) {
item->setReplies(
HistoryMessageRepliesData(replies));
}
});
}
}
_incrementRequests.erase(peer);
break;
}
}
if (!_toIncrement.empty() && !_incrementTimer.isActive()) {
_incrementTimer.callOnce(kSendViewsTimeout);
}
}
void ViewsManager::fail(const MTP::Error &error, mtpRequestId requestId) {
for (const auto &[peer, id] : _incrementRequests) {
if (id == requestId) {
_incrementRequests.erase(peer);
break;
}
}
if (!_toIncrement.empty() && !_incrementTimer.isActive()) {
_incrementTimer.callOnce(kSendViewsTimeout);
}
}
} // namespace Api

View File

@@ -0,0 +1,49 @@
/*
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"
#include "base/timer.h"
class ApiWrap;
class PeerData;
namespace Main {
class Session;
} // namespace Main
namespace Api {
class ViewsManager final {
public:
explicit ViewsManager(not_null<ApiWrap*> api);
void scheduleIncrement(not_null<HistoryItem*> item);
void removeIncremented(not_null<PeerData*> peer);
private:
void viewsIncrement();
void done(
QVector<MTPint> ids,
const MTPmessages_MessageViews &result,
mtpRequestId requestId);
void fail(const MTP::Error &error, mtpRequestId requestId);
const not_null<Main::Session*> _session;
MTP::Sender _api;
base::flat_map<not_null<PeerData*>, base::flat_set<MsgId>> _incremented;
base::flat_map<not_null<PeerData*>, base::flat_set<MsgId>> _toIncrement;
base::flat_map<not_null<PeerData*>, mtpRequestId> _incrementRequests;
base::flat_map<mtpRequestId, not_null<PeerData*>> _incrementByRequest;
base::Timer _incrementTimer;
};
} // namespace Api

View File

@@ -130,7 +130,6 @@ struct State {
not_null<HistoryItem*> item,
not_null<QWidget*> context) {
auto weak = QPointer<QWidget>(context.get());
const auto fullId = item->fullId();
const auto session = &item->history()->session();
return [=](auto consumer) {
if (!weak) {
@@ -160,7 +159,7 @@ struct State {
auto &entry = context->cache(item);
entry.requestId = 0;
auto peers = std::vector<PeerId>();
peers.reserve(std::max(result.v.size(), 1));
peers.reserve(std::max(int(result.v.size()), 1));
for (const auto &id : result.v) {
peers.push_back(UserId(id));
}
@@ -203,7 +202,7 @@ bool UpdateUserpics(
}
auto &was = state->userpics;
auto now = std::vector<Userpic>();
for (const auto peer : peers) {
for (const auto &peer : peers) {
if (ranges::contains(now, peer, &Userpic::peer)) {
continue;
}
@@ -356,6 +355,8 @@ rpl::producer<Ui::WhoReadContent> WhoRead(
} else if (UpdateUserpics(state, item, peers)) {
RegenerateParticipants(state, small, large);
pushNext();
} else if (peers.empty()) {
pushNext();
}
}, lifetime);

View File

@@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_hash.h"
#include "api/api_invite_links.h"
#include "api/api_media.h"
#include "api/api_peer_photo.h"
#include "api/api_polls.h"
#include "api/api_sending.h"
#include "api/api_text_entities.h"
#include "api/api_self_destruct.h"
@@ -21,12 +23,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_global_privacy.h"
#include "api/api_updates.h"
#include "api/api_user_privacy.h"
#include "api/api_views.h"
#include "api/api_confirm_phone.h"
#include "data/stickers/data_stickers.h"
#include "data/data_drafts.h"
#include "data/data_changes.h"
#include "data/data_photo.h"
#include "data/data_web_page.h"
#include "data/data_poll.h"
#include "data/data_folder.h"
#include "data/data_media_types.h"
#include "data/data_sparse_ids.h"
@@ -46,6 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/core_cloud_password.h"
#include "core/application.h"
#include "base/unixtime.h"
#include "base/random.h"
#include "base/qt_adapters.h"
#include "base/call_delayed.h"
#include "lang/lang_keys.h"
@@ -59,7 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "main/main_session_settings.h"
#include "main/main_account.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/stickers_box.h"
#include "boxes/sticker_set_box.h"
#include "window/notifications_manager.h"
@@ -140,15 +144,14 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this))
, _globalPrivacy(std::make_unique<Api::GlobalPrivacy>(this))
, _userPrivacy(std::make_unique<Api::UserPrivacy>(this))
, _inviteLinks(std::make_unique<Api::InviteLinks>(this)) {
, _inviteLinks(std::make_unique<Api::InviteLinks>(this))
, _views(std::make_unique<Api::ViewsManager>(this))
, _confirmPhone(std::make_unique<Api::ConfirmPhone>(this))
, _peerPhoto(std::make_unique<Api::PeerPhoto>(this))
, _polls(std::make_unique<Api::Polls>(this)) {
crl::on_main(session, [=] {
// You can't use _session->lifetime() in the constructor,
// only queued, because it is not constructed yet.
_session->uploader().photoReady(
) | rpl::start_with_next([=](const Storage::UploadedPhoto &data) {
photoUploadReady(data.fullId, data.file);
}, _session->lifetime());
_session->data().chatsFilters().changed(
) | rpl::filter([=] {
return _session->data().chatsFilters().archiveNeeded();
@@ -389,9 +392,9 @@ void ApiWrap::importChatInvite(const QString &hash) {
}).fail([=](const MTP::Error &error) {
const auto &type = error.type();
if (type == qstr("CHANNELS_TOO_MUCH")) {
Ui::show(Box<InformBox>(tr::lng_join_channel_error(tr::now)));
Ui::show(Box<Ui::InformBox>(tr::lng_join_channel_error(tr::now)));
} else if (error.code() == 400) {
Ui::show(Box<InformBox>((type == qstr("USERS_TOO_MUCH"))
Ui::show(Box<Ui::InformBox>((type == qstr("USERS_TOO_MUCH"))
? tr::lng_group_invite_no_room(tr::now)
: tr::lng_group_invite_bad_link(tr::now)));
}
@@ -463,19 +466,19 @@ void ApiWrap::sendMessageFail(
uint64 randomId,
FullMsgId itemId) {
if (error.type() == qstr("PEER_FLOOD")) {
Ui::show(Box<InformBox>(
Ui::show(Box<Ui::InformBox>(
PeerFloodErrorText(&session(), PeerFloodType::Send)));
} else if (error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
const auto link = textcmdLink(
session().createInternalLinkFull(qsl("spambot")),
tr::lng_cant_more_info(tr::now));
Ui::show(Box<InformBox>(tr::lng_error_public_groups_denied(
Ui::show(Box<Ui::InformBox>(tr::lng_error_public_groups_denied(
tr::now,
lt_more_info,
link)));
} else if (error.type().startsWith(qstr("SLOWMODE_WAIT_"))) {
const auto chop = qstr("SLOWMODE_WAIT_").size();
const auto left = error.type().midRef(chop).toInt();
const auto left = base::StringViewMid(error.type(), chop).toInt();
if (const auto channel = peer->asChannel()) {
const auto seconds = channel->slowmodeSeconds();
if (seconds >= left) {
@@ -490,7 +493,7 @@ void ApiWrap::sendMessageFail(
Assert(peer->isUser());
if (const auto item = scheduled.lookupItem(peer->id, itemId.msg)) {
scheduled.removeSending(item);
Ui::show(Box<InformBox>(tr::lng_cant_do_this(tr::now)));
Ui::show(Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now)));
}
}
if (const auto item = _session->data().message(itemId)) {
@@ -557,7 +560,8 @@ void ApiWrap::resolveMessageDatas() {
)).done([=](
const MTPmessages_Messages &result,
mtpRequestId requestId) {
gotMessageDatas(nullptr, result, requestId);
_session->data().processExistingMessages(nullptr, result);
finalizeMessageDataRequest(nullptr, requestId);
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
finalizeMessageDataRequest(nullptr, requestId);
}).afterDelay(kSmallDelayMs).send();
@@ -583,7 +587,8 @@ void ApiWrap::resolveMessageDatas() {
)).done([=](
const MTPmessages_Messages &result,
mtpRequestId requestId) {
gotMessageDatas(channel, result, requestId);
_session->data().processExistingMessages(channel, result);
finalizeMessageDataRequest(channel, requestId);
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
finalizeMessageDataRequest(channel, requestId);
}).afterDelay(kSmallDelayMs).send();
@@ -599,37 +604,6 @@ void ApiWrap::resolveMessageDatas() {
}
}
void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId requestId) {
const auto handleResult = [&](auto &&result) {
_session->data().processUsers(result.vusers());
_session->data().processChats(result.vchats());
_session->data().processMessages(
result.vmessages(),
NewMessageType::Existing);
};
switch (msgs.type()) {
case mtpc_messages_messages:
handleResult(msgs.c_messages_messages());
break;
case mtpc_messages_messagesSlice:
handleResult(msgs.c_messages_messagesSlice());
break;
case mtpc_messages_channelMessages: {
auto &d = msgs.c_messages_channelMessages();
if (channel) {
channel->ptsReceived(d.vpts().v);
} else {
LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotDependencyItem)"));
}
handleResult(d);
} break;
case mtpc_messages_messagesNotModified:
LOG(("API Error: received messages.messagesNotModified! (ApiWrap::gotDependencyItem)"));
break;
}
finalizeMessageDataRequest(channel, requestId);
}
void ApiWrap::finalizeMessageDataRequest(
ChannelData *channel,
mtpRequestId requestId) {
@@ -661,8 +635,8 @@ QString ApiWrap::exportDirectMessageLink(
const auto fallback = [&] {
auto linkChannel = channel;
auto linkItemId = item->id;
auto linkCommentId = 0;
auto linkThreadId = 0;
auto linkCommentId = MsgId();
auto linkThreadId = MsgId();
if (inRepliesContext) {
if (const auto rootId = item->replyToTop()) {
const auto root = item->history()->owner().message(
@@ -692,11 +666,11 @@ QString ApiWrap::exportDirectMessageLink(
: "c/" + QString::number(peerToChannel(linkChannel->id).bare);
const auto query = base
+ '/'
+ QString::number(linkItemId)
+ QString::number(linkItemId.bare)
+ (linkCommentId
? "?comment=" + QString::number(linkCommentId)
? "?comment=" + QString::number(linkCommentId.bare)
: linkThreadId
? "?thread=" + QString::number(linkThreadId)
? "?thread=" + QString::number(linkThreadId.bare)
: "");
if (linkChannel->hasUsername()
&& !linkChannel->isMegagroup()
@@ -1277,7 +1251,7 @@ void ApiWrap::migrateDone(
void ApiWrap::migrateFail(not_null<PeerData*> peer, const MTP::Error &error) {
const auto &type = error.type();
if (type == qstr("CHANNELS_TOO_MUCH")) {
Ui::show(Box<InformBox>(tr::lng_migrate_error(tr::now)));
Ui::show(Box<Ui::InformBox>(tr::lng_migrate_error(tr::now)));
}
if (auto handlers = _migrateCallbacks.take(peer)) {
for (auto &handler : *handlers) {
@@ -1758,7 +1732,7 @@ void ApiWrap::deleteAllFromUser(
? history->collectMessagesFromUserToDelete(from)
: QVector<MsgId>();
const auto channelId = peerToChannel(channel->id);
for (const auto msgId : ids) {
for (const auto &msgId : ids) {
if (const auto item = _session->data().message(channelId, msgId)) {
item->destroy();
}
@@ -2110,13 +2084,14 @@ void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
} else if (error.type() == qstr("CHANNEL_PRIVATE")
|| error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA")
|| error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
Ui::show(Box<InformBox>(channel->isMegagroup()
Ui::show(Box<Ui::InformBox>(channel->isMegagroup()
? tr::lng_group_not_accessible(tr::now)
: tr::lng_channel_not_accessible(tr::now)));
} else if (error.type() == qstr("CHANNELS_TOO_MUCH")) {
Ui::show(Box<InformBox>(tr::lng_join_channel_error(tr::now)));
Ui::show(Box<Ui::InformBox>(
tr::lng_join_channel_error(tr::now)));
} else if (error.type() == qstr("USERS_TOO_MUCH")) {
Ui::show(Box<InformBox>(tr::lng_group_full(tr::now)));
Ui::show(Box<Ui::InformBox>(tr::lng_group_full(tr::now)));
}
_channelAmInRequests.remove(channel);
}).send();
@@ -3288,7 +3263,7 @@ void ApiWrap::requestMessageAfterDate(
// So we request a message with offset_date = desired_date - 1 and add_offset = -1.
// This should give us the first message with date >= desired_date.
const auto offsetId = 0;
const auto offsetDate = static_cast<int>(base::QDateToDateTime(date).toTime_t()) - 1;
const auto offsetDate = static_cast<int>(date.startOfDay().toSecsSinceEpoch()) - 1;
const auto addOffset = -1;
const auto limit = 1;
const auto maxId = 0;
@@ -3652,8 +3627,9 @@ void ApiWrap::forwardMessages(
const auto history = action.history;
const auto peer = history->peer;
histories.readInbox(history);
if (!action.options.scheduled) {
histories.readInbox(history);
}
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, action.options);
@@ -3724,7 +3700,7 @@ void ApiWrap::forwardMessages(
ids.reserve(count);
randomIds.reserve(count);
for (const auto item : draft.items) {
const auto randomId = openssl::RandomValue<uint64>();
const auto randomId = base::RandomValue<uint64>();
if (genClientSideMessage) {
if (const auto message = item->toHistoryMessage()) {
const auto newId = FullMsgId(
@@ -3835,7 +3811,7 @@ void ApiWrap::sendSharedContact(
MTP_string(lastName),
MTP_string(), // vcard
MTP_long(userId.bare)),
MTPReplyMarkup());
HistoryMessageMarkupData());
const auto media = MTP_inputMediaContact(
MTP_string(phone),
@@ -4034,7 +4010,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
auto newId = FullMsgId(
peerToChannel(peer->id),
_session->data().nextLocalMessageId());
auto randomId = openssl::RandomValue<uint64>();
auto randomId = base::RandomValue<uint64>();
TextUtilities::Trim(sending);
@@ -4099,7 +4075,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
messagePostAuthor,
sending,
media,
MTPReplyMarkup());
HistoryMessageMarkupData());
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
history->sendRequestId = request(MTPmessages_SendMessage(
MTP_flags(sendFlags),
@@ -4158,7 +4134,7 @@ void ApiWrap::sendBotStart(not_null<UserData*> bot, PeerData *chat) {
sendMessage(std::move(message));
return;
}
const auto randomId = openssl::RandomValue<uint64>();
const auto randomId = base::RandomValue<uint64>();
request(MTPmessages_StartBot(
bot->inputUser,
chat ? chat->input : MTP_inputPeerEmpty(),
@@ -4184,7 +4160,7 @@ void ApiWrap::sendInlineResult(
const auto newId = FullMsgId(
peerToChannel(peer->id),
_session->data().nextLocalMessageId());
const auto randomId = openssl::RandomValue<uint64>();
const auto randomId = base::RandomValue<uint64>();
auto flags = NewMessageFlags(peer);
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
@@ -4340,7 +4316,7 @@ void ApiWrap::sendMedia(
not_null<HistoryItem*> item,
const MTPInputMedia &media,
Api::SendOptions options) {
const auto randomId = openssl::RandomValue<uint64>();
const auto randomId = base::RandomValue<uint64>();
_session->data().registerMessageRandomId(randomId, item->fullId());
sendMediaWithRandomId(item, media, options, randomId);
@@ -4414,7 +4390,7 @@ void ApiWrap::sendAlbumWithUploaded(
const MessageGroupId &groupId,
const MTPInputMedia &media) {
const auto localId = item->fullId();
const auto randomId = openssl::RandomValue<uint64>();
const auto randomId = base::RandomValue<uint64>();
_session->data().registerMessageRandomId(randomId, localId);
const auto albumIt = _sendingAlbums.find(groupId.raw());
@@ -4523,105 +4499,6 @@ FileLoadTo ApiWrap::fileLoadTaskOptions(const SendAction &action) const {
action.replaceMediaOf);
}
void ApiWrap::uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image) {
peer = peer->migrateToOrMe();
const auto ready = PreparePeerPhoto(
instance().mainDcId(),
peer->id,
std::move(image));
const auto fakeId = FullMsgId(
peerToChannel(peer->id),
_session->data().nextLocalMessageId());
const auto already = ranges::find(
_peerPhotoUploads,
peer,
[](const auto &pair) { return pair.second; });
if (already != end(_peerPhotoUploads)) {
_session->uploader().cancel(already->first);
_peerPhotoUploads.erase(already);
}
_peerPhotoUploads.emplace(fakeId, peer);
_session->uploader().uploadMedia(fakeId, ready);
}
void ApiWrap::photoUploadReady(
const FullMsgId &msgId,
const MTPInputFile &file) {
if (const auto maybePeer = _peerPhotoUploads.take(msgId)) {
const auto peer = *maybePeer;
const auto applier = [=](const MTPUpdates &result) {
applyUpdates(result);
};
if (peer->isSelf()) {
request(MTPphotos_UploadProfilePhoto(
MTP_flags(MTPphotos_UploadProfilePhoto::Flag::f_file),
file,
MTPInputFile(), // video
MTPdouble() // video_start_ts
)).done([=](const MTPphotos_Photo &result) {
result.match([&](const MTPDphotos_photo &data) {
_session->data().processPhoto(data.vphoto());
_session->data().processUsers(data.vusers());
});
}).send();
} else if (const auto chat = peer->asChat()) {
const auto history = _session->data().history(chat);
history->sendRequestId = request(MTPmessages_EditChatPhoto(
chat->inputChat,
MTP_inputChatUploadedPhoto(
MTP_flags(MTPDinputChatUploadedPhoto::Flag::f_file),
file,
MTPInputFile(), // video
MTPdouble()) // video_start_ts
)).done(applier).afterRequest(history->sendRequestId).send();
} else if (const auto channel = peer->asChannel()) {
const auto history = _session->data().history(channel);
history->sendRequestId = request(MTPchannels_EditPhoto(
channel->inputChannel,
MTP_inputChatUploadedPhoto(
MTP_flags(MTPDinputChatUploadedPhoto::Flag::f_file),
file,
MTPInputFile(), // video
MTPdouble()) // video_start_ts
)).done(applier).afterRequest(history->sendRequestId).send();
}
}
}
void ApiWrap::clearPeerPhoto(not_null<PhotoData*> photo) {
const auto self = _session->user();
if (self->userpicPhotoId() == photo->id) {
request(MTPphotos_UpdateProfilePhoto(
MTP_inputPhotoEmpty()
)).done([=](const MTPphotos_Photo &result) {
self->setPhoto(MTP_userProfilePhotoEmpty());
}).send();
} else if (photo->peer && photo->peer->userpicPhotoId() == photo->id) {
const auto applier = [=](const MTPUpdates &result) {
applyUpdates(result);
};
if (const auto chat = photo->peer->asChat()) {
request(MTPmessages_EditChatPhoto(
chat->inputChat,
MTP_inputChatPhotoEmpty()
)).done(applier).send();
} else if (const auto channel = photo->peer->asChannel()) {
request(MTPchannels_EditPhoto(
channel->inputChannel,
MTP_inputChatPhotoEmpty()
)).done(applier).send();
}
} else {
request(MTPphotos_DeletePhotos(
MTP_vector<MTPInputPhoto>(1, photo->mtpInput())
)).send();
_session->storage().remove(Storage::UserPhotosRemoveOne(
peerToUser(self->id),
photo->id));
}
}
void ApiWrap::reloadContactSignupSilent() {
if (_contactSignupSilentRequestId) {
return;
@@ -4664,34 +4541,27 @@ void ApiWrap::saveContactSignupSilent(bool silent) {
_contactSignupSilentRequestId = requestId;
}
void ApiWrap::saveSelfBio(const QString &text, FnMut<void()> done) {
if (_saveBioRequestId) {
if (text != _saveBioText) {
request(_saveBioRequestId).cancel();
void ApiWrap::saveSelfBio(const QString &text) {
if (_bio.requestId) {
if (text != _bio.requestedText) {
request(_bio.requestId).cancel();
} else {
if (done) {
_saveBioDone = std::move(done);
}
return;
}
}
_saveBioText = text;
_saveBioDone = std::move(done);
_saveBioRequestId = request(MTPaccount_UpdateProfile(
_bio.requestedText = text;
_bio.requestId = request(MTPaccount_UpdateProfile(
MTP_flags(MTPaccount_UpdateProfile::Flag::f_about),
MTPstring(),
MTPstring(),
MTP_string(text)
)).done([=](const MTPUser &result) {
_saveBioRequestId = 0;
_bio.requestId = 0;
_session->data().processUsers(MTP_vector<MTPUser>(1, result));
_session->user()->setAbout(_saveBioText);
if (_saveBioDone) {
_saveBioDone();
}
_session->data().processUser(result);
_session->user()->setAbout(_bio.requestedText);
}).fail([=](const MTP::Error &error) {
_saveBioRequestId = 0;
_bio.requestId = 0;
}).send();
}
@@ -4731,167 +4601,18 @@ Api::InviteLinks &ApiWrap::inviteLinks() {
return *_inviteLinks;
}
void ApiWrap::createPoll(
const PollData &data,
const SendAction &action,
Fn<void()> done,
Fn<void(const MTP::Error &error)> fail) {
sendAction(action);
const auto history = action.history;
const auto peer = history->peer;
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (action.replyTo) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
const auto clearCloudDraft = action.clearDraft;
if (clearCloudDraft) {
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
history->clearLocalDraft();
history->clearCloudDraft();
history->startSavingCloudDraft();
}
const auto silentPost = ShouldSendSilent(peer, action.options);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
if (action.options.scheduled) {
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
const auto replyTo = action.replyTo;
history->sendRequestId = request(MTPmessages_SendMedia(
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
PollDataToInputMedia(&data),
MTP_string(),
MTP_long(openssl::RandomValue<uint64>()),
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(action.options.scheduled)
)).done([=](
const MTPUpdates &result,
const MTP::Response &response) mutable {
applyUpdates(result);
if (clearCloudDraft) {
history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
}
_session->changes().historyUpdated(
history,
(action.options.scheduled
? Data::HistoryUpdate::Flag::ScheduledSent
: Data::HistoryUpdate::Flag::MessageSent));
done();
finish();
}).fail([=](
const MTP::Error &error,
const MTP::Response &response) mutable {
if (clearCloudDraft) {
history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
}
fail(error);
finish();
}).afterRequest(history->sendRequestId
).send();
return history->sendRequestId;
});
Api::ViewsManager &ApiWrap::views() {
return *_views;
}
void ApiWrap::sendPollVotes(
FullMsgId itemId,
const std::vector<QByteArray> &options) {
if (_pollVotesRequestIds.contains(itemId)) {
return;
}
const auto item = _session->data().message(itemId);
const auto media = item ? item->media() : nullptr;
const auto poll = media ? media->poll() : nullptr;
if (!item) {
return;
}
const auto showSending = poll && !options.empty();
const auto hideSending = [=] {
if (showSending) {
if (const auto item = _session->data().message(itemId)) {
poll->sendingVotes.clear();
_session->data().requestItemRepaint(item);
}
}
};
if (showSending) {
poll->sendingVotes = options;
_session->data().requestItemRepaint(item);
}
auto prepared = QVector<MTPbytes>();
prepared.reserve(options.size());
ranges::transform(
options,
ranges::back_inserter(prepared),
[](const QByteArray &option) { return MTP_bytes(option); });
const auto requestId = request(MTPmessages_SendVote(
item->history()->peer->input,
MTP_int(item->id),
MTP_vector<MTPbytes>(prepared)
)).done([=](const MTPUpdates &result) {
_pollVotesRequestIds.erase(itemId);
hideSending();
applyUpdates(result);
}).fail([=](const MTP::Error &error) {
_pollVotesRequestIds.erase(itemId);
hideSending();
}).send();
_pollVotesRequestIds.emplace(itemId, requestId);
Api::ConfirmPhone &ApiWrap::confirmPhone() {
return *_confirmPhone;
}
void ApiWrap::closePoll(not_null<HistoryItem*> item) {
const auto itemId = item->fullId();
if (_pollCloseRequestIds.contains(itemId)) {
return;
}
const auto media = item ? item->media() : nullptr;
const auto poll = media ? media->poll() : nullptr;
if (!poll) {
return;
}
const auto requestId = request(MTPmessages_EditMessage(
MTP_flags(MTPmessages_EditMessage::Flag::f_media),
item->history()->peer->input,
MTP_int(item->id),
MTPstring(),
PollDataToInputMedia(poll, true),
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(0) // schedule_date
)).done([=](const MTPUpdates &result) {
_pollCloseRequestIds.erase(itemId);
applyUpdates(result);
}).fail([=](const MTP::Error &error) {
_pollCloseRequestIds.erase(itemId);
}).send();
_pollCloseRequestIds.emplace(itemId, requestId);
Api::PeerPhoto &ApiWrap::peerPhoto() {
return *_peerPhoto;
}
void ApiWrap::reloadPollResults(not_null<HistoryItem*> item) {
const auto itemId = item->fullId();
if (!IsServerMsgId(item->id)
|| _pollReloadRequestIds.contains(itemId)) {
return;
}
const auto requestId = request(MTPmessages_GetPollResults(
item->history()->peer->input,
MTP_int(item->id)
)).done([=](const MTPUpdates &result) {
_pollReloadRequestIds.erase(itemId);
applyUpdates(result);
}).fail([=](const MTP::Error &error) {
_pollReloadRequestIds.erase(itemId);
}).send();
_pollReloadRequestIds.emplace(itemId, requestId);
Api::Polls &ApiWrap::polls() {
return *_polls;
}

View File

@@ -62,6 +62,10 @@ class SensitiveContent;
class GlobalPrivacy;
class UserPrivacy;
class InviteLinks;
class ViewsManager;
class ConfirmPhone;
class PeerPhoto;
class Polls;
namespace details {
@@ -381,15 +385,12 @@ public:
uint64 randomId = 0,
FullMsgId itemId = FullMsgId());
void uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image);
void clearPeerPhoto(not_null<PhotoData*> photo);
void reloadContactSignupSilent();
rpl::producer<bool> contactSignupSilent() const;
std::optional<bool> contactSignupSilentCurrent() const;
void saveContactSignupSilent(bool silent);
void saveSelfBio(const QString &text, FnMut<void()> done);
void saveSelfBio(const QString &text);
[[nodiscard]] Api::Authorizations &authorizations();
[[nodiscard]] Api::AttachedStickers &attachedStickers();
@@ -400,17 +401,10 @@ public:
[[nodiscard]] Api::GlobalPrivacy &globalPrivacy();
[[nodiscard]] Api::UserPrivacy &userPrivacy();
[[nodiscard]] Api::InviteLinks &inviteLinks();
void createPoll(
const PollData &data,
const SendAction &action,
Fn<void()> done,
Fn<void(const MTP::Error &error)> fail);
void sendPollVotes(
FullMsgId itemId,
const std::vector<QByteArray> &options);
void closePoll(not_null<HistoryItem*> item);
void reloadPollResults(not_null<HistoryItem*> item);
[[nodiscard]] Api::ViewsManager &views();
[[nodiscard]] Api::ConfirmPhone &confirmPhone();
[[nodiscard]] Api::PeerPhoto &peerPhoto();
[[nodiscard]] Api::Polls &polls();
void updatePrivacyLastSeens();
@@ -456,7 +450,6 @@ private:
void saveDraftsToCloud();
void resolveMessageDatas();
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId requestId);
void finalizeMessageDataRequest(
ChannelData *channel,
mtpRequestId requestId);
@@ -573,8 +566,6 @@ private:
FileReferencesHandler &&handler,
Request &&data);
void photoUploadReady(const FullMsgId &msgId, const MTPInputFile &file);
void migrateDone(
not_null<PeerData*> peer,
not_null<ChannelData*> channel);
@@ -705,11 +696,10 @@ private:
std::vector<FnMut<void(const MTPUser &)>> _supportContactCallbacks;
base::flat_map<FullMsgId, not_null<PeerData*>> _peerPhotoUploads;
mtpRequestId _saveBioRequestId = 0;
FnMut<void()> _saveBioDone;
QString _saveBioText;
struct {
mtpRequestId requestId = 0;
QString requestedText;
} _bio;
const std::unique_ptr<Api::Authorizations> _authorizations;
const std::unique_ptr<Api::AttachedStickers> _attachedStickers;
@@ -720,10 +710,10 @@ private:
const std::unique_ptr<Api::GlobalPrivacy> _globalPrivacy;
const std::unique_ptr<Api::UserPrivacy> _userPrivacy;
const std::unique_ptr<Api::InviteLinks> _inviteLinks;
base::flat_map<FullMsgId, mtpRequestId> _pollVotesRequestIds;
base::flat_map<FullMsgId, mtpRequestId> _pollCloseRequestIds;
base::flat_map<FullMsgId, mtpRequestId> _pollReloadRequestIds;
const std::unique_ptr<Api::ViewsManager> _views;
const std::unique_ptr<Api::ConfirmPhone> _confirmPhone;
const std::unique_ptr<Api::PeerPhoto> _peerPhoto;
const std::unique_ptr<Api::Polls> _polls;
mtpRequestId _wallPaperRequestId = 0;
QString _wallPaperSlug;

View File

@@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/text/text_utilities.h"
@@ -104,7 +104,8 @@ void AboutBox::showVersionHistory() {
QGuiApplication::clipboard()->setText(url);
Ui::show(Box<InformBox>("The link to the current private alpha version of Telegram Desktop was copied to the clipboard."));
Ui::show(Box<Ui::InformBox>("The link to the current private alpha "
"version of Telegram Desktop was copied to the clipboard."));
} else {
UrlClickHandler::Open(Core::App().changelogLink());
}

View File

@@ -0,0 +1,68 @@
/*
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 "boxes/about_sponsored_box.h"
#include "lang/lang_keys.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "styles/style_boxes.h"
#include "styles/style_layers.h"
#include <QtGui/QDesktopServices>
namespace Ui {
namespace {
constexpr auto kUrl = "https://telegram.org/ads"_cs;
} // namespace
void AboutSponsoredBox(not_null<Ui::GenericBox*> box) {
box->setTitle(tr::lng_sponsored_title());
box->setWidth(st::boxWideWidth);
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
const auto addUrl = [&] {
const auto &st = st::sponsoredUrlButton;
const auto row = box->addRow(object_ptr<RpWidget>(box));
row->resize(0, st.height + st.padding.top() + st.padding.bottom());
const auto button = Ui::CreateChild<RoundButton>(
row,
rpl::single<QString>(kUrl.utf8()),
st);
button->setBrushOverride(Qt::NoBrush);
button->setPenOverride(QPen(st::historyLinkInFg));
button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
rpl::combine(
row->sizeValue(),
button->sizeValue()
) | rpl::start_with_next([=](
const QSize &rowSize,
const QSize &buttonSize) {
button->moveToLeft(
(rowSize.width() - buttonSize.width()) / 2,
(rowSize.height() - buttonSize.height()) / 2);
}, row->lifetime());
button->addClickHandler([=] {
QDesktopServices::openUrl({ kUrl.utf8() });
});
};
const auto &stLabel = st::aboutLabel;
const auto info1 = box->addRow(object_ptr<FlatLabel>(box, stLabel));
info1->setText(tr::lng_sponsored_info_description1(tr::now));
box->addSkip(st::sponsoredUrlButtonSkip);
addUrl();
box->addSkip(st::sponsoredUrlButtonSkip);
const auto info2 = box->addRow(object_ptr<FlatLabel>(box, stLabel));
info2->setText(tr::lng_sponsored_info_description2(tr::now));
}
} // namespace Ui

View File

@@ -0,0 +1,16 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ui/layers/generic_box.h"
namespace Ui {
void AboutSponsoredBox(not_null<Ui::GenericBox*> box);
} // namespace Ui

View File

@@ -8,15 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/add_contact_box.h"
#include "lang/lang_keys.h"
#include "mtproto/sender.h"
#include "base/flat_set.h"
#include "base/openssl_help.h"
#include "boxes/confirm_box.h"
#include "base/random.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/add_participants_box.h"
#include "boxes/peers/edit_peer_common.h"
#include "boxes/peers/edit_participant_box.h"
#include "boxes/peers/edit_participants_box.h"
#include "core/file_utilities.h"
#include "core/application.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "countries/countries_instance.h" // Countries::ExtractPhoneCode.
@@ -36,26 +34,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_changes.h"
#include "data/data_cloud_file.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "apiwrap.h"
#include "api/api_invite_links.h"
#include "api/api_peer_photo.h"
#include "main/main_session.h"
#include "facades.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_dialogs.h"
#include "styles/style_widgets.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QClipboard>
namespace {
constexpr auto kMaxGroupChannelTitle = 128; // See also edit_peer_info_box.
constexpr auto kMaxUserFirstLastName = 64; // See also edit_contact_box.
constexpr auto kMaxChannelDescription = 255; // See also edit_peer_info_box.
constexpr auto kMinUsernameLength = 5;
bool IsValidPhone(QString phone) {
phone = phone.replace(QRegularExpression(qsl("[^\\d]")), QString());
return (phone.length() >= 8)
@@ -73,7 +66,7 @@ void ChatCreateDone(
const MTPUpdates &updates) {
navigation->session().api().applyUpdates(updates);
auto success = base::make_optional(&updates)
const auto success = base::make_optional(&updates)
| [](auto updates) -> std::optional<const QVector<MTPChat>*> {
switch (updates->type()) {
case mtpc_updates:
@@ -97,7 +90,7 @@ void ChatCreateDone(
}
| [&](not_null<ChatData*> chat) {
if (!image.isNull()) {
chat->session().api().uploadPeerPhoto(
chat->session().api().peerPhoto().upload(
chat,
std::move(image));
}
@@ -164,7 +157,7 @@ void ShowAddParticipantsError(
*weak = Ui::show(std::move(box));
};
Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_cant_invite_offer_admin(tr::now),
tr::lng_cant_invite_make_admin(tr::now),
tr::lng_cancel(tr::now),
@@ -203,7 +196,7 @@ void ShowAddParticipantsError(
}
return tr::lng_failed_add_participant(tr::now);
}();
Ui::show(Box<InformBox>(text), Ui::LayerOption::KeepOther);
Ui::show(Box<Ui::InformBox>(text), Ui::LayerOption::KeepOther);
}
class RevokePublicLinkBox::Inner : public TWidget {
@@ -280,7 +273,8 @@ void AddContactBox::prepare() {
setTabOrder(_last, _first);
}
const auto readyToAdd = !_phone->getLastText().isEmpty()
&& (!_first->getLastText().isEmpty() || !_last->getLastText().isEmpty());
&& (!_first->getLastText().isEmpty()
|| !_last->getLastText().isEmpty());
setTitle(readyToAdd
? tr::lng_confirm_contact_data()
: tr::lng_enter_contact_data());
@@ -290,11 +284,21 @@ void AddContactBox::prepare() {
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
setDimensions(st::boxWideWidth, st::contactPadding.top() + _first->height() + st::contactSkip + _last->height() + st::contactPhoneSkip + _phone->height() + st::contactPadding.bottom() + st::boxPadding.bottom());
setDimensions(
st::boxWideWidth,
st::contactPadding.top()
+ _first->height()
+ st::contactSkip
+ _last->height()
+ st::contactPhoneSkip
+ _phone->height()
+ st::contactPadding.bottom()
+ st::boxPadding.bottom());
}
void AddContactBox::setInnerFocus() {
if ((_first->getLastText().isEmpty() && _last->getLastText().isEmpty()) || !_phone->isEnabled()) {
if ((_first->getLastText().isEmpty() && _last->getLastText().isEmpty())
|| !_phone->isEnabled()) {
(_invertOrder ? _last : _first)->setFocusFast();
_phone->finishAnimating();
} else {
@@ -309,8 +313,18 @@ void AddContactBox::paintEvent(QPaintEvent *e) {
if (_retrying) {
p.setPen(st::boxTextFg);
p.setFont(st::boxTextFont);
auto textHeight = height() - st::contactPadding.top() - st::contactPadding.bottom() - st::boxPadding.bottom();
p.drawText(QRect(st::boxPadding.left(), st::contactPadding.top(), width() - st::boxPadding.left() - st::boxPadding.right(), textHeight), tr::lng_contact_not_joined(tr::now, lt_name, _sentName), style::al_topleft);
const auto textHeight = height()
- st::contactPadding.top()
- st::contactPadding.bottom()
- st::boxPadding.bottom();
p.drawText(
QRect(
st::boxPadding.left(),
st::contactPadding.top(),
width() - st::boxPadding.left() - st::boxPadding.right(),
textHeight),
tr::lng_contact_not_joined(tr::now, lt_name, _sentName),
style::al_topleft);
} else {
st::contactUserIcon.paint(
p,
@@ -328,18 +342,25 @@ void AddContactBox::paintEvent(QPaintEvent *e) {
void AddContactBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_first->resize(width() - st::boxPadding.left() - st::contactPadding.left() - st::boxPadding.right(), _first->height());
_first->resize(
width()
- st::boxPadding.left()
- st::contactPadding.left()
- st::boxPadding.right(),
_first->height());
_last->resize(_first->width(), _last->height());
_phone->resize(_first->width(), _last->height());
if (_invertOrder) {
_last->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), st::contactPadding.top());
_first->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _last->y() + _last->height() + st::contactSkip);
_phone->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _first->y() + _first->height() + st::contactPhoneSkip);
} else {
_first->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), st::contactPadding.top());
_last->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _first->y() + _first->height() + st::contactSkip);
_phone->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _last->y() + _last->height() + st::contactPhoneSkip);
}
const auto left = st::boxPadding.left() + st::contactPadding.left();
const auto &firstRow = _invertOrder ? _last : _first;
const auto &secondRow = _invertOrder ? _first : _last;
const auto &thirdRow = _phone;
firstRow->moveToLeft(left, st::contactPadding.top());
secondRow->moveToLeft(
left,
firstRow->y() + firstRow->height() + st::contactSkip);
thirdRow->moveToLeft(
left,
secondRow->y() + secondRow->height() + st::contactPhoneSkip);
}
void AddContactBox::submit() {
@@ -361,9 +382,11 @@ void AddContactBox::save() {
return;
}
auto firstName = TextUtilities::PrepareForSending(_first->getLastText());
auto lastName = TextUtilities::PrepareForSending(_last->getLastText());
auto phone = _phone->getLastText().trimmed();
auto firstName = TextUtilities::PrepareForSending(
_first->getLastText());
auto lastName = TextUtilities::PrepareForSending(
_last->getLastText());
const auto phone = _phone->getLastText().trimmed();
if (firstName.isEmpty() && lastName.isEmpty()) {
if (_invertOrder) {
_last->setFocus();
@@ -383,7 +406,7 @@ void AddContactBox::save() {
lastName = QString();
}
_sentName = firstName;
_contactId = openssl::RandomValue<uint64>();
_contactId = base::RandomValue<uint64>();
_addRequest = _session->api().request(MTPcontacts_ImportContacts(
MTP_vector<MTPInputContact>(
1,
@@ -478,7 +501,7 @@ void GroupInfoBox::prepare() {
? tr::lng_dlg_new_channel_name
: tr::lng_dlg_new_group_name)(),
_initialTitle);
_title->setMaxLength(kMaxGroupChannelTitle);
_title->setMaxLength(Ui::EditPeer::kMaxGroupChannelTitle);
_title->setInstantReplaces(Ui::InstantReplaces::Default());
_title->setInstantReplacesEnabled(
Core::App().settings().replaceEmojiValue());
@@ -494,16 +517,22 @@ void GroupInfoBox::prepare() {
Ui::InputField::Mode::MultiLine,
tr::lng_create_group_description());
_description->show();
_description->setMaxLength(kMaxChannelDescription);
_description->setMaxLength(Ui::EditPeer::kMaxChannelDescription);
_description->setInstantReplaces(Ui::InstantReplaces::Default());
_description->setInstantReplacesEnabled(
Core::App().settings().replaceEmojiValue());
_description->setSubmitSettings(
Core::App().settings().sendSubmitWay());
connect(_description, &Ui::InputField::resized, [=] { descriptionResized(); });
connect(_description, &Ui::InputField::submitted, [=] { submit(); });
connect(_description, &Ui::InputField::cancelled, [=] { closeBox(); });
connect(_description, &Ui::InputField::resized, [=] {
descriptionResized();
});
connect(_description, &Ui::InputField::submitted, [=] {
submit();
});
connect(_description, &Ui::InputField::cancelled, [=] {
closeBox();
});
Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(),
@@ -530,17 +559,34 @@ void GroupInfoBox::setInnerFocus() {
void GroupInfoBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_photo->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top());
_photo->moveToLeft(
st::boxPadding.left() + st::newGroupInfoPadding.left(),
st::boxPadding.top() + st::newGroupInfoPadding.top());
auto nameLeft = st::defaultUserpicButton.size.width()
const auto nameLeft = st::defaultUserpicButton.size.width()
+ st::newGroupNamePosition.x();
_title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right() - nameLeft, _title->height());
_title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y());
_title->resize(
width()
- st::boxPadding.left()
- st::newGroupInfoPadding.left()
- st::boxPadding.right()
- nameLeft,
_title->height());
_title->moveToLeft(
st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft,
st::boxPadding.top()
+ st::newGroupInfoPadding.top()
+ st::newGroupNamePosition.y());
if (_description) {
_description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description->height());
auto descriptionLeft = st::boxPadding.left()
_description->resize(
width()
- st::boxPadding.left()
- st::newGroupInfoPadding.left()
- st::boxPadding.right(),
_description->height());
const auto descriptionLeft = st::boxPadding.left()
+ st::newGroupInfoPadding.left();
auto descriptionTop = st::boxPadding.top()
const auto descriptionTop = st::boxPadding.top()
+ st::newGroupInfoPadding.top()
+ st::defaultUserpicButton.size.height()
+ st::newGroupDescriptionPadding.top();
@@ -596,18 +642,18 @@ void GroupInfoBox::createGroup(
}
} else if (error.type() == qstr("USERS_TOO_FEW")) {
Ui::show(
Box<InformBox>(tr::lng_cant_invite_privacy(tr::now)),
Box<Ui::InformBox>(tr::lng_cant_invite_privacy(tr::now)),
Ui::LayerOption::KeepOther);
} else if (error.type() == qstr("PEER_FLOOD")) {
Ui::show(
Box<InformBox>(
Box<Ui::InformBox>(
PeerFloodErrorText(
&_navigation->session(),
PeerFloodType::InviteGroup)),
Ui::LayerOption::KeepOther);
} else if (error.type() == qstr("USER_RESTRICTED")) {
Ui::show(
Box<InformBox>(tr::lng_cant_do_this(tr::now)),
Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now)),
Ui::LayerOption::KeepOther);
}
}).send();
@@ -654,7 +700,9 @@ void GroupInfoBox::submit() {
}
}
void GroupInfoBox::createChannel(const QString &title, const QString &description) {
void GroupInfoBox::createChannel(
const QString &title,
const QString &description) {
Expects(!_creationRequestId);
const auto flags = (_type == Type::Megagroup)
@@ -677,11 +725,13 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
case mtpc_updatesCombined:
return &updates->c_updatesCombined().vchats().v;
}
LOG(("API Error: unexpected update cons %1 (GroupInfoBox::createChannel)").arg(updates->type()));
LOG(("API Error: unexpected update cons %1 "
"(GroupInfoBox::createChannel)").arg(updates->type()));
return std::nullopt;
}
| [](auto chats) {
return (!chats->empty() && chats->front().type() == mtpc_channel)
return (!chats->empty()
&& chats->front().type() == mtpc_channel)
? base::make_optional(chats)
: std::nullopt;
}
@@ -692,7 +742,7 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
| [&](not_null<ChannelData*> channel) {
auto image = _photo->takeResultImage();
if (!image.isNull()) {
channel->session().api().uploadPeerPhoto(
channel->session().api().peerPhoto().upload(
channel,
std::move(image));
}
@@ -700,7 +750,8 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
checkInviteLink();
};
if (!success) {
LOG(("API Error: channel not found in updates (GroupInfoBox::creationDone)"));
LOG(("API Error: channel not found in updates "
"(GroupInfoBox::creationDone)"));
closeBox();
}
}).fail([this](const MTP::Error &error) {
@@ -709,9 +760,9 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
_title->setFocus();
_title->showError();
} else if (error.type() == qstr("USER_RESTRICTED")) {
Ui::show(Box<InformBox>(tr::lng_cant_do_this(tr::now)));
Ui::show(Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now)));
} else if (error.type() == qstr("CHANNELS_TOO_MUCH")) {
Ui::show(Box<InformBox>(tr::lng_cant_do_this(tr::now))); // TODO
Ui::show(Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now))); // TODO
}
}).send();
}
@@ -813,7 +864,8 @@ SetupChannelBox::SetupChannelBox(
st::setupChannelLink,
nullptr,
channel->username,
channel->session().createInternalLink(QString())) {
channel->session().createInternalLink(QString()))
, _checkTimer([=] { check(); }) {
}
void SetupChannelBox::prepare() {
@@ -825,7 +877,8 @@ void SetupChannelBox::prepare() {
_channel->inputChannel,
MTP_string("preston")
)).fail([=](const MTP::Error &error) {
firstCheckFail(error);
_checkRequestId = 0;
firstCheckFail(error.type());
}).send();
addButton(tr::lng_settings_save(), [=] { save(); });
@@ -836,10 +889,9 @@ void SetupChannelBox::prepare() {
connect(_link, &Ui::MaskedInputField::changed, [=] { handleChange(); });
_link->setVisible(_privacyGroup->value() == Privacy::Public);
_checkTimer.setSingleShot(true);
connect(&_checkTimer, &QTimer::timeout, [=] { check(); });
_privacyGroup->setChangedCallback([this](Privacy value) { privacyChanged(value); });
_privacyGroup->setChangedCallback([=](Privacy value) {
privacyChanged(value);
});
_channel->session().changes().peerUpdates(
_channel,
@@ -866,9 +918,20 @@ void SetupChannelBox::setInnerFocus() {
}
void SetupChannelBox::updateMaxHeight() {
auto newHeight = st::boxPadding.top() + st::newGroupPadding.top() + _public->heightNoMargins() + _aboutPublicHeight + st::newGroupSkip + _private->heightNoMargins() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom();
if (!_channel->isMegagroup() || _privacyGroup->value() == Privacy::Public) {
newHeight += st::newGroupLinkPadding.top() + _link->height() + st::newGroupLinkPadding.bottom();
auto newHeight = st::boxPadding.top()
+ st::newGroupPadding.top()
+ _public->heightNoMargins()
+ _aboutPublicHeight
+ st::newGroupSkip
+ _private->heightNoMargins()
+ _aboutPrivate.countHeight(_aboutPublicWidth)
+ st::newGroupSkip
+ st::newGroupPadding.bottom();
if (!_channel->isMegagroup()
|| _privacyGroup->value() == Privacy::Public) {
newHeight += st::newGroupLinkPadding.top()
+ _link->height()
+ st::newGroupLinkPadding.bottom();
}
setDimensions(st::boxWideWidth, newHeight);
}
@@ -894,17 +957,43 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) {
p.fillRect(e->rect(), st::boxBg);
p.setPen(st::newGroupAboutFg);
QRect aboutPublic(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadio.diameter + st::defaultBoxCheckbox.textPosition.x(), _public->bottomNoMargins(), _aboutPublicWidth, _aboutPublicHeight);
_aboutPublic.drawLeft(p, aboutPublic.x(), aboutPublic.y(), aboutPublic.width(), width());
const auto aboutPublic = QRect(
st::boxPadding.left()
+ st::newGroupPadding.left()
+ st::defaultRadio.diameter
+ st::defaultBoxCheckbox.textPosition.x(),
_public->bottomNoMargins(),
_aboutPublicWidth,
_aboutPublicHeight);
_aboutPublic.drawLeft(
p,
aboutPublic.x(),
aboutPublic.y(),
aboutPublic.width(),
width());
QRect aboutPrivate(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadio.diameter + st::defaultBoxCheckbox.textPosition.x(), _private->bottomNoMargins(), _aboutPublicWidth, _aboutPublicHeight);
_aboutPrivate.drawLeft(p, aboutPrivate.x(), aboutPrivate.y(), aboutPrivate.width(), width());
const auto aboutPrivate = QRect(
st::boxPadding.left()
+ st::newGroupPadding.left()
+ st::defaultRadio.diameter
+ st::defaultBoxCheckbox.textPosition.x(),
_private->bottomNoMargins(),
_aboutPublicWidth,
_aboutPublicHeight);
_aboutPrivate.drawLeft(
p,
aboutPrivate.x(),
aboutPrivate.y(),
aboutPrivate.width(),
width());
if (!_channel->isMegagroup() || !_link->isHidden()) {
p.setPen(st::boxTextFg);
p.setFont(st::newGroupLinkFont);
p.drawTextLeft(
st::boxPadding.left() + st::newGroupPadding.left() + st::defaultInputField.textMargins.left(),
st::boxPadding.left()
+ st::newGroupPadding.left()
+ st::defaultInputField.textMargins.left(),
_link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop,
width(),
(_link->isHidden()
@@ -916,20 +1005,29 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) {
if (!_channel->isMegagroup()) {
QTextOption option(style::al_left);
option.setWrapMode(QTextOption::WrapAnywhere);
p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont);
p.setFont(_linkOver
? st::boxTextFont->underline()
: st::boxTextFont);
p.setPen(st::defaultLinkButton.color);
auto inviteLinkText = _channel->inviteLink().isEmpty() ? tr::lng_group_invite_create(tr::now) : _channel->inviteLink();
const auto inviteLinkText = _channel->inviteLink().isEmpty()
? tr::lng_group_invite_create(tr::now)
: _channel->inviteLink();
p.drawText(_invitationLink, inviteLinkText, option);
}
} else {
const auto top = _link->y()
- st::newGroupLinkPadding.top()
+ st::newGroupLinkTop
+ st::newGroupLinkFont->ascent
- st::boxTextFont->ascent;
if (!_errorText.isEmpty()) {
p.setPen(st::boxTextFgError);
p.setFont(st::boxTextFont);
p.drawTextRight(st::boxPadding.right(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _errorText);
p.drawTextRight(st::boxPadding.right(), top, width(), _errorText);
} else if (!_goodText.isEmpty()) {
p.setPen(st::boxTextFgGood);
p.setFont(st::boxTextFont);
p.drawTextRight(st::boxPadding.right(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodText);
p.drawTextRight(st::boxPadding.right(), top, width(), _goodText);
}
}
}
@@ -937,12 +1035,32 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) {
void SetupChannelBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_public->moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top());
_private->moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _public->bottomNoMargins() + _aboutPublicHeight + st::newGroupSkip);
const auto left = st::boxPadding.left() + st::newGroupPadding.left();
_public->moveToLeft(
left,
st::boxPadding.top() + st::newGroupPadding.top());
_private->moveToLeft(
left,
_public->bottomNoMargins() + _aboutPublicHeight + st::newGroupSkip);
_link->resize(width() - st::boxPadding.left() - st::newGroupLinkPadding.left() - st::boxPadding.right(), _link->height());
_link->moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _private->bottomNoMargins() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top());
_invitationLink = QRect(_link->x(), _link->y() + (_link->height() / 2) - st::boxTextFont->height, _link->width(), 2 * st::boxTextFont->height);
_link->resize(
width()
- st::boxPadding.left()
- st::newGroupLinkPadding.left()
- st::boxPadding.right(),
_link->height());
_link->moveToLeft(
st::boxPadding.left() + st::newGroupLinkPadding.left(),
_private->bottomNoMargins()
+ _aboutPrivate.countHeight(_aboutPublicWidth)
+ st::newGroupSkip
+ st::newGroupPadding.bottom()
+ st::newGroupLinkPadding.top());
_invitationLink = QRect(
_link->x(),
_link->y() + (_link->height() / 2) - st::boxTextFont->height,
_link->width(),
2 * st::boxTextFont->height);
}
void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) {
@@ -982,9 +1100,13 @@ void SetupChannelBox::save() {
_channel->inputChannel,
MTP_string(_sentUsername)
)).done([=](const MTPBool &result) {
updateDone(result);
_channel->setName(
TextUtilities::SingleLine(_channel->name),
_sentUsername);
closeBox();
}).fail([=](const MTP::Error &error) {
updateFail(error);
_saveRequestId = 0;
updateFail(error.type());
}).send();
};
if (_saveRequestId) {
@@ -1007,38 +1129,45 @@ void SetupChannelBox::save() {
}
void SetupChannelBox::handleChange() {
QString name = _link->text().trimmed();
const auto name = _link->text().trimmed();
if (name.isEmpty()) {
if (!_errorText.isEmpty() || !_goodText.isEmpty()) {
_errorText = _goodText = QString();
update();
}
_checkTimer.stop();
_checkTimer.cancel();
} else {
int32 len = name.size();
for (int32 i = 0; i < len; ++i) {
QChar ch = name.at(i);
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') {
if (_errorText != tr::lng_create_channel_link_bad_symbols(tr::now)) {
_errorText = tr::lng_create_channel_link_bad_symbols(tr::now);
const auto len = int(name.size());
for (auto i = 0; i < len; ++i) {
const auto ch = name.at(i);
if ((ch < 'A' || ch > 'Z')
&& (ch < 'a' || ch > 'z')
&& (ch < '0' || ch > '9')
&& ch != '_') {
const auto badSymbols =
tr::lng_create_channel_link_bad_symbols(tr::now);
if (_errorText != badSymbols) {
_errorText = badSymbols;
update();
}
_checkTimer.stop();
_checkTimer.cancel();
return;
}
}
if (name.size() < kMinUsernameLength) {
if (_errorText != tr::lng_create_channel_link_too_short(tr::now)) {
_errorText = tr::lng_create_channel_link_too_short(tr::now);
if (name.size() < Ui::EditPeer::kMinUsernameLength) {
const auto tooShort =
tr::lng_create_channel_link_too_short(tr::now);
if (_errorText != tooShort) {
_errorText = tooShort;
update();
}
_checkTimer.stop();
_checkTimer.cancel();
} else {
if (!_errorText.isEmpty() || !_goodText.isEmpty()) {
_errorText = _goodText = QString();
update();
}
_checkTimer.start(UsernameCheckTimeout);
_checkTimer.callOnce(Ui::EditPeer::kUsernameCheckTimeout);
}
}
}
@@ -1047,16 +1176,25 @@ void SetupChannelBox::check() {
if (_checkRequestId) {
_channel->session().api().request(_checkRequestId).cancel();
}
QString link = _link->text().trimmed();
if (link.size() >= kMinUsernameLength) {
const auto link = _link->text().trimmed();
if (link.size() >= Ui::EditPeer::kMinUsernameLength) {
_checkUsername = link;
_checkRequestId = _api.request(MTPchannels_CheckUsername(
_channel->inputChannel,
MTP_string(link)
)).done([=](const MTPBool &result) {
checkDone(result);
_checkRequestId = 0;
_errorText = (mtpIsTrue(result)
|| _checkUsername == _channel->username)
? QString()
: tr::lng_create_channel_link_occupied(tr::now);
_goodText = _errorText.isEmpty()
? tr::lng_create_channel_link_available(tr::now)
: QString();
update();
}).fail([=](const MTP::Error &error) {
checkFail(error);
_checkRequestId = 0;
checkFail(error.type());
}).send();
}
}
@@ -1090,26 +1228,20 @@ void SetupChannelBox::privacyChanged(Privacy value) {
update();
}
void SetupChannelBox::updateDone(const MTPBool &result) {
_channel->setName(TextUtilities::SingleLine(_channel->name), _sentUsername);
closeBox();
}
void SetupChannelBox::updateFail(const MTP::Error &error) {
_saveRequestId = 0;
QString err(error.type());
if (err == "USERNAME_NOT_MODIFIED"
|| _sentUsername == _channel->username) {
void SetupChannelBox::updateFail(const QString &error) {
if ((error == "USERNAME_NOT_MODIFIED")
|| (_sentUsername == _channel->username)) {
_channel->setName(
TextUtilities::SingleLine(_channel->name),
TextUtilities::SingleLine(_sentUsername));
closeBox();
} else if (err == "USERNAME_INVALID") {
} else if (error == "USERNAME_INVALID") {
_link->setFocus();
_link->showError();
_errorText = tr::lng_create_channel_link_invalid(tr::now);
update();
} else if (err == "USERNAME_OCCUPIED" || err == "USERNAMES_UNAVAILABLE") {
} else if ((error == "USERNAME_OCCUPIED")
|| (error == "USERNAMES_UNAVAILABLE")) {
_link->setFocus();
_link->showError();
_errorText = tr::lng_create_channel_link_occupied(tr::now);
@@ -1119,33 +1251,21 @@ void SetupChannelBox::updateFail(const MTP::Error &error) {
}
}
void SetupChannelBox::checkDone(const MTPBool &result) {
_checkRequestId = 0;
QString newError = (mtpIsTrue(result) || _checkUsername == _channel->username) ? QString() : tr::lng_create_channel_link_occupied(tr::now);
QString newGood = newError.isEmpty() ? tr::lng_create_channel_link_available(tr::now) : QString();
if (_errorText != newError || _goodText != newGood) {
_errorText = newError;
_goodText = newGood;
update();
}
}
void SetupChannelBox::checkFail(const MTP::Error &error) {
_checkRequestId = 0;
QString err(error.type());
if (err == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
void SetupChannelBox::checkFail(const QString &error) {
if (error == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
Ui::hideLayer();
} else if (err == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
} else if (error == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
if (_existing) {
showRevokePublicLinkBoxForEdit();
} else {
_tooMuchUsernames = true;
_privacyGroup->setValue(Privacy::Private);
}
} else if (err == qstr("USERNAME_INVALID")) {
} else if (error == qstr("USERNAME_INVALID")) {
_errorText = tr::lng_create_channel_link_invalid(tr::now);
update();
} else if (err == qstr("USERNAME_OCCUPIED") && _checkUsername != _channel->username) {
} else if (error == qstr("USERNAME_OCCUPIED")
&& _checkUsername != _channel->username) {
_errorText = tr::lng_create_channel_link_occupied(tr::now);
update();
} else {
@@ -1171,12 +1291,10 @@ void SetupChannelBox::showRevokePublicLinkBoxForEdit() {
Ui::LayerOption::KeepOther);
}
void SetupChannelBox::firstCheckFail(const MTP::Error &error) {
_checkRequestId = 0;
const auto &type = error.type();
if (type == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
void SetupChannelBox::firstCheckFail(const QString &error) {
if (error == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
Ui::hideLayer();
} else if (type == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
} else if (error == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
if (_existing) {
showRevokePublicLinkBoxForEdit();
} else {
@@ -1192,8 +1310,16 @@ void SetupChannelBox::firstCheckFail(const MTP::Error &error) {
EditNameBox::EditNameBox(QWidget*, not_null<UserData*> user)
: _user(user)
, _api(&_user->session().mtp())
, _first(this, st::defaultInputField, tr::lng_signup_firstname(), _user->firstName)
, _last(this, st::defaultInputField, tr::lng_signup_lastname(), _user->lastName)
, _first(
this,
st::defaultInputField,
tr::lng_signup_firstname(),
_user->firstName)
, _last(
this,
st::defaultInputField,
tr::lng_signup_lastname(),
_user->lastName)
, _invertOrder(langFirstNameGoesSecond()) {
}
@@ -1211,8 +1337,8 @@ void EditNameBox::prepare() {
if (_invertOrder) {
setTabOrder(_last, _first);
}
_first->setMaxLength(kMaxUserFirstLastName);
_last->setMaxLength(kMaxUserFirstLastName);
_first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
_last->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
@@ -1241,19 +1367,28 @@ void EditNameBox::submit() {
void EditNameBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_first->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _first->height());
_first->resize(
width()
- st::boxPadding.left()
- st::newGroupInfoPadding.left()
- st::boxPadding.right(),
_first->height());
_last->resize(_first->size());
const auto left = st::boxPadding.left() + st::newGroupInfoPadding.left();
const auto skip = st::contactSkip;
if (_invertOrder) {
_last->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::contactPadding.top());
_first->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _last->y() + _last->height() + st::contactSkip);
_last->moveToLeft(left, st::contactPadding.top());
_first->moveToLeft(left, _last->y() + _last->height() + skip);
} else {
_first->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::contactPadding.top());
_last->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _first->y() + _first->height() + st::contactSkip);
_first->moveToLeft(left, st::contactPadding.top());
_last->moveToLeft(left, _first->y() + _first->height() + skip);
}
}
void EditNameBox::save() {
if (_requestId) return;
if (_requestId) {
return;
}
auto first = TextUtilities::PrepareForSending(_first->getLastText());
auto last = TextUtilities::PrepareForSending(_last->getLastText());
@@ -1279,29 +1414,27 @@ void EditNameBox::save() {
MTP_string(first),
MTP_string(last),
MTPstring()
)).done([=](const MTPUser &result) {
saveSelfDone(result);
)).done([=](const MTPUser &user) {
_user->owner().processUser(user);
closeBox();
}).fail([=](const MTP::Error &error) {
saveSelfFail(error);
_requestId = 0;
saveSelfFail(error.type());
}).send();
}
void EditNameBox::saveSelfDone(const MTPUser &user) {
_user->owner().processUsers(MTP_vector<MTPUser>(1, user));
closeBox();
}
void EditNameBox::saveSelfFail(const MTP::Error &error) {
auto err = error.type();
auto first = TextUtilities::SingleLine(_first->getLastText().trimmed());
auto last = TextUtilities::SingleLine(_last->getLastText().trimmed());
if (err == "NAME_NOT_MODIFIED") {
_user->setName(first, last, QString(), TextUtilities::SingleLine(_user->username));
void EditNameBox::saveSelfFail(const QString &error) {
if (error == "NAME_NOT_MODIFIED") {
_user->setName(
TextUtilities::SingleLine(_first->getLastText().trimmed()),
TextUtilities::SingleLine(_last->getLastText().trimmed()),
QString(),
TextUtilities::SingleLine(_user->username));
closeBox();
} else if (err == "FIRSTNAME_INVALID") {
} else if (error == "FIRSTNAME_INVALID") {
_first->setFocus();
_first->showError();
} else if (err == "LASTNAME_INVALID") {
} else if (error == "LASTNAME_INVALID") {
_last->setFocus();
_last->showError();
} else {
@@ -1316,8 +1449,11 @@ RevokePublicLinkBox::Inner::Inner(
: TWidget(parent)
, _session(session)
, _api(&_session->mtp())
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _revokeWidth(st::normalFont->width(tr::lng_channels_too_much_public_revoke(tr::now)))
, _rowHeight(st::contactsPadding.top()
+ st::contactsPhotoSize
+ st::contactsPadding.bottom())
, _revokeWidth(st::normalFont->width(
tr::lng_channels_too_much_public_revoke(tr::now)))
, _revokeCallback(std::move(revokeCallback)) {
setMouseTracking(true);
@@ -1367,7 +1503,9 @@ RevokePublicLinkBox::RevokePublicLinkBox(
}
void RevokePublicLinkBox::prepare() {
_innerTop = st::boxPadding.top() + _aboutRevoke->height() + st::boxPadding.top();
_innerTop = st::boxPadding.top()
+ _aboutRevoke->height()
+ st::boxPadding.top();
_inner = setInnerWidget(object_ptr<Inner>(this, _session, [=] {
const auto callback = _revokeCallback;
closeBox();
@@ -1392,11 +1530,21 @@ void RevokePublicLinkBox::Inner::mouseMoveEvent(QMouseEvent *e) {
}
void RevokePublicLinkBox::Inner::updateSelected() {
auto point = mapFromGlobal(QCursor::pos());
const auto point = mapFromGlobal(QCursor::pos());
PeerData *selected = nullptr;
auto top = _rowsTop;
for (const auto &row : _rows) {
auto revokeLink = style::rtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - _revokeWidth, top + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, _revokeWidth, st::normalFont->height, width());
const auto revokeLink = style::rtlrect(
width()
- st::contactsPadding.right()
- st::contactsCheckPosition.x()
- _revokeWidth,
top
+ st::contactsPadding.top()
+ (st::contactsPhotoSize - st::normalFont->height) / 2,
_revokeWidth,
st::normalFont->height,
width());
if (revokeLink.contains(point)) {
selected = row.peer;
break;
@@ -1405,7 +1553,9 @@ void RevokePublicLinkBox::Inner::updateSelected() {
}
if (selected != _selected) {
_selected = selected;
setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default);
setCursor((_selected || _pressed)
? style::cur_pointer
: style::cur_default);
update();
}
}
@@ -1418,21 +1568,26 @@ void RevokePublicLinkBox::Inner::mousePressEvent(QMouseEvent *e) {
}
void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = base::take(_pressed);
setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default);
const auto pressed = base::take(_pressed);
setCursor((_selected || _pressed)
? style::cur_pointer
: style::cur_default);
if (pressed && pressed == _selected) {
auto text_method = pressed->isMegagroup()
const auto textMethod = pressed->isMegagroup()
? tr::lng_channels_too_much_public_revoke_confirm_group
: tr::lng_channels_too_much_public_revoke_confirm_channel;
auto text = text_method(
const auto text = textMethod(
tr::now,
lt_link,
_session->createInternalLink(pressed->userName()),
lt_group,
pressed->name);
auto confirmText = tr::lng_channels_too_much_public_revoke(tr::now);
const auto confirmText = tr::lng_channels_too_much_public_revoke(
tr::now);
auto callback = crl::guard(this, [=](Fn<void()> &&close) {
if (_revokeRequestId) return;
if (_revokeRequestId) {
return;
}
_revokeRequestId = _api.request(MTPchannels_UpdateUsername(
pressed->asChannel()->inputChannel,
MTP_string()
@@ -1444,7 +1599,7 @@ void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
}).send();
});
Ui::show(
Box<ConfirmBox>(text, confirmText, std::move(callback)),
Box<Ui::ConfirmBox>(text, confirmText, std::move(callback)),
Ui::LayerOption::KeepOther);
}
}
@@ -1464,18 +1619,33 @@ void RevokePublicLinkBox::resizeEvent(QResizeEvent *e) {
_aboutRevoke->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
}
void RevokePublicLinkBox::Inner::paintChat(Painter &p, const ChatRow &row, bool selected) const {
auto peer = row.peer;
peer->paintUserpicLeft(p, row.userpic, st::contactsPadding.left(), st::contactsPadding.top(), width(), st::contactsPhotoSize);
void RevokePublicLinkBox::Inner::paintChat(
Painter &p,
const ChatRow &row,
bool selected) const {
const auto peer = row.peer;
peer->paintUserpicLeft(
p,
row.userpic,
st::contactsPadding.left(),
st::contactsPadding.top(),
width(),
st::contactsPhotoSize);
p.setPen(st::contactsNameFg);
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
int32 namew = width() - namex - st::contactsPadding.right() - (_revokeWidth + st::contactsCheckPosition.x() * 2);
const auto namex = st::contactsPadding.left()
+ st::contactsPhotoSize
+ st::contactsPadding.left();
auto namew = width()
- namex
- st::contactsPadding.right()
- (_revokeWidth + st::contactsCheckPosition.x() * 2);
const auto badgeStyle = Ui::PeerBadgeStyle{
&st::dialogsVerifiedIcon,
&st::attentionButtonFg };
&st::attentionButtonFg
};
namew -= Ui::DrawPeerBadgeGetWidth(
peer,
p,
@@ -1487,14 +1657,32 @@ void RevokePublicLinkBox::Inner::paintChat(Painter &p, const ChatRow &row, bool
namew,
width(),
badgeStyle);
row.name.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew, width());
row.name.drawLeftElided(
p,
namex,
st::contactsPadding.top() + st::contactsNameTop,
namew,
width());
p.setFont(selected ? st::linkOverFont : st::linkFont);
p.setPen(selected ? st::defaultLinkButton.overColor : st::defaultLinkButton.color);
p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), tr::lng_channels_too_much_public_revoke(tr::now), _revokeWidth);
p.setPen(selected
? st::defaultLinkButton.overColor
: st::defaultLinkButton.color);
p.drawTextRight(
st::contactsPadding.right() + st::contactsCheckPosition.x(),
st::contactsPadding.top()
+ (st::contactsPhotoSize - st::normalFont->height) / 2,
width(),
tr::lng_channels_too_much_public_revoke(tr::now),
_revokeWidth);
p.setPen(st::contactsStatusFg);
p.setTextPalette(st::revokePublicLinkStatusPalette);
row.status.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsStatusTop, namew, width());
row.status.drawLeftElided(
p,
namex,
st::contactsPadding.top() + st::contactsStatusTop,
namew,
width());
p.restoreTextPalette();
}

View File

@@ -8,12 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/abstract_box.h"
#include "base/timer.h"
#include "mtproto/sender.h"
#include "styles/style_widgets.h"
#include <QtCore/QTimer>
class ConfirmBox;
class PeerListBox;
namespace Window {
@@ -25,6 +22,7 @@ class Session;
} // namespace Main
namespace Ui {
class ConfirmBox;
class FlatLabel;
class InputField;
class PhoneInput;
@@ -118,7 +116,10 @@ protected:
private:
void createChannel(const QString &title, const QString &description);
void createGroup(not_null<PeerListBox*> selectUsersBox, const QString &title, const std::vector<not_null<PeerData*>> &users);
void createGroup(
not_null<PeerListBox*> selectUsersBox,
const QString &title,
const std::vector<not_null<PeerData*>> &users);
void submitName();
void submit();
void checkInviteLink();
@@ -176,12 +177,10 @@ private:
void check();
void save();
void updateDone(const MTPBool &result);
void updateFail(const MTP::Error &error);
void updateFail(const QString &error);
void checkDone(const MTPBool &result);
void checkFail(const MTP::Error &error);
void firstCheckFail(const MTP::Error &error);
void checkFail(const QString &error);
void firstCheckFail(const QString &error);
void updateMaxHeight();
@@ -209,7 +208,7 @@ private:
mtpRequestId _checkRequestId = 0;
QString _sentUsername, _checkUsername, _errorText, _goodText;
QTimer _checkTimer;
base::Timer _checkTimer;
};
@@ -226,8 +225,7 @@ protected:
private:
void submit();
void save();
void saveSelfDone(const MTPUser &user);
void saveSelfFail(const MTP::Error &error);
void saveSelfFail(const QString &error);
const not_null<UserData*> _user;
MTP::Sender _api;

View File

@@ -20,7 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "boxes/background_preview_box.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "window/window_session_controller.h"
#include "window/themes/window_theme.h"
#include "styles/style_overview.h"
@@ -176,7 +176,7 @@ void BackgroundBox::removePaper(const Data::WallPaper &paper) {
)).send();
};
_controller->show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_background_sure_delete(tr::now),
tr::lng_selected_delete(tr::now),
tr::lng_cancel(tr::now),

View File

@@ -28,7 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document_resolver.h"
#include "data/data_file_origin.h"
#include "base/unixtime.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/background_preview_box.h"
#include "window/window_session_controller.h"
#include "styles/style_chat.h"
@@ -210,7 +210,7 @@ void ServiceCheck::Generator::paintFrame(
const auto frames = framesForStyle(st);
auto &image = frames->image;
const auto count = int(frames->ready.size());
const auto index = int(std::round(toggled * (count - 1)));
const auto index = int(base::SafeRound(toggled * (count - 1)));
Assert(index >= 0 && index < count);
if (!frames->ready[index]) {
frames->ready[index] = true;
@@ -288,7 +288,6 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
bool out) {
Expects(history->peer->isUser());
static auto id = ServerMaxMsgId + (ServerMaxMsgId / 3);
const auto flags = MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| (out ? MessageFlag::Outgoing : MessageFlag(0));
@@ -296,7 +295,7 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
const auto viaBotId = UserId();
const auto groupedId = uint64();
const auto item = history->makeMessage(
++id,
history->nextNonHistoryEntryId(),
flags,
replyTo,
viaBotId,
@@ -305,7 +304,7 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
QString(),
TextWithEntities{ TextUtilities::Clean(text) },
MTP_messageMediaEmpty(),
MTPReplyMarkup(),
HistoryMessageMarkupData(),
groupedId);
return AdminLog::OwnedItem(delegate, item);
}
@@ -785,7 +784,7 @@ bool BackgroundPreviewBox::Start(
}
if (!IsValidWallPaperSlug(slug)) {
controller->show(
Box<InformBox>(tr::lng_background_bad_link(tr::now)));
Box<Ui::InformBox>(tr::lng_background_bad_link(tr::now)));
return false;
}
controller->session().api().requestWallPaper(slug, crl::guard(controller, [=](
@@ -795,7 +794,7 @@ bool BackgroundPreviewBox::Start(
result.withUrlParams(params)));
}), crl::guard(controller, [=](const MTP::Error &error) {
controller->show(
Box<InformBox>(tr::lng_background_bad_link(tr::now)));
Box<Ui::InformBox>(tr::lng_background_bad_link(tr::now)));
}));
return true;
}

View File

@@ -973,3 +973,21 @@ autolockTimeField: InputField(scheduleTimeField) {
heightMin: 20px;
}
autolockTimeWidth: 52px;
sponsoredUrlButtonSkip: 11px;
sponsoredUrlButton: RoundButton(defaultActiveButton) {
height: 32px;
width: -42px;
textBg: transparent;
textBgOver: transparent;
radius: roundRadiusLarge;
padding: margins(2px, 2px, 2px, 2px);
textFg: historyLinkInFg;
textFgOver: historyLinkInFg;
textTop: 7px;
font: normalFont;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}

View File

@@ -9,26 +9,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/sent_code_field.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/toast/toast.h"
#include "ui/text/format_values.h" // Ui::FormatPhone
#include "ui/text/text_utilities.h"
#include "ui/special_fields.h"
#include "boxes/confirm_phone_box.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/phone_banned_box.h"
#include "countries/countries_instance.h" // Countries::ExtractPhoneCode.
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "mtproto/sender.h"
#include "apiwrap.h"
#include "window/window_session_controller.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
namespace {
void createErrorLabel(
void CreateErrorLabel(
QWidget *parent,
object_ptr<Ui::FadeWrap<Ui::FlatLabel>> &label,
const QString &text,
@@ -67,7 +68,7 @@ void createErrorLabel(
class ChangePhoneBox::EnterPhone : public Ui::BoxContent {
public:
EnterPhone(QWidget*, not_null<Main::Session*> session);
EnterPhone(QWidget*, not_null<Window::SessionController*> controller);
void setInnerFocus() override {
_phone->setFocusFast();
@@ -78,14 +79,16 @@ protected:
private:
void submit();
void sendPhoneDone(const MTPauth_SentCode &result, const QString &phoneNumber);
void sendPhoneDone(
const MTPauth_SentCode &result,
const QString &phoneNumber);
void sendPhoneFail(const MTP::Error &error, const QString &phoneNumber);
void showError(const QString &text);
void hideError() {
showError(QString());
}
const not_null<Main::Session*> _session;
const not_null<Window::SessionController*> _controller;
MTP::Sender _api;
object_ptr<Ui::PhoneInput> _phone = { nullptr };
@@ -129,41 +132,51 @@ private:
QString _hash;
int _codeLength = 0;
int _callTimeout = 0;
object_ptr<SentCodeField> _code = { nullptr };
object_ptr<Ui::SentCodeField> _code = { nullptr };
object_ptr<Ui::FadeWrap<Ui::FlatLabel>> _error = { nullptr };
object_ptr<Ui::FlatLabel> _callLabel = { nullptr };
mtpRequestId _requestId = 0;
SentCodeCall _call;
Ui::SentCodeCall _call;
};
ChangePhoneBox::EnterPhone::EnterPhone(
QWidget*,
not_null<Main::Session*> session)
: _session(session)
, _api(&session->mtp()) {
not_null<Window::SessionController*> controller)
: _controller(controller)
, _api(&controller->session().mtp()) {
}
void ChangePhoneBox::EnterPhone::prepare() {
setTitle(tr::lng_change_phone_title());
auto phoneValue = QString();
const auto phoneValue = QString();
_phone.create(
this,
st::defaultInputField,
tr::lng_change_phone_new_title(),
Countries::ExtractPhoneCode(_session->user()->phone()),
Countries::ExtractPhoneCode(_controller->session().user()->phone()),
phoneValue);
_phone->resize(st::boxWidth - 2 * st::boxPadding.left(), _phone->height());
_phone->resize(
st::boxWidth - 2 * st::boxPadding.left(),
_phone->height());
_phone->moveToLeft(st::boxPadding.left(), st::boxLittleSkip);
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
auto description = object_ptr<Ui::FlatLabel>(this, tr::lng_change_phone_new_description(tr::now), st::changePhoneLabel);
auto errorSkip = st::boxLittleSkip + st::changePhoneError.style.font->height;
description->moveToLeft(st::boxPadding.left(), _phone->y() + _phone->height() + errorSkip + st::boxLittleSkip);
const auto description = object_ptr<Ui::FlatLabel>(
this,
tr::lng_change_phone_new_description(tr::now),
st::changePhoneLabel);
const auto errorSkip = st::boxLittleSkip
+ st::changePhoneError.style.font->height;
description->moveToLeft(
st::boxPadding.left(),
_phone->y() + _phone->height() + errorSkip + st::boxLittleSkip);
setDimensions(st::boxWidth, description->bottomNoMargins() + st::boxLittleSkip);
setDimensions(
st::boxWidth,
description->bottomNoMargins() + st::boxLittleSkip);
addButton(tr::lng_change_phone_new_submit(), [this] { submit(); });
addButton(tr::lng_cancel(), [this] { closeBox(); });
@@ -175,13 +188,15 @@ void ChangePhoneBox::EnterPhone::submit() {
}
hideError();
auto phoneNumber = _phone->getLastText().trimmed();
const auto phoneNumber = _phone->getLastText().trimmed();
_requestId = _api.request(MTPaccount_SendChangePhoneCode(
MTP_string(phoneNumber),
MTP_codeSettings(MTP_flags(0))
)).done([=](const MTPauth_SentCode &result) {
_requestId = 0;
sendPhoneDone(result, phoneNumber);
}).fail([=](const MTP::Error &error) {
_requestId = 0;
sendPhoneFail(error, phoneNumber);
}).handleFloodErrors().send();
}
@@ -189,33 +204,45 @@ void ChangePhoneBox::EnterPhone::submit() {
void ChangePhoneBox::EnterPhone::sendPhoneDone(
const MTPauth_SentCode &result,
const QString &phoneNumber) {
Expects(result.type() == mtpc_auth_sentCode);
_requestId = 0;
using CodeData = const MTPDauth_sentCode&;
const auto &data = result.match([](const auto &data) -> CodeData {
return data;
});
auto codeLength = 0;
auto &data = result.c_auth_sentCode();
switch (data.vtype().type()) {
case mtpc_auth_sentCodeTypeApp:
const auto hasLength = data.vtype().match([&](
const MTPDauth_sentCodeTypeApp &typeData) {
LOG(("Error: should not be in-app code!"));
showError(Lang::Hard::ServerError());
return;
case mtpc_auth_sentCodeTypeSms: codeLength = data.vtype().c_auth_sentCodeTypeSms().vlength().v; break;
case mtpc_auth_sentCodeTypeCall: codeLength = data.vtype().c_auth_sentCodeTypeCall().vlength().v; break;
case mtpc_auth_sentCodeTypeFlashCall:
return false;
}, [&](const MTPDauth_sentCodeTypeSms &typeData) {
codeLength = typeData.vlength().v;
return true;
}, [&](const MTPDauth_sentCodeTypeCall &typeData) {
codeLength = typeData.vlength().v;
return true;
}, [&](const MTPDauth_sentCodeTypeFlashCall &typeData) {
LOG(("Error: should not be flashcall!"));
showError(Lang::Hard::ServerError());
return false;
});
if (!hasLength) {
return;
}
auto phoneCodeHash = qs(data.vphone_code_hash());
auto callTimeout = 0;
if (const auto nextType = data.vnext_type()) {
if (nextType->type() == mtpc_auth_codeTypeCall) {
callTimeout = data.vtimeout().value_or(60);
const auto phoneCodeHash = qs(data.vphone_code_hash());
const auto callTimeout = [&] {
if (const auto nextType = data.vnext_type()) {
return nextType->match([&](const MTPDauth_sentCodeTypeCall &) {
return data.vtimeout().value_or(60);
}, [](const auto &) {
return 0;
});
}
}
Ui::show(
return 0;
}();
_controller->show(
Box<EnterCode>(
_session,
&_controller->session(),
phoneNumber,
phoneCodeHash,
codeLength,
@@ -223,28 +250,36 @@ void ChangePhoneBox::EnterPhone::sendPhoneDone(
Ui::LayerOption::KeepOther);
}
void ChangePhoneBox::EnterPhone::sendPhoneFail(const MTP::Error &error, const QString &phoneNumber) {
_requestId = 0;
void ChangePhoneBox::EnterPhone::sendPhoneFail(
const MTP::Error &error,
const QString &phoneNumber) {
if (MTP::IsFloodError(error)) {
showError(tr::lng_flood_error(tr::now));
} else if (error.type() == qstr("PHONE_NUMBER_INVALID")) {
showError(tr::lng_bad_phone(tr::now));
} else if (error.type() == qstr("PHONE_NUMBER_BANNED")) {
ShowPhoneBannedError(phoneNumber);
Ui::ShowPhoneBannedError(&_controller->window(), phoneNumber);
} else if (error.type() == qstr("PHONE_NUMBER_OCCUPIED")) {
Ui::show(Box<InformBox>(
tr::lng_change_phone_occupied(
tr::now,
lt_phone,
Ui::FormatPhone(phoneNumber)),
tr::lng_box_ok(tr::now)));
_controller->show(
Box<Ui::InformBox>(
tr::lng_change_phone_occupied(
tr::now,
lt_phone,
Ui::FormatPhone(phoneNumber)),
tr::lng_box_ok(tr::now)),
Ui::LayerOption::CloseOther);
} else {
showError(Lang::Hard::ServerError());
}
}
void ChangePhoneBox::EnterPhone::showError(const QString &text) {
createErrorLabel(this, _error, text, st::boxPadding.left(), _phone->y() + _phone->height() + st::boxLittleSkip);
CreateErrorLabel(
this,
_error,
text,
st::boxPadding.left(),
_phone->y() + _phone->height() + st::boxLittleSkip);
if (!text.isEmpty()) {
_phone->showError();
}
@@ -269,16 +304,23 @@ ChangePhoneBox::EnterCode::EnterCode(
void ChangePhoneBox::EnterCode::prepare() {
setTitle(tr::lng_change_phone_title());
auto descriptionText = tr::lng_change_phone_code_description(
const auto descriptionText = tr::lng_change_phone_code_description(
tr::now,
lt_phone,
Ui::Text::Bold(Ui::FormatPhone(_phone)),
Ui::Text::WithEntities);
auto description = object_ptr<Ui::FlatLabel>(this, rpl::single(descriptionText), st::changePhoneLabel);
const auto description = object_ptr<Ui::FlatLabel>(
this,
rpl::single(descriptionText),
st::changePhoneLabel);
description->moveToLeft(st::boxPadding.left(), 0);
auto phoneValue = QString();
_code.create(this, st::defaultInputField, tr::lng_change_phone_code_title(), phoneValue);
const auto phoneValue = QString();
_code.create(
this,
st::defaultInputField,
tr::lng_change_phone_code_title(),
phoneValue);
_code->setAutoSubmit(_codeLength, [=] { submit(); });
_code->setChangedCallback([=] { hideError(); });
@@ -289,7 +331,7 @@ void ChangePhoneBox::EnterCode::prepare() {
setDimensions(st::boxWidth, countHeight());
if (_callTimeout > 0) {
_call.setStatus({ SentCodeCall::State::Waiting, _callTimeout });
_call.setStatus({ Ui::SentCodeCall::State::Waiting, _callTimeout });
updateCall();
}
@@ -298,7 +340,8 @@ void ChangePhoneBox::EnterCode::prepare() {
}
int ChangePhoneBox::EnterCode::countHeight() {
auto errorSkip = st::boxLittleSkip + st::changePhoneError.style.font->height;
const auto errorSkip = st::boxLittleSkip
+ st::changePhoneError.style.font->height;
return _code->bottomNoMargins() + errorSkip + 3 * st::boxLittleSkip;
}
@@ -316,12 +359,14 @@ void ChangePhoneBox::EnterCode::submit() {
MTP_string(_hash),
MTP_string(code)
)).done([=](const MTPUser &result) {
_requestId = 0;
session->data().processUser(result);
if (weak) {
Ui::hideLayer();
}
Ui::Toast::Show(tr::lng_change_phone_success(tr::now));
}).fail(crl::guard(this, [=](const MTP::Error &error) {
_requestId = 0;
sendCodeFail(error);
})).handleFloodErrors().send();
}
@@ -336,12 +381,14 @@ void ChangePhoneBox::EnterCode::sendCall() {
}
void ChangePhoneBox::EnterCode::updateCall() {
auto text = _call.getText();
const auto text = _call.getText();
if (text.isEmpty()) {
_callLabel.destroy();
} else if (!_callLabel) {
_callLabel.create(this, text, st::changePhoneLabel);
_callLabel->moveToLeft(st::boxPadding.left(), countHeight() - _callLabel->height());
_callLabel->moveToLeft(
st::boxPadding.left(),
countHeight() - _callLabel->height());
_callLabel->show();
} else {
_callLabel->setText(text);
@@ -349,17 +396,22 @@ void ChangePhoneBox::EnterCode::updateCall() {
}
void ChangePhoneBox::EnterCode::showError(const QString &text) {
createErrorLabel(this, _error, text, st::boxPadding.left(), _code->y() + _code->height() + st::boxLittleSkip);
CreateErrorLabel(
this,
_error,
text,
st::boxPadding.left(),
_code->y() + _code->height() + st::boxLittleSkip);
if (!text.isEmpty()) {
_code->showError();
}
}
void ChangePhoneBox::EnterCode::sendCodeFail(const MTP::Error &error) {
_requestId = 0;
if (MTP::IsFloodError(error)) {
showError(tr::lng_flood_error(tr::now));
} else if (error.type() == qstr("PHONE_CODE_EMPTY") || error.type() == qstr("PHONE_CODE_INVALID")) {
} else if (error.type() == qstr("PHONE_CODE_EMPTY")
|| error.type() == qstr("PHONE_CODE_INVALID")) {
showError(tr::lng_bad_code(tr::now));
} else if (error.type() == qstr("PHONE_CODE_EXPIRED")
|| error.type() == qstr("PHONE_NUMBER_BANNED")) {
@@ -371,18 +423,25 @@ void ChangePhoneBox::EnterCode::sendCodeFail(const MTP::Error &error) {
}
}
ChangePhoneBox::ChangePhoneBox(QWidget*, not_null<Main::Session*> session)
: _session(session) {
ChangePhoneBox::ChangePhoneBox(
QWidget*,
not_null<Window::SessionController*> controller)
: _controller(controller) {
}
void ChangePhoneBox::prepare() {
const auto session = _session;
setTitle(tr::lng_change_phone_title());
addButton(tr::lng_change_phone_button(), [=] {
Ui::show(Box<ConfirmBox>(tr::lng_change_phone_warning(tr::now), [=] {
Ui::show(Box<EnterPhone>(session));
}));
addButton(tr::lng_change_phone_button(), [=, controller = _controller] {
auto callback = [=] {
controller->show(
Box<EnterPhone>(controller),
Ui::LayerOption::CloseOther);
};
controller->show(
Box<Ui::ConfirmBox>(
tr::lng_change_phone_warning(tr::now),
std::move(callback)),
Ui::LayerOption::CloseOther);
});
addButton(tr::lng_cancel(), [this] {
closeBox();
@@ -392,14 +451,22 @@ void ChangePhoneBox::prepare() {
this,
tr::lng_change_phone_about(Ui::Text::RichLangValue),
st::changePhoneDescription);
label->moveToLeft((st::boxWideWidth - label->width()) / 2, st::changePhoneDescriptionTop);
label->moveToLeft(
(st::boxWideWidth - label->width()) / 2,
st::changePhoneDescriptionTop);
setDimensions(st::boxWideWidth, label->bottomNoMargins() + st::boxLittleSkip);
setDimensions(
st::boxWideWidth,
label->bottomNoMargins() + st::boxLittleSkip);
}
void ChangePhoneBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
Painter p(this);
st::changePhoneIcon.paint(p, (width() - st::changePhoneIcon.width()) / 2, st::changePhoneIconTop, width());
st::changePhoneIcon.paint(
p,
(width() - st::changePhoneIcon.width()) / 2,
st::changePhoneIconTop,
width());
}

View File

@@ -9,13 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
namespace Main {
class Session;
} // namespace Main
namespace Window {
class SessionController;
} // namespace Window
class ChangePhoneBox : public Ui::BoxContent {
public:
ChangePhoneBox(QWidget*, not_null<Main::Session*> session);
ChangePhoneBox(QWidget*, not_null<Window::SessionController*> controller);
protected:
void prepare() override;
@@ -26,7 +26,7 @@ private:
class EnterPhone;
class EnterCode;
const not_null<Main::Session*> _session;
const not_null<Window::SessionController*> _controller;
};

View File

@@ -1,983 +0,0 @@
/*
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 "boxes/confirm_box.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "apiwrap.h"
#include "api/api_invite_links.h"
#include "history/history.h"
#include "history/history_item.h"
#include "ui/layers/generic_box.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/toast/toast.h"
#include "ui/image/image.h"
#include "ui/text/text_utilities.h"
#include "ui/empty_userpic.h"
#include "core/click_handler_types.h"
#include "window/window_session_controller.h"
#include "storage/localstorage.h"
#include "data/data_scheduled_messages.h"
#include "data/data_session.h"
#include "data/data_photo.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h"
#include "data/data_photo_media.h"
#include "data/data_changes.h"
#include "base/unixtime.h"
#include "history/view/controls/history_view_ttl_button.h"
#include "main/main_session.h"
#include "mtproto/mtproto_config.h"
#include "facades.h" // Ui::showChatsList
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QClipboard>
namespace {
TextParseOptions kInformBoxTextOptions = {
(TextParseLinks
| TextParseMultiline
| TextParseMarkdown
| TextParseRichText), // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
TextParseOptions kMarkedTextBoxOptions = {
(TextParseLinks
| TextParseMultiline
| TextParseMarkdown
| TextParseRichText
| TextParseMentions
| TextParseHashtags), // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
[[nodiscard]] bool IsOldForPin(MsgId id, not_null<PeerData*> peer) {
const auto normal = peer->migrateToOrMe();
const auto migrated = normal->migrateFrom();
const auto top = Data::ResolveTopPinnedId(normal, migrated);
if (!top) {
return false;
} else if (peer == migrated) {
return top.channel || (id < top.msg);
} else if (migrated) {
return top.channel && (id < top.msg);
} else {
return (id < top.msg);
}
}
} // namespace
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(tr::lng_box_ok(tr::now))
, _cancelText(tr::lng_cancel(tr::now))
, _confirmStyle(st::defaultBoxButton)
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
, _confirmedCallback(std::move(confirmedCallback))
, _cancelledCallback(std::move(cancelledCallback)) {
init(text);
}
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(tr::lng_cancel(tr::now))
, _confirmStyle(st::defaultBoxButton)
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
, _confirmedCallback(std::move(confirmedCallback))
, _cancelledCallback(std::move(cancelledCallback)) {
init(text);
}
ConfirmBox::ConfirmBox(
QWidget*,
const TextWithEntities &text,
const QString &confirmText,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(tr::lng_cancel(tr::now))
, _confirmStyle(st::defaultBoxButton)
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
, _confirmedCallback(std::move(confirmedCallback))
, _cancelledCallback(std::move(cancelledCallback)) {
init(text);
}
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const style::RoundButton &confirmStyle,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(tr::lng_cancel(tr::now))
, _confirmStyle(confirmStyle)
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
, _confirmedCallback(std::move(confirmedCallback))
, _cancelledCallback(std::move(cancelledCallback)) {
init(text);
}
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const QString &cancelText,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(cancelText)
, _confirmStyle(st::defaultBoxButton)
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
, _confirmedCallback(std::move(confirmedCallback))
, _cancelledCallback(std::move(cancelledCallback)) {
init(text);
}
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const style::RoundButton &confirmStyle,
const QString &cancelText,
ConfirmBox::ConfirmedCallback confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(cancelText)
, _confirmStyle(st::defaultBoxButton)
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
, _confirmedCallback(std::move(confirmedCallback))
, _cancelledCallback(std::move(cancelledCallback)) {
init(text);
}
ConfirmBox::ConfirmBox(
const InformBoxTag &,
const QString &text,
const QString &doneText,
Fn<void()> closedCallback)
: _confirmText(doneText)
, _confirmStyle(st::defaultBoxButton)
, _informative(true)
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
, _confirmedCallback(generateInformCallback(closedCallback))
, _cancelledCallback(generateInformCallback(closedCallback)) {
init(text);
}
ConfirmBox::ConfirmBox(
const InformBoxTag &,
const TextWithEntities &text,
const QString &doneText,
Fn<void()> closedCallback)
: _confirmText(doneText)
, _confirmStyle(st::defaultBoxButton)
, _informative(true)
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
, _confirmedCallback(generateInformCallback(closedCallback))
, _cancelledCallback(generateInformCallback(closedCallback)) {
init(text);
}
FnMut<void()> ConfirmBox::generateInformCallback(
Fn<void()> closedCallback) {
return crl::guard(this, [=] {
closeBox();
if (closedCallback) {
closedCallback();
}
});
}
void ConfirmBox::init(const QString &text) {
_text.setText(
st::boxLabelStyle,
text,
_informative ? kInformBoxTextOptions : _textPlainOptions);
}
void ConfirmBox::init(const TextWithEntities &text) {
_text.setMarkedText(st::boxLabelStyle, text, kMarkedTextBoxOptions);
}
void ConfirmBox::prepare() {
addButton(
rpl::single(_confirmText),
[=] { confirmed(); },
_confirmStyle);
if (!_informative) {
addButton(
rpl::single(_cancelText),
[=] { _cancelled = true; closeBox(); });
}
boxClosing() | rpl::start_with_next([=] {
if (!_confirmed && (!_strictCancel || _cancelled)) {
if (auto callback = std::move(_cancelledCallback)) {
callback();
}
}
}, lifetime());
textUpdated();
}
void ConfirmBox::setMaxLineCount(int count) {
if (_maxLineCount != count) {
_maxLineCount = count;
textUpdated();
}
}
void ConfirmBox::textUpdated() {
_textWidth = st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right();
_textHeight = _text.countHeight(_textWidth);
if (_maxLineCount > 0) {
accumulate_min(_textHeight, _maxLineCount * st::boxLabelStyle.lineHeight);
}
setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
setMouseTracking(_text.hasLinks());
}
void ConfirmBox::confirmed() {
if (!_confirmed) {
_confirmed = true;
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)) {
const auto weak = Ui::MakeWeak(this);
callback(crl::guard(weak, [=] { closeBox(); }));
}
}
}
}
void ConfirmBox::mouseMoveEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateHover();
}
void ConfirmBox::mousePressEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateHover();
ClickHandler::pressed();
return BoxContent::mousePressEvent(e);
}
void ConfirmBox::mouseReleaseEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateHover();
if (const auto activated = ClickHandler::unpressed()) {
ActivateClickHandler(window(), activated, e->button());
crl::on_main(this, [=] {
closeBox();
});
return;
}
BoxContent::mouseReleaseEvent(e);
}
void ConfirmBox::leaveEventHook(QEvent *e) {
ClickHandler::clearActive(this);
}
void ConfirmBox::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
setCursor(active ? style::cur_pointer : style::cur_default);
update();
}
void ConfirmBox::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
update();
}
void ConfirmBox::updateLink() {
_lastMousePos = QCursor::pos();
updateHover();
}
void ConfirmBox::updateHover() {
auto m = mapFromGlobal(_lastMousePos);
auto state = _text.getStateLeft(m - QPoint(st::boxPadding.left(), st::boxPadding.top()), _textWidth, width());
ClickHandler::setActive(state.link, this);
}
void ConfirmBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
confirmed();
} else {
BoxContent::keyPressEvent(e);
}
}
void ConfirmBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
Painter p(this);
// draw box title / text
p.setPen(st::boxTextFg);
if (_maxLineCount > 0) {
_text.drawLeftElided(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), _maxLineCount, style::al_left);
} else {
_text.drawLeft(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), style::al_left);
}
}
InformBox::InformBox(QWidget*, const QString &text, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, tr::lng_box_ok(tr::now), std::move(closedCallback)) {
}
InformBox::InformBox(QWidget*, const QString &text, const QString &doneText, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) {
}
InformBox::InformBox(QWidget*, const TextWithEntities &text, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, tr::lng_box_ok(tr::now), std::move(closedCallback)) {
}
InformBox::InformBox(QWidget*, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) {
}
MaxInviteBox::MaxInviteBox(QWidget*, not_null<ChannelData*> channel) : BoxContent()
, _channel(channel)
, _text(
st::boxLabelStyle,
tr::lng_participant_invite_sorry(
tr::now,
lt_count,
channel->session().serverConfig().chatSizeMax),
kInformBoxTextOptions,
(st::boxWidth
- st::boxPadding.left()
- st::defaultBox.buttonPadding.right())) {
}
void MaxInviteBox::prepare() {
setMouseTracking(true);
addButton(tr::lng_box_ok(), [=] { closeBox(); });
_textWidth = st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right();
_textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight);
setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom());
_channel->session().changes().peerUpdates(
_channel,
Data::PeerUpdate::Flag::InviteLinks
) | rpl::start_with_next([=] {
rtlupdate(_invitationLink);
}, lifetime());
}
void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
updateSelected(e->globalPos());
}
void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
mouseMoveEvent(e);
if (_linkOver) {
if (_channel->inviteLink().isEmpty()) {
_channel->session().api().inviteLinks().create(_channel);
} else {
QGuiApplication::clipboard()->setText(_channel->inviteLink());
Ui::Toast::Show(tr::lng_create_channel_link_copied(tr::now));
}
}
}
void MaxInviteBox::leaveEventHook(QEvent *e) {
updateSelected(QCursor::pos());
}
void MaxInviteBox::updateSelected(const QPoint &cursorGlobalPosition) {
QPoint p(mapFromGlobal(cursorGlobalPosition));
bool linkOver = _invitationLink.contains(p);
if (linkOver != _linkOver) {
_linkOver = linkOver;
update();
setCursor(_linkOver ? style::cur_pointer : style::cur_default);
}
}
void MaxInviteBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
Painter p(this);
// draw box title / text
p.setPen(st::boxTextFg);
_text.drawLeftElided(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), 16, style::al_left);
QTextOption option(style::al_left);
option.setWrapMode(QTextOption::WrapAnywhere);
p.setFont(_linkOver ? st::defaultInputField.font->underline() : st::defaultInputField.font);
p.setPen(st::defaultLinkButton.color);
auto inviteLinkText = _channel->inviteLink().isEmpty() ? tr::lng_group_invite_create(tr::now) : _channel->inviteLink();
p.drawText(_invitationLink, inviteLinkText, option);
}
void MaxInviteBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height);
}
PinMessageBox::PinMessageBox(
QWidget*,
not_null<PeerData*> peer,
MsgId msgId)
: _peer(peer)
, _api(&peer->session().mtp())
, _msgId(msgId)
, _pinningOld(IsOldForPin(msgId, peer))
, _text(
this,
(_pinningOld
? tr::lng_pinned_pin_old_sure(tr::now)
: (peer->isChat() || peer->isMegagroup())
? tr::lng_pinned_pin_sure_group(tr::now)
: tr::lng_pinned_pin_sure(tr::now)),
st::boxLabel) {
}
void PinMessageBox::prepare() {
addButton(tr::lng_pinned_pin(), [this] { pinMessage(); });
addButton(tr::lng_cancel(), [this] { closeBox(); });
if (_peer->isUser() && !_peer->isSelf()) {
_pinForPeer.create(
this,
tr::lng_pinned_also_for_other(
tr::now,
lt_user,
_peer->shortName()),
false,
st::defaultBoxCheckbox);
_checkbox = _pinForPeer;
} else if (!_pinningOld && (_peer->isChat() || _peer->isMegagroup())) {
_notify.create(
this,
tr::lng_pinned_notify(tr::now),
true,
st::defaultBoxCheckbox);
_checkbox = _notify;
}
auto height = st::boxPadding.top() + _text->height() + st::boxPadding.bottom();
if (_checkbox) {
height += st::boxMediumSkip + _checkbox->heightNoMargins();
}
setDimensions(st::boxWidth, height);
}
void PinMessageBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
if (_checkbox) {
_checkbox->moveToLeft(st::boxPadding.left(), _text->y() + _text->height() + st::boxMediumSkip);
}
}
void PinMessageBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
pinMessage();
} else {
BoxContent::keyPressEvent(e);
}
}
void PinMessageBox::pinMessage() {
if (_requestId) return;
auto flags = MTPmessages_UpdatePinnedMessage::Flags(0);
if (_notify && !_notify->checked()) {
flags |= MTPmessages_UpdatePinnedMessage::Flag::f_silent;
}
if (_pinForPeer && !_pinForPeer->checked()) {
flags |= MTPmessages_UpdatePinnedMessage::Flag::f_pm_oneside;
}
_requestId = _api.request(MTPmessages_UpdatePinnedMessage(
MTP_flags(flags),
_peer->input,
MTP_int(_msgId)
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
Ui::hideLayer();
}).fail([=](const MTP::Error &error) {
Ui::hideLayer();
}).send();
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<HistoryItem*> item,
bool suggestModerateActions)
: _session(&item->history()->session())
, _ids(1, item->fullId()) {
if (suggestModerateActions) {
_moderateBan = item->suggestBanReport();
_moderateDeleteAll = item->suggestDeleteAllReport();
if (_moderateBan || _moderateDeleteAll) {
_moderateFrom = item->from()->asUser();
_moderateInChannel = item->history()->peer->asChannel();
}
}
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<Main::Session*> session,
MessageIdsList &&selected)
: _session(session)
, _ids(std::move(selected)) {
Expects(!_ids.empty());
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<PeerData*> peer,
bool justClear)
: _session(&peer->session())
, _wipeHistoryPeer(peer)
, _wipeHistoryJustClear(justClear) {
}
void DeleteMessagesBox::prepare() {
auto details = TextWithEntities();
const auto appendDetails = [&](TextWithEntities &&text) {
details.append(qstr("\n\n")).append(std::move(text));
};
auto deleteText = lifetime().make_state<rpl::variable<QString>>();
*deleteText = tr::lng_box_delete();
auto deleteStyle = &st::defaultBoxButton;
auto canDelete = true;
if (const auto peer = _wipeHistoryPeer) {
if (_wipeHistoryJustClear) {
const auto isChannel = peer->isBroadcast();
const auto isPublicGroup = peer->isMegagroup()
&& peer->asChannel()->isPublic();
if (isChannel || isPublicGroup) {
canDelete = false;
}
details.text = isChannel
? tr::lng_no_clear_history_channel(tr::now)
: isPublicGroup
? tr::lng_no_clear_history_group(tr::now)
: peer->isSelf()
? tr::lng_sure_delete_saved_messages(tr::now)
: peer->isUser()
? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name)
: tr::lng_sure_delete_group_history(tr::now, lt_group, peer->name);
deleteStyle = &st::attentionBoxButton;
} else {
details.text = peer->isSelf()
? tr::lng_sure_delete_saved_messages(tr::now)
: peer->isUser()
? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name)
: peer->isChat()
? tr::lng_sure_delete_and_exit(tr::now, lt_group, peer->name)
: peer->isMegagroup()
? tr::lng_sure_leave_group(tr::now)
: tr::lng_sure_leave_channel(tr::now);
if (!peer->isUser()) {
*deleteText = tr::lng_box_leave();
}
deleteStyle = &st::attentionBoxButton;
}
if (auto revoke = revokeText(peer)) {
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
appendDetails(std::move(revoke->description));
if (!peer->isUser() && !_wipeHistoryJustClear) {
_revoke->checkedValue(
) | rpl::start_with_next([=](bool revokeForAll) {
*deleteText = revokeForAll
? tr::lng_box_delete()
: tr::lng_box_leave();
}, _revoke->lifetime());
}
}
} else if (_moderateFrom) {
Assert(_moderateInChannel != nullptr);
details.text = tr::lng_selected_delete_sure_this(tr::now);
if (_moderateBan) {
_banUser.create(this, tr::lng_ban_user(tr::now), false, st::defaultBoxCheckbox);
}
_reportSpam.create(this, tr::lng_report_spam(tr::now), false, st::defaultBoxCheckbox);
if (_moderateDeleteAll) {
_deleteAll.create(this, tr::lng_delete_all_from(tr::now), false, st::defaultBoxCheckbox);
}
} else {
details.text = (_ids.size() == 1)
? tr::lng_selected_delete_sure_this(tr::now)
: tr::lng_selected_delete_sure(tr::now, lt_count, _ids.size());
if (const auto peer = checkFromSinglePeer()) {
auto count = int(_ids.size());
if (hasScheduledMessages()) {
} else if (auto revoke = revokeText(peer)) {
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
appendDetails(std::move(revoke->description));
} else if (peer->isChannel()) {
if (peer->isMegagroup()) {
appendDetails({ tr::lng_delete_for_everyone_hint(tr::now, lt_count, count) });
}
} else if (peer->isChat()) {
appendDetails({ tr::lng_delete_for_me_chat_hint(tr::now, lt_count, count) });
} else if (!peer->isSelf()) {
appendDetails({ tr::lng_delete_for_me_hint(tr::now, lt_count, count) });
}
}
}
_text.create(this, rpl::single(std::move(details)), st::boxLabel);
if (_wipeHistoryJustClear
&& _wipeHistoryPeer
&& ((_wipeHistoryPeer->isUser()
&& !_wipeHistoryPeer->isSelf()
&& !_wipeHistoryPeer->isNotificationsUser())
|| (_wipeHistoryPeer->isChat()
&& _wipeHistoryPeer->asChat()->canDeleteMessages())
|| (_wipeHistoryPeer->isChannel()
&& _wipeHistoryPeer->asChannel()->canDeleteMessages()))) {
_wipeHistoryPeer->updateFull();
_autoDeleteSettings.create(
this,
(_wipeHistoryPeer->messagesTTL()
? tr::lng_edit_auto_delete_settings(tr::now)
: tr::lng_enable_auto_delete(tr::now)),
st::boxLinkButton);
_autoDeleteSettings->setClickedCallback([=] {
getDelegate()->show(
Box(
HistoryView::Controls::AutoDeleteSettingsBox,
_wipeHistoryPeer),
Ui::LayerOption(0));
});
}
if (canDelete) {
addButton(
deleteText->value(),
[=] { deleteAndClear(); },
*deleteStyle);
addButton(tr::lng_cancel(), [=] { closeBox(); });
} else {
addButton(tr::lng_about_done(), [=] { closeBox(); });
}
auto fullHeight = st::boxPadding.top() + _text->height() + st::boxPadding.bottom();
if (_moderateFrom) {
fullHeight += st::boxMediumSkip;
if (_banUser) {
fullHeight += _banUser->heightNoMargins() + st::boxLittleSkip;
}
fullHeight += _reportSpam->heightNoMargins();
if (_deleteAll) {
fullHeight += st::boxLittleSkip + _deleteAll->heightNoMargins();
}
} else if (_revoke) {
fullHeight += st::boxMediumSkip + _revoke->heightNoMargins();
}
if (_autoDeleteSettings) {
fullHeight += st::boxMediumSkip + _autoDeleteSettings->height() + st::boxLittleSkip;
}
setDimensions(st::boxWidth, fullHeight);
}
bool DeleteMessagesBox::hasScheduledMessages() const {
for (const auto &fullId : _ids) {
if (const auto item = _session->data().message(fullId)) {
if (item->isScheduled()) {
return true;
}
}
}
return false;
}
PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
auto result = (PeerData*)nullptr;
for (const auto &fullId : _ids) {
if (const auto item = _session->data().message(fullId)) {
const auto peer = item->history()->peer;
if (!result) {
result = peer;
} else if (result != peer) {
return nullptr;
}
}
}
return result;
}
auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
-> std::optional<RevokeConfig> {
auto result = RevokeConfig();
if (peer == _wipeHistoryPeer) {
if (!peer->canRevokeFullHistory()) {
return std::nullopt;
} else if (const auto user = peer->asUser()) {
result.checkbox = tr::lng_delete_for_other_check(
tr::now,
lt_user,
user->firstName);
} else if (_wipeHistoryJustClear) {
return std::nullopt;
} else {
result.checkbox = tr::lng_delete_for_everyone_check(tr::now);
}
return result;
}
const auto items = ranges::views::all(
_ids
) | ranges::views::transform([&](FullMsgId id) {
return peer->owner().message(id);
}) | ranges::views::filter([](HistoryItem *item) {
return (item != nullptr);
}) | ranges::to_vector;
if (items.size() != _ids.size()) {
// We don't have information about all messages.
return std::nullopt;
}
const auto now = base::unixtime::now();
const auto canRevoke = [&](HistoryItem * item) {
return item->canDeleteForEveryone(now);
};
const auto cannotRevoke = [&](HistoryItem *item) {
return !item->canDeleteForEveryone(now);
};
const auto canRevokeAll = ranges::none_of(items, cannotRevoke);
auto outgoing = items | ranges::views::filter(&HistoryItem::out);
const auto canRevokeOutgoingCount = canRevokeAll
? -1
: ranges::count_if(outgoing, canRevoke);
if (canRevokeAll) {
if (const auto user = peer->asUser()) {
result.checkbox = tr::lng_delete_for_other_check(
tr::now,
lt_user,
user->firstName);
} else {
result.checkbox = tr::lng_delete_for_everyone_check(tr::now);
}
return result;
} else if (canRevokeOutgoingCount > 0) {
result.checkbox = tr::lng_delete_for_other_my(tr::now);
if (const auto user = peer->asUser()) {
if (canRevokeOutgoingCount == 1) {
result.description = tr::lng_selected_unsend_about_user_one(
tr::now,
lt_user,
Ui::Text::Bold(user->shortName()),
Ui::Text::WithEntities);
} else {
result.description = tr::lng_selected_unsend_about_user(
tr::now,
lt_count,
canRevokeOutgoingCount,
lt_user,
Ui::Text::Bold(user->shortName()),
Ui::Text::WithEntities);
}
} else if (canRevokeOutgoingCount == 1) {
result.description = tr::lng_selected_unsend_about_group_one(
tr::now,
Ui::Text::WithEntities);
} else {
result.description = tr::lng_selected_unsend_about_group(
tr::now,
lt_count,
canRevokeOutgoingCount,
Ui::Text::WithEntities);
}
return result;
}
return std::nullopt;
}
void DeleteMessagesBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
auto top = _text->bottomNoMargins() + st::boxMediumSkip;
if (_moderateFrom) {
if (_banUser) {
_banUser->moveToLeft(st::boxPadding.left(), top);
top += _banUser->heightNoMargins() + st::boxLittleSkip;
}
_reportSpam->moveToLeft(st::boxPadding.left(), top);
top += _reportSpam->heightNoMargins() + st::boxLittleSkip;
if (_deleteAll) {
_deleteAll->moveToLeft(st::boxPadding.left(), top);
top += _deleteAll->heightNoMargins() + st::boxLittleSkip;
}
} else if (_revoke) {
const auto availableWidth = width() - 2 * st::boxPadding.left();
_revoke->resizeToNaturalWidth(availableWidth);
_revoke->moveToLeft(st::boxPadding.left(), top);
top += _revoke->heightNoMargins() + st::boxLittleSkip;
}
if (_autoDeleteSettings) {
top += st::boxMediumSkip - st::boxLittleSkip;
_autoDeleteSettings->moveToLeft(st::boxPadding.left(), top);
}
}
void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
// Don't make the clearing history so easy.
if (!_wipeHistoryPeer) {
deleteAndClear();
}
} else {
BoxContent::keyPressEvent(e);
}
}
void DeleteMessagesBox::deleteAndClear() {
const auto revoke = _revoke ? _revoke->checked() : false;
if (const auto peer = _wipeHistoryPeer) {
const auto justClear = _wipeHistoryJustClear;
closeBox();
if (justClear) {
peer->session().api().clearHistory(peer, revoke);
} else {
for (const auto &controller : peer->session().windows()) {
if (controller->activeChatCurrent().peer() == peer) {
Ui::showChatsList(&peer->session());
}
}
// Don't delete old history by default,
// because Android app doesn't.
//
//if (const auto from = peer->migrateFrom()) {
// peer->session().api().deleteConversation(from, false);
//}
peer->session().api().deleteConversation(peer, revoke);
}
return;
}
if (_moderateFrom) {
if (_banUser && _banUser->checked()) {
_moderateInChannel->session().api().kickParticipant(
_moderateInChannel,
_moderateFrom,
ChatRestrictionsInfo());
}
if (_reportSpam->checked()) {
_moderateInChannel->session().api().request(
MTPchannels_ReportSpam(
_moderateInChannel->inputChannel,
_moderateFrom->inputUser,
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg)))
).send();
}
if (_deleteAll && _deleteAll->checked()) {
_moderateInChannel->session().api().deleteAllFromUser(
_moderateInChannel,
_moderateFrom);
}
}
if (_deleteConfirmedCallback) {
_deleteConfirmedCallback();
}
// deleteMessages can initiate closing of the current section,
// which will cause this box to be destroyed.
const auto session = _session;
const auto weak = Ui::MakeWeak(this);
session->data().histories().deleteMessages(_ids, revoke);
if (const auto strong = weak.data()) {
strong->closeBox();
}
session->data().sendHistoryChangeNotifications();
}
ConfirmDontWarnBox::ConfirmDontWarnBox(
QWidget*,
rpl::producer<TextWithEntities> text,
const QString &checkbox,
rpl::producer<QString> confirm,
FnMut<void(bool)> callback)
: _confirm(std::move(confirm))
, _content(setupContent(std::move(text), checkbox, std::move(callback))) {
}
void ConfirmDontWarnBox::prepare() {
setDimensionsToContent(st::boxWidth, _content);
addButton(std::move(_confirm), [=] { _callback(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });
}
not_null<Ui::RpWidget*> ConfirmDontWarnBox::setupContent(
rpl::producer<TextWithEntities> text,
const QString &checkbox,
FnMut<void(bool)> callback) {
const auto result = Ui::CreateChild<Ui::VerticalLayout>(this);
result->add(
object_ptr<Ui::FlatLabel>(
result,
std::move(text),
st::boxLabel),
st::boxPadding);
const auto control = result->add(
object_ptr<Ui::Checkbox>(
result,
checkbox,
false,
st::defaultBoxCheckbox),
style::margins(
st::boxPadding.left(),
st::boxPadding.bottom(),
st::boxPadding.right(),
st::boxPadding.bottom()));
_callback = [=, callback = std::move(callback)]() mutable {
const auto checked = control->checked();
auto local = std::move(callback);
closeBox();
local(checked);
};
return result;
}

View File

@@ -1,275 +0,0 @@
/*
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 "boxes/abstract_box.h"
#include "mtproto/sender.h"
namespace Data {
class PhotoMedia;
class CloudImageView;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
namespace Ui {
class Checkbox;
class FlatLabel;
class EmptyUserpic;
class LinkButton;
} // namespace Ui
class InformBox;
class ConfirmBox : public Ui::BoxContent, public ClickHandlerHost {
public:
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();
// If strict cancel is set the cancelledCallback is only called if the cancel button was pressed.
void setStrictCancel(bool strictCancel) {
_strictCancel = strictCancel;
}
void setMaxLineCount(int count);
// ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
protected:
void prepare() override;
void keyPressEvent(QKeyEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void leaveEventHook(QEvent *e) override;
private:
struct InformBoxTag {
};
ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, Fn<void()> closedCallback);
ConfirmBox(const InformBoxTag &, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback);
FnMut<void()> generateInformCallback(Fn<void()> closedCallback);
friend class InformBox;
void confirmed();
void init(const QString &text);
void init(const TextWithEntities &text);
void textUpdated();
void updateHover();
QString _confirmText;
QString _cancelText;
const style::RoundButton &_confirmStyle;
bool _informative = false;
Ui::Text::String _text;
int _textWidth = 0;
int _textHeight = 0;
int _maxLineCount = 16;
QPoint _lastMousePos;
bool _confirmed = false;
bool _cancelled = false;
bool _strictCancel = false;
ConfirmBox::ConfirmedCallback _confirmedCallback;
FnMut<void()> _cancelledCallback;
};
class InformBox : public ConfirmBox {
public:
InformBox(QWidget*, const QString &text, Fn<void()> closedCallback = nullptr);
InformBox(QWidget*, const QString &text, const QString &doneText, Fn<void()> closedCallback = nullptr);
InformBox(QWidget*, const TextWithEntities &text, Fn<void()> closedCallback = nullptr);
InformBox(QWidget*, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback = nullptr);
};
class MaxInviteBox final : public Ui::BoxContent {
public:
MaxInviteBox(QWidget*, not_null<ChannelData*> channel);
protected:
void prepare() override;
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void leaveEventHook(QEvent *e) override;
private:
void updateSelected(const QPoint &cursorGlobalPosition);
not_null<ChannelData*> _channel;
Ui::Text::String _text;
int32 _textWidth, _textHeight;
QRect _invitationLink;
bool _linkOver = false;
QPoint _lastMousePos;
};
class PinMessageBox final : public Ui::BoxContent {
public:
PinMessageBox(QWidget*, not_null<PeerData*> peer, MsgId msgId);
protected:
void prepare() override;
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
private:
void pinMessage();
const not_null<PeerData*> _peer;
MTP::Sender _api;
MsgId _msgId = 0;
bool _pinningOld = false;
object_ptr<Ui::FlatLabel> _text;
object_ptr<Ui::Checkbox> _notify = { nullptr };
object_ptr<Ui::Checkbox> _pinForPeer = { nullptr };
QPointer<Ui::Checkbox> _checkbox;
mtpRequestId _requestId = 0;
};
class DeleteMessagesBox final : public Ui::BoxContent {
public:
DeleteMessagesBox(
QWidget*,
not_null<HistoryItem*> item,
bool suggestModerateActions);
DeleteMessagesBox(
QWidget*,
not_null<Main::Session*> session,
MessageIdsList &&selected);
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool justClear);
void setDeleteConfirmedCallback(Fn<void()> callback) {
_deleteConfirmedCallback = std::move(callback);
}
protected:
void prepare() override;
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
private:
struct RevokeConfig {
QString checkbox;
TextWithEntities description;
};
void deleteAndClear();
[[nodiscard]] PeerData *checkFromSinglePeer() const;
[[nodiscard]] bool hasScheduledMessages() const;
[[nodiscard]] std::optional<RevokeConfig> revokeText(
not_null<PeerData*> peer) const;
const not_null<Main::Session*> _session;
PeerData * const _wipeHistoryPeer = nullptr;
const bool _wipeHistoryJustClear = false;
const MessageIdsList _ids;
UserData *_moderateFrom = nullptr;
ChannelData *_moderateInChannel = nullptr;
bool _moderateBan = false;
bool _moderateDeleteAll = false;
object_ptr<Ui::FlatLabel> _text = { nullptr };
object_ptr<Ui::Checkbox> _revoke = { nullptr };
object_ptr<Ui::Checkbox> _banUser = { nullptr };
object_ptr<Ui::Checkbox> _reportSpam = { nullptr };
object_ptr<Ui::Checkbox> _deleteAll = { nullptr };
object_ptr<Ui::LinkButton> _autoDeleteSettings = { nullptr };
Fn<void()> _deleteConfirmedCallback;
};
class ConfirmDontWarnBox : public Ui::BoxContent {
public:
ConfirmDontWarnBox(
QWidget*,
rpl::producer<TextWithEntities> text,
const QString &checkbox,
rpl::producer<QString> confirm,
FnMut<void(bool)> callback);
protected:
void prepare() override;
private:
not_null<Ui::RpWidget*> setupContent(
rpl::producer<TextWithEntities> text,
const QString &checkbox,
FnMut<void(bool)> callback);
rpl::producer<QString> _confirm;
FnMut<void()> _callback;
not_null<Ui::RpWidget*> _content;
};

View File

@@ -1,416 +0,0 @@
/*
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 "boxes/confirm_phone_box.h"
#include "boxes/confirm_box.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h"
#include "ui/text/format_values.h" // Ui::FormatPhone
#include "ui/text/text_utilities.h"
#include "core/click_handler_types.h" // UrlClickHandler
#include "base/qthelp_url.h" // qthelp::url_encode
#include "base/platform/base_platform_info.h"
#include "main/main_session.h"
#include "mainwidget.h"
#include "lang/lang_keys.h"
#include "mtproto/facade.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
namespace {
object_ptr<ConfirmPhoneBox> CurrentConfirmPhoneBox = { nullptr };
void SendToBannedHelp(const QString &phone) {
const auto version = QString::fromLatin1(AppVersionStr)
+ (cAlphaVersion()
? qsl(" alpha %1").arg(cAlphaVersion())
: (AppBetaVersion ? " beta" : ""));
const auto subject = qsl("Banned phone number: ") + phone;
const auto body = qsl("\
I'm trying to use my mobile phone number: ") + phone + qsl("\n\
But Telegram says it's banned. Please help.\n\
\n\
App version: ") + version + qsl("\n\
OS version: ") + Platform::SystemVersionPretty() + qsl("\n\
Locale: ") + Platform::SystemLanguage();
const auto url = "mailto:?to="
+ qthelp::url_encode("login@stel.com")
+ "&subject="
+ qthelp::url_encode(subject)
+ "&body="
+ qthelp::url_encode(body);
UrlClickHandler::Open(url);
}
} // namespace
void ShowPhoneBannedError(const QString &phone) {
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto close = [=] {
if (*box) {
(*box)->closeBox();
}
};
*box = Ui::show(Box<ConfirmBox>(
tr::lng_signin_banned_text(tr::now),
tr::lng_box_ok(tr::now),
tr::lng_signin_banned_help(tr::now),
close,
[=] { SendToBannedHelp(phone); close(); }));
}
SentCodeField::SentCodeField(
QWidget *parent,
const style::InputField &st,
rpl::producer<QString> placeholder,
const QString &val)
: Ui::InputField(parent, st, std::move(placeholder), val) {
connect(this, &Ui::InputField::changed, [this] { fix(); });
}
void SentCodeField::setAutoSubmit(int length, Fn<void()> submitCallback) {
_autoSubmitLength = length;
_submitCallback = std::move(submitCallback);
}
void SentCodeField::setChangedCallback(Fn<void()> changedCallback) {
_changedCallback = std::move(changedCallback);
}
QString SentCodeField::getDigitsOnly() const {
return QString(
getLastText()
).remove(
QRegularExpression("[^\\d]")
);
}
void SentCodeField::fix() {
if (_fixing) return;
_fixing = true;
auto newText = QString();
const auto now = getLastText();
auto oldPos = textCursor().position();
auto newPos = -1;
auto oldLen = now.size();
auto digitCount = 0;
for (const auto &ch : now) {
if (ch.isDigit()) {
++digitCount;
}
}
if (_autoSubmitLength > 0 && digitCount > _autoSubmitLength) {
digitCount = _autoSubmitLength;
}
auto strict = (_autoSubmitLength > 0)
&& (digitCount == _autoSubmitLength);
newText.reserve(oldLen);
int i = 0;
for (const auto &ch : now) {
if (i++ == oldPos) {
newPos = newText.length();
}
if (ch.isDigit()) {
if (!digitCount--) {
break;
}
newText += ch;
if (strict && !digitCount) {
break;
}
} else if (ch == '-') {
newText += ch;
}
}
if (newPos < 0) {
newPos = newText.length();
}
if (newText != now) {
setText(newText);
setCursorPosition(newPos);
}
_fixing = false;
if (_changedCallback) {
_changedCallback();
}
if (strict && _submitCallback) {
_submitCallback();
}
}
SentCodeCall::SentCodeCall(
FnMut<void()> callCallback,
Fn<void()> updateCallback)
: _call(std::move(callCallback))
, _update(std::move(updateCallback)) {
_timer.setCallback([=] {
if (_status.state == State::Waiting) {
if (--_status.timeout <= 0) {
_status.state = State::Calling;
_timer.cancel();
if (_call) {
_call();
}
}
}
if (_update) {
_update();
}
});
}
void SentCodeCall::setStatus(const Status &status) {
_status = status;
if (_status.state == State::Waiting) {
_timer.callEach(1000);
}
}
QString SentCodeCall::getText() const {
switch (_status.state) {
case State::Waiting: {
if (_status.timeout >= 3600) {
return tr::lng_code_call(tr::now, lt_minutes, qsl("%1:%2").arg(_status.timeout / 3600).arg((_status.timeout / 60) % 60, 2, 10, QChar('0')), lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0')));
}
return tr::lng_code_call(tr::now, lt_minutes, QString::number(_status.timeout / 60), lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0')));
} break;
case State::Calling: return tr::lng_code_calling(tr::now);
case State::Called: return tr::lng_code_called(tr::now);
}
return QString();
}
void ConfirmPhoneBox::Start(
not_null<Main::Session*> session,
const QString &phone,
const QString &hash) {
if (CurrentConfirmPhoneBox
&& (CurrentConfirmPhoneBox->getPhone() != phone
|| &CurrentConfirmPhoneBox->session() != session)) {
CurrentConfirmPhoneBox.destroyDelayed();
}
if (!CurrentConfirmPhoneBox) {
CurrentConfirmPhoneBox = Box<ConfirmPhoneBox>(session, phone, hash);
}
CurrentConfirmPhoneBox->checkPhoneAndHash();
}
ConfirmPhoneBox::ConfirmPhoneBox(
QWidget*,
not_null<Main::Session*> session,
const QString &phone,
const QString &hash)
: _session(session)
, _api(&session->mtp())
, _phone(phone)
, _hash(hash)
, _call([this] { sendCall(); }, [this] { update(); }) {
}
void ConfirmPhoneBox::sendCall() {
_api.request(MTPauth_ResendCode(
MTP_string(_phone),
MTP_string(_phoneHash)
)).done([=](const MTPauth_SentCode &result) {
callDone(result);
}).send();
}
void ConfirmPhoneBox::checkPhoneAndHash() {
if (_sendCodeRequestId) {
return;
}
_sendCodeRequestId = _api.request(MTPaccount_SendConfirmPhoneCode(
MTP_string(_hash),
MTP_codeSettings(MTP_flags(0))
)).done([=](const MTPauth_SentCode &result) {
sendCodeDone(result);
}).fail([=](const MTP::Error &error) {
sendCodeFail(error);
}).handleFloodErrors().send();
}
void ConfirmPhoneBox::sendCodeDone(const MTPauth_SentCode &result) {
result.match([&](const MTPDauth_sentCode &data) {
_sendCodeRequestId = 0;
_sentCodeLength = data.vtype().match([&](const MTPDauth_sentCodeTypeApp &data) {
LOG(("Error: should not be in-app code!"));
return 0;
}, [&](const MTPDauth_sentCodeTypeSms &data) {
return data.vlength().v;
}, [&](const MTPDauth_sentCodeTypeCall &data) {
return data.vlength().v;
}, [&](const MTPDauth_sentCodeTypeFlashCall &data) {
LOG(("Error: should not be flashcall!"));
return 0;
});
_phoneHash = qs(data.vphone_code_hash());
if (const auto nextType = data.vnext_type()) {
if (nextType->type() == mtpc_auth_codeTypeCall) {
_call.setStatus({ SentCodeCall::State::Waiting, data.vtimeout().value_or(60) });
}
}
launch();
});
}
void ConfirmPhoneBox::sendCodeFail(const MTP::Error &error) {
auto errorText = Lang::Hard::ServerError();
if (MTP::IsFloodError(error)) {
errorText = tr::lng_flood_error(tr::now);
} else if (error.code() == 400) {
errorText = tr::lng_confirm_phone_link_invalid(tr::now);
}
_sendCodeRequestId = 0;
Ui::show(Box<InformBox>(errorText));
if (this == CurrentConfirmPhoneBox) {
CurrentConfirmPhoneBox.destroyDelayed();
} else {
deleteLater();
}
}
void ConfirmPhoneBox::launch() {
if (!CurrentConfirmPhoneBox) return;
Ui::show(std::move(CurrentConfirmPhoneBox));
}
void ConfirmPhoneBox::prepare() {
_about.create(
this,
tr::lng_confirm_phone_about(
lt_phone,
rpl::single(Ui::Text::Bold(Ui::FormatPhone(_phone))),
Ui::Text::WithEntities),
st::confirmPhoneAboutLabel);
_code.create(this, st::confirmPhoneCodeField, tr::lng_code_ph());
_code->setAutoSubmit(_sentCodeLength, [=] { sendCode(); });
_code->setChangedCallback([=] { showError(QString()); });
setTitle(tr::lng_confirm_phone_title());
addButton(tr::lng_confirm_phone_send(), [=] { sendCode(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });
setDimensions(st::boxWidth, st::usernamePadding.top() + _code->height() + st::usernameSkip + _about->height() + st::usernameSkip);
connect(_code, &Ui::InputField::submitted, [=] { sendCode(); });
showChildren();
}
void ConfirmPhoneBox::callDone(const MTPauth_SentCode &result) {
_call.callDone();
}
void ConfirmPhoneBox::sendCode() {
if (_sendCodeRequestId) {
return;
}
const auto code = _code->getDigitsOnly();
if (code.isEmpty()) {
_code->showError();
return;
}
_code->setDisabled(true);
setFocus();
showError(QString());
_sendCodeRequestId = _api.request(MTPaccount_ConfirmPhone(
MTP_string(_phoneHash),
MTP_string(code)
)).done([=](const MTPBool &result) {
confirmDone(result);
}).fail([=](const MTP::Error &error) {
confirmFail(error);
}).handleFloodErrors().send();
}
void ConfirmPhoneBox::confirmDone(const MTPBool &result) {
_sendCodeRequestId = 0;
Ui::show(Box<InformBox>(tr::lng_confirm_phone_success(tr::now, lt_phone, Ui::FormatPhone(_phone))));
}
void ConfirmPhoneBox::confirmFail(const MTP::Error &error) {
auto errorText = Lang::Hard::ServerError();
if (MTP::IsFloodError(error)) {
errorText = tr::lng_flood_error(tr::now);
} else {
auto &errorType = error.type();
if (errorType == qstr("PHONE_CODE_EMPTY") || errorType == qstr("PHONE_CODE_INVALID")) {
errorText = tr::lng_bad_code(tr::now);
}
}
_sendCodeRequestId = 0;
_code->setDisabled(false);
_code->setFocus();
showError(errorText);
}
void ConfirmPhoneBox::showError(const QString &error) {
_error = error;
if (!_error.isEmpty()) {
_code->showError();
}
update();
}
void ConfirmPhoneBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
Painter p(this);
p.setFont(st::boxTextFont);
auto callText = _call.getText();
if (!callText.isEmpty()) {
p.setPen(st::usernameDefaultFg);
auto callTextRectLeft = st::usernamePadding.left();
auto callTextRectTop = _about->y() + _about->height();
auto callTextRectWidth = width() - 2 * st::usernamePadding.left();
auto callTextRect = QRect(callTextRectLeft, callTextRectTop, callTextRectWidth, st::usernameSkip);
p.drawText(callTextRect, callText, style::al_left);
}
auto errorText = _error;
if (errorText.isEmpty()) {
p.setPen(st::usernameDefaultFg);
errorText = tr::lng_confirm_phone_enter_code(tr::now);
} else {
p.setPen(st::boxTextFgError);
}
auto errorTextRectLeft = st::usernamePadding.left();
auto errorTextRectTop = _code->y() + _code->height();
auto errorTextRectWidth = width() - 2 * st::usernamePadding.left();
auto errorTextRect = QRect(errorTextRectLeft, errorTextRectTop, errorTextRectWidth, st::usernameSkip);
p.drawText(errorTextRect, errorText, style::al_left);
}
void ConfirmPhoneBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_code->resize(width() - st::usernamePadding.left() - st::usernamePadding.right(), _code->height());
_code->moveToLeft(st::usernamePadding.left(), st::usernamePadding.top());
_about->moveToLeft(st::usernamePadding.left(), _code->y() + _code->height() + st::usernameSkip);
}
void ConfirmPhoneBox::setInnerFocus() {
_code->setFocusFast();
}

View File

@@ -1,157 +0,0 @@
/*
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 "boxes/abstract_box.h"
#include "base/timer.h"
#include "ui/widgets/input_fields.h"
#include "mtproto/sender.h"
namespace Ui {
class InputField;
class FlatLabel;
} // namespace Ui
namespace Main {
class Session;
} // namespace Main
void ShowPhoneBannedError(const QString &phone);
class SentCodeField : public Ui::InputField {
public:
SentCodeField(
QWidget *parent,
const style::InputField &st,
rpl::producer<QString> placeholder = nullptr,
const QString &val = QString());
void setAutoSubmit(int length, Fn<void()> submitCallback);
void setChangedCallback(Fn<void()> changedCallback);
QString getDigitsOnly() const;
private:
void fix();
// Flag for not calling onTextChanged() recursively.
bool _fixing = false;
int _autoSubmitLength = 0;
Fn<void()> _submitCallback;
Fn<void()> _changedCallback;
};
class SentCodeCall {
public:
SentCodeCall(
FnMut<void()> callCallback,
Fn<void()> updateCallback);
enum class State {
Waiting,
Calling,
Called,
Disabled,
};
struct Status {
Status() {
}
Status(State state, int timeout) : state(state), timeout(timeout) {
}
State state = State::Disabled;
int timeout = 0;
};
void setStatus(const Status &status);
void callDone() {
if (_status.state == State::Calling) {
_status.state = State::Called;
if (_update) {
_update();
}
}
}
QString getText() const;
private:
Status _status;
base::Timer _timer;
FnMut<void()> _call;
Fn<void()> _update;
};
class ConfirmPhoneBox final : public Ui::BoxContent {
public:
static void Start(
not_null<Main::Session*> session,
const QString &phone,
const QString &hash);
[[nodiscard]] Main::Session &session() const {
return *_session;
}
protected:
void prepare() override;
void setInnerFocus() override;
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
private:
ConfirmPhoneBox(
QWidget*,
not_null<Main::Session*> session,
const QString &phone,
const QString &hash);
friend class object_ptr<ConfirmPhoneBox>;
void sendCode();
void sendCall();
void checkPhoneAndHash();
void sendCodeDone(const MTPauth_SentCode &result);
void sendCodeFail(const MTP::Error &error);
void callDone(const MTPauth_SentCode &result);
void confirmDone(const MTPBool &result);
void confirmFail(const MTP::Error &error);
QString getPhone() const {
return _phone;
}
void launch();
void showError(const QString &error);
const not_null<Main::Session*> _session;
MTP::Sender _api;
mtpRequestId _sendCodeRequestId = 0;
// _hash from the link for account.sendConfirmPhoneCode call.
// _phoneHash from auth.sentCode for account.confirmPhone call.
QString _phone, _hash;
QString _phoneHash;
// If we receive the code length, we autosubmit _code field when enough symbols is typed.
int _sentCodeLength = 0;
mtpRequestId _checkCodeRequestId = 0;
object_ptr<Ui::FlatLabel> _about = { nullptr };
object_ptr<SentCodeField> _code = { nullptr };
QString _error;
SentCodeCall _call;
};

View File

@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/connection_box.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "base/qthelp_url.h"
@@ -74,7 +74,7 @@ void HostInput::correctValue(
QString newText;
int newCursor = nowCursor;
newText.reserve(now.size());
for (auto i = 0, l = now.size(); i < l; ++i) {
for (auto i = 0, l = int(now.size()); i < l; ++i) {
if (now[i] == ',') {
newText.append('.');
} else {
@@ -120,7 +120,7 @@ void Base64UrlInput::correctValue(
QString newText;
newText.reserve(now.size());
auto newPos = nowCursor;
for (auto i = 0, l = now.size(); i < l; ++i) {
for (auto i = 0, l = int(now.size()); i < l; ++i) {
const auto ch = now[i];
if ((ch >= '0' && ch <= '9')
|| (ch >= 'a' && ch <= 'z')
@@ -537,8 +537,8 @@ void ProxyRow::showMenu() {
_deleteClicks.fire({});
});
}
const auto parentTopLeft = window()->mapToGlobal({ 0, 0 });
const auto buttonTopLeft = _menuToggle->mapToGlobal({ 0, 0 });
const auto parentTopLeft = window()->mapToGlobal(QPoint());
const auto buttonTopLeft = _menuToggle->mapToGlobal(QPoint());
const auto parent = QRect(parentTopLeft, window()->size());
const auto button = QRect(buttonTopLeft, _menuToggle->size());
const auto bottom = button.y()
@@ -1131,13 +1131,13 @@ void ProxiesBoxController::ShowApplyConfirmation(
close();
};
Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
text,
tr::lng_sure_enable(tr::now),
std::move(callback)),
Ui::LayerOption::KeepOther);
} else {
Ui::show(Box<InformBox>(
Ui::show(Box<Ui::InformBox>(
(proxy.status() == ProxyData::Status::Unsupported
? tr::lng_proxy_unsupported(tr::now)
: tr::lng_proxy_invalid(tr::now))));

View File

@@ -30,7 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unique_qptr.h"
#include "base/event_filter.h"
#include "base/call_delayed.h"
#include "base/openssl_help.h"
#include "base/random.h"
#include "window/window_session_controller.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
@@ -885,7 +885,7 @@ not_null<Ui::InputField*> CreatePollBox::setupSolution(
object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
using namespace Settings;
const auto id = openssl::RandomValue<uint64>();
const auto id = base::RandomValue<uint64>();
const auto error = lifetime().make_state<Errors>(Error::Question);
auto result = object_ptr<Ui::VerticalLayout>(this);

View File

@@ -0,0 +1,459 @@
/*
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 "boxes/delete_messages_box.h"
#include "apiwrap.h"
#include "base/unixtime.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_histories.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "history/history.h"
#include "history/history_item.h"
#include "history/view/controls/history_view_ttl_button.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/labels.h"
#include "window/window_session_controller.h"
#include "facades.h" // Ui::showChatsList
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<HistoryItem*> item,
bool suggestModerateActions)
: _session(&item->history()->session())
, _ids(1, item->fullId()) {
if (suggestModerateActions) {
_moderateBan = item->suggestBanReport();
_moderateDeleteAll = item->suggestDeleteAllReport();
if (_moderateBan || _moderateDeleteAll) {
_moderateFrom = item->from()->asUser();
_moderateInChannel = item->history()->peer->asChannel();
}
}
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<Main::Session*> session,
MessageIdsList &&selected)
: _session(session)
, _ids(std::move(selected)) {
Expects(!_ids.empty());
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<PeerData*> peer,
bool justClear)
: _session(&peer->session())
, _wipeHistoryPeer(peer)
, _wipeHistoryJustClear(justClear) {
}
void DeleteMessagesBox::prepare() {
auto details = TextWithEntities();
const auto appendDetails = [&](TextWithEntities &&text) {
details.append(qstr("\n\n")).append(std::move(text));
};
auto deleteText = lifetime().make_state<rpl::variable<QString>>();
*deleteText = tr::lng_box_delete();
auto deleteStyle = &st::defaultBoxButton;
auto canDelete = true;
if (const auto peer = _wipeHistoryPeer) {
if (_wipeHistoryJustClear) {
const auto isChannel = peer->isBroadcast();
const auto isPublicGroup = peer->isMegagroup()
&& peer->asChannel()->isPublic();
if (isChannel || isPublicGroup) {
canDelete = false;
}
details.text = isChannel
? tr::lng_no_clear_history_channel(tr::now)
: isPublicGroup
? tr::lng_no_clear_history_group(tr::now)
: peer->isSelf()
? tr::lng_sure_delete_saved_messages(tr::now)
: peer->isUser()
? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name)
: tr::lng_sure_delete_group_history(
tr::now,
lt_group,
peer->name);
deleteStyle = &st::attentionBoxButton;
} else {
details.text = peer->isSelf()
? tr::lng_sure_delete_saved_messages(tr::now)
: peer->isUser()
? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name)
: peer->isChat()
? tr::lng_sure_delete_and_exit(tr::now, lt_group, peer->name)
: peer->isMegagroup()
? tr::lng_sure_leave_group(tr::now)
: tr::lng_sure_leave_channel(tr::now);
if (!peer->isUser()) {
*deleteText = tr::lng_box_leave();
}
deleteStyle = &st::attentionBoxButton;
}
if (auto revoke = revokeText(peer)) {
_revoke.create(
this,
revoke->checkbox,
false,
st::defaultBoxCheckbox);
appendDetails(std::move(revoke->description));
if (!peer->isUser() && !_wipeHistoryJustClear) {
_revoke->checkedValue(
) | rpl::start_with_next([=](bool revokeForAll) {
*deleteText = revokeForAll
? tr::lng_box_delete()
: tr::lng_box_leave();
}, _revoke->lifetime());
}
}
} else if (_moderateFrom) {
Assert(_moderateInChannel != nullptr);
details.text = tr::lng_selected_delete_sure_this(tr::now);
if (_moderateBan) {
_banUser.create(
this,
tr::lng_ban_user(tr::now),
false,
st::defaultBoxCheckbox);
}
_reportSpam.create(
this,
tr::lng_report_spam(tr::now),
false,
st::defaultBoxCheckbox);
if (_moderateDeleteAll) {
_deleteAll.create(
this,
tr::lng_delete_all_from(tr::now),
false,
st::defaultBoxCheckbox);
}
} else {
details.text = (_ids.size() == 1)
? tr::lng_selected_delete_sure_this(tr::now)
: tr::lng_selected_delete_sure(tr::now, lt_count, _ids.size());
if (const auto peer = checkFromSinglePeer()) {
auto count = int(_ids.size());
if (hasScheduledMessages()) {
} else if (auto revoke = revokeText(peer)) {
_revoke.create(
this,
revoke->checkbox,
false,
st::defaultBoxCheckbox);
appendDetails(std::move(revoke->description));
} else if (peer->isChannel()) {
if (peer->isMegagroup()) {
appendDetails({
tr::lng_delete_for_everyone_hint(
tr::now,
lt_count,
count)
});
}
} else if (peer->isChat()) {
appendDetails({
tr::lng_delete_for_me_chat_hint(tr::now, lt_count, count)
});
} else if (!peer->isSelf()) {
appendDetails({
tr::lng_delete_for_me_hint(tr::now, lt_count, count)
});
}
}
}
_text.create(this, rpl::single(std::move(details)), st::boxLabel);
if (_wipeHistoryJustClear
&& _wipeHistoryPeer
&& ((_wipeHistoryPeer->isUser()
&& !_wipeHistoryPeer->isSelf()
&& !_wipeHistoryPeer->isNotificationsUser())
|| (_wipeHistoryPeer->isChat()
&& _wipeHistoryPeer->asChat()->canDeleteMessages())
|| (_wipeHistoryPeer->isChannel()
&& _wipeHistoryPeer->asChannel()->canDeleteMessages()))) {
_wipeHistoryPeer->updateFull();
_autoDeleteSettings.create(
this,
(_wipeHistoryPeer->messagesTTL()
? tr::lng_edit_auto_delete_settings(tr::now)
: tr::lng_enable_auto_delete(tr::now)),
st::boxLinkButton);
_autoDeleteSettings->setClickedCallback([=] {
getDelegate()->show(
Box(
HistoryView::Controls::AutoDeleteSettingsBox,
_wipeHistoryPeer),
Ui::LayerOption(0));
});
}
if (canDelete) {
addButton(
deleteText->value(),
[=] { deleteAndClear(); },
*deleteStyle);
addButton(tr::lng_cancel(), [=] { closeBox(); });
} else {
addButton(tr::lng_about_done(), [=] { closeBox(); });
}
auto fullHeight = st::boxPadding.top()
+ _text->height()
+ st::boxPadding.bottom();
if (_moderateFrom) {
fullHeight += st::boxMediumSkip;
if (_banUser) {
fullHeight += _banUser->heightNoMargins() + st::boxLittleSkip;
}
fullHeight += _reportSpam->heightNoMargins();
if (_deleteAll) {
fullHeight += st::boxLittleSkip + _deleteAll->heightNoMargins();
}
} else if (_revoke) {
fullHeight += st::boxMediumSkip + _revoke->heightNoMargins();
}
if (_autoDeleteSettings) {
fullHeight += st::boxMediumSkip
+ _autoDeleteSettings->height()
+ st::boxLittleSkip;
}
setDimensions(st::boxWidth, fullHeight);
}
bool DeleteMessagesBox::hasScheduledMessages() const {
for (const auto &fullId : _ids) {
if (const auto item = _session->data().message(fullId)) {
if (item->isScheduled()) {
return true;
}
}
}
return false;
}
PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
auto result = (PeerData*)nullptr;
for (const auto &fullId : _ids) {
if (const auto item = _session->data().message(fullId)) {
const auto peer = item->history()->peer;
if (!result) {
result = peer;
} else if (result != peer) {
return nullptr;
}
}
}
return result;
}
auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
-> std::optional<RevokeConfig> {
auto result = RevokeConfig();
if (peer == _wipeHistoryPeer) {
if (!peer->canRevokeFullHistory()) {
return std::nullopt;
} else if (const auto user = peer->asUser()) {
result.checkbox = tr::lng_delete_for_other_check(
tr::now,
lt_user,
user->firstName);
} else if (_wipeHistoryJustClear) {
return std::nullopt;
} else {
result.checkbox = tr::lng_delete_for_everyone_check(tr::now);
}
return result;
}
const auto items = ranges::views::all(
_ids
) | ranges::views::transform([&](FullMsgId id) {
return peer->owner().message(id);
}) | ranges::views::filter([](HistoryItem *item) {
return (item != nullptr);
}) | ranges::to_vector;
if (items.size() != _ids.size()) {
// We don't have information about all messages.
return std::nullopt;
}
const auto now = base::unixtime::now();
const auto canRevoke = [&](HistoryItem * item) {
return item->canDeleteForEveryone(now);
};
const auto cannotRevoke = [&](HistoryItem *item) {
return !item->canDeleteForEveryone(now);
};
const auto canRevokeAll = ranges::none_of(items, cannotRevoke);
auto outgoing = items | ranges::views::filter(&HistoryItem::out);
const auto canRevokeOutgoingCount = canRevokeAll
? -1
: ranges::count_if(outgoing, canRevoke);
if (canRevokeAll) {
if (const auto user = peer->asUser()) {
result.checkbox = tr::lng_delete_for_other_check(
tr::now,
lt_user,
user->firstName);
} else {
result.checkbox = tr::lng_delete_for_everyone_check(tr::now);
}
return result;
} else if (canRevokeOutgoingCount > 0) {
result.checkbox = tr::lng_delete_for_other_my(tr::now);
if (const auto user = peer->asUser()) {
if (canRevokeOutgoingCount == 1) {
result.description = tr::lng_selected_unsend_about_user_one(
tr::now,
lt_user,
Ui::Text::Bold(user->shortName()),
Ui::Text::WithEntities);
} else {
result.description = tr::lng_selected_unsend_about_user(
tr::now,
lt_count,
canRevokeOutgoingCount,
lt_user,
Ui::Text::Bold(user->shortName()),
Ui::Text::WithEntities);
}
} else if (canRevokeOutgoingCount == 1) {
result.description = tr::lng_selected_unsend_about_group_one(
tr::now,
Ui::Text::WithEntities);
} else {
result.description = tr::lng_selected_unsend_about_group(
tr::now,
lt_count,
canRevokeOutgoingCount,
Ui::Text::WithEntities);
}
return result;
}
return std::nullopt;
}
void DeleteMessagesBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
auto top = _text->bottomNoMargins() + st::boxMediumSkip;
if (_moderateFrom) {
if (_banUser) {
_banUser->moveToLeft(st::boxPadding.left(), top);
top += _banUser->heightNoMargins() + st::boxLittleSkip;
}
_reportSpam->moveToLeft(st::boxPadding.left(), top);
top += _reportSpam->heightNoMargins() + st::boxLittleSkip;
if (_deleteAll) {
_deleteAll->moveToLeft(st::boxPadding.left(), top);
top += _deleteAll->heightNoMargins() + st::boxLittleSkip;
}
} else if (_revoke) {
const auto availableWidth = width() - 2 * st::boxPadding.left();
_revoke->resizeToNaturalWidth(availableWidth);
_revoke->moveToLeft(st::boxPadding.left(), top);
top += _revoke->heightNoMargins() + st::boxLittleSkip;
}
if (_autoDeleteSettings) {
top += st::boxMediumSkip - st::boxLittleSkip;
_autoDeleteSettings->moveToLeft(st::boxPadding.left(), top);
}
}
void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
// Don't make the clearing history so easy.
if (!_wipeHistoryPeer) {
deleteAndClear();
}
} else {
BoxContent::keyPressEvent(e);
}
}
void DeleteMessagesBox::deleteAndClear() {
const auto revoke = _revoke ? _revoke->checked() : false;
if (const auto peer = _wipeHistoryPeer) {
const auto justClear = _wipeHistoryJustClear;
closeBox();
if (justClear) {
peer->session().api().clearHistory(peer, revoke);
} else {
for (const auto &controller : peer->session().windows()) {
if (controller->activeChatCurrent().peer() == peer) {
Ui::showChatsList(&peer->session());
}
}
// Don't delete old history by default,
// because Android app doesn't.
//
//if (const auto from = peer->migrateFrom()) {
// peer->session().api().deleteConversation(from, false);
//}
peer->session().api().deleteConversation(peer, revoke);
}
return;
}
if (_moderateFrom) {
if (_banUser && _banUser->checked()) {
_moderateInChannel->session().api().kickParticipant(
_moderateInChannel,
_moderateFrom,
ChatRestrictionsInfo());
}
if (_reportSpam->checked()) {
_moderateInChannel->session().api().request(
MTPchannels_ReportSpam(
_moderateInChannel->inputChannel,
_moderateFrom->inputUser,
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg)))
).send();
}
if (_deleteAll && _deleteAll->checked()) {
_moderateInChannel->session().api().deleteAllFromUser(
_moderateInChannel,
_moderateFrom);
}
}
if (_deleteConfirmedCallback) {
_deleteConfirmedCallback();
}
// deleteMessages can initiate closing of the current section,
// which will cause this box to be destroyed.
const auto session = _session;
const auto weak = Ui::MakeWeak(this);
session->data().histories().deleteMessages(_ids, revoke);
if (const auto strong = weak.data()) {
strong->closeBox();
}
session->data().sendHistoryChangeNotifications();
}

View File

@@ -0,0 +1,74 @@
/*
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 "boxes/abstract_box.h"
namespace Main {
class Session;
} // namespace Main
namespace Ui {
class Checkbox;
class FlatLabel;
class LinkButton;
} // namespace Ui
class DeleteMessagesBox final : public Ui::BoxContent {
public:
DeleteMessagesBox(
QWidget*,
not_null<HistoryItem*> item,
bool suggestModerateActions);
DeleteMessagesBox(
QWidget*,
not_null<Main::Session*> session,
MessageIdsList &&selected);
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool justClear);
void setDeleteConfirmedCallback(Fn<void()> callback) {
_deleteConfirmedCallback = std::move(callback);
}
protected:
void prepare() override;
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
private:
struct RevokeConfig {
QString checkbox;
TextWithEntities description;
};
void deleteAndClear();
[[nodiscard]] PeerData *checkFromSinglePeer() const;
[[nodiscard]] bool hasScheduledMessages() const;
[[nodiscard]] std::optional<RevokeConfig> revokeText(
not_null<PeerData*> peer) const;
const not_null<Main::Session*> _session;
PeerData * const _wipeHistoryPeer = nullptr;
const bool _wipeHistoryJustClear = false;
const MessageIdsList _ids;
UserData *_moderateFrom = nullptr;
ChannelData *_moderateInChannel = nullptr;
bool _moderateBan = false;
bool _moderateDeleteAll = false;
object_ptr<Ui::FlatLabel> _text = { nullptr };
object_ptr<Ui::Checkbox> _revoke = { nullptr };
object_ptr<Ui::Checkbox> _banUser = { nullptr };
object_ptr<Ui::Checkbox> _reportSpam = { nullptr };
object_ptr<Ui::Checkbox> _deleteAll = { nullptr };
object_ptr<Ui::LinkButton> _autoDeleteSettings = { nullptr };
Fn<void()> _deleteConfirmedCallback;
};

View File

@@ -39,11 +39,6 @@ using DictState = BlobState;
using QueryCallback = Fn<void(const QString &)>;
constexpr auto kMaxQueryLength = 15;
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
#define OLD_QT
using QStringView = QString;
#endif
class Inner : public Ui::RpWidget {
public:
Inner(

View File

@@ -22,7 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toast/toast.h"
#include "ui/text/text_options.h"
#include "storage/localstorage.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "core/application.h"
@@ -478,7 +478,7 @@ void Rows::showMenu(int index) {
}
}
const auto toggle = menuToggleArea(row);
const auto parentTopLeft = window()->mapToGlobal({ 0, 0 });
const auto parentTopLeft = window()->mapToGlobal(QPoint());
const auto buttonTopLeft = mapToGlobal(toggle.topLeft());
const auto parent = QRect(parentTopLeft, window()->size());
const auto button = QRect(buttonTopLeft, toggle.size());

View File

@@ -0,0 +1,148 @@
/*
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 "boxes/max_invite_box.h"
#include "api/api_invite_links.h"
#include "apiwrap.h"
#include "data/data_changes.h"
#include "data/data_channel.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "mtproto/mtproto_config.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QClipboard>
namespace {
TextParseOptions kInformBoxTextOptions = {
(TextParseLinks
| TextParseMultiline
| TextParseMarkdown
| TextParseRichText), // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
} // namespace
MaxInviteBox::MaxInviteBox(QWidget*, not_null<ChannelData*> channel)
: BoxContent()
, _channel(channel)
, _text(
st::boxLabelStyle,
tr::lng_participant_invite_sorry(
tr::now,
lt_count,
channel->session().serverConfig().chatSizeMax),
kInformBoxTextOptions,
(st::boxWidth
- st::boxPadding.left()
- st::defaultBox.buttonPadding.right())) {
}
void MaxInviteBox::prepare() {
setMouseTracking(true);
addButton(tr::lng_box_ok(), [=] { closeBox(); });
_textWidth = st::boxWidth
- st::boxPadding.left()
- st::defaultBox.buttonPadding.right();
_textHeight = std::min(
_text.countHeight(_textWidth),
16 * st::boxLabelStyle.lineHeight);
setDimensions(
st::boxWidth,
st::boxPadding.top()
+ _textHeight
+ st::boxTextFont->height
+ st::boxTextFont->height * 2
+ st::newGroupLinkPadding.bottom());
_channel->session().changes().peerUpdates(
_channel,
Data::PeerUpdate::Flag::InviteLinks
) | rpl::start_with_next([=] {
rtlupdate(_invitationLink);
}, lifetime());
}
void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
updateSelected(e->globalPos());
}
void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
mouseMoveEvent(e);
if (_linkOver) {
if (_channel->inviteLink().isEmpty()) {
_channel->session().api().inviteLinks().create(_channel);
} else {
QGuiApplication::clipboard()->setText(_channel->inviteLink());
Ui::Toast::Show(tr::lng_create_channel_link_copied(tr::now));
}
}
}
void MaxInviteBox::leaveEventHook(QEvent *e) {
updateSelected(QCursor::pos());
}
void MaxInviteBox::updateSelected(const QPoint &cursorGlobalPosition) {
const auto p = QPoint(mapFromGlobal(cursorGlobalPosition));
const auto linkOver = _invitationLink.contains(p);
if (linkOver != _linkOver) {
_linkOver = linkOver;
update();
setCursor(_linkOver ? style::cur_pointer : style::cur_default);
}
}
void MaxInviteBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
Painter p(this);
// draw box title / text
p.setPen(st::boxTextFg);
_text.drawLeftElided(
p,
st::boxPadding.left(),
st::boxPadding.top(),
_textWidth,
width(),
16,
style::al_left);
auto option = QTextOption(style::al_left);
option.setWrapMode(QTextOption::WrapAnywhere);
p.setFont(_linkOver
? st::defaultInputField.font->underline()
: st::defaultInputField.font);
p.setPen(st::defaultLinkButton.color);
const auto inviteLinkText = _channel->inviteLink().isEmpty()
? tr::lng_group_invite_create(tr::now)
: _channel->inviteLink();
p.drawText(_invitationLink, inviteLinkText, option);
}
void MaxInviteBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_invitationLink = myrtlrect(
st::boxPadding.left(),
st::boxPadding.top() + _textHeight + st::boxTextFont->height,
width() - st::boxPadding.left() - st::boxPadding.right(),
2 * st::boxTextFont->height);
}

View File

@@ -0,0 +1,38 @@
/*
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 "boxes/abstract_box.h"
class MaxInviteBox final : public Ui::BoxContent {
public:
MaxInviteBox(QWidget*, not_null<ChannelData*> channel);
protected:
void prepare() override;
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void leaveEventHook(QEvent *e) override;
private:
void updateSelected(const QPoint &cursorGlobalPosition);
not_null<ChannelData*> _channel;
Ui::Text::String _text;
int32 _textWidth, _textHeight;
QRect _invitationLink;
bool _linkOver = false;
QPoint _lastMousePos;
};

View File

@@ -9,8 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/bytes.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "boxes/confirm_phone_box.h"
#include "ui/boxes/confirm_box.h"
#include "base/unixtime.h"
#include "mainwindow.h"
#include "apiwrap.h"
@@ -24,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/sent_code_field.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/fade_wrap.h"
#include "passport/passport_encryption.h"
@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_layers.h"
#include "styles/style_passport.h"
#include "styles/style_boxes.h"
#include "base/qt_adapters.h"
namespace {
@@ -107,7 +108,7 @@ void StartPendingReset(
auto finish = [=](const QString &message) mutable {
if (const auto strong = weak.data()) {
if (!message.isEmpty()) {
strong->getDelegate()->show(Box<InformBox>(message));
strong->getDelegate()->show(Box<Ui::InformBox>(message));
}
strong->closeBox();
}
@@ -138,7 +139,7 @@ void StartPendingReset(
lt_count,
minutes);
if (const auto strong = weak.data()) {
strong->getDelegate()->show(Box<InformBox>(
strong->getDelegate()->show(Box<Ui::InformBox>(
tr::lng_cloud_password_reset_later(
tr::now,
lt_duration,
@@ -440,7 +441,7 @@ void PasscodeBox::recoverPasswordDone(
if (weak) {
_newPasswordSet.fire_copy(newPasswordBytes);
if (weak) {
getDelegate()->show(Box<InformBox>(
getDelegate()->show(Box<Ui::InformBox>(
tr::lng_cloud_password_updated(tr::now)));
if (weak) {
closeBox();
@@ -462,7 +463,7 @@ void PasscodeBox::setPasswordDone(const QByteArray &newPasswordBytes) {
: _oldPasscode->isHidden()
? tr::lng_cloud_password_was_set(tr::now)
: tr::lng_cloud_password_updated(tr::now);
getDelegate()->show(Box<InformBox>(text));
getDelegate()->show(Box<Ui::InformBox>(text));
if (weak) {
closeBox();
}
@@ -525,7 +526,7 @@ void PasscodeBox::setPasswordFail(
const MTP::Error &error) {
const auto prefix = qstr("EMAIL_UNCONFIRMED_");
if (error.type().startsWith(prefix)) {
const auto codeLength = error.type().midRef(prefix.size()).toInt();
const auto codeLength = base::StringViewMid(error.type(), prefix.size()).toInt();
closeReplacedBy();
_setRequest = 0;
@@ -562,7 +563,7 @@ void PasscodeBox::validateEmail(
const auto weak = Ui::MakeWeak(this);
_clearUnconfirmedPassword.fire({});
if (weak) {
auto box = Box<InformBox>(
auto box = Box<Ui::InformBox>(
Lang::Hard::EmailConfirmationExpired());
weak->getDelegate()->show(
std::move(box),
@@ -689,7 +690,7 @@ void PasscodeBox::save(bool force) {
if (!onlyCheck && !_recoverEmail->isHidden() && email.isEmpty() && !force) {
_skipEmailWarning = true;
_replacedBy = getDelegate()->show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_cloud_password_about_recover(tr::now),
tr::lng_cloud_password_skip_email(tr::now),
st::attentionBoxButton,
@@ -726,7 +727,7 @@ void PasscodeBox::submitOnlyCheckCloudPassword(const QString &oldPassword) {
send();
close();
};
getDelegate()->show(Box<ConfirmBox>(
getDelegate()->show(Box<Ui::ConfirmBox>(
tr::lng_cloud_password_passport_losing(tr::now),
tr::lng_continue(tr::now),
confirmed));
@@ -797,7 +798,7 @@ void PasscodeBox::requestPasswordData() {
}
void PasscodeBox::serverError() {
getDelegate()->show(Box<InformBox>(Lang::Hard::ServerError()));
getDelegate()->show(Box<Ui::InformBox>(Lang::Hard::ServerError()));
closeBox();
}
@@ -952,7 +953,7 @@ void PasscodeBox::suggestSecretReset(const QString &newPassword) {
resetSecret(check, newPassword, std::move(close));
});
};
getDelegate()->show(Box<ConfirmBox>(
getDelegate()->show(Box<Ui::ConfirmBox>(
Lang::Hard::PassportCorruptedChange(),
Lang::Hard::PassportCorruptedReset(),
std::move(resetSecretAndSave)));
@@ -1085,7 +1086,7 @@ void PasscodeBox::recoverByEmail() {
}
});
});
*confirmBox = getDelegate()->show(Box<ConfirmBox>(
*confirmBox = getDelegate()->show(Box<Ui::ConfirmBox>(
tr::lng_cloud_password_reset_no_email(tr::now),
tr::lng_cloud_password_reset_ok(tr::now),
reset));
@@ -1170,7 +1171,7 @@ RecoverBox::RecoverBox(
}
});
});
*confirmBox = getDelegate()->show(Box<ConfirmBox>(
*confirmBox = getDelegate()->show(Box<Ui::ConfirmBox>(
tr::lng_cloud_password_reset_with_email(tr::now),
tr::lng_cloud_password_reset_ok(tr::now),
reset));
@@ -1272,7 +1273,7 @@ void RecoverBox::submit() {
send();
close();
};
getDelegate()->show(Box<ConfirmBox>(
getDelegate()->show(Box<Ui::ConfirmBox>(
tr::lng_cloud_password_passport_losing(tr::now),
tr::lng_continue(tr::now),
confirmed));
@@ -1297,7 +1298,7 @@ void RecoverBox::proceedToClear() {
_submitRequest = 0;
_newPasswordSet.fire({});
getDelegate()->show(
Box<InformBox>(tr::lng_cloud_password_removed(tr::now)),
Box<Ui::InformBox>(tr::lng_cloud_password_removed(tr::now)),
Ui::LayerOption::CloseOther);
}
@@ -1345,7 +1346,7 @@ void RecoverBox::checkSubmitFail(const MTP::Error &error) {
if (err == qstr("PASSWORD_EMPTY")) {
_newPasswordSet.fire(QByteArray());
getDelegate()->show(
Box<InformBox>(tr::lng_cloud_password_removed(tr::now)),
Box<Ui::InformBox>(tr::lng_cloud_password_removed(tr::now)),
Ui::LayerOption::CloseOther);
} else if (err == qstr("PASSWORD_RECOVERY_NA")) {
closeBox();
@@ -1386,7 +1387,8 @@ RecoveryEmailValidation ConfirmRecoveryEmail(
reloads->fire({});
if (*weak) {
(*weak)->getDelegate()->show(
Box<InformBox>(tr::lng_cloud_password_was_set(tr::now)),
Box<Ui::InformBox>(
tr::lng_cloud_password_was_set(tr::now)),
Ui::LayerOption::CloseOther);
}
}).fail([=](const MTP::Error &error) {
@@ -1398,7 +1400,7 @@ RecoveryEmailValidation ConfirmRecoveryEmail(
} else if (error.type() == qstr("EMAIL_HASH_EXPIRED")) {
cancels->fire({});
if (*weak) {
auto box = Box<InformBox>(
auto box = Box<Ui::InformBox>(
Lang::Hard::EmailConfirmationExpired());
(*weak)->getDelegate()->show(
std::move(box),

View File

@@ -1240,7 +1240,7 @@ int PeerListContent::resizeGetHeight(int newWidth) {
return belowTop + _belowHeight;
}
void PeerListContent::enterEventHook(QEvent *e) {
void PeerListContent::enterEventHook(QEnterEvent *e) {
setMouseTracking(true);
}

View File

@@ -622,7 +622,7 @@ protected:
int visibleBottom) override;
void paintEvent(QPaintEvent *e) override;
void enterEventHook(QEvent *e) override;
void enterEventHook(QEnterEvent *e) override;
void leaveEventHook(QEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;

View File

@@ -7,8 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/peer_list_controllers.h"
#include "base/openssl_help.h"
#include "boxes/confirm_box.h"
#include "base/random.h"
#include "ui/boxes/confirm_box.h"
#include "ui/widgets/checkbox.h"
#include "ui/ui_utility.h"
#include "main/main_session.h"
@@ -36,7 +36,7 @@ void ShareBotGame(not_null<UserData*> bot, not_null<PeerData*> chat) {
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
const auto randomId = openssl::RandomValue<uint64>();
const auto randomId = base::RandomValue<uint64>();
const auto api = &chat->session().api();
history->sendRequestId = api->request(MTPmessages_SendMedia(
MTP_flags(0),
@@ -482,7 +482,7 @@ void AddBotToGroupBoxController::shareBotGame(not_null<PeerData*> chat) {
return tr::lng_bot_sure_share_game_group(tr::now, lt_group, chat->name);
}();
Ui::show(
Box<ConfirmBox>(confirmText, std::move(send)),
Box<Ui::ConfirmBox>(confirmText, std::move(send)),
Ui::LayerOption::KeepOther);
}
@@ -490,7 +490,7 @@ void AddBotToGroupBoxController::addBotToGroup(not_null<PeerData*> chat) {
if (const auto megagroup = chat->asMegagroup()) {
if (!megagroup->canAddMembers()) {
Ui::show(
Box<InformBox>(tr::lng_error_cant_add_member(tr::now)),
Box<Ui::InformBox>(tr::lng_error_cant_add_member(tr::now)),
Ui::LayerOption::KeepOther);
return;
}
@@ -500,7 +500,7 @@ void AddBotToGroupBoxController::addBotToGroup(not_null<PeerData*> chat) {
});
auto confirmText = tr::lng_bot_sure_invite(tr::now, lt_group, chat->name);
Ui::show(
Box<ConfirmBox>(confirmText, send),
Box<Ui::ConfirmBox>(confirmText, send),
Ui::LayerOption::KeepOther);
}

View File

@@ -9,7 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_participant_box.h"
#include "boxes/peers/edit_peer_type_box.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/max_invite_box.h"
#include "lang/lang_keys.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
@@ -105,7 +106,8 @@ void AddParticipantsBoxController::rowClicked(not_null<PeerListRow*> row) {
} else if (count >= serverConfig.chatSizeMax
&& count < serverConfig.megagroupSizeMax) {
Ui::show(
Box<InformBox>(tr::lng_profile_add_more_after_create(tr::now)),
Box<Ui::InformBox>(
tr::lng_profile_add_more_after_create(tr::now)),
Ui::LayerOption::KeepOther);
}
}
@@ -565,20 +567,20 @@ void AddSpecialBoxController::showAdmin(
if (canBanMembers) {
if (!sure) {
_editBox = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_sure_add_admin_unremove(tr::now),
showAdminSure),
Ui::LayerOption::KeepOther);
return;
}
} else {
Ui::show(Box<InformBox>(
Ui::show(Box<Ui::InformBox>(
tr::lng_error_cant_add_admin_unban(tr::now)),
Ui::LayerOption::KeepOther);
return;
}
} else {
Ui::show(Box<InformBox>(
Ui::show(Box<Ui::InformBox>(
tr::lng_error_cant_add_admin_invite(tr::now)),
Ui::LayerOption::KeepOther);
return;
@@ -588,14 +590,14 @@ void AddSpecialBoxController::showAdmin(
if (canBanMembers) {
if (!sure) {
_editBox = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_sure_add_admin_unremove(tr::now),
showAdminSure),
Ui::LayerOption::KeepOther);
return;
}
} else {
Ui::show(Box<InformBox>(
Ui::show(Box<Ui::InformBox>(
tr::lng_error_cant_add_admin_unban(tr::now)),
Ui::LayerOption::KeepOther);
return;
@@ -608,7 +610,7 @@ void AddSpecialBoxController::showAdmin(
? tr::lng_sure_add_admin_invite
: tr::lng_sure_add_admin_invite_channel)(tr::now);
_editBox = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
text,
showAdminSure),
Ui::LayerOption::KeepOther);
@@ -616,7 +618,8 @@ void AddSpecialBoxController::showAdmin(
}
} else {
Ui::show(
Box<InformBox>(tr::lng_error_cant_add_admin_invite(tr::now)),
Box<Ui::InformBox>(
tr::lng_error_cant_add_admin_invite(tr::now)),
Ui::LayerOption::KeepOther);
return;
}
@@ -716,7 +719,7 @@ void AddSpecialBoxController::showRestricted(
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
if (!sure) {
_editBox = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_sure_ban_admin(tr::now),
showRestrictedSure),
Ui::LayerOption::KeepOther);
@@ -724,7 +727,7 @@ void AddSpecialBoxController::showRestricted(
}
} else {
Ui::show(
Box<InformBox>(tr::lng_error_cant_ban_admin(tr::now)),
Box<Ui::InformBox>(tr::lng_error_cant_ban_admin(tr::now)),
Ui::LayerOption::KeepOther);
return;
}
@@ -813,7 +816,7 @@ void AddSpecialBoxController::kickUser(
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
if (!sure) {
_editBox = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_sure_ban_admin(tr::now),
kickUserSure),
Ui::LayerOption::KeepOther);
@@ -821,7 +824,7 @@ void AddSpecialBoxController::kickUser(
}
} else {
Ui::show(
Box<InformBox>(tr::lng_error_cant_ban_admin(tr::now)),
Box<Ui::InformBox>(tr::lng_error_cant_ban_admin(tr::now)),
Ui::LayerOption::KeepOther);
return;
}
@@ -836,7 +839,7 @@ void AddSpecialBoxController::kickUser(
lt_user,
participant->name);
_editBox = Ui::show(
Box<ConfirmBox>(text, kickUserSure),
Box<Ui::ConfirmBox>(text, kickUserSure),
Ui::LayerOption::KeepOther);
return;
}

View File

@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_session.h"
#include "boxes/peers/edit_peer_common.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/input_fields.h"
@@ -26,8 +27,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kMaxUserFirstLastName = 64; // See also add_contact_box.
QString UserPhone(not_null<UserData*> user) {
const auto phone = user->phone();
return phone.isEmpty()
@@ -222,8 +221,8 @@ void Controller::initNameFields(
};
QObject::connect(first, &Ui::InputField::submitted, submit);
QObject::connect(last, &Ui::InputField::submitted, submit);
first->setMaxLength(kMaxUserFirstLastName);
first->setMaxLength(kMaxUserFirstLastName);
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
}
void Controller::setupWarning() {

View File

@@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h"
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
#include "boxes/peer_list_box.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/add_contact_box.h"
#include "apiwrap.h"
#include "facades.h"
@@ -152,7 +152,7 @@ void Controller::choose(not_null<ChannelData*> chat) {
onstack(chat);
};
Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
text,
tr::lng_manage_discussion_group_link(tr::now),
sure),
@@ -184,7 +184,7 @@ void Controller::choose(not_null<ChatData*> chat) {
chat->session().api().migrateChat(chat, crl::guard(this, done));
};
Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
text,
tr::lng_manage_discussion_group_link(tr::now),
sure),

View File

@@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/special_buttons.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "settings/settings_privacy_security.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/passcode_box.h"
#include "boxes/peers/edit_peer_permissions_box.h"
#include "boxes/peers/edit_peer_info_box.h"
@@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "core/core_cloud_password.h"
#include "base/unixtime.h"
#include "base/qt_adapters.h"
#include "apiwrap.h"
#include "api/api_cloud_password.h"
#include "main/main_session.h"
@@ -453,7 +452,14 @@ void EditAdminBox::transferOwnership() {
)).fail([=](const MTP::Error &error) {
_checkTransferRequestId = 0;
if (!handleTransferPasswordError(error)) {
getDelegate()->show(Box<ConfirmBox>(
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
const auto callback = crl::guard(this, [=] {
transferOwnershipChecked();
if (*box) {
(*box)->closeBox();
}
});
*box = getDelegate()->show(Box<Ui::ConfirmBox>(
tr::lng_rights_transfer_about(
tr::now,
lt_group,
@@ -462,7 +468,7 @@ void EditAdminBox::transferOwnership() {
Ui::Text::Bold(user()->shortName()),
Ui::Text::RichLangValue),
tr::lng_rights_transfer_sure(tr::now),
crl::guard(this, [=] { transferOwnershipChecked(); })));
callback));
}
}).send();
}
@@ -570,7 +576,7 @@ void EditAdminBox::sendTransferRequestFrom(
|| (type == qstr("SESSION_TOO_FRESH_XXX"));
}();
const auto weak = Ui::MakeWeak(this);
getDelegate()->show(Box<InformBox>(problem));
getDelegate()->show(Box<Ui::InformBox>(problem));
if (box) {
box->closeBox();
}
@@ -703,7 +709,7 @@ void EditRestrictedBox::showRestrictUntil() {
highlighted,
[this](const QDate &date) {
setRestrictUntil(
static_cast<int>(base::QDateToDateTime(date).toTime_t()));
static_cast<int>(date.startOfDay().toSecsSinceEpoch()));
}),
Ui::LayerOption::KeepOther);
_restrictUntilBox->setMaxDate(

View File

@@ -10,7 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/edit_participant_box.h"
#include "boxes/peers/add_participants_box.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/max_invite_box.h"
#include "boxes/add_contact_box.h"
#include "main/main_session.h"
#include "mtproto/mtproto_config.h"
@@ -1690,7 +1691,7 @@ void ParticipantsBoxController::kickParticipant(not_null<PeerData*> participant)
lt_user,
user ? user->firstName : participant->name);
_editBox = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
text,
tr::lng_box_remove(tr::now),
crl::guard(this, [=] { kickParticipantSure(participant); })),
@@ -1729,7 +1730,7 @@ void ParticipantsBoxController::kickParticipantSure(
void ParticipantsBoxController::removeAdmin(not_null<UserData*> user) {
_editBox = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_profile_sure_remove_admin(
tr::now,
lt_user,

View File

@@ -0,0 +1,18 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Ui::EditPeer {
constexpr auto kMaxGroupChannelTitle = 128;
constexpr auto kMaxUserFirstLastName = 64;
constexpr auto kMaxChannelDescription = 255;
constexpr auto kMinUsernameLength = 5;
constexpr auto kUsernameCheckTimeout = crl::time(200);
} // namespace Ui::EditPeer

View File

@@ -8,11 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_peer_info_box.h"
#include "apiwrap.h"
#include "api/api_peer_photo.h"
#include "main/main_session.h"
#include "boxes/add_contact_box.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/edit_participants_box.h"
#include "boxes/peers/edit_peer_common.h"
#include "boxes/peers/edit_peer_type_box.h"
#include "boxes/peers/edit_peer_history_visibility_box.h"
#include "boxes/peers/edit_peer_permissions_box.h"
@@ -249,9 +251,6 @@ void ShowEditPermissions(
namespace {
constexpr auto kMaxGroupChannelTitle = 128; // See also add_contact_box.
constexpr auto kMaxChannelDescription = 255; // See also add_contact_box.
class Controller : public base::has_weak_ptr {
public:
Controller(
@@ -475,7 +474,7 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
: tr::lng_dlg_new_channel_name)(),
_peer->name),
st::editPeerTitleMargins);
result->entity()->setMaxLength(kMaxGroupChannelTitle);
result->entity()->setMaxLength(Ui::EditPeer::kMaxGroupChannelTitle);
result->entity()->setInstantReplaces(Ui::InstantReplaces::Default());
result->entity()->setInstantReplacesEnabled(
Core::App().settings().replaceEmojiValue());
@@ -509,7 +508,7 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
tr::lng_create_group_description(),
_peer->about()),
st::editPeerDescriptionMargins);
result->entity()->setMaxLength(kMaxChannelDescription);
result->entity()->setMaxLength(Ui::EditPeer::kMaxChannelDescription);
result->entity()->setInstantReplaces(Ui::InstantReplaces::Default());
result->entity()->setInstantReplacesEnabled(
Core::App().settings().replaceEmojiValue());
@@ -1471,7 +1470,7 @@ void Controller::savePhoto() {
? _controls.photo->takeResultImage()
: QImage();
if (!image.isNull()) {
_peer->session().api().uploadPeerPhoto(_peer, std::move(image));
_peer->session().api().peerPhoto().upload(_peer, std::move(image));
}
_box->closeBox();
}
@@ -1487,7 +1486,7 @@ void Controller::deleteWithConfirmation() {
deleteChannel();
});
_navigation->parentController()->show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
text,
tr::lng_box_delete(tr::now),
st::attentionBoxButton,
@@ -1514,7 +1513,7 @@ void Controller::deleteChannel() {
session->api().applyUpdates(result);
//}).fail([=](const MTP::Error &error) {
// if (error.type() == qstr("CHANNEL_TOO_LARGE")) {
// Ui::show(Box<InformBox>(tr::lng_cant_delete_channel(tr::now)));
// Ui::show(Box<Ui::InformBox>(tr::lng_cant_delete_channel(tr::now)));
// }
}).send();
}

View File

@@ -30,7 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_group_call_tracker.h" // GenerateUs...
#include "history/history_message.h" // GetErrorTextForSending.
#include "history/history.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/peer_list_box.h"
#include "mainwindow.h"
#include "facades.h" // Ui::showPerProfile.
@@ -680,7 +680,7 @@ void AddPermanentLinkBlock(
}
});
const auto revokeLink = crl::guard(weak, [=] {
const auto box = std::make_shared<QPointer<ConfirmBox>>();
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
const auto done = crl::guard(weak, [=] {
const auto close = [=] {
if (*box) {
@@ -694,7 +694,9 @@ void AddPermanentLinkBlock(
close);
});
*box = Ui::show(
Box<ConfirmBox>(tr::lng_group_invite_about_new(tr::now), done),
Box<Ui::ConfirmBox>(
tr::lng_group_invite_about_new(tr::now),
done),
Ui::LayerOption::KeepOther);
});
@@ -868,7 +870,7 @@ void ShareInviteLinkBox(not_null<PeerData*> peer, const QString &link) {
}
text.append(error.first);
Ui::show(
Box<InformBox>(text),
Box<Ui::InformBox>(text),
Ui::LayerOption::KeepOther);
return;
}
@@ -968,7 +970,7 @@ void RevokeLink(
not_null<PeerData*> peer,
not_null<UserData*> admin,
const QString &link) {
const auto box = std::make_shared<QPointer<ConfirmBox>>();
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
const auto revoke = [=] {
const auto done = [=](const LinkData &data) {
if (*box) {
@@ -978,7 +980,7 @@ void RevokeLink(
peer->session().api().inviteLinks().revoke(peer, admin, link, done);
};
*box = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
tr::lng_group_invite_revoke_about(tr::now),
revoke),
Ui::LayerOption::KeepOther);
@@ -988,7 +990,7 @@ void DeleteLink(
not_null<PeerData*> peer,
not_null<UserData*> admin,
const QString &link) {
const auto box = std::make_shared<QPointer<ConfirmBox>>();
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
const auto sure = [=] {
const auto finish = [=] {
if (*box) {
@@ -1002,7 +1004,7 @@ void DeleteLink(
finish);
};
*box = Ui::show(
Box<ConfirmBox>(tr::lng_group_invite_delete_sure(tr::now), sure),
Box<Ui::ConfirmBox>(tr::lng_group_invite_delete_sure(tr::now), sure),
Ui::LayerOption::KeepOther);
}

View File

@@ -18,7 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/popup_menu.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/edit_peer_invite_link.h"
#include "settings/settings_common.h" // AddDivider.
@@ -197,7 +197,7 @@ private:
void DeleteAllRevoked(
not_null<PeerData*> peer,
not_null<UserData*> admin) {
const auto box = std::make_shared<QPointer<ConfirmBox>>();
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
const auto sure = [=] {
const auto finish = [=] {
if (*box) {
@@ -210,7 +210,9 @@ void DeleteAllRevoked(
finish);
};
*box = Ui::show(
Box<ConfirmBox>(tr::lng_group_invite_delete_all_sure(tr::now), sure),
Box<Ui::ConfirmBox>(
tr::lng_group_invite_delete_all_sure(tr::now),
sure),
Ui::LayerOption::KeepOther);
}
@@ -268,7 +270,8 @@ void Row::update(const InviteLinkData &data, TimeId now) {
void Row::updateExpireProgress(TimeId now) {
const auto updated = ComputeProgress(_data, now);
if (std::round(_progressTillExpire * 360) != std::round(updated * 360)) {
if (base::SafeRound(_progressTillExpire * 360)
!= base::SafeRound(updated * 360)) {
_progressTillExpire = updated;
const auto color = ComputeColor(_data, _progressTillExpire);
if (_color != color) {
@@ -291,7 +294,8 @@ crl::time Row::updateExpireIn() const {
if (_data.expireDate <= start) {
return 0;
}
return std::round((_data.expireDate - start) * crl::time(1000) / 720.);
return base::SafeRound(
(_data.expireDate - start) * crl::time(1000) / 720.);
}
QString Row::generateName() {

View File

@@ -11,9 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_invite_links.h"
#include "main/main_session.h"
#include "boxes/add_contact_box.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/edit_participants_box.h"
#include "boxes/peers/edit_peer_common.h"
#include "boxes/peers/edit_peer_info_box.h" // CreateButton.
#include "boxes/peers/edit_peer_invite_link.h"
#include "boxes/peers/edit_peer_invite_links.h"
@@ -55,9 +56,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kUsernameCheckTimeout = crl::time(200);
constexpr auto kMinUsernameLength = 5;
class Controller : public base::has_weak_ptr {
public:
Controller(
@@ -419,7 +417,7 @@ void Controller::checkUsernameAvailability() {
const auto checking = initial
? qsl(".bad.")
: getUsernameInput();
if (checking.size() < kMinUsernameLength) {
if (checking.size() < Ui::EditPeer::kMinUsernameLength) {
return;
}
if (_checkUsernameRequestId) {
@@ -496,11 +494,11 @@ void Controller::usernameChanged() {
});
if (bad) {
showUsernameError(tr::lng_create_channel_link_bad_symbols());
} else if (username.size() < kMinUsernameLength) {
} else if (username.size() < Ui::EditPeer::kMinUsernameLength) {
showUsernameError(tr::lng_create_channel_link_too_short());
} else {
_controls.usernameResult = nullptr;
_checkUsernameTimer.callOnce(kUsernameCheckTimeout);
_checkUsernameTimer.callOnce(Ui::EditPeer::kUsernameCheckTimeout);
}
}

View File

@@ -0,0 +1,68 @@
/*
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 "boxes/phone_banned_box.h"
#include "ui/boxes/confirm_box.h"
#include "core/click_handler_types.h" // UrlClickHandler
#include "base/qthelp_url.h" // qthelp::url_encode
#include "base/platform/base_platform_info.h"
#include "window/window_controller.h"
#include "lang/lang_keys.h"
namespace Ui {
namespace {
void SendToBannedHelp(const QString &phone) {
const auto version = QString::fromLatin1(AppVersionStr)
+ (cAlphaVersion()
? qsl(" alpha %1").arg(cAlphaVersion())
: (AppBetaVersion ? " beta" : ""));
const auto subject = qsl("Banned phone number: ") + phone;
const auto body = qsl("\
I'm trying to use my mobile phone number: ") + phone + qsl("\n\
But Telegram says it's banned. Please help.\n\
\n\
App version: ") + version + qsl("\n\
OS version: ") + ::Platform::SystemVersionPretty() + qsl("\n\
Locale: ") + ::Platform::SystemLanguage();
const auto url = "mailto:?to="
+ qthelp::url_encode("login@stel.com")
+ "&subject="
+ qthelp::url_encode(subject)
+ "&body="
+ qthelp::url_encode(body);
UrlClickHandler::Open(url);
}
} // namespace
void ShowPhoneBannedError(
not_null<Window::Controller*> controller,
const QString &phone) {
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto close = [=] {
if (*box) {
(*box)->closeBox();
}
};
*box = controller->show(
Box<Ui::ConfirmBox>(
tr::lng_signin_banned_text(tr::now),
tr::lng_box_ok(tr::now),
tr::lng_signin_banned_help(tr::now),
close,
[=] { SendToBannedHelp(phone); close(); }),
Ui::LayerOption::CloseOther);
}
} // namespace Ui

View File

@@ -0,0 +1,20 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Window {
class Controller;
} // namespace Window
namespace Ui {
void ShowPhoneBannedError(
not_null<Window::Controller*> controller,
const QString &phone);
} // namespace Ui

View File

@@ -0,0 +1,129 @@
/*
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 "boxes/pin_messages_box.h"
#include "apiwrap.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/labels.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
namespace {
[[nodiscard]] bool IsOldForPin(MsgId id, not_null<PeerData*> peer) {
const auto normal = peer->migrateToOrMe();
const auto migrated = normal->migrateFrom();
const auto top = Data::ResolveTopPinnedId(normal, migrated);
if (!top) {
return false;
} else if (peer == migrated) {
return top.channel || (id < top.msg);
} else if (migrated) {
return top.channel && (id < top.msg);
} else {
return (id < top.msg);
}
}
} // namespace
PinMessageBox::PinMessageBox(
QWidget*,
not_null<PeerData*> peer,
MsgId msgId)
: _peer(peer)
, _api(&peer->session().mtp())
, _msgId(msgId)
, _pinningOld(IsOldForPin(msgId, peer))
, _text(
this,
(_pinningOld
? tr::lng_pinned_pin_old_sure(tr::now)
: (peer->isChat() || peer->isMegagroup())
? tr::lng_pinned_pin_sure_group(tr::now)
: tr::lng_pinned_pin_sure(tr::now)),
st::boxLabel) {
}
void PinMessageBox::prepare() {
addButton(tr::lng_pinned_pin(), [this] { pinMessage(); });
addButton(tr::lng_cancel(), [this] { closeBox(); });
if (_peer->isUser() && !_peer->isSelf()) {
_pinForPeer.create(
this,
tr::lng_pinned_also_for_other(
tr::now,
lt_user,
_peer->shortName()),
false,
st::defaultBoxCheckbox);
_checkbox = _pinForPeer;
} else if (!_pinningOld && (_peer->isChat() || _peer->isMegagroup())) {
_notify.create(
this,
tr::lng_pinned_notify(tr::now),
true,
st::defaultBoxCheckbox);
_checkbox = _notify;
}
auto height = st::boxPadding.top()
+ _text->height()
+ st::boxPadding.bottom();
if (_checkbox) {
height += st::boxMediumSkip + _checkbox->heightNoMargins();
}
setDimensions(st::boxWidth, height);
}
void PinMessageBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
if (_checkbox) {
_checkbox->moveToLeft(
st::boxPadding.left(),
_text->y() + _text->height() + st::boxMediumSkip);
}
}
void PinMessageBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
pinMessage();
} else {
BoxContent::keyPressEvent(e);
}
}
void PinMessageBox::pinMessage() {
if (_requestId) {
return;
}
auto flags = MTPmessages_UpdatePinnedMessage::Flags(0);
if (_notify && !_notify->checked()) {
flags |= MTPmessages_UpdatePinnedMessage::Flag::f_silent;
}
if (_pinForPeer && !_pinForPeer->checked()) {
flags |= MTPmessages_UpdatePinnedMessage::Flag::f_pm_oneside;
}
_requestId = _api.request(MTPmessages_UpdatePinnedMessage(
MTP_flags(flags),
_peer->input,
MTP_int(_msgId)
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
Ui::hideLayer();
}).fail([=](const MTP::Error &error) {
Ui::hideLayer();
}).send();
}

View File

@@ -0,0 +1,43 @@
/*
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 "boxes/abstract_box.h"
#include "mtproto/sender.h"
namespace Ui {
class Checkbox;
class FlatLabel;
} // namespace Ui
class PinMessageBox final : public Ui::BoxContent {
public:
PinMessageBox(QWidget*, not_null<PeerData*> peer, MsgId msgId);
protected:
void prepare() override;
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
private:
void pinMessage();
const not_null<PeerData*> _peer;
MTP::Sender _api;
MsgId _msgId = 0;
bool _pinningOld = false;
object_ptr<Ui::FlatLabel> _text;
object_ptr<Ui::Checkbox> _notify = { nullptr };
object_ptr<Ui::Checkbox> _pinForPeer = { nullptr };
QPointer<Ui::Checkbox> _checkbox;
mtpRequestId _requestId = 0;
};

View File

@@ -1,143 +0,0 @@
/*
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 "boxes/rate_call_box.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "mainwindow.h"
#include "main/main_session.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "apiwrap.h"
#include "styles/style_layers.h"
#include "styles/style_calls.h"
namespace {
constexpr auto kMaxRating = 5;
constexpr auto kRateCallCommentLengthMax = 200;
} // namespace
RateCallBox::RateCallBox(
QWidget*,
not_null<Main::Session*> session,
uint64 callId,
uint64 callAccessHash)
: _session(session)
, _api(&_session->mtp())
, _callId(callId)
, _callAccessHash(callAccessHash) {
}
void RateCallBox::prepare() {
setTitle(tr::lng_call_rate_label());
addButton(tr::lng_cancel(), [this] { closeBox(); });
for (auto i = 0; i < kMaxRating; ++i) {
_stars.emplace_back(this, st::callRatingStar);
_stars.back()->setClickedCallback([this, value = i + 1] { ratingChanged(value); });
_stars.back()->show();
}
updateMaxHeight();
}
void RateCallBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
auto starsWidth = (_stars.size() * st::callRatingStar.width);
auto starLeft = (width() - starsWidth) / 2;
auto starTop = st::callRatingStarTop;
for (auto &star : _stars) {
star->moveToLeft(starLeft, starTop);
starLeft += star->width();
}
if (_comment) {
_comment->moveToLeft(st::callRatingPadding.left(), _stars.back()->bottomNoMargins() + st::callRatingCommentTop);
}
}
void RateCallBox::ratingChanged(int value) {
Expects(value > 0 && value <= kMaxRating);
if (!_rating) {
clearButtons();
addButton(tr::lng_send_button(), [this] { send(); });
addButton(tr::lng_cancel(), [this] { closeBox(); });
}
_rating = value;
for (auto i = 0; i < kMaxRating; ++i) {
_stars[i]->setIconOverride((i < value) ? &st::callRatingStarFilled : nullptr);
_stars[i]->setRippleColorOverride((i < value) ? &st::lightButtonBgOver : nullptr);
}
if (value < kMaxRating) {
if (!_comment) {
_comment.create(
this,
st::callRatingComment,
Ui::InputField::Mode::MultiLine,
tr::lng_call_rate_comment());
_comment->show();
_comment->setSubmitSettings(Core::App().settings().sendSubmitWay());
_comment->setMaxLength(kRateCallCommentLengthMax);
_comment->resize(width() - (st::callRatingPadding.left() + st::callRatingPadding.right()), _comment->height());
updateMaxHeight();
connect(_comment, &Ui::InputField::resized, [=] { commentResized(); });
connect(_comment, &Ui::InputField::submitted, [=] { send(); });
connect(_comment, &Ui::InputField::cancelled, [=] { closeBox(); });
}
_comment->setFocusFast();
} else if (_comment) {
_comment.destroy();
updateMaxHeight();
}
}
void RateCallBox::setInnerFocus() {
if (_comment) {
_comment->setFocusFast();
} else {
setFocus();
}
}
void RateCallBox::commentResized() {
updateMaxHeight();
update();
}
void RateCallBox::send() {
Expects(_rating > 0 && _rating <= kMaxRating);
if (_requestId) {
return;
}
auto comment = _comment ? _comment->getLastText().trimmed() : QString();
_requestId = _api.request(MTPphone_SetCallRating(
MTP_flags(0),
MTP_inputPhoneCall(MTP_long(_callId), MTP_long(_callAccessHash)),
MTP_int(_rating),
MTP_string(comment)
)).done([=](const MTPUpdates &updates) {
_session->api().applyUpdates(updates);
closeBox();
}).fail([=](const MTP::Error &error) { closeBox(); }).send();
}
void RateCallBox::updateMaxHeight() {
auto newHeight = st::callRatingPadding.top() + st::callRatingStarTop + _stars.back()->heightNoMargins() + st::callRatingPadding.bottom();
if (_comment) {
newHeight += st::callRatingCommentTop + _comment->height();
}
setDimensions(st::boxWideWidth, newHeight);
}

View File

@@ -19,7 +19,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "confirm_box.h"
#include "editor/photo_editor_layer_widget.h"
#include "history/history_drag_area.h"
#include "history/view/history_view_schedule_box.h"
@@ -549,9 +548,6 @@ void SendFilesBox::pushBlock(int from, int till) {
block.takeWidget(),
QMargins(0, _inner->count() ? st::sendMediaRowSkip : 0, 0, 0));
const auto preventDelete =
widget->lifetime().make_state<rpl::event_stream<int>>();
block.itemDeleteRequest(
) | rpl::filter([=] {
return !_removingIndex;
@@ -562,9 +558,9 @@ void SendFilesBox::pushBlock(int from, int till) {
if (index < 0 || index >= _list.files.size()) {
return;
}
// Prevent item delete if it is the only one.
// Just close the box if it is the only one.
if (_list.files.size() == 1) {
preventDelete->fire_copy(0);
closeBox();
return;
}
_list.files.erase(_list.files.begin() + index);
@@ -572,9 +568,7 @@ void SendFilesBox::pushBlock(int from, int till) {
});
}, widget->lifetime());
rpl::merge(
block.itemReplaceRequest(),
preventDelete->events()
block.itemReplaceRequest(
) | rpl::start_with_next([=](int index) {
const auto replace = [=](Ui::PreparedList list) {
if (list.files.empty()) {

View File

@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_authorizations.h"
#include "base/timer.h"
#include "base/unixtime.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "styles/style_boxes.h"
@@ -81,7 +81,7 @@ private:
Full _data;
object_ptr<Inner> _inner;
QPointer<ConfirmBox> _terminateBox;
QPointer<Ui::ConfirmBox> _terminateBox;
base::Timer _shortPollTimer;
@@ -250,7 +250,7 @@ void SessionsContent::terminate(Fn<void()> terminateRequest, QString message) {
terminateRequest();
});
_terminateBox = Ui::show(
Box<ConfirmBox>(
Box<Ui::ConfirmBox>(
message,
tr::lng_settings_reset_button(tr::now),
st::attentionBoxButton,

View File

@@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwidget.h"
#include "base/qthelp_url.h"
#include "storage/storage_account.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "apiwrap.h"
#include "ui/toast/toast.h"
#include "ui/widgets/multi_select.h"
@@ -72,7 +72,7 @@ protected:
int visibleBottom) override;
void paintEvent(QPaintEvent *e) override;
void enterEventHook(QEvent *e) override;
void enterEventHook(QEnterEvent *e) override;
void leaveEventHook(QEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
@@ -906,7 +906,7 @@ void ShareBox::Inner::paintEvent(QPaintEvent *e) {
}
}
void ShareBox::Inner::enterEventHook(QEvent *e) {
void ShareBox::Inner::enterEventHook(QEnterEvent *e) {
setMouseTracking(true);
}
@@ -1113,7 +1113,7 @@ QString AppendShareGameScoreUrl(
auto channelAccessHash = uint64(channel ? channel->access : 0);
shareHashDataInts[0] = session->userId().bare;
shareHashDataInts[1] = fullId.channel.bare;
shareHashDataInts[2] = fullId.msg;
shareHashDataInts[2] = uint64(fullId.msg.bare);
shareHashDataInts[3] = channelAccessHash;
// Count SHA1() of data.
@@ -1155,7 +1155,8 @@ void ShareGameScoreByHash(
auto hashEncrypted = QByteArray::fromBase64(hash.toLatin1(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (hashEncrypted.size() <= key128Size || (hashEncrypted.size() != key128Size + 0x20)) {
Ui::show(Box<InformBox>(tr::lng_confirm_phone_link_invalid(tr::now)));
Ui::show(Box<Ui::InformBox>(
tr::lng_confirm_phone_link_invalid(tr::now)));
return;
}
@@ -1175,19 +1176,19 @@ void ShareGameScoreByHash(
//// Check next 64 bits of SHA1() of data.
//auto skipSha1Part = sizeof(channelAccessHash);
//if (memcmp(dataSha1 + skipSha1Part, hashEncrypted.constData() + skipSha1Part, key128Size - skipSha1Part) != 0) {
// Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
// Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
// return;
//}
// Check 128 bits of SHA1() of data.
if (memcmp(dataSha1, hashEncrypted.constData(), key128Size) != 0) {
Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
return;
}
auto hashDataInts = reinterpret_cast<uint64*>(hashData.data());
if (hashDataInts[0] != session->userId().bare) {
Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
return;
}
@@ -1195,20 +1196,19 @@ void ShareGameScoreByHash(
auto channelAccessHash = hashDataInts[3];
//auto channelAccessHashInts = reinterpret_cast<int32*>(&channelAccessHash);
//if (channelAccessHashInts[0] != hashDataInts[3]) {
// Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
// Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
// return;
//}
if (((hashDataInts[1] >> 40) != 0)
|| ((hashDataInts[2] >> 32) != 0)
|| (!hashDataInts[1] && channelAccessHash)) {
// If there is no channel id, there should be no channel access_hash.
Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
return;
}
auto channelId = ChannelId(hashDataInts[1]);
auto msgId = MsgId(hashDataInts[2]);
auto msgId = MsgId(int64(hashDataInts[2]));
if (const auto item = session->data().message(channelId, msgId)) {
FastShareMessage(item);
} else {
@@ -1219,7 +1219,8 @@ void ShareGameScoreByHash(
if (const auto item = session->data().message(channel, msgId)) {
FastShareMessage(item);
} else {
Ui::show(Box<InformBox>(tr::lng_edit_deleted(tr::now)));
Ui::show(Box<Ui::InformBox>(
tr::lng_edit_deleted(tr::now)));
}
});
};

View File

@@ -13,11 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document_media.h"
#include "data/stickers/data_stickers.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "ui/boxes/confirm_box.h"
#include "core/application.h"
#include "mtproto/sender.h"
#include "storage/storage_account.h"
#include "dialogs/dialogs_layout.h"
#include "dialogs/ui/dialogs_layout.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h"
#include "ui/image/image.h"
@@ -257,7 +257,7 @@ void StickerSetBox::handleError(Error error) {
switch (error) {
case Error::NotFound:
_controller->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
Box<Ui::InformBox>(tr::lng_stickers_not_found(tr::now)));
break;
default: Unexpected("Error in StickerSetBox::handleError.");
}
@@ -404,7 +404,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
auto p = StickersPack();
p.reserve(stickers.size());
for (auto j = 0, c = stickers.size(); j != c; ++j) {
for (auto j = 0, c = int(stickers.size()); j != c; ++j) {
auto doc = _controller->session().data().document(stickers[j].v);
if (!doc || !doc->sticker()) continue;
@@ -532,7 +532,7 @@ void StickerSetBox::Inner::installDone(
auto &order = isMasks
? stickers.maskSetsOrderRef()
: stickers.setsOrderRef();
const auto insertAtIndex = 0, currentIndex = order.indexOf(_setId);
const auto insertAtIndex = 0, currentIndex = int(order.indexOf(_setId));
if (currentIndex != insertAtIndex) {
if (currentIndex > 0) {
order.removeAt(currentIndex);

View File

@@ -11,13 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h"
#include "data/stickers/data_stickers.h"
class ConfirmBox;
namespace Window {
class SessionController;
} // namespace Window
namespace Ui {
class ConfirmBox;
class PlainShadow;
} // namespace Ui

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