Compare commits

...

430 Commits

Author SHA1 Message Date
John Preston
0b5500fe75 Version 1.6.2.
- Delete any message on both ends in any private chat, anytime.
- Control whether your forwarded messages link back to your account.
- Control who may see your profile picture.
- Enjoy the new streamlined group management screen.
2019-03-24 18:53:06 +04:00
John Preston
2845f48430 Closed alpha version 1.6.1.1. 2019-03-24 12:12:45 +04:00
John Preston
4ba959e6e1 Use sticker set thumbnails in StickersBox. 2019-03-24 12:12:45 +04:00
John Preston
72d9ac508a Use sticker set thumbnails in the panel. 2019-03-24 12:12:45 +04:00
John Preston
386600baf9 Save and load sticker set thumbnails. 2019-03-24 12:12:44 +04:00
John Preston
eb1825defd Add revoking of full history. 2019-03-24 12:12:44 +04:00
John Preston
33069739ee Improve revoke phrases. 2019-03-24 12:12:44 +04:00
John Preston
dd8c526fb7 Prepare code for revoking of full history. 2019-03-24 12:12:43 +04:00
John Preston
2701e63406 Allow revoking only sent messages. 2019-03-24 12:12:43 +04:00
John Preston
b972da059a Show explaining preview of forwards privacy. 2019-03-24 12:12:42 +04:00
John Preston
81862215b4 Add forwards and profile photo privacy settings. 2019-03-24 12:12:42 +04:00
John Preston
a34e998c42 Handle fwd_from without a link to the account. 2019-03-24 12:12:42 +04:00
John Preston
6d1193a751 Update API scheme to layer 97. 2019-03-24 12:12:41 +04:00
John Preston
0cd7399dc9 Update API scheme to layer 96. 2019-03-24 12:12:41 +04:00
John Preston
f1b0b60340 Fix possible crash in MainWindow destructor. 2019-03-24 12:12:41 +04:00
John Preston
d1cf43f9a4 Fix streaming receivedTill reporting.
It was incorrect in case audio and video had different durations.
2019-03-24 12:12:40 +04:00
John Preston
a0b3b1affd Fix fade in widget animation.
Fixes #5812.
2019-03-24 12:12:40 +04:00
John Preston
2a7fdfc832 Fix call icon position in single column info page. 2019-03-24 12:12:40 +04:00
John Preston
672070e618 Fix icon position in EditPeerInfoBox. 2019-03-24 12:12:39 +04:00
John Preston
6a2b1bb48d Fix HTML export wrapper. 2019-03-24 12:12:39 +04:00
John Preston
db121c0839 Take album caption from any album item. 2019-03-22 14:22:49 +04:00
23rd
ca9db9fd3f Refactored code.
- Removed std::optional from EditPeerHistoryVisibilityBox.
 - Added std::optional for savedCallback in EditPeerTypeBox.
 - Guarded boxCallbacks.
2019-03-22 13:40:23 +04:00
23rd
ecccf673a9 Deleted unused code of Delete Button. 2019-03-22 13:40:23 +04:00
John Preston
e0d7cae3fe Fix build for macOS. 2019-03-22 13:40:23 +04:00
John Preston
241526f127 Improve code style a bit. 2019-03-22 13:40:22 +04:00
23rd
4148099115 Redesigned Delete Button in EditPeerInfoBox. 2019-03-22 13:40:22 +04:00
23rd
5edf200157 Fixed focus in EditPeerTypeBox. Slightly refactored code. 2019-03-22 13:40:22 +04:00
23rd
bd7ba3acb1 Refactored code.
- Slightly improved design.
 - Added "const" in EditPeerTypeBox & EditPeerInfoBox.
2019-03-22 13:40:22 +04:00
23rd
e024d9bbb0 Added opening EditPeerTypeBox when error of saving username was handled. 2019-03-22 13:40:22 +04:00
23rd
3d7b8b3162 Added Invite Link button. Refactored code.
- Removed unused includes.
 - Improved design for boxes.
 - Draw buttons for EditPeerInfoBox in single place.
 - Simplified conditions for all buttons.
 - Made AddSkip more flexible.
2019-03-22 13:40:22 +04:00
23rd
8887272577 Refactored code. Removed unused code.
- Deleted manage_peer_box from sources.
2019-03-22 13:40:22 +04:00
23rd
c86257568f Fixed issue when "Too much usernames" box appearing only after typing. 2019-03-22 13:40:22 +04:00
23rd
ae25538706 Added opening of EditPeerInfoBox in new way. 2019-03-22 13:40:22 +04:00
23rd
21e417433b Added waiting for full data update of peer to open EditPeerInfoBox. 2019-03-22 13:40:22 +04:00
23rd
cb272be805 Refactored code. Slightly improved animations and design. 2019-03-22 13:40:22 +04:00
23rd
b79d8d6c82 Removed Checkbox for Sign Messages and added Toggle Button.
- That is how it looks in mobile clients.
2019-03-22 13:40:22 +04:00
23rd
be8aed6a95 Added GroupTypeBox with Controller. 2019-03-22 13:40:22 +04:00
23rd
d06337dddc Added HistoryVisibilityBox. 2019-03-22 13:40:22 +04:00
23rd
0f3ec47074 Begin of EditPeerBox redesigning.
- Moved buttons from ManageGroupBox to EditPeerBox.
 - Added counting of permissions.
2019-03-22 13:40:21 +04:00
23rd
3a5bad4b7a Fixed incorrect display of uploaded video's thumbnail in edited message.
- After uploading a video the data_document changes a source of the 
 good thumbnail and loses an information about it (e.g. width, height, 
 bytesSize).
2019-03-22 13:39:12 +04:00
23rd
2aecd1035e Removed "Export history" from context menu for empty chats. 2019-03-22 13:38:09 +04:00
23rd
5d04842a80 Refactored edit_caption_box. 2019-03-22 13:36:47 +04:00
23rd
59c73a4814 Fixed drawing of custom thumbnails in edit_caption_box. 2019-03-22 13:36:47 +04:00
John Preston
25affe5484 Version 1.6.1.
- Bug fixes and other minor improvements.
2019-03-20 14:32:34 +04:00
John Preston
399aed4087 Remove setting for Mac App Store version. 2019-03-20 14:31:32 +04:00
John Preston
31dbe2278e Fix possible crash in local file streaming.
Cache file size instead of requesting it from file system each time.
2019-03-20 14:21:50 +04:00
John Preston
9ed064b7fc Fix crash in streaming parts loading. 2019-03-20 13:41:13 +04:00
John Preston
a59353df9f Fix possible crash in DomainResolver.
App::CallDelayed() could be queued twice for a single key, if before
the delayed call we cleared entry in _attempts and created it again.
2019-03-20 13:23:16 +04:00
John Preston
8acd47bf2f Fix pre-history visibility rights check. 2019-03-20 13:22:58 +04:00
John Preston
be53cb027c Possibly fix a crash in microphone testing. 2019-03-20 13:00:38 +04:00
John Preston
6ff8c1de05 Fix possible crash in layers destruction.
clearClosingLayers could've called itself from layer->setClosing.
2019-03-20 11:41:10 +04:00
John Preston
2ebbf062d0 Show webpage with embed_url as a video. 2019-03-19 13:21:13 +04:00
John Preston
fd538bc6c8 Version 1.6.
- Play video files and listen to music
without waiting for them to fully download.
- Press CTRL+0 (CMD+0 on macOS) to jump to your Saved Messages.
2019-03-18 12:24:03 +04:00
John Preston
c0959ceaeb Start video when moving to it in media viewer.
Fixes #5796.
2019-03-18 11:44:49 +04:00
John Preston
6c382c647c Fix caching of first slice in header. 2019-03-18 11:00:11 +04:00
John Preston
8f9bed0443 Fix document caption in media viewer.
Regression was introduced in 5cae57601a.

Fixes #5799, fixes #5802, fixes #5804.
2019-03-17 23:00:09 +04:00
John Preston
dc3996c077 Beta version 1.5.18: Update libtgvoip. 2019-03-15 16:57:18 +04:00
John Preston
5bfd5e4495 Beta version 1.5.18.
- Bug fixes and other minor improvements.
2019-03-15 16:11:55 +04:00
John Preston
d646de7184 Add button to download audio files. 2019-03-15 16:09:05 +04:00
John Preston
bc2b0f8392 Add button to download video files.
Fixes #5781.
2019-03-15 14:15:04 +04:00
John Preston
f2a7cf5c64 Improve shared videos design. 2019-03-15 12:09:48 +04:00
John Preston
0df628dc7a Fix notifications hiding on Linux.
Regression was introduced in 3372dfcd3e.

Only when platform-specific code can give us the global time of the
last user input event we rely on idle time for notifications hiding.

Fixes #5791.
2019-03-14 21:59:10 +04:00
John Preston
a5d1fbff98 Fix removing photo in webpage preview. 2019-03-14 17:14:18 +04:00
John Preston
5cae57601a Allow video download from media viewer. 2019-03-14 16:03:02 +04:00
John Preston
2b7fb7a9a6 Pause music only when video playback starts. 2019-03-14 14:45:08 +04:00
John Preston
feb238c5d9 Fix crash if asked to read more than 64MB at once. 2019-03-14 14:14:24 +04:00
John Preston
0d888eea85 Fix local cache time limit setting storing.
Fixes #5611.
2019-03-14 13:22:42 +04:00
John Preston
bfb6ecbac7 Fail streaming on error in any stream. 2019-03-14 12:47:18 +04:00
John Preston
2152fe6a79 Beta version 1.5.17: Improve large file streaming.
Allow header for streaming up to 8 MB.
2019-03-13 20:56:04 +04:00
John Preston
b113696fe6 Beta version 1.5.17.
- Bug fixes and other minor improvements.
2019-03-13 19:02:53 +04:00
John Preston
b65a24df96 Allow streaming videos with unknown duration.
When you stream image/gif as a soundless video the total duration is
unknown, so we accumulate packet->pts + packet->duration as duration.
2019-03-13 18:58:50 +04:00
John Preston
c655bf852f Fix crash in video player seek. 2019-03-13 16:28:07 +04:00
John Preston
be495c17bc Fix seek to video end. 2019-03-13 16:21:07 +04:00
John Preston
9785ff4be6 Add more checks in streaming. 2019-03-13 15:11:54 +04:00
John Preston
5ec37e9112 Use separate click handler for OpenWith. 2019-03-13 13:35:47 +04:00
John Preston
f9f84fd407 Fix idle time checking in MainWidget.
Regression was introduced in 78d00bcf22.

Fixes #5779, fixes #5780.
2019-03-13 11:21:56 +04:00
John Preston
ed93669693 Beta version 1.5.16: Update libtgvoip. 2019-03-12 19:04:22 +04:00
John Preston
e79ddf2459 Beta version 1.5.16: Fix audio stucking. 2019-03-12 18:57:48 +04:00
John Preston
5efe47cfb6 Beta version 1.5.16: Remove streaming logs. 2019-03-12 18:56:35 +04:00
John Preston
b8045cbcc7 Beta version 1.5.16.
- Play video files and listen to received music
without waiting for them to download.
- Press CTRL+0 (CMD+0 on macOS) to jump to your Saved Messages.
2019-03-12 17:05:11 +04:00
John Preston
aa1090a585 Fix text disappearing in support mode. 2019-03-12 16:54:15 +04:00
John Preston
0a5589f869 Remove deleted chats with users from list. 2019-03-12 16:08:41 +04:00
John Preston
383b29dbd8 Fix possible crash in calls.
Fixes #5732.
2019-03-12 15:26:29 +04:00
John Preston
13a9b967e9 Use user phrases for support accounts. 2019-03-12 14:38:59 +04:00
John Preston
b798654ca7 Set focus to intro widget.
Fixes #5705.
2019-03-12 14:38:59 +04:00
John Preston
a5e6890b77 Fix icon pixmap sizes on Retina with scaling. 2019-03-12 14:27:22 +04:00
John Preston
2a3a38531b Fix photo inline result sending.
Fixes #5594.
2019-03-12 13:49:16 +04:00
John Preston
4ebf6ebb6f Use the same poll option values as others. 2019-03-12 13:15:08 +04:00
23rd
6fe736c9fc Added Shortcut to jump to the Saved Messages. 2019-03-12 13:03:23 +04:00
John Preston
ef682e7023 Fix photos in overview with disabled autodownload.
Fixes #5599, fixes #5747.
2019-03-12 12:55:26 +04:00
John Preston
5c3f667fc3 Fix background reset on language change. 2019-03-12 12:55:26 +04:00
John Preston
a95a055acd After update try relaunching for 1 second on macOS. 2019-03-12 09:35:53 +04:00
John Preston
846499a4fb Fix volume saving to settings. 2019-03-12 09:09:53 +04:00
John Preston
6afb3f70bb Closed alpha version 1.5.15.6. 2019-03-11 21:03:26 +04:00
John Preston
c063d94aa5 Remove DocumentData::actionOnLoad. Fix GIF open. 2019-03-11 19:07:35 +04:00
John Preston
261720c941 Fix radial animations on macOS.
QOpenGLWidget doesn't draw antialiased ellipses and arcs,
so we use a software rasterizer and then draw the resulting image.
2019-03-11 13:51:15 +04:00
John Preston
7b3c452316 Change direction of infinite radial animation. 2019-03-11 13:19:38 +04:00
John Preston
aa00f9bd34 Fix new animations engine restarts. 2019-03-11 12:08:21 +04:00
John Preston
b0ff443eac Fix sending of saved GIFs. 2019-03-11 12:08:21 +04:00
John Preston
a886c598c1 Fix non-streamable videos layout. 2019-03-11 12:08:20 +04:00
John Preston
2ce4abfdfe Fix crash in media caching. 2019-03-11 12:08:20 +04:00
John Preston
18c42954ae Fix sparse frame painting on macOS. 2019-03-11 12:08:20 +04:00
John Preston
b57b4fa0f8 Fix reading first slice for good header cache. 2019-03-11 12:08:20 +04:00
John Preston
e66cde398a Closed alpha version 1.5.15.5. 2019-03-11 12:08:19 +04:00
John Preston
3706be77ea Fix macOS media viewer controls hiding. 2019-03-11 12:08:19 +04:00
John Preston
f481f1e142 Make videos larger, fix playback animation. 2019-03-11 12:08:19 +04:00
John Preston
84b09795f3 Store first slice in the header cache key. 2019-03-11 12:08:19 +04:00
John Preston
95954c4b1f Closed alpha version 1.5.15.4. 2019-03-11 12:08:18 +04:00
John Preston
a56a12a1ef Optimized video frame pushing. 2019-03-11 12:08:18 +04:00
John Preston
5c4b459f57 Use new animations in video viewer. 2019-03-11 12:08:18 +04:00
John Preston
9a616edf2a Add new animations engine. 2019-03-11 12:08:17 +04:00
John Preston
92332b45ea Don't reset zoom on video seek. 2019-03-11 12:08:17 +04:00
John Preston
5a7fcc3a22 Don't show fast share for own messages. 2019-03-11 12:08:17 +04:00
John Preston
6c441353c4 Closed alpha version 1.5.15.3. 2019-03-11 12:08:17 +04:00
John Preston
b742c95516 Support streamed video rotation. 2019-03-11 12:08:16 +04:00
John Preston
a59c3da3d0 Cache small files in one value. 2019-03-11 12:08:16 +04:00
John Preston
8399f4189f Don't show receivedTill for local loaders. 2019-03-11 12:08:16 +04:00
John Preston
67b9fe846b Improve video frame position checks. 2019-03-11 12:08:16 +04:00
John Preston
0f4ccce0e1 Update ffmpeg. 2019-03-11 12:08:15 +04:00
John Preston
01d763eed1 Use DocumentData::getDuration for all types. 2019-03-11 12:08:15 +04:00
John Preston
41c60419f1 Enable voice messages streaming. 2019-03-11 12:08:15 +04:00
John Preston
195164d9d4 Fix display / download of video messages. 2019-03-11 12:08:14 +04:00
John Preston
518d1da736 Fail streaming if no codec for a stream. 2019-03-11 12:08:14 +04:00
John Preston
aade3d4f27 Allow streaming video from overview. 2019-03-11 12:08:14 +04:00
John Preston
22356eb01c Fix initial video duration display. 2019-03-11 12:08:14 +04:00
John Preston
b5eb88a32f Closed alpha version 1.5.15.2. 2019-03-11 12:08:13 +04:00
John Preston
6887993f92 Report streaming failed. 2019-03-11 12:08:13 +04:00
John Preston
71b733a018 Display receivedTill in video player controls. 2019-03-11 12:08:13 +04:00
John Preston
e2eb9cea00 Apply sample_aspect_ratio in streaming. 2019-03-11 12:08:12 +04:00
John Preston
99e96a5b13 Allow looping video without audio in streaming. 2019-03-11 12:08:12 +04:00
John Preston
7093254b66 Fix crash in empty sticker set box. 2019-03-11 12:08:12 +04:00
John Preston
f4544b0964 Fix crash in passcode setup. 2019-03-11 12:08:12 +04:00
John Preston
c27456277e Support streaming of local files. 2019-03-11 12:08:11 +04:00
John Preston
2e824ace00 Fix video messages inline playback. 2019-03-11 12:08:11 +04:00
John Preston
dafa286b18 Show option to download on streaming error. 2019-03-11 12:08:11 +04:00
John Preston
003d01206f Allow .opus playback. 2019-03-11 12:08:10 +04:00
John Preston
f0963a332a Fix crash on failed streaming. 2019-03-11 12:08:10 +04:00
John Preston
91bdb66f0d Fix call icon position for the Info layer. 2019-03-11 12:08:10 +04:00
John Preston
ffb48c42b0 Closed alpha version 1.5.15.1. 2019-03-11 12:08:10 +04:00
John Preston
8171828c2a Fix build on GCC. 2019-03-11 12:08:09 +04:00
John Preston
a8aa66d191 Check frame format before sws_getCachedContext. 2019-03-11 12:08:09 +04:00
John Preston
e631d98230 Implement media cache management. 2019-03-11 12:08:09 +04:00
John Preston
1940c67a09 Disable music / video autodownload. 2019-03-11 12:08:09 +04:00
John Preston
c574119718 Implement file reference update in streaming. 2019-03-11 12:08:08 +04:00
John Preston
648cd44ddd Display correct video / music state. 2019-03-11 12:08:08 +04:00
John Preston
fde8dd9607 Play streaming audio in player. 2019-03-11 12:08:08 +04:00
John Preston
f1e0cd6c1d Play streaming video in mediaview. 2019-03-11 11:52:11 +04:00
John Preston
44df10d6cb Improve working with cache in streaming. 2019-03-11 11:49:54 +04:00
John Preston
b6a757842a Pause loading if loaded for 1 minute. 2019-03-11 11:49:54 +04:00
John Preston
4636c74586 Remove from memory old file slices. 2019-03-11 11:49:54 +04:00
John Preston
2208621050 First version of caching in media streaming. 2019-03-11 11:49:54 +04:00
John Preston
f133dd396c Return pair<iterator,bool> from flat_set::emplace. 2019-03-11 11:49:54 +04:00
John Preston
ccd04b98b9 Fix sync video to audio. 2019-03-11 11:49:54 +04:00
John Preston
d37b65e624 If stuck wait for three seconds of packets. 2019-03-11 11:49:54 +04:00
John Preston
3e9b811875 Implement precise seek in streaming. 2019-03-11 11:49:54 +04:00
John Preston
44c562d8ba Fix streaming seek, display progress. 2019-03-11 11:49:53 +04:00
John Preston
93c548c013 Support streaming speed changing. 2019-03-11 11:49:53 +04:00
John Preston
a7d9281768 Implement pause / resume in streaming. 2019-03-11 11:49:53 +04:00
John Preston
3b369fc98e Buffer audio when waiting data in streaming. 2019-03-11 11:49:53 +04:00
John Preston
e5cd7e6d40 Fix streaming from the middle of the file. 2019-03-11 11:49:53 +04:00
John Preston
99d05ba967 Sync video stream to audio stream. 2019-03-11 11:49:53 +04:00
John Preston
ec9512899e Support streaming playback speed 0.5 - 2. 2019-03-11 11:49:22 +04:00
John Preston
26ea6c4e63 Provide receivedTill for streamed tracks. 2019-03-11 11:49:22 +04:00
John Preston
8e44a7f5c4 Basic code for video streaming + testing on video. 2019-03-11 11:49:22 +04:00
John Preston
a093cb6274 Move some logic to Media::Streaming::Player. 2019-03-11 11:49:21 +04:00
John Preston
64f2f330f6 Render first frame when starting streaming. 2019-03-11 11:49:21 +04:00
John Preston
473e30e594 Basic code for media streaming + testing on music. 2019-03-11 11:49:21 +04:00
23rd
dc95756ec9 Fixed infrequent separation of grouped notifications. 2019-03-11 00:00:02 +04:00
23rd
2a935868a8 Added grouping of album files into a single notification.
- Added display of "Album" in inDialogsText().
2019-03-11 00:00:02 +04:00
23rd
f48d8538c0 Added ability to see attached stickers on photos. 2019-03-10 22:10:36 +04:00
23rd
3372dfcd3e Refactored checking of last input while notifications are displayed.
- Removed condition for Windows platform only.
 - Added smooth hiding of notifications in case video is watched or voice message is recorded.
 - psUserActionDone() was completely replaced with Core::App().updateNonIdle().
2019-03-10 22:02:58 +04:00
23rd
78d00bcf22 Refactored counting idle time.
- psIdleTime() was replaced with Platform::LastUserInputTime().
 - _lastTimeVideoPlayedAt was moved to Application as _lastNonIdleTime.
 - Call of updateNonIdle() was added while voice is recording.
 - Fixed #5695.
 - Thanks Preston. =)
2019-03-10 22:02:58 +04:00
23rd
9dc9e019f6 Added Search Shortcut in Shared Media.
- Works for Documents, Audio files and Shared links.
2019-03-10 10:58:05 +04:00
John Zimmermann
178c0078c1 docs: Fix setting the gcc-7 alternative with apt
#5766
2019-03-10 10:56:48 +04:00
Martin Delille
8478abe378 Add brew install cmake ninja 2019-03-10 10:29:37 +04:00
23rd
bfc9e43eb4 Added a handler for "MESSAGE_EMPTY" error to delete a local message.
- Added a determination of the zero-width-space as the space.
 - Fixes #3145.
2019-03-10 10:26:40 +04:00
John Preston
e174025a92 Fix travis build. 2019-03-09 15:27:36 +04:00
23rd
89f4408029 Added forwarded info in tooltip of sticker. 2019-03-09 15:24:35 +04:00
23rd
d7dc277003 Added author of channel post in tooltip.
- Added "const" to vars within HistoryMessageSigned::refresh().
2019-03-09 15:01:08 +04:00
23rd
32bc723745 Added scroll animation in dialogs list when it scrolls to top. 2019-03-09 13:56:33 +04:00
23rd
c2ad765424 Fixed extra space in a name of the post author after forwarding message. 2019-03-09 13:41:39 +04:00
23rd
9799afa064 Updated libvdpau to 1.2. 2019-03-06 14:41:04 +04:00
23rd
e880c14d61 Fixed crash in window resizing when layer is opened.
Regression was introduced in 26f1ade5ba.
2019-03-05 13:38:58 +04:00
23rd
e70465c633 Removed unnecessary calling of saveDraftToCloud() method when quit. 2019-02-20 11:46:37 +04:00
23rd
4ed1835d32 Fixed Ctrl + F shortcut for full screen toggle in media view. 2019-02-20 11:43:50 +04:00
23rd
19bbccd1a7 Improved "Create link" box title display. 2019-02-20 11:42:10 +04:00
23rd
9d8b80cbce Fixed Travis build.
Regression was introduced in 771a51224e.
2019-02-20 11:41:13 +04:00
John Preston
dec8264625 Fix extensive CPU usage on macOS when audio is played.
Regression was introduced in 91c85ec86b

The openal-soft version 1.19.1 tried to use semaphores created by sem_init,
which are not supported on macOS, so they just didn't work at all. This was
leading to an event loop thread spin-waiting instead of a normal sem_wait.

In the v1.19 upstream branch GCD semaphores are used on macOS.
2019-02-20 11:37:38 +04:00
John Preston
fe618bd652 Use crl::time/now instead of TimeMs/getms. 2019-02-19 11:06:33 +04:00
John Preston
d208236994 Accept binary_guard in crl::guard(). 2019-02-17 15:56:07 +04:00
John Preston
4d987f7278 Fix index_based_iterator for const containers. 2019-02-17 15:56:07 +04:00
23rd
193e454fd4 Fixed sending polls as reply to other messages.
Fixes #5550.
2019-02-17 15:55:44 +04:00
John Preston
bdfb9b4143 Ignore actions from other chats in HistoryWidget.
This should fix an issue that was noticed in #5701.
2019-02-17 15:09:02 +04:00
John Preston
c9716f3c72 Make crl::object_on_queue usages consistent. 2019-02-17 15:09:01 +04:00
John Preston
7c1704e68b Fix crash in EditCaptionBox. 2019-02-17 13:51:53 +04:00
John Preston
771a51224e Support errors in rpl::event_stream. 2019-02-17 10:55:29 +04:00
John Preston
cf275b152a Fix crash in layers closing.
Sometimes AbstractBox::setClosing invoked Ui::hideLayers that
destroyed LayerStackWidget and all its children, including the
closing AbstractBox. After that a unique_ptr stored on stack
and owning that box was destroyed and it lead to a crash.

Now LayerStackWidget always owns several closing boxes.
2019-02-17 10:55:28 +04:00
John Preston
98cb85df66 Polymorphic classes without virtual dtor warning. 2019-02-15 15:55:34 +04:00
John Preston
032694ad9e Move files to media/audio and media/clip. 2019-02-13 15:41:33 +03:00
John Preston
5437215677 Use premultiplied format for GIF frames. 2019-02-13 15:19:05 +03:00
John Preston
5ec80238a0 Fix permissions dependencies. 2019-02-13 15:19:05 +03:00
John Preston
ae6c152988 Version 1.5.15: Fix macOS media viewer overlay.
Regression was introduced in c1a0dad2b7.
2019-02-12 19:55:35 +03:00
John Preston
7d15cca1ee Version 1.5.15.
- Crash fix.
2019-02-12 19:02:08 +03:00
John Preston
83c5a67af5 Fix another crash in last message checking.
Regression was introduced in 83bc6fb39c.
2019-02-12 19:01:30 +03:00
John Preston
c9ad2cd1aa Version 1.5.14.
- Crash fix.
2019-02-12 16:56:23 +03:00
John Preston
fe1f198d99 Fix crash in last message checking.
Fixes #5683.
2019-02-12 16:53:46 +03:00
John Preston
818662c2e6 Version 1.5.13: Don't automatically load executable files. 2019-02-12 14:28:33 +03:00
John Preston
05d0d2a6d6 Version 1.5.13.
- Bug fixes and other minor improvements.
2019-02-12 14:03:34 +03:00
John Preston
c1a0dad2b7 Use QOpenGLWidget for macOS media viewer overlay.
Also move mediaview to media/view/media_view_overlay_widget.
2019-02-12 14:00:47 +03:00
John Preston
4caf26d069 Fix build for Xcode. 2019-02-11 15:56:25 +03:00
John Preston
83bc6fb39c Fix changelog dialogs list appearance.
Fixes #5678, fixes #5674.
2019-02-11 15:52:36 +03:00
John Preston
dbb7568b92 Fix changelogs blog link previews. 2019-02-11 15:52:36 +03:00
John Preston
45fda44924 Fix crash on bad sticker.
DocumentData::getStickerLarge and DocumentData::loaded go to a loop.
2019-02-11 15:52:36 +03:00
John Preston
26f1ade5ba Optimize connecting widget. 2019-02-10 21:35:44 +03:00
John Preston
9dd93a77a0 Always keep inline thumbnail images loaded. 2019-02-10 11:19:27 +03:00
John Preston
331d1baad6 Fix videos without thumbnails in MediaView.
Fixes #5668.
2019-02-10 11:18:54 +03:00
John Preston
d3159d86da Version 1.5.12: Fix manual loading GIFs to cache. 2019-02-09 18:00:48 +03:00
John Preston
f9e1513491 Version 1.5.12.
- Apply blur effects to backgrounds.
- Use the backgrounds you set in Telegram Desktop
in all other Telegram apps.
2019-02-09 16:46:43 +03:00
John Preston
b6e37b7730 Allow removing cloud wallpapers. 2019-02-09 16:36:07 +03:00
John Preston
f9d56eb4c1 Send installWallPaper requests. 2019-02-08 19:47:02 +03:00
John Preston
95565c39ed Upload wallpapers to the cloud. 2019-02-08 19:20:08 +03:00
John Preston
890aacaeee Allow to blur wallpapers from file. 2019-02-08 16:55:02 +03:00
John Preston
e2f0886950 Add option to blur chat background. 2019-02-07 19:36:30 +03:00
John Preston
fe21b5a502 Support blurred backgrounds. 2019-02-06 17:38:37 +03:00
John Preston
e7043c4d63 Show patterns with colors in galery. 2019-02-05 12:32:54 +03:00
John Preston
aae2101131 Sort backgrounds in the gallery. 2019-02-04 21:37:40 +03:00
John Preston
64afed0fb2 Fix crash for videos without thumbnails. 2019-02-04 19:04:36 +03:00
John Preston
4d9464ed87 Remove flags checking for backgrounds.
Also limit image size to 2960px.

Fixes #5641.
2019-02-04 18:53:00 +03:00
John Preston
b43191506a Fix preview of color-only backgrounds.
Regression was introduced in f506a5ea6c.
2019-02-04 18:03:31 +03:00
John Preston
c47781c25a Version 1.5.11.
- Bug fixes and other minor improvements.
2019-02-01 15:51:46 +03:00
John Preston
f0c4868b3e Ignore default banned rights for channel admins.
Fixes #5640.
2019-02-01 15:50:57 +03:00
John Preston
35e5c2329b Fix wall paper preview on Retina. 2019-02-01 15:41:43 +03:00
John Preston
74fc5524ab Fix dock and menu hiding on macOS.
Regression was introduced in 0681d10c51.
2019-02-01 15:41:43 +03:00
John Preston
2d4c99a6f7 Fix build for old OS X versions. 2019-02-01 13:23:35 +03:00
John Preston
69c73d0a2c Version 1.5.10.
- Bug fixes and other minor improvements.
2019-02-01 12:51:02 +03:00
John Preston
58510e0208 Improve chat list bot icon layout. 2019-02-01 12:50:30 +03:00
Jiachen YANG
0681d10c51 fixing mediaview fullscreen on X11 2019-02-01 12:38:32 +03:00
John Zimmermann
add2356c8a Generalize Unity Integration to not depend on libunity 2019-02-01 12:34:55 +03:00
John Preston
c66b2b2291 Fix setting offline on quit. 2019-02-01 12:23:37 +03:00
23rd
769923c6cc Fixed a keeping online status after application quit.
Fixes https://github.com/telegramdesktop/tdesktop/issues/5528.
2019-02-01 11:52:25 +03:00
23rd
27528d084f Added shortcuts to skip months in CalendarBox. 2019-02-01 11:49:14 +03:00
23rd
299aa69058 Added an icon for bots in the dialog list.
Fixes https://github.com/telegramdesktop/tdesktop/issues/1894 .
2019-02-01 11:48:45 +03:00
John Preston
d1cc09f40e Destroy layers in reverse order. 2019-02-01 11:47:30 +03:00
John Preston
a133b43eed Fix crash in dual background box show. 2019-02-01 11:32:34 +03:00
John Preston
9b57725b8c Fix bad function call in data export cancel. 2019-02-01 11:17:23 +03:00
John Preston
34b0f6f014 Fix crash in group migration. 2019-02-01 11:09:14 +03:00
John Preston
f5cc93ec64 Decouple MTP::Instance from Core::App. 2019-02-01 10:48:31 +03:00
John Preston
4f3263d979 Fix crash in MediaView with thumbless GIFs. 2019-02-01 10:28:04 +03:00
John Preston
b28e374e06 Fix Media::Audio::Instance destruction. 2019-02-01 10:09:55 +03:00
John Preston
918d58ef0a Better check unique results in support mode. 2019-02-01 09:53:15 +03:00
John Preston
5a388d9dde Improve Poland number formatting. 2019-02-01 09:18:31 +03:00
John Preston
0f4909621b Version 1.5.9.
- Bug fixes and other minor improvements.
2019-01-31 20:34:19 +03:00
John Preston
55d3d8adc3 Allow to delete users from exceptions. 2019-01-31 20:31:44 +03:00
John Preston
d2d6a6daa4 Fix proxy sponsor messages search display. 2019-01-31 15:56:57 +03:00
John Preston
a7f4ac2797 Search by hashtag inside groups. 2019-01-31 15:51:19 +03:00
John Preston
25b5027dc7 Only creator can restrict in old groups. 2019-01-31 15:20:15 +03:00
John Preston
93a967dc74 Add random_padding to dns requests. 2019-01-31 13:48:10 +03:00
John Preston
3cfc3dcecf Mark even more extensions as executables. 2019-01-30 17:59:55 +03:00
John Preston
e09510ea9f Fix crash in update checker destruction. 2019-01-30 17:58:23 +03:00
John Preston
4c289fc8fb Fix add members button in channels. 2019-01-30 13:49:36 +03:00
John Preston
58cf0fa2b1 Display date in background preview. 2019-01-29 20:03:51 +03:00
John Preston
5ca12a73c3 Use new HistoryWallPaper media type for wallpaper. 2019-01-29 19:26:19 +03:00
John Preston
fd8e9dad92 Fix pattern wallpapers with themes. 2019-01-29 14:52:33 +03:00
John Preston
df0fe0a460 Closed alpha version 1.5.8.2. 2019-01-29 14:52:33 +03:00
John Preston
646d15b257 Add LSFileQuarantineEnabled to the .plist 2019-01-29 14:52:33 +03:00
John Preston
2eb6848eb8 Fix background preview on retina screens. 2019-01-29 14:52:33 +03:00
John Preston
9b3c103f16 Backport patch for Mojave accessibility access request. 2019-01-29 14:52:33 +03:00
John Preston
6a2a13d346 Closed alpha version 1.5.8.1. 2019-01-29 14:52:33 +03:00
John Preston
b6edf4561d Add support for pattern wallpapers. 2019-01-29 14:52:33 +03:00
John Preston
c2744700c0 Mark more extensions as executables. 2019-01-29 14:52:33 +03:00
John Preston
f506a5ea6c Save wallpaper settings locally. 2019-01-29 14:52:33 +03:00
John Preston
2f702148e3 Fix manage channel actions visibility.
Fixes #5601.
2019-01-29 14:52:33 +03:00
John Preston
e10c928207 Update API scheme to layer 95. 2019-01-29 14:52:33 +03:00
John Preston
a1baa23a52 Use both thumbnails in photos and documents.
Fixes #5602.
2019-01-28 13:10:45 +03:00
John Preston
a70e72f75d Application->Sandbox, Messenger->Application. 2019-01-23 12:51:58 +04:00
John Preston
4111da1dd0 Move some calls from App namespace. 2019-01-22 17:10:01 +04:00
John Preston
e7804d014d Share background from preview. 2019-01-22 17:10:00 +04:00
John Preston
bf87de3706 Fix removing chats from dialogs. 2019-01-22 17:05:06 +04:00
John Preston
ebc2043055 Improve empty group display. 2019-01-22 11:50:21 +04:00
John Preston
69b1f6c4e1 Version 1.5.8.
- Global permissions for groups. Restrict all members in any group
from posting certain types of content.
- Unified group settings. Make groups public,
set admins with granular permissions and toggle persistent history
in just a few clicks in any group.
- Choose the emoji set you would like to use in Chat Settings.
- Choose input and output devices for Telegram Calls
in Settings > Advanced > Call Settings.
- Support for automatically downloading files and music.
2019-01-21 21:28:45 +04:00
John Preston
2708777167 Closed alpha version 1.5.7.2. 2019-01-21 18:06:20 +04:00
John Preston
6e0d62bb65 Re-apply document thumb only for stickers. 2019-01-21 17:43:24 +04:00
John Preston
6d706fd222 Improve unacessible permissions design. 2019-01-21 17:43:24 +04:00
John Preston
6066265717 Fix emoji suggestions in monospace. 2019-01-21 11:02:20 +04:00
John Preston
805e4d01e7 Allow re-downloading failed media. 2019-01-21 10:49:44 +04:00
John Preston
e209299af4 Fix invite link block visibility. 2019-01-21 10:40:25 +04:00
John Preston
b3f0a3c9f5 Make audio device selection box wider. 2019-01-21 10:37:31 +04:00
John Preston
1da8841ac7 fixup use Text 2019-01-21 10:37:20 +04:00
John Preston
7df5df6351 Improve phrases for removed users. 2019-01-21 10:26:19 +04:00
John Preston
bf85b0c109 Closed alpha version 1.5.7.1. 2019-01-18 16:41:08 +04:00
John Preston
314e30272b Replace SingleTimer with base::Timer. 2019-01-18 16:41:08 +04:00
John Preston
61b9a32504 Add 'Contact joined' notifications setting. 2019-01-18 16:41:08 +04:00
John Preston
01b7d4ffba Use Text to display empty group state. 2019-01-18 16:41:07 +04:00
John Preston
8643972f8c Send thumbs only for big files. 2019-01-18 16:41:07 +04:00
John Preston
1894b8fcf7 Handle t.me/bg links with wallpapers / colors. 2019-01-18 16:41:07 +04:00
John Preston
e59a68cd68 Refresh wallpaper file references. 2019-01-17 12:21:31 +04:00
John Preston
466c6da5e3 Save wallpaper information. 2019-01-17 12:21:31 +04:00
John Preston
b8cb792831 Read background image async. 2019-01-17 12:21:31 +04:00
John Preston
0f9c2a62fe Load fullres images of new wallpapers. 2019-01-17 12:21:31 +04:00
John Preston
04350af96f Use one place for saving restrictions. 2019-01-17 12:21:31 +04:00
John Preston
287b3509ab Optimize getPeerDialog requests. 2019-01-17 12:21:31 +04:00
John Preston
2a5bcd3eec Support empty group placeholder for creators. 2019-01-17 12:21:31 +04:00
John Preston
2a0b9a44dd Remove supergroup migrate messages. 2019-01-17 12:21:31 +04:00
John Preston
c552db04d7 Use 'exception' and 'remove user' phrases. 2019-01-17 12:21:30 +04:00
John Preston
22f1ffc72b Use different phrases for default restrictions. 2019-01-17 12:21:30 +04:00
John Preston
4f33be20d4 Add user to group on appointing of admin. 2019-01-17 12:21:30 +04:00
John Preston
9728ddeaf9 Handle migration to supergroups in boxes. 2019-01-17 12:21:30 +04:00
John Preston
3c44bdb6b7 Support auto-migrate to supergroups. 2019-01-17 12:21:30 +04:00
John Preston
b236844c94 Fix crash in admin log events. 2019-01-17 12:21:30 +04:00
John Preston
67d12fa6d2 Improve update handling for legacy chats. 2019-01-17 12:21:30 +04:00
John Preston
215856adc3 Improve AddSpecial box for legacy groups. 2019-01-17 12:21:30 +04:00
John Preston
07e010dfb5 Save admins in legacy groups. 2019-01-17 12:21:30 +04:00
John Preston
dba9ca2084 Replace TLHelp helpers with .match() 2019-01-17 12:21:30 +04:00
John Preston
9a60e744d3 Unify permissions checks in participants boxes. 2019-01-17 12:21:30 +04:00
John Preston
e1a2ab0d7e Log only source base name in assertions. 2019-01-17 12:21:30 +04:00
John Preston
a605c110a8 Support legacy groups in participant boxes. 2019-01-17 12:21:29 +04:00
John Preston
18c6be0d3b Unify legacy and megagroups information edit. 2019-01-17 12:21:29 +04:00
John Preston
ff728e2fc1 Add default permissions changes to admin log. 2019-01-17 12:21:29 +04:00
John Preston
eff90395b6 Add EditPeerPermissionsBox. 2019-01-17 12:21:29 +04:00
John Preston
f4d52b82b4 Allow reusing permissions edit controls. 2019-01-17 12:21:29 +04:00
John Preston
61419b57c8 Prepare legacy group restrictions checking. 2019-01-17 12:21:29 +04:00
John Preston
441989a8e1 Remove EditChannelBox. 2019-01-17 12:21:29 +04:00
John Preston
c5a41e1f55 Divide data/data_peer and remove from PCH. 2019-01-17 12:21:29 +04:00
John Preston
0ce4d66601 Rename restrictionReason to unavailableReason. 2019-01-17 12:21:28 +04:00
John Preston
d2d6b319b6 Update API scheme to layer 93. Broken. 2019-01-17 12:21:28 +04:00
John Preston
47edb71a68 Update API scheme to layer 92. 2019-01-17 12:21:28 +04:00
John Preston
1f8626b383 Move App::histories to Data::Session. 2019-01-17 12:21:28 +04:00
John Preston
0d6a36e187 Fix volume widget position.
Fixes #5467.
2019-01-17 12:20:50 +04:00
John Preston
548a0c8517 Fix MTP logging. 2019-01-17 12:20:50 +04:00
John Preston
09d85e25c1 Fix possible crash in SendFilesBox. 2019-01-17 12:20:50 +04:00
John Preston
51b5b14dea Beta version 1.5.7.
- Choose the emoji set you would like to use
in Settings > Chat Settings.
- Choose input and output devices for Telegram Calls
in Settings > Adavanced > Call Settings.
2019-01-11 17:31:36 +04:00
John Preston
0d290a2c28 Fix emoji icon in theme preview.
Fixes #5561.
2019-01-11 17:30:57 +04:00
John Preston
c1b3d589c7 Fix elision in document extension in MediaView.
Fixes #5555.
2019-01-11 17:30:57 +04:00
John Preston
65430d92ea Refactor calls settings panel. 2019-01-11 17:30:57 +04:00
John Preston
8711830f66 Move calls settings to Settings > Advanced.
Also add calls settings button to the calls list box.
2019-01-11 17:30:57 +04:00
John Preston
c4d919d46b Improve emoji quality while creating cache. 2019-01-11 17:30:57 +04:00
John Preston
3e7a688811 Fix tray icon counter on Linux.
Fixes #5525.
2019-01-11 17:30:57 +04:00
John Preston
2773a675d0 Improve sticker set download phrase. 2019-01-11 17:30:57 +04:00
John Preston
9bbdccc111 Postpone sticker send from StickerSetBox.
Fixes #5539.
2019-01-11 17:30:57 +04:00
John Preston
bb8defeb42 Improve change emoji set box design. 2019-01-11 17:30:57 +04:00
John Preston
545dbd0791 Return sticker-related context menu actions.
Regression was introduced in 3e22ada889.
2019-01-11 17:30:57 +04:00
John Preston
c7469075ab Closed beta version 1.5.6.1: Fix build in GCC. 2019-01-11 17:30:57 +04:00
John Preston
54fa974789 Closed beta version 1.5.6.1. 2019-01-11 17:30:57 +04:00
John Preston
2cd3cec478 Go through open history in support mode. 2019-01-11 17:30:00 +04:00
John Preston
c11b977f1d Fix lagging chat list update in support. 2019-01-11 17:30:00 +04:00
John Preston
30e8f17b37 [all] / [one from chat] in support search results. 2019-01-11 17:30:00 +04:00
John Preston
2c3190ce2a Hide LoadMore button in search mode. 2019-01-11 17:30:00 +04:00
John Preston
ea7796dccc Ctrl+[1-5] jump to the relevant pinned chat. 2019-01-11 17:30:00 +04:00
John Preston
a11ca58f36 Fix Ctrl+Insert in hashtag search results. 2019-01-11 17:30:00 +04:00
John Preston
496d711684 Improve support shortcuts handling. 2019-01-11 17:30:00 +04:00
John Preston
219b824338 Refresh filtered results on more dialogs. 2019-01-11 17:30:00 +04:00
John Preston
df389a365c Display emoji set loading radial animation. 2019-01-11 17:30:00 +04:00
John Preston
aa2c52c1f8 Unpack and prepare emoji asynchronously. 2019-01-11 17:30:00 +04:00
John Preston
f48ae29f22 Load emoji sets from the cloud. 2019-01-11 17:30:00 +04:00
John Preston
de00e0e15c Add simple switch emoji set box. 2019-01-11 17:30:00 +04:00
John Preston
79fea49272 Add updating emoji on the run. 2019-01-11 17:30:00 +04:00
John Preston
8190b10680 Support custom emoji sets loading. 2019-01-11 17:30:00 +04:00
Omkar Nath Singh
1ebd9562a2 Update copyright year (#5559) 2019-01-07 11:36:54 +04:00
John Preston
ebaf63393f Fix build for old OS X and MacAppStore. 2019-01-06 15:22:18 +04:00
John Preston
7c168740d9 Update instructions for Xcode 10.1. 2019-01-05 16:34:34 +04:00
Gregory K
11b991cddc Add call settings (#5540) 2019-01-05 15:08:02 +04:00
John Preston
8306e58b75 Fix build in Xcode / GCC. 2018-12-28 19:41:06 +04:00
John Preston
4002739682 Suggest adding bots to channels as admins. 2018-12-28 15:42:58 +04:00
John Preston
c259921269 Use qualified names for App::main and App::wnd. 2018-12-28 11:14:00 +04:00
John Preston
2eb3041c1f Beta version 1.5.6.
- Fix crash on macOS.
2018-12-27 19:55:36 +04:00
John Preston
d539d9b5d2 Fix postponed calls from crl::on_main() on macOS.
In libdispatch crl::on_main() implementation we bypass Application::notify() frame.
So we handle event loop nesting control manually by wrapping all invokations done
through crl::on_main() with the same methods we do from Application::notify().
2018-12-27 13:34:12 +04:00
John Preston
d17c985bcb Beta version 1.5.5.
- Support for auto-download of files and music.
- Improved auto-download settings.
2018-12-27 09:26:19 +04:00
John Preston
e2668e7cfa Default auto-download 8 MB files. 2018-12-27 09:24:46 +04:00
Omkar Nath Singh
18c2c61bee Update Ubuntu support version (#5372) 2018-12-26 15:09:20 +03:00
23rd
be0b0c1984 Fixed an editing of unsupported messages. 2018-12-26 15:10:56 +04:00
John Preston
b00ca217b3 Don't autoread mentions with voice/video messages.
Voice/video message unread flag is the same that mention unread flag.
If we mark such mentions as read together with all others we mark
media as watched/listened instantly when they appear on the screen.

So now we mark as read only simple mentions, without "unread" media.
2018-12-26 14:30:55 +04:00
John Preston
874d76b16b Ignore activations from ~PopupMenu in file dialog event loops. 2018-12-26 13:54:49 +04:00
John Preston
cfac261516 Create Application before ConcurrentTimerEnvironment.
Fixes #5498.
2018-12-26 13:02:43 +04:00
John Preston
7b5e5c2587 Move caption to the next album item on cancel.
After #4869 albums are sent with captions in the first media.
In case we cancel the first media leaving the rest of the album
the caption will be lost unless we move it to the new "first" media.
2018-12-26 11:24:12 +04:00
John Preston
db064381d9 Re-update libtgvoip.
The submodule was rolled back in 0b87db8b45.
2018-12-26 11:20:01 +04:00
John Preston
096c310e0e Display consistent caption/comment placeholder.
After latest PRs regarding sticker sending with comment (#5500)
and album sending with caption (#4869) the input field placeholder
in SendFilesBox was inconsistent with the sending behaviour. Fix it.
2018-12-26 10:53:21 +04:00
udf
0b87db8b45 Ignore only empty drafts while sending with clear_draft (#5424) 2018-12-26 10:52:48 +04:00
John Preston
71cf4a4885 Change default autodownload settings. 2018-12-26 09:58:27 +04:00
John Preston
a0c6104fae Redesign auto download box. 2018-12-25 22:15:22 +04:00
John Preston
8e54ac4dcf Rename autolock_box module to auto_lock_box. 2018-12-25 22:15:22 +04:00
John Preston
97b0288c7d Add automatic loading of videos/files. 2018-12-25 22:15:22 +04:00
John Preston
e3cc8652e4 New structs for media autodownload settings. 2018-12-25 22:15:22 +04:00
John Preston
8708a001c7 Always display nice percent values.
Sum of percent values should never exceed 100%. If any two answers
received same amount of votes, they should show same percent values.
This way sum could be less than 100% (three answers, one vote each),
but this looks better than giving extra vote to some random answer.
2018-12-25 22:12:35 +04:00
John Preston
6fc4facddf Improve updates sending script. 2018-12-25 19:42:02 +04:00
John Preston
e5536880fb Improve mouse/keyboard selection interactions.
Fixes #5458.
2018-12-25 16:41:40 +04:00
John Preston
44ff8f92ac Fix crash with invalid custom langpacks. 2018-12-25 15:22:25 +04:00
John Preston
95208267de Fix applying langpacks from file. 2018-12-25 15:22:01 +04:00
John Preston
9c579e0d5b Fix crash in wrong confirm email button. 2018-12-25 14:53:47 +04:00
John Preston
d1be4c6d96 Fix crash with event loop nesting. 2018-12-25 14:11:10 +04:00
John Preston
a65afdac95 Fix crash in RevokePublicLinkBox. 2018-12-25 12:48:12 +04:00
John Preston
22b47925d4 Fix assertion violation in calls. 2018-12-25 12:21:00 +04:00
John Preston
f291e365e5 Add slide animations in CreatePollBox. 2018-12-25 11:41:22 +04:00
John Preston
6f176803d4 Reload poll data each 30 seconds without update. 2018-12-24 21:03:53 +04:00
John Preston
b6a3bb4080 Allow closing CreatePollBox by escape. 2018-12-24 17:13:44 +04:00
23rd
c7c1deab81 Add caption to first item of album istead of sending separated message. 2018-12-24 17:12:18 +04:00
RMPR
2ded5870b5 Update supported Fedora version (#5502) 2018-12-24 17:03:40 +04:00
John Preston
57f2ae098f Show exact option votes count in a tooltip.
Fixes #5505.
2018-12-24 14:24:16 +04:00
John Preston
76c06923d5 Add ripple animation to poll voting. 2018-12-24 14:03:13 +04:00
John Preston
fb7ac874f0 Show poll question in pinned bar. 2018-12-24 13:25:02 +04:00
John Preston
12905f0dcb Version 1.5.4: Fix build in Xcode. 2018-12-24 12:16:05 +04:00
John Preston
68a313a58f Version 1.5.4.
- Bug fixes and other minor improvements.
2018-12-23 21:37:26 +04:00
John Preston
152115bf2e Disable multiline poll options. 2018-12-23 21:28:12 +04:00
John Preston
8bd3051224 Fix crop photo box title. 2018-12-23 21:23:36 +04:00
John Preston
aa94ca6619 Fix stuck inline mode.
Regression was introduced in 017ec87d60.

Fixes #5503.
2018-12-23 20:57:34 +04:00
John Preston
e397f72eb2 Lock poll creating.
Fixes #5504.
2018-12-23 20:47:00 +04:00
John Preston
4d495b8d7c Fix votes count in RTL languages. 2018-12-23 20:42:32 +04:00
John Preston
a142a2717c Fix no votes label. 2018-12-23 20:37:32 +04:00
John Preston
de4a477686 Mark event loop nesting more carefully.
Fixes #5506. I hope fixes #5508.
2018-12-23 16:08:48 +04:00
John Preston
4e692e2c1e Version 1.5.3: Fix build for GCC. 2018-12-23 01:31:12 +04:00
John Preston
8237e6f7a3 Version 1.5.3.
- Create polls in groups and channels - right from the chat menu.
2018-12-23 00:30:55 +04:00
23rd
d1a9f1feac Fixed caption when sending single WEBP as file. 2018-12-23 00:27:36 +04:00
John Preston
ef1d38462f Simplest polls data export. 2018-12-23 00:23:19 +04:00
John Preston
93c8e9aa1f Add poll vote sending animation. 2018-12-22 23:32:04 +04:00
John Preston
ac2dce4bb1 Fix polls percent display. 2018-12-22 22:48:25 +04:00
John Preston
f2e1d90c74 Add send vote / retract vote animation. 2018-12-22 22:36:00 +04:00
John Preston
8e28a229f2 Improve polls design. 2018-12-22 14:23:22 +04:00
John Preston
363f6cb329 Add question / options length warnings. 2018-12-22 10:29:03 +04:00
John Preston
b6f7832745 Add create poll box from groups three-dot menu. 2018-12-22 10:29:03 +04:00
John Preston
74c1db740d Implement polls voting and actions. 2018-12-21 17:09:33 +04:00
John Preston
4bb5dcf50c Simplest poll layout. 2018-12-21 17:09:32 +04:00
John Preston
b0d01389c6 Add .terminal extension as executable on macOS. 2018-12-21 17:09:32 +04:00
John Preston
3e22ada889 Remove HistoryMediaType type-tag. 2018-12-21 17:09:32 +04:00
John Preston
6d08394adc Divide history_media_types to several modules. 2018-12-21 17:09:31 +04:00
John Preston
47bdeeef9a Poll data and updates handling added. 2018-12-21 17:09:31 +04:00
John Preston
099440d008 Add test poll sending code. 2018-12-21 17:09:30 +04:00
John Preston
eb7201a55b Strictly match message / media types. 2018-12-21 17:09:30 +04:00
John Preston
6d9f40db30 Update API scheme to layer 91. 2018-12-21 17:09:30 +04:00
John Preston
7960706e60 Update API scheme to layer 90. 2018-12-17 11:01:30 +04:00
John Preston
8b0e54a95c Fix macOS main menu items. 2018-12-17 10:45:48 +04:00
John Preston
89e8f0ccc3 Fix pt-br FAQ link. 2018-12-17 10:12:44 +04:00
724 changed files with 52099 additions and 29978 deletions

View File

@@ -72,10 +72,6 @@ GOTO:EOF
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION
)
echo %BUILD_VERSION% | findstr /C:"disable_unity_integration">nul && (
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_UNITY_INTEGRATION
)
echo %BUILD_VERSION% | findstr /C:"disable_gtk_integration">nul && (
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_GTK_INTEGRATION
)

View File

@@ -14,7 +14,6 @@ env:
- BUILD_VERSION="disable_crash_reports"
- BUILD_VERSION="disable_network_proxy"
- BUILD_VERSION="disable_desktop_file_generation"
- BUILD_VERSION="disable_unity_integration"
- BUILD_VERSION="disable_gtk_integration"
matrix:
@@ -45,7 +44,7 @@ addons:
- libopus-dev
- libpulse-dev
- libssl-dev
- libunity-dev
- libdee-dev
- libva-dev
- libvdpau-dev
- libxcb-xkb-dev

View File

@@ -116,10 +116,6 @@ build() {
GYP_DEFINES+=",TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION"
fi
if [[ $BUILD_VERSION == *"disable_unity_integration"* ]]; then
GYP_DEFINES+=",TDESKTOP_DISABLE_UNITY_INTEGRATION"
fi
if [[ $BUILD_VERSION == *"disable_gtk_integration"* ]]; then
GYP_DEFINES+=",TDESKTOP_DISABLE_GTK_INTEGRATION"
fi
@@ -318,6 +314,7 @@ buildVdpau() {
git clone git://anongit.freedesktop.org/vdpau/libvdpau
cd "$EXTERNAL/libvdpau"
git checkout libvdpau-1.2
./autogen.sh --prefix=$VDPAU_PATH --enable-static
make $MAKE_ARGS
sudo make install

2
LEGAL
View File

@@ -1,7 +1,7 @@
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
Copyright (c) 2014-2018 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2019 John Preston, https://desktop.telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -15,8 +15,8 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* Windows XP - Windows 10 (**not** RT)
* Mac OS X 10.8 - Mac OS X 10.11
* Mac OS X 10.6 - Mac OS X 10.7 (separate build)
* Ubuntu 12.04 - Ubuntu 18.04
* Fedora 22 - Fedora 28
* Ubuntu 12.04 - Ubuntu 18.10
* Fedora 22 - Fedora 29
* [Snappy](https://snapcraft.io/telegram-desktop)
## Third-party
@@ -45,7 +45,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
## Build instructions
* [Visual Studio 2017][msvc]
* [Xcode 9][xcode]
* [Xcode 10][xcode]
* [GYP/CMake on GNU/Linux][cmake]
[//]: # (LINKS)

View File

@@ -1,5 +1,5 @@
diff --git a/src/build/common.gypi b/src/build/common.gypi
index 29990c6..53e99d4 100644
index 29990c65..53e99d44 100644
--- a/src/build/common.gypi
+++ b/src/build/common.gypi
@@ -330,6 +330,7 @@
@@ -11,7 +11,7 @@ index 29990c6..53e99d4 100644
},
}],
diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
index 1a93ce6..1c1d643 100644
index 1a93ce6d..b5986e33 100644
--- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj
+++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
@@ -35,6 +35,19 @@
@@ -34,7 +34,15 @@ index 1a93ce6..1c1d643 100644
162F64F2161C577500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; };
162F64F3161C577500CD68D5 /* arch_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 162F64F1161C577500CD68D5 /* arch_utilities.h */; };
162F64F4161C579B00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; };
@@ -170,11 +183,8 @@
@@ -67,6 +80,7 @@
4DBE49A7134A4F280072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
4DBE49A8134A4F380072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
4DBE49A9134A4F460072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
+ 5A8B220921E0C5740045F83C /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
8B3101C611F0CD9F00FCF3E4 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D6A5FE840307C02AAC07 /* AppKit.framework */; };
8B3101C711F0CD9F00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; };
8B3101CA11F0CDB000FCF3E4 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D6A5FE840307C02AAC07 /* AppKit.framework */; };
@@ -170,11 +184,8 @@
F92C564A0ECD10CA009BE4BA /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; };
F92C564C0ECD10DD009BE4BA /* breakpadUtilities.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; };
F92C56570ECD113E009BE4BA /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C554A0ECCF530009BE4BA /* Carbon.framework */; };
@@ -46,7 +54,7 @@ index 1a93ce6..1c1d643 100644
F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */; };
F93803CD0F8083B7004D428B /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536B0ECCE3FD009BE4BA /* dynamic_images.cc */; };
F93803CE0F8083B7004D428B /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536D0ECCE3FD009BE4BA /* exception_handler.cc */; };
@@ -213,7 +223,6 @@
@@ -213,7 +224,6 @@
F9C44DBD0EF072A0003AEBAA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DBA0EF072A0003AEBAA /* MainMenu.xib */; };
F9C44E000EF077CD003AEBAA /* Breakpad.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
F9C44E3C0EF08B12003AEBAA /* Breakpad.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
@@ -54,7 +62,7 @@ index 1a93ce6..1c1d643 100644
F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C53770ECCE635009BE4BA /* HTTPMultipartUpload.m */; };
F9C44EE50EF0A006003AEBAA /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9C44EE40EF0A006003AEBAA /* SystemConfiguration.framework */; };
F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C44EE80EF0A3C1003AEBAA /* GTMLogger.m */; };
@@ -410,20 +419,6 @@
@@ -410,20 +420,6 @@
remoteGlobalIDString = F92C563B0ECD10B3009BE4BA;
remoteInfo = breakpadUtilities;
};
@@ -75,7 +83,7 @@ index 1a93ce6..1c1d643 100644
F93DE2FB0F82C3C600608B94 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
@@ -536,13 +531,6 @@
@@ -536,13 +532,6 @@
remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
remoteInfo = Breakpad;
};
@@ -89,7 +97,7 @@ index 1a93ce6..1c1d643 100644
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -714,7 +702,6 @@
@@ -714,7 +703,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -97,7 +105,7 @@ index 1a93ce6..1c1d643 100644
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1181,18 +1168,13 @@
@@ -1181,18 +1169,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */;
buildPhases = (
@@ -116,7 +124,7 @@ index 1a93ce6..1c1d643 100644
);
name = Breakpad;
productInstallPath = "$(HOME)/Library/Frameworks";
@@ -1399,6 +1381,8 @@
@@ -1399,6 +1382,8 @@
/* Begin PBXProject section */
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
@@ -125,7 +133,7 @@ index 1a93ce6..1c1d643 100644
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Breakpad" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
@@ -1583,16 +1567,6 @@
@@ -1583,16 +1568,6 @@
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
@@ -142,7 +150,7 @@ index 1a93ce6..1c1d643 100644
F92C569C0ECE04A7009BE4BA /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -1640,20 +1614,6 @@
@@ -1640,20 +1615,6 @@
shellPath = /bin/sh;
shellScript = "install_name_tool -id \"@executable_path/../Resources/breakpadUtilities.dylib\" \"${BUILT_PRODUCTS_DIR}/breakpadUtilities.dylib\"\n";
};
@@ -163,10 +171,11 @@ index 1a93ce6..1c1d643 100644
F9C77DD80F7DD5CF0045F7DB /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1674,6 +1634,19 @@
@@ -1674,6 +1635,20 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 5A8B220921E0C5740045F83C /* breakpad_nlist_64.cc in Sources */,
+ 0748C0501C63C52D004489BF /* bootstrap_compat.cc in Sources */,
+ 0748C04F1C63C523004489BF /* macho_walker.cc in Sources */,
+ 0748C04E1C63C51C004489BF /* md5.cc in Sources */,
@@ -183,7 +192,7 @@ index 1a93ce6..1c1d643 100644
F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */,
F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */,
F92C55D10ECD0064009BE4BA /* Breakpad.mm in Sources */,
@@ -1955,16 +1928,6 @@
@@ -1955,16 +1930,6 @@
target = F92C563B0ECD10B3009BE4BA /* breakpadUtilities */;
targetProxy = F92C564D0ECD10E5009BE4BA /* PBXContainerItemProxy */;
};
@@ -200,7 +209,7 @@ index 1a93ce6..1c1d643 100644
F93DE2FC0F82C3C600608B94 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F93803BD0F80820F004D428B /* generator_test */;
@@ -2025,11 +1988,6 @@
@@ -2025,11 +1990,6 @@
target = 8DC2EF4F0486A6940098B216 /* Breakpad */;
targetProxy = F9C44E190EF0790F003AEBAA /* PBXContainerItemProxy */;
};
@@ -212,7 +221,7 @@ index 1a93ce6..1c1d643 100644
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -2126,8 +2084,12 @@
@@ -2126,8 +2086,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */;
buildSettings = {
@@ -226,7 +235,7 @@ index 1a93ce6..1c1d643 100644
};
name = Debug;
};
@@ -2135,7 +2097,12 @@
@@ -2135,7 +2099,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 8B31027811F0D3AF00FCF3E4 /* BreakpadRelease.xcconfig */;
buildSettings = {
@@ -239,7 +248,7 @@ index 1a93ce6..1c1d643 100644
};
name = Release;
};
@@ -2454,7 +2421,12 @@
@@ -2454,7 +2423,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */;
buildSettings = {
@@ -253,7 +262,7 @@ index 1a93ce6..1c1d643 100644
name = "Debug With Code Coverage";
};
diff --git a/src/client/mac/Framework/Breakpad.mm b/src/client/mac/Framework/Breakpad.mm
index 1d2e519..943310f 100644
index 1d2e519b..943310fa 100644
--- a/src/client/mac/Framework/Breakpad.mm
+++ b/src/client/mac/Framework/Breakpad.mm
@@ -355,10 +355,10 @@ bool Breakpad::Initialize(NSDictionary *parameters) {
@@ -480,7 +489,7 @@ index 1d2e519..943310f 100644
}
diff --git a/src/common/language.cc b/src/common/language.cc
index 978fb85..a95ae5f 100644
index 978fb855..a95ae5f7 100644
--- a/src/common/language.cc
+++ b/src/common/language.cc
@@ -46,8 +46,27 @@
@@ -552,7 +561,7 @@ index 978fb85..a95ae5f 100644
#endif
}
diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc
index 562875e..4367851 100644
index 562875e1..43678510 100644
--- a/src/common/linux/elf_symbols_to_module.cc
+++ b/src/common/linux/elf_symbols_to_module.cc
@@ -39,6 +39,29 @@
@@ -615,7 +624,7 @@ index 562875e..4367851 100644
module->AddExtern(ext);
}
diff --git a/src/tools/linux/tools_linux.gypi b/src/tools/linux/tools_linux.gypi
index 1c15992..020e4c1 100644
index 1c15992e..020e4c1c 100644
--- a/src/tools/linux/tools_linux.gypi
+++ b/src/tools/linux/tools_linux.gypi
@@ -58,7 +58,7 @@
@@ -627,3 +636,16 @@ index 1c15992..020e4c1 100644
],
'dependencies': [
'../common/common.gyp:common',
diff --git a/src/tools/mac/dump_syms/macho_dump.cc b/src/tools/mac/dump_syms/macho_dump.cc
index d882bbe8..3432bb45 100644
--- a/src/tools/mac/dump_syms/macho_dump.cc
+++ b/src/tools/mac/dump_syms/macho_dump.cc
@@ -140,7 +140,7 @@ void DumpFile(const char *filename) {
size_t object_files_size;
const SuperFatArch* super_fat_object_files =
fat_reader.object_files(&object_files_size);
- struct fat_arch *object_files;
+ struct fat_arch *object_files = 0;
if (!super_fat_object_files->ConvertToFatArch(object_files)) {
exit(1);
}

View File

@@ -12,7 +12,108 @@ pacman --noconfirm -S pkg-config
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
./configure --toolchain=msvc --disable-programs --disable-doc --disable-everything --enable-protocol=file --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --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=wavpack --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=pcm_zork --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_d3d11va --enable-hwaccel=h264_dxva2 --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --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=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release"
./configure --toolchain=msvc \
--extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release" \
--disable-programs \
--disable-doc \
--disable-network \
--disable-everything \
--enable-hwaccel=h264_d3d11va \
--enable-hwaccel=h264_d3d11va2 \
--enable-hwaccel=h264_dxva2 \
--enable-hwaccel=hevc_d3d11va \
--enable-hwaccel=hevc_d3d11va2 \
--enable-hwaccel=hevc_dxva2 \
--enable-hwaccel=mpeg2_d3d11va \
--enable-hwaccel=mpeg2_d3d11va2 \
--enable-hwaccel=mpeg2_dxva2 \
--enable-protocol=file --enable-libopus \
--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=pcm_zork \
--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 -j4
make -j4 install

View File

@@ -1,8 +1,8 @@
diff --git a/build/common.gypi b/build/common.gypi
index 1affc70..c0d2f6a 100644
index 1affc70..0677e4b 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -66,6 +66,11 @@
@@ -66,6 +66,13 @@
'conditions': [
['clang!=0', {
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', # -std=c++11
@@ -10,11 +10,13 @@ index 1affc70..c0d2f6a 100644
+ 'OTHER_LDFLAGS': [
+ '/usr/local/macold/lib/libc++.a',
+ '/usr/local/macold/lib/libc++abi.a',
+ '-isysroot/',
+ '-L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/',
+ ],
# Don't link in libarclite_macosx.a, see http://crbug.com/156530.
'CLANG_LINK_OBJC_RUNTIME': 'NO', # -fno-objc-link-runtime
@@ -116,6 +121,9 @@
@@ -116,6 +123,9 @@
],
},

View File

@@ -1,5 +1,5 @@
diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf
index eec9e1f..7ae53c7 100644
index eec9e1f688..7ae53c7a1e 100644
--- a/mkspecs/common/msvc-desktop.conf
+++ b/mkspecs/common/msvc-desktop.conf
@@ -30,9 +30,10 @@ QMAKE_YACCFLAGS = -d
@@ -17,7 +17,7 @@ index eec9e1f..7ae53c7 100644
QMAKE_CFLAGS_LTCG = -GL
QMAKE_CFLAGS_SSE2 = -arch:SSE2
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index 391fbcc..d07802b 100644
index 391fbcc519..d07802bb7a 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -427,11 +427,12 @@ qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
@@ -36,7 +36,7 @@ index 391fbcc..d07802b 100644
// Note: Only return error if the first WriteFile failed.
q->setError(QFile::WriteError, qt_error_string());
diff --git a/src/corelib/tools/qunicodetables.cpp b/src/corelib/tools/qunicodetables.cpp
index 14e4fd1..0619a17 100644
index 14e4fd10aa..0619a176a7 100644
--- a/src/corelib/tools/qunicodetables.cpp
+++ b/src/corelib/tools/qunicodetables.cpp
@@ -6227,7 +6227,8 @@ static const Properties uc_properties[] = {
@@ -50,7 +50,7 @@ index 14e4fd1..0619a17 100644
{ 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
{ 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
index 2d00b9d..eeba86e 100644
index 2d00b9dce9..eeba86e936 100644
--- a/src/gui/kernel/qhighdpiscaling.cpp
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -51,6 +51,9 @@ static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS";
@@ -64,7 +64,7 @@ index 2d00b9d..eeba86e 100644
qreal result = 1;
if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) {
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
index 5b2f4ec..790db46 100644
index 5b2f4ece77..790db46d25 100644
--- a/src/gui/kernel/qplatformdialoghelper.h
+++ b/src/gui/kernel/qplatformdialoghelper.h
@@ -386,6 +386,10 @@ public:
@@ -79,7 +79,7 @@ index 5b2f4ec..790db46 100644
virtual void selectNameFilter(const QString &filter) = 0;
virtual QString selectedNameFilter() const = 0;
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index bcd29b6..bcb0672 100644
index bcd29b6fe1..bcb0672f69 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -2525,7 +2525,8 @@ void QWindowPrivate::setCursor(const QCursor *newCursor)
@@ -93,7 +93,7 @@ index bcd29b6..bcb0672 100644
QCursor *c = QGuiApplication::overrideCursor();
if (!c && hasCursor)
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
index 918c989..4158259 100644
index 918c98997b..4158259743 100644
--- a/src/gui/painting/qpaintengine_p.h
+++ b/src/gui/painting/qpaintengine_p.h
@@ -80,8 +80,18 @@ public:
@@ -117,7 +117,7 @@ index 918c989..4158259 100644
// Make sure we're inside the viewport.
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 7e507bb..936e7a9 100644
index 7e507bba2d..936e7a92cb 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -283,7 +283,8 @@ private:
@@ -131,7 +131,7 @@ index 7e507bb..936e7a9 100644
public:
inline QTextItemInt()
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index aca475a..5fa0be2 100644
index aca475a581..5fa0be2c45 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -694,6 +694,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
@@ -208,7 +208,7 @@ index aca475a..5fa0be2 100644
static const QFixed RightBearingNotCalculated;
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
index f74d4d4..8ad672c 100644
index f74d4d4229..8ad672c9fe 100644
--- a/src/gui/text/qtextlayout.h
+++ b/src/gui/text/qtextlayout.h
@@ -196,6 +196,9 @@ private:
@@ -222,7 +222,7 @@ index f74d4d4..8ad672c 100644
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index c4cb8e6..45793e3 100644
index c4cb8e65c0..45793e364f 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -110,6 +110,8 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
@@ -235,7 +235,7 @@ index c4cb8e6..45793e3 100644
delete channels[i].socket;
}
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 41834b2..8cdf4ab 100644
index 41834b21ae..8cdf4ab145 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -675,6 +675,13 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
@@ -253,7 +253,7 @@ index 41834b2..8cdf4ab 100644
setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
socketState = QAbstractSocket::UnconnectedState;
diff --git a/src/platformsupport/dbustray/qdbustrayicon.cpp b/src/platformsupport/dbustray/qdbustrayicon.cpp
index 4d6e707..9bdb0be 100644
index 4d6e70720d..9bdb0beb67 100644
--- a/src/platformsupport/dbustray/qdbustrayicon.cpp
+++ b/src/platformsupport/dbustray/qdbustrayicon.cpp
@@ -58,9 +58,18 @@ QT_BEGIN_NAMESPACE
@@ -290,7 +290,7 @@ index 4d6e707..9bdb0be 100644
}
if (!necessary)
diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
index 728b166..1dc6459 100644
index 728b166b71..1dc64593e1 100644
--- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
+++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
@@ -172,6 +172,79 @@ void QBasicFontDatabase::releaseHandle(void *handle)
@@ -388,7 +388,7 @@ index 728b166..1dc6459 100644
if (error != FT_Err_Ok) {
qDebug() << "FT_New_Face failed with index" << index << ':' << hex << error;
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
index 8ebabf3..7bb8abd 100644
index 8ebabf3419..7bb8abd0d0 100644
--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
@@ -375,6 +375,17 @@ static void populateFromPattern(FcPattern *pattern)
@@ -450,7 +450,7 @@ index 8ebabf3..7bb8abd 100644
}
populateFromPattern(pattern);
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
index 566abf2..5c5fde9 100644
index 566abf2126..5c5fde9813 100644
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
@@ -265,6 +265,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
@@ -482,7 +482,7 @@ index 566abf2..5c5fde9 100644
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
double d;
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
index 7b45958..2ed2fd9 100644
index 7b459584ea..2ed2fd9b3b 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
@@ -764,7 +764,8 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gl
@@ -496,7 +496,7 @@ index 7b45958..2ed2fd9 100644
QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const
diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro
index 86bdd47..9b9c8de 100644
index 86bdd4729b..9b9c8ded08 100644
--- a/src/plugins/platforminputcontexts/compose/compose.pro
+++ b/src/plugins/platforminputcontexts/compose/compose.pro
@@ -15,7 +15,8 @@ HEADERS += $$PWD/qcomposeplatforminputcontext.h \
@@ -510,7 +510,7 @@ index 86bdd47..9b9c8de 100644
LIBS += $$QMAKE_LIBS_XKBCOMMON
QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON
diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
index d1bea9a..36a15a6 100644
index d1bea9af23..36a15a6473 100644
--- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
@@ -232,6 +232,12 @@ bool QComposeInputContext::checkComposeTable()
@@ -527,7 +527,7 @@ index d1bea9a..36a15a6 100644
event.setCommitString(QChar(character));
QCoreApplication::sendEvent(m_focusObject, &event);
diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro
index faea54b..fe4a837 100644
index faea54b874..fe4a837511 100644
--- a/src/plugins/platforminputcontexts/platforminputcontexts.pro
+++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro
@@ -1,7 +1,8 @@
@@ -541,7 +541,7 @@ index faea54b..fe4a837 100644
contains(QT_CONFIG, xcb-plugin): SUBDIRS += compose
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index caa8884..9dc3bc1 100644
index caa8884661..9dc3bc1661 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -210,7 +210,8 @@ QT_END_NAMESPACE
@@ -572,7 +572,7 @@ index caa8884..9dc3bc1 100644
}
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index 934f68a..3ece698 100644
index 934f68ad18..3ece6984ac 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -64,6 +64,9 @@ public:
@@ -586,7 +586,7 @@ index 934f68a..3ece698 100644
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index ca92103..f27ea15 100644
index ca92103826..f27ea15bad 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -38,7 +38,8 @@
@@ -624,7 +624,7 @@ index ca92103..f27ea15 100644
p.setCompositionMode(QPainter::CompositionMode_Source);
const QVector<QRect> rects = region.rects();
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 058209d..6af61e7 100644
index 058209da7e..6af61e7dab 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -546,9 +546,9 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm
@@ -654,7 +654,7 @@ index 058209d..6af61e7 100644
}
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
index c2d206f..9b97398 100644
index c2d206fb45..9b9739862d 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
@@ -384,6 +384,12 @@ bool QCocoaKeyMapper::updateKeyboard()
@@ -681,7 +681,7 @@ index c2d206f..9b97398 100644
}
return ret;
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 8152c57..87ba2f3 100644
index 8152c57ffd..87ba2f3f72 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -94,6 +94,8 @@ QT_USE_NAMESPACE
@@ -821,7 +821,7 @@ index 8152c57..87ba2f3 100644
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index c0d5904..f3c2047 100644
index c0d5904367..f3c2047196 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -141,7 +141,8 @@ static bool isMouseEvent(NSEvent *ev)
@@ -883,7 +883,7 @@ index c0d5904..f3c2047 100644
[iconButton setImage:image];
[image release];
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index c67bcfd..2616f42 100644
index c67bcfd23b..6a60670aee 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -647,6 +647,12 @@ QT_WARNING_POP
@@ -957,8 +957,19 @@ index c67bcfd..2616f42 100644
- (void)cancelOperation:(id)sender
{
Q_UNUSED(sender);
@@ -1981,6 +2006,10 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
// change the cursor
[nativeCursor set];
+ // Patch: Backport a fix from cd08753d3e. Starting with macOS Mojave this requires accessibility access.
+ if (QSysInfo::macVersion() >= Q_MV_OSX(10, 14))
+ return;
+
// Make sure the cursor is updated correctly if the mouse does not move and window is under cursor
// by creating a fake move event
if (m_updatingDrag)
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 94bb71e..16ab51e 100644
index 94bb71e429..16ab51e166 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -716,12 +716,20 @@ public:
@@ -1163,7 +1174,7 @@ index 94bb71e..16ab51e 100644
{
m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time.
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index 1e58b9b..1741c21 100644
index 1e58b9b3d4..1741c21a1c 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -1268,6 +1268,10 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
@@ -1178,7 +1189,7 @@ index 1e58b9b..1741c21 100644
if (!kbItem.exists)
return result;
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
index 1d23a9d..640cd42 100644
index 1d23a9d9b9..640cd426ed 100644
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -127,6 +127,10 @@ static inline bool launchMail(const QUrl &url)
@@ -1193,7 +1204,7 @@ index 1d23a9d..640cd42 100644
// but that cannot handle a Windows command line [yet].
command.replace(QStringLiteral("%1"), url.toString(QUrl::FullyEncoded));
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index b38d7c2..34f19c4 100644
index b38d7c29ae..34f19c4efa 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1020,7 +1020,8 @@ void QWindowsWindow::destroyWindow()
@@ -1247,7 +1258,7 @@ index b38d7c2..34f19c4 100644
break;
}
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 6fffa1e..cb1c9c1 100644
index 6fffa1e6e9..cb1c9c1161 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -265,6 +265,10 @@ private:
@@ -1262,7 +1273,7 @@ index 6fffa1e..cb1c9c1 100644
inline bool isDropSiteEnabled() const { return m_dropTarget != 0; }
void setDropSiteEnabled(bool enabled);
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 09e7ecf..c0f15a4 100644
index 09e7ecf3a3..c0f15a4242 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -79,7 +79,10 @@ static int resourceType(const QByteArray &key)
@@ -1292,7 +1303,7 @@ index 09e7ecf..c0f15a4 100644
break;
}
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index f88b710..6f818a5 100644
index f88b710864..6f818a5a72 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -68,7 +68,10 @@ public:
@@ -1308,7 +1319,7 @@ index f88b710..6f818a5 100644
QXcbNativeInterface();
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index bc2de89..aa8f8df 100644
index bc2de899f5..aa8f8df4ad 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -1200,6 +1200,15 @@ QList<QUrl> QFileDialogPrivate::userSelectedFiles() const
@@ -1343,7 +1354,7 @@ index bc2de89..aa8f8df 100644
Returns a list of urls containing the selected files in the dialog.
If no files are selected, or the mode is not ExistingFiles or
diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h
index ffe49a2..42dc563 100644
index ffe49a2dd2..42dc563c8a 100644
--- a/src/widgets/dialogs/qfiledialog.h
+++ b/src/widgets/dialogs/qfiledialog.h
@@ -108,6 +108,9 @@ public:
@@ -1357,7 +1368,7 @@ index ffe49a2..42dc563 100644
QList<QUrl> selectedUrls() const;
diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h
index f610e46..547a646 100644
index f610e46f83..547a64695a 100644
--- a/src/widgets/dialogs/qfiledialog_p.h
+++ b/src/widgets/dialogs/qfiledialog_p.h
@@ -123,6 +123,10 @@ public:
@@ -1398,7 +1409,7 @@ index f610e46..547a646 100644
{
if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index b1d80d7..42e32fd 100644
index b1d80d7b8f..42e32fd404 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -5138,6 +5138,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
@@ -1451,7 +1462,7 @@ index b1d80d7..42e32fd 100644
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
res = focusNextPrevChild(false);
diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp
index 704142f..7c4340e 100644
index 704142fe5c..7c4340e459 100644
--- a/src/widgets/util/qsystemtrayicon.cpp
+++ b/src/widgets/util/qsystemtrayicon.cpp
@@ -709,6 +709,10 @@ void QSystemTrayIconPrivate::updateMenu_sys_qpa()
@@ -1466,7 +1477,7 @@ index 704142f..7c4340e 100644
}
diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp
index 2e2a042..472e377 100644
index 2e2a042bf1..472e37722b 100644
--- a/src/widgets/widgets/qabstractscrollarea.cpp
+++ b/src/widgets/widgets/qabstractscrollarea.cpp
@@ -640,15 +640,22 @@ scrolling range.
@@ -1497,7 +1508,7 @@ index 2e2a042..472e377 100644
}
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
index daf9f00..57499dc 100644
index daf9f00c46..57499dc4a4 100644
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
@@ -40,6 +40,11 @@
@@ -1539,7 +1550,7 @@ index daf9f00..57499dc 100644
#ifndef QT_NO_COMPLETER
complete(event->key());
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index deca002..8a2023f 100644
index deca002bf5..8a2023f503 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -71,6 +71,11 @@

View File

@@ -92,7 +92,7 @@ msgServiceFont: semiboldFont;
msgServiceNameFont: semiboldFont;
msgServicePhotoWidth: 100px;
msgDateFont: font(13px);
msgMinWidth: 190px;
msgMinWidth: 160px;
msgPhotoSize: 33px;
msgPhotoSkip: 40px;
msgPadding: margins(13px, 7px, 13px, 8px);
@@ -258,19 +258,6 @@ videoIcon: icon {
};
locationSize: size(320px, 240px);
webPageLeft: 10px;
webPageBar: 2px;
webPageTitleFont: semiboldFont;
webPageTitleStyle: semiboldTextStyle;
webPageTitleOutFg: historyTextOutFg;
webPageTitleInFg: historyTextInFg;
webPageDescriptionOutFg: historyTextOutFg;
webPageDescriptionInFg: historyTextInFg;
webPageDescriptionFont: normalFont;
webPageDescriptionStyle: defaultTextStyle;
webPagePhotoSize: 100px;
webPagePhotoDelta: 8px;
mediaPlayerSuppressDuration: 150;
botDescSkip: 8px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -311,7 +311,8 @@ div.selected {
background-position: 12px 12px;
background-size: 24px 24px;
}
.default .media .title {
.default .media .title,
.default .media_poll .question {
padding-top: 4px;
font-size: 14px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -128,6 +128,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gif_error" = "An error has occurred while reading GIF animation :(";
"lng_edit_error" = "You cannot edit this message";
"lng_join_channel_error" = "Sorry, you have joined too many channels and supergroups. Please leave some before joining this one.";
"lng_migrate_error" = "This action will convert the group to a supergroup. Unfortunately, you are a member of too many supergroups and channels. Please leave some of the channels or groups you don't need before proceeding.";
"lng_error_phone_flood" = "Sorry, you have deleted and re-created your account too many times recently. Please wait for a few days before signing up again.";
"lng_error_start_minimized_passcoded" = "You have set a local passcode, so Telegram Desktop can't be launched minimised; it will ask you to enter your passcode before it can start working.";
"lng_error_pinned_max#one" = "Sorry, you can pin no more than {count} chat to the top.";
@@ -142,10 +143,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_error_admin_limit_channel" = "Sorry, you've reached the maximum number of admins for this channel.";
"lng_sure_add_admin_invite" = "This user is not a member of this group. Add them to the group and promote them to admin?";
"lng_sure_add_admin_invite_channel" = "This user is not a subscriber of this channel. Add them to the channel and promote them to admin?";
"lng_sure_add_admin_unban" = "This user is currently restricted or banned. Are you sure you want to unban and promote them?";
"lng_sure_add_admin_unremove" = "This user is currently restricted or removed. Are you sure you want to promote them?";
"lng_sure_ban_admin" = "This user is an admin. Are you sure you want to go ahead and restrict them?";
"lng_sure_ban_user_group" = "Ban {user} in the group?";
"lng_sure_ban_user_channel" = "Ban {user} in the channel?";
"lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in the Settings (Connection Type).";
"lng_sure_enable" = "Enable";
@@ -156,6 +155,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_deleted" = "Deleted Account";
"lng_deleted_message" = "Deleted message";
"lng_pinned_message" = "Pinned message";
"lng_pinned_poll" = "Pinned poll";
"lng_pinned_unpin_sure" = "Would you like to unpin this message?";
"lng_pinned_pin_sure" = "Would you like to pin this message?";
"lng_pinned_pin" = "Pin";
@@ -274,16 +274,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_empty_bio" = "None";
"lng_settings_section_notify" = "Notifications";
"lng_settings_notify_title" = "Notifications for chats";
"lng_settings_desktop_notify" = "Desktop notifications";
"lng_settings_show_name" = "Show sender's name";
"lng_settings_show_preview" = "Show message preview";
"lng_settings_native_title" = "Native notifications";
"lng_settings_use_windows" = "Use Windows notifications";
"lng_settings_use_native_notifications" = "Use native notifications";
"lng_settings_notifications_position" = "Location on the screen";
"lng_settings_notifications_count" = "Notifications count";
"lng_settings_sound_notify" = "Play sound";
"lng_settings_badge_title" = "Badge counter";
"lng_settings_include_muted" = "Include muted chats in unread count";
"lng_settings_count_unread" = "Count unread messages";
"lng_settings_events_title" = "Events";
"lng_settings_events_joined" = "Contact joined Telegram";
"lng_notification_preview" = "You have a new message";
"lng_notification_reply" = "Reply";
@@ -330,6 +335,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_bg_tile" = "Tile background";
"lng_settings_adaptive_wide" = "Adaptive layout for wide screens";
"lng_settings_section_call_settings" = "Calls Settings";
"lng_settings_call_section_output" = "Speakers and headphones";
"lng_settings_call_section_input" = "Microphone";
"lng_settings_call_input_device" = "Input device";
"lng_settings_call_output_device" = "Output device";
"lng_settings_call_input_volume" = "Input volume: {percent}%";
"lng_settings_call_output_volume" = "Output volume: {percent}%";
"lng_settings_call_test_mic" = "Test microphone";
"lng_settings_call_stop_mic_test" = "Stop test";
"lng_settings_call_section_other" = "Other settings";
"lng_settings_call_open_system_prefs" = "Open system sound preferences";
"lng_settings_call_device_default" = "Default";
"lng_settings_call_audio_ducking" = "Mute other sounds during calls";
"lng_settings_language" = "Language";
"lng_settings_default_scale" = "Default interface scale";
"lng_settings_connection_type" = "Connection type";
@@ -340,6 +359,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_calls_peer_to_peer" = "Peer-to-peer in calls";
"lng_settings_groups_invite" = "Groups";
"lng_settings_group_privacy_about" = "Change who can add you to groups and channels.";
"lng_settings_forwards_privacy" = "Forwarded messages";
"lng_settings_profile_photo_privacy" = "Profile photo";
"lng_settings_sessions_about" = "Control your sessions on other devices.";
"lng_settings_passcode_disable" = "Disable passcode";
"lng_settings_password_disable" = "Disable cloud password";
@@ -376,6 +397,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_theme_reverting#other" = "Reverting to the old theme in {count} seconds.";
"lng_theme_keep_changes" = "Keep changes";
"lng_theme_revert" = "Revert";
"lng_background_header" = "Background preview";
"lng_background_text1" = "Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff!";
"lng_background_text2" = "I can't even take you seriously right now.";
"lng_background_bad_link" = "This background link appears to be invalid.";
"lng_background_apply" = "Apply";
"lng_background_share" = "Share";
"lng_background_link_copied" = "Link copied to clipboard";
"lng_background_blur" = "Blurred";
"lng_background_sure_delete" = "Are you sure you want to delete this background?";
"lng_download_path_ask" = "Ask download path for each file";
"lng_download_path" = "Download path";
@@ -408,7 +438,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_local_storage_round#other" = "{count} video messages";
"lng_local_storage_animation#one" = "{count} animation";
"lng_local_storage_animation#other" = "{count} animations";
"lng_local_storage_media" = "Media cache";
"lng_local_storage_size_limit" = "Total size limit: {size}";
"lng_local_storage_media_limit" = "Media cache limit: {size}";
"lng_local_storage_time_limit" = "Clear files older than: {limit}";
"lng_local_storage_limit_weeks#one" = "{count} week";
"lng_local_storage_limit_weeks#other" = "{count} weeks";
@@ -610,6 +642,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_edit_privacy_calls_p2p_contacts" = "My contacts";
"lng_edit_privacy_calls_p2p_nobody" = "Nobody";
"lng_edit_privacy_forwards_title" = "Forwarded messages privacy";
"lng_edit_privacy_forwards_header" = "Who can add link to my account when forwarding my messages";
"lng_edit_privacy_forwards_warning" = "When forwarded to other chats, messages you send will not link back to your account.";
"lng_edit_privacy_forwards_always_empty" = "Always allow";
"lng_edit_privacy_forwards_never_empty" = "Never allow";
"lng_edit_privacy_forwards_exceptions" = "These settings will override the values above.";
"lng_edit_privacy_forwards_always_title" = "Always allow";
"lng_edit_privacy_forwards_never_title" = "Never allow";
"lng_edit_privacy_forwards_sample_message" = "Reinhardt, we need to find you some new tunes 🎶";
"lng_edit_privacy_forwards_sample_everyone" = "Link to your account.";
"lng_edit_privacy_forwards_sample_contacts" = "Link if allowed by settings below.";
"lng_edit_privacy_forwards_sample_nobody" = "Not a link to your account.";
"lng_edit_privacy_profile_photo_title" = "Profile photo privacy";
"lng_edit_privacy_profile_photo_header" = "Who can see my profile photo";
"lng_edit_privacy_profile_photo_always_empty" = "Always allow";
"lng_edit_privacy_profile_photo_never_empty" = "Never allow";
"lng_edit_privacy_profile_photo_exceptions" = "These settings will override the values above.";
"lng_edit_privacy_profile_photo_always_title" = "Always allow";
"lng_edit_privacy_profile_photo_never_title" = "Never allow";
"lng_self_destruct_title" = "Account self-destruction";
"lng_self_destruct_description" = "If you don't come online at least once within this period, your account will be deleted along with all groups, messages and contacts.";
"lng_self_destruct_months#one" = "{count} month";
@@ -647,10 +700,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_create_public_link" = "Create public link";
"lng_profile_edit_public_link" = "Edit public link";
"lng_profile_search_members" = "Search members";
"lng_profile_manage_admins" = "Manage administrators";
"lng_profile_manage_blocklist" = "Manage banned users";
"lng_profile_manage_restrictedlist" = "Manage restricted users";
"lng_profile_recent_actions" = "Recent actions";
"lng_profile_common_groups#one" = "{count} group in common";
"lng_profile_common_groups#other" = "{count} groups in common";
"lng_profile_participants_section" = "Members";
@@ -678,6 +727,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_join_group" = "Join Group";
"lng_profile_delete_and_exit" = "Leave";
"lng_profile_kick" = "Remove";
"lng_profile_delete_removed" = "Delete";
"lng_profile_sure_kick" = "Remove {user} from the group?";
"lng_profile_sure_kick_channel" = "Remove {user} from the channel?";
"lng_profile_sure_remove_admin" = "Remove {user} from admins?";
@@ -773,13 +823,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_recent_actions" = "Recent Actions";
"lng_manage_peer_members" = "Members";
"lng_manage_peer_administrators" = "Administrators";
"lng_manage_peer_banned_users" = "Banned users";
"lng_manage_peer_restricted_users" = "Restricted users";
"lng_manage_peer_exceptions" = "Exceptions";
"lng_manage_peer_removed_users" = "Removed users";
"lng_manage_peer_permissions" = "Permissions";
"lng_manage_peer_group_type" = "Group type";
"lng_manage_peer_channel_type" = "Channel type";
"lng_manage_private_peer_title" = "Private";
"lng_manage_public_peer_title" = "Public";
"lng_manage_history_visibility_title" = "Chat history for new members";
"lng_manage_history_visibility_shown" = "Visible";
"lng_manage_history_visibility_shown_about" = "New members will see messages that were sent before they joined.";
"lng_manage_history_visibility_hidden" = "Hidden";
"lng_manage_history_visibility_hidden_about" = "New members won't see earlier messages.";
"lng_manage_history_visibility_hidden_legacy" = "New members won't see more than 100 previous messages.";
"lng_report_title" = "Report channel";
"lng_report_group_title" = "Report group";
@@ -794,17 +852,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_report_thanks" = "Thank you! Your report will be reviewed by our team very soon.";
"lng_channel_add_members" = "Add members";
"lng_channel_add_banned" = "Ban user";
"lng_channel_add_restricted" = "Restrict user";
"lng_channel_add_users" = "Add users";
"lng_channel_add_removed" = "Remove user";
"lng_channel_add_exception" = "Add exception";
"lng_channel_admins" = "Administrators";
"lng_channel_add_admin" = "Add Administrator";
"lng_channel_admin_status_creator" = "Creator";
"lng_channel_admin_status_promoted_by" = "Promoted by {user}";
"lng_channel_admin_status_not_admin" = "Not administrator";
"lng_channel_banned_status_restricted_by" = "Restricted by {user}";
"lng_channel_banned_status_removed_by" = "Removed by {user}";
"lng_group_blocked_list_about" = "Banned users are removed from the group and can only come back if invited by an admin.\nInvite links don't work for them.";
"lng_channel_blocked_list_about" = "Banned users are removed from the channel.\nInvite links don't work for them.";
"lng_channel_removed_list_about" = "Users removed from the channel by admins cannot rejoin it via invite links.";
"lng_group_removed_list_about" = "Users removed from the group by admins cannot rejoin it via invite links.";
"lng_chat_all_members_admins" = "All Members Are Admins";
"lng_chat_about_all_admins" = "Group members can add new members, edit name and photo of the group.";
@@ -829,6 +889,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_create_private_group_about" = "People can only join if they were invited or have an invite link";
"lng_create_group_skip" = "Skip";
"lng_create_channel_link_about" = "You can use a-z, 0-9 and underscores.\nMinimum length is 5 characters.";
"lng_create_channel_link_invalid" = "This link is invalid";
"lng_create_channel_link_occupied" = "Sorry, this link is already occupied";
"lng_create_channel_link_too_short" = "Sorry, this link is too short";
@@ -884,7 +946,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_changed_title_channel" = "Channel name was changed to «{title}»";
"lng_action_created_chat" = "{from} created group «{title}»";
"lng_action_created_channel" = "Channel created";
"lng_action_group_migrate" = "The group was upgraded to a supergroup";
"lng_action_pinned_message" = "{from} pinned «{text}»";
"lng_action_pinned_media" = "{from} pinned {media}";
"lng_action_pinned_media_photo" = "a photo";
@@ -939,8 +1000,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_convert_feature4" = "— Creator can set a public link for the group";
"lng_profile_convert_warning" = "{bold_start}Note:{bold_end} This action can not be undone";
"lng_profile_convert_confirm" = "Convert";
"lng_profile_add_more_after_upgrade#one" = "You will be able to add up to {count} member after you upgrade your group to a supergroup.";
"lng_profile_add_more_after_upgrade#other" = "You will be able to add up to {count} members after you upgrade your group to a supergroup.";
"lng_profile_add_more_after_create" = "You will be able to add more members after you create the group.";
"lng_channel_not_accessible" = "Sorry, this channel is not accessible.";
"lng_group_not_accessible" = "Sorry, this group is not accessible.";
@@ -973,6 +1033,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_forwarded_via" = "Forwarded from {user} via {inline_bot}";
"lng_forwarded_channel_via" = "Forwarded from {channel} via {inline_bot}";
"lng_forwarded_signed" = "{channel} ({user})";
"lng_forwarded_hidden" = "The account was hidden by the user.";
"lng_signed_author" = "Author: {user}";
"lng_in_reply_to" = "In reply to";
"lng_edited" = "edited";
"lng_edited_date" = "Edited: {date}";
@@ -997,13 +1059,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_media_audio" = "Voice message";
"lng_media_auto_settings" = "Automatic media download";
"lng_media_auto_in_private" = "In private chats";
"lng_media_auto_in_groups" = "In groups";
"lng_media_auto_in_channels" = "In channels";
"lng_media_auto_title" = "Automatically download";
"lng_media_photo_title" = "Photos";
"lng_media_video_title" = "Video files";
"lng_media_audio_title" = "Voice messages";
"lng_media_gif_title" = "GIFs and animations";
"lng_media_auto_private_chats" = "Private chats";
"lng_media_auto_groups" = "Groups and channels";
"lng_media_auto_play" = "Autoplay";
"lng_media_video_messages_title" = "Round video messages";
"lng_media_file_title" = "Files";
"lng_media_music_title" = "Music";
"lng_media_animation_title" = "Animated GIFs";
"lng_media_size_limit" = "Limit by size";
"lng_media_size_up_to" = "up to {size}";
"lng_media_chat_background" = "Chat background";
"lng_emoji_category1" = "People";
"lng_emoji_category2" = "Nature";
@@ -1013,6 +1082,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_emoji_category6" = "Objects";
"lng_emoji_category7" = "Symbols & Flags";
"lng_emoji_hide_panel" = "Click here to hide the emoji sidebar";
"lng_emoji_manage_sets" = "Choose emoji set";
"lng_emoji_set_ready" = "Downloaded";
"lng_emoji_set_active" = "Current set";
"lng_emoji_set_download" = "Download {size}";
"lng_emoji_set_loading" = "{percent}, {progress}";
"lng_recent_stickers" = "Frequently used";
"lng_faved_stickers_add" = "Add to Favorites";
@@ -1021,6 +1095,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_stickers_description" = "You can choose a sticker set which will be available for every member while in the group chat.";
"lng_group_stickers_add" = "Choose sticker set";
"lng_group_about_header" = "You have created a group.";
"lng_group_about_text" = "Groups can have:";
"lng_group_about1" = "Up to 100,000 members";
"lng_group_about2" = "Persistent chat history";
"lng_group_about3" = "Public links such as t.me/title";
"lng_group_about4" = "Admins with different rights";
"lng_switch_stickers" = "Stickers";
"lng_switch_emoji" = "Emoji";
"lng_switch_gifs" = "GIFs";
@@ -1048,6 +1129,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stickers_count#one" = "{count} sticker";
"lng_stickers_count#other" = "{count} stickers";
"lng_stickers_masks_pack" = "This is a pack of mask stickers. You can use them in the photo editor on our mobile apps.";
"lng_stickers_attached_sets" = "Sets of attached stickers";
"lng_stickers_group_set" = "Group sticker set";
"lng_stickers_remove_group_set" = "Remove group sticker set?";
"lng_stickers_group_from_your" = "Choose from your stickers";
@@ -1066,6 +1148,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_in_dlg_file" = "File";
"lng_in_dlg_sticker" = "Sticker";
"lng_in_dlg_sticker_emoji" = "{emoji} Sticker";
"lng_in_dlg_poll" = "Poll";
"lng_ban_user" = "Ban User";
"lng_delete_all_from" = "Delete all from this user";
@@ -1082,7 +1165,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_cant_invite_banned" = "Sorry, only admin can add this user.";
"lng_cant_invite_privacy" = "Sorry, you cannot add this user to groups because of their privacy settings.";
"lng_cant_invite_privacy_channel" = "Sorry, you cannot add this user to channels because of their privacy settings.";
"lng_cant_invite_bot_to_channel" = "Sorry, bots can only be added to channels as administrators.";
"lng_cant_do_this" = "Sorry, this action is unavailable.";
"lng_cant_invite_offer_admin" = "Bots can only be added as administrators.";
"lng_cant_invite_make_admin" = "Make admin";
"lng_send_button" = "Send";
"lng_message_ph" = "Write a message...";
@@ -1184,6 +1270,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_edit_permissions" = "Edit permissions";
"lng_context_restrict_user" = "Restrict user";
"lng_context_remove_from_group" = "Remove from group";
"lng_context_add_to_group" = "Add to group";
"lng_context_copy_link" = "Copy Link";
"lng_context_copy_post_link" = "Copy Post Link";
@@ -1204,6 +1291,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_copy_text" = "Copy Text";
"lng_context_open_gif" = "Open GIF";
"lng_context_save_gif" = "Save GIF";
"lng_context_attached_stickers" = "Attached Stickers";
"lng_context_to_msg" = "Go To Message";
"lng_context_reply_msg" = "Reply";
"lng_context_edit_msg" = "Edit";
@@ -1267,9 +1355,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_edit_contact_title" = "Edit contact name";
"lng_edit_channel_title" = "Edit channel";
"lng_edit_sign_messages" = "Sign messages";
"lng_edit_group_who_invites" = "Who can add members";
"lng_edit_group_invites_everybody" = "All members";
"lng_edit_group_invites_only_admins" = "Only admins";
"lng_edit_group" = "Edit group";
"lng_edit_self_title" = "Edit your name";
"lng_confirm_contact_data" = "New Contact";
@@ -1305,8 +1390,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_delete_for_me_chat_hint#other" = "This will delete them just for you, not for other participants of the chat.";
"lng_delete_for_me_hint#one" = "This will delete it just for you.";
"lng_delete_for_me_hint#other" = "This will delete them just for you.";
"lng_selected_unsend_about_user_one" = "You can also delete the message you sent from {user}'s inbox by checking \"Unsend my messages\".";
"lng_selected_unsend_about_user#one" = "You can also delete the {count} message you sent from {user}'s inbox by checking \"Unsend my messages\".";
"lng_selected_unsend_about_user#other" = "You can also delete the {count} messages you sent from {user}'s inbox by checking \"Unsend my messages\".";
"lng_selected_unsend_about_group_one" = "You can also delete the message you sent from the inboxes of other group members by checking \"Unsend my messages\".";
"lng_selected_unsend_about_group#one" = "You can also delete the {count} message you sent from the inboxes of other group members by checking \"Unsend my messages\".";
"lng_selected_unsend_about_group#other" = "You can also delete the {count} messages you sent from the inboxes of other group members by checking \"Unsend my messages\".";
"lng_delete_for_everyone_check" = "Delete for everyone";
"lng_delete_for_other_check" = "Delete for {user}";
"lng_delete_for_other_check" = "Also delete for {user}";
"lng_delete_for_other_my" = "Unsend my messages";
"lng_box_delete" = "Delete";
"lng_box_leave" = "Leave";
@@ -1361,7 +1453,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_menu_formatting_link_edit" = "Edit link";
"lng_menu_formatting_clear" = "Plain text";
"lng_formatting_link_create_title" = "Create link";
"lng_formatting_link_edit_title" = "Create link";
"lng_formatting_link_edit_title" = "Edit link";
"lng_formatting_link_text" = "Text";
"lng_formatting_link_url" = "URL";
"lng_formatting_link_create" = "Create";
@@ -1439,14 +1531,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_player_message_today" = "Today at {time}";
"lng_player_message_yesterday" = "Yesterday at {time}";
"lng_player_message_date" = "{date} at {time}";
//"lng_player_cant_stream" = "This file can't be played before it is fully downloaded.\n\nWould you like to download it?";
"lng_player_download" = "Download";
"lng_rights_edit_admin" = "Manage permissions";
"lng_rights_edit_admin_header" = "What can this admin do?";
"lng_rights_about_add_admins_yes" = "This admin will be able to add new admins with the same (or more limited) permissions.";
"lng_rights_about_add_admins_no" = "This admin will not be able to add new admins.";
"lng_rights_about_admin_cant_edit" = "You cannot edit rights of this admin.";
"lng_rights_about_admin_cant_edit" = "You are not allowed to edit the rights of this admin.";
"lng_rights_about_restriction_cant_edit" = "You cannot change the restrictions for this user.";
"lng_rights_restriction_for_all" = "This option is disabled for all members in Group Permissions. You can either enable the permission for everyone or make this user an admin.";
"lng_rights_permission_for_all" = "This option is enabled for all members in Group Permissions.";
"lng_rights_permission_unavailable" = "This permission is not available in public groups.";
"lng_rights_permission_cant_edit" = "You cannot edit this permission.";
"lng_rights_user_restrictions" = "User restrictions";
"lng_rights_user_restrictions_header" = "What can this user do?";
"lng_rights_user_restrictions_header" = "What can this member do?";
"lng_rights_default_restrictions_header" = "What can members of this group do?";
"lng_rights_channel_info" = "Change channel info";
"lng_rights_channel_post" = "Post messages";
@@ -1464,6 +1565,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_rights_chat_send_media" = "Send media";
"lng_rights_chat_send_stickers" = "Send stickers & GIFs";
"lng_rights_chat_send_links" = "Embed links";
"lng_rights_chat_send_polls" = "Send polls";
"lng_rights_chat_add_members" = "Add members";
"lng_rights_chat_banned_until_header" = "Restricted until";
"lng_rights_chat_banned_forever" = "Forever";
"lng_rights_chat_banned_day#one" = "For {count} day";
@@ -1478,9 +1581,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_restricted_send_stickers" = "The admins of this group restricted you from posting stickers here.";
"lng_restricted_send_gifs" = "The admins of this group restricted you from posting GIFs here.";
"lng_restricted_send_inline" = "The admins of this group restricted you from posting inline content here.";
"lng_restricted_send_polls" = "The admins of this group restricted you from posting polls here.";
"lng_restricted_list_title" = "Restricted users";
"lng_banned_list_title" = "Banned users";
"lng_restricted_send_message_all" = "Writing messages isn't allowed in this group.";
"lng_restricted_send_media_all" = "Posting media content isn't allowed in this group.";
"lng_restricted_send_stickers_all" = "Posting stickers isn't allowed in this group.";
"lng_restricted_send_gifs_all" = "Posting GIFs isn't allowed in this group.";
"lng_restricted_send_inline_all" = "Posting inline content isn't allowed in this group.";
"lng_restricted_send_polls_all" = "Posting polls isn't allowed in this group.";
"lng_exceptions_list_title" = "Exceptions";
"lng_removed_list_title" = "Removed users";
"lng_admin_log_title_all" = "All actions";
"lng_admin_log_title_selected" = "Selected actions";
@@ -1540,10 +1651,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_participant_joined_channel" = "{from} joined the channel";
"lng_admin_log_participant_left" = "{from} left the group";
"lng_admin_log_participant_left_channel" = "{from} left the channel";
"lng_admin_log_stopped_poll" = "{from} stopped poll:";
"lng_admin_log_invited" = "invited {user}";
"lng_admin_log_banned" = "banned {user}";
"lng_admin_log_restricted" = "changed restrictions for {user} {until}";
"lng_admin_log_promoted" = "changed privileges for {user}";
"lng_admin_log_changed_default_permissions" = "changed default permissions";
"lng_admin_log_changed_stickers_group" = "{from} changed the group's {sticker_set}";
"lng_admin_log_changed_stickers_set" = "sticker set";
"lng_admin_log_removed_stickers_group" = "{from} removed the group's sticker set";
@@ -1555,12 +1668,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_banned_send_media" = "Send media";
"lng_admin_log_banned_send_stickers" = "Send stickers & GIFs";
"lng_admin_log_banned_embed_links" = "Embed links";
"lng_admin_log_banned_send_polls" = "Send polls";
"lng_admin_log_admin_change_info" = "Change info";
"lng_admin_log_admin_post_messages" = "Post messages";
"lng_admin_log_admin_edit_messages" = "Edit messages";
"lng_admin_log_admin_delete_messages" = "Delete messages";
"lng_admin_log_admin_ban_users" = "Ban users";
"lng_admin_log_admin_invite_users" = "Add users";
"lng_admin_log_admin_invite_users" = "Add members";
"lng_admin_log_admin_invite_link" = "Invite users via link";
"lng_admin_log_admin_pin_messages" = "Pin messages";
"lng_admin_log_admin_add_admins" = "Add new admins";
@@ -1829,6 +1943,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_launch_exe_sure" = "Run";
"lng_launch_exe_dont_ask" = "Don't ask me again";
"lng_polls_anonymous" = "Anonymous Poll";
"lng_polls_closed" = "Final results";
"lng_polls_votes_count#one" = "{count} vote";
"lng_polls_votes_count#other" = "{count} votes";
"lng_polls_votes_none" = "No votes";
"lng_polls_retract" = "Retract vote";
"lng_polls_stop" = "Stop poll";
"lng_polls_stop_warning" = "If you stop this poll now, nobody will be able to vote in it anymore. This action cannot be undone.";
"lng_polls_stop_sure" = "Stop";
"lng_polls_create" = "Create poll";
"lng_polls_create_title" = "New poll";
"lng_polls_create_question" = "Question";
"lng_polls_create_question_placeholder" = "Ask a question";
"lng_polls_create_options" = "Poll options";
"lng_polls_create_option_add" = "Add an option...";
"lng_polls_create_limit#one" = "You can add {count} more option.";
"lng_polls_create_limit#other" = "You can add {count} more options.";
"lng_polls_create_maximum" = "You have added the maximum number of options.";
"lng_polls_create_button" = "Create";
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";
@@ -1841,6 +1975,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_linux_menu_undo" = "Undo";
"lng_linux_menu_redo" = "Redo";
"lng_linux_no_audio_prefs" = "You don't have any audio configuration applications installed.";
// Mac specific
"lng_mac_choose_program_menu" = "Other...";

View File

@@ -207,7 +207,7 @@
52;MX;Mexico;
51;PE;Peru;51 XXX XXX XXX;11;
49;DE;Germany;49 XXX XXXXXXXX;13;
48;PL;Poland;48 XX XXX XXXX;11;
48;PL;Poland;48 XXX XXX XXX;11;
47;NO;Norway;47 XXXX XXXX;10;
46;SE;Sweden;46 XX XXX XXXX;11;
45;DK;Denmark;45 XXXX XXXX;10;

View File

@@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/gui">
<file alias="emoji/set0_preview.webp">../emoji/set0_preview.webp</file>
<file alias="emoji/set1_preview.webp">../emoji/set1_preview.webp</file>
<file alias="emoji/set2_preview.webp">../emoji/set2_preview.webp</file>
<file alias="emoji/set3_preview.webp">../emoji/set3_preview.webp</file>
</qresource>
</RCC>

View File

@@ -176,7 +176,8 @@ inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = In
inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia;
inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
inputMediaPoll#6b3765b poll:Poll = InputMedia;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
@@ -194,8 +195,6 @@ inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
inputTakeoutFileLocation#29be5899 = InputFileLocation;
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
peerUser#9db1bc6d user_id:int = Peer;
peerChat#bad0e5bb chat_id:int = Peer;
peerChannel#bddde532 channel_id:int = Peer;
@@ -215,7 +214,7 @@ fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileL
fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation;
userEmpty#200250ba id:int = User;
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
@@ -228,13 +227,13 @@ userStatusLastWeek#7bf09fc = UserStatus;
userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat;
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
chatForbidden#7328bdb id:int title:string = Chat;
channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#edd2a791 flags:# id:int participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int = ChatFull;
channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
chatFull#22a235da flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int = ChatFull;
channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
@@ -261,6 +260,7 @@ messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:str
messageMediaGame#fdb19008 game:Game = MessageMedia;
messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
@@ -284,6 +284,7 @@ messageActionCustomAction#fae69f56 message:string = MessageAction;
messageActionBotAllowed#abe9affe domain:string = MessageAction;
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
messageActionContactSignUp#f3f25f76 = MessageAction;
dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
@@ -293,6 +294,7 @@ photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_r
photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
@@ -316,12 +318,12 @@ peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bo
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper;
wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper;
wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
inputReportReasonSpam#58dbcab8 = ReportReason;
inputReportReasonViolence#1e22c78d = ReportReason;
inputReportReasonPornography#2e59d922 = ReportReason;
inputReportReasonChildAbuse#adf44ee3 = ReportReason;
inputReportReasonOther#e1746d0a text:string = ReportReason;
inputReportReasonCopyright#9b89f93a = ReportReason;
@@ -350,8 +352,8 @@ messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<
messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs;
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesNotModified#74535f21 count:int = messages.Messages;
messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats;
@@ -387,7 +389,6 @@ updateChatParticipants#7761198 participants:ChatParticipants = Update;
updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update;
updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update;
updateContactRegistered#2575bbb9 user_id:int date:int = Update;
updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update;
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
updateEncryptedChatTyping#1710f156 chat_id:int = Update;
@@ -411,7 +412,6 @@ updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update;
updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update;
updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update;
updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update;
@@ -446,7 +446,9 @@ updateContactsReset#7084a7be = Update;
updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update;
updateUserPinnedMessage#4c43da18 user_id:int id:int = Update;
updateChatPinnedMessage#22893b26 chat_id:int id:int = Update;
updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update;
updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update;
updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@@ -473,7 +475,7 @@ upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes
dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@@ -511,7 +513,7 @@ inputDocumentEmpty#72f0eaae = InputDocument;
inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument;
documentEmpty#36f8c871 id:long = Document;
document#59534e4c id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = Document;
document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;
help.support#17c6b5f6 phone_number:string user:User = help.Support;
@@ -540,11 +542,15 @@ inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey;
inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey;
inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey;
inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey;
inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey;
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
privacyKeyChatInvite#500e6dfa = PrivacyKey;
privacyKeyPhoneCall#3d662b7b = PrivacyKey;
privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
privacyKeyForwards#69ec56a3 = PrivacyKey;
privacyKeyProfilePhoto#96151fed = PrivacyKey;
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
@@ -616,7 +622,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
stickerSet#6a90bcb7 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
@@ -673,8 +679,8 @@ channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant;
channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant;
channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant;
channelParticipantAdmin#5daa6e23 flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights = ChannelParticipant;
channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter;
@@ -682,6 +688,7 @@ channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter;
channelParticipantsBots#b0d1865b = ChannelParticipantsFilter;
channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter;
channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter;
channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter;
channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants;
channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;
@@ -723,7 +730,7 @@ messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_off
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType;
@@ -916,11 +923,7 @@ langPackStringDeleted#2979eeb2 key:string = LangPackString;
langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector<LangPackString> = LangPackDifference;
langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage;
channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights;
channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights;
langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage;
channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction;
@@ -938,6 +941,8 @@ channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:Channel
channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction;
channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@@ -1057,6 +1062,17 @@ secureRequiredTypeOneOf#27477b4 types:Vector<SecureRequiredType> = SecureRequire
help.passportConfigNotModified#bfb9f457 = help.PassportConfig;
help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig;
inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent;
jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue;
jsonNull#3f6d7b68 = JSONValue;
jsonBool#c7345e6a value:Bool = JSONValue;
jsonNumber#2be0dfa4 value:double = JSONValue;
jsonString#b71e767a value:string = JSONValue;
jsonArray#f7444763 value:Vector<JSONValue> = JSONValue;
jsonObject#99c1d49d value:Vector<JSONObjectValue> = JSONValue;
pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell;
pageTableRow#e0c0c5e5 cells:Vector<PageTableCell> = PageTableRow;
@@ -1071,13 +1087,50 @@ pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector<PageBlock> = PageLis
pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle;
page#ae891bec flags:# part:flags.0?true rtl:flags.1?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page;
page#ae891bec flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page;
help.supportName#8c05f1c9 name:string = help.SupportName;
help.userInfoEmpty#f3ae2eed = help.UserInfo;
help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:string date:int = help.UserInfo;
pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer;
poll#d5529d06 id:long flags:# closed:flags.0?true question:string answers:Vector<PollAnswer> = Poll;
pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true option:bytes voters:int = PollAnswerVoters;
pollResults#5755785a flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int = PollResults;
chatOnlines#f041e250 onlines:int = ChatOnlines;
statsURL#47a971e0 url:string = StatsURL;
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights;
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
account.wallPapersNotModified#1c199183 = account.WallPapers;
account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings;
wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings;
autoDownloadSettings#d246fd47 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_max:int = AutoDownloadSettings;
account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings;
emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector<string> = EmojiKeyword;
emojiKeywordDeleted#236df622 keyword:string emoticons:Vector<string> = EmojiKeyword;
emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector<EmojiKeyword> = EmojiKeywordsDifference;
emojiURL#a575739d url:string = EmojiURL;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -1088,7 +1141,7 @@ invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode;
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
auth.logOut#5717da40 = Bool;
@@ -1111,7 +1164,7 @@ account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
account.resetNotifySettings#db7e1747 = Bool;
account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
account.updateStatus#6628562c offline:Bool = Bool;
account.getWallPapers#c04cfac2 = Vector<WallPaper>;
account.getWallPapers#aabb1763 hash:int = account.WallPapers;
account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool;
account.checkUsername#2714d86c username:string = Bool;
account.updateUsername#3e0bdd7c username:string = User;
@@ -1120,7 +1173,7 @@ account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> =
account.deleteAccount#418d4e0b reason:string = Bool;
account.getAccountTTL#8fc711d = AccountDaysTTL;
account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;
account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode;
account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User;
account.updateDeviceLocked#38df3532 period:int = Bool;
account.getAuthorizations#e320c158 = account.Authorizations;
@@ -1128,7 +1181,7 @@ account.resetAuthorization#df77f3bc hash:long = Bool;
account.getPassword#548a30f5 = account.Password;
account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings;
account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool;
account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode;
account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode;
account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword;
account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
@@ -1140,7 +1193,7 @@ account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long =
account.deleteSecureValue#b880bc4b types:Vector<SecureValueType> = Bool;
account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm;
account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector<SecureValueHash> credentials:SecureCredentialsEncrypted = Bool;
account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode;
account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool;
account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode;
account.verifyEmail#ecba39db email:string code:string = Bool;
@@ -1149,6 +1202,16 @@ account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool;
account.confirmPasswordEmail#8fdf1920 code:string = Bool;
account.resendPasswordEmail#7a7f2a15 = Bool;
account.cancelPasswordEmail#c1cbd5b6 = Bool;
account.getContactSignUpNotification#9f07c728 = Bool;
account.setContactSignUpNotification#cff43f61 silent:Bool = Bool;
account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates;
account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper;
account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool;
account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool;
account.resetWallPapers#bb3b9804 = Bool;
account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings;
account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
@@ -1160,11 +1223,10 @@ contacts.getContacts#c023849f hash:int = contacts.Contacts;
contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts;
contacts.deleteContact#8e953744 id:InputUser = contacts.Link;
contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool;
contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool;
contacts.block#332b49fc id:InputUser = Bool;
contacts.unblock#e54100bd id:InputUser = Bool;
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
contacts.exportCard#84e53737 = Vector<int>;
contacts.importCard#4fe196fe export_card:Vector<int> = User;
contacts.search#11f812d8 q:string limit:int = contacts.Found;
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers;
@@ -1178,7 +1240,7 @@ messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
@@ -1211,7 +1273,7 @@ messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages
messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers;
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite;
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
messages.importChatInvite#6c50051c hash:string = Updates;
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
@@ -1219,7 +1281,6 @@ messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = m
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates;
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
@@ -1230,10 +1291,10 @@ messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
messages.editMessage#c000e4c8 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Updates;
messages.editInlineBotMessage#adc3e828 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Bool;
messages.editMessage#d116f31e flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
@@ -1274,6 +1335,15 @@ messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogP
messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>;
messages.clearAllDrafts#7e58ee9c = Bool;
messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates;
messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector<bytes> = Updates;
messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates;
messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines;
messages.getStatsURL#812c2ae6 flags:# dark:flags.0?true peer:InputPeer params:string = StatsURL;
messages.editChatAbout#def60797 peer:InputPeer about:string = Bool;
messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates;
messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference;
messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference;
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@@ -1296,7 +1366,6 @@ upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector<Fil
help.getConfig#c4f9186b = Config;
help.getNearestDc#1fb33026 = NearestDc;
help.getAppUpdate#522d5a7d source:string = help.AppUpdate;
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
help.getInviteText#4d392343 = help.InviteText;
help.getSupport#9cdf08cd = help.Support;
help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
@@ -1307,6 +1376,8 @@ help.getProxyData#3d7758e1 = help.ProxyData;
help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
help.getAppConfig#98914110 = JSONValue;
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
help.getPassportConfig#c661ad08 hash:int = help.PassportConfig;
help.getSupportName#d360e72c = help.SupportName;
help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo;
@@ -1322,8 +1393,7 @@ channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channe
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates;
channels.editAbout#13e27f1e channel:InputChannel about:string = Bool;
channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates;
channels.editAdmin#70f893ba channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights = Updates;
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
@@ -1331,14 +1401,11 @@ channels.updateUsername#3514b3de channel:InputChannel username:string = Bool;
channels.joinChannel#24b524c5 channel:InputChannel = Updates;
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite;
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates;
channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates;
channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats;
channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates;
channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates;
channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
@@ -1367,13 +1434,13 @@ phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtoc
phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;
phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool;
phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates;
phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates;
phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
langpack.getDifference#9d51e814 lang_code:string from_version:int = LangPackDifference;
langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference;
langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>;
langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage;
// LAYER 89
// LAYER 97

View File

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

View File

@@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,5,2,0
PRODUCTVERSION 1,5,2,0
FILEVERSION 1,6,2,0
PRODUCTVERSION 1,6,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -52,10 +52,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "1.5.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
VALUE "FileVersion", "1.6.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2019"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.5.2.0"
VALUE "ProductVersion", "1.6.2.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,5,2,0
PRODUCTVERSION 1,5,2,0
FILEVERSION 1,6,2,0
PRODUCTVERSION 1,6,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -43,10 +43,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Desktop Updater"
VALUE "FileVersion", "1.5.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
VALUE "FileVersion", "1.6.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2019"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.5.2.0"
VALUE "ProductVersion", "1.6.2.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -7,9 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <windows.h>
#include <string>
#include <windows.h>
#ifdef small
#undef small
#endif // small
#pragma warning(push)
#pragma warning(disable:4091)
#include <DbgHelp.h>

View File

@@ -6,6 +6,7 @@ For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#import <Cocoa/Cocoa.h>
#include <sys/xattr.h>
NSString *appName = @"Telegram.app";
NSString *appDir = nil;
@@ -44,6 +45,20 @@ void writeLog(NSString *msg) {
[_logFile synchronizeFile];
}
void RemoveQuarantineAttribute(NSString *path) {
const char *kQuarantineAttribute = "com.apple.quarantine";
writeLog([@"Removing quarantine: " stringByAppendingString:path]);
removexattr([path fileSystemRepresentation], kQuarantineAttribute, 0);
}
void RemoveQuarantineFromBundle(NSString *path) {
RemoveQuarantineAttribute(path);
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/MacOS/Telegram"]);
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/Helpers/crashpad_handler"]);
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/Frameworks/Updater"]);
}
void delFolder() {
writeLog([@"Fully clearing old path: " stringByAppendingString:[workDir stringByAppendingString:@"tupdates/ready"]]);
if (![[NSFileManager defaultManager] removeItemAtPath:[workDir stringByAppendingString:@"tupdates/ready"] error:nil]) {
@@ -232,6 +247,9 @@ int main(int argc, const char * argv[]) {
}
NSString *appPath = [[NSArray arrayWithObjects:appDir, appRealName, nil] componentsJoinedByString:@""];
RemoveQuarantineFromBundle(appPath);
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects: @"-noupdate", nil];
if (toSettings) [args addObject:@"-tosettings"];
if (_debug) [args addObject:@"-debug"];
@@ -248,18 +266,24 @@ int main(int argc, const char * argv[]) {
[args addObject:workDir];
}
writeLog([[NSArray arrayWithObjects:@"Running application '", appPath, @"' with args '", [args componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]);
NSError *error = nil;
NSRunningApplication *result = [[NSWorkspace sharedWorkspace]
for (int i = 0; i < 5; ++i) {
NSError *error = nil;
NSRunningApplication *result = [[NSWorkspace sharedWorkspace]
launchApplicationAtURL:[NSURL fileURLWithPath:appPath]
options:NSWorkspaceLaunchDefault
configuration:[NSDictionary
dictionaryWithObject:args
forKey:NSWorkspaceLaunchConfigurationArguments]
error:&error];
if (!result) {
if (result) {
closeLog();
return 0;
}
writeLog([[NSString stringWithFormat:@"Could not run application, error %ld: ", (long)[error code]] stringByAppendingString: error ? [error localizedDescription] : @"(nil)"]);
usleep(200000);
}
closeLog();
return result ? 0 : -1;
return -1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h"
#include "base/flat_map.h"
#include "base/flat_set.h"
#include "core/single_timer.h"
#include "mtproto/sender.h"
#include "chat_helpers/stickers.h"
#include "data/data_messages.h"
@@ -24,6 +23,11 @@ enum class SendMediaType;
struct FileLoadTo;
class mtpFileLoader;
namespace Data {
struct UpdatedFileReferences;
class WallPaper;
} // namespace Data
namespace InlineBots {
class Result;
} // namespace InlineBots
@@ -43,14 +47,6 @@ struct CloudPasswordState;
namespace Api {
inline const MTPVector<MTPChat> *getChatsFromMessagesChats(const MTPmessages_Chats &chats) {
switch (chats.type()) {
case mtpc_messages_chats: return &chats.c_messages_chats().vchats;
case mtpc_messages_chatsSlice: return &chats.c_messages_chatsSlice().vchats;
}
return nullptr;
}
template <typename IntRange>
inline int32 CountHash(IntRange &&range) {
uint32 acc = 0;
@@ -62,7 +58,7 @@ inline int32 CountHash(IntRange &&range) {
} // namespace Api
class ApiWrap : private MTP::Sender, private base::Subscriber {
class ApiWrap : public MTP::Sender, private base::Subscriber {
public:
ApiWrap(not_null<AuthSession*> session);
@@ -87,16 +83,22 @@ public:
void requestDialogEntry(
not_null<History*> history,
Fn<void()> callback = nullptr);
void requestDialogEntries(std::vector<not_null<History*>> histories);
void dialogEntryApplied(not_null<History*> history);
//void applyFeedSources(const MTPDchannels_feedSources &data); // #feed
//void setFeedChannels(
// not_null<Data::Feed*> feed,
// const std::vector<not_null<ChannelData*>> &channels);
void changeDialogUnreadMark(not_null<History*> history, bool unread);
//void changeDialogUnreadMark(not_null<Data::Feed*> feed, bool unread); // #feed
void requestFakeChatListMessage(not_null<History*> history);
void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer);
void requestWallPaper(
const QString &slug,
Fn<void(const Data::WallPaper &)> done,
Fn<void(const RPCError &)> fail);
void requestFullPeer(not_null<PeerData*> peer);
void requestPeer(not_null<PeerData*> peer);
void requestPeers(const QList<PeerData*> &peers);
void requestLastParticipants(not_null<ChannelData*> channel);
void requestBots(not_null<ChannelData*> channel);
@@ -134,29 +136,43 @@ public:
void requestChannelMembersForAdd(
not_null<ChannelData*> channel,
Fn<void(const MTPchannels_ChannelParticipants&)> callback);
void processFullPeer(PeerData *peer, const MTPmessages_ChatFull &result);
void processFullPeer(UserData *user, const MTPUserFull &result);
void processFullPeer(
not_null<PeerData*> peer,
const MTPmessages_ChatFull &result);
void processFullPeer(
not_null<UserData*> user,
const MTPUserFull &result);
void migrateChat(
not_null<ChatData*> chat,
FnMut<void(not_null<ChannelData*>)> done,
FnMut<void(const RPCError &)> fail = nullptr);
void markMediaRead(const base::flat_set<not_null<HistoryItem*>> &items);
void markMediaRead(not_null<HistoryItem*> item);
void requestSelfParticipant(ChannelData *channel);
void requestSelfParticipant(not_null<ChannelData*> channel);
void kickParticipant(not_null<ChatData*> chat, not_null<UserData*> user);
void kickParticipant(
not_null<ChannelData*> channel,
not_null<UserData*> user,
const MTPChannelBannedRights &currentRights);
const MTPChatBannedRights &currentRights);
void unblockParticipant(
not_null<ChannelData*> channel,
not_null<UserData*> user);
void deleteAllFromUser(
not_null<ChannelData*> channel,
not_null<UserData*> from);
void saveDefaultRestrictions(
not_null<PeerData*> peer,
const MTPChatBannedRights &rights,
Fn<void(bool)> callback = nullptr);
void requestWebPageDelayed(WebPageData *page);
void clearWebPageRequest(WebPageData *page);
void clearWebPageRequests();
void requestAttachedStickerSets(not_null<PhotoData*> photo);
void scheduleStickerSetRequest(uint64 setId, uint64 access);
void requestStickerSets();
void saveStickerSets(
@@ -195,7 +211,12 @@ public:
const MTPUserStatus &status,
int currentOnlineTill);
void clearHistory(not_null<PeerData*> peer);
void clearHistory(not_null<PeerData*> peer, bool revoke);
void deleteConversation(not_null<PeerData*> peer, bool revoke);
void deleteMessages(
not_null<PeerData*> peer,
const QVector<MTPint> &ids,
bool revoke);
base::Observable<PeerData*> &fullPeerUpdated() {
return _fullPeerUpdated;
@@ -209,12 +230,9 @@ public:
void jumpToDate(Dialogs::Key chat, const QDate &date);
void preloadEnoughUnreadMentions(not_null<History*> history);
void checkForUnreadMentions(const base::flat_set<MsgId> &possiblyReadMentions, ChannelData *channel = nullptr);
void editChatAdmins(
not_null<ChatData*> chat,
bool adminsEnabled,
base::flat_set<not_null<UserData*>> &&admins);
void checkForUnreadMentions(
const base::flat_set<MsgId> &possiblyReadMentions,
ChannelData *channel = nullptr);
using SliceType = Data::LoadDirection;
void requestSharedMedia(
@@ -260,6 +278,9 @@ public:
int availableCount,
const QVector<MTPChannelParticipant> &list)> callbackList,
Fn<void()> callbackNotModified = nullptr);
void addChatParticipants(
not_null<PeerData*> peer,
const std::vector<not_null<UserData*>> &users);
struct SendOptions {
SendOptions(not_null<History*> history);
@@ -329,7 +350,7 @@ public:
bool handleSupportSwitch = false;
};
void sendMessage(MessageToSend &&message);
void sendBotStart(not_null<UserData*> bot);
void sendBotStart(not_null<UserData*> bot, PeerData *chat = nullptr);
void sendInlineResult(
not_null<UserData*> bot,
not_null<InlineBots::Result*> data,
@@ -350,6 +371,11 @@ public:
rpl::producer<Core::CloudPasswordState> passwordState() const;
std::optional<Core::CloudPasswordState> passwordStateCurrent() const;
void reloadContactSignupSilent();
rpl::producer<bool> contactSignupSilent() const;
std::optional<bool> contactSignupSilentCurrent() const;
void saveContactSignupSilent(bool silent);
void saveSelfBio(const QString &text, FnMut<void()> done);
struct Privacy {
@@ -358,6 +384,8 @@ public:
Calls,
Invites,
CallsPeer2Peer,
Forwards,
ProfilePhoto,
};
enum class Option {
Everyone,
@@ -377,6 +405,17 @@ public:
rpl::producer<int> selfDestructValue() const;
void saveSelfDestruct(int days);
void createPoll(
const PollData &data,
const SendOptions &options,
FnMut<void()> done,
FnMut<void(const RPCError &error)> fail);
void sendPollVotes(
FullMsgId itemId,
const std::vector<QByteArray> &options);
void closePoll(FullMsgId itemId);
void reloadPollResults(not_null<HistoryItem*> item);
~ApiWrap();
private:
@@ -391,13 +430,9 @@ private:
struct StickersByEmoji {
std::vector<not_null<DocumentData*>> list;
int32 hash = 0;
TimeMs received = 0;
crl::time received = 0;
};
using SimpleFileLocationId = Data::SimpleFileLocationId;
using DocumentFileLocationId = Data::DocumentFileLocationId;
using FileLocationId = Data::FileLocationId;
void updatesReceived(const MTPUpdates &updates);
void checkQuitPreventFinished();
@@ -412,13 +447,18 @@ private:
QVector<MTPInputMessage> collectMessageIds(const MessageDataRequests &requests);
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
void historyDialogEntryApplied(not_null<History*> history);
void applyFeedDialogs(
not_null<Data::Feed*> feed,
const MTPmessages_Dialogs &dialogs);
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req);
void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req);
void gotChatFull(
not_null<PeerData*> peer,
const MTPmessages_ChatFull &result,
mtpRequestId req);
void gotUserFull(
not_null<UserData*> user,
const MTPUserFull &result,
mtpRequestId req);
void applyLastParticipantsList(
not_null<ChannelData*> channel,
int availableCount,
@@ -462,9 +502,6 @@ private:
void requestSavedGifs(TimeId now);
void readFeaturedSets();
void cancelEditChatAdmins(not_null<ChatData*> chat);
void saveChatAdmins(not_null<ChatData*> chat);
void sendSaveChatAdminsRequests(not_null<ChatData*> chat);
void refreshChannelAdmins(
not_null<ChannelData*> channel,
const QVector<MTPChannelParticipant> &participants);
@@ -508,6 +545,10 @@ private:
UserId userId,
const SendOptions &options);
void deleteHistory(
not_null<PeerData*> peer,
bool justClear,
bool revoke);
void sendReadRequest(not_null<PeerData*> peer, MsgId upTo);
int applyAffectedHistory(
not_null<PeerData*> peer,
@@ -568,6 +609,13 @@ private:
void setSelfDestructDays(int days);
void migrateDone(
not_null<PeerData*> peer,
not_null<ChannelData*> channel);
void migrateFail(not_null<PeerData*> peer, const RPCError &error);
void sendDialogRequests();
not_null<AuthSession*> _session;
MessageDataRequests _messageDataRequests;
@@ -596,7 +644,11 @@ private:
not_null<UserData*>>;
base::flat_map<KickRequest, mtpRequestId> _kickRequests;
QMap<ChannelData*, mtpRequestId> _selfParticipantRequests;
base::flat_map<
not_null<PeerData*>,
mtpRequestId> _defaultRestrictionsRequests;
base::flat_set<not_null<ChannelData*>> _selfParticipantRequests;
base::flat_map<
not_null<ChannelData*>,
@@ -638,19 +690,13 @@ private:
base::flat_map<
not_null<History*>,
std::vector<Fn<void()>>> _dialogRequests;
base::flat_map<
not_null<History*>,
std::vector<Fn<void()>>> _dialogRequestsPending;
base::flat_set<not_null<History*>> _fakeChatListRequests;
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;
base::flat_map<
not_null<ChatData*>,
mtpRequestId> _chatAdminsEnabledRequests;
base::flat_map<
not_null<ChatData*>,
base::flat_set<not_null<UserData*>>> _chatAdminsToSave;
base::flat_map<
not_null<ChatData*>,
base::flat_set<mtpRequestId>> _chatAdminsSaveRequests;
base::flat_map<std::tuple<
not_null<PeerData*>,
SharedMediaType,
@@ -694,7 +740,7 @@ private:
rpl::event_stream<uint64> _stickerSetInstalled;
base::flat_map<not_null<Data::Feed*>, TimeMs> _feedReadsDelayed;
base::flat_map<not_null<Data::Feed*>, crl::time> _feedReadsDelayed;
base::flat_map<not_null<Data::Feed*>, mtpRequestId> _feedReadRequests;
base::Timer _feedReadTimer;
@@ -712,13 +758,21 @@ private:
mtpRequestId _deepLinkInfoRequestId = 0;
TimeMs _termsUpdateSendAt = 0;
crl::time _termsUpdateSendAt = 0;
mtpRequestId _termsUpdateRequestId = 0;
mtpRequestId _checkInviteRequestId = 0;
FnMut<void(const MTPChatInvite &result)> _checkInviteDone;
FnMut<void(const RPCError &error)> _checkInviteFail;
struct MigrateCallbacks {
FnMut<void(not_null<ChannelData*>)> done;
FnMut<void(const RPCError&)> fail;
};
base::flat_map<
not_null<PeerData*>,
std::vector<MigrateCallbacks>> _migrateCallbacks;
std::vector<FnMut<void(const MTPUser &)>> _supportContactCallbacks;
base::flat_map<FullMsgId, not_null<PeerData*>> _peerPhotoUploads;
@@ -739,4 +793,19 @@ private:
std::optional<int> _selfDestructDays;
rpl::event_stream<int> _selfDestructChanges;
base::flat_map<FullMsgId, mtpRequestId> _pollVotesRequestIds;
base::flat_map<FullMsgId, mtpRequestId> _pollCloseRequestIds;
base::flat_map<FullMsgId, mtpRequestId> _pollReloadRequestIds;
mtpRequestId _wallPaperRequestId = 0;
QString _wallPaperSlug;
Fn<void(const Data::WallPaper &)> _wallPaperDone;
Fn<void(const RPCError &)> _wallPaperFail;
mtpRequestId _contactSignupSilentRequestId = 0;
std::optional<bool> _contactSignupSilent;
rpl::event_stream<bool> _contactSignupSilentChanges;
mtpRequestId _attachedStickerSetsRequestId = 0;
};

File diff suppressed because it is too large Load Diff

View File

@@ -8,16 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "data/data_types.h"
#include "data/data_peer.h"
enum NewMessageType : char;
enum class ImageRoundRadius;
class Messenger;
class MainWindow;
class MainWidget;
class HistoryItem;
class History;
class Histories;
namespace HistoryView {
class Element;
} // namespace HistoryView
@@ -38,6 +35,8 @@ enum RoundCorners {
SelectedOverlayLargeCorners,
DateCorners,
DateSelectedCorners,
OverviewVideoCorners,
OverviewVideoSelectedCorners,
ForwardCorners,
MediaviewSaveCorners,
EmojiHoverCorners,
@@ -67,16 +66,6 @@ namespace App {
QString formatPhone(QString phone);
UserData *feedUser(const MTPUser &user);
UserData *feedUsers(const MTPVector<MTPUser> &users); // returns last user
PeerData *feedChat(const MTPChat &chat);
PeerData *feedChats(const MTPVector<MTPChat> &chats); // returns last chat
void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos);
void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d);
void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d);
void feedChatAdmins(const MTPDupdateChatAdmins &d);
void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d);
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached
void updateEditedMessage(const MTPMessage &m);
void addSavedGif(DocumentData *doc);
@@ -90,68 +79,13 @@ namespace App {
ImagePtr image(const MTPPhotoSize &size);
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded);
inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asUser(peer(id, restriction));
}
inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChat(peer(id, restriction));
}
inline ChannelData *channel(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChannel(peer(id, restriction));
}
inline UserData *user(UserId userId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asUser(peer(peerFromUser(userId), restriction));
}
inline ChatData *chat(ChatId chatId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChat(peer(peerFromChat(chatId), restriction));
}
inline ChannelData *channel(ChannelId channelId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChannel(peer(peerFromChannel(channelId), restriction));
}
inline PeerData *peerLoaded(const PeerId &id) {
return peer(id, PeerData::FullLoaded);
}
inline UserData *userLoaded(const PeerId &id) {
return user(id, PeerData::FullLoaded);
}
inline ChatData *chatLoaded(const PeerId &id) {
return chat(id, PeerData::FullLoaded);
}
inline ChannelData *channelLoaded(const PeerId &id) {
return channel(id, PeerData::FullLoaded);
}
inline UserData *userLoaded(UserId userId) {
return user(userId, PeerData::FullLoaded);
}
inline ChatData *chatLoaded(ChatId chatId) {
return chat(chatId, PeerData::FullLoaded);
}
inline ChannelData *channelLoaded(ChannelId channelId) {
return channel(channelId, PeerData::FullLoaded);
}
void enumerateUsers(Fn<void(not_null<UserData*>)> action);
void enumerateGroups(Fn<void(not_null<PeerData*>)> action);
void enumerateChannels(Fn<void(not_null<ChannelData*>)> action);
[[nodiscard]] QString peerName(const PeerData *peer, bool forDialogs = false);
PeerData *peerByName(const QString &username);
QString peerName(const PeerData *peer, bool forDialogs = false);
Histories &histories();
not_null<History*> history(const PeerId &peer);
History *historyLoaded(const PeerId &peer);
HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
inline not_null<History*> history(const PeerData *peer) {
Assert(peer != nullptr);
return history(peer->id);
}
inline History *historyLoaded(const PeerData *peer) {
return peer ? historyLoaded(peer->id) : nullptr;
}
inline HistoryItem *histItemById(const ChannelData *channel, MsgId itemId) {
return histItemById(channel ? peerToChannel(channel->id) : 0, itemId);
}
inline HistoryItem *histItemById(const FullMsgId &msgId) {
[[nodiscard]] HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
[[nodiscard]] HistoryItem *histItemById(
const ChannelData *channel,
MsgId itemId);
[[nodiscard]] inline HistoryItem *histItemById(const FullMsgId &msgId) {
return histItemById(msgId.channel, msgId.msg);
}
void historyRegItem(not_null<HistoryItem*> item);
@@ -183,8 +117,6 @@ namespace App {
const style::font &monofont();
void clearHistories();
void initMedia();
void deinitMedia();
@@ -222,14 +154,4 @@ namespace App {
return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts);
}
struct WallPaper {
WallPaper(int32 id, ImagePtr thumb, ImagePtr full) : id(id), thumb(thumb), full(full) {
}
int32 id;
ImagePtr thumb;
ImagePtr full;
};
typedef QList<WallPaper> WallPapers;
DeclareSetting(WallPapers, ServerBackgrounds);
};

View File

@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "auth_session.h"
#include "apiwrap.h"
#include "messenger.h"
#include "core/application.h"
#include "core/changelogs.h"
#include "storage/file_download.h"
#include "storage/file_upload.h"
@@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/storage_facade.h"
#include "storage/serialize_common.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "window/notifications_manager.h"
#include "window/themes/window_theme.h"
#include "platform/platform_specific.h"
@@ -30,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kAutoLockTimeoutLateMs = TimeMs(3000);
constexpr auto kAutoLockTimeoutLateMs = crl::time(3000);
constexpr auto kLegacyCallsPeerToPeerNobody = 4;
} // namespace
@@ -45,11 +46,13 @@ AuthSessionSettings::Variables::Variables()
}
QByteArray AuthSessionSettings::serialize() const {
const auto autoDownload = _variables.autoDownload.serialize();
auto size = sizeof(qint32) * 23;
for (auto i = _variables.soundOverrides.cbegin(), e = _variables.soundOverrides.cend(); i != e; ++i) {
size += Serialize::stringSize(i.key()) + Serialize::stringSize(i.value());
}
size += _variables.groupStickersSectionHidden.size() * sizeof(quint64);
size += Serialize::bytearraySize(autoDownload);
auto result = QByteArray();
result.reserve(size);
@@ -88,6 +91,8 @@ QByteArray AuthSessionSettings::serialize() const {
stream << qint32(_variables.includeMutedCounter ? 1 : 0);
stream << qint32(_variables.countUnreadMessages ? 1 : 0);
stream << qint32(_variables.exeLaunchWarning ? 1 : 0);
stream << autoDownload;
stream << qint32(_variables.supportAllSearchResults.current() ? 1 : 0);
}
return result;
}
@@ -122,6 +127,8 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
qint32 includeMutedCounter = _variables.includeMutedCounter ? 1 : 0;
qint32 countUnreadMessages = _variables.countUnreadMessages ? 1 : 0;
qint32 exeLaunchWarning = _variables.exeLaunchWarning ? 1 : 0;
QByteArray autoDownload;
qint32 supportAllSearchResults = _variables.supportAllSearchResults.current() ? 1 : 0;
stream >> selectorTab;
stream >> lastSeenWarningSeen;
@@ -195,11 +202,21 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
if (!stream.atEnd()) {
stream >> exeLaunchWarning;
}
if (!stream.atEnd()) {
stream >> autoDownload;
}
if (!stream.atEnd()) {
stream >> supportAllSearchResults;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for AuthSessionSettings::constructFromSerialized()"));
return;
}
if (!autoDownload.isEmpty()
&& !_variables.autoDownload.setFromSerialized(autoDownload)) {
return;
}
auto uncheckedTab = static_cast<ChatHelpers::SelectorTab>(selectorTab);
switch (uncheckedTab) {
@@ -259,6 +276,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
_variables.includeMutedCounter = (includeMutedCounter == 1);
_variables.countUnreadMessages = (countUnreadMessages == 1);
_variables.exeLaunchWarning = (exeLaunchWarning == 1);
_variables.supportAllSearchResults = (supportAllSearchResults == 1);
}
void AuthSessionSettings::setSupportChatsTimeSlice(int slice) {
@@ -273,6 +291,18 @@ rpl::producer<int> AuthSessionSettings::supportChatsTimeSliceValue() const {
return _variables.supportChatsTimeSlice.value();
}
void AuthSessionSettings::setSupportAllSearchResults(bool all) {
_variables.supportAllSearchResults = all;
}
bool AuthSessionSettings::supportAllSearchResults() const {
return _variables.supportAllSearchResults.current();
}
rpl::producer<bool> AuthSessionSettings::supportAllSearchResultsValue() const {
return _variables.supportAllSearchResults.value();
}
void AuthSessionSettings::setTabbedSelectorSectionEnabled(bool enabled) {
_variables.tabbedSelectorSectionEnabled = enabled;
if (enabled) {
@@ -342,14 +372,13 @@ rpl::producer<int> AuthSessionSettings::thirdColumnWidthChanges() const {
}
AuthSession &Auth() {
auto result = Messenger::Instance().authSession();
auto result = Core::App().authSession();
Assert(result != nullptr);
return *result;
}
AuthSession::AuthSession(const MTPUser &user)
: _user(App::user(user.match([](const auto &data) { return data.vid.v; })))
, _autoLockTimer([this] { checkAutoLock(); })
: _autoLockTimer([this] { checkAutoLock(); })
, _api(std::make_unique<ApiWrap>(this))
, _calls(std::make_unique<Calls::Instance>())
, _downloader(std::make_unique<Storage::Downloader>())
@@ -357,21 +386,17 @@ AuthSession::AuthSession(const MTPUser &user)
, _storage(std::make_unique<Storage::Facade>())
, _notifications(std::make_unique<Window::Notifications::System>(this))
, _data(std::make_unique<Data::Session>(this))
, _user(_data->processUser(user))
, _changelogs(Core::Changelogs::Create(this))
, _supportHelper(
(Support::ValidateAccount(user)
? std::make_unique<Support::Helper>(this)
: nullptr)) {
App::feedUser(user);
, _supportHelper(Support::Helper::Create(this)) {
_saveDataTimer.setCallback([=] {
Local::writeUserSettings();
});
Messenger::Instance().passcodeLockChanges(
Core::App().passcodeLockChanges(
) | rpl::start_with_next([=] {
_shouldLockAt = 0;
}, _lifetime);
Messenger::Instance().lockChanges(
Core::App().lockChanges(
) | rpl::start_with_next([=] {
notifications().updateAll();
}, _lifetime);
@@ -404,23 +429,28 @@ AuthSession::AuthSession(const MTPUser &user)
}
bool AuthSession::Exists() {
if (const auto messenger = Messenger::InstancePointer()) {
return (messenger->authSession() != nullptr);
}
return false;
return Core::IsAppLaunched() && (Core::App().authSession() != nullptr);
}
base::Observable<void> &AuthSession::downloaderTaskFinished() {
return downloader().taskFinished();
}
UserId AuthSession::userId() const {
return _user->bareId();
}
PeerId AuthSession::userPeerId() const {
return _user->id;
}
bool AuthSession::validateSelf(const MTPUser &user) {
if (user.type() != mtpc_user || !user.c_user().is_self()) {
LOG(("API Error: bad self user received."));
return false;
} else if (user.c_user().vid.v != userId()) {
LOG(("Auth Error: wrong self user received."));
crl::on_main(this, [] { Messenger::Instance().logOut(); });
crl::on_main(this, [] { Core::App().logOut(); });
return false;
}
return true;
@@ -438,33 +468,41 @@ void AuthSession::moveSettingsFrom(AuthSessionSettings &&other) {
}
}
void AuthSession::saveSettingsDelayed(TimeMs delay) {
void AuthSession::saveSettingsDelayed(crl::time delay) {
Expects(this == &Auth());
_saveDataTimer.callOnce(delay);
}
void AuthSession::localPasscodeChanged() {
_shouldLockAt = 0;
_autoLockTimer.cancel();
checkAutoLock();
}
void AuthSession::checkAutoLock() {
if (!Global::LocalPasscode()
|| Messenger::Instance().passcodeLocked()) {
|| Core::App().passcodeLocked()) {
_shouldLockAt = 0;
_autoLockTimer.cancel();
return;
}
Messenger::Instance().checkLocalTime();
auto now = getms(true);
auto shouldLockInMs = Global::AutoLock() * 1000LL;
auto idleForMs = psIdleTime();
auto notPlayingVideoForMs = now - settings().lastTimeVideoPlayedAt();
auto checkTimeMs = qMin(idleForMs, notPlayingVideoForMs);
Core::App().checkLocalTime();
const auto now = crl::now();
const auto shouldLockInMs = Global::AutoLock() * 1000LL;
const auto checkTimeMs = now - Core::App().lastNonIdleTime();
if (checkTimeMs >= shouldLockInMs || (_shouldLockAt > 0 && now > _shouldLockAt + kAutoLockTimeoutLateMs)) {
Messenger::Instance().lockByPasscode();
_shouldLockAt = 0;
_autoLockTimer.cancel();
Core::App().lockByPasscode();
} else {
_shouldLockAt = now + (shouldLockInMs - checkTimeMs);
_autoLockTimer.callOnce(shouldLockInMs - checkTimeMs);
}
}
void AuthSession::checkAutoLockIn(TimeMs time) {
void AuthSession::checkAutoLockIn(crl::time time) {
if (_autoLockTimer.isActive()) {
auto remain = _autoLockTimer.remainingTime();
if (remain > 0 && remain <= time) return;
@@ -486,4 +524,7 @@ Support::Templates& AuthSession::supportTemplates() const {
return supportHelper().templates();
}
AuthSession::~AuthSession() = default;
AuthSession::~AuthSession() {
ClickHandler::clearActive();
ClickHandler::unpressed();
}

View File

@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/filter.h>
#include <rpl/variable.h>
#include "base/timer.h"
#include "data/data_auto_download.h"
class ApiWrap;
enum class SendFilesWay;
@@ -102,6 +103,9 @@ public:
void setSupportChatsTimeSlice(int slice);
int supportChatsTimeSlice() const;
rpl::producer<int> supportChatsTimeSliceValue() const;
void setSupportAllSearchResults(bool all);
bool supportAllSearchResults() const;
rpl::producer<bool> supportAllSearchResultsValue() const;
ChatHelpers::SelectorTab selectorTab() const {
return _variables.selectorTab;
@@ -135,12 +139,6 @@ public:
bool smallDialogsList() const {
return _variables.smallDialogsList;
}
void setLastTimeVideoPlayedAt(TimeMs time) {
_lastTimeVideoPlayedAt = time;
}
TimeMs lastTimeVideoPlayedAt() const {
return _lastTimeVideoPlayedAt;
}
void setSoundOverride(const QString &key, const QString &path) {
_variables.soundOverrides.insert(key, path);
}
@@ -183,6 +181,13 @@ public:
_variables.groupStickersSectionHidden.remove(peerId);
}
Data::AutoDownload::Full &autoDownload() {
return _variables.autoDownload;
}
const Data::AutoDownload::Full &autoDownload() const {
return _variables.autoDownload;
}
bool hadLegacyCallsPeerToPeerNobody() const {
return _variables.hadLegacyCallsPeerToPeerNobody;
}
@@ -234,6 +239,7 @@ private:
bool includeMutedCounter = true;
bool countUnreadMessages = true;
bool exeLaunchWarning = true;
Data::AutoDownload::Full autoDownload;
static constexpr auto kDefaultSupportChatsLimitSlice
= 7 * 24 * 60 * 60;
@@ -243,6 +249,7 @@ private:
bool supportTemplatesAutocomplete = true;
rpl::variable<int> supportChatsTimeSlice
= kDefaultSupportChatsLimitSlice;
rpl::variable<bool> supportAllSearchResults = false;
};
rpl::event_stream<bool> _thirdSectionInfoEnabledValue;
@@ -250,11 +257,9 @@ private:
rpl::event_stream<bool> _tabbedReplacedWithInfoValue;
Variables _variables;
TimeMs _lastTimeVideoPlayedAt = 0;
};
// One per Messenger.
class AuthSession;
AuthSession &Auth();
@@ -269,12 +274,8 @@ public:
static bool Exists();
UserId userId() const {
return _user->bareId();
}
PeerId userPeerId() const {
return _user->id;
}
UserId userId() const;
PeerId userPeerId() const;
not_null<UserData*> user() const {
return _user;
}
@@ -303,7 +304,7 @@ public:
return _settings;
}
void moveSettingsFrom(AuthSessionSettings &&other);
void saveSettingsDelayed(TimeMs delay = kDefaultSaveDelay);
void saveSettingsDelayed(crl::time delay = kDefaultSaveDelay);
ApiWrap &api() {
return *_api;
@@ -314,7 +315,8 @@ public:
}
void checkAutoLock();
void checkAutoLockIn(TimeMs time);
void checkAutoLockIn(crl::time time);
void localPasscodeChanged();
rpl::lifetime &lifetime() {
return _lifetime;
@@ -330,13 +332,12 @@ public:
~AuthSession();
private:
static constexpr auto kDefaultSaveDelay = TimeMs(1000);
static constexpr auto kDefaultSaveDelay = crl::time(1000);
const not_null<UserData*> _user;
AuthSessionSettings _settings;
base::Timer _saveDataTimer;
TimeMs _shouldLockAt = 0;
crl::time _shouldLockAt = 0;
base::Timer _autoLockTimer;
const std::unique_ptr<ApiWrap> _api;
@@ -346,8 +347,9 @@ private:
const std::unique_ptr<Storage::Facade> _storage;
const std::unique_ptr<Window::Notifications::System> _notifications;
// _data depends on _downloader / _uploader, including destructor.
// _data depends on _downloader / _uploader / _notifications.
const std::unique_ptr<Data::Session> _data;
const not_null<UserData*> _user;
// _changelogs depends on _data, subscribes on chats loading event.
const std::unique_ptr<Core::Changelogs> _changelogs;

View File

@@ -24,6 +24,12 @@ inline constexpr size_t array_size(const Type(&)[Size]) {
return Size;
}
template <typename Container, typename T>
inline bool contains(const Container &container, const T &value) {
const auto end = std::end(container);
return std::find(std::begin(container), end, value) != end;
}
} // namespace base
template <typename T>

View File

@@ -19,7 +19,10 @@ void log(const char *message, const char *file, int line);
inline constexpr void noop() {
}
[[noreturn]] inline void fail(const char *message, const char *file, int line) {
[[noreturn]] inline void fail(
const char *message,
const char *file,
int line) {
log(message, file, line);
// Crash with access violation and generate crash report.
@@ -30,24 +33,36 @@ inline constexpr void noop() {
std::abort();
}
#ifndef GSL_UNLIKELY
#define DEFINED_GSL_UNLIKELY_
#define GSL_UNLIKELY(expression) (expression)
#endif // GSL_UNLIKELY
inline constexpr void validate(bool condition, const char *message, const char *file, int line) {
(GSL_UNLIKELY(!(condition))) ? fail(message, file, line) : noop();
constexpr const char* extract_basename(const char* path, size_t size) {
while (size != 0 && path[size - 1] != '/' && path[size - 1] != '\\') {
--size;
}
return path + size;
}
#ifdef DEFINED_GSL_UNLIKELY_
#undef GSL_UNLIKELY
#undef DEFINED_GSL_UNLIKELY_
#endif // DEFINED_GSL_UNLIKELY_
} // namespace assertion
} // namespace base
#define AssertCustom(condition, message) (::base::assertion::validate(condition, message, __FILE__, __LINE__))
#if defined(__clang__) || defined(__GNUC__)
#define AssertUnlikelyHelper(x) __builtin_expect(!!(x), 0)
#else
#define AssertUnlikelyHelper(x) (!!(x))
#endif
#define AssertValidationCondition(condition, message, file, line)\
((AssertUnlikelyHelper(!(condition)))\
? ::base::assertion::fail(message, file, line)\
: ::base::assertion::noop())
#define SOURCE_FILE_BASENAME (::base::assertion::extract_basename(\
__FILE__,\
sizeof(__FILE__)))
#define AssertCustom(condition, message) (AssertValidationCondition(\
condition,\
message,\
SOURCE_FILE_BASENAME,\
__LINE__))
#define Assert(condition) AssertCustom(condition, "\"" #condition "\"")
// Define our own versions of Expects() and Ensures().
@@ -55,17 +70,28 @@ inline constexpr void validate(bool condition, const char *message, const char *
#ifdef Expects
#undef Expects
#endif // Expects
#define Expects(condition) (::base::assertion::validate(condition, "\"" #condition "\"", __FILE__, __LINE__))
#define Expects(condition) (AssertValidationCondition(\
condition,\
"\"" #condition "\"",\
SOURCE_FILE_BASENAME,\
__LINE__))
#ifdef Ensures
#undef Ensures
#endif // Ensures
#define Ensures(condition) (::base::assertion::validate(condition, "\"" #condition "\"", __FILE__, __LINE__))
#define Ensures(condition) (AssertValidationCondition(\
condition,\
"\"" #condition "\"",\
SOURCE_FILE_BASENAME,\
__LINE__))
#ifdef Unexpected
#undef Unexpected
#endif // Unexpected
#define Unexpected(message) (::base::assertion::fail("Unexpected: " message, __FILE__, __LINE__))
#define Unexpected(message) (::base::assertion::fail(\
"Unexpected: " message,\
SOURCE_FILE_BASENAME,\
__LINE__))
#ifdef _DEBUG
#define AssertIsDebug(...)

View File

@@ -46,7 +46,6 @@ using uint64 = quint64;
using float32 = float;
using float64 = double;
using TimeMs = int64;
using TimeId = int32;
// Define specializations for QByteArray for Qt 5.3.2, because

View File

@@ -21,7 +21,9 @@ public:
~binary_guard();
bool alive() const;
void kill();
binary_guard &operator=(std::nullptr_t);
explicit operator bool() const;
private:
void destroy();
@@ -44,15 +46,20 @@ inline binary_guard &binary_guard::operator=(binary_guard &&other) {
return *this;
}
inline binary_guard::~binary_guard() {
inline binary_guard &binary_guard::operator=(std::nullptr_t) {
destroy();
return *this;
}
inline binary_guard::operator bool() const {
return alive();
}
inline bool binary_guard::alive() const {
return _bothAlive && _bothAlive->load();
}
inline void binary_guard::kill() {
inline binary_guard::~binary_guard() {
destroy();
}
@@ -74,3 +81,21 @@ inline std::pair<binary_guard, binary_guard> make_binary_guard() {
}
} // namespace base
namespace crl {
template <typename T, typename Enable>
struct guard_traits;
template <>
struct guard_traits<base::binary_guard, void> {
static base::binary_guard create(base::binary_guard value) {
return value;
}
static bool check(const base::binary_guard &guard) {
return guard.alive();
}
};
} // namespace crl

View File

@@ -26,16 +26,16 @@ QMutex EnvironmentMutex;
class CallDelayedEvent : public QEvent {
public:
CallDelayedEvent(
crl::time_type timeout,
crl::time timeout,
Qt::TimerType type,
FnMut<void()> method);
crl::time_type timeout() const;
crl::time timeout() const;
Qt::TimerType type() const;
FnMut<void()> takeMethod();
private:
crl::time_type _timeout = 0;
crl::time _timeout = 0;
Qt::TimerType _type = Qt::PreciseTimer;
FnMut<void()> _method;
@@ -48,7 +48,7 @@ public:
};
CallDelayedEvent::CallDelayedEvent(
crl::time_type timeout,
crl::time timeout,
Qt::TimerType type,
FnMut<void()> method)
: QEvent(kCallDelayedEvent)
@@ -58,7 +58,7 @@ CallDelayedEvent::CallDelayedEvent(
Expects(_timeout >= 0 && _timeout < std::numeric_limits<int>::max());
}
crl::time_type CallDelayedEvent::timeout() const {
crl::time CallDelayedEvent::timeout() const {
return _timeout;
}
@@ -178,7 +178,7 @@ TimerObjectWrap::~TimerObjectWrap() {
}
void TimerObjectWrap::call(
crl::time_type timeout,
crl::time timeout,
Qt::TimerType type,
FnMut<void()> method) {
sendEvent(std::make_unique<CallDelayedEvent>(
@@ -281,7 +281,7 @@ Fn<void()> ConcurrentTimer::createAdjuster() {
}
void ConcurrentTimer::start(
TimeMs timeout,
crl::time timeout,
Qt::TimerType type,
Repeat repeat) {
_type = type;
@@ -290,7 +290,7 @@ void ConcurrentTimer::start(
setTimeout(timeout);
cancelAndSchedule(_timeout);
_next = crl::time() + _timeout;
_next = crl::now() + _timeout;
}
void ConcurrentTimer::cancelAndSchedule(int timeout) {
@@ -301,11 +301,11 @@ void ConcurrentTimer::cancelAndSchedule(int timeout) {
runner = _runner,
guard = std::move(guards.second)
]() mutable {
if (!guard.alive()) {
if (!guard) {
return;
}
runner([=, guard = std::move(guard)] {
if (!guard.alive()) {
if (!guard) {
return;
}
timerEvent();
@@ -319,7 +319,7 @@ void ConcurrentTimer::timerEvent() {
if (_adjusted) {
start(_timeout, _type, repeat());
} else {
_next = crl::time() + _timeout;
_next = crl::now() + _timeout;
}
} else {
cancel();
@@ -338,12 +338,12 @@ void ConcurrentTimer::cancel() {
}
}
TimeMs ConcurrentTimer::remainingTime() const {
crl::time ConcurrentTimer::remainingTime() const {
if (!isActive()) {
return -1;
}
const auto now = crl::time();
return (_next > now) ? (_next - now) : TimeMs(0);
const auto now = crl::now();
return (_next > now) ? (_next - now) : crl::time(0);
}
void ConcurrentTimer::adjust() {
@@ -354,7 +354,7 @@ void ConcurrentTimer::adjust() {
}
}
void ConcurrentTimer::setTimeout(TimeMs timeout) {
void ConcurrentTimer::setTimeout(crl::time timeout) {
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
_timeout = static_cast<unsigned int>(timeout);

View File

@@ -23,7 +23,7 @@ public:
~TimerObjectWrap();
void call(
crl::time_type timeout,
crl::time timeout,
Qt::TimerType type,
FnMut<void()> method);
void cancel();
@@ -67,8 +67,8 @@ public:
crl::weak_on_queue<Object> weak,
Fn<void()> callback = nullptr);
static Qt::TimerType DefaultType(TimeMs timeout) {
constexpr auto kThreshold = TimeMs(1000);
static Qt::TimerType DefaultType(crl::time timeout) {
constexpr auto kThreshold = crl::time(1000);
return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer;
}
@@ -76,19 +76,19 @@ public:
_callback = std::move(callback);
}
void callOnce(TimeMs timeout) {
void callOnce(crl::time timeout) {
callOnce(timeout, DefaultType(timeout));
}
void callEach(TimeMs timeout) {
void callEach(crl::time timeout) {
callEach(timeout, DefaultType(timeout));
}
void callOnce(TimeMs timeout, Qt::TimerType type) {
void callOnce(crl::time timeout, Qt::TimerType type) {
start(timeout, type, Repeat::SingleShot);
}
void callEach(TimeMs timeout, Qt::TimerType type) {
void callEach(crl::time timeout, Qt::TimerType type) {
start(timeout, type, Repeat::Interval);
}
@@ -97,7 +97,7 @@ public:
}
void cancel();
TimeMs remainingTime() const;
crl::time remainingTime() const;
private:
enum class Repeat : unsigned {
@@ -105,12 +105,12 @@ private:
SingleShot = 1,
};
Fn<void()> createAdjuster();
void start(TimeMs timeout, Qt::TimerType type, Repeat repeat);
void start(crl::time timeout, Qt::TimerType type, Repeat repeat);
void adjust();
void cancelAndSchedule(int timeout);
void setTimeout(TimeMs timeout);
void setTimeout(crl::time timeout);
int timeout() const;
void timerEvent();
@@ -127,7 +127,7 @@ private:
details::TimerObjectWrap _object;
Fn<void()> _callback;
base::binary_guard _running;
TimeMs _next = 0;
crl::time _next = 0;
int _timeout = 0;
Qt::TimerType _type : 2;

View File

@@ -602,36 +602,38 @@ public:
using parent::contains;
using parent::erase;
iterator insert(const Type &value) {
std::pair<iterator, bool> insert(const Type &value) {
if (this->empty() || this->compare()(value, this->front())) {
this->impl().push_front(value);
return this->begin();
return std::make_pair(this->begin(), true);
} else if (this->compare()(this->back(), value)) {
this->impl().push_back(value);
return (this->end() - 1);
return std::make_pair(this->end() - 1, true);
}
auto where = this->getLowerBound(value);
if (this->compare()(value, *where)) {
return this->impl().insert(where, value);
return std::make_pair(this->impl().insert(where, value), true);
}
return this->end();
return std::make_pair(where, false);
}
iterator insert(Type &&value) {
std::pair<iterator, bool> insert(Type &&value) {
if (this->empty() || this->compare()(value, this->front())) {
this->impl().push_front(std::move(value));
return this->begin();
return std::make_pair(this->begin(), true);
} else if (this->compare()(this->back(), value)) {
this->impl().push_back(std::move(value));
return (this->end() - 1);
return std::make_pair(this->end() - 1, true);
}
auto where = this->getLowerBound(value);
if (this->compare()(value, *where)) {
return this->impl().insert(where, std::move(value));
return std::make_pair(
this->impl().insert(where, std::move(value)),
true);
}
return this->end();
return std::make_pair(where, false);
}
template <typename... Args>
iterator emplace(Args&&... args) {
std::pair<iterator, bool> emplace(Args&&... args) {
return this->insert(Type(std::forward<Args>(args)...));
}

View File

@@ -18,12 +18,20 @@ public:
using value_type = typename Container::value_type;
using difference_type = typename Container::difference_type;
using pointer = typename Container::pointer;
using reference = typename Container::reference;
using pointer = std::conditional_t<
std::is_const_v<Container>,
typename Container::const_pointer,
typename Container::pointer>;
using reference = std::conditional_t<
std::is_const_v<Container>,
typename Container::const_reference,
typename Container::reference>;
using base_type = std::conditional_t<
std::is_const_v<Container>,
typename Container::const_iterator,
typename Container::iterator>;
index_based_iterator(
Container *container,
typename Container::iterator impl)
index_based_iterator(Container *container, base_type impl)
: _container(container)
, _index(impl - _container->begin()) {
}
@@ -99,7 +107,7 @@ public:
return !(*this < other);
}
typename Container::iterator base() const {
base_type base() const {
return _container->begin() + _index;
}

View File

@@ -21,6 +21,10 @@ extern "C" {
#include <openssl/evp.h>
} // extern "C"
#ifdef small
#undef small
#endif // small
namespace openssl {
class Context {

View File

@@ -40,7 +40,7 @@ Timer::Timer(Fn<void()> callback)
Qt::QueuedConnection);
}
void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
void Timer::start(crl::time timeout, Qt::TimerType type, Repeat repeat) {
cancel();
_type = type;
@@ -49,7 +49,7 @@ void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
setTimeout(timeout);
_timerId = startTimer(_timeout, _type);
if (_timerId) {
_next = crl::time() + _timeout;
_next = crl::now() + _timeout;
} else {
_next = 0;
}
@@ -61,12 +61,12 @@ void Timer::cancel() {
}
}
TimeMs Timer::remainingTime() const {
crl::time Timer::remainingTime() const {
if (!isActive()) {
return -1;
}
auto now = crl::time();
return (_next > now) ? (_next - now) : TimeMs(0);
const auto now = crl::now();
return (_next > now) ? (_next - now) : crl::time(0);
}
void Timer::Adjust() {
@@ -87,7 +87,7 @@ void Timer::adjust() {
}
}
void Timer::setTimeout(TimeMs timeout) {
void Timer::setTimeout(crl::time timeout) {
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
_timeout = static_cast<unsigned int>(timeout);
@@ -102,7 +102,7 @@ void Timer::timerEvent(QTimerEvent *e) {
if (_adjusted) {
start(_timeout, _type, repeat());
} else {
_next = crl::time() + _timeout;
_next = crl::now() + _timeout;
}
} else {
cancel();
@@ -114,7 +114,7 @@ void Timer::timerEvent(QTimerEvent *e) {
}
int DelayedCallTimer::call(
TimeMs timeout,
crl::time timeout,
FnMut<void()> callback,
Qt::TimerType type) {
Expects(timeout >= 0);

View File

@@ -21,8 +21,8 @@ public:
Fn<void()> callback = nullptr);
explicit Timer(Fn<void()> callback = nullptr);
static Qt::TimerType DefaultType(TimeMs timeout) {
constexpr auto kThreshold = TimeMs(1000);
static Qt::TimerType DefaultType(crl::time timeout) {
constexpr auto kThreshold = crl::time(1000);
return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer;
}
@@ -30,19 +30,19 @@ public:
_callback = std::move(callback);
}
void callOnce(TimeMs timeout) {
void callOnce(crl::time timeout) {
callOnce(timeout, DefaultType(timeout));
}
void callEach(TimeMs timeout) {
void callEach(crl::time timeout) {
callEach(timeout, DefaultType(timeout));
}
void callOnce(TimeMs timeout, Qt::TimerType type) {
void callOnce(crl::time timeout, Qt::TimerType type) {
start(timeout, type, Repeat::SingleShot);
}
void callEach(TimeMs timeout, Qt::TimerType type) {
void callEach(crl::time timeout, Qt::TimerType type) {
start(timeout, type, Repeat::Interval);
}
@@ -51,7 +51,7 @@ public:
}
void cancel();
TimeMs remainingTime() const;
crl::time remainingTime() const;
static void Adjust();
@@ -63,10 +63,10 @@ private:
Interval = 0,
SingleShot = 1,
};
void start(TimeMs timeout, Qt::TimerType type, Repeat repeat);
void start(crl::time timeout, Qt::TimerType type, Repeat repeat);
void adjust();
void setTimeout(TimeMs timeout);
void setTimeout(crl::time timeout);
int timeout() const;
void setRepeat(Repeat repeat) {
@@ -77,7 +77,7 @@ private:
}
Fn<void()> _callback;
TimeMs _next = 0;
crl::time _next = 0;
int _timeout = 0;
int _timerId = 0;
@@ -89,7 +89,7 @@ private:
class DelayedCallTimer final : private QObject {
public:
int call(TimeMs timeout, FnMut<void()> callback) {
int call(crl::time timeout, FnMut<void()> callback) {
return call(
timeout,
std::move(callback),
@@ -97,7 +97,7 @@ public:
}
int call(
TimeMs timeout,
crl::time timeout,
FnMut<void()> callback,
Qt::TimerType type);
void cancel(int callId);

View File

@@ -57,12 +57,21 @@ public:
}
~has_weak_ptr() {
if (auto alive = _alive.load()) {
if (const auto alive = _alive.load()) {
alive->value.store(nullptr);
details::decrement(alive);
}
}
friend inline void invalidate_weak_ptrs(has_weak_ptr *object) {
if (auto alive = object->_alive.load()) {
if (object->_alive.compare_exchange_strong(alive, nullptr)) {
alive->value.store(nullptr);
details::decrement(alive);
}
}
}
private:
template <typename Child>
friend class weak_ptr;

View File

@@ -13,6 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "zip.h"
#include "unzip.h"
#ifdef small
#undef small
#endif // small
namespace zlib {
namespace internal {
@@ -172,15 +176,28 @@ public:
return error();
}
int goToFirstFile() {
if (error() == UNZ_OK) {
_error = _handle ? unzGoToFirstFile(_handle) : -1;
}
return error();
}
int goToNextFile() {
if (error() == UNZ_OK) {
_error = _handle ? unzGoToNextFile(_handle) : -1;
}
return error();
}
int getCurrentFileInfo(
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize
) {
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize) {
if (error() == UNZ_OK) {
_error = _handle ? unzGetCurrentFileInfo(
_handle,
@@ -196,6 +213,21 @@ public:
return error();
}
QString getCurrentFileName() {
unz_file_info info = { 0 };
constexpr auto kMaxName = 128;
char name[kMaxName + 1] = { 0 };
const auto result = getCurrentFileInfo(
&info,
name,
kMaxName,
nullptr,
0,
nullptr,
0);
return (result == UNZ_OK) ? QString::fromUtf8(name) : QString();
}
int openCurrentFile() {
if (error() == UNZ_OK) {
_error = _handle ? unzOpenCurrentFile(_handle) : -1;

View File

@@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwidget.h"
#include "mainwindow.h"
#include "boxes/confirm_box.h"
#include "application.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "styles/style_boxes.h"
@@ -70,7 +69,7 @@ void AboutBox::showVersionHistory() {
}
url = url.arg(qsl("talpha%1_%2").arg(cRealAlphaVersion()).arg(Core::countAlphaVersionSignature(cRealAlphaVersion())));
Application::clipboard()->setText(url);
QApplication::clipboard()->setText(url);
Ui::show(Box<InformBox>("The link to the current private alpha version of Telegram Desktop was copied to the clipboard."));
} else {
@@ -87,13 +86,19 @@ void AboutBox::keyPressEvent(QKeyEvent *e) {
}
QString telegramFaqLink() {
auto result = qsl("https://telegram.org/faq");
auto language = Lang::Current().id();
for (auto faqLanguage : { "de", "es", "it", "ko", "br" }) {
if (language.startsWith(QLatin1String(faqLanguage))) {
result.append('/').append(faqLanguage);
const auto result = qsl("https://telegram.org/faq");
const auto langpacked = [&](const char *language) {
return result + '/' + language;
};
const auto current = Lang::Current().id();
for (const auto language : { "de", "es", "it", "ko" }) {
if (current.startsWith(QLatin1String(language))) {
return langpacked(language);
}
}
if (current.startsWith(qstr("pt-br"))) {
return langpacked("br");
}
return result;
}

View File

@@ -378,11 +378,14 @@ void AbstractBox::updateButtonsPositions() {
if (_leftButton) {
_leftButton->moveToLeft(right, top);
}
for_const (auto &button, _buttons) {
for (const auto &button : _buttons) {
button->moveToRight(right, top);
right += button->width() + padding.left();
}
}
if (_topButton) {
_topButton->moveToRight(0, 0);
}
}
QPointer<QWidget> AbstractBox::outerContainer() {
@@ -403,6 +406,7 @@ void AbstractBox::clearButtons() {
button.destroy();
}
_leftButton.destroy();
_topButton = nullptr;
}
QPointer<Ui::RoundButton> AbstractBox::addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) {
@@ -423,6 +427,15 @@ QPointer<Ui::RoundButton> AbstractBox::addLeftButton(Fn<QString()> textFactory,
return result;
}
QPointer<Ui::IconButton> AbstractBox::addTopButton(const style::IconButton &st, Fn<void()> clickCallback) {
_topButton = base::make_unique_q<Ui::IconButton>(this, st);
auto result = QPointer<Ui::IconButton>(_topButton.get());
result->setClickedCallback(std::move(clickCallback));
result->show();
updateButtonsPositions();
return result;
}
void AbstractBox::setDimensions(int newWidth, int maxHeight) {
_maxContentHeight = maxHeight;

View File

@@ -8,10 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "window/layer_widget.h"
#include "base/unique_qptr.h"
#include "ui/rp_widget.h"
namespace style {
struct RoundButton;
struct IconButton;
struct ScrollArea;
} // namespace style
@@ -35,6 +37,7 @@ public:
virtual void clearButtons() = 0;
virtual QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) = 0;
virtual QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) = 0;
virtual QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback) = 0;
virtual void updateButtonsPositions() = 0;
virtual void showBox(
@@ -100,8 +103,14 @@ public:
void clearButtons() {
getDelegate()->clearButtons();
}
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback);
QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback);
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback = nullptr);
QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback = nullptr);
QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback = nullptr) {
return getDelegate()->addTopButton(st, std::move(clickCallback));
}
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, const style::RoundButton &st) {
return getDelegate()->addButton(std::move(textFactory), nullptr, st);
}
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) {
return getDelegate()->addButton(std::move(textFactory), std::move(clickCallback), st);
}
@@ -251,6 +260,7 @@ public:
void clearButtons() override;
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) override;
QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) override;
QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback) override;
void updateButtonsPositions() override;
QPointer<QWidget> outerContainer() override;
@@ -319,6 +329,7 @@ private:
std::vector<object_ptr<Ui::RoundButton>> _buttons;
object_ptr<Ui::RoundButton> _leftButton = { nullptr };
base::unique_qptr<Ui::IconButton> _topButton = { nullptr };
};
@@ -337,3 +348,45 @@ enum CreatingGroupType {
CreatingGroupGroup,
CreatingGroupChannel,
};
class BoxPointer {
public:
BoxPointer() = default;
BoxPointer(const BoxPointer &other) = default;
BoxPointer(BoxPointer &&other) : _value(base::take(other._value)) {
}
BoxPointer &operator=(const BoxPointer &other) {
if (_value != other._value) {
destroy();
_value = other._value;
}
return *this;
}
BoxPointer &operator=(BoxPointer &&other) {
if (_value != other._value) {
destroy();
_value = base::take(other._value);
}
return *this;
}
BoxPointer &operator=(BoxContent *other) {
if (_value != other) {
destroy();
_value = other;
}
return *this;
}
~BoxPointer() {
destroy();
}
private:
void destroy() {
if (const auto value = base::take(_value)) {
value->closeBox();
}
}
QPointer<BoxContent> _value;
};

View File

@@ -10,13 +10,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h"
#include "styles/style_dialogs.h"
#include "lang/lang_keys.h"
#include "messenger.h"
#include "mtproto/sender.h"
#include "base/flat_set.h"
#include "boxes/confirm_box.h"
#include "boxes/photo_crop_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/add_participants_box.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 "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
@@ -25,6 +28,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toast/toast.h"
#include "ui/special_buttons.h"
#include "ui/text_options.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "apiwrap.h"
@@ -59,7 +66,7 @@ style::InputField CreateBioFieldStyle() {
QString PeerFloodErrorText(PeerFloodType type) {
auto link = textcmdLink(
Messenger::Instance().createInternalLinkFull(qsl("spambot")),
Core::App().createInternalLinkFull(qsl("spambot")),
lang(lng_cant_more_info));
if (type == PeerFloodType::InviteGroup) {
return lng_cant_invite_not_contact(lt_more_info, link);
@@ -67,6 +74,77 @@ QString PeerFloodErrorText(PeerFloodType type) {
return lng_cant_send_to_not_contact(lt_more_info, link);
}
void ShowAddParticipantsError(
const QString &error,
not_null<PeerData*> chat,
const std::vector<not_null<UserData*>> &users) {
if (error == qstr("USER_BOT")) {
const auto channel = chat->asChannel();
if ((users.size() == 1)
&& (users.front()->botInfo != nullptr)
&& channel
&& !channel->isMegagroup()
&& channel->canAddAdmins()) {
const auto makeAdmin = [=] {
const auto user = users.front();
const auto weak = std::make_shared<QPointer<EditAdminBox>>();
const auto close = [=](auto&&...) {
if (*weak) {
(*weak)->closeBox();
}
};
const auto saveCallback = SaveAdminCallback(
channel,
user,
close,
close);
auto box = Box<EditAdminBox>(
channel,
user,
MTP_chatAdminRights(MTP_flags(0)));
box->setSaveCallback(saveCallback);
*weak = Ui::show(std::move(box));
};
Ui::show(
Box<ConfirmBox>(
lang(lng_cant_invite_offer_admin),
lang(lng_cant_invite_make_admin),
lang(lng_cancel),
makeAdmin),
LayerOption::KeepOther);
return;
}
}
const auto bot = ranges::find_if(users, [](not_null<UserData*> user) {
return user->botInfo != nullptr;
});
const auto hasBot = (bot != end(users));
const auto text = [&] {
if (error == qstr("USER_BOT")) {
return lang(lng_cant_invite_bot_to_channel);
} else if (error == qstr("USER_LEFT_CHAT")) {
// Trying to return a user who has left.
} else if (error == qstr("USER_KICKED")) {
// Trying to return a user who was kicked by admin.
return lang(lng_cant_invite_banned);
} else if (error == qstr("USER_PRIVACY_RESTRICTED")) {
return lang(lng_cant_invite_privacy);
} else if (error == qstr("USER_NOT_MUTUAL_CONTACT")) {
// Trying to return user who does not have me in contacts.
return lang(lng_failed_add_not_mutual);
} else if (error == qstr("USER_ALREADY_PARTICIPANT") && hasBot) {
return lang(lng_bot_already_in_group);
} else if (error == qstr("PEER_FLOOD")) {
const auto isGroup = (chat->isChat() || chat->isMegagroup());
return PeerFloodErrorText(isGroup
? PeerFloodType::InviteGroup
: PeerFloodType::InviteChannel);
}
return lang(lng_failed_add_participant);
}();
Ui::show(Box<InformBox>(text), LayerOption::KeepOther);
}
class RevokePublicLinkBox::Inner : public TWidget, private MTP::Sender {
public:
Inner(QWidget *parent, Fn<void()> revokeCallback);
@@ -244,8 +322,9 @@ bool AddContactBox::onSaveUserFail(const RPCError &error) {
if (MTP::isDefaultHandledError(error)) return false;
_addRequest = 0;
QString err(error.type());
QString firstName = _first->getLastText().trimmed(), lastName = _last->getLastText().trimmed();
const auto &err = error.type();
const auto firstName = _first->getLastText().trimmed();
const auto lastName = _last->getLastText().trimmed();
if (err == "CHAT_TITLE_NOT_MODIFIED") {
_user->setName(firstName, lastName, _user->nameOrPhone, _user->username);
closeBox();
@@ -263,21 +342,21 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
if (!isBoxShown() || !App::main()) return;
const auto &d = res.c_contacts_importedContacts();
App::feedUsers(d.vusers);
Auth().data().processUsers(d.vusers);
const auto &v = d.vimported.v;
const auto user = [&]() -> UserData* {
if (!v.isEmpty()) {
auto &c = v.front().c_importedContact();
if (c.vclient_id.v == _contactId) {
return App::userLoaded(c.vuser_id.v);
return Auth().data().userLoaded(c.vuser_id.v);
}
}
return nullptr;
}();
if (user) {
if (user->contactStatus() == UserData::ContactStatus::Contact
|| Auth().supportMode()) {
|| user->session().supportMode()) {
Ui::showPeerHistory(user, ShowAtTheEndMsgId);
}
Ui::hideLayer();
@@ -291,7 +370,7 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
void AddContactBox::onSaveUserDone(const MTPcontacts_ImportedContacts &res) {
auto &d = res.c_contacts_importedContacts();
App::feedUsers(d.vusers);
Auth().data().processUsers(d.vusers);
closeBox();
}
@@ -329,9 +408,9 @@ void GroupInfoBox::prepare() {
_photo.create(
this,
(_creating == CreatingGroupChannel)
? peerFromChannel(0)
: peerFromChat(0),
lang((_creating == CreatingGroupChannel)
? lng_create_channel_crop
: lng_create_group_crop),
Ui::UserpicButton::Role::ChangePhoto,
st::defaultUserpicButton);
_title.create(
@@ -458,11 +537,13 @@ void GroupInfoBox::createGroup(
: std::nullopt;
}
| [](auto chats) {
return App::chat(chats->front().c_chat().vid.v);
return Auth().data().chat(chats->front().c_chat().vid.v);
}
| [&](not_null<ChatData*> chat) {
if (!image.isNull()) {
Auth().api().uploadPeerPhoto(chat, std::move(image));
chat->session().api().uploadPeerPhoto(
chat,
std::move(image));
}
Ui::showPeerHistory(chat, ShowAtUnreadMsgId);
};
@@ -531,8 +612,7 @@ void GroupInfoBox::submit() {
};
Ui::show(
Box<PeerListBox>(
std::make_unique<AddParticipantsBoxController>(
nullptr),
std::make_unique<AddParticipantsBoxController>(),
std::move(initBox)),
LayerOption::KeepOther);
}
@@ -541,7 +621,11 @@ void GroupInfoBox::submit() {
void GroupInfoBox::createChannel(const QString &title, const QString &description) {
bool mega = false;
auto flags = mega ? MTPchannels_CreateChannel::Flag::f_megagroup : MTPchannels_CreateChannel::Flag::f_broadcast;
_creationRequestId = request(MTPchannels_CreateChannel(MTP_flags(flags), MTP_string(title), MTP_string(description))).done([this](const MTPUpdates &result) {
_creationRequestId = request(MTPchannels_CreateChannel(
MTP_flags(flags),
MTP_string(title),
MTP_string(description)
)).done([=](const MTPUpdates &result) {
Auth().api().applyUpdates(result);
auto success = base::make_optional(&result)
@@ -561,17 +645,19 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
: std::nullopt;
}
| [](auto chats) {
return App::channel(chats->front().c_channel().vid.v);
return Auth().data().channel(chats->front().c_channel().vid.v);
}
| [this](not_null<ChannelData*> channel) {
| [&](not_null<ChannelData*> channel) {
auto image = _photo->takeResultImage();
if (!image.isNull()) {
Auth().api().uploadPeerPhoto(channel, std::move(image));
channel->session().api().uploadPeerPhoto(
channel,
std::move(image));
}
_createdChannel = channel;
_creationRequestId = request(
MTPchannels_ExportInvite(_createdChannel->inputChannel)
).done([this](const MTPExportedChatInvite &result) {
_creationRequestId = request(MTPmessages_ExportChatInvite(
_createdChannel->input
)).done([=](const MTPExportedChatInvite &result) {
_creationRequestId = 0;
if (result.type() == mtpc_chatInviteExported) {
auto link = qs(result.c_chatInviteExported().vlink);
@@ -749,7 +835,7 @@ void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) {
void SetupChannelBox::mousePressEvent(QMouseEvent *e) {
if (_linkOver) {
if (_channel->inviteLink().isEmpty()) {
Auth().api().exportInviteLink(_channel);
_channel->session().api().exportInviteLink(_channel);
} else {
QGuiApplication::clipboard()->setText(_channel->inviteLink());
Ui::Toast::Show(lang(lng_create_channel_link_copied));
@@ -1069,7 +1155,7 @@ void EditNameBox::save() {
}
void EditNameBox::saveSelfDone(const MTPUser &user) {
App::feedUsers(MTP_vector<MTPUser>(1, user));
_user->owner().processUsers(MTP_vector<MTPUser>(1, user));
closeBox();
}
@@ -1096,261 +1182,6 @@ bool EditNameBox::saveSelfFail(const RPCError &error) {
return true;
}
EditChannelBox::EditChannelBox(QWidget*, not_null<ChannelData*> channel)
: _channel(channel)
, _title(this, st::defaultInputField, langFactory(_channel->isMegagroup() ? lng_dlg_new_group_name : lng_dlg_new_channel_name), _channel->name)
, _description(
this,
st::newGroupDescription,
Ui::InputField::Mode::MultiLine,
langFactory(lng_create_group_description),
_channel->about())
, _sign(this, lang(lng_edit_sign_messages), channel->addsSignature(), st::defaultBoxCheckbox)
, _inviteGroup(std::make_shared<Ui::RadioenumGroup<Invites>>(channel->anyoneCanAddMembers() ? Invites::Everybody : Invites::OnlyAdmins))
, _inviteEverybody(this, _inviteGroup, Invites::Everybody, lang(lng_edit_group_invites_everybody))
, _inviteOnlyAdmins(this, _inviteGroup, Invites::OnlyAdmins, lang(lng_edit_group_invites_only_admins))
, _publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), st::boxLinkButton) {
}
void EditChannelBox::prepare() {
setTitle(langFactory(_channel->isMegagroup() ? lng_edit_group : lng_edit_channel_title));
addButton(langFactory(lng_settings_save), [this] { save(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); });
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::NameChanged, [this](const Notify::PeerUpdate &update) {
if (update.peer == _channel) {
handleChannelNameChange();
}
}));
setMouseTracking(true);
_title->setMaxLength(kMaxGroupChannelTitle);
_title->setInstantReplaces(Ui::InstantReplaces::Default());
_title->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(),
_title);
_description->setMaxLength(kMaxChannelDescription);
_description->setInstantReplaces(Ui::InstantReplaces::Default());
_description->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
connect(_description, &Ui::InputField::resized, [=] { descriptionResized(); });
connect(_description, &Ui::InputField::submitted, [=] { save(); });
connect(_description, &Ui::InputField::cancelled, [=] { closeBox(); });
Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(),
_description);
_publicLink->addClickHandler([=] { setupPublicLink(); });
_publicLink->setVisible(_channel->canEditUsername());
_sign->setVisible(canEditSignatures());
_inviteEverybody->setVisible(canEditInvites());
_inviteOnlyAdmins->setVisible(canEditInvites());
updateMaxHeight();
}
void EditChannelBox::setInnerFocus() {
_title->setFocusFast();
}
void EditChannelBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (_title->hasFocus()) {
save();
}
} else {
BoxContent::keyPressEvent(e);
}
}
void EditChannelBox::handleChannelNameChange() {
_publicLink->setText(lang(_channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link));
_sign->setChecked(_channel->addsSignature());
}
void EditChannelBox::descriptionResized() {
updateMaxHeight();
update();
}
bool EditChannelBox::canEditSignatures() const {
return _channel->canEditInformation() && !_channel->isMegagroup();
}
bool EditChannelBox::canEditInvites() const {
return _channel->canEditInformation() && _channel->isMegagroup();
}
void EditChannelBox::updateMaxHeight() {
auto newHeight = st::newGroupInfoPadding.top() + _title->height();
newHeight += st::newGroupDescriptionPadding.top() + _description->height() + st::newGroupDescriptionPadding.bottom();
if (canEditSignatures()) {
newHeight += st::newGroupPublicLinkPadding.top() + _sign->heightNoMargins() + st::newGroupPublicLinkPadding.bottom();
}
if (canEditInvites()) {
newHeight += st::boxTitleHeight + _inviteEverybody->heightNoMargins();
newHeight += st::boxLittleSkip + _inviteOnlyAdmins->heightNoMargins();
}
if (_channel->canEditUsername()) {
newHeight += st::newGroupPublicLinkPadding.top() + _publicLink->height() + st::newGroupPublicLinkPadding.bottom();
}
newHeight += st::boxPadding.bottom() + st::newGroupInfoPadding.bottom();
setDimensions(st::boxWideWidth, newHeight);
}
void EditChannelBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _title->height());
_title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::newGroupInfoPadding.top() + st::newGroupNamePosition.y());
_description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description->height());
_description->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _title->y() + _title->height() + st::newGroupDescriptionPadding.top());
_sign->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
_inviteEverybody->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::boxTitleHeight);
_inviteOnlyAdmins->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _inviteEverybody->bottomNoMargins() + st::boxLittleSkip);
if (canEditSignatures()) {
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _sign->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
} else if (canEditInvites()) {
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _inviteOnlyAdmins->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
} else {
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
}
}
void EditChannelBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
if (canEditInvites()) {
Painter p(this);
p.setPen(st::boxTitleFg);
p.setFont(st::autoDownloadTitleFont);
p.drawTextLeft(st::boxTitlePosition.x(), _description->y() + _description->height() + st::boxTitlePosition.y(), width(), lang(lng_edit_group_who_invites));
}
}
void EditChannelBox::save() {
if (_saveTitleRequestId || _saveDescriptionRequestId || _saveSignRequestId || _saveInvitesRequestId) return;
auto title = TextUtilities::PrepareForSending(_title->getLastText());
auto description = TextUtilities::PrepareForSending(_description->getLastText(), TextUtilities::PrepareTextOption::CheckLinks);
if (title.isEmpty()) {
_title->setFocus();
_title->showError();
return;
}
_sentTitle = title;
_sentDescription = description;
if (_sentTitle == _channel->name) {
saveDescription();
} else {
_saveTitleRequestId = MTP::send(MTPchannels_EditTitle(_channel->inputChannel, MTP_string(_sentTitle)), rpcDone(&EditChannelBox::onSaveTitleDone), rpcFail(&EditChannelBox::onSaveFail));
}
}
void EditChannelBox::setupPublicLink() {
Ui::show(
Box<SetupChannelBox>(_channel, true),
LayerOption::KeepOther);
}
void EditChannelBox::saveDescription() {
if (_sentDescription == _channel->about()) {
saveSign();
} else {
_saveDescriptionRequestId = MTP::send(MTPchannels_EditAbout(_channel->inputChannel, MTP_string(_sentDescription)), rpcDone(&EditChannelBox::onSaveDescriptionDone), rpcFail(&EditChannelBox::onSaveFail));
}
}
void EditChannelBox::saveSign() {
if (!canEditSignatures() || _channel->addsSignature() == _sign->checked()) {
saveInvites();
} else {
_saveSignRequestId = MTP::send(MTPchannels_ToggleSignatures(_channel->inputChannel, MTP_bool(_sign->checked())), rpcDone(&EditChannelBox::onSaveSignDone), rpcFail(&EditChannelBox::onSaveFail));
}
}
void EditChannelBox::saveInvites() {
if (!canEditInvites() || _channel->anyoneCanAddMembers() == (_inviteGroup->value() == Invites::Everybody)) {
closeBox();
} else {
_saveInvitesRequestId = MTP::send(MTPchannels_ToggleInvites(_channel->inputChannel, MTP_bool(_inviteGroup->value() == Invites::Everybody)), rpcDone(&EditChannelBox::onSaveInvitesDone), rpcFail(&EditChannelBox::onSaveFail));
}
}
bool EditChannelBox::onSaveFail(const RPCError &error, mtpRequestId req) {
if (MTP::isDefaultHandledError(error)) return false;
QString err(error.type());
if (req == _saveTitleRequestId) {
_saveTitleRequestId = 0;
if (err == qstr("CHAT_NOT_MODIFIED") || err == qstr("CHAT_TITLE_NOT_MODIFIED")) {
_channel->setName(_sentTitle, _channel->username);
saveDescription();
return true;
} else if (err == qstr("NO_CHAT_TITLE")) {
_title->setFocus();
_title->showError();
return true;
} else {
_title->setFocus();
}
} else if (req == _saveDescriptionRequestId) {
_saveDescriptionRequestId = 0;
if (err == qstr("CHAT_ABOUT_NOT_MODIFIED")) {
_channel->setAbout(_sentDescription);
saveSign();
return true;
} else {
_description->setFocus();
}
} else if (req == _saveSignRequestId) {
_saveSignRequestId = 0;
if (err == qstr("CHAT_NOT_MODIFIED")) {
saveInvites();
return true;
}
} else if (req == _saveInvitesRequestId) {
_saveInvitesRequestId = 0;
if (err == qstr("CHAT_NOT_MODIFIED")) {
closeBox();
return true;
}
}
return true;
}
void EditChannelBox::onSaveTitleDone(const MTPUpdates &result) {
_saveTitleRequestId = 0;
Auth().api().applyUpdates(result);
saveDescription();
}
void EditChannelBox::onSaveDescriptionDone(const MTPBool &result) {
_saveDescriptionRequestId = 0;
_channel->setAbout(_sentDescription);
saveSign();
}
void EditChannelBox::onSaveSignDone(const MTPUpdates &result) {
_saveSignRequestId = 0;
Auth().api().applyUpdates(result);
saveInvites();
}
void EditChannelBox::onSaveInvitesDone(const MTPUpdates &result) {
_saveSignRequestId = 0;
Auth().api().applyUpdates(result);
closeBox();
}
RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn<void()> revokeCallback) : TWidget(parent)
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _revokeWidth(st::normalFont->width(lang(lng_channels_too_much_public_revoke)))
@@ -1359,27 +1190,29 @@ RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn<void()> revokeCallback) :
resize(width(), 5 * _rowHeight);
request(MTPchannels_GetAdminedPublicChannels()).done([this](const MTPmessages_Chats &result) {
if (auto chats = Api::getChatsFromMessagesChats(result)) {
for_const (auto &chat, chats->v) {
if (auto peer = App::feedChat(chat)) {
if (!peer->isChannel() || peer->userName().isEmpty()) {
continue;
}
auto row = ChatRow(peer);
row.peer = peer;
row.name.setText(
st::contactsNameStyle,
peer->name,
Ui::NameTextOptions());
row.status.setText(
st::defaultTextStyle,
Messenger::Instance().createInternalLink(
textcmdLink(1, peer->userName())),
Ui::DialogTextOptions());
_rows.push_back(std::move(row));
request(MTPchannels_GetAdminedPublicChannels(
)).done([=](const MTPmessages_Chats &result) {
const auto &chats = result.match([](const auto &data) {
return data.vchats.v;
});
for (const auto &chat : chats) {
if (const auto peer = Auth().data().processChat(chat)) {
if (!peer->isChannel() || peer->userName().isEmpty()) {
continue;
}
auto row = ChatRow(peer);
row.peer = peer;
row.name.setText(
st::contactsNameStyle,
peer->name,
Ui::NameTextOptions());
row.status.setText(
st::defaultTextStyle,
Core::App().createInternalLink(
textcmdLink(1, peer->userName())),
Ui::DialogTextOptions());
_rows.push_back(std::move(row));
}
}
resize(width(), _rows.size() * _rowHeight);
@@ -1387,23 +1220,30 @@ RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn<void()> revokeCallback) :
}).send();
}
RevokePublicLinkBox::RevokePublicLinkBox(QWidget*, Fn<void()> revokeCallback)
: _aboutRevoke(this, lang(lng_channels_too_much_public_about), Ui::FlatLabel::InitType::Simple, st::aboutRevokePublicLabel)
RevokePublicLinkBox::RevokePublicLinkBox(
QWidget*,
Fn<void()> revokeCallback)
: _aboutRevoke(
this,
lang(lng_channels_too_much_public_about),
Ui::FlatLabel::InitType::Simple,
st::aboutRevokePublicLabel)
, _revokeCallback(std::move(revokeCallback)) {
}
void RevokePublicLinkBox::prepare() {
_innerTop = st::boxPadding.top() + _aboutRevoke->height() + st::boxPadding.top();
_inner = setInnerWidget(object_ptr<Inner>(this, [this] {
_inner = setInnerWidget(object_ptr<Inner>(this, [=] {
const auto callback = _revokeCallback;
closeBox();
if (_revokeCallback) {
_revokeCallback();
if (callback) {
callback();
}
}), st::boxLayerScroll, _innerTop);
addButton(langFactory(lng_cancel), [this] { closeBox(); });
addButton(langFactory(lng_cancel), [=] { closeBox(); });
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
_inner->resizeToWidth(st::boxWideWidth);
setDimensions(st::boxWideWidth, _innerTop + _inner->height());
@@ -1444,16 +1284,20 @@ void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default);
if (pressed && pressed == _selected) {
auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel;
auto text = text_method(lt_link, Messenger::Instance().createInternalLink(pressed->userName()), lt_group, pressed->name);
auto text = text_method(lt_link, Core::App().createInternalLink(pressed->userName()), lt_group, pressed->name);
auto confirmText = lang(lng_channels_too_much_public_revoke);
_weakRevokeConfirmBox = Ui::show(Box<ConfirmBox>(text, confirmText, crl::guard(this, [this, pressed]() {
if (_revokeRequestId) return;
_revokeRequestId = request(MTPchannels_UpdateUsername(pressed->asChannel()->inputChannel, MTP_string(""))).done([this](const MTPBool &result) {
_revokeRequestId = request(MTPchannels_UpdateUsername(
pressed->asChannel()->inputChannel,
MTP_string("")
)).done([=](const MTPBool &result) {
const auto callback = _revokeCallback;
if (_weakRevokeConfirmBox) {
_weakRevokeConfirmBox->closeBox();
}
if (_revokeCallback) {
_revokeCallback();
if (callback) {
callback();
}
}).send();
})), LayerOption::KeepOther);

View File

@@ -38,6 +38,10 @@ enum class PeerFloodType {
InviteChannel,
};
QString PeerFloodErrorText(PeerFloodType type);
void ShowAddParticipantsError(
const QString &error,
not_null<PeerData*> chat,
const std::vector<not_null<UserData*>> &users);
class AddContactBox : public BoxContent, public RPCSender {
public:
@@ -96,7 +100,6 @@ private:
void descriptionResized();
void updateMaxHeight();
void updateSelected(const QPoint &cursorGlobalPosition);
CreatingGroupType _creating;
bool _fromTypeChoose = false;
@@ -134,7 +137,6 @@ private:
};
void privacyChanged(Privacy value);
void updateSelected(const QPoint &cursorGlobalPosition);
void showAddContactsToChannelBox() const;
void handleChange();
void check();
void save();
@@ -201,62 +203,6 @@ private:
};
class EditChannelBox : public BoxContent, public RPCSender {
public:
EditChannelBox(QWidget*, not_null<ChannelData*> channel);
protected:
void prepare() override;
void setInnerFocus() override;
void keyPressEvent(QKeyEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
private:
void updateMaxHeight();
bool canEditSignatures() const;
bool canEditInvites() const;
void handleChannelNameChange();
void descriptionResized();
void setupPublicLink();
void save();
void onSaveTitleDone(const MTPUpdates &result);
void onSaveDescriptionDone(const MTPBool &result);
void onSaveSignDone(const MTPUpdates &result);
void onSaveInvitesDone(const MTPUpdates &result);
bool onSaveFail(const RPCError &error, mtpRequestId req);
void saveDescription();
void saveSign();
void saveInvites();
not_null<ChannelData*> _channel;
object_ptr<Ui::InputField> _title;
object_ptr<Ui::InputField> _description;
object_ptr<Ui::Checkbox> _sign;
enum class Invites {
Everybody,
OnlyAdmins,
};
std::shared_ptr<Ui::RadioenumGroup<Invites>> _inviteGroup;
object_ptr<Ui::Radioenum<Invites>> _inviteEverybody;
object_ptr<Ui::Radioenum<Invites>> _inviteOnlyAdmins;
object_ptr<Ui::LinkButton> _publicLink;
mtpRequestId _saveTitleRequestId = 0;
mtpRequestId _saveDescriptionRequestId = 0;
mtpRequestId _saveSignRequestId = 0;
mtpRequestId _saveInvitesRequestId = 0;
QString _sentTitle, _sentDescription;
};
class RevokePublicLinkBox : public BoxContent, public RPCSender {
public:
RevokePublicLinkBox(QWidget*, Fn<void()> revokeCallback);

View File

@@ -0,0 +1,179 @@
/*
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/auto_download_box.h"
#include "lang/lang_keys.h"
#include "auth_session.h"
#include "data/data_session.h"
#include "info/profile/info_profile_button.h"
#include "ui/widgets/continuous_sliders.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/wrap.h"
#include "storage/localstorage.h"
#include "settings/settings_common.h"
#include "export/view/export_view_settings.h"
#include "styles/style_boxes.h"
#include "styles/style_settings.h"
namespace {
constexpr auto kMegabyte = 1024 * 1024;
constexpr auto kDefaultLimit = 10 * kMegabyte;
} // namespace
AutoDownloadBox::AutoDownloadBox(
QWidget*,
Data::AutoDownload::Source source)
: _source(source) {
}
void AutoDownloadBox::prepare() {
setupContent();
}
void AutoDownloadBox::setupContent() {
using namespace Settings;
using namespace Data::AutoDownload;
using namespace rpl::mappers;
using Type = Data::AutoDownload::Type;
setTitle(langFactory(lng_media_auto_title));
const auto settings = &Auth().settings().autoDownload();
const auto checked = [=](Source source, Type type) {
return (settings->bytesLimit(source, type) > 0);
};
auto wrap = object_ptr<Ui::VerticalLayout>(this);
const auto content = wrap.data();
setInnerWidget(object_ptr<Ui::OverrideMargins>(
this,
std::move(wrap)));
static const auto kHidden = {
Type::Video,
Type::Music,
Type::VoiceMessage
};
const auto values = Ui::CreateChild<base::flat_map<Type, int>>(content);
const auto add = [&](Type type, LangKey label) {
if (ranges::find(kHidden, type) != end(kHidden)) {
return;
}
const auto value = settings->bytesLimit(_source, type);
AddButton(
content,
label,
st::settingsButton
)->toggleOn(
rpl::single(value > 0)
)->toggledChanges(
) | rpl::start_with_next([=](bool enabled) {
(*values)[type] = enabled ? 1 : 0;
}, content->lifetime());
values->emplace(type, value);
};
add(Type::Photo, lng_media_photo_title);
add(Type::VoiceMessage, lng_media_audio_title);
add(Type::VideoMessage, lng_media_video_messages_title);
add(Type::Video, lng_media_video_title);
add(Type::File, lng_media_file_title);
add(Type::Music, lng_media_music_title);
add(Type::GIF, lng_media_animation_title);
const auto limits = Ui::CreateChild<rpl::event_stream<int>>(content);
using Pair = base::flat_map<Type, int>::value_type;
const auto settingsLimit = ranges::max_element(
*values,
std::less<>(),
[](Pair pair) { return pair.second; })->second;
const auto initialLimit = settingsLimit ? settingsLimit : kDefaultLimit;
const auto limit = Ui::CreateChild<int>(content, initialLimit);
AddButtonWithLabel(
content,
lng_media_size_limit,
limits->events_starting_with_copy(
initialLimit
) | rpl::map([](int value) {
return lng_media_size_up_to(
lt_size,
QString::number(value / kMegabyte) + " MB");
}),
st::autoDownloadLimitButton
)->setAttribute(Qt::WA_TransparentForMouseEvents);
const auto slider = content->add(
object_ptr<Ui::MediaSlider>(content, st::autoDownloadLimitSlider),
st::autoDownloadLimitPadding);
slider->resize(st::autoDownloadLimitSlider.seekSize);
slider->setPseudoDiscrete(
Export::View::kSizeValueCount,
Export::View::SizeLimitByIndex,
*limit,
[=](int value) {
*limit = value;
limits->fire_copy(value);
});
addButton(langFactory(lng_connection_save), [=] {
auto allowMore = ranges::view::all(
*values
) | ranges::view::filter([&](Pair pair) {
const auto [type, enabled] = pair;
const auto value = enabled ? *limit : 0;
const auto old = settings->bytesLimit(_source, type);
return (old < value);
}) | ranges::view::transform([](Pair pair) {
return pair.first;
});
const auto allowMoreTypes = base::flat_set<Type>(
allowMore.begin(),
allowMore.end());
const auto changed = ranges::find_if(*values, [&](Pair pair) {
const auto [type, enabled] = pair;
const auto value = enabled ? *limit : 0;
return settings->bytesLimit(_source, type) != value;
}) != end(*values);
const auto hiddenChanged = ranges::find_if(kHidden, [&](Type type) {
const auto now = settings->bytesLimit(_source, type);
return (now > 0) && (now != *limit);
}) != end(kHidden);
if (changed) {
for (const auto [type, enabled] : *values) {
const auto value = enabled ? *limit : 0;
settings->setBytesLimit(_source, type, value);
}
}
if (hiddenChanged) {
for (const auto type : kHidden) {
const auto now = settings->bytesLimit(_source, type);
if (now > 0) {
settings->setBytesLimit(_source, type, *limit);
}
}
}
if (changed || hiddenChanged) {
Local::writeUserSettings();
}
if (allowMoreTypes.contains(Type::Photo)) {
Auth().data().photoLoadSettingsChanged();
}
if (ranges::find_if(allowMoreTypes, _1 != Type::Photo)
!= allowMoreTypes.end()) {
Auth().data().documentLoadSettingsChanged();
}
closeBox();
});
addButton(langFactory(lng_cancel), [=] { closeBox(); });
setDimensionsToContent(st::boxWidth, content);
}

View File

@@ -0,0 +1,30 @@
/*
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 Data {
namespace AutoDownload {
enum class Source;
} // namespace AutoDownload
} // namespace Data
class AutoDownloadBox : public BoxContent {
public:
AutoDownloadBox(QWidget*, Data::AutoDownload::Source source);
protected:
void prepare() override;
private:
void setupContent();
Data::AutoDownload::Source _source;
};

View File

@@ -5,7 +5,7 @@ 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/autolock_box.h"
#include "boxes/auto_lock_box.h"
#include "lang/lang_keys.h"
#include "storage/localstorage.h"

View File

@@ -8,22 +8,58 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/background_box.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "window/themes/window_theme.h"
#include "ui/effects/round_checkbox.h"
#include "ui/image/image.h"
#include "auth_session.h"
#include "apiwrap.h"
#include "mtproto/sender.h"
#include "data/data_session.h"
#include "boxes/background_preview_box.h"
#include "boxes/confirm_box.h"
#include "styles/style_overview.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
class BackgroundBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
namespace {
constexpr auto kBackgroundsInRow = 3;
QImage TakeMiddleSample(QImage original, QSize size) {
size *= cIntRetinaFactor();
const auto from = original.size();
if (from.isEmpty()) {
auto result = original.scaled(size);
result.setDevicePixelRatio(cRetinaFactor());
return result;
}
const auto take = (from.width() * size.height()
> from.height() * size.width())
? QSize(size.width() * from.height() / size.height(), from.height())
: QSize(from.width(), size.height() * from.width() / size.width());
auto result = original.copy(
(from.width() - take.width()) / 2,
(from.height() - take.height()) / 2,
take.width(),
take.height()
).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
result.setDevicePixelRatio(cRetinaFactor());
return result;
}
} // namespace
class BackgroundBox::Inner
: public Ui::RpWidget
, private MTP::Sender
, private base::Subscriber {
public:
Inner(QWidget *parent);
void setBackgroundChosenCallback(Fn<void(int index)> callback) {
_backgroundChosenCallback = std::move(callback);
}
rpl::producer<Data::WallPaper> chooseEvents() const;
rpl::producer<Data::WallPaper> removeRequests() const;
void removePaper(const Data::WallPaper &data);
~Inner();
@@ -34,16 +70,51 @@ protected:
void mouseReleaseEvent(QMouseEvent *e) override;
private:
void gotWallpapers(const MTPVector<MTPWallPaper> &result);
void updateWallpapers();
struct Paper {
Data::WallPaper data;
mutable QPixmap thumbnail;
};
struct Selected {
int index = 0;
inline bool operator==(const Selected &other) const {
return index == other.index;
}
inline bool operator!=(const Selected &other) const {
return !(*this == other);
}
};
struct DeleteSelected {
int index = 0;
inline bool operator==(const DeleteSelected &other) const {
return index == other.index;
}
inline bool operator!=(const DeleteSelected &other) const {
return !(*this == other);
}
};
using Selection = base::optional_variant<Selected, DeleteSelected>;
Fn<void(int index)> _backgroundChosenCallback;
int getSelectionIndex(const Selection &selection) const;
void repaintPaper(int index);
void resizeToContentAndPreload();
void updatePapers();
void requestPapers();
void sortPapers();
void paintPaper(
Painter &p,
const Paper &paper,
int column,
int row) const;
void validatePaperThumbnail(const Paper &paper) const;
std::vector<Paper> _papers;
Selection _over;
Selection _overDown;
int _bgCount = 0;
int _rows = 0;
int _over = -1;
int _overDown = -1;
std::unique_ptr<Ui::RoundCheckbox> _check; // this is not a widget
rpl::event_stream<Data::WallPaper> _backgroundChosen;
rpl::event_stream<Data::WallPaper> _backgroundRemove;
};
@@ -53,180 +124,320 @@ BackgroundBox::BackgroundBox(QWidget*) {
void BackgroundBox::prepare() {
setTitle(langFactory(lng_backgrounds_header));
addButton(langFactory(lng_close), [this] { closeBox(); });
addButton(langFactory(lng_close), [=] { closeBox(); });
setDimensions(st::boxWideWidth, st::boxMaxListHeight);
_inner = setInnerWidget(object_ptr<Inner>(this), st::backgroundScroll);
_inner->setBackgroundChosenCallback([this](int index) { backgroundChosen(index); });
_inner->chooseEvents(
) | rpl::start_with_next([](const Data::WallPaper &paper) {
Ui::show(Box<BackgroundPreviewBox>(paper), LayerOption::KeepOther);
}, _inner->lifetime());
_inner->removeRequests(
) | rpl::start_with_next([=](const Data::WallPaper &paper) {
removePaper(paper);
}, _inner->lifetime());
}
void BackgroundBox::backgroundChosen(int index) {
if (index >= 0 && index < App::cServerBackgrounds().size()) {
auto &paper = App::cServerBackgrounds()[index];
if (App::main()) App::main()->setChatBackground(paper);
using Update = Window::Theme::BackgroundUpdate;
Window::Theme::Background()->notify(Update(Update::Type::Start, !paper.id));
}
closeBox();
void BackgroundBox::removePaper(const Data::WallPaper &paper) {
const auto box = std::make_shared<QPointer<BoxContent>>();
const auto remove = [=, weak = make_weak(this)]{
if (*box) {
(*box)->closeBox();
}
if (weak) {
weak->_inner->removePaper(paper);
}
Auth().data().removeWallpaper(paper);
Auth().api().request(MTPaccount_SaveWallPaper(
paper.mtpInput(),
MTP_bool(true),
paper.mtpSettings()
)).send();
};
*box = Ui::show(
Box<ConfirmBox>(
lang(lng_background_sure_delete),
lang(lng_selected_delete),
lang(lng_cancel),
remove),
LayerOption::KeepOther);
}
BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent)
, _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [this] { update(); })) {
BackgroundBox::Inner::Inner(QWidget *parent) : RpWidget(parent)
, _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [=] { update(); })) {
_check->setChecked(true, Ui::RoundCheckbox::SetStyle::Fast);
if (App::cServerBackgrounds().isEmpty()) {
resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
MTP::send(MTPaccount_GetWallPapers(), rpcDone(&Inner::gotWallpapers));
if (Auth().data().wallpapers().empty()) {
resize(st::boxWideWidth, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
} else {
updateWallpapers();
updatePapers();
}
requestPapers();
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
using Update = Window::Theme::BackgroundUpdate;
subscribe(Window::Theme::Background(), [=](const Update &update) {
if (update.paletteChanged()) {
_check->invalidateCache();
} else if (update.type == Update::Type::New) {
sortPapers();
requestPapers();
this->update();
}
});
setMouseTracking(true);
}
void BackgroundBox::Inner::gotWallpapers(const MTPVector<MTPWallPaper> &result) {
App::WallPapers wallpapers;
auto oldBackground = Images::Create(qsl(":/gui/art/bg_initial.jpg"), "JPG");
wallpapers.push_back(App::WallPaper(Window::Theme::kInitialBackground, oldBackground, oldBackground));
auto &v = result.v;
for_const (auto &w, v) {
switch (w.type()) {
case mtpc_wallPaper: {
auto &d = w.c_wallPaper();
auto &sizes = d.vsizes.v;
const MTPPhotoSize *thumb = 0, *full = 0;
int32 thumbLevel = -1, fullLevel = -1;
for (QVector<MTPPhotoSize>::const_iterator j = sizes.cbegin(), e = sizes.cend(); j != e; ++j) {
char size = 0;
int32 w = 0, h = 0;
switch (j->type()) {
case mtpc_photoSize: {
auto &s = j->c_photoSize().vtype.v;
if (s.size()) size = s[0];
w = j->c_photoSize().vw.v;
h = j->c_photoSize().vh.v;
} break;
case mtpc_photoCachedSize: {
auto &s = j->c_photoCachedSize().vtype.v;
if (s.size()) size = s[0];
w = j->c_photoCachedSize().vw.v;
h = j->c_photoCachedSize().vh.v;
} break;
}
if (!size || !w || !h) continue;
int32 newThumbLevel = qAbs((st::backgroundSize.width() * cIntRetinaFactor()) - w), newFullLevel = qAbs(2560 - w);
if (thumbLevel < 0 || newThumbLevel < thumbLevel) {
thumbLevel = newThumbLevel;
thumb = &(*j);
}
if (fullLevel < 0 || newFullLevel < fullLevel) {
fullLevel = newFullLevel;
full = &(*j);
}
}
if (thumb && full && full->type() != mtpc_photoSizeEmpty) {
wallpapers.push_back(App::WallPaper(d.vid.v ? d.vid.v : INT_MAX, App::image(*thumb), App::image(*full)));
}
} break;
case mtpc_wallPaperSolid: {
auto &d = w.c_wallPaperSolid();
} break;
void BackgroundBox::Inner::requestPapers() {
request(MTPaccount_GetWallPapers(
MTP_int(Auth().data().wallpapersHash())
)).done([=](const MTPaccount_WallPapers &result) {
if (Auth().data().updateWallpapers(result)) {
updatePapers();
}
}
App::cSetServerBackgrounds(wallpapers);
updateWallpapers();
}).send();
}
void BackgroundBox::Inner::updateWallpapers() {
_bgCount = App::cServerBackgrounds().size();
_rows = _bgCount / BackgroundsInRow;
if (_bgCount % BackgroundsInRow) ++_rows;
resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, _rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
for (int i = 0; i < BackgroundsInRow * 3; ++i) {
if (i >= _bgCount) break;
App::cServerBackgrounds()[i].thumb->load(Data::FileOrigin());
void BackgroundBox::Inner::sortPapers() {
const auto current = Window::Theme::Background()->id();
const auto night = Window::Theme::IsNightMode();
ranges::stable_sort(_papers, std::greater<>(), [&](const Paper &paper) {
const auto &data = paper.data;
return std::make_tuple(
data.id() == current,
night ? data.isDark() : !data.isDark(),
!data.isDefault() && !data.isLocal(),
!data.isDefault() && data.isLocal());
});
if (!_papers.empty() && _papers.front().data.id() == current) {
_papers.front().data = _papers.front().data.withParamsFrom(
Window::Theme::Background()->paper());
}
}
void BackgroundBox::Inner::updatePapers() {
_over = _overDown = Selection();
_papers = Auth().data().wallpapers(
) | ranges::view::filter([](const Data::WallPaper &paper) {
return !paper.isPattern() || paper.backgroundColor().has_value();
}) | ranges::view::transform([](const Data::WallPaper &paper) {
return Paper{ paper };
}) | ranges::to_vector;
sortPapers();
resizeToContentAndPreload();
}
void BackgroundBox::Inner::resizeToContentAndPreload() {
const auto count = _papers.size();
const auto rows = (count / kBackgroundsInRow)
+ (count % kBackgroundsInRow ? 1 : 0);
resize(st::boxWideWidth, rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
const auto preload = kBackgroundsInRow * 3;
for (const auto &paper : _papers | ranges::view::take(preload)) {
paper.data.loadThumbnail();
}
update();
}
void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
QRect r(e->rect());
Painter p(this);
if (_rows) {
for (int i = 0; i < _rows; ++i) {
if ((st::backgroundSize.height() + st::backgroundPadding) * (i + 1) <= r.top()) continue;
for (int j = 0; j < BackgroundsInRow; ++j) {
int index = i * BackgroundsInRow + j;
if (index >= _bgCount) break;
const auto &paper = App::cServerBackgrounds()[index];
paper.thumb->load(Data::FileOrigin());
int x = st::backgroundPadding + j * (st::backgroundSize.width() + st::backgroundPadding);
int y = st::backgroundPadding + i * (st::backgroundSize.height() + st::backgroundPadding);
const auto &pix = paper.thumb->pix(
Data::FileOrigin(),
st::backgroundSize.width(),
st::backgroundSize.height());
p.drawPixmap(x, y, pix);
if (paper.id == Window::Theme::Background()->id()) {
auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
_check->paint(p, getms(), checkLeft, checkTop, width());
}
}
}
} else {
if (_papers.empty()) {
p.setFont(st::noContactsFont);
p.setPen(st::noContactsColor);
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
return;
}
auto row = 0;
auto column = 0;
for (const auto &paper : _papers) {
const auto increment = gsl::finally([&] {
++column;
if (column == kBackgroundsInRow) {
column = 0;
++row;
}
});
if ((st::backgroundSize.height() + st::backgroundPadding) * (row + 1) <= r.top()) {
continue;
} else if ((st::backgroundSize.height() + st::backgroundPadding) * row >= r.top() + r.height()) {
break;
}
paintPaper(p, paper, column, row);
}
}
void BackgroundBox::Inner::validatePaperThumbnail(
const Paper &paper) const {
Expects(paper.data.thumbnail() != nullptr);
const auto thumbnail = paper.data.thumbnail();
if (!paper.thumbnail.isNull()) {
return;
} else if (!thumbnail->loaded()) {
thumbnail->load(paper.data.fileOrigin());
return;
}
auto original = thumbnail->original();
if (paper.data.isPattern()) {
const auto color = *paper.data.backgroundColor();
original = Data::PreparePatternImage(
std::move(original),
color,
Data::PatternColor(color),
paper.data.patternIntensity());
}
paper.thumbnail = App::pixmapFromImageInPlace(TakeMiddleSample(
original,
st::backgroundSize));
paper.thumbnail.setDevicePixelRatio(cRetinaFactor());
}
void BackgroundBox::Inner::paintPaper(
Painter &p,
const Paper &paper,
int column,
int row) const {
const auto x = st::backgroundPadding + column * (st::backgroundSize.width() + st::backgroundPadding);
const auto y = st::backgroundPadding + row * (st::backgroundSize.height() + st::backgroundPadding);
validatePaperThumbnail(paper);
if (!paper.thumbnail.isNull()) {
p.drawPixmap(x, y, paper.thumbnail);
}
const auto over = _overDown ? _overDown : _over;
if (paper.data.id() == Window::Theme::Background()->id()) {
const auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
const auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
_check->paint(p, crl::now(), checkLeft, checkTop, width());
} else if (Data::IsCloudWallPaper(paper.data)
&& !Data::IsDefaultWallPaper(paper.data)
&& over.has_value()
&& (&paper == &_papers[getSelectionIndex(over)])) {
const auto deleteSelected = over.is<DeleteSelected>();
const auto deletePos = QPoint(x + st::backgroundSize.width() - st::stickerPanDeleteIconBg.width(), y);
p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityBgOver : st::stickerPanDeleteOpacityBg);
st::stickerPanDeleteIconBg.paint(p, deletePos, width());
p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityFgOver : st::stickerPanDeleteOpacityFg);
st::stickerPanDeleteIconFg.paint(p, deletePos, width());
p.setOpacity(1.);
}
}
void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
int x = e->pos().x(), y = e->pos().y();
int row = int((y - st::backgroundPadding) / (st::backgroundSize.height() + st::backgroundPadding));
if (y - row * (st::backgroundSize.height() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.height()) row = _rows + 1;
int col = int((x - st::backgroundPadding) / (st::backgroundSize.width() + st::backgroundPadding));
if (x - col * (st::backgroundSize.width() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.width()) row = _rows + 1;
int newOver = row * BackgroundsInRow + col;
if (newOver >= _bgCount) newOver = -1;
if (newOver != _over) {
const auto newOver = [&] {
const auto x = e->pos().x();
const auto y = e->pos().y();
const auto width = st::backgroundSize.width();
const auto height = st::backgroundSize.height();
const auto skip = st::backgroundPadding;
const auto row = int((y - skip) / (height + skip));
const auto column = int((x - skip) / (width + skip));
const auto result = row * kBackgroundsInRow + column;
if (y - row * (height + skip) > skip + height) {
return Selection();
} else if (x - column * (width + skip) > skip + width) {
return Selection();
} else if (result >= _papers.size()) {
return Selection();
}
const auto deleteLeft = (column + 1) * (width + skip)
- st::stickerPanDeleteIconBg.width();
const auto deleteBottom = row * (height + skip) + skip
+ st::stickerPanDeleteIconBg.height();
const auto currentId = Window::Theme::Background()->id();
const auto inDelete = (x >= deleteLeft)
&& (y < deleteBottom)
&& Data::IsCloudWallPaper(_papers[result].data)
&& !Data::IsDefaultWallPaper(_papers[result].data)
&& (currentId != _papers[result].data.id());
return (result >= _papers.size())
? Selection()
: inDelete
? Selection(DeleteSelected{ result })
: Selection(Selected{ result });
}();
if (_over != newOver) {
repaintPaper(getSelectionIndex(_over));
_over = newOver;
setCursor((_over >= 0 || _overDown >= 0) ? style::cur_pointer : style::cur_default);
repaintPaper(getSelectionIndex(_over));
setCursor((_over.has_value() || _overDown.has_value())
? style::cur_pointer
: style::cur_default);
}
}
void BackgroundBox::Inner::repaintPaper(int index) {
if (index < 0 || index >= _papers.size()) {
return;
}
const auto row = (index / kBackgroundsInRow);
const auto column = (index % kBackgroundsInRow);
const auto width = st::backgroundSize.width();
const auto height = st::backgroundSize.height();
const auto skip = st::backgroundPadding;
update(
(width + skip) * column + skip,
(height + skip) * row + skip,
width,
height);
}
void BackgroundBox::Inner::mousePressEvent(QMouseEvent *e) {
_overDown = _over;
}
int BackgroundBox::Inner::getSelectionIndex(
const Selection &selection) const {
return selection.match([](const Selected &data) {
return data.index;
}, [](const DeleteSelected &data) {
return data.index;
}, [](std::nullopt_t) {
return -1;
});
}
void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
if (_overDown == _over && _over >= 0) {
if (_backgroundChosenCallback) {
_backgroundChosenCallback(_over);
if (base::take(_overDown) == _over && _over.has_value()) {
const auto index = getSelectionIndex(_over);
if (index >= 0 && index < _papers.size()) {
if (base::get_if<DeleteSelected>(&_over)) {
_backgroundRemove.fire_copy(_papers[index].data);
} else if (base::get_if<Selected>(&_over)) {
_backgroundChosen.fire_copy(_papers[index].data);
}
}
} else if (_over < 0) {
} else if (!_over.has_value()) {
setCursor(style::cur_default);
}
}
rpl::producer<Data::WallPaper> BackgroundBox::Inner::chooseEvents() const {
return _backgroundChosen.events();
}
auto BackgroundBox::Inner::removeRequests() const
-> rpl::producer<Data::WallPaper> {
return _backgroundRemove.events();
}
void BackgroundBox::Inner::removePaper(const Data::WallPaper &data) {
const auto i = ranges::find(
_papers,
data.id(),
[](const Paper &paper) { return paper.data.id(); });
if (i != end(_papers)) {
_papers.erase(i);
_over = _overDown = Selection();
resizeToContentAndPreload();
}
}
BackgroundBox::Inner::~Inner() = default;

View File

@@ -9,9 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
namespace Ui {
class RoundCheckbox;
} // namespace Ui
namespace Data {
class WallPaper;
} // namespace Data
class BackgroundBox : public BoxContent {
public:
@@ -21,9 +21,10 @@ protected:
void prepare() override;
private:
void backgroundChosen(int index);
class Inner;
void removePaper(const Data::WallPaper &paper);
QPointer<Inner> _inner;
};

View File

@@ -0,0 +1,796 @@
/*
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/background_preview_box.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "window/themes/window_theme.h"
#include "ui/toast/toast.h"
#include "ui/image/image.h"
#include "ui/widgets/checkbox.h"
#include "history/history.h"
#include "history/history_message.h"
#include "history/view/history_view_message.h"
#include "auth_session.h"
#include "apiwrap.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/data_document.h"
#include "boxes/confirm_box.h"
#include "boxes/background_preview_box.h"
#include "styles/style_history.h"
#include "styles/style_boxes.h"
namespace {
constexpr auto kMaxWallPaperSlugLength = 255;
class ServiceCheck : public Ui::AbstractCheckView {
public:
ServiceCheck(const style::ServiceCheck &st, bool checked);
QSize getSize() const override;
void paint(
Painter &p,
int left,
int top,
int outerWidth,
crl::time ms) override;
QImage prepareRippleMask() const override;
bool checkRippleStartPosition(QPoint position) const override;
private:
class Generator {
public:
Generator();
void paintFrame(
Painter &p,
int left,
int top,
not_null<const style::ServiceCheck*> st,
float64 toggled);
void invalidate();
private:
struct Frames {
QImage image;
std::vector<bool> ready;
};
not_null<Frames*> framesForStyle(
not_null<const style::ServiceCheck*> st);
static void FillFrame(
QImage &image,
not_null<const style::ServiceCheck*> st,
int index,
int count);
static void PaintFillingFrame(
Painter &p,
not_null<const style::ServiceCheck*> st,
float64 progress);
static void PaintCheckingFrame(
Painter &p,
not_null<const style::ServiceCheck*> st,
float64 progress);
base::flat_map<not_null<const style::ServiceCheck*>, Frames> _data;
rpl::lifetime _lifetime;
};
static Generator &Frames();
const style::ServiceCheck &_st;
};
ServiceCheck::Generator::Generator() {
*_lifetime.make_state<base::Subscription>() = Window::Theme::Background(
)->add_subscription([=](const Window::Theme::BackgroundUpdate &update) {
if (update.paletteChanged()) {
invalidate();
}
});
}
auto ServiceCheck::Generator::framesForStyle(
not_null<const style::ServiceCheck*> st) -> not_null<Frames*> {
if (const auto i = _data.find(st); i != _data.end()) {
return &i->second;
}
const auto result = &_data.emplace(st, Frames()).first->second;
const auto size = st->diameter;
const auto count = (st->duration / AnimationTimerDelta) + 2;
result->image = QImage(
QSize(count * size, size) * cIntRetinaFactor(),
QImage::Format_ARGB32_Premultiplied);
result->image.fill(Qt::transparent);
result->image.setDevicePixelRatio(cRetinaFactor());
result->ready.resize(count);
return result;
}
void ServiceCheck::Generator::FillFrame(
QImage &image,
not_null<const style::ServiceCheck*> st,
int index,
int count) {
Expects(count > 1);
Expects(index >= 0 && index < count);
Painter p(&image);
PainterHighQualityEnabler hq(p);
p.translate(index * st->diameter, 0);
const auto progress = index / float64(count - 1);
if (progress > 0.5) {
PaintCheckingFrame(p, st, (progress - 0.5) * 2);
} else {
PaintFillingFrame(p, st, progress * 2);
}
}
void ServiceCheck::Generator::PaintFillingFrame(
Painter &p,
not_null<const style::ServiceCheck*> st,
float64 progress) {
const auto shift = progress * st->shift;
p.setBrush(st->color);
p.setPen(Qt::NoPen);
p.drawEllipse(QRectF(
shift,
shift,
st->diameter - 2 * shift,
st->diameter - 2 * shift));
if (progress < 1.) {
const auto remove = progress * (st->diameter / 2. - st->thickness);
p.setCompositionMode(QPainter::CompositionMode_Source);
p.setPen(Qt::NoPen);
p.setBrush(Qt::transparent);
p.drawEllipse(QRectF(
st->thickness + remove,
st->thickness + remove,
st->diameter - 2 * (st->thickness + remove),
st->diameter - 2 * (st->thickness + remove)));
}
}
void ServiceCheck::Generator::PaintCheckingFrame(
Painter &p,
not_null<const style::ServiceCheck*> st,
float64 progress) {
const auto shift = (1. - progress) * st->shift;
p.setBrush(st->color);
p.setPen(Qt::NoPen);
p.drawEllipse(QRectF(
shift,
shift,
st->diameter - 2 * shift,
st->diameter - 2 * shift));
if (progress > 0.) {
const auto tip = QPointF(st->tip.x(), st->tip.y());
const auto left = tip - QPointF(st->small, st->small) * progress;
const auto right = tip - QPointF(-st->large, st->large) * progress;
p.setCompositionMode(QPainter::CompositionMode_Source);
p.setBrush(Qt::NoBrush);
auto pen = QPen(Qt::transparent);
pen.setWidth(st->stroke);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
p.setPen(pen);
auto path = QPainterPath();
path.moveTo(left);
path.lineTo(tip);
path.lineTo(right);
p.drawPath(path);
}
}
void ServiceCheck::Generator::paintFrame(
Painter &p,
int left,
int top,
not_null<const style::ServiceCheck*> st,
float64 toggled) {
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)));
Assert(index >= 0 && index < count);
if (!frames->ready[index]) {
frames->ready[index] = true;
FillFrame(image, st, index, count);
}
const auto size = st->diameter;
const auto part = size * cIntRetinaFactor();
p.drawImage(
QPoint(left, top),
image,
QRect(index * part, 0, part, part));
}
void ServiceCheck::Generator::invalidate() {
_data.clear();
}
ServiceCheck::Generator &ServiceCheck::Frames() {
static const auto Instance = Ui::CreateChild<Generator>(
QApplication::instance());
return *Instance;
}
ServiceCheck::ServiceCheck(
const style::ServiceCheck &st,
bool checked)
: AbstractCheckView(st.duration, checked, nullptr)
, _st(st) {
}
QSize ServiceCheck::getSize() const {
const auto inner = QRect(0, 0, _st.diameter, _st.diameter);
return inner.marginsAdded(_st.margin).size();
}
void ServiceCheck::paint(
Painter &p,
int left,
int top,
int outerWidth,
crl::time ms) {
Frames().paintFrame(
p,
left + _st.margin.left(),
top + _st.margin.top(),
&_st,
currentAnimationValue(ms));
}
QImage ServiceCheck::prepareRippleMask() const {
return QImage();
}
bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
return false;
}
[[nodiscard]] bool IsValidWallPaperSlug(const QString &slug) {
if (slug.isEmpty() || slug.size() > kMaxWallPaperSlugLength) {
return false;
}
return ranges::find_if(slug, [](QChar ch) {
return (ch != '.')
&& (ch != '_')
&& (ch != '-')
&& (ch < '0' || ch > '9')
&& (ch < 'a' || ch > 'z')
&& (ch < 'A' || ch > 'Z');
}) == slug.end();
}
AdminLog::OwnedItem GenerateTextItem(
not_null<HistoryView::ElementDelegate*> delegate,
not_null<History*> history,
const QString &text,
bool out) {
Expects(history->peer->isUser());
using Flag = MTPDmessage::Flag;
static auto id = ServerMaxMsgId + (ServerMaxMsgId / 3);
const auto flags = Flag::f_entities
| Flag::f_from_id
| (out ? Flag::f_out : Flag(0));
const auto replyTo = 0;
const auto viaBotId = 0;
const auto item = new HistoryMessage(
history,
++id,
flags,
replyTo,
viaBotId,
unixtime(),
out ? history->session().userId() : peerToUser(history->peer->id),
QString(),
TextWithEntities{ TextUtilities::Clean(text) });
return AdminLog::OwnedItem(delegate, item);
}
QImage PrepareScaledNonPattern(
const QImage &image,
Images::Option blur) {
const auto size = st::boxWideWidth;
const auto width = std::max(image.width(), 1);
const auto height = std::max(image.height(), 1);
const auto takeWidth = (width > height)
? (width * size / height)
: size;
const auto takeHeight = (width > height)
? size
: (height * size / width);
return Images::prepare(
image,
takeWidth * cIntRetinaFactor(),
takeHeight * cIntRetinaFactor(),
Images::Option::Smooth
| Images::Option::TransparentBackground
| blur,
size,
size);
}
QImage ColorizePattern(QImage image, QColor color) {
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
image = std::move(image).convertToFormat(
QImage::Format_ARGB32_Premultiplied);
}
// Similar to style::colorizeImage.
// But style::colorizeImage takes pattern with all pixels having the
// same components value, from (0, 0, 0, 0) to (255, 255, 255, 255).
//
// While in patterns we have different value ranges, usually they are
// from (0, 0, 0, 0) to (0, 0, 0, 255), so we should use only 'alpha'.
const auto width = image.width();
const auto height = image.height();
const auto pattern = anim::shifted(color);
const auto resultBytesPerPixel = (image.depth() >> 3);
constexpr auto resultIntsPerPixel = 1;
const auto resultIntsPerLine = (image.bytesPerLine() >> 2);
const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel;
auto resultInts = reinterpret_cast<uint32*>(image.bits());
Assert(resultIntsAdded >= 0);
Assert(image.depth() == static_cast<int>((resultIntsPerPixel * sizeof(uint32)) << 3));
Assert(image.bytesPerLine() == (resultIntsPerLine << 2));
const auto maskBytesPerPixel = (image.depth() >> 3);
const auto maskBytesPerLine = image.bytesPerLine();
const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel;
// We want to read the last byte of four available.
// This is the difference with style::colorizeImage.
auto maskBytes = image.constBits() + (maskBytesPerPixel - 1);
Assert(maskBytesAdded >= 0);
Assert(image.depth() == (maskBytesPerPixel << 3));
for (auto y = 0; y != height; ++y) {
for (auto x = 0; x != width; ++x) {
auto maskOpacity = static_cast<anim::ShiftedMultiplier>(*maskBytes) + 1;
*resultInts = anim::unshifted(pattern * maskOpacity);
maskBytes += maskBytesPerPixel;
resultInts += resultIntsPerPixel;
}
maskBytes += maskBytesAdded;
resultInts += resultIntsAdded;
}
return image;
}
QImage PrepareScaledFromFull(
const QImage &image,
std::optional<QColor> patternBackground,
Images::Option blur = Images::Option(0)) {
auto result = PrepareScaledNonPattern(image, blur);
if (patternBackground) {
result = ColorizePattern(
std::move(result),
Data::PatternColor(*patternBackground));
}
return std::move(result).convertToFormat(
QImage::Format_ARGB32_Premultiplied);
}
} // namespace
BackgroundPreviewBox::BackgroundPreviewBox(
QWidget*,
const Data::WallPaper &paper)
: _text1(GenerateTextItem(
delegate(),
Auth().data().history(peerFromUser(PeerData::kServiceNotificationsId)),
lang(lng_background_text1),
false))
, _text2(GenerateTextItem(
delegate(),
Auth().data().history(peerFromUser(PeerData::kServiceNotificationsId)),
lang(lng_background_text2),
true))
, _paper(paper)
, _radial(animation(this, &BackgroundPreviewBox::step_radial)) {
subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
}
not_null<HistoryView::ElementDelegate*> BackgroundPreviewBox::delegate() {
return static_cast<HistoryView::ElementDelegate*>(this);
}
void BackgroundPreviewBox::prepare() {
setTitle(langFactory(lng_background_header));
addButton(langFactory(lng_background_apply), [=] { apply(); });
addButton(langFactory(lng_cancel), [=] { closeBox(); });
if (_paper.hasShareUrl()) {
addLeftButton(langFactory(lng_background_share), [=] { share(); });
}
updateServiceBg(_paper.backgroundColor());
_paper.loadThumbnail();
_paper.loadDocument();
if (_paper.document() && _paper.document()->loading()) {
_radial.start(_paper.document()->progress());
}
if (_paper.thumbnail() && !_paper.isPattern()) {
createBlurCheckbox();
}
setScaledFromThumb();
checkLoadedDocument();
_text1->setDisplayDate(true);
_text1->initDimensions();
_text1->resizeGetHeight(st::boxWideWidth);
_text2->initDimensions();
_text2->resizeGetHeight(st::boxWideWidth);
setDimensions(st::boxWideWidth, st::boxWideWidth);
}
void BackgroundPreviewBox::createBlurCheckbox() {
_blur.create(
this,
lang(lng_background_blur),
st::backgroundCheckbox,
std::make_unique<ServiceCheck>(
st::backgroundCheck,
_paper.isBlurred()));
rpl::combine(
sizeValue(),
_blur->sizeValue()
) | rpl::start_with_next([=](QSize outer, QSize inner) {
_blur->move(
(outer.width() - inner.width()) / 2,
outer.height() - st::historyPaddingBottom - inner.height());
}, _blur->lifetime());
_blur->paintRequest(
) | rpl::filter([=] {
return _serviceBg.has_value();
}) | rpl::start_with_next([=] {
Painter p(_blur.data());
PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen);
p.setBrush(*_serviceBg);
p.drawRoundedRect(
_blur->rect(),
st::historyMessageRadius,
st::historyMessageRadius);
}, _blur->lifetime());
_blur->checkedChanges(
) | rpl::start_with_next([=](bool checked) {
checkBlurAnimationStart();
update();
}, lifetime());
_blur->setDisabled(true);
}
void BackgroundPreviewBox::apply() {
const auto install = (_paper.id() != Window::Theme::Background()->id())
&& Data::IsCloudWallPaper(_paper);
App::main()->setChatBackground(_paper, std::move(_full));
if (install) {
Auth().api().request(MTPaccount_InstallWallPaper(
_paper.mtpInput(),
_paper.mtpSettings()
)).send();
}
closeBox();
}
void BackgroundPreviewBox::share() {
QApplication::clipboard()->setText(_paper.shareUrl());
Ui::Toast::Show(lang(lng_background_link_copied));
}
void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto ms = crl::now();
const auto color = _paper.backgroundColor();
if (color) {
p.fillRect(e->rect(), *color);
}
if (!color || _paper.isPattern()) {
if (!_scaled.isNull() || setScaledFromThumb()) {
paintImage(p, ms);
paintRadial(p, ms);
} else if (!color) {
p.fillRect(e->rect(), st::boxBg);
return;
} else {
// Progress of pattern loading.
paintRadial(p, ms);
}
}
paintTexts(p, ms);
}
void BackgroundPreviewBox::paintImage(Painter &p, crl::time ms) {
Expects(!_scaled.isNull());
const auto master = _paper.isPattern()
? std::clamp(_paper.patternIntensity() / 100., 0., 1.)
: 1.;
const auto factor = cIntRetinaFactor();
const auto size = st::boxWideWidth;
const auto from = QRect(
0,
(size - height()) / 2 * factor,
size * factor,
height() * factor);
const auto guard = gsl::finally([&] { p.setOpacity(1.); });
const auto fade = _fadeIn.current(ms, 1.);
if (fade < 1. && !_fadeOutThumbnail.isNull()) {
p.drawPixmap(rect(), _fadeOutThumbnail, from);
}
const auto &pixmap = (!_blurred.isNull() && _paper.isBlurred())
? _blurred
: _scaled;
p.setOpacity(master * fade);
p.drawPixmap(rect(), pixmap, from);
checkBlurAnimationStart();
}
void BackgroundPreviewBox::paintRadial(Painter &p, crl::time ms) {
bool radial = false;
float64 radialOpacity = 0;
if (_radial.animating()) {
_radial.step(ms);
radial = _radial.animating();
radialOpacity = _radial.opacity();
}
if (!radial) {
return;
}
auto inner = radialRect();
p.setPen(Qt::NoPen);
p.setOpacity(radialOpacity);
p.setBrush(st::radialBg);
{
PainterHighQualityEnabler hq(p);
p.drawEllipse(inner);
}
p.setOpacity(1);
QRect arc(inner.marginsRemoved(QMargins(st::radialLine, st::radialLine, st::radialLine, st::radialLine)));
_radial.draw(p, arc, st::radialLine, st::radialFg);
}
int BackgroundPreviewBox::textsTop() const {
const auto bottom = _blur ? _blur->y() : height();
return bottom
- st::historyPaddingBottom
- _text1->height()
- _text2->height();
}
QRect BackgroundPreviewBox::radialRect() const {
const auto available = textsTop() - st::historyPaddingBottom;
return QRect(
QPoint(
(width() - st::radialSize.width()) / 2,
(available - st::radialSize.height()) / 2),
st::radialSize);
}
void BackgroundPreviewBox::paintTexts(Painter &p, crl::time ms) {
const auto height1 = _text1->height();
const auto height2 = _text2->height();
p.translate(0, textsTop());
paintDate(p);
_text1->draw(p, rect(), TextSelection(), ms);
p.translate(0, height1);
_text2->draw(p, rect(), TextSelection(), ms);
p.translate(0, height2);
}
void BackgroundPreviewBox::paintDate(Painter &p) {
const auto date = _text1->Get<HistoryView::DateBadge>();
if (!date || !_serviceBg) {
return;
}
const auto text = date->text;
const auto bubbleHeight = st::msgServicePadding.top() + st::msgServiceFont->height + st::msgServicePadding.bottom();
const auto bubbleTop = st::msgServiceMargin.top();
const auto textWidth = st::msgServiceFont->width(text);
const auto bubbleWidth = st::msgServicePadding.left() + textWidth + st::msgServicePadding.right();
const auto bubbleLeft = (width() - bubbleWidth) / 2;
const auto radius = bubbleHeight / 2;
p.setPen(Qt::NoPen);
p.setBrush(*_serviceBg);
p.drawRoundedRect(bubbleLeft, bubbleTop, bubbleWidth, bubbleHeight, radius, radius);
p.setPen(st::msgServiceFg);
p.setFont(st::msgServiceFont);
p.drawText(bubbleLeft + st::msgServicePadding.left(), bubbleTop + st::msgServicePadding.top() + st::msgServiceFont->ascent, text);
}
void BackgroundPreviewBox::step_radial(crl::time ms, bool timer) {
Expects(_paper.document() != nullptr);
const auto document = _paper.document();
const auto wasAnimating = _radial.animating();
const auto updated = _radial.update(
document->progress(),
!document->loading(),
ms);
if (timer
&& (wasAnimating || _radial.animating())
&& (!anim::Disabled() || updated)) {
update(radialRect());
}
checkLoadedDocument();
}
bool BackgroundPreviewBox::setScaledFromThumb() {
const auto thumbnail = _paper.thumbnail();
if (!thumbnail || !thumbnail->loaded()) {
return false;
} else if (_paper.isPattern() && _paper.document() != nullptr) {
return false;
}
auto scaled = PrepareScaledFromFull(
thumbnail->original(),
patternBackgroundColor(),
_paper.document() ? Images::Option::Blurred : Images::Option(0));
auto blurred = (_paper.document() || _paper.isPattern())
? QImage()
: PrepareScaledNonPattern(
Data::PrepareBlurredBackground(thumbnail->original()),
Images::Option(0));
setScaledFromImage(std::move(scaled), std::move(blurred));
return true;
}
void BackgroundPreviewBox::setScaledFromImage(
QImage &&image,
QImage &&blurred) {
updateServiceBg(Window::Theme::CountAverageColor(image));
if (!_full.isNull()) {
startFadeInFrom(std::move(_scaled));
}
_scaled = App::pixmapFromImageInPlace(std::move(image));
_blurred = App::pixmapFromImageInPlace(std::move(blurred));
if (_blur && (!_paper.document() || !_full.isNull())) {
_blur->setDisabled(false);
}
}
void BackgroundPreviewBox::startFadeInFrom(QPixmap previous) {
_fadeOutThumbnail = std::move(previous);
_fadeIn.start([=] { update(); }, 0., 1., st::backgroundCheck.duration);
}
void BackgroundPreviewBox::checkBlurAnimationStart() {
if (_fadeIn.animating()
|| _blurred.isNull()
|| !_blur
|| _paper.isBlurred() == _blur->checked()) {
return;
}
_paper = _paper.withBlurred(_blur->checked());
startFadeInFrom(_paper.isBlurred() ? _scaled : _blurred);
}
void BackgroundPreviewBox::updateServiceBg(std::optional<QColor> background) {
if (background) {
_serviceBg = Window::Theme::AdjustedColor(
st::msgServiceBg->c,
*background);
}
}
std::optional<QColor> BackgroundPreviewBox::patternBackgroundColor() const {
return _paper.isPattern() ? _paper.backgroundColor() : std::nullopt;
}
void BackgroundPreviewBox::checkLoadedDocument() {
const auto document = _paper.document();
if (!_full.isNull()
|| !document
|| !document->loaded(DocumentData::FilePathResolve::Checked)
|| _generating) {
return;
}
const auto generateCallback = [=](QImage &&image) {
auto [left, right] = base::make_binary_guard();
_generating = std::move(left);
crl::async([
this,
image = std::move(image),
patternBackground = patternBackgroundColor(),
guard = std::move(right)
]() mutable {
auto scaled = PrepareScaledFromFull(image, patternBackground);
const auto ms = crl::now();
auto blurred = patternBackground
? QImage()
: PrepareScaledNonPattern(
Data::PrepareBlurredBackground(image),
Images::Option(0));
crl::on_main(std::move(guard), [
this,
image = std::move(image),
scaled = std::move(scaled),
blurred = std::move(blurred)
]() mutable {
_full = std::move(image);
setScaledFromImage(std::move(scaled), std::move(blurred));
update();
});
});
};
_generating = Data::ReadImageAsync(
document,
Window::Theme::ProcessBackgroundImage,
generateCallback);
}
bool BackgroundPreviewBox::Start(
const QString &slug,
const QMap<QString, QString> &params) {
if (const auto paper = Data::WallPaper::FromColorSlug(slug)) {
Ui::show(Box<BackgroundPreviewBox>(paper->withUrlParams(params)));
return true;
}
if (!IsValidWallPaperSlug(slug)) {
Ui::show(Box<InformBox>(lang(lng_background_bad_link)));
return false;
}
Auth().api().requestWallPaper(slug, [=](const Data::WallPaper &result) {
Ui::show(Box<BackgroundPreviewBox>(result.withUrlParams(params)));
}, [](const RPCError &error) {
Ui::show(Box<InformBox>(lang(lng_background_bad_link)));
});
return true;
}
HistoryView::Context BackgroundPreviewBox::elementContext() {
return HistoryView::Context::ContactPreview;
}
std::unique_ptr<HistoryView::Element> BackgroundPreviewBox::elementCreate(
not_null<HistoryMessage*> message) {
return std::make_unique<HistoryView::Message>(delegate(), message);
}
std::unique_ptr<HistoryView::Element> BackgroundPreviewBox::elementCreate(
not_null<HistoryService*> message) {
Unexpected("Service message in BackgroundPreviewBox.");
}
bool BackgroundPreviewBox::elementUnderCursor(
not_null<const Element*> view) {
return false;
}
void BackgroundPreviewBox::elementAnimationAutoplayAsync(
not_null<const Element*> element) {
}
crl::time BackgroundPreviewBox::elementHighlightTime(
not_null<const Element*> element) {
return crl::time(0);
}
bool BackgroundPreviewBox::elementInSelectionMode() {
return false;
}

View File

@@ -0,0 +1,81 @@
/*
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/binary_guard.h"
#include "window/themes/window_theme.h"
#include "history/admin_log/history_admin_log_item.h"
#include "history/view/history_view_element.h"
#include "ui/effects/radial_animation.h"
namespace Ui {
class Checkbox;
} // namespace Ui
class BackgroundPreviewBox
: public BoxContent
, private HistoryView::ElementDelegate {
public:
BackgroundPreviewBox(QWidget*, const Data::WallPaper &paper);
static bool Start(
const QString &slug,
const QMap<QString, QString> &params);
protected:
void prepare() override;
void paintEvent(QPaintEvent *e) override;
private:
using Element = HistoryView::Element;
not_null<HistoryView::ElementDelegate*> delegate();
HistoryView::Context elementContext() override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryService*> message) override;
bool elementUnderCursor(not_null<const Element*> view) override;
void elementAnimationAutoplayAsync(
not_null<const Element*> element) override;
crl::time elementHighlightTime(
not_null<const Element*> element) override;
bool elementInSelectionMode() override;
void apply();
void share();
void step_radial(crl::time ms, bool timer);
QRect radialRect() const;
void checkLoadedDocument();
bool setScaledFromThumb();
void setScaledFromImage(QImage &&image, QImage &&blurred);
void updateServiceBg(std::optional<QColor> background);
std::optional<QColor> patternBackgroundColor() const;
void paintImage(Painter &p, crl::time ms);
void paintRadial(Painter &p, crl::time ms);
void paintTexts(Painter &p, crl::time ms);
void paintDate(Painter &p);
void createBlurCheckbox();
int textsTop() const;
void startFadeInFrom(QPixmap previous);
void checkBlurAnimationStart();
AdminLog::OwnedItem _text1;
AdminLog::OwnedItem _text2;
Data::WallPaper _paper;
QImage _full;
QPixmap _scaled, _blurred, _fadeOutThumbnail;
Animation _fadeIn;
Ui::RadialAnimation _radial;
base::binary_guard _generating;
std::optional<QColor> _serviceBg;
object_ptr<Ui::Checkbox> _blur = { nullptr };
};

View File

@@ -13,6 +13,19 @@ using "intro/intro.style";
boxDuration: 200;
boxRadius: 3px;
ServiceCheck {
margin: margins;
diameter: pixels;
shift: pixels;
thickness: pixels;
tip: point;
small: pixels;
large: pixels;
stroke: pixels;
color: color;
duration: int;
}
boxButtonFont: font(boxFontSize semibold);
defaultBoxButton: RoundButton(defaultLightButton) {
width: -24px;
@@ -69,7 +82,7 @@ boxTitle: FlatLabel(defaultFlatLabel) {
linkFontOver: font(17px semibold underline);
}
}
boxTitlePosition: point(23px, 20px);
boxTitlePosition: point(23px, 16px);
boxTitleHeight: 56px;
boxLayerTitlePosition: point(23px, 16px);
boxLayerTitleHeight: 56px;
@@ -533,6 +546,10 @@ aboutLabel: FlatLabel(defaultFlatLabel) {
autoDownloadTopDelta: 10px;
autoDownloadTitlePosition: point(23px, 18px);
autoDownloadTitleFont: font(15px semibold);
autoDownloadLimitSlider: MediaSlider(defaultContinuousSlider) {
seekSize: size(15px, 15px);
}
autoDownloadLimitPadding: margins(22px, 8px, 22px, 8px);
confirmCaptionArea: InputField(defaultInputField) {
textMargins: margins(1px, 26px, 31px, 4px);
@@ -688,6 +705,7 @@ rightsCheckbox: Checkbox(defaultBoxCheckbox) {
rightsToggle: Toggle(defaultToggle) {
toggledFg: windowBgActive;
untoggledFg: attentionButtonFg;
lockIcon: icon {{ "info_rights_lock", windowBgActive }};
xsize: 8px;
vsize: 5px;
vshift: 1px;
@@ -695,7 +713,8 @@ rightsToggle: Toggle(defaultToggle) {
duration: 120;
}
rightsDividerHeight: 10px;
rightsHeaderMargin: margins(23px, 20px, 23px, 8px);
rightsDividerMargin: margins(0px, 0px, 0px, 20px);
rightsHeaderMargin: margins(23px, 0px, 23px, 8px);
rightsToggleMargin: margins(23px, 8px, 23px, 8px);
rightsAboutMargin: margins(23px, 8px, 23px, 8px);
rightsPhotoButton: UserpicButton(defaultUserpicButton) {
@@ -718,7 +737,7 @@ rightsHeaderLabel: FlatLabel(boxLabel) {
}
textFg: windowActiveTextFg;
}
rightsUntilMargin: margins(0px, 8px, 0px, 0px);
rightsUntilMargin: margins(0px, 8px, 0px, 20px);
mutePhotoButton: UserpicButton(defaultUserpicButton) {
size: size(40px, 40px);
@@ -834,3 +853,100 @@ themesScroll: ScrollArea(defaultScrollArea) {
bottomsh: 0px;
topsh: 0px;
}
createPollField: InputField(defaultInputField) {
font: boxTextFont;
textMargins: margins(0px, 0px, 0px, 0px);
textAlign: align(left);
heightMin: 36px;
heightMax: 86px;
placeholderFg: placeholderFg;
placeholderFgActive: placeholderFgActive;
placeholderFgError: placeholderFgActive;
placeholderMargins: margins(2px, 0px, 2px, 0px);
placeholderAlign: align(topleft);
placeholderScale: 0.;
placeholderFont: boxTextFont;
placeholderShift: -50px;
border: 0px;
borderActive: 0px;
duration: 100;
}
createPollFieldPadding: margins(22px, 5px, 22px, 5px);
createPollOptionField: InputField(createPollField) {
textMargins: margins(22px, 8px, 40px, 8px);
placeholderMargins: margins(2px, 0px, 2px, 0px);
heightMax: 64px;
}
createPollLimitLabel: FlatLabel(defaultFlatLabel) {
minWidth: 274px;
align: align(topleft);
}
createPollLimitPadding: margins(22px, 10px, 22px, 5px);
createPollOptionRemove: CrossButton {
width: 22px;
height: 22px;
cross: CrossAnimation {
size: 22px;
skip: 6px;
stroke: 1px;
minScale: 0.3;
}
crossFg: boxTitleCloseFg;
crossFgOver: boxTitleCloseFgOver;
crossPosition: point(0px, 0px);
duration: 150;
loadingPeriod: 1000;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}
createPollOptionRemovePosition: point(10px, 7px);
createPollWarning: FlatLabel(defaultFlatLabel) {
textFg: windowSubTextFg;
palette: TextPalette(defaultTextPalette) {
linkFg: boxTextFgError;
}
}
createPollWarningPosition: point(16px, 6px);
callSettingsButton: IconButton {
width: 50px;
height: boxLayerTitleHeight;
icon: icon {{ "menu_settings", boxTitleCloseFg }};
iconOver: icon {{ "menu_settings", boxTitleCloseFgOver }};
iconPosition: point(8px, -1px);
rippleAreaSize: 44px;
rippleAreaPosition: point(0px, 6px);
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}
backgroundCheckbox: Checkbox(defaultCheckbox) {
textFg: msgServiceFg;
textFgActive: msgServiceFg;
width: -50px;
margin: margins(0px, 0px, 0px, 0px);
textPosition: point(0px, 8px);
checkPosition: point(0px, 0px);
style: semiboldTextStyle;
}
backgroundCheck: ServiceCheck {
margin: margins(12px, 8px, 8px, 8px);
diameter: 18px;
shift: 2px;
thickness: 2px;
tip: point(7px, 13px);
small: 3px;
large: 6px;
stroke: 2px;
color: msgServiceFg;
duration: 200;
}

View File

@@ -286,7 +286,7 @@ int CalendarBox::Inner::rowsTop() const {
void CalendarBox::Inner::paintRows(Painter &p, QRect clip) {
p.setFont(st::calendarDaysFont);
auto ms = getms();
auto ms = crl::now();
auto y = rowsTop();
auto index = -_context->daysShift();
auto highlightedIndex = _context->highlightedIndex();
@@ -495,16 +495,8 @@ void CalendarBox::setMaxDate(QDate date) {
}
void CalendarBox::prepare() {
_previous->setClickedCallback([this] {
if (isPreviousEnabled()) {
_context->skipMonth(-1);
}
});
_next->setClickedCallback([this] {
if (isNextEnabled()) {
_context->skipMonth(1);
}
});
_previous->setClickedCallback([this] { goPreviousMonth(); });
_next->setClickedCallback([this] { goNextMonth(); });
// _inner = setInnerWidget(object_ptr<Inner>(this, _context.get()), st::calendarScroll, st::calendarTitleHeight);
_inner->setDateChosenCallback(std::move(_callback));
@@ -528,6 +520,18 @@ bool CalendarBox::isNextEnabled() const {
return (_context->maxDayIndex() >= _context->daysCount());
}
void CalendarBox::goPreviousMonth() {
if (isPreviousEnabled()) {
_context->skipMonth(-1);
}
}
void CalendarBox::goNextMonth() {
if (isNextEnabled()) {
_context->skipMonth(1);
}
}
void CalendarBox::monthChanged(QDate month) {
setDimensions(_st.width, st::calendarTitleHeight + _inner->countHeight());
auto previousEnabled = isPreviousEnabled();
@@ -548,4 +552,14 @@ void CalendarBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
}
void CalendarBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) {
e->ignore();
} else if (e->key() == Qt::Key_Left) {
goPreviousMonth();
} else if (e->key() == Qt::Key_Right) {
goNextMonth();
}
}
CalendarBox::~CalendarBox() = default;

View File

@@ -42,6 +42,7 @@ public:
protected:
void prepare() override;
void keyPressEvent(QKeyEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
private:
@@ -50,6 +51,9 @@ private:
bool isPreviousEnabled() const;
bool isNextEnabled() const;
void goPreviousMonth();
void goNextMonth();
const style::CalendarSizes &_st;
class Context;

View File

@@ -8,13 +8,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/change_phone_box.h"
#include "lang/lang_keys.h"
#include "styles/style_boxes.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/input_fields.h"
#include "ui/wrap/fade_wrap.h"
#include "boxes/confirm_phone_box.h"
#include "ui/toast/toast.h"
#include "boxes/confirm_box.h"
#include "auth_session.h"
#include "data/data_session.h"
#include "styles/style_boxes.h"
namespace {
@@ -144,11 +146,19 @@ void ChangePhoneBox::EnterPhone::submit() {
hideError();
auto phoneNumber = _phone->getLastText().trimmed();
_requestId = MTP::send(MTPaccount_SendChangePhoneCode(MTP_flags(0), MTP_string(phoneNumber), MTP_bool(false)), rpcDone(crl::guard(this, [this, phoneNumber](const MTPauth_SentCode &result) {
return sendPhoneDone(phoneNumber, result);
})), rpcFail(crl::guard(this, [this, phoneNumber](const RPCError &error) {
return sendPhoneFail(phoneNumber, error);
})));
_requestId = MTP::send(
MTPaccount_SendChangePhoneCode(
MTP_string(phoneNumber),
MTP_codeSettings(
MTP_flags(0),
MTPstring())),
rpcDone(crl::guard(this, [=](
const MTPauth_SentCode &result) {
return sendPhoneDone(phoneNumber, result);
})), rpcFail(crl::guard(this, [=](
const RPCError &error) {
return sendPhoneFail(phoneNumber, error);
})));
}
void ChangePhoneBox::EnterPhone::sendPhoneDone(const QString &phoneNumber, const MTPauth_SentCode &result) {
@@ -260,7 +270,7 @@ void ChangePhoneBox::EnterCode::submit() {
MTP_string(_hash),
MTP_string(code)
), rpcDone([weak = make_weak(this)](const MTPUser &result) {
App::feedUser(result);
Auth().data().processUser(result);
if (weak) {
Ui::hideLayer();
}

View File

@@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwidget.h"
#include "mainwindow.h"
#include "apiwrap.h"
#include "application.h"
#include "history/history.h"
#include "history/history_item.h"
#include "ui/widgets/checkbox.h"
@@ -23,42 +22,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "ui/empty_userpic.h"
#include "core/click_handler_types.h"
#include "window/window_controller.h"
#include "storage/localstorage.h"
#include "data/data_session.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "auth_session.h"
#include "observer_peer.h"
namespace {
void ConvertToSupergroupDone(const MTPUpdates &updates) {
Auth().api().applyUpdates(updates);
auto handleChats = [](const MTPVector<MTPChat> &chats) {
for (const auto &chat : chats.v) {
if (chat.type() == mtpc_channel) {
const auto channel = App::channel(chat.c_channel().vid.v);
Ui::showPeerHistory(channel, ShowAtUnreadMsgId);
Auth().api().requestParticipantsCountDelayed(channel);
}
}
};
switch (updates.type()) {
case mtpc_updates:
handleChats(updates.c_updates().vchats);
break;
case mtpc_updatesCombined:
handleChats(updates.c_updatesCombined().vchats);
break;
default:
LOG(("API Error: unexpected update cons %1 "
"(ConvertToSupergroupBox::convertDone)").arg(updates.type()));
break;
}
}
} // namespace
TextParseOptions _confirmBoxTextOptions = {
TextParseLinks | TextParseMultiline | TextParseRichText, // flags
0, // maxw
@@ -66,7 +38,11 @@ TextParseOptions _confirmBoxTextOptions = {
Qt::LayoutDirectionAuto, // dir
};
ConfirmBox::ConfirmBox(QWidget*, const QString &text, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
FnMut<void()> confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(lang(lng_box_ok))
, _cancelText(lang(lng_cancel))
, _confirmStyle(st::defaultBoxButton)
@@ -76,7 +52,12 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, FnMut<void()> confirmedCal
init(text);
}
ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
FnMut<void()> confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(lang(lng_cancel))
, _confirmStyle(st::defaultBoxButton)
@@ -86,7 +67,12 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText
init(text);
}
ConfirmBox::ConfirmBox(QWidget*, const TextWithEntities &text, const QString &confirmText, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
ConfirmBox::ConfirmBox(
QWidget*,
const TextWithEntities &text,
const QString &confirmText,
FnMut<void()> confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(lang(lng_cancel))
, _confirmStyle(st::defaultBoxButton)
@@ -96,7 +82,13 @@ ConfirmBox::ConfirmBox(QWidget*, const TextWithEntities &text, const QString &co
init(text);
}
ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const style::RoundButton &confirmStyle,
FnMut<void()> confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(lang(lng_cancel))
, _confirmStyle(confirmStyle)
@@ -106,7 +98,13 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText
init(text);
}
ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const QString &cancelText, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const QString &cancelText,
FnMut<void()> confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(cancelText)
, _confirmStyle(st::defaultBoxButton)
@@ -116,7 +114,14 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText
init(text);
}
ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, const QString &cancelText, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
ConfirmBox::ConfirmBox(
QWidget*,
const QString &text,
const QString &confirmText,
const style::RoundButton &confirmStyle,
const QString &cancelText,
FnMut<void()> confirmedCallback,
FnMut<void()> cancelledCallback)
: _confirmText(confirmText)
, _cancelText(cancelText)
, _confirmStyle(st::defaultBoxButton)
@@ -126,7 +131,11 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText
init(text);
}
ConfirmBox::ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, Fn<void()> closedCallback)
ConfirmBox::ConfirmBox(
const InformBoxTag &,
const QString &text,
const QString &doneText,
Fn<void()> closedCallback)
: _confirmText(doneText)
, _confirmStyle(st::defaultBoxButton)
, _informative(true)
@@ -136,7 +145,11 @@ ConfirmBox::ConfirmBox(const InformBoxTag &, const QString &text, const QString
init(text);
}
ConfirmBox::ConfirmBox(const InformBoxTag &, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback)
ConfirmBox::ConfirmBox(
const InformBoxTag &,
const TextWithEntities &text,
const QString &doneText,
Fn<void()> closedCallback)
: _confirmText(doneText)
, _confirmStyle(st::defaultBoxButton)
, _informative(true)
@@ -146,8 +159,9 @@ ConfirmBox::ConfirmBox(const InformBoxTag &, const TextWithEntities &text, const
init(text);
}
FnMut<void()> ConfirmBox::generateInformCallback(Fn<void()> closedCallback) {
return crl::guard(this, [this, closedCallback] {
FnMut<void()> ConfirmBox::generateInformCallback(
Fn<void()> closedCallback) {
return crl::guard(this, [=] {
closeBox();
if (closedCallback) {
closedCallback();
@@ -156,7 +170,10 @@ FnMut<void()> ConfirmBox::generateInformCallback(Fn<void()> closedCallback) {
}
void ConfirmBox::init(const QString &text) {
_text.setText(st::boxLabelStyle, text, _informative ? _confirmBoxTextOptions : _textPlainOptions);
_text.setText(
st::boxLabelStyle,
text,
_informative ? _confirmBoxTextOptions : _textPlainOptions);
}
void ConfirmBox::init(const TextWithEntities &text) {
@@ -164,9 +181,14 @@ void ConfirmBox::init(const TextWithEntities &text) {
}
void ConfirmBox::prepare() {
addButton([this] { return _confirmText; }, [this] { confirmed(); }, _confirmStyle);
addButton(
[=] { return _confirmText; },
[=] { confirmed(); },
_confirmStyle);
if (!_informative) {
addButton([this] { return _cancelText; }, [this] { _cancelled = true; closeBox(); });
addButton(
[=] { return _cancelText; },
[=] { _cancelled = true; closeBox(); });
}
boxClosing() | rpl::start_with_next([=] {
@@ -318,7 +340,7 @@ void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
mouseMoveEvent(e);
if (_linkOver) {
if (_channel->inviteLink().isEmpty()) {
Auth().api().exportInviteLink(_channel);
_channel->session().api().exportInviteLink(_channel);
} else {
QGuiApplication::clipboard()->setText(_channel->inviteLink());
Ui::Toast::Show(lang(lng_create_channel_link_copied));
@@ -363,65 +385,6 @@ void MaxInviteBox::resizeEvent(QResizeEvent *e) {
_invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height);
}
ConvertToSupergroupBox::ConvertToSupergroupBox(QWidget*, ChatData *chat)
: _chat(chat)
, _text(100)
, _note(100) {
}
void ConvertToSupergroupBox::prepare() {
QStringList text;
text.push_back(lang(lng_profile_convert_feature1));
text.push_back(lang(lng_profile_convert_feature2));
text.push_back(lang(lng_profile_convert_feature3));
text.push_back(lang(lng_profile_convert_feature4));
setTitle(langFactory(lng_profile_convert_title));
addButton(langFactory(lng_profile_convert_confirm), [this] { convertToSupergroup(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); });
_text.setText(st::boxLabelStyle, text.join('\n'), _confirmBoxTextOptions);
_note.setText(st::boxLabelStyle, lng_profile_convert_warning(lt_bold_start, textcmdStartSemibold(), lt_bold_end, textcmdStopSemibold()), _confirmBoxTextOptions);
_textWidth = st::boxWideWidth - st::boxPadding.left() - st::boxButtonPadding.right();
_textHeight = _text.countHeight(_textWidth);
setDimensions(st::boxWideWidth, _textHeight + st::boxPadding.bottom() + _note.countHeight(_textWidth));
}
void ConvertToSupergroupBox::convertToSupergroup() {
MTP::send(MTPmessages_MigrateChat(_chat->inputChat), rpcDone(&ConvertToSupergroupBox::convertDone), rpcFail(&ConvertToSupergroupBox::convertFail));
}
void ConvertToSupergroupBox::convertDone(const MTPUpdates &updates) {
Ui::hideLayer();
ConvertToSupergroupDone(updates);
}
bool ConvertToSupergroupBox::convertFail(const RPCError &error) {
if (MTP::isDefaultHandledError(error)) return false;
Ui::hideLayer();
return true;
}
void ConvertToSupergroupBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
convertToSupergroup();
} else {
BoxContent::keyPressEvent(e);
}
}
void ConvertToSupergroupBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
Painter p(this);
// draw box title / text
p.setPen(st::boxTextFg);
_text.drawLeft(p, st::boxPadding.left(), 0, _textWidth, width());
_note.drawLeft(p, st::boxPadding.left(), _textHeight + st::boxPadding.bottom(), _textWidth, width());
}
PinMessageBox::PinMessageBox(
QWidget*,
not_null<PeerData*> peer,
@@ -479,7 +442,7 @@ void PinMessageBox::pinMessage() {
}
void PinMessageBox::pinDone(const MTPUpdates &updates) {
Auth().api().applyUpdates(updates);
_peer->session().api().applyUpdates(updates);
Ui::hideLayer();
}
@@ -493,8 +456,7 @@ DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<HistoryItem*> item,
bool suggestModerateActions)
: _ids(1, item->fullId())
, _singleItem(true) {
: _ids(1, item->fullId()) {
if (suggestModerateActions) {
_moderateBan = item->suggestBanReport();
_moderateDeleteAll = item->suggestDeleteAllReport();
@@ -512,11 +474,54 @@ DeleteMessagesBox::DeleteMessagesBox(
Expects(!_ids.empty());
}
DeleteMessagesBox::DeleteMessagesBox(
QWidget*,
not_null<PeerData*> peer,
bool justClear)
: _wipeHistoryPeer(peer)
, _wipeHistoryJustClear(justClear) {
}
void DeleteMessagesBox::prepare() {
auto text = QString();
if (_moderateFrom) {
auto details = TextWithEntities();
const auto appendDetails = [&](TextWithEntities &&text) {
TextUtilities::Append(details, { "\n\n" });
TextUtilities::Append(details, std::move(text));
};
auto deleteKey = lng_box_delete;
auto deleteStyle = &st::defaultBoxButton;
if (const auto peer = _wipeHistoryPeer) {
if (_wipeHistoryJustClear) {
details.text = peer->isSelf()
? lang(lng_sure_delete_saved_messages)
: peer->isUser()
? lng_sure_delete_history(lt_contact, peer->name)
: lng_sure_delete_group_history(lt_group, peer->name);
deleteStyle = &st::attentionBoxButton;
} else {
details.text = peer->isSelf()
? lang(lng_sure_delete_saved_messages)
: peer->isUser()
? lng_sure_delete_history(lt_contact, peer->name)
: peer->isChat()
? lng_sure_delete_and_exit(lt_group, peer->name)
: lang(peer->isMegagroup()
? lng_sure_leave_group
: lng_sure_leave_channel);
deleteKey = _wipeHistoryPeer->isUser()
? lng_box_delete
: lng_box_leave;
deleteStyle = &(peer->isChannel()
? st::defaultBoxButton
: st::attentionBoxButton);
}
if (auto revoke = revokeText(peer)) {
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
appendDetails(std::move(revoke->description));
}
} else if (_moderateFrom) {
Assert(_moderateInChannel != nullptr);
text = lang(lng_selected_delete_sure_this);
details.text = lang(lng_selected_delete_sure_this);
if (_moderateBan) {
_banUser.create(this, lang(lng_ban_user), false, st::defaultBoxCheckbox);
}
@@ -525,49 +530,32 @@ void DeleteMessagesBox::prepare() {
_deleteAll.create(this, lang(lng_delete_all_from), false, st::defaultBoxCheckbox);
}
} else {
text = _singleItem ? lang(lng_selected_delete_sure_this) : lng_selected_delete_sure(lt_count, _ids.size());
auto canDeleteAllForEveryone = true;
auto now = unixtime();
auto deleteForUser = (UserData*)nullptr;
auto peer = (PeerData*)nullptr;
auto forEveryoneText = lang(lng_delete_for_everyone_check);
for (const auto fullId : std::as_const(_ids)) {
if (const auto item = App::histItemById(fullId)) {
peer = item->history()->peer;
if (!item->canDeleteForEveryone(now)) {
canDeleteAllForEveryone = false;
break;
} else if (auto user = item->history()->peer->asUser()) {
if (!deleteForUser || deleteForUser == user) {
deleteForUser = user;
forEveryoneText = lng_delete_for_other_check(
lt_user,
user->firstName);
} else {
forEveryoneText = lang(lng_delete_for_everyone_check);
}
details.text = (_ids.size() == 1)
? lang(lng_selected_delete_sure_this)
: lng_selected_delete_sure(lt_count, _ids.size());
if (const auto peer = checkFromSinglePeer()) {
auto count = int(_ids.size());
if (auto revoke = revokeText(peer)) {
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
appendDetails(std::move(revoke->description));
} else if (peer && peer->isChannel()) {
if (peer->isMegagroup()) {
appendDetails({ lng_delete_for_everyone_hint(lt_count, count) });
}
} else {
canDeleteAllForEveryone = false;
} else if (peer->isChat()) {
appendDetails({ lng_delete_for_me_chat_hint(lt_count, count) });
} else if (!peer->isSelf()) {
appendDetails({ lng_delete_for_me_hint(lt_count, count) });
}
}
auto count = int(_ids.size());
if (canDeleteAllForEveryone) {
_forEveryone.create(this, forEveryoneText, false, st::defaultBoxCheckbox);
} else if (peer && peer->isChannel()) {
if (peer->isMegagroup()) {
text += qsl("\n\n") + lng_delete_for_everyone_hint(lt_count, count);
}
} else if (peer->isChat()) {
text += qsl("\n\n") + lng_delete_for_me_chat_hint(lt_count, count);
} else if (!peer->isSelf()) {
text += qsl("\n\n") + lng_delete_for_me_hint(lt_count, count);
}
}
_text.create(this, text, Ui::FlatLabel::InitType::Simple, st::boxLabel);
_text.create(this, rpl::single(std::move(details)), st::boxLabel);
addButton(langFactory(lng_box_delete), [this] { deleteAndClear(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); });
addButton(
langFactory(deleteKey),
[=] { deleteAndClear(); },
*deleteStyle);
addButton(langFactory(lng_cancel), [=] { closeBox(); });
auto fullHeight = st::boxPadding.top() + _text->height() + st::boxPadding.bottom();
if (_moderateFrom) {
@@ -579,12 +567,112 @@ void DeleteMessagesBox::prepare() {
if (_deleteAll) {
fullHeight += st::boxLittleSkip + _deleteAll->heightNoMargins();
}
} else if (_forEveryone) {
fullHeight += st::boxMediumSkip + _forEveryone->heightNoMargins();
} else if (_revoke) {
fullHeight += st::boxMediumSkip + _revoke->heightNoMargins();
}
setDimensions(st::boxWidth, fullHeight);
}
PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
auto result = (PeerData*)nullptr;
for (const auto fullId : std::as_const(_ids)) {
if (const auto item = App::histItemById(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 = lng_delete_for_other_check(
lt_user,
user->firstName);
} else {
result.checkbox = lang(lng_delete_for_everyone_check);
}
return result;
}
const auto items = ranges::view::all(
_ids
) | ranges::view::transform([](FullMsgId id) {
return App::histItemById(id);
}) | ranges::view::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 = unixtime();
const auto canRevoke = [&](HistoryItem * item) {
return item->canDeleteForEveryone(now);
};
const auto cannotRevoke = [&](HistoryItem *item) {
return !item->canDeleteForEveryone(now);
};
const auto canRevokeAll = ranges::find_if(
items,
cannotRevoke
) == end(items);
auto outgoing = items | ranges::view::filter(&HistoryItem::out);
const auto canRevokeOutgoingCount = canRevokeAll
? -1
: ranges::count_if(outgoing, canRevoke);
if (canRevokeAll) {
if (const auto user = peer->asUser()) {
result.checkbox = lng_delete_for_other_check(
lt_user,
user->firstName);
} else {
result.checkbox = lang(lng_delete_for_everyone_check);
}
return result;
} else if (canRevokeOutgoingCount > 0) {
result.checkbox = lang(lng_delete_for_other_my);
if (const auto user = peer->asUser()) {
auto boldName = TextWithEntities{ user->firstName };
boldName.entities.push_back(
EntityInText(EntityInTextBold, 0, boldName.text.size()));
if (canRevokeOutgoingCount == 1) {
result.description = lng_selected_unsend_about_user_one__generic<TextWithEntities>(
lt_user,
boldName);
} else {
result.description = lng_selected_unsend_about_user__generic<TextWithEntities>(
lt_count,
canRevokeOutgoingCount,
lt_user,
boldName);
}
} else if (canRevokeOutgoingCount == 1) {
result.description = TextWithEntities{
lang(lng_selected_unsend_about_group_one) };
} else {
result.description = TextWithEntities{
lng_selected_unsend_about_group(
lt_count,
canRevokeOutgoingCount) };
}
return result;
}
return std::nullopt;
}
void DeleteMessagesBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
@@ -600,10 +688,10 @@ void DeleteMessagesBox::resizeEvent(QResizeEvent *e) {
if (_deleteAll) {
_deleteAll->moveToLeft(st::boxPadding.left(), top);
}
} else if (_forEveryone) {
auto availableWidth = width() - 2 * st::boxPadding.left();
_forEveryone->resizeToNaturalWidth(availableWidth);
_forEveryone->moveToLeft(st::boxPadding.left(), _text->bottomNoMargins() + st::boxMediumSkip);
} else if (_revoke) {
const auto availableWidth = width() - 2 * st::boxPadding.left();
_revoke->resizeToNaturalWidth(availableWidth);
_revoke->moveToLeft(st::boxPadding.left(), _text->bottomNoMargins() + st::boxMediumSkip);
}
}
@@ -616,22 +704,45 @@ void DeleteMessagesBox::keyPressEvent(QKeyEvent *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 {
const auto controller = App::wnd()->controller();
if (controller->activeChatCurrent().peer() == peer) {
Ui::showChatsList();
}
// 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()) {
Auth().api().kickParticipant(
_moderateInChannel->session().api().kickParticipant(
_moderateInChannel,
_moderateFrom,
MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
MTP_chatBannedRights(MTP_flags(0), MTP_int(0)));
}
if (_reportSpam->checked()) {
MTP::send(
_moderateInChannel->session().api().request(
MTPchannels_ReportSpam(
_moderateInChannel->inputChannel,
_moderateFrom->inputUser,
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg))));
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg)))
).send();
}
if (_deleteAll && _deleteAll->checked()) {
Auth().api().deleteAllFromUser(
_moderateInChannel->session().api().deleteAllFromUser(
_moderateInChannel,
_moderateFrom);
}
@@ -641,25 +752,25 @@ void DeleteMessagesBox::deleteAndClear() {
_deleteConfirmedCallback();
}
QMap<PeerData*, QVector<MTPint>> idsByPeer;
base::flat_map<not_null<PeerData*>, QVector<MTPint>> idsByPeer;
for (const auto itemId : _ids) {
if (auto item = App::histItemById(itemId)) {
auto history = item->history();
auto wasOnServer = (item->id > 0);
auto wasLast = (history->lastMessage() == item);
if (const auto item = App::histItemById(itemId)) {
const auto history = item->history();
const auto wasOnServer = IsServerMsgId(item->id);
const auto wasLast = (history->lastMessage() == item);
const auto wasInChats = (history->chatListMessage() == item);
item->destroy();
if (wasOnServer) {
idsByPeer[history->peer].push_back(MTP_int(itemId.msg));
} else if (wasLast && !history->lastMessageKnown()) {
Auth().api().requestDialogEntry(history);
} else if (wasLast || wasInChats) {
history->requestChatListMessage();
}
}
}
auto forEveryone = _forEveryone ? _forEveryone->checked() : false;
for (auto i = idsByPeer.cbegin(), e = idsByPeer.cend(); i != e; ++i) {
App::main()->deleteMessages(i.key(), i.value(), forEveryone);
for (const auto &[peer, ids] : idsByPeer) {
peer->session().api().deleteMessages(peer, ids, revoke);
}
Ui::hideLayer();
Auth().data().sendHistoryChangeNotifications();
@@ -724,7 +835,7 @@ std::vector<not_null<UserData*>> ConfirmInviteBox::GetParticipants(
auto result = std::vector<not_null<UserData*>>();
result.reserve(v.size());
for (const auto &participant : v) {
if (const auto user = App::feedUser(participant)) {
if (const auto user = Auth().data().processUser(participant)) {
result.push_back(user);
}
}

View File

@@ -119,27 +119,6 @@ private:
};
class ConvertToSupergroupBox : public BoxContent, public RPCSender {
public:
ConvertToSupergroupBox(QWidget*, ChatData *chat);
protected:
void prepare() override;
void keyPressEvent(QKeyEvent *e) override;
void paintEvent(QPaintEvent *e) override;
private:
void convertToSupergroup();
void convertDone(const MTPUpdates &updates);
bool convertFail(const RPCError &error);
ChatData *_chat;
Text _text, _note;
int32 _textWidth, _textHeight;
};
class PinMessageBox : public BoxContent, public RPCSender {
public:
PinMessageBox(QWidget*, not_null<PeerData*> peer, MsgId msgId);
@@ -172,6 +151,7 @@ public:
not_null<HistoryItem*> item,
bool suggestModerateActions);
DeleteMessagesBox(QWidget*, MessageIdsList &&selected);
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool justClear);
void setDeleteConfirmedCallback(Fn<void()> callback) {
_deleteConfirmedCallback = std::move(callback);
@@ -184,17 +164,24 @@ protected:
void keyPressEvent(QKeyEvent *e) override;
private:
struct RevokeConfig {
QString checkbox;
TextWithEntities description;
};
void deleteAndClear();
PeerData *checkFromSinglePeer() const;
std::optional<RevokeConfig> revokeText(not_null<PeerData*> peer) const;
PeerData * const _wipeHistoryPeer = nullptr;
const bool _wipeHistoryJustClear = false;
const MessageIdsList _ids;
const bool _singleItem = false;
UserData *_moderateFrom = nullptr;
ChannelData *_moderateInChannel = nullptr;
bool _moderateBan = false;
bool _moderateDeleteAll = false;
object_ptr<Ui::FlatLabel> _text = { nullptr };
object_ptr<Ui::Checkbox> _forEveryone = { 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 };

View File

@@ -170,7 +170,14 @@ void ConfirmPhoneBox::checkPhoneAndHash() {
if (_sendCodeRequestId) {
return;
}
_sendCodeRequestId = MTP::send(MTPaccount_SendConfirmPhoneCode(MTP_flags(0), MTP_string(_hash), MTPBool()), rpcDone(&ConfirmPhoneBox::sendCodeDone), rpcFail(&ConfirmPhoneBox::sendCodeFail));
_sendCodeRequestId = MTP::send(
MTPaccount_SendConfirmPhoneCode(
MTP_string(_hash),
MTP_codeSettings(
MTP_flags(0),
MTPstring())),
rpcDone(&ConfirmPhoneBox::sendCodeDone),
rpcFail(&ConfirmPhoneBox::sendCodeFail));
}
void ConfirmPhoneBox::sendCodeDone(const MTPauth_SentCode &result) {

View File

@@ -7,41 +7,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/connection_box.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "boxes/confirm_box.h"
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "base/qthelp_url.h"
#include "mainwidget.h"
#include "messenger.h"
#include "mainwindow.h"
#include "auth_session.h"
#include "data/data_session.h"
#include "mtproto/connection.h"
#include "core/application.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/toast/toast.h"
#include "ui/effects/radial_animation.h"
#include "ui/text_options.h"
#include "history/history_location_manager.h"
#include "settings/settings_common.h"
#include "application.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_info.h"
#include "styles/style_settings.h"
namespace {
constexpr auto kSaveSettingsDelayedTimeout = TimeMs(1000);
constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000);
class ProxyRow : public Ui::RippleButton {
public:
@@ -65,8 +52,8 @@ protected:
private:
void setupControls(View &&view);
int countAvailableWidth() const;
void step_radial(TimeMs ms, bool timer);
void paintCheck(Painter &p, TimeMs ms);
void step_radial(crl::time ms, bool timer);
void paintCheck(Painter &p, crl::time ms);
void showMenu();
View _view;
@@ -254,7 +241,7 @@ void ProxyRow::updateFields(View &&view) {
update();
}
void ProxyRow::step_radial(TimeMs ms, bool timer) {
void ProxyRow::step_radial(crl::time ms, bool timer) {
if (timer && !anim::Disabled()) {
update();
}
@@ -281,7 +268,7 @@ int ProxyRow::resizeGetHeight(int newWidth) {
void ProxyRow::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto ms = getms();
const auto ms = crl::now();
if (!_view.deleted) {
paintRipple(p, 0, 0, ms);
}
@@ -354,13 +341,13 @@ void ProxyRow::paintEvent(QPaintEvent *e) {
top += st::normalFont->height + st::proxyRowPadding.bottom();
}
void ProxyRow::paintCheck(Painter &p, TimeMs ms) {
void ProxyRow::paintCheck(Painter &p, crl::time ms) {
if (_progress) {
_progress->step(ms);
}
const auto loading = _progress
? _progress->computeState()
: Ui::InfiniteRadialAnimation::State{ 0., 0, FullArcLength };
: Ui::RadialState{ 0., 0, FullArcLength };
const auto toggled = _toggled.current(ms, _view.selected ? 1. : 0.)
* (1. - loading.shown);
const auto _st = &st::defaultRadio;
@@ -374,6 +361,7 @@ void ProxyRow::paintCheck(Painter &p, TimeMs ms) {
auto pen = anim::pen(_st->untoggledFg, _st->toggledFg, toggled * set);
pen.setWidth(_st->thickness);
pen.setCapStyle(Qt::RoundCap);
p.setPen(pen);
p.setBrush(_st->bg);
const auto rect = rtlrect(QRectF(left, top, _st->diameter, _st->diameter).marginsRemoved(QMarginsF(_st->thickness / 2., _st->thickness / 2., _st->thickness / 2., _st->thickness / 2.)), outerWidth);
@@ -936,102 +924,6 @@ void ProxyBox::addLabel(
} // namespace
AutoDownloadBox::AutoDownloadBox(QWidget *parent) {
}
void AutoDownloadBox::prepare() {
setupContent();
}
void AutoDownloadBox::setupContent() {
using namespace Settings;
setTitle(langFactory(lng_media_auto_title));
auto wrap = object_ptr<Ui::VerticalLayout>(this);
const auto content = wrap.data();
setInnerWidget(object_ptr<Ui::OverrideMargins>(
this,
std::move(wrap)));
using pair = std::pair<Ui::Checkbox*, Ui::Checkbox*>;
const auto pairValue = [](pair checkboxes) {
return (checkboxes.first->checked() ? 0 : dbiadNoPrivate)
| (checkboxes.second->checked() ? 0 : dbiadNoGroups);
};
const auto enabledSomething = [](int32 oldValue, int32 newValue) {
return (uint32(oldValue) & ~uint32(newValue)) != 0;
};
const auto addCheckbox = [&](int32 value, DBIAutoDownloadFlags flag) {
const auto label = (flag == dbiadNoPrivate)
? lng_media_auto_private_chats
: lng_media_auto_groups;
return content->add(
object_ptr<Ui::Checkbox>(
content,
lang(label),
!(value & flag),
st::settingsSendType),
st::settingsSendTypePadding);
};
const auto addPair = [&](int32 value) {
const auto first = addCheckbox(value, dbiadNoPrivate);
const auto second = addCheckbox(value, dbiadNoGroups);
return pair(first, second);
};
AddSubsectionTitle(content, lng_media_photo_title);
const auto photo = addPair(cAutoDownloadPhoto());
AddSkip(content);
AddSkip(content);
AddSubsectionTitle(content, lng_media_audio_title);
const auto audio = addPair(cAutoDownloadAudio());
AddSkip(content);
AddSkip(content);
AddSubsectionTitle(content, lng_media_gif_title);
const auto gif = addPair(cAutoDownloadGif());
AddSkip(content);
addButton(langFactory(lng_connection_save), [=] {
const auto photoValue = pairValue(photo);
const auto audioValue = pairValue(audio);
const auto gifValue = pairValue(gif);
const auto photosEnabled = enabledSomething(
cAutoDownloadPhoto(),
photoValue);
const auto audioEnabled = enabledSomething(
cAutoDownloadAudio(),
audioValue);
const auto gifEnabled = enabledSomething(
cAutoDownloadGif(),
gifValue);
const auto photosChanged = (cAutoDownloadPhoto() != photoValue);
const auto documentsChanged = (cAutoDownloadAudio() != audioValue)
|| (cAutoDownloadGif() != gifValue);
cSetAutoDownloadAudio(audioValue);
cSetAutoDownloadGif(gifValue);
cSetAutoDownloadPhoto(photoValue);
if (photosChanged || documentsChanged) {
Local::writeUserSettings();
}
if (photosEnabled) {
Auth().data().photoLoadSettingsChanged();
}
if (audioEnabled) {
Auth().data().voiceLoadSettingsChanged();
}
if (gifEnabled) {
Auth().data().animationLoadSettingsChanged();
}
closeBox();
});
addButton(langFactory(lng_cancel), [=] { closeBox(); });
setDimensionsToContent(st::boxWideWidth, content);
}
ProxiesBoxController::ProxiesBoxController()
: _saveTimer([] { Local::writeSettings(); }) {
_list = ranges::view::all(
@@ -1083,7 +975,7 @@ void ProxiesBoxController::ShowApplyConfirmation(
if (ranges::find(proxies, proxy) == end(proxies)) {
proxies.push_back(proxy);
}
Messenger::Instance().setCurrentProxy(
Core::App().setCurrentProxy(
proxy,
ProxyData::Settings::Enabled);
Local::writeSettings();
@@ -1106,7 +998,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
const auto type = (item.data.type == Type::Http)
? Variants::Http
: Variants::Tcp;
const auto mtproto = Messenger::Instance().mtp();
const auto mtproto = Core::App().mtp();
const auto dcId = mtproto->mainDcId();
item.state = ItemState::Checking;
@@ -1248,7 +1140,7 @@ void ProxiesBoxController::applyItem(int id) {
auto j = findByProxy(Global::SelectedProxy());
Messenger::Instance().setCurrentProxy(
Core::App().setCurrentProxy(
item->data,
ProxyData::Settings::Enabled);
saveDelayed();
@@ -1271,7 +1163,7 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
_lastSelectedProxy = base::take(Global::RefSelectedProxy());
if (Global::ProxySettings() == ProxyData::Settings::Enabled) {
_lastSelectedProxyUsed = true;
Messenger::Instance().setCurrentProxy(
Core::App().setCurrentProxy(
ProxyData(),
ProxyData::Settings::System);
saveDelayed();
@@ -1296,7 +1188,7 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
Assert(Global::ProxySettings() != ProxyData::Settings::Enabled);
if (base::take(_lastSelectedProxyUsed)) {
Messenger::Instance().setCurrentProxy(
Core::App().setCurrentProxy(
base::take(_lastSelectedProxy),
ProxyData::Settings::Enabled);
} else {
@@ -1401,9 +1293,7 @@ bool ProxiesBoxController::setProxySettings(ProxyData::Settings value) {
}
}
}
Messenger::Instance().setCurrentProxy(
Global::SelectedProxy(),
value);
Core::App().setCurrentProxy(Global::SelectedProxy(), value);
saveDelayed();
return true;
}
@@ -1491,7 +1381,7 @@ void ProxiesBoxController::share(const ProxyData &proxy) {
? "&pass=" + qthelp::url_encode(proxy.password) : "")
+ ((proxy.type == Type::Mtproto && !proxy.password.isEmpty())
? "&secret=" + proxy.password : "");
Application::clipboard()->setText(link);
QApplication::clipboard()->setText(link);
Ui::Toast::Show(lang(lng_username_copied));
}

View File

@@ -22,18 +22,6 @@ template <typename Enum>
class Radioenum;
} // namespace Ui
class AutoDownloadBox : public BoxContent {
public:
AutoDownloadBox(QWidget *parent);
protected:
void prepare() override;
private:
void setupContent();
};
class ProxiesBoxController : public base::Subscriber {
public:
using Type = ProxyData::Type;

View File

@@ -0,0 +1,731 @@
/*
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/create_poll_box.h"
#include "lang/lang_keys.h"
#include "data/data_poll.h"
#include "ui/toast/toast.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "core/event_filter.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "settings/settings_common.h"
#include "base/unique_qptr.h"
#include "styles/style_boxes.h"
#include "styles/style_settings.h"
namespace {
constexpr auto kQuestionLimit = 255;
constexpr auto kMaxOptionsCount = PollData::kMaxOptions;
constexpr auto kOptionLimit = 100;
constexpr auto kWarnQuestionLimit = 80;
constexpr auto kWarnOptionLimit = 30;
constexpr auto kErrorLimit = 99;
class Options {
public:
Options(
not_null<QWidget*> outer,
not_null<Ui::VerticalLayout*> container);
[[nodiscard]] bool isValid() const;
[[nodiscard]] rpl::producer<bool> isValidChanged() const;
[[nodiscard]] std::vector<PollAnswer> toPollAnswers() const;
void focusFirst();
[[nodiscard]] rpl::producer<int> usedCount() const;
[[nodiscard]] rpl::producer<not_null<QWidget*>> scrollToWidget() const;
[[nodiscard]] rpl::producer<> backspaceInFront() const;
private:
class Option {
public:
static Option Create(
not_null<QWidget*> outer,
not_null<Ui::VerticalLayout*> container,
int position);
void toggleRemoveAlways(bool toggled);
void show(anim::type animated);
void destroy(FnMut<void()> done);
//[[nodisacrd]] bool hasShadow() const;
//void destroyShadow();
[[nodiscard]] bool isEmpty() const;
[[nodiscard]] bool isGood() const;
[[nodiscard]] bool isTooLong() const;
[[nodiscard]] bool hasFocus() const;
void setFocus() const;
void clearValue();
void setPlaceholder() const;
void removePlaceholder() const;
not_null<Ui::InputField*> field() const;
[[nodiscard]] PollAnswer toPollAnswer(int index) const;
[[nodiscard]] rpl::producer<Qt::MouseButton> removeClicks() const;
inline bool operator<(const Option &other) const {
return field() < other.field();
}
friend inline bool operator<(
const Option &option,
Ui::InputField *field) {
return option.field() < field;
}
friend inline bool operator<(
Ui::InputField *field,
const Option &option) {
return field < option.field();
}
private:
Option() = default;
void createShadow();
void createRemove();
void createWarning();
base::unique_qptr<Ui::SlideWrap<Ui::InputField>> _field;
base::unique_qptr<Ui::PlainShadow> _shadow;
base::unique_qptr<Ui::CrossButton> _remove;
rpl::variable<bool> *_removeAlways = nullptr;
};
[[nodiscard]] bool full() const;
//[[nodiscard]] bool correctShadows() const;
//void fixShadows();
void removeEmptyTail();
void addEmptyOption();
void checkLastOption();
void validateState();
void fixAfterErase();
void destroy(Option &&option);
void removeDestroyed(not_null<Ui::InputField*> field);
int findField(not_null<Ui::InputField*> field) const;
not_null<QWidget*> _outer;
not_null<Ui::VerticalLayout*> _container;
int _position = 0;
std::vector<Option> _list;
std::set<Option, std::less<>> _destroyed;
rpl::variable<bool> _valid = false;
rpl::variable<int> _usedCount = 0;
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
rpl::event_stream<> _backspaceInFront;
};
void InitField(
not_null<QWidget*> container,
not_null<Ui::InputField*> field) {
field->setInstantReplaces(Ui::InstantReplaces::Default());
field->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
Ui::Emoji::SuggestionsController::Init(container, field);
}
not_null<Ui::FlatLabel*> CreateWarningLabel(
not_null<QWidget*> parent,
not_null<Ui::InputField*> field,
int valueLimit,
int warnLimit) {
const auto result = Ui::CreateChild<Ui::FlatLabel>(
parent.get(),
QString(),
Ui::FlatLabel::InitType::Simple,
st::createPollWarning);
result->setAttribute(Qt::WA_TransparentForMouseEvents);
QObject::connect(field, &Ui::InputField::changed, [=] {
Ui::PostponeCall(crl::guard(field, [=] {
const auto length = field->getLastText().size();
const auto value = valueLimit - length;
const auto shown = (value < warnLimit)
&& (field->height() > st::createPollOptionField.heightMin);
result->setRichText((value >= 0)
? QString::number(value)
: textcmdLink(1, QString::number(value)));
result->setVisible(shown);
}));
});
return result;
}
void FocusAtEnd(not_null<Ui::InputField*> field) {
field->setFocus();
field->setCursorPosition(field->getLastText().size());
field->ensureCursorVisible();
}
Options::Option Options::Option::Create(
not_null<QWidget*> outer,
not_null<Ui::VerticalLayout*> container,
int position) {
auto result = Option();
const auto field = container->insert(
position,
object_ptr<Ui::SlideWrap<Ui::InputField>>(
container,
object_ptr<Ui::InputField>(
container,
st::createPollOptionField,
langFactory(lng_polls_create_option_add))));
InitField(outer, field->entity());
field->entity()->setMaxLength(kOptionLimit + kErrorLimit);
result._field.reset(field);
result.createShadow();
result.createRemove();
result.createWarning();
return result;
}
//bool Options::Option::hasShadow() const {
// return (_shadow != nullptr);
//}
void Options::Option::createShadow() {
Expects(_field != nullptr);
if (_shadow) {
return;
}
const auto value = Ui::CreateChild<Ui::PlainShadow>(field().get());
value->show();
field()->sizeValue(
) | rpl::start_with_next([=](QSize size) {
const auto left = st::createPollFieldPadding.left();
value->setGeometry(
left,
size.height() - st::lineWidth,
size.width() - left,
st::lineWidth);
}, value->lifetime());
_shadow.reset(value);
}
//void Options::Option::destroyShadow() {
// _shadow = nullptr;
//}
void Options::Option::createRemove() {
using namespace rpl::mappers;
const auto field = this->field();
auto &lifetime = field->lifetime();
const auto remove = Ui::CreateChild<Ui::CrossButton>(
field.get(),
st::createPollOptionRemove);
remove->hide(anim::type::instant);
const auto toggle = lifetime.make_state<rpl::variable<bool>>(false);
_removeAlways = lifetime.make_state<rpl::variable<bool>>(false);
QObject::connect(field, &Ui::InputField::changed, [=] {
// Don't capture 'this'! Because Option is a value type.
*toggle = !field->getLastText().isEmpty();
});
rpl::combine(
toggle->value(),
_removeAlways->value(),
_1 || _2
) | rpl::start_with_next([=](bool shown) {
remove->toggle(shown, anim::type::normal);
}, remove->lifetime());
field->widthValue(
) | rpl::start_with_next([=](int width) {
remove->moveToRight(
st::createPollOptionRemovePosition.x(),
st::createPollOptionRemovePosition.y(),
width);
}, remove->lifetime());
_remove.reset(remove);
}
void Options::Option::createWarning() {
using namespace rpl::mappers;
const auto field = this->field();
const auto warning = CreateWarningLabel(
field,
field,
kOptionLimit,
kWarnOptionLimit);
rpl::combine(
field->sizeValue(),
warning->sizeValue()
) | rpl::start_with_next([=](QSize size, QSize label) {
warning->moveToLeft(
(size.width()
- label.width()
- st::createPollWarningPosition.x()),
(size.height()
- label.height()
- st::createPollWarningPosition.y()),
size.width());
}, warning->lifetime());
}
bool Options::Option::isEmpty() const {
return field()->getLastText().trimmed().isEmpty();
}
bool Options::Option::isGood() const {
return !field()->getLastText().trimmed().isEmpty() && !isTooLong();
}
bool Options::Option::isTooLong() const {
return (field()->getLastText().size() > kOptionLimit);
}
bool Options::Option::hasFocus() const {
return field()->hasFocus();
}
void Options::Option::setFocus() const {
FocusAtEnd(field());
}
void Options::Option::clearValue() {
field()->setText(QString());
}
void Options::Option::setPlaceholder() const {
field()->setPlaceholder(langFactory(lng_polls_create_option_add));
}
void Options::Option::toggleRemoveAlways(bool toggled) {
*_removeAlways = toggled;
}
not_null<Ui::InputField*> Options::Option::field() const {
return _field->entity();
}
void Options::Option::removePlaceholder() const {
field()->setPlaceholder(nullptr);
}
PollAnswer Options::Option::toPollAnswer(int index) const {
Expects(index >= 0 && index < kMaxOptionsCount);
return PollAnswer{
field()->getLastText().trimmed(),
QByteArray(1, ('0' + index))
};
}
rpl::producer<Qt::MouseButton> Options::Option::removeClicks() const {
return _remove->clicks();
}
Options::Options(
not_null<QWidget*> outer,
not_null<Ui::VerticalLayout*> container)
: _outer(outer)
, _container(container)
, _position(_container->count()) {
checkLastOption();
}
bool Options::full() const {
return (_list.size() == kMaxOptionsCount);
}
bool Options::isValid() const {
return _valid.current();
}
rpl::producer<bool> Options::isValidChanged() const {
return _valid.changes();
}
rpl::producer<int> Options::usedCount() const {
return _usedCount.value();
}
rpl::producer<not_null<QWidget*>> Options::scrollToWidget() const {
return _scrollToWidget.events();
}
rpl::producer<> Options::backspaceInFront() const {
return _backspaceInFront.events();
}
void Options::Option::show(anim::type animated) {
_field->hide(anim::type::instant);
_field->show(animated);
}
void Options::Option::destroy(FnMut<void()> done) {
if (anim::Disabled() || _field->isHidden()) {
Ui::PostponeCall(std::move(done));
return;
}
_field->hide(anim::type::normal);
App::CallDelayed(
st::slideWrapDuration * 2,
_field.get(),
std::move(done));
}
std::vector<PollAnswer> Options::toPollAnswers() const {
auto result = std::vector<PollAnswer>();
result.reserve(_list.size());
auto counter = int(0);
const auto makeAnswer = [&](const Option &option) {
return option.toPollAnswer(counter++);
};
ranges::copy(
_list
| ranges::view::filter(&Option::isGood)
| ranges::view::transform(makeAnswer),
ranges::back_inserter(result));
return result;
}
void Options::focusFirst() {
Expects(!_list.empty());
_list.front().setFocus();
}
//
//bool Options::correctShadows() const {
// // Last one should be without shadow if all options were used.
// const auto noShadow = ranges::find(
// _list,
// true,
// ranges::not_fn(&Option::hasShadow));
// return (noShadow == end(_list) - (full() ? 1 : 0));
//}
//
//void Options::fixShadows() {
// if (correctShadows()) {
// return;
// }
// for (auto &option : _list) {
// option.createShadow();
// }
// if (full()) {
// _list.back().destroyShadow();
// }
//}
void Options::removeEmptyTail() {
// Only one option at the end of options list can be empty.
// Remove all other trailing empty options.
// Only last empty and previous option have non-empty placeholders.
const auto focused = ranges::find_if(
_list,
&Option::hasFocus);
const auto end = _list.end();
const auto reversed = ranges::view::reverse(_list);
const auto emptyItem = ranges::find_if(
reversed,
ranges::not_fn(&Option::isEmpty)).base();
const auto focusLast = (focused > emptyItem) && (focused < end);
if (emptyItem == end) {
return;
}
if (focusLast) {
emptyItem->setFocus();
}
for (auto i = emptyItem + 1; i != end; ++i) {
destroy(std::move(*i));
}
_list.erase(emptyItem + 1, end);
fixAfterErase();
}
void Options::destroy(Option &&option) {
const auto field = option.field();
option.destroy([=] { removeDestroyed(field); });
_destroyed.emplace(std::move(option));
}
void Options::fixAfterErase() {
Expects(!_list.empty());
const auto last = _list.end() - 1;
last->setPlaceholder();
last->toggleRemoveAlways(false);
if (last != begin(_list)) {
(last - 1)->setPlaceholder();
(last - 1)->toggleRemoveAlways(false);
}
}
void Options::addEmptyOption() {
if (full()) {
return;
} else if (!_list.empty() && _list.back().isEmpty()) {
return;
}
if (_list.size() > 1) {
(_list.end() - 2)->removePlaceholder();
(_list.end() - 2)->toggleRemoveAlways(true);
}
_list.push_back(Option::Create(
_outer,
_container,
_position + _list.size() + _destroyed.size()));
const auto field = _list.back().field();
QObject::connect(field, &Ui::InputField::submitted, [=] {
const auto index = findField(field);
if (_list[index].isGood() && index + 1 < _list.size()) {
_list[index + 1].setFocus();
}
});
QObject::connect(field, &Ui::InputField::changed, [=] {
Ui::PostponeCall(crl::guard(field, [=] {
validateState();
}));
});
QObject::connect(field, &Ui::InputField::focused, [=] {
_scrollToWidget.fire_copy(field);
});
Core::InstallEventFilter(field, [=](not_null<QEvent*> event) {
if (event->type() != QEvent::KeyPress
|| !field->getLastText().isEmpty()) {
return false;
}
const auto key = static_cast<QKeyEvent*>(event.get())->key();
if (key != Qt::Key_Backspace) {
return false;
}
const auto index = findField(field);
if (index > 0) {
_list[index - 1].setFocus();
} else {
_backspaceInFront.fire({});
}
return true;
});
_list.back().removeClicks(
) | rpl::start_with_next([=] {
Ui::PostponeCall(crl::guard(field, [=] {
Expects(!_list.empty());
const auto item = begin(_list) + findField(field);
if (item == _list.end() - 1) {
item->clearValue();
return;
}
if (item->hasFocus()) {
(item + 1)->setFocus();
}
destroy(std::move(*item));
_list.erase(item);
fixAfterErase();
validateState();
}));
}, field->lifetime());
_list.back().show((_list.size() == 1)
? anim::type::instant
: anim::type::normal);
//fixShadows();
}
void Options::removeDestroyed(not_null<Ui::InputField*> field) {
_destroyed.erase(_destroyed.find(field));
}
void Options::validateState() {
checkLastOption();
_valid = (ranges::count_if(_list, &Option::isGood) > 1)
&& (ranges::find_if(_list, &Option::isTooLong) == end(_list));
const auto lastEmpty = !_list.empty() && _list.back().isEmpty();
_usedCount = _list.size() - (lastEmpty ? 1 : 0);
}
int Options::findField(not_null<Ui::InputField*> field) const {
const auto result = ranges::find(
_list,
field,
&Option::field) - begin(_list);
Ensures(result >= 0 && result < _list.size());
return result;
}
void Options::checkLastOption() {
removeEmptyTail();
addEmptyOption();
}
} // namespace
CreatePollBox::CreatePollBox(QWidget*) {
}
rpl::producer<PollData> CreatePollBox::submitRequests() const {
return _submitRequests.events();
}
void CreatePollBox::setInnerFocus() {
_setInnerFocus();
}
void CreatePollBox::submitFailed(const QString &error) {
Ui::Toast::Show(error);
}
not_null<Ui::InputField*> CreatePollBox::setupQuestion(
not_null<Ui::VerticalLayout*> container) {
using namespace Settings;
AddSubsectionTitle(container, lng_polls_create_question);
const auto question = container->add(
object_ptr<Ui::InputField>(
container,
st::createPollField,
Ui::InputField::Mode::MultiLine,
langFactory(lng_polls_create_question_placeholder)),
st::createPollFieldPadding);
InitField(getDelegate()->outerContainer(), question);
question->setMaxLength(kQuestionLimit + kErrorLimit);
const auto warning = CreateWarningLabel(
container,
question,
kQuestionLimit,
kWarnQuestionLimit);
rpl::combine(
question->geometryValue(),
warning->sizeValue()
) | rpl::start_with_next([=](QRect geometry, QSize label) {
warning->moveToLeft(
(container->width()
- label.width()
- st::createPollWarningPosition.x()),
(geometry.y()
- st::createPollFieldPadding.top()
- st::settingsSubsectionTitlePadding.bottom()
- st::settingsSubsectionTitle.style.font->height
+ st::settingsSubsectionTitle.style.font->ascent
- st::createPollWarning.style.font->ascent),
geometry.width());
}, warning->lifetime());
return question;
}
object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
using namespace Settings;
const auto id = rand_value<uint64>();
const auto valid = lifetime().make_state<rpl::event_stream<bool>>();
auto result = object_ptr<Ui::VerticalLayout>(this);
const auto container = result.data();
const auto question = setupQuestion(container);
AddDivider(container);
AddSkip(container);
AddSubsectionTitle(container, lng_polls_create_options);
const auto options = lifetime().make_state<Options>(
getDelegate()->outerContainer(),
container);
auto limit = options->usedCount() | rpl::after_next([=](int count) {
setCloseByEscape(!count);
setCloseByOutsideClick(!count);
}) | rpl::map([=](int count) {
return (count < kMaxOptionsCount)
? lng_polls_create_limit(lt_count, kMaxOptionsCount - count)
: lang(lng_polls_create_maximum);
}) | rpl::after_next([=] {
container->resizeToWidth(container->widthNoMargins());
});
container->add(
object_ptr<Ui::FlatLabel>(
container,
std::move(limit),
st::createPollLimitLabel),
st::createPollLimitPadding);
const auto isValidQuestion = [=] {
const auto text = question->getLastText().trimmed();
return !text.isEmpty() && (text.size() <= kQuestionLimit);
};
connect(question, &Ui::InputField::submitted, [=] {
if (isValidQuestion()) {
options->focusFirst();
}
});
_setInnerFocus = [=] {
question->setFocusFast();
};
const auto collectResult = [=] {
auto result = PollData(id);
result.question = question->getLastText().trimmed();
result.answers = options->toPollAnswers();
return result;
};
const auto updateValid = [=] {
valid->fire(isValidQuestion() && options->isValid());
};
connect(question, &Ui::InputField::changed, [=] {
updateValid();
});
valid->events_starting_with(
false
) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](bool valid) {
clearButtons();
if (valid) {
addButton(
langFactory(lng_polls_create_button),
[=] { _submitRequests.fire(collectResult()); });
}
addButton(langFactory(lng_cancel), [=] { closeBox(); });
}, lifetime());
options->isValidChanged(
) | rpl::start_with_next([=] {
updateValid();
}, lifetime());
options->scrollToWidget(
) | rpl::start_with_next([=](not_null<QWidget*> widget) {
scrollToWidget(widget);
}, lifetime());
options->backspaceInFront(
) | rpl::start_with_next([=] {
FocusAtEnd(question);
}, lifetime());
return std::move(result);
}
void CreatePollBox::prepare() {
setTitle(langFactory(lng_polls_create_title));
const auto inner = setInnerWidget(setupContent());
setDimensionsToContent(st::boxWideWidth, inner);
}

View File

@@ -0,0 +1,39 @@
/*
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 Ui {
class VerticalLayout;
} // namespace Ui
struct PollData;
class CreatePollBox : public BoxContent {
public:
CreatePollBox(QWidget*);
rpl::producer<PollData> submitRequests() const;
void submitFailed(const QString &error);
void setInnerFocus() override;
protected:
void prepare() override;
private:
object_ptr<Ui::RpWidget> setupContent();
not_null<Ui::InputField*> setupQuestion(
not_null<Ui::VerticalLayout*> container);
Fn<void()> _setInnerFocus;
Fn<rpl::producer<bool>()> _dataIsValidValue;
rpl::event_stream<PollData> _submitRequests;
};

View File

@@ -11,12 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "ui/text_options.h"
#include "ui/special_buttons.h"
#include "media/media_clip_reader.h"
#include "media/clip/media_clip_reader.h"
#include "history/history.h"
#include "history/history_item.h"
#include "data/data_media_types.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "data/data_user.h"
#include "lang/lang_keys.h"
#include "core/event_filter.h"
#include "chat_helpers/message_field.h"
@@ -41,18 +42,22 @@ EditCaptionBox::EditCaptionBox(
Expects(item->media()->allowsEditCaption());
QSize dimensions;
ImagePtr image;
auto image = (Image*)nullptr;
DocumentData *doc = nullptr;
const auto media = item->media();
if (const auto photo = media->photo()) {
_photo = true;
dimensions = QSize(photo->full->width(), photo->full->height());
image = photo->full;
dimensions = QSize(photo->width(), photo->height());
image = photo->large();
} else if (const auto document = media->document()) {
dimensions = document->dimensions;
image = document->thumb;
image = document->thumbnail();
dimensions = image
? image->size()
: document->dimensions;
if (document->isAnimation()) {
_gifw = document->dimensions.width();
_gifh = document->dimensions.height();
_animated = true;
} else if (document->isVideoFile()) {
_animated = true;
@@ -67,11 +72,11 @@ EditCaptionBox::EditCaptionBox(
ConvertEntitiesToTextTags(original.entities)
};
if (!_animated && (dimensions.isEmpty() || doc || image->isNull())) {
if (image->isNull()) {
if (!_animated && (dimensions.isEmpty() || doc || !image)) {
if (!image) {
_thumbw = 0;
} else {
int32 tw = image->width(), th = image->height();
const auto tw = image->width(), th = image->height();
if (tw > th) {
_thumbw = (tw * st::msgFileThumbSize) / th;
} else {
@@ -79,7 +84,7 @@ EditCaptionBox::EditCaptionBox(
}
_thumbnailImage = image;
_refreshThumbnail = [=] {
auto options = Images::Option::Smooth
const auto options = Images::Option::Smooth
| Images::Option::RoundedSmall
| Images::Option::RoundedTopLeft
| Images::Option::RoundedTopRight
@@ -96,7 +101,7 @@ EditCaptionBox::EditCaptionBox(
}
if (doc) {
auto nameString = doc->isVoiceMessage()
const auto nameString = doc->isVoiceMessage()
? lang(lng_media_audio)
: doc->composeNameString();
_name.setText(
@@ -104,7 +109,7 @@ EditCaptionBox::EditCaptionBox(
nameString,
Ui::NameTextOptions());
_status = formatSizeText(doc->size);
_statusw = qMax(
_statusw = std::max(
_name.maxWidth(),
st::normalFont->width(_status));
_isImage = doc->isImage();
@@ -114,12 +119,15 @@ EditCaptionBox::EditCaptionBox(
_refreshThumbnail();
}
} else {
int32 maxW = 0, maxH = 0;
if (!image) {
image = Image::BlankMedia();
}
auto maxW = 0, maxH = 0;
const auto limitW = st::sendMediaPreviewSize;
auto limitH = std::min(st::confirmMaxHeight, _gifh ? _gifh : INT_MAX);
if (_animated) {
int32 limitW = st::sendMediaPreviewSize;
int32 limitH = st::confirmMaxHeight;
maxW = qMax(dimensions.width(), 1);
maxH = qMax(dimensions.height(), 1);
maxW = std::max(dimensions.width(), 1);
maxH = std::max(dimensions.height(), 1);
if (maxW * limitH > maxH * limitW) {
if (maxW < limitW) {
maxH = maxH * limitW / maxW;
@@ -160,24 +168,42 @@ EditCaptionBox::EditCaptionBox(
}
_refreshThumbnail();
int32 tw = _thumb.width(), th = _thumb.height();
if (!tw || !th) {
tw = th = 1;
}
_thumbw = st::sendMediaPreviewSize;
if (_thumb.width() < _thumbw) {
_thumbw = (_thumb.width() > 20) ? _thumb.width() : 20;
}
int32 maxthumbh = qMin(qRound(1.5 * _thumbw), int(st::confirmMaxHeight));
_thumbh = qRound(th * float64(_thumbw) / tw);
if (_thumbh > maxthumbh) {
_thumbw = qRound(_thumbw * float64(maxthumbh) / _thumbh);
_thumbh = maxthumbh;
if (_thumbw < 10) {
_thumbw = 10;
const auto resizeDimensions = [&](int &thumbWidth, int &thumbHeight, int &thumbX) {
auto tw = thumbWidth, th = thumbHeight;
if (!tw || !th) {
tw = th = 1;
}
if (thumbWidth < st::sendMediaPreviewSize) {
thumbWidth = (thumbWidth > 20) ? thumbWidth : 20;
} else {
thumbWidth = st::sendMediaPreviewSize;
}
const auto maxThumbHeight = std::min(int(std::round(1.5 * thumbWidth)), limitH);
thumbHeight = int(std::round(th * float64(thumbWidth) / tw));
if (thumbHeight > maxThumbHeight) {
thumbWidth = int(std::round(thumbWidth * float64(maxThumbHeight) / thumbHeight));
thumbHeight = maxThumbHeight;
if (thumbWidth < 10) {
thumbWidth = 10;
}
}
thumbX = (st::boxWideWidth - thumbWidth) / 2;
};
if (doc && doc->isAnimation()) {
resizeDimensions(_gifw, _gifh, _gifx);
}
limitH = std::min(st::confirmMaxHeight, _gifh ? _gifh : INT_MAX);
_thumbw = _thumb.width();
_thumbh = _thumb.height();
// If thumb's and resized gif's sizes are equal,
// Then just take made values.
if (_thumbw == _gifw && _thumbh == _gifh) {
_thumbx = (st::boxWideWidth - _thumbw) / 2;
} else {
resizeDimensions(_thumbw, _thumbh, _thumbx);
}
_thumbx = (st::boxWideWidth - _thumbw) / 2;
const auto prepareBasicThumb = _refreshThumbnail;
const auto scaleThumbDown = [=] {
@@ -200,7 +226,9 @@ EditCaptionBox::EditCaptionBox(
? _thumbnailImage->loaded()
: true;
subscribe(Auth().downloaderTaskFinished(), [=] {
if (!_thumbnailImageLoaded && _thumbnailImage->loaded()) {
if (!_thumbnailImageLoaded
&& _thumbnailImage
&& _thumbnailImage->loaded()) {
_thumbnailImageLoaded = true;
_refreshThumbnail();
update();
@@ -263,7 +291,7 @@ void EditCaptionBox::clipCallback(Media::Clip::Notification notification) {
}
if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) {
auto s = QSize(_thumbw, _thumbh);
const auto s = QSize(_gifw, _gifh);
_gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None);
}
@@ -337,7 +365,7 @@ void EditCaptionBox::setupEmojiPanel() {
void EditCaptionBox::updateBoxSize() {
auto newHeight = st::boxPhotoPadding.top() + st::boxPhotoCaptionSkip + _field->height() + errorTopSkip() + st::normalFont->height;
if (_photo || _animated) {
newHeight += _thumbh;
newHeight += std::max(_thumbh, _gifh);
} else if (_thumbw) {
newHeight += 0 + st::msgFileThumbSize + 0;
} else if (_doc) {
@@ -358,22 +386,24 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (_photo || _animated) {
const auto th = std::max(_gifh, _thumbh);
if (_thumbx > st::boxPhotoPadding.left()) {
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), _thumbh, st::confirmBg);
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), th, st::confirmBg);
}
if (_thumbx + _thumbw < width() - st::boxPhotoPadding.right()) {
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, _thumbh, st::confirmBg);
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, th, st::confirmBg);
}
if (_gifPreview && _gifPreview->started()) {
auto s = QSize(_thumbw, _thumbh);
auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Layer);
auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : getms());
p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), frame);
const auto s = QSize(_gifw, _gifh);
const auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Layer);
const auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : crl::now());
p.drawPixmap(_gifx, st::boxPhotoPadding.top(), frame);
} else {
p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), _thumb);
const auto offset = _gifh ? ((_gifh - _thumbh) / 2) : 0;
p.drawPixmap(_thumbx, st::boxPhotoPadding.top() + offset, _thumb);
}
if (_animated && !_gifPreview) {
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_thumbh - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (th - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
p.setPen(Qt::NoPen);
p.setBrush(st::msgDateImgBg);
@@ -382,13 +412,13 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
p.drawEllipse(inner);
}
auto icon = &st::historyFileInPlay;
const auto icon = &st::historyFileInPlay;
icon->paintInCenter(p, inner);
}
} else if (_doc) {
int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
int32 h = _thumbw ? (0 + st::msgFileThumbSize + 0) : (0 + st::msgFileSize + 0);
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0;
const auto w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
const auto h = _thumbw ? (0 + st::msgFileThumbSize + 0) : (0 + st::msgFileSize + 0);
auto nameleft = 0, nametop = 0, nameright = 0, statustop = 0;
if (_thumbw) {
nameleft = 0 + st::msgFileThumbSize + st::msgFileThumbPadding.right();
nametop = st::msgFileThumbNameTop - st::msgFileThumbPadding.top();
@@ -400,12 +430,12 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
nameright = 0;
statustop = st::msgFileStatusTop - st::msgFilePadding.top();
}
int32 namewidth = w - nameleft - 0;
const auto namewidth = w - nameleft - 0;
if (namewidth > _statusw) {
//w -= (namewidth - _statusw);
//namewidth = _statusw;
}
int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top();
const auto x = (width() - w) / 2, y = st::boxPhotoPadding.top();
// App::roundRect(p, x, y, w, h, st::msgInBg, MessageInCorners, &st::msgInShadow);
@@ -413,7 +443,7 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
QRect rthumb(rtlrect(x + 0, y + 0, st::msgFileThumbSize, st::msgFileThumbSize, width()));
p.drawPixmap(rthumb.topLeft(), _thumb);
} else {
QRect inner(rtlrect(x + 0, y + 0, st::msgFileSize, st::msgFileSize, width()));
const QRect inner(rtlrect(x + 0, y + 0, st::msgFileSize, st::msgFileSize, width()));
p.setPen(Qt::NoPen);
p.setBrush(st::msgFileInBg);
@@ -422,14 +452,14 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
p.drawEllipse(inner);
}
auto icon = &(_isAudio ? st::historyFileInPlay : _isImage ? st::historyFileInImage : st::historyFileInDocument);
const auto icon = &(_isAudio ? st::historyFileInPlay : _isImage ? st::historyFileInImage : st::historyFileInDocument);
icon->paintInCenter(p, inner);
}
p.setFont(st::semiboldFont);
p.setPen(st::historyFileNameInFg);
_name.drawLeftElided(p, x + nameleft, y + nametop, namewidth, width());
auto &status = st::mediaInFg;
const auto &status = st::mediaInFg;
p.setFont(st::normalFont);
p.setPen(status);
p.drawTextLeft(x + nameleft, y + statustop, width(), _status);
@@ -464,7 +494,7 @@ void EditCaptionBox::setInnerFocus() {
void EditCaptionBox::save() {
if (_saveRequestId) return;
auto item = App::histItemById(_msgId);
const auto item = App::histItemById(_msgId);
if (!item) {
_error = lang(lng_edit_deleted);
update();
@@ -499,9 +529,8 @@ void EditCaptionBox::save() {
MTP_int(item->id),
MTP_string(sending.text),
MTPInputMedia(),
MTPnullMarkup,
sentEntities,
MTP_inputGeoPointEmpty()),
MTPReplyMarkup(),
sentEntities),
rpcDone(&EditCaptionBox::saveDone),
rpcFail(&EditCaptionBox::saveFail));
}

View File

@@ -63,7 +63,7 @@ private:
not_null<Window::Controller*> _controller;
FullMsgId _msgId;
ImagePtr _thumbnailImage;
Image *_thumbnailImage = nullptr;
bool _thumbnailImageLoaded = false;
Fn<void()> _refreshThumbnail;
bool _animated = false;
@@ -87,6 +87,10 @@ private:
bool _isAudio = false;
bool _isImage = false;
int _gifw = 0;
int _gifh = 0;
int _gifx = 0;
bool _previewCancelled = false;
mtpRequestId _saveRequestId = 0;

View File

@@ -442,7 +442,7 @@ public:
protected:
void correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) override;
void paintAdditionalPlaceholder(Painter &p, TimeMs ms) override;
void paintAdditionalPlaceholder(Painter &p, crl::time ms) override;
void wheelEvent(QWheelEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
@@ -501,7 +501,7 @@ void EditColorBox::Field::correctValue(const QString &was, int wasCursor, QStrin
}
}
void EditColorBox::Field::paintAdditionalPlaceholder(Painter &p, TimeMs ms) {
void EditColorBox::Field::paintAdditionalPlaceholder(Painter &p, crl::time ms) {
p.setFont(_st.font);
p.setPen(_st.placeholderFg);
auto inner = QRect(_st.textMargins.right(), _st.textMargins.top(), width() - 2 * _st.textMargins.right(), height() - _st.textMargins.top() - _st.textMargins.bottom());
@@ -565,7 +565,7 @@ public:
protected:
void correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) override;
void paintAdditionalPlaceholder(Painter &p, TimeMs ms) override;
void paintAdditionalPlaceholder(Painter &p, crl::time ms) override;
};
@@ -606,7 +606,7 @@ void EditColorBox::ResultField::correctValue(const QString &was, int wasCursor,
}
}
void EditColorBox::ResultField::paintAdditionalPlaceholder(Painter &p, TimeMs ms) {
void EditColorBox::ResultField::paintAdditionalPlaceholder(Painter &p, crl::time ms) {
p.setFont(_st.font);
p.setPen(_st.placeholderFg);
p.drawText(QRect(_st.textMargins.right(), _st.textMargins.top(), width(), height() - _st.textMargins.top() - _st.textMargins.bottom()), "#", style::al_topleft);

View File

@@ -1,523 +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/edit_participant_box.h"
#include "lang/lang_keys.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "ui/text_options.h"
#include "ui/special_buttons.h"
#include "boxes/calendar_box.h"
#include "data/data_peer_values.h"
#include "styles/style_boxes.h"
namespace {
constexpr auto kMaxRestrictDelayDays = 366;
constexpr auto kSecondsInDay = 24 * 60 * 60;
constexpr auto kSecondsInWeek = 7 * kSecondsInDay;
template <typename CheckboxesMap, typename DependenciesMap>
void ApplyDependencies(CheckboxesMap &checkboxes, DependenciesMap &dependencies, QPointer<Ui::Checkbox> changed) {
auto checkAndApply = [&checkboxes](auto &&current, auto dependency, bool isChecked) {
for (auto &&checkbox : checkboxes) {
if ((checkbox.first & dependency) && (checkbox.second->checked() == isChecked)) {
current->setChecked(isChecked);
return true;
}
}
return false;
};
auto applySomeDependency = [&checkboxes, &dependencies, &changed, checkAndApply] {
auto result = false;
for (auto &&entry : checkboxes) {
if (entry.second == changed) {
continue;
}
auto isChecked = entry.second->checked();
for (auto &&dependency : dependencies) {
if (entry.first & (isChecked ? dependency.first : dependency.second)) {
if (checkAndApply(entry.second, (isChecked ? dependency.second : dependency.first), !isChecked)) {
result = true;
break;
}
}
}
}
return result;
};
while (true) {
if (!applySomeDependency()) {
break;
}
};
}
} // namespace
class EditParticipantBox::Inner : public TWidget {
public:
Inner(
QWidget *parent,
not_null<ChannelData*> channel,
not_null<UserData*> user,
bool hasAdminRights);
template <typename Widget>
QPointer<Widget> addControl(object_ptr<Widget> widget, QMargins margin) {
doAddControl(std::move(widget), margin);
return static_cast<Widget*>(_rows.back().widget.data());
}
void removeControl(QPointer<TWidget> widget);
protected:
int resizeGetHeight(int newWidth) override;
void paintEvent(QPaintEvent *e) override;
private:
void doAddControl(object_ptr<TWidget> widget, QMargins margin);
not_null<ChannelData*> _channel;
not_null<UserData*> _user;
object_ptr<Ui::UserpicButton> _userPhoto;
Text _userName;
bool _hasAdminRights = false;
struct Control {
object_ptr<TWidget> widget;
QMargins margin;
};
std::vector<Control> _rows;
};
EditParticipantBox::Inner::Inner(
QWidget *parent,
not_null<ChannelData*> channel,
not_null<UserData*> user,
bool hasAdminRights)
: TWidget(parent)
, _channel(channel)
, _user(user)
, _userPhoto(
this,
_user,
Ui::UserpicButton::Role::Custom,
st::rightsPhotoButton)
, _hasAdminRights(hasAdminRights) {
_userPhoto->setPointerCursor(false);
_userName.setText(
st::rightsNameStyle,
App::peerName(_user),
Ui::NameTextOptions());
}
void EditParticipantBox::Inner::removeControl(QPointer<TWidget> widget) {
auto row = std::find_if(_rows.begin(), _rows.end(), [widget](auto &&row) {
return (row.widget == widget);
});
Assert(row != _rows.end());
row->widget.destroy();
_rows.erase(row);
}
void EditParticipantBox::Inner::doAddControl(object_ptr<TWidget> widget, QMargins margin) {
widget->setParent(this);
_rows.push_back({ std::move(widget), margin });
_rows.back().widget->show();
}
int EditParticipantBox::Inner::resizeGetHeight(int newWidth) {
_userPhoto->moveToLeft(st::rightsPhotoMargin.left(), st::rightsPhotoMargin.top());
auto newHeight = st::rightsPhotoMargin.top()
+ st::rightsPhotoButton.size.height()
+ st::rightsPhotoMargin.bottom();
for (auto &&row : _rows) {
auto rowWidth = newWidth - row.margin.left() - row.margin.right();
newHeight += row.margin.top();
row.widget->resizeToNaturalWidth(rowWidth);
row.widget->moveToLeft(row.margin.left(), newHeight);
newHeight += row.widget->heightNoMargins() + row.margin.bottom();
}
return newHeight;
}
void EditParticipantBox::Inner::paintEvent(QPaintEvent *e) {
Painter p(this);
p.fillRect(e->rect(), st::boxBg);
p.setPen(st::contactsNameFg);
auto namex = st::rightsPhotoMargin.left()
+ st::rightsPhotoButton.size .width()
+ st::rightsPhotoMargin.right();
auto namew = width() - namex - st::rightsPhotoMargin.right();
_userName.drawLeftElided(p, namex, st::rightsPhotoMargin.top() + st::rightsNameTop, namew, width());
auto statusText = [this] {
if (_user->botInfo) {
auto seesAllMessages = (_user->botInfo->readsAllHistory || _hasAdminRights);
return lang(seesAllMessages ? lng_status_bot_reads_all : lng_status_bot_not_reads_all);
}
return Data::OnlineText(_user->onlineTill, unixtime());
};
p.setFont(st::contactsStatusFont);
p.setPen(st::contactsStatusFg);
p.drawTextLeft(namex, st::rightsPhotoMargin.top() + st::rightsStatusTop, width(), statusText());
}
EditParticipantBox::EditParticipantBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, bool hasAdminRights) : BoxContent()
, _channel(channel)
, _user(user)
, _hasAdminRights(hasAdminRights) {
}
void EditParticipantBox::prepare() {
_inner = setInnerWidget(object_ptr<Inner>(
this,
_channel,
_user,
hasAdminRights()));
}
template <typename Widget>
QPointer<Widget> EditParticipantBox::addControl(object_ptr<Widget> widget, QMargins margin) {
Expects(_inner != nullptr);
return _inner->addControl(std::move(widget), margin);
}
void EditParticipantBox::removeControl(QPointer<TWidget> widget) {
Expects(_inner != nullptr);
return _inner->removeControl(widget);
}
void EditParticipantBox::resizeToContent() {
_inner->resizeToWidth(st::boxWideWidth);
setDimensions(_inner->width(), qMin(_inner->height(), st::boxMaxListHeight));
}
EditAdminBox::EditAdminBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, const MTPChannelAdminRights &rights) : EditParticipantBox(nullptr, channel, user, (rights.c_channelAdminRights().vflags.v != 0))
, _oldRights(rights) {
auto dependency = [this](Flag dependent, Flag dependency) {
_dependencies.push_back(std::make_pair(dependent, dependency));
};
dependency(Flag::f_invite_link, Flag::f_invite_users); // invite_link <-> invite_users
dependency(Flag::f_invite_users, Flag::f_invite_link);
}
MTPChannelAdminRights EditAdminBox::DefaultRights(not_null<ChannelData*> channel) {
auto defaultRights = channel->isMegagroup()
? (Flag::f_change_info | Flag::f_delete_messages | Flag::f_ban_users | Flag::f_invite_users | Flag::f_invite_link | Flag::f_pin_messages)
: (Flag::f_change_info | Flag::f_post_messages | Flag::f_edit_messages | Flag::f_delete_messages | Flag::f_invite_users | Flag::f_invite_link);
return MTP_channelAdminRights(MTP_flags(defaultRights));
}
void EditAdminBox::prepare() {
EditParticipantBox::prepare();
auto hadRights = _oldRights.c_channelAdminRights().vflags.v;
setTitle(langFactory(hadRights ? lng_rights_edit_admin : lng_channel_add_admin));
addControl(object_ptr<BoxContentDivider>(this), QMargins());
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
const auto prepareRights = hadRights ? _oldRights : DefaultRights(channel());
const auto filterByMyRights = canSave()
&& !hadRights
&& !channel()->amCreator();
const auto prepareFlags = prepareRights.c_channelAdminRights().vflags.v
& (filterByMyRights ? channel()->adminRights() : ~Flag(0));
auto addCheckbox = [&](Flags flags, const QString &text) {
const auto checked = (prepareFlags & flags) != 0;
auto control = addControl(object_ptr<Ui::Checkbox>(this, text, checked, st::rightsCheckbox, st::rightsToggle), st::rightsToggleMargin);
control->checkedChanges(
) | rpl::start_with_next([=](bool checked) {
InvokeQueued(this, [=] {
applyDependencies(control);
});
}, control->lifetime());
if (!channel()->amCreator()) {
if (!(channel()->adminRights() & flags)) {
control->setDisabled(true); // Grey out options that we don't have ourselves.
}
}
if (!canSave()) {
control->setDisabled(true);
}
_checkboxes.emplace(flags, control);
};
if (channel()->isMegagroup()) {
addCheckbox(Flag::f_change_info, lang(lng_rights_group_info));
addCheckbox(Flag::f_delete_messages, lang(lng_rights_group_delete));
addCheckbox(Flag::f_ban_users, lang(lng_rights_group_ban));
addCheckbox(Flag::f_invite_users | Flag::f_invite_link, lang(channel()->anyoneCanAddMembers() ? lng_rights_group_invite_link : lng_rights_group_invite));
addCheckbox(Flag::f_pin_messages, lang(lng_rights_group_pin));
addCheckbox(Flag::f_add_admins, lang(lng_rights_add_admins));
} else {
addCheckbox(Flag::f_change_info, lang(lng_rights_channel_info));
addCheckbox(Flag::f_post_messages, lang(lng_rights_channel_post));
addCheckbox(Flag::f_edit_messages, lang(lng_rights_channel_edit));
addCheckbox(Flag::f_delete_messages, lang(lng_rights_channel_delete));
addCheckbox(Flag::f_invite_users | Flag::f_invite_link, lang(lng_rights_group_invite));
addCheckbox(Flag::f_add_admins, lang(lng_rights_add_admins));
}
auto addAdmins = _checkboxes.find(Flag::f_add_admins);
if (addAdmins != _checkboxes.end()) {
_aboutAddAdmins = addControl(
object_ptr<Ui::FlatLabel>(this, st::boxLabel),
st::rightsAboutMargin);
Assert(addAdmins != _checkboxes.end());
addAdmins->second->checkedChanges(
) | rpl::start_with_next([=](bool checked) {
refreshAboutAddAdminsText();
}, addAdmins->second->lifetime());
refreshAboutAddAdminsText();
}
if (canSave()) {
addButton(langFactory(lng_settings_save), [this] {
if (!_saveCallback) {
return;
}
auto newFlags = MTPDchannelAdminRights::Flags(0);
for (auto &&checkbox : _checkboxes) {
if (checkbox.second->checked()) {
newFlags |= checkbox.first;
} else {
newFlags &= ~checkbox.first;
}
}
if (!channel()->amCreator()) {
// Leave only rights that we have so we could save them.
newFlags &= channel()->adminRights();
}
_saveCallback(_oldRights, MTP_channelAdminRights(MTP_flags(newFlags)));
});
addButton(langFactory(lng_cancel), [this] { closeBox(); });
} else {
addButton(langFactory(lng_box_ok), [this] { closeBox(); });
}
applyDependencies(nullptr);
for (auto &&checkbox : _checkboxes) {
checkbox.second->finishAnimating();
}
resizeToContent();
}
void EditAdminBox::applyDependencies(QPointer<Ui::Checkbox> changed) {
ApplyDependencies(_checkboxes, _dependencies, changed);
}
void EditAdminBox::refreshAboutAddAdminsText() {
auto addAdmins = _checkboxes.find(Flag::f_add_admins);
Assert(addAdmins != _checkboxes.end());
auto text = [this, addAdmins] {
if (!canSave()) {
return lang(lng_rights_about_admin_cant_edit);
} else if (addAdmins->second->checked()) {
return lang(lng_rights_about_add_admins_yes);
}
return lang(lng_rights_about_add_admins_no);
};
_aboutAddAdmins->setText(text());
resizeToContent();
}
EditRestrictedBox::EditRestrictedBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, bool hasAdminRights, const MTPChannelBannedRights &rights) : EditParticipantBox(nullptr, channel, user, hasAdminRights)
, _oldRights(rights) {
auto dependency = [this](Flag dependent, Flag dependency) {
_dependencies.push_back(std::make_pair(dependent, dependency));
};
dependency(Flag::f_send_gifs, Flag::f_send_stickers); // stickers <-> gifs
dependency(Flag::f_send_stickers, Flag::f_send_gifs);
dependency(Flag::f_send_games, Flag::f_send_stickers); // stickers <-> games
dependency(Flag::f_send_stickers, Flag::f_send_games);
dependency(Flag::f_send_inline, Flag::f_send_stickers); // stickers <-> inline
dependency(Flag::f_send_stickers, Flag::f_send_inline);
dependency(Flag::f_send_stickers, Flag::f_send_media); // stickers -> send_media
dependency(Flag::f_embed_links, Flag::f_send_media); // embed_links -> send_media
dependency(Flag::f_send_media, Flag::f_send_messages); // send_media- > send_messages
dependency(Flag::f_send_messages, Flag::f_view_messages); // send_messages -> view_messages
}
void EditRestrictedBox::prepare() {
EditParticipantBox::prepare();
setTitle(langFactory(lng_rights_user_restrictions));
addControl(object_ptr<BoxContentDivider>(this), QMargins());
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_user_restrictions_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
auto prepareRights = (_oldRights.c_channelBannedRights().vflags.v ? _oldRights : DefaultRights(channel()));
_until = prepareRights.c_channelBannedRights().vuntil_date.v;
auto addCheckbox = [&](Flags flags, const QString &text) {
auto checked = (prepareRights.c_channelBannedRights().vflags.v & flags) == 0;
auto control = addControl(object_ptr<Ui::Checkbox>(this, text, checked, st::rightsCheckbox, st::rightsToggle), st::rightsToggleMargin);
control->checkedChanges(
) | rpl::start_with_next([=](bool checked) {
InvokeQueued(this, [=] {
applyDependencies(control);
});
}, control->lifetime());
if (!canSave()) {
control->setDisabled(true);
}
_checkboxes.emplace(flags, control);
};
addCheckbox(Flag::f_view_messages, lang(lng_rights_chat_read));
addCheckbox(Flag::f_send_messages, lang(lng_rights_chat_send_text));
addCheckbox(Flag::f_send_media, lang(lng_rights_chat_send_media));
addCheckbox(Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline, lang(lng_rights_chat_send_stickers));
addCheckbox(Flag::f_embed_links, lang(lng_rights_chat_send_links));
addControl(object_ptr<BoxContentDivider>(this), st::rightsUntilMargin);
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_chat_banned_until_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
setRestrictUntil(_until);
//addControl(object_ptr<Ui::LinkButton>(this, lang(lng_rights_chat_banned_block), st::boxLinkButton));
if (canSave()) {
addButton(langFactory(lng_settings_save), [this] {
if (!_saveCallback) {
return;
}
auto newFlags = MTPDchannelBannedRights::Flags(0);
for (auto &&checkbox : _checkboxes) {
if (checkbox.second->checked()) {
newFlags &= ~checkbox.first;
} else {
newFlags |= checkbox.first;
}
}
_saveCallback(_oldRights, MTP_channelBannedRights(MTP_flags(newFlags), MTP_int(getRealUntilValue())));
});
addButton(langFactory(lng_cancel), [this] { closeBox(); });
} else {
addButton(langFactory(lng_box_ok), [this] { closeBox(); });
}
applyDependencies(nullptr);
for (auto &&checkbox : _checkboxes) {
checkbox.second->finishAnimating();
}
resizeToContent();
}
void EditRestrictedBox::applyDependencies(QPointer<Ui::Checkbox> changed) {
ApplyDependencies(_checkboxes, _dependencies, changed);
}
MTPChannelBannedRights EditRestrictedBox::DefaultRights(not_null<ChannelData*> channel) {
auto defaultRights = Flag::f_send_messages | Flag::f_send_media | Flag::f_embed_links | Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline;
return MTP_channelBannedRights(MTP_flags(defaultRights), MTP_int(0));
}
void EditRestrictedBox::showRestrictUntil() {
auto tomorrow = QDate::currentDate().addDays(1);
auto highlighted = isUntilForever() ? tomorrow : ParseDateTime(getRealUntilValue()).date();
auto month = highlighted;
_restrictUntilBox = Ui::show(
Box<CalendarBox>(
month,
highlighted,
[this](const QDate &date) {
setRestrictUntil(static_cast<int>(QDateTime(date).toTime_t()));
}),
LayerOption::KeepOther);
_restrictUntilBox->setMaxDate(QDate::currentDate().addDays(kMaxRestrictDelayDays));
_restrictUntilBox->setMinDate(tomorrow);
_restrictUntilBox->addLeftButton(langFactory(lng_rights_chat_banned_forever), [this] { setRestrictUntil(0); });
}
void EditRestrictedBox::setRestrictUntil(TimeId until) {
_until = until;
if (_restrictUntilBox) {
_restrictUntilBox->closeBox();
}
clearVariants();
createUntilGroup();
createUntilVariants();
resizeToContent();
}
void EditRestrictedBox::clearVariants() {
for (auto &&widget : base::take(_untilVariants)) {
removeControl(widget.data());
}
}
void EditRestrictedBox::createUntilGroup() {
_untilGroup = std::make_shared<Ui::RadiobuttonGroup>(isUntilForever() ? 0 : _until);
_untilGroup->setChangedCallback([this](int value) {
if (value == kUntilCustom) {
_untilGroup->setValue(_until);
showRestrictUntil();
} else if (_until != value) {
_until = value;
}
});
}
void EditRestrictedBox::createUntilVariants() {
auto addVariant = [this](int value, const QString &text) {
if (!canSave() && _untilGroup->value() != value) {
return;
}
_untilVariants.push_back(addControl(object_ptr<Ui::Radiobutton>(this, _untilGroup, value, text, st::defaultBoxCheckbox), st::rightsToggleMargin));
if (!canSave()) {
_untilVariants.back()->setDisabled(true);
}
};
auto addCustomVariant = [addVariant](TimeId until, TimeId from, TimeId to) {
if (!ChannelData::IsRestrictedForever(until) && until > from && until <= to) {
addVariant(
until,
lng_rights_chat_banned_custom_date(
lt_date,
langDayOfMonthFull(ParseDateTime(until).date())));
}
};
auto addCurrentVariant = [this, addCustomVariant](TimeId from, TimeId to) {
auto oldUntil = _oldRights.c_channelBannedRights().vuntil_date.v;
if (oldUntil < _until) {
addCustomVariant(oldUntil, from, to);
}
addCustomVariant(_until, from, to);
if (oldUntil > _until) {
addCustomVariant(oldUntil, from, to);
}
};
addVariant(0, lang(lng_rights_chat_banned_forever));
auto now = unixtime();
auto nextDay = now + kSecondsInDay;
auto nextWeek = now + kSecondsInWeek;
addCurrentVariant(0, nextDay);
addVariant(kUntilOneDay, lng_rights_chat_banned_day(lt_count, 1));
addCurrentVariant(nextDay, nextWeek);
addVariant(kUntilOneWeek, lng_rights_chat_banned_week(lt_count, 1));
addCurrentVariant(nextWeek, INT_MAX);
addVariant(kUntilCustom, lang(lng_rights_chat_banned_custom));
}
TimeId EditRestrictedBox::getRealUntilValue() const {
Expects(_until != kUntilCustom);
if (_until == kUntilOneDay) {
return unixtime() + kSecondsInDay;
} else if (_until == kUntilOneWeek) {
return unixtime() + kSecondsInWeek;
}
Assert(_until >= 0);
return _until;
}

View File

@@ -1,138 +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"
namespace Ui {
class FlatLabel;
class LinkButton;
class Checkbox;
class Radiobutton;
class RadiobuttonGroup;
} // namespace Ui
class CalendarBox;
class EditParticipantBox : public BoxContent {
public:
EditParticipantBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, bool hasAdminRights);
protected:
void prepare() override;
void resizeToContent();
not_null<UserData*> user() const {
return _user;
}
not_null<ChannelData*> channel() const {
return _channel;
}
template <typename Widget>
QPointer<Widget> addControl(object_ptr<Widget> widget, QMargins margin);
void removeControl(QPointer<TWidget> widget);
bool hasAdminRights() const {
return _hasAdminRights;
}
private:
not_null<ChannelData*> _channel;
not_null<UserData*> _user;
bool _hasAdminRights = false;
class Inner;
QPointer<Inner> _inner;
};
class EditAdminBox : public EditParticipantBox {
public:
EditAdminBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, const MTPChannelAdminRights &rights);
void setSaveCallback(Fn<void(MTPChannelAdminRights, MTPChannelAdminRights)> callback) {
_saveCallback = std::move(callback);
}
protected:
void prepare() override;
private:
using Flag = MTPDchannelAdminRights::Flag;
using Flags = MTPDchannelAdminRights::Flags;
static MTPChannelAdminRights DefaultRights(not_null<ChannelData*> channel);
bool canSave() const {
return !!_saveCallback;
}
void applyDependencies(QPointer<Ui::Checkbox> changed);
void refreshAboutAddAdminsText();
const MTPChannelAdminRights _oldRights;
std::vector<std::pair<Flag, Flag>> _dependencies;
Fn<void(MTPChannelAdminRights, MTPChannelAdminRights)> _saveCallback;
std::map<Flags, QPointer<Ui::Checkbox>> _checkboxes;
QPointer<Ui::FlatLabel> _aboutAddAdmins;
};
// Restricted box works with flags in the opposite way.
// If some flag is set in the rights then the checkbox is unchecked.
class EditRestrictedBox : public EditParticipantBox {
public:
EditRestrictedBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, bool hasAdminRights, const MTPChannelBannedRights &rights);
void setSaveCallback(Fn<void(MTPChannelBannedRights, MTPChannelBannedRights)> callback) {
_saveCallback = std::move(callback);
}
protected:
void prepare() override;
private:
using Flag = MTPDchannelBannedRights::Flag;
using Flags = MTPDchannelBannedRights::Flags;
static MTPChannelBannedRights DefaultRights(not_null<ChannelData*> channel);
bool canSave() const {
return !!_saveCallback;
}
void applyDependencies(QPointer<Ui::Checkbox> changed);
void showRestrictUntil();
void setRestrictUntil(TimeId until);
bool isUntilForever() {
return ChannelData::IsRestrictedForever(_until);
}
void clearVariants();
void createUntilGroup();
void createUntilVariants();
TimeId getRealUntilValue() const;
const MTPChannelBannedRights _oldRights;
TimeId _until = 0;
std::vector<std::pair<Flag, Flag>> _dependencies;
Fn<void(MTPChannelBannedRights, MTPChannelBannedRights)> _saveCallback;
std::map<Flags, QPointer<Ui::Checkbox>> _checkboxes;
std::shared_ptr<Ui::RadiobuttonGroup> _untilGroup;
QVector<QPointer<Ui::Radiobutton>> _untilVariants;
QPointer<CalendarBox> _restrictUntilBox;
static constexpr auto kUntilOneDay = -1;
static constexpr auto kUntilOneWeek = -2;
static constexpr auto kUntilCustom = -3;
};

View File

@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "apiwrap.h"
#include "auth_session.h"
#include "data/data_user.h"
#include "styles/style_settings.h"
#include "styles/style_boxes.h"
@@ -238,12 +239,12 @@ void EditPrivacyBox::setupContent() {
const auto group = std::make_shared<Ui::RadioenumGroup<Option>>(
_value.option);
const auto toggle = Ui::CreateChild<rpl::event_stream<>>(content);
const auto toggle = Ui::CreateChild<rpl::event_stream<Option>>(content);
group->setChangedCallback([=](Option value) {
_value.option = value;
toggle->fire({});
toggle->fire_copy(value);
});
auto optionValue = toggle->events_starting_with_copy(_value.option);
const auto addOptionRow = [&](Option option) {
return (_controller->hasOption(option) || (_value.option == option))
@@ -274,8 +275,8 @@ void EditPrivacyBox::setupContent() {
std::move(label),
st::settingsButton,
text);
button->toggleOn(toggle->events_starting_with(
rpl::empty_value()
button->toggleOn(rpl::duplicate(
optionValue
) | rpl::map([=] {
return showExceptionLink(exception);
}))->entity()->addClickHandler([=] {
@@ -284,6 +285,13 @@ void EditPrivacyBox::setupContent() {
return button;
};
auto above = _controller->setupAboveWidget(
content,
std::move(optionValue));
if (above) {
content->add(std::move(above));
}
AddSubsectionTitle(content, _controller->optionsTitleKey());
addOptionRow(Option::Everyone);
addOptionRow(Option::Contacts);

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