Compare commits

...

388 Commits

Author SHA1 Message Date
John Preston
bec39d89e1 Beta version 1.6.4: Fix dialogs up button glitch. 2019-04-05 19:52:45 +04:00
23rd
467f1449ab Beta version 1.6.4: Update dialogs up button position when resize. 2019-04-05 18:42:25 +03:00
John Preston
53c659cbda Beta version 1.6.4.
- Replace media when editing messages with media content.
- Jump quickly to the top of your chats list.
- Get emoji suggestions for the first word you type in a message.
- Help Telegram improve emoji suggestions in your language
using this interface https://translations.telegram.org/en/emoji
2019-04-05 15:53:46 +04:00
John Preston
5deee18247 Use channels.exportMessageLink to check links. 2019-04-05 15:50:16 +04:00
John Preston
60a991bcb0 Fix typing / send action updates handling. 2019-04-05 15:17:34 +04:00
John Preston
d3c5ed08ab Add qt_signal_producer.h to git. 2019-04-05 14:41:06 +04:00
John Preston
2bdce7dce6 Fix window activations handling without event loop nesting.
This was causing an assertion violation in Ui::PostponeCall.

- Add a generic Core::QtSignalProducer to convert Qt signals to rpl::producer.
- Track event loop nesting inside QtSignalProducer.
- Use QtSignalProducer for QWindow::activeChanged tracking.
2019-04-05 14:13:54 +04:00
23rd
41b2e7c9c7 Added floating button in dialog list to jump to top. 2019-04-05 14:13:18 +04:00
John Preston
6021923bf1 Closed alpha version 1.6.3.6: Fix instructions. 2019-04-04 21:51:06 +04:00
John Preston
839cedde65 Closed alpha version 1.6.3.6: Update to VS 2019. 2019-04-04 20:51:42 +04:00
23rd
92d10fd34c Redesigned edit media button. Slightly refactored.
- Added minimal height of thumbs.
 - Removed unused _statusw.
2019-04-04 20:51:00 +04:00
23rd
25e0e4b5d3 Fixed edit single media to photo with bad dimensions. 2019-04-04 20:23:44 +04:00
John Preston
43cc2145a8 Don't update radial animations in cycle. 2019-04-04 19:31:07 +04:00
John Preston
c3c46f8e29 Fix new animations engine bug. 2019-04-04 19:31:03 +04:00
John Preston
0744f43a0e Create private channel post links. 2019-04-04 19:31:02 +04:00
John Preston
73470c3a95 Handle private channel post links. 2019-04-04 19:30:59 +04:00
23rd
a6d0fa433e Refactored variables for edit media in HistoryItem.
- Replaced _isLocalUpdateMedia with client flag.
 - Removed _isEditingMedia.
2019-04-04 13:23:14 +03:00
23rd
a9fa49e372 Disabled edit media with gif files. 2019-04-04 11:02:42 +03:00
23rd
2cb69f0c2b Added ability to edit album items with remoteContent. 2019-04-04 11:01:10 +03:00
23rd
1da9bfc643 Removed unnecessary making thumbnail of remoteContent. 2019-04-04 10:13:13 +03:00
23rd
78227cd947 Fixed MIME checking for files when edit media. 2019-04-04 10:13:11 +03:00
John Preston
456a949d01 Fix working with document thumbnails. 2019-04-04 00:08:05 +04:00
John Preston
7f598e358a Fix edit media preview for Retina screen. 2019-04-04 00:08:05 +04:00
John Preston
a058e75a6d Fix crashes on macOS 10.14.4 by disabling GPU switches.
Fixes macOS regression when OpenGL apps crash on GPU switches.
See https://bugreports.qt.io/browse/QTCREATORBUG-22215

Fixes #5858.
2019-04-04 00:08:05 +04:00
23rd
48362cd4bc Added more appropriate phrase for invalid files in edit media. 2019-04-03 20:08:27 +03:00
23rd
bd653dfdff Refactored ApiWrap.
- Joined editUploadedPhoto with editUploadedDocument.
2019-04-03 20:00:12 +03:00
John Preston
bc03c80d8d Closed alpha version 1.6.3.6. 2019-04-03 16:57:49 +04:00
John Preston
2dcbe15f8b Ignore tab key in emoji suggestions for Support mode. 2019-04-03 16:57:48 +04:00
John Preston
b364cbbd69 Improve support accounts presentation.
- Change "Bot Info" to "User Info".
- Remove "Block user" and "Add to Group" buttons from profile page.
- Allow revoking messages from support chats.
2019-04-03 16:50:38 +04:00
John Preston
3e374eda51 Fix video messages with disabled autoplay. 2019-04-03 16:50:38 +04:00
John Preston
0ae63b072c Update some icons. 2019-04-03 16:50:38 +04:00
John Preston
f718410df3 Improve sticker sending by drag-n-drop preview. 2019-04-03 16:50:38 +04:00
John Preston
74e120bc7b Don't show digits in first word emoji suggestions. 2019-04-03 16:50:38 +04:00
John Preston
5f8ede194b Fix rendering of large images on macOS. 2019-04-03 16:42:08 +04:00
John Preston
4d321b1cf0 Fix crash in Clang in Xcode 10.2. 2019-04-03 13:09:49 +04:00
23rd
84858b8940 Added MEDIA_NEW_INVALID error handler. Disabled edit media with webp. 2019-04-02 20:28:54 +03:00
23rd
92f95fa9eb Fixed crash when edit album item with photo with invalid dimensions.
- Added InformBox for invalid files.
2019-04-02 18:14:12 +04:00
23rd
5d8888bb8b Refactored code.
- Refactored passing message id to edit media.
 - Removed get/setEditMedia from mainwidget.
 - Combined onEditMedia and onSendFileConfirm in single method.
 - Added argument in FileLoadTask to pass message id to edit media.
 - Renamed flags in apiwrap.
 - Added check for allowing edit media when use clipboard.
 - Removed unused fileIsValidForAlbum.
 - Removed LOGs.
 - Replaced _isNotAlbum with _isAlbum.
 - Removed _viaRemoteContent.
 - Removed _newMediaPath.
 - Added empty() to MessageGroupId.
2019-04-02 18:14:12 +04:00
23rd
4988d21819 Added ability to edit media via clipboard and remoteContent.
- Moved thumb updating to updateEditPreview() method.
 - Added _viaRemoteContent var to check when we use remoteContent.
 - Added setMimeDataHook to handle clipboard content.
2019-04-02 18:14:12 +04:00
23rd
94964c35ce Fixed false definition FileMediaInformation as Image. 2019-04-02 18:14:12 +04:00
23rd
d605b18ec0 Fixed checking for song without file path. 2019-04-02 18:14:12 +04:00
23rd
590e6c8e9d Fixed ability to cancel edit media in albums. 2019-04-02 18:14:12 +04:00
23rd
67572b0d9a Added canceling upload edit media to Data::Media destructors.
- We should stop upload media if message was deleted from other client.
2019-04-02 18:14:12 +04:00
23rd
5554867553 Fixed editing other messages when media is edited.
- Added new condition for skipping message in History::lastSentMessage.
 - Added reset of _savedMedia in HistoryMessage destructor.
2019-04-02 18:14:12 +04:00
23rd
f3102573ea Improved applying edition.
- Fixed cancel single media.
2019-04-02 18:14:12 +04:00
23rd
0e7ce97da7 Refacotred HistoryWidget::sendFileConfirmed.
- New way to edit media in message.
 - Added some "const".
 - Fixed uploading state in albums when edit media.
2019-04-02 18:14:12 +04:00
23rd
9d789c2657 Fixed sending groupId when edit media. 2019-04-02 18:14:12 +04:00
23rd
468975e9f3 Added to AbstractBox ability to center box when changing dimensions.
- Added using of force center for edit_caption_box.
2019-04-02 18:14:12 +04:00
23rd
145dda843e Added initial local reference for edited media. 2019-04-02 18:14:12 +04:00
23rd
6e69069ba2 Added Ctrl+E and Ctrl+O shortcut to edit media. 2019-04-02 18:14:12 +04:00
23rd
be2b2cbf7e Refactored ApiWrap::editMedia.
- Slightly refactored checkEntitiesAndViewsUpdate.
 - Slightly refactored HistoryMessage.
2019-04-02 18:14:12 +04:00
23rd
0e4d85a5e5 Added handler for MESSAGE_NOT_MODIFIED error when edit media. 2019-04-02 18:14:12 +04:00
23rd
653fd1bb63 Added initial implementation of cancel of media uploading for editing. 2019-04-02 18:14:12 +04:00
23rd
741501d1d9 Removed sending gif attributes when edit media.
- Removed handling gif for render animated preview.
2019-04-02 18:14:12 +04:00
23rd
89e1291d86 Added confirming only images and videos when edit album item.
- Added hiding of checkbox when edit album item.
2019-04-02 18:14:12 +04:00
23rd
25e3674819 Added allowsEditMedia() to Media. Slightly refactored. 2019-04-02 18:14:12 +04:00
23rd
c84f99cf3a Fixed uploading edit media with thumbnails. 2019-04-02 18:14:12 +04:00
23rd
820c7ba84e Added checkbox to send photo as file for edit media. 2019-04-02 18:14:12 +04:00
23rd
6735605f21 Added animated gif preview when users edits media. 2019-04-02 18:14:12 +04:00
23rd
d5a2daa8c9 Refactored edit_caption_box. 2019-04-02 18:14:12 +04:00
23rd
25177d9022 Added updating of thumbnails when user edits media. 2019-04-02 18:14:12 +04:00
23rd
f24ce584db Fixed item updating when upload editing media. 2019-04-02 18:14:12 +04:00
23rd
1ed83cf193 Fixed subscribeToUploader. 2019-04-02 18:14:12 +04:00
23rd
aaf61dfbad Fixed NewUnread message type. 2019-04-02 18:14:11 +04:00
23rd
be58e23775 Init edit media. 2019-04-02 18:14:11 +04:00
John Preston
db631acf80 Remove old animations code. 2019-04-02 14:33:54 +04:00
John Preston
74dc4e0c62 Allow disabling new animations. 2019-04-02 14:33:54 +04:00
John Preston
99bb09374d Use new animations engine everywhere. 2019-04-02 14:33:53 +04:00
John Preston
a6e96f9a28 Use new animations engine in all Basic-s. 2019-04-02 14:33:53 +04:00
John Preston
cd3c1c6dc0 Use new animations engine for typings. 2019-04-02 14:33:53 +04:00
John Preston
3971f27c66 Closed alpha version 1.6.3.4. 2019-04-02 14:33:53 +04:00
John Preston
c4357c7ad3 Animate suggestions select-by-keyboard. 2019-04-02 14:33:53 +04:00
John Preston
1da9385fe2 Scroll suggestions by dragging. 2019-04-02 14:33:53 +04:00
John Preston
9ba65e9ca0 Skip flags and some other suggestions. 2019-04-02 14:33:53 +04:00
John Preston
a12bc60ef5 Redesign emoji suggestions widget. 2019-04-02 14:33:53 +04:00
John Preston
f76dc74040 Show emoji by first word after a delay. 2019-04-02 14:33:53 +04:00
John Preston
932ed20c4b Refresh emoji after server responds. 2019-04-02 14:33:53 +04:00
John Preston
b353af00c9 Fix crash in login. 2019-04-02 14:33:53 +04:00
John Preston
ce2204e120 Add caching for emoji keywords. 2019-04-02 14:33:53 +04:00
John Preston
4b3a9fac67 Use several LRU input languages. 2019-04-02 14:33:53 +04:00
John Preston
54ca5772f8 Closed alpha version 1.6.3.3. 2019-04-02 14:33:53 +04:00
John Preston
2dacf1b2ef Accept any characters for suggestions. 2019-04-02 14:33:53 +04:00
John Preston
817e9aa43d Fix crash in emoji keywords init. 2019-04-02 14:33:53 +04:00
John Preston
dba677dcc7 Filter emoji languages by server. 2019-04-02 14:33:53 +04:00
John Preston
24dcde2f87 Closed alpha version 1.6.3.2. 2019-04-02 14:33:53 +04:00
John Preston
77fbf19a72 Use serverside keywords for emoji suggestions. 2019-04-02 14:33:53 +04:00
John Preston
3cd9d4b5ec Fix video messages playback on Retina. 2019-04-02 14:33:53 +04:00
John Preston
d3bf489bea Improve base::binary_guard interface. 2019-04-02 14:33:52 +04:00
John Preston
efb2972d28 Move delete-from-ToS to AuthSession. 2019-04-02 14:33:52 +04:00
23rd
3fa3428b4b Added ability to go to top of media panel by clicking on selected tab. 2019-04-02 14:33:52 +04:00
John Preston
84e9e37353 Closed alpha version 1.6.3.1: Fix build for Xcode. 2019-03-29 14:24:08 +04:00
John Preston
5c0f278775 Closed alpha version 1.6.3.1. 2019-03-29 14:24:08 +04:00
John Preston
8759d637ff Use StorageFileLocation in mtpFileLoader. 2019-03-29 14:24:07 +04:00
John Preston
95023ca770 Use StorageFileLocation in streaming loader. 2019-03-29 14:24:07 +04:00
John Preston
3f49796c43 Fix file reference updating. 2019-03-29 14:24:07 +04:00
John Preston
aa8f62da9d Support new ('modern') API file locations. 2019-03-29 14:24:07 +04:00
John Preston
eba2a98703 Add general StorageFileLocation abstraction. 2019-03-29 14:24:06 +04:00
John Preston
d36f6a0322 Update API scheme to layer 98. 2019-03-29 14:24:06 +04:00
John Preston
9ec3d24fec Send ImageSize instead of Video for image/gif. 2019-03-26 17:40:40 +04:00
John Preston
bf182697b9 Use streaming player speed in 2x playback. 2019-03-26 16:51:40 +04:00
John Preston
e87084715d Fix song / voice playback. 2019-03-26 16:51:40 +04:00
John Preston
3bd1bbc77a Use Streaming::Player in video messages playback. 2019-03-26 16:51:39 +04:00
John Preston
8aaa70a05a Fix infinite group set requests on bad API responses. 2019-03-26 16:51:10 +04:00
John Preston
9b247ce5ed Version 1.6.4: Fix leaving + rejoining for channels. 2019-03-25 16:47:19 +04:00
Royal Wizard
09ff556aa6 Version 1.6.3: Add child abuse report reason (#5828) 2019-03-25 16:07:30 +04:00
John Preston
a26d82eec6 Version 1.6.3:
- Bug fixes and other minor improvements.
2019-03-25 16:04:59 +04:00
John Preston
bb2e683dea Fix leaving channels and supergroups.
Fixes #5838.
2019-03-25 15:52:30 +04:00
John Preston
d7a67a6a1c Fix two crashes in groups edit. 2019-03-25 11:57:04 +04:00
John Preston
8c6e72b21a Hide Nobody option from profile photo privacy. 2019-03-25 11:57:04 +04:00
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
676 changed files with 30608 additions and 16155 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

View File

@@ -44,7 +44,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
## Build instructions
* [Visual Studio 2017][msvc]
* [Visual Studio 2019][msvc]
* [Xcode 10][xcode]
* [GYP/CMake on GNU/Linux][cmake]

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,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
@@ -252,8 +252,28 @@ index 41834b2..8cdf4ab 100644
if (value == WSAEADDRNOTAVAIL) {
setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
socketState = QAbstractSocket::UnconnectedState;
diff --git a/src/platformsupport/cglconvenience/cglconvenience.mm b/src/platformsupport/cglconvenience/cglconvenience.mm
index fb609ae485..7cca45ded4 100644
--- a/src/platformsupport/cglconvenience/cglconvenience.mm
+++ b/src/platformsupport/cglconvenience/cglconvenience.mm
@@ -128,7 +128,14 @@ void *qcgl_createNSOpenGLPixelFormat(const QSurfaceFormat &format)
if (format.stereo())
attrs << NSOpenGLPFAStereo;
- attrs << NSOpenGLPFAAllowOfflineRenderers;
+ // Patch: Fix macOS regression. It crashes on GPU switches.
+ // See https://bugreports.qt.io/browse/QTCREATORBUG-22215
+ static const QAppleOperatingSystemVersion version = qt_apple_os_version();
+ if ((version.major < 10)
+ || (version.major == 10 && version.minor < 14)
+ || (version.major == 10 && version.minor == 14 && version.patch < 4)) {
+ attrs << NSOpenGLPFAAllowOfflineRenderers;
+ }
QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER");
if (!useLayer.isEmpty() && useLayer.toInt() > 0) {
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 +310,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 +408,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 +470,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 +502,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 +516,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 +530,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 +547,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 +561,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 +592,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 +606,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 +644,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 +674,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 +701,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 +841,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 +903,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 +977,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 +1194,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 +1209,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 +1224,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 +1278,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 +1293,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 +1323,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 +1339,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 +1374,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 +1388,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 +1429,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 +1482,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 +1497,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 +1528,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 +1570,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);
@@ -294,4 +294,7 @@ notifyFadeRight: icon {{ "fade_horizontal", notificationBg }};
stickerIconLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }};
stickerIconRight: icon {{ "fade_horizontal", emojiPanCategories }};
emojiSuggestionsFadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }};
emojiSuggestionsFadeRight: icon {{ "fade_horizontal", boxBg }};
transparentPlaceholderSize: 4px;

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.

Before

Width:  |  Height:  |  Size: 807 B

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 946 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.

Before

Width:  |  Height:  |  Size: 551 B

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 B

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 B

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 458 B

After

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 1.2 KiB

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.

Before

Width:  |  Height:  |  Size: 438 B

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 B

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -141,12 +141,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_error_cant_ban_admin" = "Sorry, you can't ban this user because they are an admin in this group and you are not allowed to demote them.";
"lng_error_admin_limit" = "Sorry, you've reached the maximum number of admins for this group.";
"lng_error_admin_limit_channel" = "Sorry, you've reached the maximum number of admins for this channel.";
"lng_error_post_link_invalid" = "Unfortunately, you can't access this message. You are not a member of the chat where it was posted.";
"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_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_remove_user_group" = "Remove {user} from the group?";
"lng_sure_remove_user_channel" = "Remove {user} from 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";
@@ -164,6 +163,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_pinned_unpin" = "Unpin";
"lng_pinned_notify" = "Notify all members";
"lng_edit_media_album_error" = "This file cannot be saved as a part of an album.";
"lng_edit_media_invalid_file" = "Sorry, no way to use this file.";
"lng_intro_about" = "Welcome to the official Telegram Desktop app.\nIt's fast and secure.";
"lng_start_msgs" = "START MESSAGING";
@@ -361,6 +363,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";
@@ -398,10 +402,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_theme_keep_changes" = "Keep changes";
"lng_theme_revert" = "Revert";
"lng_background_header" = "Background preview";
"lng_background_text1" = "You can't swipe left or right to preview anything - this is tdesktop, sorry.";
"lng_background_text2" = "Sounds awful.";
"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";
@@ -434,7 +442,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";
@@ -636,6 +646,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";
@@ -799,6 +830,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"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.";
@@ -812,6 +849,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_report_message_title" = "Report message";
"lng_report_reason_spam" = "Spam";
"lng_report_reason_violence" = "Violence";
"lng_report_reason_child_abuse" = "Child Abuse";
"lng_report_reason_pornography" = "Pornography";
"lng_report_reason_other" = "Other";
"lng_report_reason_description" = "Description";
@@ -856,6 +894,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";
@@ -991,6 +1031,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_invite_no_room" = "Unable to join this group because there are too many members in it already.";
"lng_channel_public_link_copied" = "Link copied to clipboard.";
"lng_context_about_private_link" = "This link will only work for members of this chat.";
"lng_forwarded" = "Forwarded from {user}";
"lng_forwarded_date" = "Original: {date}";
@@ -998,6 +1039,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}";
@@ -1035,6 +1078,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"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";
@@ -1091,6 +1135,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";
@@ -1215,6 +1260,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_duration_played" = "{played} / {duration}";
"lng_date_and_duration" = "{date}, {duration}";
"lng_choose_image" = "Choose an image";
"lng_choose_file" = "Choose a file";
"lng_choose_files" = "Choose files";
"lng_game_tag" = "Game";
@@ -1252,6 +1298,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";
@@ -1350,8 +1397,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";
@@ -1406,7 +1460,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";
@@ -1484,6 +1538,8 @@ 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?";

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

@@ -191,9 +191,12 @@ inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto;
inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation;
inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
inputTakeoutFileLocation#29be5899 = InputFileLocation;
inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation;
inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation;
peerUser#9db1bc6d user_id:int = Peer;
peerChat#bad0e5bb chat_id:int = Peer;
@@ -210,14 +213,11 @@ storage.fileMov#4b09ebbc = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;
fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation;
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;
userProfilePhoto#ecd75d8c photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto;
userStatusEmpty#9d05049 = UserStatus;
userStatusOnline#edb93949 expires:int = UserStatus;
@@ -243,7 +243,7 @@ chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?
chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants;
chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
chatPhoto#475cdbd5 photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
@@ -278,7 +278,7 @@ messageActionHistoryClear#9fbab604 = MessageAction;
messageActionGameScore#92a72876 game_id:long score:int = MessageAction;
messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction;
messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction;
messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
messageActionScreenshotTaken#4792929b = MessageAction;
messageActionCustomAction#fae69f56 message:string = MessageAction;
messageActionBotAllowed#abe9affe domain:string = MessageAction;
@@ -289,7 +289,7 @@ 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;
photoEmpty#2331b22d id:long = Photo;
photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> = Photo;
photo#d07504a5 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> dc_id:int = Photo;
photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
@@ -318,7 +318,7 @@ peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bo
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
wallPaper#f04f91ec id:long flags:# creator:flags.0?true default:flags.1?true access_hash:long slug:string document:Document = 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;
@@ -446,7 +446,7 @@ 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;
@@ -542,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;
@@ -612,13 +616,13 @@ chatInviteEmpty#69df3769 = ExportedChatInvite;
chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector<User> = ChatInvite;
chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
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#eeb46f27 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 thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
@@ -726,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;
@@ -894,11 +898,11 @@ inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_co
inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall;
phoneCallEmpty#5366c915 id:long = PhoneCall;
phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCall#e6f9ddf3 flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector<PhoneConnection> start_date:int = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
phoneCallWaiting#1b8f4ad1 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
phoneCallRequested#87eabb53 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
@@ -924,7 +928,7 @@ langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:fl
channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction;
channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction;
channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction;
@@ -1112,6 +1116,25 @@ 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;
emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage;
fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -1122,7 +1145,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;
@@ -1154,7 +1177,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;
@@ -1162,7 +1185,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;
@@ -1174,7 +1197,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;
@@ -1186,10 +1209,13 @@ 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.uploadWallPaper#c7ba9b4d file:InputFile mime_type:string = WallPaper;
account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper;
account.saveWallPaper#189581b3 wallpaper:InputWallPaper unsave:Bool = Bool;
account.installWallPaper#4a0378ce wallpaper:InputWallPaper = Bool;
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;
@@ -1218,7 +1244,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;
@@ -1316,9 +1342,13 @@ messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer
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#83f6c0cd peer:InputPeer = StatsURL;
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.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector<string> = Vector<EmojiLanguage>;
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;
@@ -1404,18 +1434,18 @@ stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = mes
stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet;
phone.getCallConfig#55451fa9 = DataJSON;
phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
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.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = 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 93
// LAYER 98

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="1.5.8.0" />
Version="1.6.4.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,8,0
PRODUCTVERSION 1,5,8,0
FILEVERSION 1,6,4,0
PRODUCTVERSION 1,6,4,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.8.0"
VALUE "FileVersion", "1.6.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2019"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.5.8.0"
VALUE "ProductVersion", "1.6.4.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,5,8,0
PRODUCTVERSION 1,5,8,0
FILEVERSION 1,6,4,0
PRODUCTVERSION 1,6,4,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.8.0"
VALUE "FileVersion", "1.6.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2019"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.5.8.0"
VALUE "ProductVersion", "1.6.4.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

@@ -25,7 +25,7 @@ class mtpFileLoader;
namespace Data {
struct UpdatedFileReferences;
struct WallPaper;
class WallPaper;
} // namespace Data
namespace InlineBots {
@@ -76,6 +76,7 @@ public:
ChannelData *channel,
MsgId msgId,
RequestMessageDataCallback callback);
QString exportDirectMessageLink(not_null<HistoryItem*> item);
void requestContacts();
void requestDialogEntry(not_null<Data::Feed*> feed);
@@ -172,6 +173,7 @@ public:
void clearWebPageRequest(WebPageData *page);
void clearWebPageRequests();
void requestAttachedStickerSets(not_null<PhotoData*> photo);
void scheduleStickerSetRequest(uint64 setId, uint64 access);
void requestStickerSets();
void saveStickerSets(
@@ -210,7 +212,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;
@@ -322,6 +329,13 @@ public:
SendMediaType type,
const SendOptions &options);
void editMedia(
Storage::PreparedList &&list,
SendMediaType type,
TextWithTags &&caption,
const SendOptions &options,
MsgId msgIdToEdit);
void sendUploadedPhoto(
FullMsgId localId,
const MTPInputFile &file,
@@ -331,6 +345,13 @@ public:
const MTPInputFile &file,
const std::optional<MTPInputFile> &thumb,
bool silent);
void editUploadedFile(
FullMsgId localId,
const MTPInputFile &file,
const std::optional<MTPInputFile> &thumb,
bool silent,
bool isDocument);
void cancelLocalItem(not_null<HistoryItem*> item);
struct MessageToSend {
@@ -378,6 +399,8 @@ public:
Calls,
Invites,
CallsPeer2Peer,
Forwards,
ProfilePhoto,
};
enum class Option {
Everyone,
@@ -405,7 +428,7 @@ public:
void sendPollVotes(
FullMsgId itemId,
const std::vector<QByteArray> &options);
void closePoll(FullMsgId itemId);
void closePoll(not_null<HistoryItem*> item);
void reloadPollResults(not_null<HistoryItem*> item);
~ApiWrap();
@@ -422,7 +445,7 @@ private:
struct StickersByEmoji {
std::vector<not_null<DocumentData*>> list;
int32 hash = 0;
TimeMs received = 0;
crl::time received = 0;
};
void updatesReceived(const MTPUpdates &updates);
@@ -537,6 +560,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,
@@ -728,7 +755,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;
@@ -746,7 +773,7 @@ private:
mtpRequestId _deepLinkInfoRequestId = 0;
TimeMs _termsUpdateSendAt = 0;
crl::time _termsUpdateSendAt = 0;
mtpRequestId _termsUpdateRequestId = 0;
mtpRequestId _checkInviteRequestId = 0;
@@ -794,4 +821,8 @@ private:
std::optional<bool> _contactSignupSilent;
rpl::event_stream<bool> _contactSignupSilentChanges;
mtpRequestId _attachedStickerSetsRequestId = 0;
base::flat_map<FullMsgId, QString> _unlikelyMessageLinks;
};

View File

@@ -7,11 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "app.h"
#include "styles/style_overview.h"
#include "styles/style_mediaview.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_history.h"
#include "styles/style_boxes.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "data/data_channel.h"
@@ -25,11 +20,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h"
#include "history/history_item_components.h"
#include "history/view/history_view_service_message.h"
#include "media/media_audio.h"
#include "media/audio/media_audio.h"
#include "ui/image/image.h"
#include "inline_bots/inline_bot_layout_item.h"
#include "core/crash_reports.h"
#include "core/update_checker.h"
#include "core/sandbox.h"
#include "core/application.h"
#include "window/themes/window_theme.h"
#include "window/notifications_manager.h"
#include "platform/platform_notifications_manager.h"
@@ -37,14 +34,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localstorage.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "messenger.h"
#include "application.h"
#include "mainwindow.h"
#include "mainwidget.h"
#include "apiwrap.h"
#include "numbers.h"
#include "observer_peer.h"
#include "auth_session.h"
#include "styles/style_overview.h"
#include "styles/style_mediaview.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_history.h"
#include "styles/style_boxes.h"
#ifdef OS_MAC_OLD
#include <libexif/exif-data.h>
@@ -117,10 +117,9 @@ namespace App {
}
MainWindow *wnd() {
if (auto instance = Messenger::InstancePointer()) {
return instance->getActiveWindow();
}
return nullptr;
return Core::IsAppLaunched()
? Core::App().getActiveWindow()
: nullptr;
}
MainWidget *main() {
@@ -130,22 +129,6 @@ namespace App {
return nullptr;
}
UserData *feedUser(const MTPUser &user) {
return Auth().data().user(user);
}
UserData *feedUsers(const MTPVector<MTPUser> &users) {
return Auth().data().processUsers(users);
}
PeerData *feedChat(const MTPChat &chat) {
return Auth().data().chat(chat);
}
PeerData *feedChats(const MTPVector<MTPChat> &chats) {
return Auth().data().processChats(chats);
}
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m) {
auto peerId = peerFromMTP(m.vto_id);
if (m.has_from_id() && peerId == Auth().userPeerId()) {
@@ -156,12 +139,14 @@ namespace App {
auto entities = m.has_entities()
? TextUtilities::EntitiesFromMTP(m.ventities.v)
: EntitiesInText();
const auto media = m.has_media() ? &m.vmedia : nullptr;
existing->setText({ text, entities });
existing->updateSentMedia(m.has_media() ? &m.vmedia : nullptr);
existing->updateReplyMarkup(m.has_reply_markup()
? (&m.vreply_markup)
: nullptr);
existing->updateForwardedInfo(m.has_fwd_from()
? &m.vfwd_from
: nullptr);
existing->setViewsCount(m.has_views() ? m.vviews.v : -1);
existing->indexAsNewItem();
Auth().data().requestItemTextRefresh(existing);
@@ -174,9 +159,9 @@ namespace App {
return false;
}
void updateEditedMessage(const MTPMessage &message) {
message.match([](const MTPDmessageEmpty &) {
}, [](const auto &message) {
void updateEditedMessage(const MTPMessage &m) {
m.match([](const MTPDmessageEmpty &) {
}, [&m](const auto &message) {
auto peerId = peerFromMTP(message.vto_id);
if (message.has_from_id() && peerId == Auth().userPeerId()) {
peerId = peerFromUser(message.vfrom_id);
@@ -185,6 +170,9 @@ namespace App {
peerToChannel(peerId),
message.vid.v);
if (existing) {
if (existing->isLocalUpdateMedia()) {
checkEntitiesAndViewsUpdate(m.c_message());
}
existing->applyEdition(message);
}
});
@@ -242,108 +230,14 @@ namespace App {
return feedMsgs(msgs.v, type);
}
ImagePtr image(const MTPPhotoSize &size) {
switch (size.type()) {
case mtpc_photoSize: {
auto &d = size.c_photoSize();
if (d.vlocation.type() == mtpc_fileLocation) {
auto &l = d.vlocation.c_fileLocation();
return Images::Create(
StorageImageLocation(
d.vw.v,
d.vh.v,
l.vdc_id.v,
l.vvolume_id.v,
l.vlocal_id.v,
l.vsecret.v,
l.vfile_reference.v),
d.vsize.v);
}
} break;
case mtpc_photoCachedSize: {
auto &d = size.c_photoCachedSize();
if (d.vlocation.type() == mtpc_fileLocation) {
auto &l = d.vlocation.c_fileLocation();
auto bytes = qba(d.vbytes);
return Images::Create(
StorageImageLocation(
d.vw.v,
d.vh.v,
l.vdc_id.v,
l.vvolume_id.v,
l.vlocal_id.v,
l.vsecret.v,
l.vfile_reference.v),
bytes);
} else if (d.vlocation.type() == mtpc_fileLocationUnavailable) {
const auto bytes = qba(d.vbytes);
if (auto image = App::readImage(bytes); !image.isNull()) {
return Images::Create(std::move(image), "JPG");
}
}
} break;
case mtpc_photoStrippedSize: {
const auto &d = size.c_photoStrippedSize();
auto bytes = qba(d.vbytes);
if (bytes.size() >= 3 && bytes[0] == '\x01') {
const char header[] = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49"
"\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c"
"\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37"
"\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3"
"\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff"
"\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35"
"\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00"
"\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01"
"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
"\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05"
"\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06"
"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52"
"\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28"
"\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53"
"\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75"
"\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96"
"\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6"
"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6"
"\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4"
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
"\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05"
"\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41"
"\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33"
"\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26"
"\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a"
"\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74"
"\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94"
"\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4"
"\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4"
"\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4"
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00"
"\x3f\x00";
const char footer[] = "\xff\xd9";
auto real = QByteArray(header, sizeof(header) - 1);
real[164] = bytes[1];
real[166] = bytes[2];
bytes = real + bytes.mid(3) + QByteArray::fromRawData(footer, sizeof(footer) - 1);
if (auto image = App::readImage(bytes); !image.isNull()) {
return Images::Create(std::move(image), "JPG");
}
}
} break;
}
return ImagePtr();
}
void feedInboxRead(const PeerId &peer, MsgId upTo) {
if (const auto history = App::historyLoaded(peer)) {
if (const auto history = Auth().data().historyLoaded(peer)) {
history->inboxRead(upTo);
}
}
void feedOutboxRead(const PeerId &peer, MsgId upTo, TimeId when) {
if (auto history = App::historyLoaded(peer)) {
if (auto history = Auth().data().historyLoaded(peer)) {
history->outboxRead(upTo);
if (const auto user = history->peer->asUser()) {
user->madeAction(when);
@@ -371,7 +265,7 @@ namespace App {
if (!data) return;
const auto affectedHistory = (channelId != NoChannel)
? App::history(peerFromChannel(channelId)).get()
? Auth().data().history(peerFromChannel(channelId)).get()
: nullptr;
auto historiesToCheck = base::flat_set<not_null<History*>>();
@@ -393,7 +287,7 @@ namespace App {
}
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink) {
if (const auto user = userLoaded(userId.v)) {
if (const auto user = Auth().data().userLoaded(userId.v)) {
const auto wasShowPhone = (user->contactStatus() == UserData::ContactStatus::CanAdd);
switch (myLink.type()) {
case mtpc_contactLinkContact:
@@ -413,10 +307,10 @@ namespace App {
user->setContactStatus(UserData::ContactStatus::CanAdd);
}
const auto showPhone = !isServiceUser(user->id)
const auto showPhone = !user->isServiceUser()
&& !user->isSelf()
&& user->contactStatus() == UserData::ContactStatus::CanAdd;
const auto showPhoneChanged = !isServiceUser(user->id)
const auto showPhoneChanged = !user->isServiceUser()
&& !user->isSelf()
&& (showPhone != wasShowPhone);
if (showPhoneChanged) {
@@ -431,62 +325,18 @@ namespace App {
}
}
not_null<PeerData*> peer(PeerId id) {
return Auth().data().peer(id);
}
not_null<UserData*> user(UserId id) {
return Auth().data().user(id);
}
not_null<ChatData*> chat(ChatId id) {
return Auth().data().chat(id);
}
not_null<ChannelData*> channel(ChannelId id) {
return Auth().data().channel(id);
}
PeerData *peerLoaded(PeerId id) {
return Auth().data().peerLoaded(id);
}
UserData *userLoaded(UserId id) {
return Auth().data().userLoaded(id);
}
ChatData *chatLoaded(ChatId id) {
return Auth().data().chatLoaded(id);
}
ChannelData *channelLoaded(ChannelId id) {
return Auth().data().channelLoaded(id);
}
QString peerName(const PeerData *peer, bool forDialogs) {
return peer ? ((forDialogs && peer->isUser() && !peer->asUser()->nameOrPhone.isEmpty()) ? peer->asUser()->nameOrPhone : peer->name) : lang(lng_deleted);
}
not_null<History*> history(PeerId peer) {
return Auth().data().history(peer);
}
History *historyLoaded(PeerId peer) {
return Auth().data().historyLoaded(peer);
}
not_null<History*> history(not_null<const PeerData*> peer) {
return history(peer->id);
}
History *historyLoaded(const PeerData *peer) {
return peer ? historyLoaded(peer->id) : nullptr;
}
HistoryItem *histItemById(ChannelId channelId, MsgId itemId) {
if (!itemId) return nullptr;
auto data = fetchMsgsData(channelId, false);
const auto data = fetchMsgsData(channelId, false);
if (!data) return nullptr;
auto i = data->constFind(itemId);
if (i != data->cend()) {
return i.value();
}
return nullptr;
const auto i = data->constFind(itemId);
return (i != data->cend()) ? i.value() : nullptr;
}
HistoryItem *histItemById(const ChannelData *channel, MsgId itemId) {
@@ -674,6 +524,8 @@ namespace App {
prepareCorners(SelectedOverlayLargeCorners, st::historyMessageRadius, st::msgSelectOverlay);
prepareCorners(DateCorners, st::dateRadius, st::msgDateImgBg);
prepareCorners(DateSelectedCorners, st::dateRadius, st::msgDateImgBgSelected);
prepareCorners(OverviewVideoCorners, st::overviewVideoStatusRadius, st::msgDateImgBg);
prepareCorners(OverviewVideoSelectedCorners, st::overviewVideoStatusRadius, st::msgDateImgBgSelected);
prepareCorners(InShadowCorners, st::historyMessageRadius, st::msgInShadow);
prepareCorners(InSelectedShadowCorners, st::historyMessageRadius, st::msgInShadowSelected);
prepareCorners(ForwardCorners, st::historyMessageRadius, st::historyForwardChooseBg);
@@ -810,14 +662,11 @@ namespace App {
setLaunchState(QuitRequested);
if (auto window = App::wnd()) {
if (!Core::App().isSavingSession()) {
if (!Core::Sandbox::Instance().isSavingSession()) {
window->hide();
}
}
if (auto mainwidget = App::main()) {
mainwidget->saveDraftToCloud();
}
Messenger::QuitAttempt();
Core::Application::QuitAttempt();
}
bool quitting() {

View File

@@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
enum NewMessageType : char;
enum class ImageRoundRadius;
class Messenger;
class MainWindow;
class MainWidget;
class HistoryItem;
@@ -36,6 +35,8 @@ enum RoundCorners {
SelectedOverlayLargeCorners,
DateCorners,
DateSelectedCorners,
OverviewVideoCorners,
OverviewVideoSelectedCorners,
ForwardCorners,
MediaviewSaveCorners,
EmojiHoverCorners,
@@ -65,11 +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
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached
void updateEditedMessage(const MTPMessage &m);
void addSavedGif(DocumentData *doc);
@@ -81,24 +77,9 @@ namespace App {
void feedWereDeleted(ChannelId channelId, const QVector<MTPint> &msgsIds);
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink);
ImagePtr image(const MTPPhotoSize &size);
[[nodiscard]] not_null<PeerData*> peer(PeerId id);
[[nodiscard]] not_null<UserData*> user(UserId userId);
[[nodiscard]] not_null<ChatData*> chat(ChatId chatId);
[[nodiscard]] not_null<ChannelData*> channel(ChannelId channelId);
[[nodiscard]] PeerData *peerLoaded(PeerId id);
[[nodiscard]] UserData *userLoaded(UserId userId);
[[nodiscard]] ChatData *chatLoaded(ChatId chatId);
[[nodiscard]] ChannelData *channelLoaded(ChannelId channelId);
[[nodiscard]] QString peerName(const PeerData *peer, bool forDialogs = false);
[[nodiscard]] not_null<History*> history(PeerId peer);
[[nodiscard]] History *historyLoaded(PeerId peer);
[[nodiscard]] HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
[[nodiscard]] not_null<History*> history(not_null<const PeerData*> peer);
[[nodiscard]] History *historyLoaded(const PeerData *peer);
[[nodiscard]] HistoryItem *histItemById(
const ChannelData *channel,
MsgId itemId);

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"
@@ -31,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
@@ -372,7 +372,7 @@ rpl::producer<int> AuthSessionSettings::thirdColumnWidthChanges() const {
}
AuthSession &Auth() {
auto result = Messenger::Instance().authSession();
auto result = Core::App().authSession();
Assert(result != nullptr);
return *result;
}
@@ -386,17 +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->user(user))
, _user(_data->processUser(user))
, _changelogs(Core::Changelogs::Create(this))
, _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);
@@ -429,10 +429,7 @@ 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() {
@@ -453,7 +450,7 @@ bool AuthSession::validateSelf(const MTPUser &user) {
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;
@@ -471,33 +468,47 @@ 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::termsDeleteNow() {
api().request(MTPaccount_DeleteAccount(
MTP_string("Decline ToS update")
)).send();
}
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;

View File

@@ -139,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);
}
@@ -263,11 +257,9 @@ private:
rpl::event_stream<bool> _tabbedReplacedWithInfoValue;
Variables _variables;
TimeMs _lastTimeVideoPlayedAt = 0;
};
// One per Messenger.
class AuthSession;
AuthSession &Auth();
@@ -312,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;
@@ -323,7 +315,9 @@ public:
}
void checkAutoLock();
void checkAutoLockIn(TimeMs time);
void checkAutoLockIn(crl::time time);
void localPasscodeChanged();
void termsDeleteNow();
rpl::lifetime &lifetime() {
return _lifetime;
@@ -339,12 +333,12 @@ public:
~AuthSession();
private:
static constexpr auto kDefaultSaveDelay = TimeMs(1000);
static constexpr auto kDefaultSaveDelay = crl::time(1000);
AuthSessionSettings _settings;
base::Timer _saveDataTimer;
TimeMs _shouldLockAt = 0;
crl::time _shouldLockAt = 0;
base::Timer _autoLockTimer;
const std::unique_ptr<ApiWrap> _api;

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

@@ -20,9 +20,11 @@ public:
binary_guard &operator=(binary_guard &&other);
~binary_guard();
bool alive() const;
binary_guard &operator=(std::nullptr_t);
bool alive() const;
binary_guard make_guard();
explicit operator bool() const;
private:
@@ -30,8 +32,6 @@ private:
std::atomic<bool> *_bothAlive = nullptr;
friend std::pair<binary_guard, binary_guard> make_binary_guard();
};
inline binary_guard::binary_guard(binary_guard &&other)
@@ -46,6 +46,10 @@ inline binary_guard &binary_guard::operator=(binary_guard &&other) {
return *this;
}
inline binary_guard::~binary_guard() {
destroy();
}
inline binary_guard &binary_guard::operator=(std::nullptr_t) {
destroy();
return *this;
@@ -59,10 +63,6 @@ inline bool binary_guard::alive() const {
return _bothAlive && _bothAlive->load();
}
inline binary_guard::~binary_guard() {
destroy();
}
inline void binary_guard::destroy() {
if (const auto both = base::take(_bothAlive)) {
auto old = true;
@@ -72,12 +72,30 @@ inline void binary_guard::destroy() {
}
}
inline std::pair<binary_guard, binary_guard> make_binary_guard() {
auto result = std::pair<binary_guard, binary_guard>();
result.first._bothAlive
= result.second._bothAlive
= new std::atomic<bool>(true);
inline binary_guard binary_guard::make_guard() {
destroy();
auto result = binary_guard();
_bothAlive = result._bothAlive = new std::atomic<bool>(true);
return result;
}
} // 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>(
@@ -268,7 +268,6 @@ ConcurrentTimer::ConcurrentTimer(
}
Fn<void()> ConcurrentTimer::createAdjuster() {
auto guards = base::make_binary_guard();
_guard = std::make_shared<bool>(true);
return [=, runner = _runner, guard = std::weak_ptr<bool>(_guard)] {
runner([=] {
@@ -281,7 +280,7 @@ Fn<void()> ConcurrentTimer::createAdjuster() {
}
void ConcurrentTimer::start(
TimeMs timeout,
crl::time timeout,
Qt::TimerType type,
Repeat repeat) {
_type = type;
@@ -290,16 +289,14 @@ void ConcurrentTimer::start(
setTimeout(timeout);
cancelAndSchedule(_timeout);
_next = crl::time() + _timeout;
_next = crl::now() + _timeout;
}
void ConcurrentTimer::cancelAndSchedule(int timeout) {
auto guards = base::make_binary_guard();
_running = std::move(guards.first);
auto method = [
=,
runner = _runner,
guard = std::move(guards.second)
guard = _running.make_guard()
]() mutable {
if (!guard) {
return;
@@ -319,7 +316,7 @@ void ConcurrentTimer::timerEvent() {
if (_adjusted) {
start(_timeout, _type, repeat());
} else {
_next = crl::time() + _timeout;
_next = crl::now() + _timeout;
}
} else {
cancel();
@@ -338,12 +335,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 +351,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

@@ -686,6 +686,40 @@ public:
}
return { where, false };
}
std::pair<iterator, bool> insert_or_assign(
const Key &key,
const Type &value) {
if (this->empty() || this->compare()(key, this->front().first)) {
this->impl().emplace_front(key, value);
return { this->begin(), true };
} else if (this->compare()(this->back().first, key)) {
this->impl().emplace_back(key, value);
return { this->end() - 1, true };
}
auto where = this->getLowerBound(key);
if (this->compare()(key, where->first)) {
return { this->impl().insert(where, value_type(key, value)), true };
}
where->second = value;
return { where, false };
}
std::pair<iterator, bool> insert_or_assign(
const Key &key,
Type &&value) {
if (this->empty() || this->compare()(key, this->front().first)) {
this->impl().emplace_front(key, std::move(value));
return { this->begin(), true };
} else if (this->compare()(this->back().first, key)) {
this->impl().emplace_back(key, std::move(value));
return { this->end() - 1, true };
}
auto where = this->getLowerBound(key);
if (this->compare()(key, where->first)) {
return { this->impl().insert(where, value_type(key, std::move(value))), true };
}
where->second = std::move(value);
return { where, false };
}
template <typename... Args>
std::pair<iterator, bool> emplace(
const Key &key,
@@ -695,6 +729,14 @@ public:
Type(std::forward<Args>(args)...)));
}
template <typename... Args>
std::pair<iterator, bool> emplace_or_assign(
const Key &key,
Args&&... args) {
return this->insert_or_assign(
key,
Type(std::forward<Args>(args)...));
}
template <typename... Args>
std::pair<iterator, bool> try_emplace(
const Key &key,
Args&&... args) {

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 {

View File

@@ -436,7 +436,7 @@ QPointer<Ui::IconButton> AbstractBox::addTopButton(const style::IconButton &st,
return result;
}
void AbstractBox::setDimensions(int newWidth, int maxHeight) {
void AbstractBox::setDimensions(int newWidth, int maxHeight, bool forceCenterPosition) {
_maxContentHeight = maxHeight;
auto fullHeight = countFullHeight();
@@ -447,8 +447,13 @@ void AbstractBox::setDimensions(int newWidth, int maxHeight) {
resize(newWidth, countRealHeight());
auto newGeometry = geometry();
auto parentHeight = parentWidget()->height();
if (newGeometry.top() + newGeometry.height() + st::boxVerticalMargin > parentHeight) {
auto newTop = qMax(parentHeight - int(st::boxVerticalMargin) - newGeometry.height(), (parentHeight - newGeometry.height()) / 2);
if (newGeometry.top() + newGeometry.height() + st::boxVerticalMargin > parentHeight
|| forceCenterPosition) {
const auto top1 = parentHeight - int(st::boxVerticalMargin) - newGeometry.height();
const auto top2 = (parentHeight - newGeometry.height()) / 2;
const auto newTop = forceCenterPosition
? std::min(top1, top2)
: std::max(top1, top2);
if (newTop != newGeometry.top()) {
move(newGeometry.left(), newTop);
}

View File

@@ -44,7 +44,10 @@ public:
object_ptr<BoxContent> box,
LayerOptions options,
anim::type animated) = 0;
virtual void setDimensions(int newWidth, int maxHeight) = 0;
virtual void setDimensions(
int newWidth,
int maxHeight,
bool forceCenterPosition = false) = 0;
virtual void setNoContentMargin(bool noContentMargin) = 0;
virtual bool isBoxShown() const = 0;
virtual void closeBox() = 0;
@@ -158,8 +161,11 @@ protected:
}
getDelegate()->setNoContentMargin(noContentMargin);
}
void setDimensions(int newWidth, int maxHeight) {
getDelegate()->setDimensions(newWidth, maxHeight);
void setDimensions(
int newWidth,
int maxHeight,
bool forceCenterPosition = false) {
getDelegate()->setDimensions(newWidth, maxHeight, forceCenterPosition);
}
void setDimensionsToContent(
int newWidth,
@@ -264,7 +270,10 @@ public:
void updateButtonsPositions() override;
QPointer<QWidget> outerContainer() override;
void setDimensions(int newWidth, int maxHeight) override;
void setDimensions(
int newWidth,
int maxHeight,
bool forceCenterPosition = false) override;
void setNoContentMargin(bool noContentMargin) override {
if (_noContentMargin != noContentMargin) {

View File

@@ -10,7 +10,6 @@ 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"
@@ -20,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#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"
@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#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"
@@ -65,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);
@@ -321,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();
@@ -340,14 +342,14 @@ 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;
@@ -368,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();
}
@@ -535,7 +537,7 @@ 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()) {
@@ -643,7 +645,7 @@ 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);
}
| [&](not_null<ChannelData*> channel) {
auto image = _photo->takeResultImage();
@@ -1153,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();
}
@@ -1194,7 +1196,7 @@ RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn<void()> revokeCallback) :
return data.vchats.v;
});
for (const auto &chat : chats) {
if (const auto peer = App::feedChat(chat)) {
if (const auto peer = Auth().data().processChat(chat)) {
if (!peer->isChannel() || peer->userName().isEmpty()) {
continue;
}
@@ -1207,7 +1209,7 @@ RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn<void()> revokeCallback) :
Ui::NameTextOptions());
row.status.setText(
st::defaultTextStyle,
Messenger::Instance().createInternalLink(
Core::App().createInternalLink(
textcmdLink(1, peer->userName())),
Ui::DialogTextOptions());
_rows.push_back(std::move(row));
@@ -1282,7 +1284,7 @@ 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;

View File

@@ -56,8 +56,17 @@ void AutoDownloadBox::setupContent() {
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,
@@ -111,16 +120,6 @@ void AutoDownloadBox::setupContent() {
*limit = value;
limits->fire_copy(value);
});
const auto save = [=](
Type type,
std::pair<bool, bool> pair) {
const auto limit = [](bool checked) {
return checked ? kMaxBytesLimit : 0;
};
settings->setBytesLimit(Source::User, type, limit(pair.first));
settings->setBytesLimit(Source::Group, type, limit(pair.second));
settings->setBytesLimit(Source::Channel, type, limit(pair.second));
};
addButton(langFactory(lng_connection_save), [=] {
auto allowMore = ranges::view::all(
@@ -143,11 +142,26 @@ void AutoDownloadBox::setupContent() {
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)) {

View File

@@ -8,97 +8,43 @@ 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 "history/history.h"
#include "history/history_message.h"
#include "history/view/history_view_message.h"
#include "auth_session.h"
#include "apiwrap.h"
#include "mtproto/sender.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/data_document.h"
#include "boxes/background_preview_box.h"
#include "boxes/confirm_box.h"
#include "styles/style_overview.h"
#include "styles/style_history.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
namespace {
constexpr auto kBackgroundsInRow = 3;
constexpr auto kMaxWallPaperSlugLength = 255;
[[nodiscard]] bool IsValidWallPaperSlug(const QString &slug) {
if (slug.isEmpty() || slug.size() > kMaxWallPaperSlugLength) {
return false;
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;
}
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;
const auto id = ServerMaxMsgId + (ServerMaxMsgId / 3) + (out ? 1 : 0);
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 PrepareScaledFromFull(
const QImage &image,
Images::Option blur = Images::Option(0)) {
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,
takeHeight,
Images::Option::Smooth | blur,
size,
size);
}
QPixmap PrepareScaledFromThumb(ImagePtr thumb) {
return thumb->loaded()
? App::pixmapFromImageInPlace(PrepareScaledFromFull(
thumb->original(),
Images::Option::Blurred))
: QPixmap();
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
@@ -110,9 +56,10 @@ class BackgroundBox::Inner
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();
@@ -123,14 +70,51 @@ protected:
void mouseReleaseEvent(QMouseEvent *e) override;
private:
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;
int _over = -1;
int _overDown = -1;
std::vector<Paper> _papers;
Selection _over;
Selection _overDown;
std::unique_ptr<Ui::RoundCheckbox> _check; // this is not a widget
rpl::event_stream<Data::WallPaper> _backgroundChosen;
rpl::event_stream<Data::WallPaper> _backgroundRemove;
};
@@ -145,64 +129,126 @@ void BackgroundBox::prepare() {
setDimensions(st::boxWideWidth, st::boxMaxListHeight);
_inner = setInnerWidget(object_ptr<Inner>(this), st::backgroundScroll);
_inner->setBackgroundChosenCallback([=](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) {
const auto &papers = Auth().data().wallpapers();
if (index >= 0 && index < papers.size()) {
App::main()->setChatBackground(papers[index]);
}
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) : RpWidget(parent)
, _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [=] { update(); })) {
_check->setChecked(true, Ui::RoundCheckbox::SetStyle::Fast);
if (Auth().data().wallpapers().empty()) {
resize(kBackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
resize(st::boxWideWidth, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
} else {
updateWallpapers();
updatePapers();
}
request(MTPaccount_GetWallPapers(
MTP_int(Auth().data().wallpapersHash())
)).done([=](const MTPaccount_WallPapers &result) {
if (Auth().data().updateWallpapers(result)) {
updateWallpapers();
}
}).send();
requestPapers();
subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
subscribe(Window::Theme::Background(), [=](const Window::Theme::BackgroundUpdate &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::updateWallpapers() {
const auto &papers = Auth().data().wallpapers();
const auto count = papers.size();
void BackgroundBox::Inner::requestPapers() {
request(MTPaccount_GetWallPapers(
MTP_int(Auth().data().wallpapersHash())
)).done([=](const MTPaccount_WallPapers &result) {
if (Auth().data().updateWallpapers(result)) {
updatePapers();
}
}).send();
}
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(kBackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
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.thumb->load(Data::FileOrigin());
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);
const auto &papers = Auth().data().wallpapers();
if (papers.empty()) {
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);
@@ -210,7 +256,7 @@ void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
}
auto row = 0;
auto column = 0;
for (const auto &paper : papers) {
for (const auto &paper : _papers) {
const auto increment = gsl::finally([&] {
++column;
if (column == kBackgroundsInRow) {
@@ -220,24 +266,67 @@ void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
});
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);
}
}
paper.thumb->load(Data::FileOrigin());
void BackgroundBox::Inner::validatePaperThumbnail(
const Paper &paper) const {
Expects(paper.data.thumbnail() != nullptr);
int x = st::backgroundPadding + column * (st::backgroundSize.width() + st::backgroundPadding);
int y = st::backgroundPadding + row * (st::backgroundSize.height() + st::backgroundPadding);
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());
}
const auto &pix = paper.thumb->pix(
Data::FileOrigin(),
st::backgroundSize.width(),
st::backgroundSize.height());
p.drawPixmap(x, y, pix);
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);
}
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());
}
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.);
}
}
@@ -250,282 +339,105 @@ void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
const auto skip = st::backgroundPadding;
const auto row = int((y - skip) / (height + skip));
const auto column = int((x - skip) / (width + skip));
if (y - row * (height + skip) > skip + height) {
return -1;
} else if (x - column * (width + skip) > skip + width) {
return -1;
}
const auto result = row * kBackgroundsInRow + column;
return (result < Auth().data().wallpapers().size()) ? result : -1;
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)
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;
BackgroundPreviewBox::BackgroundPreviewBox(
QWidget*,
const Data::WallPaper &paper)
: _text1(GenerateTextItem(
this,
App::history(App::user(ServiceUserId)),
lang(lng_background_text1),
false))
, _text2(GenerateTextItem(
this,
App::history(App::user(ServiceUserId)),
lang(lng_background_text2),
true))
, _paper(paper)
, _radial(animation(this, &BackgroundPreviewBox::step_radial)) {
subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
}
void BackgroundPreviewBox::prepare() {
setTitle(langFactory(lng_background_header));
addButton(langFactory(lng_background_apply), [=] { apply(); });
addButton(langFactory(lng_cancel), [=] { closeBox(); });
_scaled = PrepareScaledFromThumb(_paper.thumb);
checkLoadedDocument();
if (_paper.thumb && !_paper.thumb->loaded()) {
_paper.thumb->loadEvenCancelled(Data::FileOriginWallpaper(
_paper.id,
_paper.accessHash));
}
if (_paper.document) {
_paper.document->save(Data::FileOriginWallpaper(
_paper.id,
_paper.accessHash), QString());
if (_paper.document->loading()) {
_radial.start(_paper.document->progress());
}
}
_text1->setDisplayDate(true);
_text1->initDimensions();
_text1->resizeGetHeight(st::boxWideWidth);
_text2->initDimensions();
_text2->resizeGetHeight(st::boxWideWidth);
setDimensions(st::boxWideWidth, st::boxWideWidth);
}
void BackgroundPreviewBox::apply() {
App::main()->setChatBackground(_paper, std::move(_full));
closeBox();
}
void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto ms = getms();
if (const auto color = Window::Theme::GetWallPaperColor(_paper.slug)) {
p.fillRect(e->rect(), *color);
} else {
if (_scaled.isNull()) {
_scaled = PrepareScaledFromThumb(_paper.thumb);
if (_scaled.isNull()) {
p.fillRect(e->rect(), st::boxBg);
return;
}
}
paintImage(p);
paintRadial(p, ms);
}
paintTexts(p, ms);
}
void BackgroundPreviewBox::paintImage(Painter &p) {
Expects(!_scaled.isNull());
const auto factor = cIntRetinaFactor();
const auto size = st::boxWideWidth;
const auto from = QRect(
0,
(size - height()) / 2 * factor,
size * factor,
height() * factor);
p.drawPixmap(rect(), _scaled, from);
}
void BackgroundPreviewBox::paintRadial(Painter &p, TimeMs 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);
}
QRect BackgroundPreviewBox::radialRect() const {
const auto available = height()
- st::historyPaddingBottom
- _text1->height()
- _text2->height()
- st::historyPaddingBottom;
return QRect(
QPoint(
(width() - st::radialSize.width()) / 2,
(available - st::radialSize.height()) / 2),
st::radialSize);
}
void BackgroundPreviewBox::paintTexts(Painter &p, TimeMs ms) {
const auto height1 = _text1->height();
const auto height2 = _text2->height();
const auto top = height()
- height1
- height2
- st::historyPaddingBottom;
p.translate(0, top);
_text1->draw(p, rect(), TextSelection(), ms);
p.translate(0, height1);
_text2->draw(p, rect(), TextSelection(), ms);
p.translate(0, height2);
}
void BackgroundPreviewBox::step_radial(TimeMs 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();
}
void BackgroundPreviewBox::checkLoadedDocument() {
const auto document = _paper.document;
if (!document
|| !document->loaded(DocumentData::FilePathResolveChecked)
|| _generating) {
return;
}
_generating = Data::ReadImageAsync(document, [=](
QImage &&image) mutable {
auto [left, right] = base::make_binary_guard();
_generating = std::move(left);
crl::async([
this,
image = std::move(image),
guard = std::move(right)
]() mutable {
auto scaled = PrepareScaledFromFull(image);
crl::on_main([
this,
image = std::move(image),
scaled = std::move(scaled),
guard = std::move(guard)
]() mutable {
if (!guard) {
return;
}
_scaled = App::pixmapFromImageInPlace(std::move(scaled));
_full = std::move(image);
update();
});
});
});
}
bool BackgroundPreviewBox::Start(const QString &slug, const QString &mode) {
if (Window::Theme::GetWallPaperColor(slug)) {
Ui::show(Box<BackgroundPreviewBox>(Data::WallPaper{
Window::Theme::kCustomBackground,
0ULL, // accessHash
MTPDwallPaper::Flags(0),
slug,
}));
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));
}, [](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>(this, 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) {
}
TimeMs BackgroundPreviewBox::elementHighlightTime(
not_null<const Element*> element) {
return TimeMs();
}
bool BackgroundPreviewBox::elementInSelectionMode() {
return false;
}

View File

@@ -7,16 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/binary_guard.h"
#include "boxes/abstract_box.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 RoundCheckbox;
} // namespace Ui
namespace Data {
class WallPaper;
} // namespace Data
class BackgroundBox : public BoxContent {
public:
@@ -26,55 +21,10 @@ protected:
void prepare() override;
private:
void backgroundChosen(int index);
class Inner;
void removePaper(const Data::WallPaper &paper);
QPointer<Inner> _inner;
};
class BackgroundPreviewBox
: public BoxContent
, public HistoryView::ElementDelegate {
public:
BackgroundPreviewBox(QWidget*, const Data::WallPaper &paper);
static bool Start(const QString &slug, const QString &mode);
using Element = HistoryView::Element;
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;
TimeMs elementHighlightTime(
not_null<const Element*> element) override;
bool elementInSelectionMode() override;
protected:
void prepare() override;
void paintEvent(QPaintEvent *e) override;
private:
void apply();
void step_radial(TimeMs ms, bool timer);
QRect radialRect() const;
void checkLoadedDocument();
void paintImage(Painter &p);
void paintRadial(Painter &p, TimeMs ms);
void paintTexts(Painter &p, TimeMs ms);
AdminLog::OwnedItem _text1;
AdminLog::OwnedItem _text2;
Data::WallPaper _paper;
QImage _full;
QPixmap _scaled;
Ui::RadialAnimation _radial;
base::binary_guard _generating;
};

View File

@@ -0,0 +1,786 @@
/*
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) 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) {
Frames().paintFrame(
p,
left + _st.margin.left(),
top + _st.margin.top(),
&_st,
currentAnimationValue());
}
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([=](crl::time now) { radialAnimationCallback(now); }) {
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);
paintRadial(p);
} else if (!color) {
p.fillRect(e->rect(), st::boxBg);
return;
} else {
// Progress of pattern loading.
paintRadial(p);
}
}
paintTexts(p, ms);
}
void BackgroundPreviewBox::paintImage(Painter &p) {
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.value(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) {
const auto radial = _radial.animating();
const auto radialOpacity = radial ? _radial.opacity() : 0.;
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::radialAnimationCallback(crl::time now) {
Expects(_paper.document() != nullptr);
const auto document = _paper.document();
const auto wasAnimating = _radial.animating();
const auto updated = _radial.update(
document->progress(),
!document->loading(),
now);
if ((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) {
crl::async([
this,
image = std::move(image),
patternBackground = patternBackgroundColor(),
guard = _generating.make_guard()
]() 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,82 @@
/*
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/animations.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 radialAnimationCallback(crl::time now);
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);
void paintRadial(Painter &p);
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;
Ui::Animations::Simple _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;
@@ -582,6 +595,23 @@ backgroundScroll: ScrollArea(boxLayerScroll) {
deltab: 10px;
}
editMediaButtonSize: 29px;
editMediaButtonSkip: 8px;
editMediaButtonFileSkipRight: 1px;
editMediaButtonFileSkipTop: 7px;
editMediaButtonIconFile: icon {{ "settings_edit", menuIconFg }};
editMediaButtonIconPhoto: icon {{ "settings_edit", msgServiceFg }};
editMediaButton: IconButton {
width: editMediaButtonSize;
height: editMediaButtonSize;
icon: editMediaButtonIconPhoto;
rippleAreaSize: editMediaButtonSize;
ripple: defaultRippleAnimation;
}
calendarTitleHeight: boxTitleHeight;
calendarPrevious: IconButton {
width: calendarTitleHeight;
@@ -630,6 +660,8 @@ usernameTextStyle: TextStyle(boxTextStyle, passcodeTextStyle) {
}
usernameDefaultFg: windowSubTextFg;
editMediaCheckboxMargins: margins(0px, 15px, 23px, 15px);
downloadPathSkip: 10px;
colorEditWidth: 390px;
@@ -911,3 +943,29 @@ callSettingsButton: IconButton {
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();
@@ -320,7 +320,7 @@ void CalendarBox::Inner::paintRows(Painter &p, QRect clip) {
}
return st::windowBgOver;
};
it->second->paint(p, innerLeft, innerTop, width(), ms, &(colorOverride()->c));
it->second->paint(p, innerLeft, innerTop, width(), &(colorOverride()->c));
if (it->second->empty()) {
_ripples.erase(it);
}
@@ -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,8 +22,10 @@ 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_photo.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
@@ -456,8 +457,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();
@@ -475,11 +475,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);
}
@@ -488,49 +531,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) {
@@ -542,12 +568,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);
@@ -563,10 +689,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);
}
}
@@ -579,6 +705,28 @@ 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()) {
_moderateInChannel->session().api().kickParticipant(
@@ -622,9 +770,8 @@ void DeleteMessagesBox::deleteAndClear() {
}
}
const auto revoke = _forEveryone ? _forEveryone->checked() : false;
for (const auto &[peer, ids] : idsByPeer) {
App::main()->deleteMessages(peer, ids, revoke);
peer->session().api().deleteMessages(peer, ids, revoke);
}
Ui::hideLayer();
Auth().data().sendHistoryChangeNotifications();
@@ -656,24 +803,17 @@ ConfirmInviteBox::ConfirmInviteBox(
}();
_title->setText(title);
_status->setText(status);
if (data.vphoto.type() == mtpc_chatPhoto) {
const auto &photo = data.vphoto.c_chatPhoto();
const auto size = 160;
const auto location = StorageImageLocation::FromMTP(
size,
size,
photo.vphoto_small);
if (!location.isNull()) {
_photo = Images::Create(location);
if (!_photo->loaded()) {
subscribe(Auth().downloaderTaskFinished(), [=] {
update();
});
_photo->load(Data::FileOrigin());
}
const auto photo = Auth().data().processPhoto(data.vphoto);
if (!photo->isNull()) {
_photo = photo->thumbnail();
if (!_photo->loaded()) {
subscribe(Auth().downloaderTaskFinished(), [=] {
update();
});
_photo->load(Data::FileOrigin());
}
}
if (!_photo) {
} else {
_photoEmpty = std::make_unique<Ui::EmptyUserpic>(
Data::PeerUserpicColor(0),
title);
@@ -689,7 +829,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

@@ -151,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);
@@ -163,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 };
@@ -203,7 +211,7 @@ private:
Fn<void()> _submit;
object_ptr<Ui::FlatLabel> _title;
object_ptr<Ui::FlatLabel> _status;
ImagePtr _photo;
Image *_photo = nullptr;
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
std::vector<not_null<UserData*>> _participants;
bool _isChannel = false;

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

@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "base/qthelp_url.h"
#include "messenger.h"
#include "core/application.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/toast/toast.h"
#include "ui/effects/animations.h"
#include "ui/effects/radial_animation.h"
#include "ui/text_options.h"
#include "styles/style_boxes.h"
@@ -28,7 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kSaveSettingsDelayedTimeout = TimeMs(1000);
constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000);
class ProxyRow : public Ui::RippleButton {
public:
@@ -52,8 +53,8 @@ protected:
private:
void setupControls(View &&view);
int countAvailableWidth() const;
void step_radial(TimeMs ms, bool timer);
void paintCheck(Painter &p, TimeMs ms);
void radialAnimationCallback();
void paintCheck(Painter &p);
void showMenu();
View _view;
@@ -67,8 +68,8 @@ private:
base::unique_qptr<Ui::DropdownMenu> _menu;
bool _set = false;
Animation _toggled;
Animation _setAnimation;
Ui::Animations::Simple _toggled;
Ui::Animations::Simple _setAnimation;
std::unique_ptr<Ui::InfiniteRadialAnimation> _progress;
std::unique_ptr<Ui::InfiniteRadialAnimation> _checking;
@@ -180,8 +181,8 @@ rpl::producer<> ProxyRow::shareClicks() const {
void ProxyRow::setupControls(View &&view) {
updateFields(std::move(view));
_toggled.finish();
_setAnimation.finish();
_toggled.stop();
_setAnimation.stop();
_menuToggle->addClickHandler([=] { showMenu(); });
}
@@ -209,7 +210,7 @@ void ProxyRow::updateFields(View &&view) {
if (state == State::Connecting) {
if (!_progress) {
_progress = std::make_unique<Ui::InfiniteRadialAnimation>(
animation(this, &ProxyRow::step_radial),
[=] { radialAnimationCallback(); },
st::proxyCheckingAnimation);
}
_progress->start();
@@ -219,7 +220,7 @@ void ProxyRow::updateFields(View &&view) {
if (state == State::Checking) {
if (!_checking) {
_checking = std::make_unique<Ui::InfiniteRadialAnimation>(
animation(this, &ProxyRow::step_radial),
[=] { radialAnimationCallback(); },
st::proxyCheckingAnimation);
_checking->start();
}
@@ -241,8 +242,8 @@ void ProxyRow::updateFields(View &&view) {
update();
}
void ProxyRow::step_radial(TimeMs ms, bool timer) {
if (timer && !anim::Disabled()) {
void ProxyRow::radialAnimationCallback() {
if (!anim::Disabled()) {
update();
}
}
@@ -268,9 +269,8 @@ int ProxyRow::resizeGetHeight(int newWidth) {
void ProxyRow::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto ms = getms();
if (!_view.deleted) {
paintRipple(p, 0, 0, ms);
paintRipple(p, 0, 0);
}
const auto left = _skipLeft;
@@ -281,7 +281,7 @@ void ProxyRow::paintEvent(QPaintEvent *e) {
p.setOpacity(st::stickersRowDisabledOpacity);
}
paintCheck(p, ms);
paintCheck(p);
p.setPen(st::proxyRowTitleFg);
p.setFont(st::semiboldFont);
@@ -323,35 +323,29 @@ void ProxyRow::paintEvent(QPaintEvent *e) {
auto statusLeft = left;
if (_checking) {
_checking->step(ms);
if (_checking) {
_checking->draw(
p,
{
st::proxyCheckingPosition.x() + statusLeft,
st::proxyCheckingPosition.y() + top
},
width());
statusLeft += st::proxyCheckingPosition.x()
+ st::proxyCheckingAnimation.size.width()
+ st::proxyCheckingSkip;
}
_checking->draw(
p,
{
st::proxyCheckingPosition.x() + statusLeft,
st::proxyCheckingPosition.y() + top
},
width());
statusLeft += st::proxyCheckingPosition.x()
+ st::proxyCheckingAnimation.size.width()
+ st::proxyCheckingSkip;
}
p.drawTextLeft(statusLeft, top, width(), status);
top += st::normalFont->height + st::proxyRowPadding.bottom();
}
void ProxyRow::paintCheck(Painter &p, TimeMs ms) {
if (_progress) {
_progress->step(ms);
}
void ProxyRow::paintCheck(Painter &p) {
const auto loading = _progress
? _progress->computeState()
: Ui::RadialState{ 0., 0, FullArcLength };
const auto toggled = _toggled.current(ms, _view.selected ? 1. : 0.)
const auto toggled = _toggled.value(_view.selected ? 1. : 0.)
* (1. - loading.shown);
const auto _st = &st::defaultRadio;
const auto set = _setAnimation.current(ms, _set ? 1. : 0.);
const auto set = _setAnimation.value(_set ? 1. : 0.);
PainterHighQualityEnabler hq(p);
@@ -975,7 +969,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();
@@ -998,7 +992,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;
@@ -1140,7 +1134,7 @@ void ProxiesBoxController::applyItem(int id) {
auto j = findByProxy(Global::SelectedProxy());
Messenger::Instance().setCurrentProxy(
Core::App().setCurrentProxy(
item->data,
ProxyData::Settings::Enabled);
saveDelayed();
@@ -1163,7 +1157,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();
@@ -1188,7 +1182,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 {
@@ -1293,9 +1287,7 @@ bool ProxiesBoxController::setProxySettings(ProxyData::Settings value) {
}
}
}
Messenger::Instance().setCurrentProxy(
Global::SelectedProxy(),
value);
Core::App().setCurrentProxy(Global::SelectedProxy(), value);
saveDelayed();
return true;
}

View File

@@ -75,7 +75,7 @@ private:
not_null<Ui::InputField*> field() const;
[[nodiscard]] PollAnswer toPollAnswer(char id) const;
[[nodiscard]] PollAnswer toPollAnswer(int index) const;
[[nodiscard]] rpl::producer<Qt::MouseButton> removeClicks() const;
@@ -324,10 +324,12 @@ void Options::Option::removePlaceholder() const {
field()->setPlaceholder(nullptr);
}
PollAnswer Options::Option::toPollAnswer(char id) const {
PollAnswer Options::Option::toPollAnswer(int index) const {
Expects(index >= 0 && index < kMaxOptionsCount);
return PollAnswer{
field()->getLastText().trimmed(),
QByteArray(1, id)
QByteArray(1, ('0' + index))
};
}
@@ -388,9 +390,9 @@ void Options::Option::destroy(FnMut<void()> done) {
std::vector<PollAnswer> Options::toPollAnswers() const {
auto result = std::vector<PollAnswer>();
result.reserve(_list.size());
auto counter = char(0);
auto counter = int(0);
const auto makeAnswer = [&](const Option &option) {
return option.toPollAnswer(++counter);
return option.toPollAnswer(counter++);
};
ranges::copy(
_list

View File

@@ -7,30 +7,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/edit_caption_box.h"
#include "ui/widgets/input_fields.h"
#include "ui/image/image.h"
#include "ui/text_options.h"
#include "ui/special_buttons.h"
#include "media/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 "apiwrap.h"
#include "auth_session.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "window/window_controller.h"
#include "core/event_filter.h"
#include "core/file_utilities.h"
#include "core/mime_type.h"
#include "data/data_document.h"
#include "data/data_media_types.h"
#include "data/data_photo.h"
#include "data/data_user.h"
#include "history/history.h"
#include "history/history_item.h"
#include "lang/lang_keys.h"
#include "layout.h"
#include "auth_session.h"
#include "apiwrap.h"
#include "styles/style_history.h"
#include "media/clip/media_clip_reader.h"
#include "storage/storage_media_prepare.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_history.h"
#include "ui/image/image.h"
#include "ui/special_buttons.h"
#include "ui/text_options.h"
#include "ui/widgets/input_fields.h"
#include "window/window_controller.h"
#include "ui/widgets/checkbox.h"
#include "confirm_box.h"
EditCaptionBox::EditCaptionBox(
QWidget*,
@@ -41,19 +46,26 @@ EditCaptionBox::EditCaptionBox(
Expects(item->media() != nullptr);
Expects(item->media()->allowsEditCaption());
_isAllowedEditMedia = item->media()->allowsEditMedia();
_isAlbum = !item->groupId().empty();
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;
@@ -68,11 +80,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 {
@@ -80,7 +92,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
@@ -97,17 +109,10 @@ EditCaptionBox::EditCaptionBox(
}
if (doc) {
auto nameString = doc->isVoiceMessage()
const auto nameString = doc->isVoiceMessage()
? lang(lng_media_audio)
: doc->composeNameString();
_name.setText(
st::semiboldTextStyle,
nameString,
Ui::NameTextOptions());
_status = formatSizeText(doc->size);
_statusw = qMax(
_name.maxWidth(),
st::normalFont->width(_status));
setName(nameString, doc->size);
_isImage = doc->isImage();
_isAudio = (doc->isVoiceMessage() || doc->isAudioFile());
}
@@ -115,12 +120,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;
@@ -161,31 +169,58 @@ 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;
}
// Edit media button takes place on thumb preview
// And its height can be greater than height of thumb.
const auto minThumbHeight = st::editMediaButtonSize
+ st::editMediaButtonSkip * 2;
const auto minThumbWidth = minThumbHeight * tw / th;
if (thumbWidth < st::sendMediaPreviewSize) {
thumbWidth = (thumbWidth > minThumbWidth)
? thumbWidth
: minThumbWidth;
} 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 = [=] {
_thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(
_thumbw * cIntRetinaFactor(),
_thumbh * cIntRetinaFactor(),
Qt::IgnoreAspectRatio,
Qt::KeepAspectRatio,
Qt::SmoothTransformation));
_thumb.setDevicePixelRatio(cRetinaFactor());
};
@@ -201,7 +236,9 @@ EditCaptionBox::EditCaptionBox(
? _thumbnailImage->loaded()
: true;
subscribe(Auth().downloaderTaskFinished(), [=] {
if (!_thumbnailImageLoaded && _thumbnailImage->loaded()) {
if (!_thumbnailImageLoaded
&& _thumbnailImage
&& _thumbnailImage->loaded()) {
_thumbnailImageLoaded = true;
_refreshThumbnail();
update();
@@ -223,6 +260,22 @@ EditCaptionBox::EditCaptionBox(
_field->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
_field->setMarkdownReplacesEnabled(rpl::single(true));
_field->setEditLinkCallback(DefaultEditLinkCallback(_field));
auto r = object_ptr<Ui::SlideWrap<Ui::Checkbox>>(
this,
object_ptr<Ui::Checkbox>(
this,
lang(lng_send_file),
false,
st::defaultBoxCheckbox),
st::editMediaCheckboxMargins);
_wayWrap = r.data();
_wayWrap->toggle(false, anim::type::instant);
r->entity()->checkedChanges(
) | rpl::start_with_next([&](bool checked) {
_asFile = checked;
}, _wayWrap->lifetime());
}
bool EditCaptionBox::emojiFilter(not_null<QEvent*> event) {
@@ -244,15 +297,27 @@ void EditCaptionBox::updateEmojiPanelGeometry() {
local.x() + _emojiToggle->width() * 3);
}
void EditCaptionBox::prepareGifPreview(not_null<DocumentData*> document) {
void EditCaptionBox::prepareGifPreview(DocumentData* document) {
const auto newPath = getNewMediaPath();
if (_gifPreview) {
return;
} else if (document->isAnimation() && document->loaded()) {
_gifPreview = Media::Clip::MakeReader(document, _msgId, [this](Media::Clip::Notification notification) {
clipCallback(notification);
});
if (_gifPreview) _gifPreview->setAutoplay();
} else if (!document && newPath.isEmpty()) {
return;
}
const auto callback = [=](Media::Clip::Notification notification) {
clipCallback(notification);
};
if (document && document->isAnimation() && document->loaded()) {
_gifPreview = Media::Clip::MakeReader(
document,
_msgId,
callback);
} else if (!newPath.isEmpty()) {
_gifPreview = Media::Clip::MakeReader(
newPath,
callback);
}
if (_gifPreview) _gifPreview->setAutoplay();
}
void EditCaptionBox::clipCallback(Media::Clip::Notification notification) {
@@ -264,7 +329,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);
}
@@ -279,14 +344,227 @@ void EditCaptionBox::clipCallback(Media::Clip::Notification notification) {
}
}
void EditCaptionBox::updateEditPreview() {
using Info = FileMediaInformation;
const auto file = &_preparedList.files.front();
const auto fileMedia = &file->information->media;
const auto fileinfo = QFileInfo(file->path);
const auto filename = fileinfo.fileName();
_isImage = fileIsImage(filename, file->mime);
_isAudio = false;
_animated = false;
_photo = false;
_doc = false;
_gifPreview = nullptr;
_thumbw = _thumbh = _thumbx = 0;
_gifw = _gifh = _gifx = 0;
auto shouldAsDoc = true;
if (const auto image = base::get_if<Info::Image>(fileMedia)) {
shouldAsDoc = !Storage::ValidateThumbDimensions(
image->data.width(),
image->data.height());
_photo = !shouldAsDoc;
_isImage = true;
} else if (const auto video = base::get_if<Info::Video>(fileMedia)) {
_animated = true;
// Never edit video as gif.
video->isGifv = false;
shouldAsDoc = false;
}
if (shouldAsDoc) {
auto nameString = filename;
if (const auto song = base::get_if<Info::Song>(fileMedia)) {
nameString = DocumentData::ComposeNameString(
filename,
song->title,
song->performer);
_isAudio = true;
}
setName(
nameString.isEmpty()
? QString("file")
: nameString,
fileinfo.size()
? fileinfo.size()
: _preparedList.files.front().content.size());
_doc = true;
}
_wayWrap->toggle(_photo && !_isAlbum, anim::type::instant);
if (!_doc) {
_thumb = App::pixmapFromImageInPlace(
file->preview.scaled(
st::sendMediaPreviewSize * cIntRetinaFactor(),
st::confirmMaxHeight * cIntRetinaFactor(),
Qt::KeepAspectRatio));
_thumbw = _thumb.width() / cIntRetinaFactor();
_thumbh = _thumb.height() / cIntRetinaFactor();
_thumbx = (st::boxWideWidth - _thumbw) / 2;
}
updateEditMediaButton();
captionResized();
}
void EditCaptionBox::updateEditMediaButton() {
const auto icon = _doc
? &st::editMediaButtonIconFile
: &st::editMediaButtonIconPhoto;
const auto color = _doc ? &st::windowBgRipple : &st::callFingerprintBg;
_editMedia->setIconOverride(icon);
_editMedia->setRippleColorOverride(color);
_editMedia->setForceRippled(!_doc, anim::type::instant);
}
void EditCaptionBox::createEditMediaButton() {
const auto callback = [=](FileDialog::OpenResult &&result) {
if (result.paths.isEmpty() && result.remoteContent.isEmpty()) {
return;
}
const auto isValidFile = [](QString mimeType) {
if (mimeType == qstr("image/webp")
|| mimeType == qstr("image/gif")) {
Ui::show(
Box<InformBox>(lang(lng_edit_media_invalid_file)),
LayerOption::KeepOther);
return false;
}
return true;
};
if (!result.remoteContent.isEmpty()) {
auto list = Storage::PrepareMediaFromImage(
QImage(),
std::move(result.remoteContent),
st::sendMediaPreviewSize);
if (!isValidFile(list.files.front().mime)) {
return;
}
if (_isAlbum) {
const auto albumMimes = {
"image/jpeg",
"image/png",
"video/mp4",
};
if ((ranges::find(albumMimes, list.files.front().mime)
== end(albumMimes))) {
Ui::show(
Box<InformBox>(lang(lng_edit_media_album_error)),
LayerOption::KeepOther);
return;
}
}
_preparedList = std::move(list);
} else if (!result.paths.isEmpty()) {
auto list = Storage::PrepareMediaList(
QStringList(result.paths.front()),
st::sendMediaPreviewSize);
// Don't rewrite _preparedList if new list is not valid for album.
if (_isAlbum) {
using Info = FileMediaInformation;
const auto media = &list.files.front().information->media;
const auto valid = media->match([&](const Info::Image &data) {
return Storage::ValidateThumbDimensions(
data.data.width(),
data.data.height());
}, [&](const Info::Video &data) {
return true;
}, [](auto &&other) {
return false;
});
if (!valid) {
Ui::show(
Box<InformBox>(lang(lng_edit_media_album_error)),
LayerOption::KeepOther);
return;
}
}
const auto info = QFileInfo(result.paths.front());
if (!isValidFile(Core::MimeTypeForFile(info).name())) {
return;
}
_preparedList = std::move(list);
} else {
return;
}
updateEditPreview();
};
const auto buttonCallback = [=] {
const auto filters = _isAlbum
? QStringList(qsl("Image and Video Files (*.png *.jpg *.mp4)"))
: QStringList(FileDialog::AllFilesFilter());
FileDialog::GetOpenPath(
this,
lang(lng_choose_file),
filters.join(qsl(";;")),
crl::guard(this, callback));
};
_editMediaClicks.events(
) | rpl::start_with_next(
buttonCallback,
lifetime());
// Create edit media button.
_editMedia.create(this, st::editMediaButton);
updateEditMediaButton();
_editMedia->setClickedCallback(buttonCallback);
}
void EditCaptionBox::prepare() {
addButton(langFactory(lng_settings_save), [this] { save(); });
if (_isAllowedEditMedia) {
createEditMediaButton();
} else {
_preparedList.files.clear();
}
addButton(langFactory(lng_cancel), [this] { closeBox(); });
updateBoxSize();
connect(_field, &Ui::InputField::submitted, [=] { save(); });
connect(_field, &Ui::InputField::cancelled, [=] { closeBox(); });
connect(_field, &Ui::InputField::resized, [=] { captionResized(); });
_field->setMimeDataHook([=](
not_null<const QMimeData*> data,
Ui::InputField::MimeAction action) {
if (action == Ui::InputField::MimeAction::Check) {
if (!data->hasText() && !_isAllowedEditMedia) {
return false;
}
if (data->hasImage()) {
const auto image = qvariant_cast<QImage>(data->imageData());
if (!image.isNull()) {
return true;
}
}
if (const auto urls = data->urls(); !urls.empty()) {
if (ranges::find_if(
urls,
[](const QUrl &url) { return !url.isLocalFile(); }
) == urls.end()) {
return true;
}
}
return data->hasText();
} else if (action == Ui::InputField::MimeAction::Insert) {
return fileFromClipboard(data);
}
Unexpected("action in MimeData hook.");
});
Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(),
_field);
@@ -298,6 +576,48 @@ void EditCaptionBox::prepare() {
_field->setTextCursor(cursor);
}
bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
if (!_isAllowedEditMedia) {
return false;
}
auto list = [&] {
auto url = QList<QUrl>();
auto canAddUrl = false;
// When we edit media, we need only 1 file.
if (data->hasUrls()) {
const auto first = data->urls().front();
url.push_front(first);
canAddUrl = first.isLocalFile();
}
auto result = canAddUrl
? Storage::PrepareMediaList(url, st::sendMediaPreviewSize)
: Storage::PreparedList(
Storage::PreparedList::Error::EmptyFile,
QString());
if (result.error == Storage::PreparedList::Error::None) {
return result;
} else if (data->hasImage()) {
auto image = qvariant_cast<QImage>(data->imageData());
if (!image.isNull()) {
_isImage = true;
_photo = true;
return Storage::PrepareMediaFromImage(
std::move(image),
QByteArray(),
st::sendMediaPreviewSize);
}
}
return result;
}();
_preparedList = std::move(list);
if (_preparedList.files.empty()) {
return false;
}
updateEditPreview();
return true;
}
void EditCaptionBox::captionResized() {
updateBoxSize();
resizeEvent(0);
@@ -337,8 +657,11 @@ void EditCaptionBox::setupEmojiPanel() {
void EditCaptionBox::updateBoxSize() {
auto newHeight = st::boxPhotoPadding.top() + st::boxPhotoCaptionSkip + _field->height() + errorTopSkip() + st::normalFont->height;
if (_photo) {
newHeight += _wayWrap->height() / 2;
}
if (_photo || _animated) {
newHeight += _thumbh;
newHeight += std::max(_thumbh, _gifh);
} else if (_thumbw) {
newHeight += 0 + st::msgFileThumbSize + 0;
} else if (_doc) {
@@ -346,7 +669,7 @@ void EditCaptionBox::updateBoxSize() {
} else {
newHeight += st::boxTitleFont->height;
}
setDimensions(st::boxWideWidth, newHeight);
setDimensions(st::boxWideWidth, newHeight, true);
}
int EditCaptionBox::errorTopSkip() const {
@@ -359,22 +682,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);
@@ -383,13 +708,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();
@@ -401,12 +726,9 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
nameright = 0;
statustop = st::msgFileStatusTop - st::msgFilePadding.top();
}
int32 namewidth = w - nameleft - 0;
if (namewidth > _statusw) {
//w -= (namewidth - _statusw);
//namewidth = _statusw;
}
int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top();
const auto editButton = _editMedia->width() + st::editMediaButtonSkip;
const auto namewidth = w - nameleft - editButton;
const auto x = (width() - w) / 2, y = st::boxPhotoPadding.top();
// App::roundRect(p, x, y, w, h, st::msgInBg, MessageInCorners, &st::msgInShadow);
@@ -414,7 +736,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);
@@ -423,14 +745,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);
@@ -445,10 +767,28 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
p.setPen(st::boxTextFgError);
p.drawTextLeft(_field->x(), _field->y() + _field->height() + errorTopSkip(), width(), _error);
}
if (_isAllowedEditMedia) {
_editMedia->moveToRight(
st::boxPhotoPadding.right() + (_doc
? st::editMediaButtonFileSkipRight
: st::editMediaButtonSkip),
st::boxPhotoPadding.top() + (_doc
? st::editMediaButtonFileSkipTop
: st::editMediaButtonSkip));
}
}
void EditCaptionBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
if (_photo) {
_wayWrap->resize(st::sendMediaPreviewSize, _wayWrap->height());
_wayWrap->moveToLeft(
st::boxPhotoPadding.left(),
st::boxPhotoPadding.top() + _thumbh);
}
_field->resize(st::sendMediaPreviewSize, _field->height());
_field->moveToLeft(st::boxPhotoPadding.left(), height() - st::normalFont->height - errorTopSkip() - _field->height());
_emojiToggle->moveToLeft(
@@ -465,7 +805,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();
@@ -493,6 +833,25 @@ void EditCaptionBox::save() {
if (!sentEntities.v.isEmpty()) {
flags |= MTPmessages_EditMessage::Flag::f_entities;
}
if (!_preparedList.files.empty()) {
const auto textWithTags = _field->getTextWithAppliedMarkdown();
auto sending = TextWithEntities{
textWithTags.text,
ConvertTextTagsToEntities(textWithTags.tags)
};
item->setText(sending);
Auth().api().editMedia(
std::move(_preparedList),
(!_asFile && _photo) ? SendMediaType::Photo : SendMediaType::File,
_field->getTextWithAppliedMarkdown(),
ApiWrap::SendOptions(item->history()),
item->fullId().msg);
closeBox();
return;
}
_saveRequestId = MTP::send(
MTPmessages_EditMessage(
MTP_flags(flags),
@@ -500,7 +859,7 @@ void EditCaptionBox::save() {
MTP_int(item->id),
MTP_string(sending.text),
MTPInputMedia(),
MTPnullMarkup,
MTPReplyMarkup(),
sentEntities),
rpcDone(&EditCaptionBox::saveDone),
rpcFail(&EditCaptionBox::saveFail));
@@ -531,3 +890,20 @@ bool EditCaptionBox::saveFail(const RPCError &error) {
update();
return true;
}
void EditCaptionBox::setName(QString nameString, qint64 size) {
_name.setText(
st::semiboldTextStyle,
nameString,
Ui::NameTextOptions());
_status = formatSizeText(size);
}
void EditCaptionBox::keyPressEvent(QKeyEvent *e) {
if ((e->key() == Qt::Key_E || e->key() == Qt::Key_O)
&& e->modifiers() == Qt::ControlModifier) {
_editMediaClicks.fire({});
} else {
e->ignore();
}
}

View File

@@ -8,6 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/abstract_box.h"
#include "storage/storage_media_prepare.h"
#include "ui/wrap/slide_wrap.h"
#include <rpl/event_stream.h>
namespace ChatHelpers {
class TabbedPanel;
@@ -24,6 +27,8 @@ class Media;
namespace Ui {
class InputField;
class EmojiButton;
class IconButton;
class Checkbox;
} // namespace Ui
namespace Window {
@@ -43,10 +48,11 @@ protected:
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
private:
void updateBoxSize();
void prepareGifPreview(not_null<DocumentData*> document);
void prepareGifPreview(DocumentData* document = nullptr);
void clipCallback(Media::Clip::Notification notification);
void setupEmojiPanel();
@@ -59,11 +65,24 @@ private:
void saveDone(const MTPUpdates &updates);
bool saveFail(const RPCError &error);
void setName(QString nameString, qint64 size);
bool fileFromClipboard(not_null<const QMimeData*> data);
void updateEditPreview();
void updateEditMediaButton();
int errorTopSkip() const;
void createEditMediaButton();
inline QString getNewMediaPath() {
return _preparedList.files.empty()
? QString()
: _preparedList.files.front().path;
}
not_null<Window::Controller*> _controller;
FullMsgId _msgId;
ImagePtr _thumbnailImage;
Image *_thumbnailImage = nullptr;
bool _thumbnailImageLoaded = false;
Fn<void()> _refreshThumbnail;
bool _animated = false;
@@ -83,13 +102,26 @@ private:
int _thumbh = 0;
Text _name;
QString _status;
int _statusw = 0;
bool _isAudio = false;
bool _isImage = false;
int _gifw = 0;
int _gifh = 0;
int _gifx = 0;
Storage::PreparedList _preparedList;
bool _previewCancelled = false;
mtpRequestId _saveRequestId = 0;
object_ptr<Ui::IconButton> _editMedia = nullptr;
Ui::SlideWrap<Ui::RpWidget> *_wayWrap = nullptr;
QString _newMediaPath;
bool _isAllowedEditMedia = false;
bool _isAlbum = false;
bool _asFile = false;
rpl::event_stream<> _editMediaClicks;
QString _error;
};

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

@@ -239,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))
@@ -275,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([=] {
@@ -285,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);

View File

@@ -38,21 +38,30 @@ public:
public:
using Key = ApiWrap::Privacy::Key;
virtual Key key() = 0;
virtual MTPInputPrivacyKey apiKey() = 0;
[[nodiscard]] virtual Key key() = 0;
[[nodiscard]] virtual MTPInputPrivacyKey apiKey() = 0;
virtual QString title() = 0;
virtual bool hasOption(Option option) {
[[nodiscard]] virtual QString title() = 0;
[[nodiscard]] virtual bool hasOption(Option option) {
return true;
}
virtual LangKey optionsTitleKey() = 0;
virtual LangKey optionLabelKey(Option option);
virtual rpl::producer<QString> warning() {
[[nodiscard]] virtual LangKey optionsTitleKey() = 0;
[[nodiscard]] virtual LangKey optionLabelKey(Option option);
[[nodiscard]] virtual rpl::producer<QString> warning() {
return rpl::never<QString>();
}
virtual LangKey exceptionButtonTextKey(Exception exception) = 0;
virtual QString exceptionBoxTitle(Exception exception) = 0;
virtual rpl::producer<QString> exceptionsDescription() = 0;
[[nodiscard]] virtual LangKey exceptionButtonTextKey(
Exception exception) = 0;
[[nodiscard]] virtual QString exceptionBoxTitle(
Exception exception) = 0;
[[nodiscard]] virtual auto exceptionsDescription()
-> rpl::producer<QString> = 0;
[[nodiscard]] virtual object_ptr<Ui::RpWidget> setupAboveWidget(
not_null<QWidget*> parent,
rpl::producer<Option> option) {
return { nullptr };
}
virtual void confirmSave(
bool someAreDisallowed,

View File

@@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/confirm_box.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "messenger.h"
#include "core/application.h"
#include "lang/lang_instance.h"
#include "lang/lang_cloud_manager.h"
#include "styles/style_boxes.h"
@@ -772,7 +772,6 @@ int Rows::countAvailableWidth() const {
void Rows::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto ms = getms();
const auto clip = e->rect();
const auto checkLeft = st::passportRowPadding.left();
@@ -801,14 +800,14 @@ void Rows::paintEvent(QPaintEvent *e) {
}
if (row.ripple) {
row.ripple->paint(p, 0, 0, width(), ms);
row.ripple->paint(p, 0, 0, width());
if (row.ripple->empty()) {
row.ripple.reset();
}
}
const auto checkTop = (row.height - st::defaultRadio.diameter) / 2;
row.check->paint(p, checkLeft, checkTop, width(), ms);
row.check->paint(p, checkLeft, checkTop, width());
auto top = st::passportRowPadding.top();
@@ -829,7 +828,7 @@ void Rows::paintEvent(QPaintEvent *e) {
p.drawEllipse(menu);
}
if (row.menuToggleRipple) {
row.menuToggleRipple->paint(p, menu.x(), menu.y(), width(), ms);
row.menuToggleRipple->paint(p, menu.x(), menu.y(), width());
if (row.menuToggleRipple->empty()) {
row.menuToggleRipple.reset();
}
@@ -1132,10 +1131,10 @@ not_null<Ui::MultiSelect*> LanguageBox::createMultiSelect() {
base::binary_guard LanguageBox::Show() {
auto result = base::binary_guard();
const auto manager = Messenger::Instance().langCloudManager();
const auto manager = Core::App().langCloudManager();
if (manager->languageList().empty()) {
auto guard = std::make_shared<base::binary_guard>();
std::tie(result, *guard) = base::make_binary_guard();
auto guard = std::make_shared<base::binary_guard>(
result.make_guard());
auto alive = std::make_shared<std::unique_ptr<base::Subscription>>(
std::make_unique<base::Subscription>());
**alive = manager->languageListChanged().add_subscription([=] {

View File

@@ -26,19 +26,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kSizeLimitsCount = 20;
constexpr auto kMegabyte = int64(1024 * 1024);
constexpr auto kTotalSizeLimitsCount = 18;
constexpr auto kMediaSizeLimitsCount = 18;
constexpr auto kMinimalSizeLimit = 100 * kMegabyte;
constexpr auto kTimeLimitsCount = 16;
constexpr auto kMaxTimeLimitValue = std::numeric_limits<size_type>::max();
constexpr auto kFakeMediaCacheTag = uint16(0xFFFF);
int64 SizeLimitInMB(int index) {
if (index < 10) {
return int64(index + 1) * 100;
int64 TotalSizeLimitInMB(int index) {
if (index < 8) {
return int64(index + 2) * 100;
}
return int64(index - 9) * 1024;
return int64(index - 7) * 1024;
}
int64 SizeLimit(int index) {
return SizeLimitInMB(index) * 1024 * 1024;
int64 TotalSizeLimit(int index) {
return TotalSizeLimitInMB(index) * kMegabyte;
}
int64 MediaSizeLimitInMB(int index) {
if (index < 9) {
return int64(index + 1) * 100;
}
return int64(index - 8) * 1024;
}
int64 MediaSizeLimit(int index) {
return MediaSizeLimitInMB(index) * kMegabyte;
}
QString SizeLimitText(int64 limit) {
@@ -124,7 +139,7 @@ protected:
private:
QString titleText(const Database::TaggedSummary &data) const;
QString sizeText(const Database::TaggedSummary &data) const;
void step_radial(TimeMs ms, bool timer);
void radialAnimationCallback();
Fn<QString(size_type)> _titleFactory;
object_ptr<Ui::FlatLabel> _title;
@@ -171,7 +186,7 @@ void LocalStorageBox::Row::toggleProgress(bool shown) {
_clearing.destroy();
} else if (!_progress) {
_progress = std::make_unique<Ui::InfiniteRadialAnimation>(
animation(this, &Row::step_radial),
[=] { radialAnimationCallback(); },
st::proxyCheckingAnimation);
_progress->start();
_clearing = object_ptr<Ui::FlatLabel>(
@@ -186,8 +201,8 @@ void LocalStorageBox::Row::toggleProgress(bool shown) {
}
}
void LocalStorageBox::Row::step_radial(TimeMs ms, bool timer) {
if (timer && !anim::Disabled()) {
void LocalStorageBox::Row::radialAnimationCallback() {
if (!anim::Disabled()) {
RpWidget::update();
}
}
@@ -229,11 +244,9 @@ void LocalStorageBox::Row::paintEvent(QPaintEvent *e) {
return;
}
Painter p(this);
const auto padding = st::localStorageRowPadding;
const auto height = st::localStorageRowHeight;
const auto bottom = height - padding.bottom() - _description->height();
_progress->step(crl::time());
_progress->draw(
p,
{
@@ -256,20 +269,30 @@ QString LocalStorageBox::Row::sizeText(const Database::TaggedSummary &data) cons
LocalStorageBox::LocalStorageBox(
QWidget*,
not_null<Database*> db,
not_null<Database*> dbBig,
CreateTag)
: _db(db) {
: _db(db)
, _dbBig(dbBig) {
const auto &settings = Local::cacheSettings();
_sizeLimit = settings.totalSizeLimit;
const auto &settingsBig = Local::cacheBigFileSettings();
_totalSizeLimit = settings.totalSizeLimit + settingsBig.totalSizeLimit;
_mediaSizeLimit = settingsBig.totalSizeLimit;
_timeLimit = settings.totalTimeLimit;
}
void LocalStorageBox::Show(not_null<Database*> db) {
void LocalStorageBox::Show(
not_null<Database*> db,
not_null<Database*> dbBig) {
auto shared = std::make_shared<object_ptr<LocalStorageBox>>(
Box<LocalStorageBox>(db, CreateTag()));
Box<LocalStorageBox>(db, dbBig, CreateTag()));
const auto weak = shared->data();
db->statsOnMain(
) | rpl::start_with_next([=](Database::Stats &&stats) {
weak->update(std::move(stats));
rpl::combine(
db->statsOnMain(),
dbBig->statsOnMain()
) | rpl::start_with_next([=](
Database::Stats &&stats,
Database::Stats &&statsBig) {
weak->update(std::move(stats), std::move(statsBig));
if (auto &strong = *shared) {
Ui::show(std::move(strong));
}
@@ -286,7 +309,7 @@ void LocalStorageBox::prepare() {
void LocalStorageBox::updateRow(
not_null<Ui::SlideWrap<Row>*> row,
Database::TaggedSummary *data) {
const Database::TaggedSummary *data) {
const auto summary = (_rows.find(0)->second == row);
const auto shown = (data && data->count && data->totalSize) || summary;
if (shown) {
@@ -295,28 +318,45 @@ void LocalStorageBox::updateRow(
row->toggle(shown, anim::type::normal);
}
void LocalStorageBox::update(Database::Stats &&stats) {
void LocalStorageBox::update(
Database::Stats &&stats,
Database::Stats &&statsBig) {
_stats = std::move(stats);
_statsBig = std::move(statsBig);
if (const auto i = _rows.find(0); i != end(_rows)) {
i->second->entity()->toggleProgress(_stats.clearing);
i->second->entity()->toggleProgress(
_stats.clearing || _statsBig.clearing);
}
for (const auto &entry : _rows) {
if (entry.first) {
if (entry.first == kFakeMediaCacheTag) {
updateRow(entry.second, &_statsBig.full);
} else if (entry.first) {
const auto i = _stats.tagged.find(entry.first);
updateRow(
entry.second,
(i != end(_stats.tagged)) ? &i->second : nullptr);
} else {
updateRow(entry.second, &_stats.full);
const auto full = summary();
updateRow(entry.second, &full);
}
}
}
void LocalStorageBox::clearByTag(uint8 tag) {
if (tag) {
auto LocalStorageBox::summary() const -> Database::TaggedSummary {
auto result = _stats.full;
result.count += _statsBig.full.count;
result.totalSize += _statsBig.full.totalSize;
return result;
}
void LocalStorageBox::clearByTag(uint16 tag) {
if (tag == kFakeMediaCacheTag) {
_dbBig->clear();
} else if (tag) {
_db->clearByTag(tag);
} else {
_db->clear();
_dbBig->clear();
Ui::Emoji::ClearIrrelevantCache();
}
}
@@ -326,7 +366,7 @@ void LocalStorageBox::setupControls() {
object_ptr<Ui::VerticalLayout>(this),
st::contactsMultiSelect.scroll);
const auto createRow = [&](
uint8 tag,
uint16 tag,
Fn<QString(size_type)> title,
Fn<QString()> clear,
const Database::TaggedSummary &data) {
@@ -364,11 +404,14 @@ void LocalStorageBox::setupControls() {
auto summaryTitle = [](size_type) {
return lang(lng_local_storage_summary);
};
auto mediaCacheTitle = [](size_type) {
return lang(lng_local_storage_media);
};
createRow(
0,
std::move(summaryTitle),
langFactory(lng_local_storage_clear),
_stats.full);
summary());
setupLimits(container);
const auto shadow = container->add(object_ptr<Ui::SlideWrap<>>(
container,
@@ -379,6 +422,11 @@ void LocalStorageBox::setupControls() {
createTagRow(Data::kVoiceMessageCacheTag, lng_local_storage_voice);
createTagRow(Data::kVideoMessageCacheTag, lng_local_storage_round);
createTagRow(Data::kAnimationCacheTag, lng_local_storage_animation);
tracker.track(createRow(
kFakeMediaCacheTag,
std::move(mediaCacheTitle),
langFactory(lng_local_storage_clear_some),
_statsBig.full));
shadow->toggleOn(
std::move(tracker).atLeastOneShownValue()
);
@@ -394,7 +442,7 @@ template <
typename Convert,
typename Callback,
typename>
void LocalStorageBox::createLimitsSlider(
not_null<Ui::MediaSlider*> LocalStorageBox::createLimitsSlider(
not_null<Ui::VerticalLayout*> container,
int valuesCount,
Convert &&convert,
@@ -415,6 +463,60 @@ void LocalStorageBox::createLimitsSlider(
[=, callback = std::forward<Callback>(callback)](Value value) {
callback(label, value);
});
return slider;
}
void LocalStorageBox::updateMediaLimit() {
const auto good = [&](int64 mediaLimit) {
return (_totalSizeLimit - mediaLimit >= kMinimalSizeLimit);
};
if (good(_mediaSizeLimit) || !_mediaSlider || !_mediaLabel) {
return;
}
auto index = 1;
while ((index < kMediaSizeLimitsCount)
&& (MediaSizeLimit(index) * 2 <= _totalSizeLimit)) {
++index;
}
--index;
_mediaSizeLimit = MediaSizeLimit(index);
_mediaSlider->setValue(index / float64(kMediaSizeLimitsCount - 1));
updateMediaLabel();
Ensures(good(_mediaSizeLimit));
}
void LocalStorageBox::updateTotalLimit() {
const auto good = [&](int64 totalLimit) {
return (totalLimit - _mediaSizeLimit >= kMinimalSizeLimit);
};
if (good(_totalSizeLimit) || !_totalSlider || !_totalLabel) {
return;
}
auto index = kTotalSizeLimitsCount - 1;
while ((index > 0)
&& (TotalSizeLimit(index - 1) >= 2 * _mediaSizeLimit)) {
--index;
}
_totalSizeLimit = TotalSizeLimit(index);
_totalSlider->setValue(index / float64(kTotalSizeLimitsCount - 1));
updateTotalLabel();
Ensures(good(_totalSizeLimit));
}
void LocalStorageBox::updateTotalLabel() {
Expects(_totalLabel != nullptr);
const auto text = SizeLimitText(_totalSizeLimit);
_totalLabel->setText(lng_local_storage_size_limit(lt_size, text));
}
void LocalStorageBox::updateMediaLabel() {
Expects(_mediaLabel != nullptr);
const auto text = SizeLimitText(_mediaSizeLimit);
_mediaLabel->setText(lng_local_storage_media_limit(lt_size, text));
}
void LocalStorageBox::setupLimits(not_null<Ui::VerticalLayout*> container) {
@@ -422,15 +524,29 @@ void LocalStorageBox::setupLimits(not_null<Ui::VerticalLayout*> container) {
object_ptr<Ui::PlainShadow>(container),
st::localStorageRowPadding);
createLimitsSlider(
_totalSlider = createLimitsSlider(
container,
kSizeLimitsCount,
SizeLimit,
_sizeLimit,
kTotalSizeLimitsCount,
TotalSizeLimit,
_totalSizeLimit,
[=](not_null<Ui::LabelSimple*> label, int64 limit) {
const auto text = SizeLimitText(limit);
label->setText(lng_local_storage_size_limit(lt_size, text));
_sizeLimit = limit;
_totalSizeLimit = limit;
_totalLabel = label;
updateTotalLabel();
updateMediaLimit();
limitsChanged();
});
_mediaSlider = createLimitsSlider(
container,
kMediaSizeLimitsCount,
MediaSizeLimit,
_mediaSizeLimit,
[=](not_null<Ui::LabelSimple*> label, int64 limit) {
_mediaSizeLimit = limit;
_mediaLabel = label;
updateMediaLabel();
updateTotalLimit();
limitsChanged();
});
@@ -440,17 +556,21 @@ void LocalStorageBox::setupLimits(not_null<Ui::VerticalLayout*> container) {
TimeLimit,
LimitToValue(_timeLimit),
[=](not_null<Ui::LabelSimple*> label, size_type limit) {
const auto text = TimeLimitText(ValueToLimit(limit));
_timeLimit = ValueToLimit(limit);
const auto text = TimeLimitText(_timeLimit);
label->setText(lng_local_storage_time_limit(lt_limit, text));
_timeLimit = limit;
limitsChanged();
});
}
void LocalStorageBox::limitsChanged() {
const auto &settings = Local::cacheSettings();
const auto changed = (settings.totalSizeLimit != _sizeLimit)
|| (settings.totalTimeLimit != _timeLimit);
const auto &settingsBig = Local::cacheBigFileSettings();
const auto sizeLimit = _totalSizeLimit - _mediaSizeLimit;
const auto changed = (settings.totalSizeLimit != sizeLimit)
|| (settingsBig.totalSizeLimit != _mediaSizeLimit)
|| (settings.totalTimeLimit != _timeLimit)
|| (settingsBig.totalTimeLimit != _timeLimit);
if (_limitsChanged != changed) {
_limitsChanged = changed;
clearButtons();
@@ -469,9 +589,12 @@ void LocalStorageBox::save() {
return;
}
auto update = Storage::Cache::Database::SettingsUpdate();
update.totalSizeLimit = _sizeLimit;
update.totalSizeLimit = _totalSizeLimit - _mediaSizeLimit;
update.totalTimeLimit = _timeLimit;
Local::updateCacheSettings(update);
auto updateBig = Storage::Cache::Database::SettingsUpdate();
updateBig.totalSizeLimit = _mediaSizeLimit;
updateBig.totalTimeLimit = _timeLimit;
Local::updateCacheSettings(update, updateBig);
Auth().data().cache().updateSettings(update);
closeBox();
}

View File

@@ -21,6 +21,7 @@ class VerticalLayout;
template <typename Widget>
class SlideWrap;
class LabelSimple;
class MediaSlider;
} // namespace Ui
class LocalStorageBox : public BoxContent {
@@ -30,9 +31,13 @@ class LocalStorageBox : public BoxContent {
public:
using Database = Storage::Cache::Database;
LocalStorageBox(QWidget*, not_null<Database*> db, CreateTag);
LocalStorageBox(
QWidget*,
not_null<Database*> db,
not_null<Database*> dbBig,
CreateTag);
static void Show(not_null<Database*> db);
static void Show(not_null<Database*> db, not_null<Database*> dbBig);
protected:
void prepare() override;
@@ -42,16 +47,22 @@ protected:
private:
class Row;
void clearByTag(uint8 tag);
void update(Database::Stats &&stats);
void clearByTag(uint16 tag);
void update(Database::Stats &&stats, Database::Stats &&statsBig);
void updateRow(
not_null<Ui::SlideWrap<Row>*> row,
Database::TaggedSummary *data);
const Database::TaggedSummary *data);
void setupControls();
void setupLimits(not_null<Ui::VerticalLayout*> container);
void updateMediaLimit();
void updateTotalLimit();
void updateTotalLabel();
void updateMediaLabel();
void limitsChanged();
void save();
Database::TaggedSummary summary() const;
template <
typename Value,
typename Convert,
@@ -62,7 +73,7 @@ private:
not_null<Ui::LabelSimple*>,
Value>
&& std::is_same_v<Value, decltype(std::declval<Convert>()(1))>>>
void createLimitsSlider(
not_null<Ui::MediaSlider*> createLimitsSlider(
not_null<Ui::VerticalLayout*> container,
int valuesCount,
Convert &&convert,
@@ -70,11 +81,18 @@ private:
Callback &&callback);
not_null<Storage::Cache::Database*> _db;
not_null<Storage::Cache::Database*> _dbBig;
Database::Stats _stats;
Database::Stats _statsBig;
base::flat_map<uint8, not_null<Ui::SlideWrap<Row>*>> _rows;
base::flat_map<uint16, not_null<Ui::SlideWrap<Row>*>> _rows;
Ui::MediaSlider *_totalSlider = nullptr;
Ui::LabelSimple *_totalLabel = nullptr;
Ui::MediaSlider *_mediaSlider = nullptr;
Ui::LabelSimple *_mediaLabel = nullptr;
int64 _sizeLimit = 0;
int64 _totalSizeLimit = 0;
int64 _mediaSizeLimit = 0;
size_type _timeLimit = 0;
bool _limitsChanged = false;

View File

@@ -372,7 +372,7 @@ void PasscodeBox::validateEmail(
}
void PasscodeBox::handleSrpIdInvalid() {
const auto now = getms(true);
const auto now = crl::now();
if (_lastSrpIdInvalidTime > 0
&& now - _lastSrpIdInvalidTime < Core::kHandleSrpIdInvalidTimeout) {
_curRequest.id = 0;
@@ -403,7 +403,7 @@ void PasscodeBox::save(bool force) {
if (_turningOff) pwd = conf = QString();
} else {
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
cSetPasscodeLastTry(getms(true));
cSetPasscodeLastTry(crl::now());
badOldPasscode();
return;
}
@@ -452,10 +452,13 @@ void PasscodeBox::save(bool force) {
changeCloudPassword(old, pwd);
}
} else {
const auto weak = make_weak(this);
cSetPasscodeBadTries(0);
Local::setPasscode(pwd.toUtf8());
Auth().checkAutoLock();
closeBox();
Auth().localPasscodeChanged();
if (weak) {
closeBox();
}
}
}

View File

@@ -113,7 +113,7 @@ private:
mtpRequestId _setRequest = 0;
Core::CloudPasswordCheckRequest _curRequest;
TimeMs _lastSrpIdInvalidTime = 0;
crl::time _lastSrpIdInvalidTime = 0;
Core::CloudPasswordAlgo _newAlgo;
Core::SecureSecretAlgo _newSecureSecretAlgo;
bool _hasRecovery = false;

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