Compare commits

...

238 Commits

Author SHA1 Message Date
John Preston
335095a332 Beta version 5.5.8: Fix build with Xcode. 2024-10-03 12:21:06 +04:00
John Preston
15fcb73e19 Beta version 5.5.8.
- Allow drag-to-scroll in reply quote edit box.
- Add bot verified badge to web app title.
- Fix crash when opening some channels.
- Fix some visual glitches.
2024-10-03 11:59:57 +04:00
John Preston
a8b0f2934b Scroll quote selection in the draft options box. 2024-10-03 11:56:04 +04:00
John Preston
7d67b3d00a Use circle userpics in reactions from forums. 2024-10-03 11:55:57 +04:00
John Preston
b60c7e97ab Don't show full query in "nothing found" info. 2024-10-03 11:55:57 +04:00
23rd
440ebfcbf6 Removed display of userpic for sponsored messages. 2024-10-03 11:55:57 +04:00
23rd
8d93eb919b Added verified badge to title in panel for web view bots. 2024-10-03 11:55:55 +04:00
John Preston
d3df2dc1e5 Use Data::MediaPreload in sponsored messages. 2024-10-03 11:54:28 +04:00
John Preston
677314dacb Extract Data::MediaPreload. 2024-10-03 11:54:28 +04:00
John Preston
20f53c89ad Fix poll bottom ripple.
Fixes #28471.
2024-10-03 11:54:28 +04:00
John Preston
1cb92ef69a Beta version 5.5.7: Workaround MSVC bug. 2024-10-01 10:55:42 +04:00
John Preston
b518f7c4c4 Beta version 5.5.7.
- Add ability to share QR code of bots.
- Add mention/hashtag autocomplete to Saved GIF caption.
- Fixed display of working hours in profiles.
- Respect the maximum reply quote length.
2024-10-01 10:06:45 +04:00
John Preston
9fdc099c3a Update lib_webview. 2024-10-01 08:57:59 +04:00
23rd
1db8ada2aa Slightly improved code style of history widget. 2024-10-01 08:57:39 +04:00
23rd
b753448052 Changed behavior for sponsored messages to display them only when ready. 2024-10-01 08:57:38 +04:00
23rd
e29c6d2f23 Fixed infinite attempts to draw foreground in userpic builder. 2024-10-01 08:57:37 +04:00
GitHub Action
1ee53ee0c1 Update User-Agent for DNS to Chrome 129.0.0.0. 2024-10-01 08:52:46 +04:00
John Preston
57438867b6 Respect the maximum quote length. 2024-09-30 14:46:18 +04:00
John Preston
86c04424f6 Add mention/hashtag autocomplete to GIF caption. 2024-09-30 14:46:18 +04:00
John Preston
632639d581 Allow custom tab action on all autocomplete fields.
Fixes #28455.
2024-09-30 14:46:18 +04:00
23rd
99c8edb3eb Fixed display of working hours in profiles. 2024-09-30 13:29:19 +03:00
23rd
4582e61cfc Improved code style in newest code from export submodule. 2024-09-30 13:12:28 +03:00
Bohdan Tkachenko
a970fe93c1 Add reactions to export chat history (#28252)
Co-authored-by: 23rd <23rd@vivaldi.net>
2024-09-30 03:02:22 -07:00
GitHub Action
91f5c72cf0 Update User-Agent for DNS to Chrome 128.0.0.0. 2024-09-30 11:03:36 +02:00
John Preston
d2f3d04ad4 Update cmake/lib_base submodules. 2024-09-30 12:47:22 +04:00
John Preston
07b93e1e02 Fix media editing in topics. 2024-09-30 12:47:22 +04:00
23rd
ab5e7b1588 Fixed color of mini icon for drafts with reply when dialog is selected. 2024-09-30 12:47:22 +04:00
23rd
0f4aadddfc Fixed display of corner status of video in sponsored messages. 2024-09-30 12:47:22 +04:00
John Preston
a3c79feeba Always show My Stars menu. 2024-09-30 12:47:22 +04:00
John Preston
e6b76fefa1 Show correct error for discuss groups. 2024-09-30 12:47:22 +04:00
23rd
a37f512949 Fixed emoji display in filenames from document views. 2024-09-30 12:47:22 +04:00
23rd
3f34c0ce37 Slightly improved style of box for warning of web view box. 2024-09-30 12:47:22 +04:00
23rd
7cc9a0b9aa Added ability to share QR code of bots. 2024-09-30 12:47:22 +04:00
23rd
fbaa79f168 Fixed display of outline in box for share of QR code on non-retina. 2024-09-30 12:47:22 +04:00
Ilya Fedin
2b0aa8e418 Add description for external video player option 2024-09-27 14:37:51 +02:00
Vladislav Grudinin
1fa2e76c9b Updated codegen submodule. 2024-09-27 14:37:29 +02:00
Vladislav Grudinin
cb166e2591 Fix build with clang 19.1.0.
Fixes #28283.
2024-09-27 14:37:29 +02:00
xmdn
187c2dda20 Check more protocols while adding link (#28407) 2024-09-26 10:54:16 -07:00
Ilya Fedin
b962d2b550 Update Qt 6.8.0-beta4 -> 6.8.0-rc1 2024-09-26 16:15:25 +02:00
Ilya Fedin
d69bcfa138 Update lib_webview & lib_ui 2024-09-26 16:15:25 +02:00
c0re100
0960a3b21d Fix restrict user in recent actions 2024-09-19 17:48:37 +03:00
John Preston
aec220fd2c Beta version 5.5.6.
- Allow resizing the window used for web apps and games.
- Add mention / hashtag autocomplete in media caption field.
- Add "Include muted chats in folder counters" notifications setting.
- Auto-select URL suggested from clipboard when creating a custom link.
- Update emoji to Unicode 15.1.
- Fix replying with a quote from media album caption.
- Fix viewing custom emoji packs from media album caption.
2024-09-19 15:02:16 +04:00
John Preston
666dacf73b Add 'tonsite' handler information to lib/xdg/*. 2024-09-19 13:19:50 +04:00
John Preston
67ce27afaa Update patches for Qt 6.8 on Windows. 2024-09-19 12:52:18 +04:00
23rd
3f6d184435 Added api support for clicks on sponsored messages with media. 2024-09-19 12:47:54 +04:00
John Preston
a2fad84dae Update API scheme to layer 188. 2024-09-19 12:47:54 +04:00
John Preston
4a84f9fa00 Allow resizing window of web apps / games. 2024-09-19 12:47:46 +04:00
Ilya Fedin
7abc921d20 Revert "Fullscreen hack for Windows 11 native resize"
This reverts commit f7bff01793.
2024-09-19 10:46:46 +02:00
Ilya Fedin
a307e7a798 Replace fullscreen mask workaround with Qt one 2024-09-19 10:46:46 +02:00
Ilya Fedin
3a9eb8463d Try to always use QWidget::screen 2024-09-19 10:46:10 +02:00
John Preston
4befb125e3 Update emoji to Unicode 15.1. 2024-09-19 12:26:52 +04:00
John Preston
ca00a19736 Updated emoji resources to Unicode 15.1. 2024-09-19 10:26:30 +02:00
John Preston
296969bcd1 Add "Ada" library mention to README. 2024-09-19 10:43:38 +04:00
John Preston
3218c30983 Add "Include muted chats in folder counters". 2024-09-19 10:34:01 +04:00
John Preston
3658b32db5 Correctly count 'other accounts unread' in menu. 2024-09-19 10:34:01 +04:00
John Preston
592d46c8f2 Fix emoji packs from album captions. 2024-09-19 10:34:01 +04:00
John Preston
8b86f12c23 Fix quote-reply to album captions. 2024-09-19 10:34:01 +04:00
John Preston
2e2d8d2af3 Add FieldAutocomplete to EditCaptionBox. 2024-09-19 10:34:01 +04:00
John Preston
3eec43cacd Add FieldAutocomplete to SendFilesBox. 2024-09-19 10:34:01 +04:00
John Preston
ba7cd25f21 Extract FieldAutocomplete code. 2024-09-19 10:34:01 +04:00
John Preston
969152e949 Move FieldAutocomplete to ChatHelpers. 2024-09-19 10:34:01 +04:00
23rd
b78443cf2d Added mini icon to drafts with reply. 2024-09-19 10:34:01 +04:00
23rd
4288ba2449 Improved UX in box for link creation when user has link in clipboard. 2024-09-19 10:34:01 +04:00
Ilya Fedin
22a3093815 Check updater exit status on Linux 2024-09-18 08:27:18 +02:00
John Preston
98ba2c7ce4 Version 5.5.5.
- Suggest URL from clipboard when creating a custom link.
- Fix animated topic icons in topic info page.
- Fix excessive getChannelDifference requests.
2024-09-13 21:04:07 +04:00
John Preston
36962b8c62 Fix possible crash in swipe-to-reply. 2024-09-13 21:04:07 +04:00
John Preston
d0a8bd1f03 Use colored topic icons only when required. 2024-09-13 20:06:38 +04:00
John Preston
c9e0f50f0f Revert "Improved color of topic icon in TopicIconView."
This reverts commit a38dcb6ee5.
2024-09-13 20:06:32 +04:00
John Preston
1dc310586d Unregister channel from shortpoll. 2024-09-13 20:06:19 +04:00
23rd
6f71d21bb7 Slightly improved box for link creation when user has link in clipboard. 2024-09-13 17:14:48 +03:00
Ilya Fedin
c93f047056 Add run0 support 2024-09-12 23:08:06 +04:00
John Preston
ef98d4ece7 Version 5.5.4.
- Fix channel updates stopping after difference request failing.
- Add QR code generation for your username in Settings.
- Fix swipe-to-reply gestures stopping. (macOS)
2024-09-12 14:41:33 +04:00
23rd
2383bf2c71 Fit amount of available colors in box for share of QR code to 8. 2024-09-12 13:39:13 +03:00
23rd
2c8c92c2a4 Slightly increased max width for username in QR code. 2024-09-12 13:38:36 +03:00
23rd
bad2dc30c3 Added button to generate QR code for self to main section of settings. 2024-09-12 13:28:10 +03:00
Ilya Fedin
fe7f4233b9 Add missing ThirdParty cache to Windows action 2024-09-12 14:13:53 +04:00
Ilya Fedin
68454a9841 Migrate almost all actions to latest OS versions 2024-09-12 14:13:53 +04:00
John Preston
d3bcf63cf7 Fix repeated request of channel difference. 2024-09-12 14:08:09 +04:00
John Preston
a5f1209f28 Remove redundant web apps code. 2024-09-12 14:08:09 +04:00
23rd
9a44ca2769 Fixed display of message without text in section of shared links. 2024-09-11 16:31:46 +03:00
23rd
155305f0f7 Added ability to generate QR code for self from settings. 2024-09-11 15:25:05 +03:00
23rd
6abce8d976 Added attention style to menu item to delete all call logs. 2024-09-11 15:25:05 +03:00
23rd
f16d1f034f Switched swipe-to-reply processing on macOS from touch to scroll events. 2024-09-11 00:37:47 +03:00
John Preston
dab107cf90 Version 5.5.3.
- Fix custom emoji sending.
- Add mention link QR code sharing.
- Fix sending files from network drives. (Windows)
2024-09-10 15:07:14 +04:00
23rd
d1d1aa3d21 Moved premium gradient in box for share of QR code to first place. 2024-09-10 13:51:23 +03:00
23rd
d0536cc31f Replaced boxes for QR code of invite links with box for share QR code. 2024-09-10 13:51:23 +03:00
23rd
c47f5e9995 Added ability to create box for share QR code without peer. 2024-09-10 13:51:23 +03:00
23rd
0916836ff9 Added ability to provide description and custom link to FillPeerQrBox. 2024-09-10 13:51:23 +03:00
John Preston
5dd9ff1062 Accept only CF_HDROP for uri-list mime.
Additional types lead to such problem: some programs, like JetBrains
IDEs, like PyCharm, copy "file://[ip-address]/file" as an URI in
uri-list, that way you can't paste it in the messenger, because it
will make a request to that address and reveal clients IP address.
2024-09-10 14:19:37 +04:00
John Preston
d1e3b9f15d Revert "Check for local URLs more strictly."
This reverts commit c3fda41224.
2024-09-10 14:19:37 +04:00
John Preston
ca3c179b75 Use full available width for text in some places.
Fixes #28384.
2024-09-10 14:19:37 +04:00
John Preston
c2d5924508 Fix build with MSVC. 2024-09-10 14:19:37 +04:00
John Preston
016d0395c3 Fix custom emoji sending. 2024-09-10 14:17:32 +04:00
23rd
925c9239bd Added ability to share QR code from channels. 2024-09-10 11:34:55 +03:00
23rd
fdcbe3cf3a Fixed width of username label with right button in profile section. 2024-09-10 11:08:42 +03:00
23rd
f6b9cc5ce1 Improved padding in box for share QR box on different scales. 2024-09-10 10:56:02 +03:00
23rd
8c915e6dc3 Renamed FillProfileQrBox to FillPeerQrBox. 2024-09-10 03:26:15 +03:00
23rd
1db426da2e Added ability to choose quality in box for share of QR code. 2024-09-10 03:26:15 +03:00
23rd
d9be363962 Added ability to hide userpic from box for share of QR code. 2024-09-10 02:00:26 +03:00
23rd
88daa37e34 Added ability to generate QR code independently from ui scale. 2024-09-10 02:00:26 +03:00
23rd
931fa01337 Added premium gradient to box for share of QR code. 2024-09-10 02:00:26 +03:00
23rd
8e1595eb29 Adapted display of longest usernames in box for share of QR code. 2024-09-10 02:00:26 +03:00
23rd
29e97232d8 Added initial ability to share QR code from user profile. 2024-09-10 02:00:26 +03:00
John Preston
f05191e668 Version 5.5.2: Fix build. 2024-09-09 21:30:15 +04:00
John Preston
1ba189e59d Version 5.5.2.
- Support two bottom buttons in web apps.
- Fix text layout outside of the message bubble glitch.
- Don't stop video when dragging media viewer in window mode.
2024-09-09 21:12:33 +04:00
23rd
c40ca70aa6 Added date of admin promotional to EditAdminBox. 2024-09-09 17:20:52 +03:00
23rd
521f991167 Replaced float labels with text in dividers in EditAdminBox. 2024-09-09 17:20:52 +03:00
23rd
edf1417bbb Added date of restriction to EditRestrictedBox. 2024-09-09 17:20:52 +03:00
23rd
686e9643ad Replaced channel participant parsing with modern way in admin log. 2024-09-09 17:20:52 +03:00
23rd
975460d268 Added api support for dates of chat participant data. 2024-09-09 17:20:52 +03:00
23rd
6b0c606d25 Switched type of subscription date from Qt to TimeId. 2024-09-09 17:20:52 +03:00
23rd
93ff0bdcff Slightly improved style of box for sending GIF with caption. 2024-09-09 17:20:52 +03:00
23rd
bf9d90ca4e Fixed emoji display in header of link for dialog filters. 2024-09-09 17:20:52 +03:00
23rd
d6e5e1e8f7 Added handle of flood errors in request of join to chatlist. 2024-09-09 17:20:52 +03:00
23rd
d3ae2ef9ea Synced local English phrases with server. 2024-09-09 17:20:52 +03:00
John Preston
40b0854704 Don't pause video on viewer drag. 2024-09-09 17:54:16 +04:00
John Preston
9aec6b6496 Set min width for field collapsed quotes. 2024-09-09 17:24:15 +04:00
John Preston
d01f977960 Don't offer hello-sticker to user you've blocked. 2024-09-09 16:42:02 +04:00
John Preston
1444009ee2 Update submodules. 2024-09-09 14:58:40 +04:00
John Preston
14ee9bee26 Fix quotes starting with custom urls. 2024-09-09 14:58:40 +04:00
Ilya Fedin
93587ddc3c Allow scale preview in separate window on Wayland 2024-09-09 14:49:44 +04:00
John Preston
0c4d03477e Fix text layout in some cases. 2024-09-09 14:28:37 +04:00
John Preston
a35092f012 Support second button in web apps. 2024-09-09 13:29:00 +04:00
John Preston
49ee7ee52b Version 5.5.1: Update cmake_helpers. 2024-09-07 00:25:47 +04:00
John Preston
52c77a1970 Version 5.5.1.
- Fix crash in peer short info box.
2024-09-06 23:30:32 +04:00
John Preston
e4269ae7fb Fix crash in PeerShortInfoBox. 2024-09-06 23:28:43 +04:00
John Preston
bd6011c524 Version 5.5.
- Star Giveaways.
- Swipe-to-Reply.
- Audio device selection in one-on-one calls.
- Text selection in collapsed / expanded quotes.
2024-09-06 21:57:47 +04:00
23rd
46cb3ec103 Added box for boosts with credits. 2024-09-06 21:57:47 +04:00
23rd
0241129948 Added support of admin log filter for extended subscriptions. 2024-09-06 21:57:47 +04:00
23rd
e44aca06cb Added support of admin log event of extended subscriptions. 2024-09-06 21:57:47 +04:00
23rd
19d386f977 Added support of credits to giveaway info results. 2024-09-06 21:57:47 +04:00
John Preston
a67fdda913 Fix the Release build for macOS. 2024-09-06 21:57:47 +04:00
John Preston
5286c7b1c3 Allow selecting text in collapsed quotes. 2024-09-06 21:57:47 +04:00
23rd
d9d96d0a6f Fixed display of custom badge in selected messages for giveaways. 2024-09-06 21:57:47 +04:00
23rd
13353bb615 Improved phrases in service message for giveaway results with credits. 2024-09-06 21:57:47 +04:00
23rd
d78348fd16 Fixed crash in box for giveaway create when winners number is constant. 2024-09-06 21:57:46 +04:00
23rd
1e8e660133 Improved phrases in top bar from box for giveaway creation with credits. 2024-09-06 21:57:46 +04:00
23rd
5196982c98 Improved phrases in box for information of giveaway with credits. 2024-09-06 21:57:46 +04:00
23rd
99f857fbf6 Improved phrases in service message for started giveaway with credits. 2024-09-06 21:57:46 +04:00
23rd
0982aa166a Added support of prepaid giveaway with credits. 2024-09-06 21:57:46 +04:00
23rd
3ae9f86097 Slightly improved display of credits in boosts from statistics list. 2024-09-06 21:57:46 +04:00
23rd
9efd9b0d68 Slightly improved timestamp parsing in Api::Boosts. 2024-09-06 21:57:46 +04:00
John Preston
267a73f355 Update API scheme on layer 187. 2024-09-06 21:57:46 +04:00
John Preston
437d8ea890 Fix build with MSVC. 2024-09-06 21:57:46 +04:00
23rd
7ed92ec402 Added credits icon to boosts in statistics list. 2024-09-06 21:57:46 +04:00
23rd
678d9ffbf9 Added support of giveaway prize action messages to export to JSON. 2024-09-06 21:57:46 +04:00
23rd
bc4b427ed1 Added support of giveaway prize action messages to export to HTML. 2024-09-06 21:57:46 +04:00
23rd
36141a9df9 Added support of giveaway results messages to export to JSON. 2024-09-06 21:57:46 +04:00
23rd
d68ba75457 Improved process of giveaway messages for export to JSON. 2024-09-06 21:57:46 +04:00
23rd
00ad32c5f4 Added support of giveaway results messages to export to HTML. 2024-09-06 21:57:46 +04:00
23rd
064bab60ff Improved process of giveaway messages for export to HTML. 2024-09-06 21:57:46 +04:00
23rd
5b146217c0 Added support for credits in messages of prize in giveaways. 2024-09-06 21:57:46 +04:00
23rd
202c81b2e5 Added support for credits in messages for starting and ending giveaways. 2024-09-06 21:57:46 +04:00
23rd
4520480604 Added support of credits giveaway to ReceiptCreditsBox. 2024-09-06 21:57:46 +04:00
23rd
aea87bb5cb United buttons for premium giveaway and premium gifts to single button. 2024-09-06 21:57:46 +04:00
23rd
19492f7e7b Improved prize description for credits in box for giveaway creation. 2024-09-06 21:57:46 +04:00
23rd
51030e3c45 Added list of options to box for giveaway creation with credits. 2024-09-06 21:57:46 +04:00
23rd
e6b8b4be18 Added initial payment support for credits giveaway. 2024-09-06 21:36:03 +04:00
23rd
6ac13b7f80 Added button for credits giveaway to box for giveaway creation. 2024-09-06 21:36:03 +04:00
23rd
7e5e6003a9 Added initial api support for credits giveaway options. 2024-09-06 21:36:03 +04:00
23rd
f445440995 Added initial data structure for credits giveaway options. 2024-09-06 21:36:03 +04:00
John Preston
d81547f091 Support cloud-saved paid reaction privacy. 2024-09-06 21:36:03 +04:00
John Preston
2b185d491b Update API scheme to layer 187. 2024-09-06 21:36:03 +04:00
John Preston
ca47440950 Don't treat .gif as "small image". 2024-09-06 21:07:17 +04:00
John Preston
5e32602f4a Add elastic overscroll to swipe-to-reply. 2024-09-06 21:07:02 +04:00
23rd
1f4516028c Fixed desync of repaint of userpics and messages while swipe-on-reply. 2024-09-06 19:52:29 +03:00
23rd
7f29d269a3 Changed swipe-on-reply detection only when scroll has began. 2024-09-06 17:11:16 +03:00
23rd
62c3374911 Disabled swipe-to-reply for channels. 2024-09-06 12:04:42 +03:00
23rd
2116e04af5 Allowed to swipe-to-reply only with started initial of touches. 2024-09-06 11:56:21 +03:00
John Preston
a97d5e80c7 Fix custom reaction as a quick one. 2024-09-05 19:13:52 +04:00
John Preston
b5098038d0 Add two-year ttl time for account. 2024-09-05 17:05:09 +04:00
John Preston
6fce718252 Add jump-to-end button to chat preview. 2024-09-05 14:50:38 +04:00
John Preston
40cf96202d Add 1.5 years account ttl value. 2024-09-05 14:11:41 +04:00
John Preston
c18e59218e Show internal list of apps as Stars Examples. 2024-09-05 13:14:07 +04:00
John Preston
216865a20d Fix file albums with inline keyboard buttons. 2024-09-05 12:01:43 +04:00
John Preston
6c5036ee8d Fix typo in swipe-to-reply through QWheelEvent. 2024-09-05 11:52:25 +04:00
Viliansh
dc2f59ca24 Added org.telegram as developer_id in the flatpak metainfo.xml
Co-authored-by: ilya-fedin <fedin-ilja2010@ya.ru>
2024-09-05 09:47:43 +02:00
Viliansh
6f6457137e removed update_contact from flatpak metainfo.xml 2024-09-05 09:47:43 +02:00
Viliansh
bc5cb6e2a2 Changed dev name in org.telegram.desktop.metainfo.xml
In flathub, and it's front-ends like KDE's Discover or GNOME Software, Telegram shows "By John Preston", and some users were hesitant to install it afraid that was "fake", so i changed it to Telegram, this would also make it consistent with snap, thanks!
2024-09-05 09:47:43 +02:00
John Preston
16825fff41 Use QWheelEvent::inverted() in swipe gesture. 2024-09-05 11:30:37 +04:00
John Preston
5024f1db8c Beta version 5.4.6.
- Add Swipe-To-Reply for modern touchpads and touchscreens.
- Add text selection in collapsed and expanded blockquotes.
- Fix text rendering in 100% interface scale on Windows.
2024-09-04 18:39:16 +04:00
23rd
a60385fc3d Removed QGraphicsOpacityEffect usage from media view overlay widget. 2024-09-04 18:39:16 +04:00
23rd
b20e2c37c1 Fixed build on Qt6. 2024-09-04 18:39:16 +04:00
John Preston
acd40cbeb6 Apply invert_media flag on message send finish. 2024-09-04 18:32:48 +04:00
23rd
6a45a862dd Removed wheel events from scale slider in section of main settings. 2024-09-04 16:01:55 +02:00
23rd
5bd45e9a20 Fixed updating of left userpic with offset from swipe-on-reply. 2024-09-04 16:01:55 +02:00
23rd
52e42f23ab Improved animation speed on release of swipe-on-reply with various x. 2024-09-04 16:01:54 +02:00
23rd
96b7755cde Fixed updating of message on bounce animation of swipe-on-reply icon. 2024-09-04 16:01:54 +02:00
23rd
c589ee1ca5 Fixed overlap of reply icon on left swipe of message with right action. 2024-09-04 16:01:54 +02:00
23rd
18c9ee093b Fixed unwanted top offset of dialogs widget when float player opened. 2024-09-04 16:01:54 +02:00
John Preston
b82fa3112c Improve touchscreen swipt-to-reply. 2024-09-04 16:01:20 +02:00
John Preston
8d0f66d562 Fix touchscreen history scrolling. 2024-09-04 14:06:11 +02:00
John Preston
20a5e0ba73 Fix controls layout after adding a bot to a group.
Fixes https://bugs.telegram.org/c/19451
2024-09-04 14:56:50 +04:00
John Preston
5a2667c71e Fix reply previews to blockquotes / codeblocks. 2024-09-04 14:45:35 +04:00
John Preston
1f4a8d7eb6 Fix build with MSVC. 2024-09-04 14:45:07 +04:00
John Preston
4430bd0328 Improve lottie icon layout in group calls. 2024-09-04 14:14:12 +04:00
John Preston
ab2e7f4c03 Fix media viewer create on non-primary screen. 2024-09-04 14:14:12 +04:00
John Preston
54e5c06b4d Revert updated Harfbuzz-NG in Qt 5.15.15.
This fixes the regression with text rendering in 100% scale.

Fixes #28340.
2024-09-04 14:14:12 +04:00
23rd
add5a6a0be Added debug util to ensure end of life of objects. 2024-09-04 14:14:12 +04:00
23rd
89c2ba4293 Weakened gesture orientation check within swipe-to-reply. 2024-09-04 14:14:12 +04:00
23rd
dd100fb709 Fixed back gesture responsiveness for swipe-to-reply on macOS. 2024-09-04 14:14:12 +04:00
John Preston
e8dd2b9e7b Use only integer translations in reply swipe. 2024-09-04 14:14:12 +04:00
23rd
71e3cd227c Added initial swipe-to-reply to section for replies. 2024-09-04 14:14:12 +04:00
23rd
1648c31a22 Moved out swipe-to-reply setup to inner method in HistoryInner. 2024-09-04 14:14:12 +04:00
23rd
f8c820f319 Fixed swipe-to-reply on macOS. 2024-09-04 14:14:12 +04:00
John Preston
300f35e78f Implement both touch and wheel swipe-to-reply. 2024-09-04 14:14:12 +04:00
23rd
2aa5849997 Improved horizontal animation for reply icon on left swipe. 2024-09-04 14:14:12 +04:00
23rd
fb1b845211 Improved process of message repaint on swipe to reply. 2024-09-04 14:14:11 +04:00
23rd
3d2af9db8e Improved distance of reply icon on left swipe. 2024-09-04 14:14:11 +04:00
23rd
6129e5a1cf Added bounce animation on finish of replying with left swipe. 2024-09-04 14:14:11 +04:00
23rd
7f70ee1227 Added initial ability to reply with left swipe. 2024-09-04 14:14:11 +04:00
23rd
c9f7da6e82 Added ability to paint icons in center of QRectF. 2024-09-04 10:33:28 +03:00
23rd
f956c0f227 Added experimental option to disable touch bar on macOS. 2024-09-04 10:12:08 +03:00
23rd
df935e0477 Improved code style of gifMaxStatusWidth static function. 2024-09-04 10:11:57 +03:00
23rd
841f1afe1e Improved subtitle space in permissions and restrictions edit boxes. 2024-09-04 10:11:54 +03:00
23rd
fb8b88557e Added ability to kick participants from section of admin log. 2024-09-04 10:11:49 +03:00
23rd
2b502b22b9 Replaced PeerData::generateUserpicImage with static function. 2024-09-04 10:11:44 +03:00
23rd
5ac80d2655 Fixed text clipping at bottom in settings section for cloud password. 2024-09-04 10:11:41 +03:00
23rd
8aa7499e63 Fixed width of stats PointDetailsWidget for charts with currency. 2024-09-04 10:11:36 +03:00
23rd
8cd5e51982 Added missed handler of server error when try to reset cloud password. 2024-09-04 10:11:31 +03:00
23rd
e5c2133446 Disabled Qt build on Windows without successful applied patches. 2024-09-04 10:11:17 +03:00
John Preston
3dccdf2f05 Beta version 5.4.5.
- Fix possible crash in text rendering.
2024-09-01 10:19:39 +04:00
John Preston
8a708c6655 Update Qt to 5.15.15 on Windows. 2024-09-01 10:19:39 +04:00
Ilya Fedin
9e1d9eee4b Fix snap build 2024-08-31 20:09:36 +02:00
Ilya Fedin
f30aabc365 Update Qt 6.7.2 -> 6.8.0 2024-08-31 19:54:58 +02:00
John Preston
a5546d016f Fix possible crash in long-word texts. 2024-08-31 21:48:52 +04:00
John Preston
f79d70d112 Use Ui::Text::String in Ui::RoundButton. 2024-08-31 21:48:52 +04:00
John Preston
ec28f258fb Use full bubble width in message text rendering.
Fixes #28331.
2024-08-31 21:48:52 +04:00
John Preston
08f3a6fb40 Fix local group sent-as display. 2024-08-31 21:48:52 +04:00
John Preston
8823d5256f Fix indentation. 2024-08-31 21:48:52 +04:00
23rd
60e7aa90d2 Added ability to report profile photo from peer info section. 2024-08-31 12:34:50 +03:00
John Preston
71357a9546 Fix archive chats list bidi support. 2024-08-29 17:48:06 +04:00
John Preston
a5b06e9c56 Fix possible crash in text elision. 2024-08-29 17:41:15 +04:00
23rd
0f94419f6d Improved fix of crash in video messages playback.
Regression was introduced in ad3e447f08.
2024-08-29 17:37:55 +04:00
John Preston
94e7aabea5 Fix spaces after emoji in text rendering. 2024-08-29 17:19:28 +04:00
John Preston
f6c816cafe Beta version 5.4.4.
- Fix wrong layout and crashes in text shaping.
- Fix crashes in voice / video messages playback.
2024-08-29 13:01:06 +04:00
John Preston
4cf160e8dc Fix UB in text shaping. 2024-08-29 12:54:52 +04:00
John Preston
9252be5e8c Fix crash in video messages playback.
Regression was introduced in ad3e447f08.
2024-08-29 12:13:51 +04:00
292 changed files with 8693 additions and 3009 deletions

View File

@@ -40,7 +40,7 @@ jobs:
macos:
name: MacOS
runs-on: macos-13
runs-on: macos-latest
strategy:
matrix:
@@ -49,7 +49,7 @@ jobs:
env:
GIT: "https://github.com"
CMAKE_PREFIX_PATH: "/usr/local/opt/ffmpeg@6:/usr/local/opt/openal-soft"
CMAKE_PREFIX_PATH: "/opt/homebrew/opt/ffmpeg@6:/opt/homebrew/opt/openal-soft"
UPLOAD_ARTIFACT: "true"
ONLY_CACHE: "false"
MANUAL_CACHING: "1"
@@ -69,7 +69,7 @@ jobs:
run: |
brew update
brew upgrade || true
brew install ada-url autoconf automake boost cmake ffmpeg@6 openal-soft openh264 openssl opus ninja pkg-config python qt yasm xz
brew install ada-url autoconf automake boost cmake ffmpeg@6 libtool openal-soft openh264 openssl opus ninja pkg-config python qt yasm xz
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
xcodebuild -version > CACHE_KEY.txt
@@ -95,7 +95,7 @@ jobs:
./autogen.sh
./configure --disable-examples --disable-doc
make -j$(sysctl -n hw.logicalcpu)
make install
sudo make install
- name: WebRTC cache.
id: cache-webrtc
@@ -111,7 +111,11 @@ jobs:
git clone --depth=1 --recursive --shallow-submodules $GIT/desktop-app/tg_owt.git
cd tg_owt
cmake -B build . -GNinja -DCMAKE_BUILD_TYPE=Debug
cmake -Bbuild -GNinja . \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_FLAGS_DEBUG="" \
-DCMAKE_CXX_FLAGS_DEBUG=""
cmake --build build --parallel
- name: Telegram Desktop build.
@@ -132,6 +136,9 @@ jobs:
cmake -Bbuild -GNinja . \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_FLAGS_DEBUG="" \
-DCMAKE_CXX_FLAGS_DEBUG="" \
-DCMAKE_EXE_LINKER_FLAGS="-s" \
-DCMAKE_FIND_FRAMEWORK=LAST \
-DTDESKTOP_API_TEST=ON \
-DDESKTOP_APP_USE_PACKAGED_LAZY=ON \

View File

@@ -40,7 +40,7 @@ jobs:
snap:
name: Ubuntu
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
env:
UPLOAD_ARTIFACT: "true"

View File

@@ -42,7 +42,7 @@ jobs:
windows:
name: Windows
runs-on: windows-2022
runs-on: windows-latest
strategy:
matrix:
@@ -94,6 +94,14 @@ jobs:
nuget sources Disable -Name "Microsoft Visual Studio Offline Packages"
nuget sources Add -Source https://api.nuget.org/v3/index.json & exit 0
- name: ThirdParty cache.
id: cache-third-party
uses: actions/cache@v4
with:
path: ${{ env.TBUILD }}\ThirdParty
key: ${{ runner.OS }}-${{ matrix.arch }}-third-party-${{ env.CACHE_KEY }}
restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-third-party-
- name: Libraries cache.
id: cache-libs
uses: actions/cache@v4

View File

@@ -64,6 +64,7 @@ Version **1.8.15** was the last that supports older systems
* QR Code generator ([MIT License](https://github.com/nayuki/QR-Code-generator#license))
* CMake ([New BSD License](https://github.com/Kitware/CMake/blob/master/Copyright.txt))
* Hunspell ([LGPL](https://github.com/hunspell/hunspell/blob/master/COPYING.LESSER))
* Ada ([Apache License 2.0](https://github.com/ada-url/ada/blob/main/LICENSE-APACHE))
## Build instructions

View File

@@ -569,6 +569,8 @@ PRIVATE
data/data_lastseen_status.h
data/data_location.cpp
data/data_location.h
data/data_media_preload.cpp
data/data_media_preload.h
data/data_media_rotation.cpp
data/data_media_rotation.h
data/data_media_types.cpp
@@ -1482,6 +1484,8 @@ PRIVATE
support/support_templates.h
ui/boxes/edit_invite_link_session.cpp
ui/boxes/edit_invite_link_session.h
ui/boxes/peer_qr_box.cpp
ui/boxes/peer_qr_box.h
ui/chat/attach/attach_item_single_file_preview.cpp
ui/chat/attach/attach_item_single_file_preview.h
ui/chat/attach/attach_item_single_media_preview.cpp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 KiB

After

Width:  |  Height:  |  Size: 935 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 234 KiB

View File

@@ -582,3 +582,55 @@ div.toast_shown {
.bot_button_column_separator {
width: 2px
}
.reactions {
margin: 5px 0;
}
.reactions .reaction {
display: inline-flex;
height: 20px;
border-radius: 15px;
background-color: #e8f5fc;
color: #168acd;
font-weight: bold;
margin-bottom: 5px;
}
.reactions .reaction.active {
background-color: #40a6e2;
color: #fff;
}
.reactions .reaction.paid {
background-color: #fdf6e1;
color: #c58523;
}
.reactions .reaction.active.paid {
background-color: #ecae0a;
color: #fdf6e1;
}
.reactions .reaction .emoji {
line-height: 20px;
margin: 0 5px;
font-size: 15px;
}
.reactions .reaction .userpic:not(:first-child) {
margin-left: -8px;
}
.reactions .reaction .userpic {
display: inline-block;
}
.reactions .reaction .userpic .initials {
font-size: 8px;
}
.reactions .reaction .count {
margin-right: 8px;
line-height: 20px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1 @@
<svg width="1000px" height="1000px" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg"><g id="Artboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><path d="M226.328419,494.722069 C372.088573,431.216685 469.284839,389.350049 517.917216,369.122161 C656.772535,311.36743 685.625481,301.334815 704.431427,301.003532 C708.567621,300.93067 717.815839,301.955743 723.806446,306.816707 C728.864797,310.92121 730.256552,316.46581 730.922551,320.357329 C731.588551,324.248848 732.417879,333.113828 731.758626,340.040666 C724.234007,419.102486 691.675104,610.964674 675.110982,699.515267 C668.10208,736.984342 654.301336,749.547532 640.940618,750.777006 C611.904684,753.448938 589.856115,731.588035 561.733393,713.153237 C517.726886,684.306416 492.866009,666.349181 450.150074,638.200013 C400.78442,605.66878 432.786119,587.789048 460.919462,558.568563 C468.282091,550.921423 596.21508,434.556479 598.691227,424.000355 C599.00091,422.680135 599.288312,417.758981 596.36474,415.160431 C593.441168,412.561881 589.126229,413.450484 586.012448,414.157198 C581.598758,415.158943 511.297793,461.625274 375.109553,553.556189 C355.154858,567.258623 337.080515,573.934908 320.886524,573.585046 C303.033948,573.199351 268.692754,563.490928 243.163606,555.192408 C211.851067,545.013936 186.964484,539.632504 189.131547,522.346309 C190.260287,513.342589 202.659244,504.134509 226.328419,494.722069 Z" id="Path-3" fill="#FFFFFF"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,7 @@
<file alias="topic_icons/gray.svg">../../art/topic_icons/gray.svg</file>
<file alias="topic_icons/general.svg">../../art/topic_icons/general.svg</file>
<file alias="links_subscription.svg">../../icons/info/edit/links_subscription.svg</file>
<file alias="plane_white.svg">../../icons/plane_white.svg</file>
</qresource>
<qresource prefix="/icons">
<file alias="calls/hands.lottie">../../icons/calls/hands.lottie</file>

View File

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

View File

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

View File

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

View File

@@ -39,6 +39,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QClipboard>
namespace Api {
namespace {
@@ -503,11 +506,19 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
bot->session().attachWebView().open({
.bot = bot,
.context = { .controller = controller },
.button = {.text = button->text, .url = button->data },
.button = { .text = button->text, .url = button->data },
.source = InlineBots::WebViewSourceButton{ .simple = true },
});
}
} break;
case ButtonType::CopyText: {
const auto text = QString::fromUtf8(button->data);
if (!text.isEmpty()) {
QGuiApplication::clipboard()->setText(text);
controller->showToast(tr::lng_text_copied(tr::now));
}
} break;
}
}

View File

@@ -232,12 +232,12 @@ void ImportInvite(
api->request(MTPchatlists_JoinChatlistInvite(
MTP_string(slug),
MTP_vector<MTPInputPeer>(std::move(inputs))
)).done(callback).fail(error).send();
)).done(callback).fail(error).handleFloodErrors().send();
} else {
api->request(MTPchatlists_JoinChatlistUpdates(
MTP_inputChatlistDialogFilter(MTP_int(filterId)),
MTP_vector<MTPInputPeer>(std::move(inputs))
)).done(callback).fail(error).send();
)).done(callback).fail(error).handleFloodErrors().send();
}
}
@@ -517,6 +517,8 @@ void ShowImportError(
} else {
window->showToast((error == u"INVITE_SLUG_EXPIRED"_q)
? tr::lng_group_invite_bad_link(tr::now)
: error.startsWith(u"FLOOD_WAIT_"_q)
? tr::lng_flood_error(tr::now)
: error);
}
}

View File

@@ -264,14 +264,24 @@ ChatParticipant::ChatParticipant(
_rank = qs(data.vrank().value_or_empty());
_rights = ChatAdminRightsInfo(data.vadmin_rights());
_by = peerToUser(peerFromUser(data.vpromoted_by()));
_date = data.vdate().v;
}, [&](const MTPDchannelParticipantSelf &data) {
_type = Type::Member;
_date = data.vdate().v;
_by = peerToUser(peerFromUser(data.vinviter_id()));
if (data.vsubscription_until_date()) {
_subscriptionDate = data.vsubscription_until_date()->v;
}
}, [&](const MTPDchannelParticipant &data) {
_type = Type::Member;
_date = data.vdate().v;
if (data.vsubscription_until_date()) {
_subscriptionDate = data.vsubscription_until_date()->v;
}
}, [&](const MTPDchannelParticipantBanned &data) {
_restrictions = ChatRestrictionsInfo(data.vbanned_rights());
_by = peerToUser(peerFromUser(data.vkicked_by()));
_date = data.vdate().v;
_type = (_restrictions.flags & ChatRestriction::ViewMessages)
? Type::Banned
@@ -348,6 +358,24 @@ ChatAdminRightsInfo ChatParticipant::rights() const {
return _rights;
}
TimeId ChatParticipant::subscriptionDate() const {
return _subscriptionDate;
}
TimeId ChatParticipant::promotedSince() const {
return (_type == Type::Admin) ? _date : TimeId(0);
}
TimeId ChatParticipant::restrictedSince() const {
return (_type == Type::Restricted || _type == Type::Banned)
? _date
: TimeId(0);
}
TimeId ChatParticipant::memberSince() const {
return (_type == Type::Member) ? _date : TimeId(0);
}
ChatParticipant::Type ChatParticipant::type() const {
return _type;
}

View File

@@ -60,6 +60,11 @@ public:
ChatRestrictionsInfo restrictions() const;
ChatAdminRightsInfo rights() const;
TimeId subscriptionDate() const;
TimeId promotedSince() const;
TimeId restrictedSince() const;
TimeId memberSince() const;
Type type() const;
QString rank() const;
@@ -73,6 +78,8 @@ private:
bool _canBeEdited = false;
QString _rank;
TimeId _subscriptionDate = 0;
TimeId _date = 0;
ChatRestrictionsInfo _restrictions;
ChatAdminRightsInfo _rights;

View File

@@ -12,6 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/core_cloud_password.h"
#include "passport/passport_encryption.h"
#include "base/unixtime.h"
#include "base/call_delayed.h"
namespace Api {
namespace {

View File

@@ -79,6 +79,8 @@ constexpr auto kTransactionsLimit = 100;
.credits = tl.data().vstars().v,
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
.barePeerId = barePeerId,
.bareGiveawayMsgId = uint64(
tl.data().vgiveaway_post_id().value_or_empty()),
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
return Data::CreditsHistoryEntry::PeerType::Peer;
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
@@ -215,6 +217,10 @@ rpl::producer<rpl::no_value, QString> CreditsTopupOptions::request() {
};
}
Data::CreditTopupOptions CreditsTopupOptions::options() const {
return _options;
}
CreditsStatus::CreditsStatus(not_null<PeerData*> peer)
: _peer(peer)
, _api(&peer->session().api().instance()) {
@@ -294,10 +300,6 @@ void CreditsHistory::requestSubscriptions(
}).send();
}
Data::CreditTopupOptions CreditsTopupOptions::options() const {
return _options;
}
rpl::producer<not_null<PeerData*>> PremiumPeerBot(
not_null<Main::Session*> session) {
const auto username = session->appConfig().get<QString>(
@@ -385,4 +387,58 @@ Data::CreditsEarnStatistics CreditsEarnStatistics::data() const {
return _data;
}
CreditsGiveawayOptions::CreditsGiveawayOptions(not_null<PeerData*> peer)
: _peer(peer)
, _api(&peer->session().api().instance()) {
}
rpl::producer<rpl::no_value, QString> CreditsGiveawayOptions::request() {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
using TLOption = MTPStarsGiveawayOption;
const auto optionsFromTL = [=](const auto &options) {
return ranges::views::all(
options
) | ranges::views::transform([=](const auto &option) {
return Data::CreditsGiveawayOption{
.winners = ranges::views::all(
option.data().vwinners().v
) | ranges::views::transform([](const auto &winner) {
return Data::CreditsGiveawayOption::Winner{
.users = winner.data().vusers().v,
.perUserStars = winner.data().vper_user_stars().v,
.isDefault = winner.data().is_default(),
};
}) | ranges::to_vector,
.storeProduct = qs(
option.data().vstore_product().value_or_empty()),
.currency = qs(option.data().vcurrency()),
.amount = option.data().vamount().v,
.credits = option.data().vstars().v,
.yearlyBoosts = option.data().vyearly_boosts().v,
.isExtended = option.data().is_extended(),
.isDefault = option.data().is_default(),
};
}) | ranges::to_vector;
};
const auto fail = [=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
};
_api.request(MTPpayments_GetStarsGiveawayOptions(
)).done([=](const MTPVector<TLOption> &result) {
_options = optionsFromTL(result.v);
consumer.put_done();
}).fail(fail).send();
return lifetime;
};
}
Data::CreditsGiveawayOptions CreditsGiveawayOptions::options() const {
return _options;
}
} // namespace Api

View File

@@ -36,6 +36,22 @@ private:
};
class CreditsGiveawayOptions final {
public:
CreditsGiveawayOptions(not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
[[nodiscard]] Data::CreditsGiveawayOptions options() const;
private:
const not_null<PeerData*> _peer;
Data::CreditsGiveawayOptions _options;
MTP::Sender _api;
};
class CreditsStatus final {
public:
CreditsStatus(not_null<PeerData*> peer);

View File

@@ -115,6 +115,28 @@ rpl::producer<bool> GlobalPrivacy::newRequirePremium() const {
return _newRequirePremium.value();
}
void GlobalPrivacy::loadPaidReactionAnonymous() {
if (_paidReactionAnonymousLoaded) {
return;
}
_paidReactionAnonymousLoaded = true;
_api.request(MTPmessages_GetPaidReactionPrivacy(
)).done([=](const MTPUpdates &result) {
_session->api().applyUpdates(result);
}).send();
}
void GlobalPrivacy::updatePaidReactionAnonymous(bool value) {
_paidReactionAnonymous = value;
}
bool GlobalPrivacy::paidReactionAnonymousCurrent() const {
return _paidReactionAnonymous.current();
}
rpl::producer<bool> GlobalPrivacy::paidReactionAnonymous() const {
return _paidReactionAnonymous.value();
}
void GlobalPrivacy::updateArchiveAndMute(bool value) {
update(

View File

@@ -49,6 +49,11 @@ public:
[[nodiscard]] bool newRequirePremiumCurrent() const;
[[nodiscard]] rpl::producer<bool> newRequirePremium() const;
void loadPaidReactionAnonymous();
void updatePaidReactionAnonymous(bool value);
[[nodiscard]] bool paidReactionAnonymousCurrent() const;
[[nodiscard]] rpl::producer<bool> paidReactionAnonymous() const;
private:
void apply(const MTPGlobalPrivacySettings &data);
@@ -67,7 +72,9 @@ private:
rpl::variable<bool> _showArchiveAndMute = false;
rpl::variable<bool> _hideReadTime = false;
rpl::variable<bool> _newRequirePremium = false;
rpl::variable<bool> _paidReactionAnonymous = false;
std::vector<Fn<void()>> _callbacks;
bool _paidReactionAnonymousLoaded = false;
};

View File

@@ -37,7 +37,8 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
MTP_int(dimensions.width()),
MTP_int(dimensions.height()),
MTPint(), // preload_prefix_size
MTPdouble())); // video_start_ts
MTPdouble(), // video_start_ts
MTPstring())); // video_codec
} else {
attributes.push_back(MTP_documentAttributeImageSize(
MTP_int(dimensions.width()),

View File

@@ -361,9 +361,10 @@ void Premium::resolveGiveawayInfo(
? GiveawayState::Refunded
: GiveawayState::Finished;
info.giftCode = qs(data.vgift_code_slug().value_or_empty());
info.activatedCount = data.vactivated_count().v;
info.activatedCount = data.vactivated_count().value_or_empty();
info.finishDate = data.vfinish_date().v;
info.startDate = data.vstart_date().v;
info.credits = data.vstars_prize().value_or_empty();
});
_giveawayInfoDone(std::move(info));
}).fail([=] {
@@ -508,7 +509,9 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::applyPrepaid(
_api.request(MTPpayments_LaunchPrepaidGiveaway(
_peer->input,
MTP_long(prepaidId),
Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
invoice.creditsAmount
? Payments::InvoiceCreditsGiveawayToTL(invoice)
: Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
consumer.put_done();
@@ -537,10 +540,10 @@ Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
const auto token = Token{ users, months };
const auto &store = _stores[token];
return Payments::InvoicePremiumGiftCode{
.randomId = randomId,
.currency = _optionsForOnePerson.currency,
.amount = store.amount,
.storeProduct = store.product,
.randomId = randomId,
.amount = store.amount,
.storeQuantity = store.quantity,
.users = token.users,
.months = token.months,

View File

@@ -57,6 +57,7 @@ struct GiveawayInfo {
TimeId tooEarlyDate = 0;
TimeId finishDate = 0;
TimeId startDate = 0;
uint64 credits = 0;
int winnersCount = 0;
int activatedCount = 0;
bool participating = false;

View File

@@ -44,7 +44,10 @@ void InnerFillMessagePostFlags(
if (ShouldSendSilent(peer, options)) {
flags |= MessageFlag::Silent;
}
if (!peer->amAnonymous()) {
if (!peer->amAnonymous()
|| (!peer->isBroadcast()
&& options.sendAs
&& options.sendAs != peer)) {
flags |= MessageFlag::HasFromId;
}
const auto channel = peer->asBroadcast();
@@ -544,7 +547,7 @@ void SendConfirmedFile(
MTP_flags(Flag::f_document
| (file->spoiler ? Flag::f_spoiler : Flag())),
file->document,
MTPDocument(), // alt_document
MTPVector<MTPDocument>(), // alt_documents
MTPint());
} else if (file->type == SendMediaType::Audio) {
const auto ttlSeconds = file->to.options.ttlSeconds;
@@ -569,7 +572,7 @@ void SendConfirmedFile(
| (isVoice ? Flag::f_voice : Flag())
| (ttlSeconds ? Flag::f_ttl_seconds : Flag())),
file->document,
MTPDocument(), // alt_document
MTPVector<MTPDocument>(), // alt_documents
MTP_int(ttlSeconds));
} else {
Unexpected("Type in sendFilesConfirmed.");

View File

@@ -571,13 +571,22 @@ rpl::producer<rpl::no_value, QString> Boosts::request() {
_boostStatus.prepaidGiveaway = ranges::views::all(
data.vprepaid_giveaways()->v
) | ranges::views::transform([](const MTPPrepaidGiveaway &r) {
return Data::BoostPrepaidGiveaway{
.months = r.data().vmonths().v,
.id = r.data().vid().v,
.quantity = r.data().vquantity().v,
.date = QDateTime::fromSecsSinceEpoch(
r.data().vdate().v),
};
return r.match([&](const MTPDprepaidGiveaway &data) {
return Data::BoostPrepaidGiveaway{
.date = base::unixtime::parse(data.vdate().v),
.id = data.vid().v,
.months = data.vmonths().v,
.quantity = data.vquantity().v,
};
}, [&](const MTPDprepaidStarsGiveaway &data) {
return Data::BoostPrepaidGiveaway{
.date = base::unixtime::parse(data.vdate().v),
.id = data.vid().v,
.credits = data.vstars().v,
.quantity = data.vquantity().v,
.boosts = data.vboosts().v,
};
});
}) | ranges::to_vector;
}
@@ -635,19 +644,21 @@ void Boosts::requestBoosts(
}
: Data::GiftCodeLink();
list.push_back({
data.is_gift(),
data.is_giveaway(),
data.is_unclaimed(),
qs(data.vid()),
data.vuser_id().value_or_empty(),
data.vgiveaway_msg_id()
.id = qs(data.vid()),
.userId = UserId(data.vuser_id().value_or_empty()),
.giveawayMessage = data.vgiveaway_msg_id()
? FullMsgId{ _peer->id, data.vgiveaway_msg_id()->v }
: FullMsgId(),
QDateTime::fromSecsSinceEpoch(data.vdate().v),
QDateTime::fromSecsSinceEpoch(data.vexpires().v),
(data.vexpires().v - data.vdate().v) / kMonthsDivider,
std::move(giftCodeLink),
data.vmultiplier().value_or_empty(),
.date = base::unixtime::parse(data.vdate().v),
.expiresAt = base::unixtime::parse(data.vexpires().v),
.expiresAfterMonths = ((data.vexpires().v - data.vdate().v)
/ kMonthsDivider),
.giftCodeLink = std::move(giftCodeLink),
.multiplier = data.vmultiplier().value_or_empty(),
.credits = data.vstars().value_or_empty(),
.isGift = data.is_gift(),
.isGiveaway = data.is_giveaway(),
.isUnclaimed = data.is_unclaimed(),
});
}
done(Data::BoostsListSlice{

View File

@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_authorizations.h"
#include "api/api_user_names.h"
#include "api/api_chat_participants.h"
#include "api/api_global_privacy.h"
#include "api/api_ringtones.h"
#include "api/api_text_entities.h"
#include "api/api_user_privacy.h"
@@ -416,13 +417,12 @@ void Updates::channelDifferenceDone(
"{ good - after not final channelDifference was received }%1"
).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
getChannelDifference(channel);
} else if (ranges::contains(
_activeChats,
channel,
[](const auto &pair) { return pair.second.peer; })) {
channel->ptsWaitingForShortPoll(timeout
} else if (inActiveChats(channel)) {
channel->ptsSetWaitingForShortPoll(timeout
? (timeout * crl::time(1000))
: kWaitForChannelGetDifference);
} else {
channel->ptsSetWaitingForShortPoll(-1);
}
}
@@ -654,6 +654,7 @@ void Updates::getDifferenceAfterFail() {
wait = wait ? std::min(wait, i->second - now) : (i->second - now);
++i;
} else {
i->first->ptsSetRequesting(false);
getChannelDifference(i->first, ChannelDifferenceRequest::AfterFail);
i = _whenGetDiffAfterFail.erase(i);
}
@@ -702,7 +703,9 @@ void Updates::getChannelDifference(
_whenGetDiffByPts.remove(channel);
}
if (!channel->ptsInited() || channel->ptsRequesting()) return;
if (!channel->ptsInited() || channel->ptsRequesting()) {
return;
}
if (from != ChannelDifferenceRequest::AfterFail) {
_whenGetDiffAfterFail.remove(channel);
@@ -739,16 +742,32 @@ void Updates::addActiveChat(rpl::producer<PeerData*> chat) {
std::move(
chat
) | rpl::start_with_next_done([=](PeerData *peer) {
_activeChats[key].peer = peer;
if (const auto channel = peer ? peer->asChannel() : nullptr) {
channel->ptsWaitingForShortPoll(
kWaitForChannelGetDifference);
auto &active = _activeChats[key];
const auto was = active.peer;
if (was != peer) {
active.peer = peer;
if (const auto channel = was ? was->asChannel() : nullptr) {
if (!inActiveChats(channel)) {
channel->ptsSetWaitingForShortPoll(-1);
}
}
if (const auto channel = peer ? peer->asChannel() : nullptr) {
channel->ptsSetWaitingForShortPoll(
kWaitForChannelGetDifference);
}
}
}, [=] {
_activeChats.erase(key);
}, _activeChats[key].lifetime);
}
bool Updates::inActiveChats(not_null<PeerData*> peer) const {
return ranges::contains(
_activeChats,
peer.get(),
[](const auto &pair) { return pair.second.peer; });
}
void Updates::requestChannelRangeDifference(not_null<History*> history) {
Expects(history->peer->isChannel());
@@ -1553,6 +1572,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
}
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping new channel message because getting the difference."));
return;
}
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -1645,6 +1665,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping channel message edit because getting the difference."));
return;
} else {
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -1660,6 +1681,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping pinned channel messages because getting the difference."));
return;
} else {
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -1774,6 +1796,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping delete channel messages because getting the difference."));
return;
}
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -1837,6 +1860,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
auto channel = session().data().channelLoaded(d.vchannel_id());
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping channel web page update because getting the difference."));
return;
} else {
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -2622,6 +2646,12 @@ void Updates::feedUpdate(const MTPUpdate &update) {
_session->credits().apply(data);
} break;
case mtpc_updatePaidReactionPrivacy: {
const auto &data = update.c_updatePaidReactionPrivacy();
_session->api().globalPrivacy().updatePaidReactionAnonymous(
mtpIsTrue(data.vprivate()));
} break;
}
}

View File

@@ -63,6 +63,7 @@ public:
void requestChannelRangeDifference(not_null<History*> history);
void addActiveChat(rpl::producer<PeerData*> chat);
[[nodiscard]] bool inActiveChats(not_null<PeerData*> peer) const;
private:
enum class ChannelDifferenceRequest {

View File

@@ -214,7 +214,10 @@ struct State {
[[nodiscard]] QImage GenerateUserpic(Userpic &userpic, int size) {
size *= style::DevicePixelRatio();
auto result = userpic.peer->generateUserpicImage(userpic.view, size);
auto result = PeerData::GenerateUserpicImage(
userpic.peer,
userpic.view,
size);
result.setDevicePixelRatio(style::DevicePixelRatio());
return result;
}

View File

@@ -2028,7 +2028,7 @@ void ApiWrap::deleteHistory(
}
if (const auto channel = peer->asChannel()) {
if (!justClear && !revoke) {
channel->ptsWaitingForShortPoll(-1);
channel->ptsSetWaitingForShortPoll(-1);
leaveChannel(channel);
} else {
if (const auto migrated = peer->migrateFrom()) {
@@ -4160,8 +4160,10 @@ void ApiWrap::sendMediaWithRandomId(
Data::Histories::ReplyToPlaceholder(),
(options.price
? MTPInputMedia(MTP_inputMediaPaidMedia(
MTP_flags(0),
MTP_long(options.price),
MTP_vector<MTPInputMedia>(1, media)))
MTP_vector<MTPInputMedia>(1, media),
MTPstring()))
: media),
MTP_string(caption.text),
MTP_long(randomId),
@@ -4232,8 +4234,10 @@ void ApiWrap::sendMultiPaidMedia(
peer->input,
Data::Histories::ReplyToPlaceholder(),
MTP_inputMediaPaidMedia(
MTP_flags(0),
MTP_long(options.price),
MTP_vector<MTPInputMedia>(std::move(medias))),
MTP_vector<MTPInputMedia>(std::move(medias)),
MTPstring()),
MTP_string(caption.text),
MTP_long(randomId),
MTPReplyMarkup(),

View File

@@ -217,7 +217,9 @@ void ShowAddParticipantsError(
channel,
user,
ChatAdminRightsInfo(),
QString());
QString(),
0,
nullptr);
box->setSaveCallback(saveCallback);
*weak = box.data();
show->showBox(std::move(box));

View File

@@ -597,8 +597,6 @@ rightsHeaderLabel: FlatLabel(boxLabel) {
}
textFg: windowActiveTextFg;
}
rightsUntilMargin: margins(0px, 8px, 0px, 20px);
rightsRankMargin: margins(0px, 7px, 0px, 20px);
groupStickersRemove: defaultMultiSelectSearchCancel;
groupStickersRemovePosition: point(6px, 6px);
@@ -787,7 +785,7 @@ backgroundConfirmPadding: margins(24px, 16px, 24px, 16px);
backgroundConfirm: RoundButton(defaultActiveButton) {
height: 44px;
textTop: 12px;
font: font(13px semibold);
style: semiboldTextStyle;
}
backgroundConfirmCancel: RoundButton(backgroundConfirm) {
textFg: mediaviewSaveMsgFg;
@@ -799,7 +797,7 @@ backgroundConfirmCancel: RoundButton(backgroundConfirm) {
height: 44px;
textTop: 12px;
font: font(13px semibold);
style: semiboldTextStyle;
ripple: RippleAnimation(defaultRippleAnimation) {
color: shadowFg;
@@ -951,7 +949,7 @@ sponsoredUrlButton: RoundButton(defaultActiveButton) {
textFg: historyLinkInFg;
textFgOver: historyLinkInFg;
textTop: 7px;
font: normalFont;
style: defaultTextStyle;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
@@ -1122,3 +1120,10 @@ moderateBoxDividerLabel: FlatLabel(boxDividerLabel) {
selectLinkFg: windowActiveTextFg;
}
}
profileQrFont: font(fsize bold);
profileQrCenterSize: 34px;
profileQrBackgroundRadius: 12px;
profileQrIcon: icon{{ "qr_mini", windowActiveTextFg }};
profileQrBackgroundMargins: margins(36px, 12px, 36px, 12px);
profileQrBackgroundPadding: margins(0px, 24px, 0px, 24px);

View File

@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/premium_limits_box.h"
#include "boxes/premium_preview_box.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/field_autocomplete.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
@@ -371,6 +372,14 @@ void EditCaptionBox::StartPhotoEdit(
});
}
void EditCaptionBox::showFinished() {
if (const auto raw = _autocomplete.get()) {
InvokeQueued(raw, [=] {
raw->raise();
});
}
}
void EditCaptionBox::prepare() {
const auto button = addButton(tr::lng_settings_save(), [=] { save(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });
@@ -525,6 +534,7 @@ void EditCaptionBox::setupField() {
_field.get(),
Window::GifPauseReason::Layer,
allow);
setupFieldAutocomplete();
Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(),
_field,
@@ -562,6 +572,55 @@ void EditCaptionBox::setupField() {
});
}
void EditCaptionBox::setupFieldAutocomplete() {
const auto parent = getDelegate()->outerContainer();
ChatHelpers::InitFieldAutocomplete(_autocomplete, {
.parent = parent,
.show = _controller->uiShow(),
.field = _field.get(),
.peer = _historyItem->history()->peer,
.features = [=] {
auto result = ChatHelpers::ComposeFeatures();
result.autocompleteCommands = false;
result.suggestStickersByEmoji = false;
return result;
},
});
const auto raw = _autocomplete.get();
const auto scheduled = std::make_shared<bool>();
const auto recountPostponed = [=] {
if (*scheduled) {
return;
}
*scheduled = true;
Ui::PostponeCall(raw, [=] {
*scheduled = false;
auto field = Ui::MapFrom(parent, this, _field->geometry());
_autocomplete->setBoundings(QRect(
field.x() - _field->x(),
st::defaultBox.margin.top(),
width(),
(field.y()
+ st::defaultComposeFiles.caption.textMargins.top()
+ st::defaultComposeFiles.caption.placeholderShift
+ st::defaultComposeFiles.caption.placeholderFont->height
- st::defaultBox.margin.top())));
});
};
for (auto w = (QWidget*)_field.get(); w; w = w->parentWidget()) {
base::install_event_filter(raw, w, [=](not_null<QEvent*> e) {
if (e->type() == QEvent::Move || e->type() == QEvent::Resize) {
recountPostponed();
}
return base::EventFilterResult::Continue;
});
if (w == parent) {
break;
}
}
}
void EditCaptionBox::setInitialText() {
_field->setTextWithTags(
_initialText,

View File

@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace ChatHelpers {
class TabbedPanel;
class FieldAutocomplete;
} // namespace ChatHelpers
namespace Window {
@@ -68,6 +69,8 @@ public:
bool invertCaption,
Fn<void()> saved);
void showFinished() override;
protected:
void prepare() override;
void setInnerFocus() override;
@@ -81,6 +84,7 @@ private:
void setupEditEventHandler();
void setupPhotoEditorEventHandler();
void setupField();
void setupFieldAutocomplete();
void setupControls();
void setInitialText();
@@ -115,6 +119,8 @@ private:
const base::unique_qptr<Ui::InputField> _field;
const base::unique_qptr<Ui::EmojiButton> _emojiToggle;
std::unique_ptr<ChatHelpers::FieldAutocomplete> _autocomplete;
base::unique_qptr<Ui::AbstractSinglePreview> _content;
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
base::unique_qptr<QObject> _emojiFilter;

View File

@@ -195,7 +195,7 @@ PaintRoundImageCallback PremiumsRow::generatePaintUserpicCallback(
const auto radius = size * Ui::ForumUserpicRadiusMultiplier();
p.drawRoundedRect(x, y, size, size, radius, radius);
}
st::settingsPrivacyPremium.paintInCenter(p, { x, y, size, size });
st::settingsPrivacyPremium.paintInCenter(p, QRect(x, y, size, size));
};
}

View File

@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/painter.h"
#include "ui/rect.h"
#include "ui/vertical_list.h"
#include "window/window_session_controller.h"
#include "styles/style_info.h"
@@ -581,6 +582,7 @@ void LinkController::addLinkBlock(not_null<Ui::VerticalLayout*> container) {
});
const auto getLinkQr = crl::guard(weak, [=] {
delegate()->peerListUiShow()->showBox(InviteLinkQrBox(
nullptr,
link,
tr::lng_group_invite_qr_title(),
tr::lng_filters_link_qr_about()));
@@ -889,6 +891,7 @@ base::unique_qptr<Ui::PopupMenu> LinksController::createRowContextMenu(
};
const auto getLinkQr = [=] {
delegate()->peerListUiShow()->showBox(InviteLinkQrBox(
nullptr,
link,
tr::lng_group_invite_qr_title(),
tr::lng_filters_link_qr_about()));
@@ -965,9 +968,9 @@ void LinksController::rowPaintIcon(
p.setBrush(*bg);
{
auto hq = PainterHighQualityEnabler(p);
p.drawEllipse(QRect(0, 0, inner, inner));
p.drawEllipse(Rect(Size(inner)));
}
st::inviteLinkIcon.paintInCenter(p, { 0, 0, inner, inner });
st::inviteLinkIcon.paintInCenter(p, Rect(Size(inner)));
}
p.drawImage(x + skip, y + skip, icon);
}
@@ -1113,7 +1116,7 @@ QString FilterChatStatusText(not_null<PeerData*> peer) {
? tr::lng_chat_status_subscribers
: tr::lng_chat_status_members)(
tr::now,
lt_count,
lt_count_decimal,
channel->membersCount());
}
}

View File

@@ -98,7 +98,7 @@ void GiftCreditsBox(
) | rpl::map([](TextWithEntities text) {
return Ui::Text::Link(
std::move(text),
tr::lng_credits_box_history_entry_gift_about_url(tr::now));
u"internal:stars_examples"_q);
});
content->add(
object_ptr<Ui::CenterWrap<>>(

View File

@@ -69,6 +69,24 @@ constexpr auto kUserpicsMax = size_t(3);
using GiftOption = Data::PremiumSubscriptionOption;
using GiftOptions = Data::PremiumSubscriptionOptions;
[[nodiscard]] QString CreateMessageLink(
not_null<Main::Session*> session,
PeerId peerId,
uint64 messageId) {
if (const auto msgId = MsgId(peerId ? messageId : 0)) {
const auto peer = session->data().peer(peerId);
if (const auto channel = peer->asBroadcast()) {
const auto username = channel->username();
const auto base = username.isEmpty()
? u"c/%1"_q.arg(peerToChannel(channel->id).bare)
: username;
const auto query = base + '/' + QString::number(msgId.bare);
return session->createInternalLink(query);
}
}
return QString();
};
GiftOptions GiftOptionFromTL(const MTPDuserFull &data) {
auto result = GiftOptions();
const auto gifts = data.vpremium_gifts();
@@ -1419,21 +1437,56 @@ void GiveawayInfoBox(
: !start->channels.empty()
? start->channels.front()->name()
: u"channel"_q;
auto text = TextWithEntities();
if (!info.giftCode.isEmpty()) {
text.append("\n\n");
text.append(Ui::Text::Bold(tr::lng_prizes_you_won(
tr::now,
auto resultText = (!info.giftCode.isEmpty())
? tr::lng_prizes_you_won(
lt_cup,
QString::fromUtf8("\xf0\x9f\x8f\x86"))));
text.append("\n\n");
} else if (info.state == State::Finished) {
text.append("\n\n");
text.append(Ui::Text::Bold(tr::lng_prizes_you_didnt(tr::now)));
text.append("\n\n");
rpl::single(
TextWithEntities{ QString::fromUtf8("\xf0\x9f\x8f\x86") }),
Ui::Text::WithEntities)
: (info.credits)
? tr::lng_prizes_you_won_credits(
lt_amount,
tr::lng_prizes_you_won_credits_amount(
lt_count,
rpl::single(float64(info.credits)),
Ui::Text::Bold),
lt_cup,
rpl::single(
TextWithEntities{ QString::fromUtf8("\xf0\x9f\x8f\x86") }),
Ui::Text::WithEntities)
: (info.state == State::Finished)
? tr::lng_prizes_you_didnt(Ui::Text::WithEntities)
: (rpl::producer<TextWithEntities>)(nullptr);
if (resultText) {
const auto &st = st::changePhoneDescription;
const auto skip = st.style.font->height * 0.5;
auto label = object_ptr<Ui::FlatLabel>(
box.get(),
std::move(resultText),
st);
if ((!info.giftCode.isEmpty()) || info.credits) {
label->setTextColorOverride(st::windowActiveTextFg->c);
}
const auto result = box->addRow(
object_ptr<Ui::PaddingWrap<Ui::CenterWrap<Ui::FlatLabel>>>(
box.get(),
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
box.get(),
std::move(label)),
QMargins(0, skip, 0, skip)));
result->paintRequest() | rpl::start_with_next([=] {
auto p = QPainter(result);
p.setPen(Qt::NoPen);
p.setBrush(st::boxDividerBg);
p.drawRoundedRect(result->rect(), st::boxRadius, st::boxRadius);
}, result->lifetime());
Ui::AddSkip(box->verticalLayout());
}
auto text = TextWithEntities();
const auto quantity = start
? start->quantity
: (results->winnersCount + results->unclaimedCount);
@@ -1442,22 +1495,39 @@ void GiveawayInfoBox(
? results->channel->isMegagroup()
: (!start->channels.empty()
&& start->channels.front()->isMegagroup());
const auto credits = start
? start->credits
: (results ? results->credits : 0);
text.append((finished
? tr::lng_prizes_end_text
: tr::lng_prizes_how_text)(
tr::now,
lt_admins,
(group
? tr::lng_prizes_admins_group
: tr::lng_prizes_admins)(
tr::now,
lt_count,
quantity,
lt_channel,
Ui::Text::Bold(first),
lt_duration,
TextWithEntities{ GiftDuration(months) },
Ui::Text::RichLangValue),
credits
? (group
? tr::lng_prizes_credits_admins_group
: tr::lng_prizes_credits_admins)(
tr::now,
lt_channel,
Ui::Text::Bold(first),
lt_amount,
tr::lng_prizes_credits_admins_amount(
tr::now,
lt_count_decimal,
float64(credits),
Ui::Text::Bold),
Ui::Text::RichLangValue)
: (group
? tr::lng_prizes_admins_group
: tr::lng_prizes_admins)(
tr::now,
lt_count,
quantity,
lt_channel,
Ui::Text::Bold(first),
lt_duration,
TextWithEntities{ GiftDuration(months) },
Ui::Text::RichLangValue),
Ui::Text::RichLangValue));
const auto many = start
? (start->channels.size() > 1)
@@ -1651,6 +1721,7 @@ void AddCreditsHistoryEntryTable(
st::giveawayGiftCodeTable),
st::giveawayGiftCodeTableMargin);
const auto peerId = PeerId(entry.barePeerId);
const auto session = &controller->session();
if (peerId) {
auto text = entry.in
? tr::lng_credits_box_history_entry_peer_in()
@@ -1658,15 +1729,12 @@ void AddCreditsHistoryEntryTable(
AddTableRow(table, std::move(text), controller, peerId);
}
if (const auto msgId = MsgId(peerId ? entry.bareMsgId : 0)) {
const auto session = &controller->session();
const auto peer = session->data().peer(peerId);
if (const auto channel = peer->asBroadcast()) {
const auto username = channel->username();
const auto base = username.isEmpty()
? u"c/%1"_q.arg(peerToChannel(channel->id).bare)
: username;
const auto query = base + '/' + QString::number(msgId.bare);
const auto link = session->createInternalLink(query);
const auto link = CreateMessageLink(
session,
peerId,
entry.bareMsgId);
auto label = object_ptr<Ui::FlatLabel>(
table,
rpl::single(Ui::Text::Link(link)),
@@ -1717,6 +1785,37 @@ void AddCreditsHistoryEntryTable(
tr::lng_credits_box_history_entry_via_premium_bot(
Ui::Text::RichLangValue));
}
if (entry.bareGiveawayMsgId) {
AddTableRow(
table,
tr::lng_gift_link_label_to(),
controller,
controller->session().userId());
}
if (entry.bareGiveawayMsgId && entry.credits) {
AddTableRow(
table,
tr::lng_gift_link_label_gift(),
tr::lng_gift_stars_title(
lt_count,
rpl::single(float64(entry.credits)),
Ui::Text::RichLangValue));
}
{
const auto link = CreateMessageLink(
session,
peerId,
entry.bareGiveawayMsgId);
if (!link.isEmpty()) {
AddTableRow(
table,
tr::lng_gift_link_label_reason(),
tr::lng_gift_link_reason_giveaway(
) | rpl::map([link](const QString &text) {
return Ui::Text::Link(text, link);
}));
}
}
if (!entry.id.isEmpty()) {
constexpr auto kOneLineCount = 18;
const auto oneLine = entry.id.length() <= kOneLineCount;
@@ -1813,3 +1912,60 @@ void AddSubscriberEntryTable(
rpl::single(Ui::Text::WithEntities(langDateTime(d))));
}
}
void AddCreditsBoostTable(
not_null<Window::SessionNavigation*> controller,
not_null<Ui::VerticalLayout*> container,
const Data::Boost &b) {
auto table = container->add(
object_ptr<Ui::TableLayout>(
container,
st::giveawayGiftCodeTable),
st::giveawayGiftCodeTableMargin);
const auto peerId = b.giveawayMessage.peer;
if (!peerId) {
return;
}
const auto from = controller->session().data().peer(peerId);
AddTableRow(
table,
tr::lng_credits_box_history_entry_peer_in(),
controller,
from->id);
if (b.credits) {
AddTableRow(
table,
tr::lng_gift_link_label_gift(),
tr::lng_gift_stars_title(
lt_count,
rpl::single(float64(b.credits)),
Ui::Text::RichLangValue));
}
{
const auto link = CreateMessageLink(
&controller->session(),
peerId,
b.giveawayMessage.msg.bare);
if (!link.isEmpty()) {
AddTableRow(
table,
tr::lng_gift_link_label_reason(),
tr::lng_gift_link_reason_giveaway(
) | rpl::map([link](const QString &text) {
return Ui::Text::Link(text, link);
}));
}
}
if (!b.date.isNull()) {
AddTableRow(
table,
tr::lng_gift_link_label_date(),
rpl::single(Ui::Text::WithEntities(langDateTime(b.date))));
}
if (!b.expiresAt.isNull()) {
AddTableRow(
table,
tr::lng_gift_until(),
rpl::single(Ui::Text::WithEntities(langDateTime(b.expiresAt))));
}
}

View File

@@ -16,6 +16,7 @@ struct GiftCode;
} // namespace Api
namespace Data {
struct Boost;
struct CreditsHistoryEntry;
struct GiveawayStart;
struct GiveawayResults;
@@ -89,3 +90,8 @@ void AddSubscriberEntryTable(
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer,
TimeId date);
void AddCreditsBoostTable(
not_null<Window::SessionNavigation*> controller,
not_null<Ui::VerticalLayout*> container,
const Data::Boost &boost);

View File

@@ -436,14 +436,16 @@ void CreateModerateMessagesBox(
return result;
}();
auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions(
box,
Ui::AddSubsectionTitle(
inner,
rpl::conditional(
rpl::single(isSingle),
tr::lng_restrict_users_part_single_header(),
tr::lng_restrict_users_part_header(
lt_count,
rpl::single(participants.size()) | tr::to_count())),
rpl::single(participants.size()) | tr::to_count())));
auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions(
box,
prepareFlags,
disabledMessages,
{ .isForum = peer->isForum() });

View File

@@ -170,11 +170,15 @@ void AddBotToGroupBoxController::requestExistingRights(
channel);
_existingRights = participant.rights().flags;
_existingRank = participant.rank();
_promotedSince = participant.promotedSince();
_promotedBy = participant.by();
addBotToGroup(_existingRightsChannel);
});
}).fail([=] {
_existingRights = ChatAdminRights();
_existingRank = QString();
_promotedSince = 0;
_promotedBy = 0;
addBotToGroup(_existingRightsChannel);
}).send();
}
@@ -191,6 +195,8 @@ void AddBotToGroupBoxController::addBotToGroup(not_null<PeerData*> chat) {
_existingRights = {};
_existingRank = QString();
_existingRightsChannel = nullptr;
_promotedSince = 0;
_promotedBy = 0;
_bot->session().api().request(_existingRightsRequestId).cancel();
}
const auto requestedAddAdmin = (_scope == Scope::GroupAdmin)
@@ -241,9 +247,12 @@ void AddBotToGroupBoxController::addBotToGroup(not_null<PeerData*> chat) {
bot,
ChatAdminRightsInfo(rights),
_existingRank,
_promotedSince,
_promotedBy ? chat->owner().user(_promotedBy).get() : nullptr,
EditAdminBotFields{
_token,
_existingRights.value_or(ChatAdminRights()) });
_existingRights.value_or(ChatAdminRights()),
});
box->setSaveCallback(saveCallback);
controller->show(std::move(box));
} else {

View File

@@ -65,6 +65,8 @@ private:
mtpRequestId _existingRightsRequestId = 0;
std::optional<ChatAdminRights> _existingRights;
QString _existingRank;
TimeId _promotedSince = 0;
UserId _promotedBy = 0;
rpl::event_stream<not_null<PeerData*>> _groups;
rpl::event_stream<not_null<PeerData*>> _channels;

View File

@@ -1276,7 +1276,9 @@ void AddSpecialBoxController::showAdmin(
_peer,
user,
currentRights,
_additional.adminRank(user));
_additional.adminRank(user),
_additional.adminPromotedSince(user),
_additional.adminPromotedBy(user));
const auto show = delegate()->peerListUiShow();
if (_additional.canAddOrEditAdmin(user)) {
const auto done = crl::guard(this, [=](
@@ -1354,7 +1356,9 @@ void AddSpecialBoxController::showRestricted(
_peer,
user,
_additional.adminRights(user).has_value(),
currentRights);
currentRights,
_additional.restrictedBy(user),
_additional.restrictedSince(user));
if (_additional.canRestrictParticipant(user)) {
const auto done = crl::guard(this, [=](
ChatRestrictionsInfo newRights) {

View File

@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "ui/controls/userpic_button.h"
#include "ui/vertical_list.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/slide_wrap.h"
@@ -63,6 +64,10 @@ public:
template <typename Widget>
Widget *addControl(object_ptr<Widget> widget, QMargins margin);
[[nodiscard]] not_null<Ui::VerticalLayout*> verticalLayout() const {
return _rows;
}
protected:
int resizeGetHeight(int newWidth) override;
void paintEvent(QPaintEvent *e) override;
@@ -164,6 +169,10 @@ EditParticipantBox::EditParticipantBox(
, _hasAdminRights(hasAdminRights) {
}
not_null<Ui::VerticalLayout*> EditParticipantBox::verticalLayout() const {
return _inner->verticalLayout();
}
void EditParticipantBox::prepare() {
_inner = setInnerWidget(object_ptr<Inner>(
this,
@@ -197,6 +206,8 @@ EditAdminBox::EditAdminBox(
not_null<UserData*> user,
ChatAdminRightsInfo rights,
const QString &rank,
TimeId promotedSince,
UserData *by,
std::optional<EditAdminBotFields> addingBot)
: EditParticipantBox(
nullptr,
@@ -205,6 +216,8 @@ EditAdminBox::EditAdminBox(
(rights.flags != 0))
, _oldRights(rights)
, _oldRank(rank)
, _promotedSince(promotedSince)
, _by(by)
, _addingBot(std::move(addingBot)) {
}
@@ -279,9 +292,26 @@ void EditAdminBox::prepare() {
object_ptr<Ui::VerticalLayout>(this)));
const auto inner = _adminControlsWrap->entity();
inner->add(
object_ptr<Ui::BoxContentDivider>(inner),
st::rightsDividerMargin);
if (_promotedSince) {
const auto parsed = base::unixtime::parse(_promotedSince);
const auto label = Ui::AddDividerText(
inner,
tr::lng_rights_about_by(
lt_user,
rpl::single(_by
? Ui::Text::Link(_by->name(), 1)
: TextWithEntities{ QString::fromUtf8("\U0001F47B") }),
lt_date,
rpl::single(TextWithEntities{ langDateTimeFull(parsed) }),
Ui::Text::WithEntities));
if (_by) {
label->setLink(1, _by->createOpenLink());
}
Ui::AddSkip(inner);
} else {
Ui::AddDivider(inner);
Ui::AddSkip(inner);
}
const auto chat = peer()->asChat();
const auto channel = peer()->asChannel();
@@ -335,9 +365,9 @@ void EditAdminBox::prepare() {
.isForum = peer()->isForum(),
.anyoneCanAddMembers = anyoneCanAddMembers,
};
Ui::AddSubsectionTitle(inner, tr::lng_rights_edit_admin_header());
auto [checkboxes, getChecked, changes] = CreateEditAdminRights(
inner,
tr::lng_rights_edit_admin_header(),
prepareFlags,
disabledMessages,
options);
@@ -348,17 +378,47 @@ void EditAdminBox::prepare() {
) | rpl::then(std::move(
changes
));
_aboutAddAdmins = inner->add(
object_ptr<Ui::FlatLabel>(inner, st::boxDividerLabel),
st::rightsAboutMargin);
rpl::duplicate(
selectedFlags
) | rpl::map(
(_1 & Flag::AddAdmins) != 0
) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](bool checked) {
refreshAboutAddAdminsText(checked);
}, lifetime());
const auto hasRank = canSave() && (chat || channel->isMegagroup());
{
const auto aboutAddAdminsInner = inner->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
inner,
object_ptr<Ui::VerticalLayout>(inner)));
const auto emptyAboutAddAdminsInner = inner->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
inner,
object_ptr<Ui::VerticalLayout>(inner)));
aboutAddAdminsInner->toggle(false, anim::type::instant);
emptyAboutAddAdminsInner->toggle(false, anim::type::instant);
Ui::AddSkip(emptyAboutAddAdminsInner->entity());
if (hasRank) {
Ui::AddDivider(emptyAboutAddAdminsInner->entity());
Ui::AddSkip(emptyAboutAddAdminsInner->entity());
}
Ui::AddSkip(aboutAddAdminsInner->entity());
Ui::AddDividerText(
aboutAddAdminsInner->entity(),
rpl::duplicate(
selectedFlags
) | rpl::map(
(_1 & Flag::AddAdmins) != 0
) | rpl::distinct_until_changed(
) | rpl::map([=](bool canAddAdmins) -> rpl::producer<QString> {
const auto empty = (amCreator() && user()->isSelf());
aboutAddAdminsInner->toggle(!empty, anim::type::instant);
emptyAboutAddAdminsInner->toggle(empty, anim::type::instant);
if (empty) {
return rpl::single(QString());
} else if (!canSave()) {
return tr::lng_rights_about_admin_cant_edit();
} else if (canAddAdmins) {
return tr::lng_rights_about_add_admins_yes();
}
return tr::lng_rights_about_add_admins_no();
}) | rpl::flatten_latest());
}
if (canTransferOwnership()) {
const auto allFlags = AdminRightsForOwnershipTransfer(options);
@@ -373,9 +433,7 @@ void EditAdminBox::prepare() {
}
if (canSave()) {
_rank = (chat || channel->isMegagroup())
? addRankInput(inner).get()
: nullptr;
_rank = hasRank ? addRankInput(inner).get() : nullptr;
_finishSave = [=, value = getChecked] {
const auto newFlags = (value() | ChatAdminRight::Other)
& ((!channel || channel->amCreator())
@@ -441,9 +499,7 @@ void EditAdminBox::refreshButtons() {
not_null<Ui::InputField*> EditAdminBox::addRankInput(
not_null<Ui::VerticalLayout*> container) {
container->add(
object_ptr<Ui::BoxContentDivider>(container),
st::rightsRankMargin);
// Ui::AddDivider(container);
container->add(
object_ptr<Ui::FlatLabel>(
@@ -480,14 +536,13 @@ not_null<Ui::InputField*> EditAdminBox::addRankInput(
}
}, result->lifetime());
container->add(
object_ptr<Ui::FlatLabel>(
container,
tr::lng_rights_edit_admin_rank_about(
lt_title,
(isOwner ? tr::lng_owner_badge : tr::lng_admin_badge)()),
st::boxDividerLabel),
st::rightsAboutMargin);
Ui::AddSkip(container);
Ui::AddDividerText(
container,
tr::lng_rights_edit_admin_rank_about(
lt_title,
(isOwner ? tr::lng_owner_badge : tr::lng_admin_badge)()));
Ui::AddSkip(container);
return result;
}
@@ -681,27 +736,18 @@ void EditAdminBox::sendTransferRequestFrom(
})).handleFloodErrors().send();
}
void EditAdminBox::refreshAboutAddAdminsText(bool canAddAdmins) {
_aboutAddAdmins->setText([&] {
if (amCreator() && user()->isSelf()) {
return QString();
} else if (!canSave()) {
return tr::lng_rights_about_admin_cant_edit(tr::now);
} else if (canAddAdmins) {
return tr::lng_rights_about_add_admins_yes(tr::now);
}
return tr::lng_rights_about_add_admins_no(tr::now);
}());
}
EditRestrictedBox::EditRestrictedBox(
QWidget*,
not_null<PeerData*> peer,
not_null<UserData*> user,
bool hasAdminRights,
ChatRestrictionsInfo rights)
ChatRestrictionsInfo rights,
UserData *by,
TimeId since)
: EditParticipantBox(nullptr, peer, user, hasAdminRights)
, _oldRights(rights) {
, _oldRights(rights)
, _by(by)
, _since(since) {
}
void EditRestrictedBox::prepare() {
@@ -712,9 +758,8 @@ void EditRestrictedBox::prepare() {
setTitle(tr::lng_rights_user_restrictions());
addControl(
object_ptr<Ui::BoxContentDivider>(this),
st::rightsDividerMargin);
Ui::AddDivider(verticalLayout());
Ui::AddSkip(verticalLayout());
const auto chat = peer()->asChat();
const auto channel = peer()->asChannel();
@@ -749,16 +794,20 @@ void EditRestrictedBox::prepare() {
return result;
}();
Ui::AddSubsectionTitle(
verticalLayout(),
tr::lng_rights_user_restrictions_header());
auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions(
this,
tr::lng_rights_user_restrictions_header(),
prepareFlags,
disabledMessages,
{ .isForum = peer()->isForum() });
addControl(std::move(checkboxes), QMargins());
_until = prepareRights.until;
addControl(object_ptr<Ui::BoxContentDivider>(this), st::rightsUntilMargin);
addControl(
object_ptr<Ui::FixedHeightWidget>(this, st::defaultVerticalListSkip));
Ui::AddDivider(verticalLayout());
addControl(
object_ptr<Ui::FlatLabel>(
this,
@@ -773,6 +822,29 @@ void EditRestrictedBox::prepare() {
// tr::lng_rights_chat_banned_block(tr::now),
// st::boxLinkButton));
if (_since) {
const auto parsed = base::unixtime::parse(_since);
const auto inner = addControl(object_ptr<Ui::VerticalLayout>(this));
const auto isBanned = (_oldRights.flags
& ChatRestriction::ViewMessages);
Ui::AddSkip(inner);
const auto label = Ui::AddDividerText(
inner,
(isBanned
? tr::lng_rights_chat_banned_by
: tr::lng_rights_chat_restricted_by)(
lt_user,
rpl::single(_by
? Ui::Text::Link(_by->name(), 1)
: TextWithEntities{ QString::fromUtf8("\U0001F47B") }),
lt_date,
rpl::single(TextWithEntities{ langDateTimeFull(parsed) }),
Ui::Text::WithEntities));
if (_by) {
label->setLink(1, _by->createOpenLink());
}
}
if (canSave()) {
const auto save = [=, value = getRestrictions] {
if (!_saveCallback) {

View File

@@ -36,6 +36,8 @@ public:
not_null<UserData*> user,
bool hasAdminRights);
[[nodiscard]] not_null<Ui::VerticalLayout*> verticalLayout() const;
protected:
void prepare() override;
@@ -77,6 +79,8 @@ public:
not_null<UserData*> user,
ChatAdminRightsInfo rights,
const QString &rank,
TimeId promotedSince,
UserData *by,
std::optional<EditAdminBotFields> addingBot = {});
void setSaveCallback(
@@ -108,7 +112,6 @@ private:
}
void finishAddAdmin();
void refreshButtons();
void refreshAboutAddAdminsText(bool canAddAdmins);
bool canTransferOwnership() const;
not_null<Ui::SlideWrap<Ui::RpWidget>*> setupTransferButton(
not_null<Ui::VerticalLayout*> container,
@@ -125,11 +128,12 @@ private:
Ui::Checkbox *_addAsAdmin = nullptr;
Ui::SlideWrap<Ui::VerticalLayout> *_adminControlsWrap = nullptr;
Ui::InputField *_rank = nullptr;
QPointer<Ui::FlatLabel> _aboutAddAdmins;
mtpRequestId _checkTransferRequestId = 0;
mtpRequestId _transferRequestId = 0;
Fn<void()> _save, _finishSave;
TimeId _promotedSince = 0;
UserData *_by = nullptr;
std::optional<EditAdminBotFields> _addingBot;
};
@@ -144,7 +148,9 @@ public:
not_null<PeerData*> peer,
not_null<UserData*> user,
bool hasAdminRights,
ChatRestrictionsInfo rights);
ChatRestrictionsInfo rights,
UserData *by,
TimeId since);
void setSaveCallback(
Fn<void(ChatRestrictionsInfo, ChatRestrictionsInfo)> callback) {
@@ -168,6 +174,8 @@ private:
TimeId getRealUntilValue() const;
const ChatRestrictionsInfo _oldRights;
UserData *_by = nullptr;
TimeId _since = 0;
TimeId _until = 0;
Fn<void(ChatRestrictionsInfo, ChatRestrictionsInfo)> _saveCallback;

View File

@@ -387,6 +387,24 @@ QString ParticipantsAdditionalData::adminRank(
return (i != end(_adminRanks)) ? i->second : QString();
}
TimeId ParticipantsAdditionalData::adminPromotedSince(
not_null<UserData*> user) const {
const auto i = _adminPromotedSince.find(user);
return (i != end(_adminPromotedSince)) ? i->second : TimeId(0);
}
TimeId ParticipantsAdditionalData::restrictedSince(
not_null<PeerData*> peer) const {
const auto i = _restrictedSince.find(peer);
return (i != end(_restrictedSince)) ? i->second : TimeId(0);
}
TimeId ParticipantsAdditionalData::memberSince(
not_null<UserData*> user) const {
const auto i = _memberSince.find(user);
return (i != end(_memberSince)) ? i->second : TimeId(0);
}
auto ParticipantsAdditionalData::restrictedRights(
not_null<PeerData*> participant) const
-> std::optional<ChatRestrictionsInfo> {
@@ -689,6 +707,11 @@ UserData *ParticipantsAdditionalData::applyAdmin(
} else {
_adminRanks.remove(user);
}
if (data.promotedSince()) {
_adminPromotedSince[user] = data.promotedSince();
} else {
_adminPromotedSince.remove(user);
}
if (const auto by = _peer->owner().userLoaded(data.by())) {
const auto i = _adminPromotedBy.find(user);
if (i == _adminPromotedBy.end()) {
@@ -741,6 +764,11 @@ PeerData *ParticipantsAdditionalData::applyBanned(
} else {
_kicked.erase(participant);
}
if (data.restrictedSince()) {
_restrictedSince[participant] = data.restrictedSince();
} else {
_restrictedSince.remove(participant);
}
_restrictedRights[participant] = data.restrictions();
if (const auto by = _peer->owner().userLoaded(data.by())) {
const auto i = _restrictedBy.find(participant);
@@ -1720,7 +1748,9 @@ void ParticipantsBoxController::showAdmin(not_null<UserData*> user) {
_peer,
user,
currentRights,
_additional.adminRank(user));
_additional.adminRank(user),
_additional.adminPromotedSince(user),
_additional.adminPromotedBy(user));
if (_additional.canAddOrEditAdmin(user)) {
const auto done = crl::guard(this, [=](
ChatAdminRightsInfo newRights,
@@ -1776,7 +1806,9 @@ void ParticipantsBoxController::showRestricted(not_null<UserData*> user) {
_peer,
user,
hasAdminRights,
currentRights);
currentRights,
_additional.restrictedBy(user),
_additional.restrictedSince(user));
if (_additional.canRestrictParticipant(user)) {
const auto done = crl::guard(this, [=](
ChatRestrictionsInfo newRights) {

View File

@@ -106,14 +106,19 @@ public:
not_null<PeerData*> participant) const;
[[nodiscard]] std::optional<ChatAdminRightsInfo> adminRights(
not_null<UserData*> user) const;
QString adminRank(not_null<UserData*> user) const;
[[nodiscard]] QString adminRank(not_null<UserData*> user) const;
[[nodiscard]] std::optional<ChatRestrictionsInfo> restrictedRights(
not_null<PeerData*> participant) const;
[[nodiscard]] bool isCreator(not_null<UserData*> user) const;
[[nodiscard]] bool isExternal(not_null<PeerData*> participant) const;
[[nodiscard]] bool isKicked(not_null<PeerData*> participant) const;
[[nodiscard]] UserData *adminPromotedBy(not_null<UserData*> user) const;
[[nodiscard]] UserData *restrictedBy(not_null<PeerData*> participant) const;
[[nodiscard]] UserData *restrictedBy(
not_null<PeerData*> participant) const;
[[nodiscard]] TimeId adminPromotedSince(not_null<UserData*>) const;
[[nodiscard]] TimeId restrictedSince(not_null<PeerData*>) const;
[[nodiscard]] TimeId memberSince(not_null<UserData*>) const;
void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel);
@@ -144,6 +149,9 @@ private:
// Data for channels.
base::flat_map<not_null<UserData*>, ChatAdminRightsInfo> _adminRights;
base::flat_map<not_null<UserData*>, QString> _adminRanks;
base::flat_map<not_null<UserData*>, TimeId> _adminPromotedSince;
base::flat_map<not_null<PeerData*>, TimeId> _restrictedSince;
base::flat_map<not_null<UserData*>, TimeId> _memberSince;
base::flat_set<not_null<UserData*>> _adminCanEdit;
base::flat_map<not_null<UserData*>, not_null<UserData*>> _adminPromotedBy;
std::map<not_null<PeerData*>, ChatRestrictionsInfo> _restrictedRights;

View File

@@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/confirm_box.h"
#include "ui/boxes/edit_invite_link.h"
#include "ui/boxes/edit_invite_link_session.h"
#include "ui/boxes/peer_qr_box.h"
#include "ui/controls/invite_link_buttons.h"
#include "ui/controls/invite_link_label.h"
#include "ui/controls/userpic_button.h"
@@ -64,8 +65,8 @@ namespace {
constexpr auto kFirstPage = 20;
constexpr auto kPerPage = 100;
constexpr auto kShareQrSize = 768;
constexpr auto kShareQrPadding = 16;
// constexpr auto kShareQrSize = 768;
// constexpr auto kShareQrPadding = 16;
using LinkData = Api::InviteLink;
@@ -282,6 +283,8 @@ private:
return updated.link.isEmpty() || (!revoked && updated.revoked);
}
#if 0
QImage QrExact(const Qr::Data &data, int pixel, QColor color) {
const auto image = [](int size) {
auto result = QImage(
@@ -383,6 +386,8 @@ void QrBox(
box->addLeftButton(tr::lng_group_invite_context_copy(), copyCallback);
}
#endif
Controller::Controller(
not_null<PeerData*> peer,
not_null<UserData*> admin,
@@ -421,6 +426,7 @@ void Controller::addHeaderBlock(not_null<Ui::VerticalLayout*> container) {
});
const auto getLinkQr = crl::guard(weak, [=] {
delegate()->peerListUiShow()->showBox(InviteLinkQrBox(
_peer,
link,
tr::lng_group_invite_qr_title(),
tr::lng_group_invite_qr_about()));
@@ -1253,6 +1259,7 @@ void AddPermanentLinkBlock(
const auto getLinkQr = crl::guard(weak, [=] {
if (const auto current = value->current(); !current.link.isEmpty()) {
show->showBox(InviteLinkQrBox(
peer,
current.link,
tr::lng_group_invite_qr_title(),
tr::lng_group_invite_qr_about()));
@@ -1510,16 +1517,14 @@ object_ptr<Ui::BoxContent> ShareInviteLinkBox(
}
object_ptr<Ui::BoxContent> InviteLinkQrBox(
PeerData *peer,
const QString &link,
rpl::producer<QString> title,
rpl::producer<QString> about) {
return Box(QrBox, link, std::move(title), std::move(about), [=](
const QImage &image,
std::shared_ptr<Ui::Show> show) {
auto mime = std::make_unique<QMimeData>();
mime->setImageData(image);
QGuiApplication::clipboard()->setMimeData(mime.release());
show->showToast(tr::lng_group_invite_qr_copied(tr::now));
return Box([=, t = std::move(title), a = std::move(about)](
not_null<Ui::GenericBox*> box) {
Ui::FillPeerQrBox(box, peer, link, std::move(a));
box->setTitle(std::move(t));
});
}

View File

@@ -50,6 +50,7 @@ void CopyInviteLink(std::shared_ptr<Ui::Show> show, const QString &link);
const QString &link,
const QString &copied = {});
[[nodiscard]] object_ptr<Ui::BoxContent> InviteLinkQrBox(
PeerData *peer,
const QString &link,
rpl::producer<QString> title,
rpl::producer<QString> about);

View File

@@ -587,6 +587,7 @@ base::unique_qptr<Ui::PopupMenu> LinksController::createRowContextMenu(
}, &st::menuIconShare);
result->addAction(tr::lng_group_invite_context_qr(tr::now), [=] {
delegate()->peerListUiShow()->showBox(InviteLinkQrBox(
nullptr,
link,
tr::lng_group_invite_qr_title(),
tr::lng_group_invite_qr_about()));
@@ -734,7 +735,7 @@ void LinksController::rowPaintIcon(
} else {
(color == Color::Revoked
? st::inviteLinkRevokedIcon
: st::inviteLinkIcon).paintInCenter(p, { 0, 0, inner, inner });
: st::inviteLinkIcon).paintInCenter(p, Rect(Size(inner)));
}
}
p.drawImage(x + skip, y + skip, icon);

View File

@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h"
#include "ui/layers/generic_box.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
@@ -583,14 +584,6 @@ template <typename Flags>
ApplyDependencies(state->checkViews, dependencies, view);
};
if (descriptor.header) {
container->add(
object_ptr<Ui::FlatLabel>(
container,
std::move(descriptor.header),
st::rightsHeaderLabel),
st::rightsHeaderMargin);
}
const auto addCheckbox = [&](
not_null<Ui::VerticalLayout*> verticalLayout,
bool isInner,
@@ -1136,19 +1129,24 @@ void ShowEditPeerPermissionsBox(
disabledByAdminRights,
tr::lng_rights_permission_cant_edit(tr::now));
if (const auto channel = peer->asChannel()) {
if (channel->isPublic()
|| (channel->isMegagroup() && channel->linkedChat())) {
if (channel->isPublic()) {
result.emplace(
Flag::ChangeInfo | Flag::PinMessages,
tr::lng_rights_permission_unavailable(tr::now));
} else if (channel->isMegagroup() && channel->linkedChat()) {
result.emplace(
Flag::ChangeInfo | Flag::PinMessages,
tr::lng_rights_permission_in_discuss(tr::now));
}
}
return result;
}();
Ui::AddSubsectionTitle(
inner,
tr::lng_rights_default_restrictions_header());
auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions(
inner,
tr::lng_rights_default_restrictions_header(),
restrictions,
disabledMessages,
{ .isForum = peer->isForum() });
@@ -1312,7 +1310,6 @@ std::vector<AdminRightLabel> AdminRightLabels(
EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
QWidget *parent,
rpl::producer<QString> header,
ChatRestrictions restrictions,
base::flat_map<ChatRestrictions, QString> disabledMessages,
Data::RestrictionsSetOptions options) {
@@ -1321,7 +1318,6 @@ EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
widget.data(),
NegateRestrictions(restrictions),
{
.header = std::move(header),
.labels = NestedRestrictionLabelsList(options),
.disabledMessages = std::move(disabledMessages),
});
@@ -1338,7 +1334,6 @@ EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
QWidget *parent,
rpl::producer<QString> header,
ChatAdminRights rights,
base::flat_map<ChatAdminRights, QString> disabledMessages,
Data::AdminRightsSetOptions options) {
@@ -1347,7 +1342,6 @@ EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
widget.data(),
rights,
{
.header = std::move(header),
.labels = NestedAdminRightLabels(options),
.disabledMessages = std::move(disabledMessages),
});

View File

@@ -73,7 +73,6 @@ struct NestedEditFlagsLabels {
template <typename Flags>
struct EditFlagsDescriptor {
rpl::producer<QString> header;
std::vector<NestedEditFlagsLabels<Flags>> labels;
base::flat_map<Flags, QString> disabledMessages;
const style::SettingsButton *st = nullptr;
@@ -90,7 +89,6 @@ using AdminRightLabel = EditFlagsLabel<ChatAdminRights>;
[[nodiscard]] auto CreateEditRestrictions(
QWidget *parent,
rpl::producer<QString> header,
ChatRestrictions restrictions,
base::flat_map<ChatRestrictions, QString> disabledMessages,
Data::RestrictionsSetOptions options)
@@ -98,7 +96,6 @@ using AdminRightLabel = EditFlagsLabel<ChatAdminRights>;
[[nodiscard]] auto CreateEditAdminRights(
QWidget *parent,
rpl::producer<QString> header,
ChatAdminRights rights,
base::flat_map<ChatAdminRights, QString> disabledMessages,
Data::AdminRightsSetOptions options)

View File

@@ -241,8 +241,8 @@ RequestsBoxController::RowHelper::RowHelper(bool isGroup)
? tr::lng_group_requests_add(tr::now)
: tr::lng_group_requests_add_channel(tr::now))
, _rejectText(tr::lng_group_requests_dismiss(tr::now))
, _acceptTextWidth(st::requestsAcceptButton.font->width(_acceptText))
, _rejectTextWidth(st::requestsRejectButton.font->width(_rejectText)) {
, _acceptTextWidth(st::requestsAcceptButton.style.font->width(_acceptText))
, _rejectTextWidth(st::requestsRejectButton.style.font->width(_rejectText)) {
}
RequestsBoxController::RequestsBoxController(
@@ -491,7 +491,7 @@ void RequestsBoxController::RowHelper::paintButton(
const auto textLeft = geometry.x()
+ ((geometry.width() - textWidth) / 2);
const auto textTop = geometry.y() + st.textTop;
p.setFont(st.font);
p.setFont(st.style.font);
p.setPen(over ? st.textFgOver : st.textFg);
p.drawTextLeft(textLeft, textTop, outerWidth, text);
}

View File

@@ -721,6 +721,7 @@ void PeerShortInfoBox::prepare() {
_roundedTop.setDevicePixelRatio(style::DevicePixelRatio());
refreshRoundedTopImage(getDelegate()->style().bg->c);
setCustomCornersFilling(RectPart::FullTop);
setDimensionsToContent(st::shortInfoWidth, _rows);
}
@@ -795,10 +796,6 @@ void PeerShortInfoBox::prepareRows() {
tr::lng_mediaview_copy(tr::now));
}
RectParts PeerShortInfoBox::customCornersFilling() {
return RectPart::FullTop;
}
void PeerShortInfoBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);

View File

@@ -162,7 +162,6 @@ public:
private:
void prepare() override;
void prepareRows();
RectParts customCornersFilling() override;
void resizeEvent(QResizeEvent *e) override;

View File

@@ -79,7 +79,8 @@ void ProcessUserpic(
if (!state->userpicView.cloud) {
GenerateImage(
state,
peer->generateUserpicImage(
PeerData::GenerateUserpicImage(
peer,
state->userpicView,
st::shortInfoWidth * style::DevicePixelRatio(),
0),

View File

@@ -23,7 +23,7 @@ using Type = SelfDestructionBox::Type;
[[nodiscard]] std::vector<int> Values(Type type) {
switch (type) {
case Type::Account: return { 30, 90, 180, 365 };
case Type::Account: return { 30, 90, 180, 365, 548, 720 };
case Type::Sessions: return { 7, 30, 90, 180, 365 };
}
Unexpected("SelfDestructionBox::Type in Values.");
@@ -113,8 +113,8 @@ void SelfDestructionBox::showContent() {
QString SelfDestructionBox::DaysLabel(int days) {
return !days
? QString()
: (days > 364)
? tr::lng_years(tr::now, lt_count, days / 365)
//: (days > 364)
//? tr::lng_years(tr::now, lt_count, days / 365)
: (days > 25)
? tr::lng_months(tr::now, lt_count, std::max(days / 30, 1))
: tr::lng_weeks(tr::now, lt_count, std::max(days / 7, 1));

View File

@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/message_field.h"
#include "menu/menu_send.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/field_autocomplete.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "editor/photo_editor_layer_widget.h"
@@ -32,7 +33,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/premium_limits_box.h"
#include "boxes/premium_preview_box.h"
#include "boxes/send_credits_box.h"
#include "platform/platform_file_utilities.h"
#include "ui/effects/scroll_content_shadow.h"
#include "ui/widgets/fields/number_input.h"
#include "ui/widgets/checkbox.h"
@@ -72,7 +72,7 @@ constexpr auto kMaxMessageLength = 4096;
using Ui::SendFilesWay;
[[nodiscard]] inline bool CanAddUrls(const QList<QUrl> &urls) {
return !urls.isEmpty() && ranges::all_of(urls, Core::UrlIsLocal);
return !urls.isEmpty() && ranges::all_of(urls, &QUrl::isLocalFile);
}
[[nodiscard]] bool CanAddFiles(not_null<const QMimeData*> data) {
@@ -1274,6 +1274,7 @@ void SendFilesBox::setupCaption() {
[=] { return show->paused(Window::GifPauseReason::Layer); },
allow,
&_st.files.caption);
setupCaptionAutocomplete();
Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(),
_caption,
@@ -1333,6 +1334,59 @@ void SendFilesBox::setupCaption() {
}, _caption->lifetime());
}
void SendFilesBox::setupCaptionAutocomplete() {
if (!_captionToPeer || !_caption) {
return;
}
const auto parent = getDelegate()->outerContainer();
ChatHelpers::InitFieldAutocomplete(_autocomplete, {
.parent = parent,
.show = _show,
.field = _caption.data(),
.peer = _captionToPeer,
.features = [=] {
auto result = ChatHelpers::ComposeFeatures();
result.autocompleteCommands = false;
result.suggestStickersByEmoji = false;
return result;
},
.sendMenuDetails = _sendMenuDetails,
});
const auto raw = _autocomplete.get();
const auto scheduled = std::make_shared<bool>();
const auto recountPostponed = [=] {
if (*scheduled) {
return;
}
*scheduled = true;
Ui::PostponeCall(raw, [=] {
*scheduled = false;
auto field = Ui::MapFrom(parent, this, _caption->geometry());
_autocomplete->setBoundings(QRect(
field.x() - _caption->x(),
st::defaultBox.margin.top(),
width(),
(field.y()
+ _st.files.caption.textMargins.top()
+ _st.files.caption.placeholderShift
+ _st.files.caption.placeholderFont->height
- st::defaultBox.margin.top())));
});
};
for (auto w = (QWidget*)_caption.data(); w; w = w->parentWidget()) {
base::install_event_filter(raw, w, [=](not_null<QEvent*> e) {
if (e->type() == QEvent::Move || e->type() == QEvent::Resize) {
recountPostponed();
}
return base::EventFilterResult::Continue;
});
if (w == parent) {
break;
}
}
}
void SendFilesBox::checkCharsLimitation() {
const auto limits = Data::PremiumLimits(&_show->session());
const auto caption = (_caption && !_caption->isHidden())
@@ -1648,6 +1702,14 @@ void SendFilesBox::updateControlsGeometry() {
_scroll->move(0, _titleHeight.current());
}
void SendFilesBox::showFinished() {
if (const auto raw = _autocomplete.get()) {
InvokeQueued(raw, [=] {
raw->raise();
});
}
}
void SendFilesBox::setInnerFocus() {
if (_caption && !_caption->isHidden()) {
_caption->setFocusFast();

View File

@@ -28,6 +28,7 @@ enum class SendType;
namespace ChatHelpers {
class TabbedPanel;
class Show;
class FieldAutocomplete;
} // namespace ChatHelpers
namespace Ui {
@@ -126,6 +127,8 @@ public:
_cancelledCallback = std::move(callback);
}
void showFinished() override;
~SendFilesBox();
protected:
@@ -206,6 +209,7 @@ private:
void refreshControls(bool initial = false);
void setupSendWayControls();
void setupCaption();
void setupCaptionAutocomplete();
void setupEmojiPanel();
void updateSendWayControls();
@@ -257,6 +261,7 @@ private:
SendFilesLimits _limits = {};
Fn<MenuDetails()> _sendMenuDetails;
Fn<void(MenuAction, MenuDetails)> _sendMenuCallback;
PeerData *_captionToPeer = nullptr;
SendFilesCheck _check;
SendFilesConfirmed _confirmedCallback;
@@ -268,6 +273,7 @@ private:
bool _invertCaption = false;
object_ptr<Ui::InputField> _caption = { nullptr };
std::unique_ptr<ChatHelpers::FieldAutocomplete> _autocomplete;
TextWithTags _prefilledCaptionText;
object_ptr<Ui::EmojiButton> _emojiToggle = { nullptr };
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;

View File

@@ -7,7 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/send_gif_with_caption_box.h"
#include "base/event_filter.h"
#include "boxes/premium_preview_box.h"
#include "chat_helpers/field_autocomplete.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
@@ -30,9 +32,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/emoji_button.h"
#include "ui/controls/emoji_button_factory.h"
#include "ui/layers/generic_box.h"
#include "ui/rect.h"
#include "ui/vertical_list.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/rect.h"
#include "ui/ui_utility.h"
#include "ui/vertical_list.h"
#include "window/window_controller.h"
#include "window/window_session_controller.h"
#include "styles/style_boxes.h"
@@ -129,7 +132,9 @@ namespace {
not_null<Window::SessionController*> controller) {
using Limit = HistoryView::Controls::CharactersLimitLabel;
const auto wrap = box->verticalLayout()->add(
const auto bottomContainer = box->setPinnedToBottomContent(
object_ptr<Ui::VerticalLayout>(box));
const auto wrap = bottomContainer->add(
object_ptr<Ui::RpWidget>(box),
st::boxRowPadding);
const auto input = Ui::CreateChild<Ui::InputField>(
@@ -224,6 +229,7 @@ namespace {
void SendGifWithCaptionBox(
not_null<Ui::GenericBox*> box,
not_null<DocumentData*> document,
not_null<PeerData*> peer,
const SendMenu::Details &details,
Fn<void(Api::SendOptions, TextWithTags)> done) {
const auto window = Core::App().findWindow(box);
@@ -233,6 +239,7 @@ void SendGifWithCaptionBox(
}
box->setTitle(tr::lng_send_gif_with_caption());
box->setWidth(st::boxWidth);
box->getDelegate()->setStyle(st::sendGifBox);
const auto container = box->verticalLayout();
[[maybe_unused]] const auto gifWidget = AddGifWidget(
@@ -252,6 +259,61 @@ void SendGifWithCaptionBox(
return true;
});
const auto sendMenuDetails = [=] { return details; };
struct Autocomplete {
std::unique_ptr<ChatHelpers::FieldAutocomplete> dropdown;
bool geometryUpdateScheduled = false;
};
const auto autocomplete = box->lifetime().make_state<Autocomplete>();
const auto outer = box->getDelegate()->outerContainer();
ChatHelpers::InitFieldAutocomplete(autocomplete->dropdown, {
.parent = outer,
.show = controller->uiShow(),
.field = input,
.peer = peer,
.features = [=] {
auto result = ChatHelpers::ComposeFeatures();
result.autocompleteCommands = false;
result.suggestStickersByEmoji = false;
return result;
},
.sendMenuDetails = sendMenuDetails,
});
const auto raw = autocomplete->dropdown.get();
const auto recountPostponed = [=] {
if (autocomplete->geometryUpdateScheduled) {
return;
}
autocomplete->geometryUpdateScheduled = true;
Ui::PostponeCall(raw, [=] {
autocomplete->geometryUpdateScheduled = false;
const auto from = input->parentWidget();
auto field = Ui::MapFrom(outer, from, input->geometry());
const auto &st = st::defaultComposeFiles;
autocomplete->dropdown->setBoundings(QRect(
field.x() - input->x(),
st::defaultBox.margin.top(),
input->width(),
(field.y()
+ st.caption.textMargins.top()
+ st.caption.placeholderShift
+ st.caption.placeholderFont->height
- st::defaultBox.margin.top())));
});
};
for (auto w = (QWidget*)input; w; w = w->parentWidget()) {
base::install_event_filter(raw, w, [=](not_null<QEvent*> e) {
if (e->type() == QEvent::Move || e->type() == QEvent::Resize) {
recountPostponed();
}
return base::EventFilterResult::Continue;
});
if (w == outer) {
break;
}
}
const auto send = [=](Api::SendOptions options) {
done(std::move(options), input->getTextWithTags());
};
@@ -261,8 +323,15 @@ void SendGifWithCaptionBox(
SendMenu::SetupMenuAndShortcuts(
confirm,
controller->uiShow(),
[=] { return details; },
sendMenuDetails,
SendMenu::DefaultCallback(controller->uiShow(), send));
box->setShowFinishedCallback([=] {
if (const auto raw = autocomplete->dropdown.get()) {
InvokeQueued(raw, [=] {
raw->raise();
});
}
});
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class PeerData;
class DocumentData;
namespace Api {
@@ -24,6 +25,7 @@ class GenericBox;
void SendGifWithCaptionBox(
not_null<Ui::GenericBox*> box,
not_null<DocumentData*> document,
not_null<PeerData*> peer,
const SendMenu::Details &details,
Fn<void(Api::SendOptions, TextWithTags)> done);

View File

@@ -1216,11 +1216,12 @@ StickersBox::Inner::Inner(
})
, _itemsTop(st::lineWidth)
, _addText(tr::lng_stickers_featured_add(tr::now))
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
, _addWidth(st::stickersTrendingAdd.style.font->width(_addText))
, _undoText(tr::lng_stickers_return(tr::now))
, _undoWidth(st::stickersUndoRemove.font->width(_undoText))
, _undoWidth(st::stickersUndoRemove.style.font->width(_undoText))
, _installedText(tr::lng_stickers_featured_installed(tr::now))
, _installedWidth(st::stickersTrendingInstalled.font->width(_installedText)) {
, _installedWidth(st::stickersTrendingInstalled.style.font->width(
_installedText)) {
setup();
}
@@ -1666,7 +1667,7 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int ind
row->ripple.reset();
}
}
p.setFont(st.font);
p.setFont(st.style.font);
p.setPen(st.textFg);
p.drawTextLeft(rect.x() - (st.width / 2), rect.y() + st.textTop, width(), text, textWidth);
} else {
@@ -1700,7 +1701,7 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int ind
row->ripple.reset();
}
}
p.setFont(st.font);
p.setFont(st.style.font);
p.setPen(selected ? st.textFgOver : st.textFg);
p.drawTextLeft(rect.x() - (st.width / 2), rect.y() + st.textTop, width(), text, textWidth);
}

View File

@@ -460,7 +460,8 @@ void Viewport::RendererGL::validateUserpicFrame(
return;
}
const auto size = tile->trackOrUserpicSize();
tileData.userpicFrame = tile->row()->peer()->generateUserpicImage(
tileData.userpicFrame = PeerData::GenerateUserpicImage(
tile->row()->peer(),
tile->row()->ensureUserpicView(),
size.width(),
0);

View File

@@ -77,7 +77,8 @@ void Viewport::RendererSW::validateUserpicFrame(
}
const auto size = tile->trackOrUserpicSize();
data.userpicFrame = Images::BlurLargeImage(
tile->row()->peer()->generateUserpicImage(
PeerData::GenerateUserpicImage(
tile->row()->peer(),
tile->row()->ensureUserpicView(),
size.width(),
0),

View File

@@ -23,7 +23,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <tgcalls/desktop_capturer/DesktopCaptureSourceManager.h>
#include <tgcalls/desktop_capturer/DesktopCaptureSourceHelper.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
namespace Calls::Group::Ui::DesktopCapture {
@@ -585,13 +584,7 @@ void ChooseSourceProcess::setupSourcesGeometry() {
void ChooseSourceProcess::setupGeometryWithParent(
not_null<QWidget*> parent) {
const auto parentScreen = [&] {
if (const auto screen = QGuiApplication::screenAt(
parent->geometry().center())) {
return screen;
}
return parent->screen();
}();
const auto parentScreen = parent->screen();
const auto myScreen = _window->screen();
if (parentScreen && myScreen != parentScreen) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)

View File

@@ -296,7 +296,9 @@ emojiPanButton: RoundButton(defaultActiveButton) {
textTop: 2px;
}
emojiPanExpand: RoundButton(defaultActiveButton) {
font: font(12px bold);
style: TextStyle(semiboldTextStyle) {
font: font(12px bold);
}
width: -8px;
height: 19px;
textTop: 1px;
@@ -1499,5 +1501,11 @@ pickLocationChooseOnMap: RoundButton(defaultActiveButton) {
height: 44px;
textTop: 11px;
width: -96px;
font: font(15px semibold);
style: TextStyle(semiboldTextStyle) {
font: font(15px semibold);
}
}
sendGifBox: Box(defaultBox) {
shadowIgnoreBottomSkip: true;
}

View File

@@ -10,20 +10,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace ChatHelpers {
struct ComposeFeatures {
bool likes = false;
bool sendAs = true;
bool ttlInfo = true;
bool botCommandSend = true;
bool silentBroadcastToggle = true;
bool attachBotsMenu = true;
bool inlineBots = true;
bool megagroupSet = true;
bool stickersSettings = true;
bool openStickerSets = true;
bool autocompleteHashtags = true;
bool autocompleteMentions = true;
bool autocompleteCommands = true;
bool commonTabbedPanel = true;
bool likes : 1 = false;
bool sendAs : 1 = true;
bool ttlInfo : 1 = true;
bool botCommandSend : 1 = true;
bool silentBroadcastToggle : 1 = true;
bool attachBotsMenu : 1 = true;
bool inlineBots : 1 = true;
bool megagroupSet : 1 = true;
bool stickersSettings : 1 = true;
bool openStickerSets : 1 = true;
bool autocompleteHashtags : 1 = true;
bool autocompleteMentions : 1 = true;
bool autocompleteCommands : 1 = true;
bool suggestStickersByEmoji : 1 = true;
bool commonTabbedPanel : 1 = true;
};
} // namespace ChatHelpers

View File

@@ -1450,17 +1450,17 @@ void EmojiListWidget::drawCollapsedBadge(
int count) {
const auto &st = st::emojiPanExpand;
const auto text = u"+%1"_q.arg(count - _columnCount * kCollapsedRows + 1);
const auto textWidth = st.font->width(text);
const auto textWidth = st.style.font->width(text);
const auto buttonw = std::max(textWidth - st.width, st.height);
const auto buttonh = st.height;
const auto buttonx = position.x() + (_singleSize.width() - buttonw) / 2;
const auto buttony = position.y() + (_singleSize.height() - buttonh) / 2;
_collapsedBg.paint(p, QRect(buttonx, buttony, buttonw, buttonh));
p.setPen(this->st().bg);
p.setFont(st.font);
p.setFont(st.style.font);
p.drawText(
buttonx + (buttonw - textWidth) / 2,
(buttony + st.textTop + st.font->ascent),
(buttony + st.textTop + st.style.font->ascent),
text);
}
@@ -2546,12 +2546,12 @@ int EmojiListWidget::paintButtonGetWidth(
: selected
? st::emojiPanButton.textFgOver
: st::emojiPanButton.textFg);
p.setFont(st::emojiPanButton.font);
p.setFont(st::emojiPanButton.style.font);
p.drawText(
rect.x() - (st::emojiPanButton.width / 2),
(rect.y()
+ st::emojiPanButton.textTop
+ st::emojiPanButton.font->ascent),
+ st::emojiPanButton.style.font->ascent),
button.text);
return emojiRight() - rect.x();
}
@@ -2678,7 +2678,7 @@ void EmojiListWidget::initButton(
const QString &text,
bool gradient) {
button.text = text;
button.textWidth = st::emojiPanButton.font->width(text);
button.textWidth = st::emojiPanButton.style.font->width(text);
const auto width = button.textWidth - st::emojiPanButton.width;
const auto height = st::emojiPanButton.height;
const auto factor = style::DevicePixelRatio();

View File

@@ -41,9 +41,9 @@ inline auto PreviewPath(int i) {
const auto kSets = {
Set{ { 0, 0, 0, "Mac" }, PreviewPath(0) },
Set{ { 1, 1804, 8'115'639, "Android" }, PreviewPath(1) },
Set{ { 2, 1805, 5'481'197, "Twemoji" }, PreviewPath(2) },
Set{ { 3, 1806, 7'047'594, "JoyPixels" }, PreviewPath(3) },
Set{ { 1, 2290, 8'306'943, "Android" }, PreviewPath(1) },
Set{ { 2, 2291, 5'694'303, "Twemoji" }, PreviewPath(2) },
Set{ { 3, 2292, 7'261'223, "JoyPixels" }, PreviewPath(3) },
};
using Loading = MTP::DedicatedLoader::Progress;

View File

@@ -713,11 +713,13 @@ void SuggestionsWidget::leaveEventHook(QEvent *e) {
}
SuggestionsController::SuggestionsController(
not_null<QWidget*> parent,
not_null<QWidget*> outer,
not_null<QTextEdit*> field,
not_null<Main::Session*> session,
const Options &options)
: _st(options.st ? *options.st : st::defaultEmojiSuggestions)
: QObject(parent)
, _st(options.st ? *options.st : st::defaultEmojiSuggestions)
, _field(field)
, _session(session)
, _showExactTimer([=] { showWithQuery(getEmojiQuery()); })

View File

@@ -37,7 +37,7 @@ class SuggestionsWidget;
using SuggestionsQuery = std::variant<QString, EmojiPtr>;
class SuggestionsController {
class SuggestionsController final : public QObject {
public:
struct Options {
bool suggestExactFirstWord = true;
@@ -47,6 +47,7 @@ public:
};
SuggestionsController(
not_null<QWidget*> parent,
not_null<QWidget*> outer,
not_null<QTextEdit*> field,
not_null<Main::Session*> session,

View File

@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/business/data_shortcut_messages.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_changes.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
@@ -53,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QApplication>
namespace ChatHelpers {
namespace {
[[nodiscard]] QString PrimaryUsername(not_null<UserData*> user) {
@@ -60,6 +62,18 @@ namespace {
return usernames.empty() ? user->username() : usernames.front();
}
template <typename T, typename U>
inline int indexOfInFirstN(const T &v, const U &elem, int last) {
for (auto b = v.cbegin(), i = b, e = b + std::max(int(v.size()), last)
; i != e
; ++i) {
if (i->user == elem) {
return (i - b);
}
}
return -1;
}
} // namespace
class FieldAutocomplete::Inner final : public Ui::RpWidget {
@@ -70,7 +84,7 @@ public:
};
Inner(
std::shared_ptr<ChatHelpers::Show> show,
std::shared_ptr<Show> show,
const style::EmojiPan &st,
not_null<FieldAutocomplete*> parent,
not_null<MentionRows*> mrows,
@@ -127,7 +141,7 @@ private:
Media::Clip::Notification notification,
not_null<DocumentData*> document);
const std::shared_ptr<ChatHelpers::Show> _show;
const std::shared_ptr<Show> _show;
const not_null<Main::Session*> _session;
const style::EmojiPan &_st;
const not_null<FieldAutocomplete*> _parent;
@@ -191,13 +205,7 @@ struct FieldAutocomplete::BotCommandRow {
FieldAutocomplete::FieldAutocomplete(
QWidget *parent,
not_null<Window::SessionController*> controller)
: FieldAutocomplete(parent, controller->uiShow()) {
}
FieldAutocomplete::FieldAutocomplete(
QWidget *parent,
std::shared_ptr<ChatHelpers::Show> show,
std::shared_ptr<Show> show,
const style::EmojiPan *stOverride)
: RpWidget(parent)
, _show(std::move(show))
@@ -235,10 +243,26 @@ FieldAutocomplete::FieldAutocomplete(
}), lifetime());
}
std::shared_ptr<ChatHelpers::Show> FieldAutocomplete::uiShow() const {
std::shared_ptr<Show> FieldAutocomplete::uiShow() const {
return _show;
}
void FieldAutocomplete::requestRefresh() {
_refreshRequests.fire({});
}
rpl::producer<> FieldAutocomplete::refreshRequests() const {
return _refreshRequests.events();
}
void FieldAutocomplete::requestStickersUpdate() {
_stickersUpdateRequests.fire({});
}
rpl::producer<> FieldAutocomplete::stickersUpdateRequests() const {
return _stickersUpdateRequests.events();
}
auto FieldAutocomplete::mentionChosen() const
-> rpl::producer<FieldAutocomplete::MentionChosen> {
return _inner->mentionChosen();
@@ -365,6 +389,10 @@ void FieldAutocomplete::showStickers(EmojiPtr emoji) {
updateFiltered(resetScroll);
}
EmojiPtr FieldAutocomplete::stickersEmoji() const {
return _emoji;
}
bool FieldAutocomplete::clearFilteredBotCommands() {
if (_brows.empty()) {
return false;
@@ -373,18 +401,6 @@ bool FieldAutocomplete::clearFilteredBotCommands() {
return true;
}
namespace {
template <typename T, typename U>
inline int indexOfInFirstN(const T &v, const U &elem, int last) {
for (auto b = v.cbegin(), i = b, e = b + std::max(int(v.size()), last); i != e; ++i) {
if (i->user == elem) {
return (i - b);
}
}
return -1;
}
}
FieldAutocomplete::StickerRows FieldAutocomplete::getStickerSuggestions() {
const auto data = &_session->data().stickers();
const auto list = data->getListByEmoji({ _emoji }, _stickersSeed);
@@ -871,7 +887,7 @@ bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) {
}
FieldAutocomplete::Inner::Inner(
std::shared_ptr<ChatHelpers::Show> show,
std::shared_ptr<Show> show,
const style::EmojiPan &st,
not_null<FieldAutocomplete*> parent,
not_null<MentionRows*> mrows,
@@ -963,8 +979,8 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
media->checkStickerSmall();
const auto paused = _show->paused(
ChatHelpers::PauseReason::TabbedPanel);
const auto size = ChatHelpers::ComputeStickerSize(
PauseReason::TabbedPanel);
const auto size = ComputeStickerSize(
document,
stickerBoundingBox());
const auto ppos = pos + QPoint(
@@ -989,7 +1005,7 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
} else if (const auto image = media->getStickerSmall()) {
p.drawPixmapLeft(ppos, width(), image->pix(size));
} else {
ChatHelpers::PaintStickerThumbnailPath(
PaintStickerThumbnailPath(
p,
media.get(),
QRect(ppos, size),
@@ -1250,7 +1266,7 @@ bool FieldAutocomplete::Inner::chooseAtIndex(
const auto bounding = selectedRect(index);
auto contentRect = QRect(
QPoint(),
ChatHelpers::ComputeStickerSize(
ComputeStickerSize(
document,
stickerBoundingBox()));
contentRect.moveCenter(bounding.center());
@@ -1464,9 +1480,9 @@ auto FieldAutocomplete::Inner::getLottieRenderer()
void FieldAutocomplete::Inner::setupLottie(StickerSuggestion &suggestion) {
const auto document = suggestion.document;
suggestion.lottie = ChatHelpers::LottiePlayerFromDocument(
suggestion.lottie = LottiePlayerFromDocument(
suggestion.documentMedia.get(),
ChatHelpers::StickerLottieSize::InlineResults,
StickerLottieSize::InlineResults,
stickerBoundingBox() * style::DevicePixelRatio(),
Lottie::Quality::Default,
getLottieRenderer());
@@ -1534,7 +1550,7 @@ void FieldAutocomplete::Inner::clipCallback(
} else if (i->webm->state() == State::Error) {
i->webm.setBad();
} else if (i->webm->ready() && !i->webm->started()) {
const auto size = ChatHelpers::ComputeStickerSize(
const auto size = ComputeStickerSize(
i->document,
stickerBoundingBox());
i->webm->start({ .frame = size, .keepAlpha = true });
@@ -1632,3 +1648,171 @@ auto FieldAutocomplete::Inner::scrollToRequested() const
-> rpl::producer<ScrollTo> {
return _scrollToRequested.events();
}
void InitFieldAutocomplete(
std::unique_ptr<FieldAutocomplete> &autocomplete,
FieldAutocompleteDescriptor &&descriptor) {
Expects(!autocomplete);
autocomplete = std::make_unique<FieldAutocomplete>(
descriptor.parent,
descriptor.show,
descriptor.stOverride);
const auto raw = autocomplete.get();
const auto field = descriptor.field;
field->rawTextEdit()->installEventFilter(raw);
field->customTab(true);
raw->mentionChosen(
) | rpl::start_with_next([=](FieldAutocomplete::MentionChosen data) {
const auto user = data.user;
if (data.mention.isEmpty()) {
field->insertTag(
user->firstName.isEmpty() ? user->name() : user->firstName,
PrepareMentionTag(user));
} else {
field->insertTag('@' + data.mention);
}
}, raw->lifetime());
const auto sendCommand = descriptor.sendBotCommand;
const auto setText = descriptor.setText;
raw->hashtagChosen(
) | rpl::start_with_next([=](FieldAutocomplete::HashtagChosen data) {
field->insertTag(data.hashtag);
}, raw->lifetime());
const auto peer = descriptor.peer;
const auto features = descriptor.features;
const auto processShortcut = descriptor.processShortcut;
const auto shortcutMessages = (processShortcut != nullptr)
? &peer->owner().shortcutMessages()
: nullptr;
raw->botCommandChosen(
) | rpl::start_with_next([=](FieldAutocomplete::BotCommandChosen data) {
if (!features().autocompleteCommands) {
return;
}
using Method = FieldAutocompleteChooseMethod;
const auto byTab = (data.method == Method::ByTab);
const auto shortcut = data.user->isSelf();
// Send bot command at once, if it was not inserted by pressing Tab.
if (byTab && data.command.size() > 1) {
field->insertTag(data.command);
} else if (!shortcut) {
sendCommand(data.command);
setText(
field->getTextWithTagsPart(field->textCursor().position()));
} else if (processShortcut) {
processShortcut(data.command.mid(1));
}
}, raw->lifetime());
raw->setModerateKeyActivateCallback(std::move(descriptor.moderateKeyActivateCallback));
if (const auto stickerChoosing = descriptor.stickerChoosing) {
raw->choosingProcesses(
) | rpl::start_with_next([=](FieldAutocomplete::Type type) {
if (type == FieldAutocomplete::Type::Stickers) {
stickerChoosing();
}
}, raw->lifetime());
}
if (const auto chosen = descriptor.stickerChosen) {
raw->stickerChosen(
) | rpl::start_with_next(chosen, raw->lifetime());
}
field->tabbed(
) | rpl::start_with_next([=] {
if (!raw->isHidden()) {
raw->chooseSelected(FieldAutocomplete::ChooseMethod::ByTab);
}
}, raw->lifetime());
const auto check = [=] {
auto parsed = ParseMentionHashtagBotCommandQuery(field, features());
if (parsed.query.isEmpty()) {
} else if (parsed.query[0] == '#'
&& cRecentWriteHashtags().isEmpty()
&& cRecentSearchHashtags().isEmpty()) {
peer->session().local().readRecentHashtagsAndBots();
} else if (parsed.query[0] == '@'
&& cRecentInlineBots().isEmpty()) {
peer->session().local().readRecentHashtagsAndBots();
} else if (parsed.query[0] == '/'
&& peer->isUser()
&& !peer->asUser()->isBot()
&& (!shortcutMessages
|| shortcutMessages->shortcuts().list.empty())) {
parsed = {};
}
raw->showFiltered(peer, parsed.query, parsed.fromStart);
};
const auto updateStickersByEmoji = [=] {
const auto errorForStickers = Data::RestrictionError(
peer,
ChatRestriction::SendStickers);
if (features().suggestStickersByEmoji && !errorForStickers) {
const auto &text = field->getTextWithTags().text;
auto length = 0;
if (const auto emoji = Ui::Emoji::Find(text, &length)) {
if (text.size() <= length) {
raw->showStickers(emoji);
return;
}
}
}
raw->showStickers(nullptr);
};
raw->refreshRequests(
) | rpl::start_with_next(check, raw->lifetime());
raw->stickersUpdateRequests(
) | rpl::start_with_next(updateStickersByEmoji, raw->lifetime());
peer->owner().botCommandsChanges(
) | rpl::filter([=](not_null<PeerData*> changed) {
return (peer == changed);
}) | rpl::start_with_next([=] {
if (raw->clearFilteredBotCommands()) {
check();
}
}, raw->lifetime());
peer->owner().stickers().updated(
Data::StickersType::Stickers
) | rpl::start_with_next(updateStickersByEmoji, raw->lifetime());
QObject::connect(
field->rawTextEdit(),
&QTextEdit::cursorPositionChanged,
raw,
check,
Qt::QueuedConnection);
field->changes() | rpl::start_with_next(
updateStickersByEmoji,
raw->lifetime());
peer->session().changes().peerUpdates(
Data::PeerUpdate::Flag::Rights
) | rpl::filter([=](const Data::PeerUpdate &update) {
return (update.peer == peer);
}) | rpl::start_with_next(updateStickersByEmoji, raw->lifetime());
if (shortcutMessages) {
shortcutMessages->shortcutsChanged(
) | rpl::start_with_next(check, raw->lifetime());
}
raw->setSendMenuDetails(std::move(descriptor.sendMenuDetails));
raw->hideFast();
}
} // namespace ChatHelpers

View File

@@ -46,46 +46,49 @@ struct Details;
} // namespace SendMenu
namespace ChatHelpers {
struct ComposeFeatures;
struct FileChosen;
class Show;
} // namespace ChatHelpers
enum class FieldAutocompleteChooseMethod {
ByEnter,
ByTab,
ByClick,
};
class FieldAutocomplete final : public Ui::RpWidget {
public:
FieldAutocomplete(
QWidget *parent,
not_null<Window::SessionController*> controller);
FieldAutocomplete(
QWidget *parent,
std::shared_ptr<ChatHelpers::Show> show,
std::shared_ptr<Show> show,
const style::EmojiPan *stOverride = nullptr);
~FieldAutocomplete();
[[nodiscard]] std::shared_ptr<ChatHelpers::Show> uiShow() const;
[[nodiscard]] std::shared_ptr<Show> uiShow() const;
bool clearFilteredBotCommands();
void showFiltered(
not_null<PeerData*> peer,
QString query,
bool addInlineBots);
void showStickers(EmojiPtr emoji);
[[nodiscard]] EmojiPtr stickersEmoji() const;
void setBoundings(QRect boundings);
const QString &filter() const;
ChatData *chat() const;
ChannelData *channel() const;
UserData *user() const;
[[nodiscard]] const QString &filter() const;
[[nodiscard]] ChatData *chat() const;
[[nodiscard]] ChannelData *channel() const;
[[nodiscard]] UserData *user() const;
int32 innerTop();
int32 innerBottom();
[[nodiscard]] int32 innerTop();
[[nodiscard]] int32 innerBottom();
bool eventFilter(QObject *obj, QEvent *e) override;
enum class ChooseMethod {
ByEnter,
ByTab,
ByClick,
};
using ChooseMethod = FieldAutocompleteChooseMethod;
struct MentionChosen {
not_null<UserData*> user;
QString mention;
@@ -100,7 +103,7 @@ public:
QString command;
ChooseMethod method = ChooseMethod::ByEnter;
};
using StickerChosen = ChatHelpers::FileChosen;
using StickerChosen = FileChosen;
enum class Type {
Mentions,
Hashtags,
@@ -110,13 +113,14 @@ public:
bool chooseSelected(ChooseMethod method) const;
bool stickersShown() const {
[[nodiscard]] bool stickersShown() const {
return !_srows.empty();
}
bool overlaps(const QRect &globalRect) {
if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) return false;
[[nodiscard]] bool overlaps(const QRect &globalRect) {
if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) {
return false;
}
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
@@ -129,11 +133,16 @@ public:
void showAnimated();
void hideAnimated();
rpl::producer<MentionChosen> mentionChosen() const;
rpl::producer<HashtagChosen> hashtagChosen() const;
rpl::producer<BotCommandChosen> botCommandChosen() const;
rpl::producer<StickerChosen> stickerChosen() const;
rpl::producer<Type> choosingProcesses() const;
void requestRefresh();
[[nodiscard]] rpl::producer<> refreshRequests() const;
void requestStickersUpdate();
[[nodiscard]] rpl::producer<> stickersUpdateRequests() const;
[[nodiscard]] rpl::producer<MentionChosen> mentionChosen() const;
[[nodiscard]] rpl::producer<HashtagChosen> hashtagChosen() const;
[[nodiscard]] rpl::producer<BotCommandChosen> botCommandChosen() const;
[[nodiscard]] rpl::producer<StickerChosen> stickerChosen() const;
[[nodiscard]] rpl::producer<Type> choosingProcesses() const;
protected:
void paintEvent(QPaintEvent *e) override;
@@ -157,7 +166,7 @@ private:
void recount(bool resetScroll = false);
StickerRows getStickerSuggestions();
const std::shared_ptr<ChatHelpers::Show> _show;
const std::shared_ptr<Show> _show;
const not_null<Main::Session*> _session;
const style::EmojiPan &_st;
QPixmap _cache;
@@ -189,7 +198,30 @@ private:
bool _hiding = false;
Ui::Animations::Simple _a_opacity;
rpl::event_stream<> _refreshRequests;
rpl::event_stream<> _stickersUpdateRequests;
Fn<bool(int)> _moderateKeyActivateCallback;
};
struct FieldAutocompleteDescriptor {
not_null<QWidget*> parent;
std::shared_ptr<Show> show;
not_null<Ui::InputField*> field;
const style::EmojiPan *stOverride = nullptr;
not_null<PeerData*> peer;
Fn<ComposeFeatures()> features;
Fn<SendMenu::Details()> sendMenuDetails;
Fn<void()> stickerChoosing;
Fn<void(FileChosen&&)> stickerChosen;
Fn<void(TextWithTags)> setText;
Fn<void(QString)> sendBotCommand;
Fn<void(QString)> processShortcut;
Fn<bool(int)> moderateKeyActivateCallback;
};
void InitFieldAutocomplete(
std::unique_ptr<FieldAutocomplete> &autocomplete,
FieldAutocompleteDescriptor &&descriptor);
} // namespace ChatHelpers

View File

@@ -409,17 +409,19 @@ base::unique_qptr<Ui::PopupMenu> GifsListWidget::fillContextMenu(
SendMenu::DefaultCallback(_show, send),
icons);
if (!isInlineResult) {
if (!isInlineResult && _inlineQueryPeer) {
auto done = crl::guard(this, [=](
Api::SendOptions options,
TextWithTags text) {
selectInlineResult(selected, options, true, std::move(text));
});
const auto show = _show;
const auto peer = _inlineQueryPeer;
menu->addAction(tr::lng_send_gif_with_caption(tr::now), [=] {
show->show(Box(
Ui::SendGifWithCaptionBox,
item->getDocument(),
peer,
copyDetails,
std::move(done)));
}, &st::menuIconEdit);

View File

@@ -63,6 +63,12 @@ constexpr auto kParseLinksTimeout = crl::time(1000);
constexpr auto kTypesDuration = 4 * crl::time(1000);
constexpr auto kCodeLanguageLimit = 32;
constexpr auto kLinkProtocols = {
"http://",
"https://",
"tonsite://"
};
// For mention / custom emoji tags save and validate selfId,
// ignore tags for different users.
[[nodiscard]] Fn<QString(QStringView)> FieldTagMimeProcessor(
@@ -147,13 +153,23 @@ void EditLinkBox(
object_ptr<Ui::RpWidget>(content),
st::markdownLinkFieldPadding);
placeholder->setAttribute(Qt::WA_TransparentForMouseEvents);
const auto link = [&] {
if (!startLink.trimmed().isEmpty()) {
return startLink.trimmed();
}
const auto clipboard = QGuiApplication::clipboard()->text().trimmed();
const auto starts = [&](const auto &protocol) {
return clipboard.startsWith(protocol);
};
return std::ranges::any_of(kLinkProtocols, starts) ? clipboard : QString();
}();
const auto url = Ui::AttachParentChild(
content,
object_ptr<Ui::InputField>(
content,
fieldSt,
tr::lng_formatting_link_url(),
startLink.trimmed()));
link));
url->heightValue(
) | rpl::start_with_next([placeholder](int height) {
placeholder->resize(placeholder->width(), height);
@@ -209,6 +225,9 @@ void EditLinkBox(
if (startText.isEmpty()) {
text->setFocusFast();
} else {
if (!url->empty()) {
url->selectAll();
}
url->setFocusFast();
}
});
@@ -216,12 +235,31 @@ void EditLinkBox(
url->customTab(true);
text->customTab(true);
const auto clearFullSelection = [=](not_null<Ui::InputField*> input) {
if (input->empty()) {
return;
}
auto cursor = input->rawTextEdit()->textCursor();
const auto hasFull = (!cursor.selectionStart()
&& (cursor.selectionEnd()
== (input->rawTextEdit()->document()->characterCount() - 1)));
if (hasFull) {
cursor.clearSelection();
input->setTextCursor(cursor);
}
};
url->tabbed(
) | rpl::start_with_next([=] {
clearFullSelection(url);
text->setFocus();
}, url->lifetime());
text->tabbed(
) | rpl::start_with_next([=] {
if (!url->empty()) {
url->selectAll();
}
clearFullSelection(text);
url->setFocus();
}, text->lifetime());
}
@@ -543,7 +581,6 @@ void InitMessageField(
[=] { return show->paused(ChatHelpers::PauseReason::Any); },
std::move(allowPremiumEmoji));
InitMessageFieldGeometry(field);
field->customTab(true);
}
void InitMessageField(

View File

@@ -213,11 +213,14 @@ StickersListWidget::StickersListWidget(
st().pathBg,
st().pathFg,
[=] { update(); }))
, _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st().headerLeft)
, _megagroupSetAbout(st::columnMinimalWidthThird
- st::emojiScroll.width
- st().headerLeft)
, _addText(tr::lng_stickers_featured_add(tr::now))
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
, _addWidth(st::stickersTrendingAdd.style.font->width(_addText))
, _installedText(tr::lng_stickers_featured_installed(tr::now))
, _installedWidth(st::stickersTrendingInstalled.font->width(_installedText))
, _installedWidth(
st::stickersTrendingInstalled.style.font->width(_installedText))
, _settings(this, tr::lng_stickers_you_have(tr::now))
, _previewTimer([=] { showPreview(); })
, _premiumMark(std::make_unique<StickerPremiumMark>(
@@ -974,7 +977,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
const auto &st = installedSet
? st::stickersTrendingInstalled
: st::stickersTrendingAdd;
p.setFont(st.font);
p.setFont(st.style.font);
p.setPen(selected ? st.textFgOver : st.textFg);
p.drawTextLeft(
add.x() - (st.width / 2),
@@ -1238,7 +1241,7 @@ void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSe
_megagroupSetButtonRipple.reset();
}
}
p.setFont(st::stickerGroupCategoryAdd.font);
p.setFont(st::stickerGroupCategoryAdd.style.font);
p.setPen(buttonSelected ? st::stickerGroupCategoryAdd.textFgOver : st::stickerGroupCategoryAdd.textFg);
p.drawTextLeft(button.x() - (st::stickerGroupCategoryAdd.width / 2), button.y() + st::stickerGroupCategoryAdd.textTop, width(), _megagroupSetButtonText, _megagroupSetButtonTextWidth);
}
@@ -2734,7 +2737,7 @@ void StickersListWidget::refreshMegagroupSetGeometry() {
auto left = megagroupSetInfoLeft();
auto availableWidth = (width() - left);
auto top = _megagroupSetAbout.countHeight(availableWidth) + st::stickerGroupCategoryAddMargin.top();
_megagroupSetButtonTextWidth = st::stickerGroupCategoryAdd.font->width(_megagroupSetButtonText);
_megagroupSetButtonTextWidth = st::stickerGroupCategoryAdd.style.font->width(_megagroupSetButtonText);
auto buttonWidth = _megagroupSetButtonTextWidth - st::stickerGroupCategoryAdd.width;
_megagroupSetButtonRect = QRect(left, top, buttonWidth, st::stickerGroupCategoryAdd.height);
}

View File

@@ -221,7 +221,8 @@ QByteArray Settings::serialize() const {
+ Serialize::stringSize(noWarningExtensions)
+ Serialize::stringSize(_customFontFamily)
+ sizeof(qint32) * 3
+ Serialize::bytearraySize(_tonsiteStorageToken);
+ Serialize::bytearraySize(_tonsiteStorageToken)
+ sizeof(qint32);
auto result = QByteArray();
result.reserve(size);
@@ -375,7 +376,8 @@ QByteArray Settings::serialize() const {
1000000))
<< qint32(_systemUnlockEnabled ? 1 : 0)
<< qint32(!_weatherInCelsius ? 0 : *_weatherInCelsius ? 1 : 2)
<< _tonsiteStorageToken;
<< _tonsiteStorageToken
<< qint32(_includeMutedCounterFolders ? 1 : 0);
}
Ensures(result.size() == size);
@@ -423,6 +425,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 sendFilesWay = _sendFilesWay.serialize();
qint32 sendSubmitWay = static_cast<qint32>(_sendSubmitWay.current());
qint32 includeMutedCounter = _includeMutedCounter ? 1 : 0;
qint32 includeMutedCounterFolders = _includeMutedCounterFolders ? 1 : 0;
qint32 countUnreadMessages = _countUnreadMessages ? 1 : 0;
std::optional<QString> noWarningExtensions;
qint32 legacyExeLaunchWarning = 1;
@@ -804,6 +807,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> tonsiteStorageToken;
}
if (!stream.atEnd()) {
stream >> includeMutedCounterFolders;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
@@ -844,6 +850,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
case ScreenCorner::BottomLeft: _notificationsCorner = uncheckedNotificationsCorner; break;
}
_includeMutedCounter = (includeMutedCounter == 1);
_includeMutedCounterFolders = (includeMutedCounterFolders == 1);
_countUnreadMessages = (countUnreadMessages == 1);
_notifyAboutPinned = (notifyAboutPinned == 1);
_autoLock = autoLock;
@@ -864,8 +871,6 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
case Ui::InputSubmitSettings::Enter:
case Ui::InputSubmitSettings::CtrlEnter: _sendSubmitWay = uncheckedSendSubmitWay; break;
}
_includeMutedCounter = (includeMutedCounter == 1);
_countUnreadMessages = (countUnreadMessages == 1);
if (noWarningExtensions) {
const auto list = noWarningExtensions->mid(0, 10240)
.split(' ', Qt::SkipEmptyParts)
@@ -1345,6 +1350,7 @@ void Settings::resetOnLastLogout() {
//_notificationsCount = 3;
//_notificationsCorner = ScreenCorner::BottomRight;
_includeMutedCounter = true;
_includeMutedCounterFolders = true;
_countUnreadMessages = true;
_notifyAboutPinned = true;
//_autoLock = 3600;

View File

@@ -238,6 +238,12 @@ public:
void setIncludeMutedCounter(bool value) {
_includeMutedCounter = value;
}
[[nodiscard]] bool includeMutedCounterFolders() const {
return _includeMutedCounterFolders;
}
void setIncludeMutedCounterFolders(bool value) {
_includeMutedCounterFolders = value;
}
[[nodiscard]] bool countUnreadMessages() const {
return _countUnreadMessages;
}
@@ -951,6 +957,7 @@ private:
int _notificationsCount = 3;
ScreenCorner _notificationsCorner = ScreenCorner::BottomRight;
bool _includeMutedCounter = true;
bool _includeMutedCounterFolders = true;
bool _countUnreadMessages = true;
rpl::variable<bool> _notifyAboutPinned = true;
int _autoLock = 3600;

View File

@@ -7,10 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Core {
bool UrlIsLocal(const QUrl &url);
} // namespace Core
namespace Main {
class Session;
} // namespace Main
@@ -49,7 +45,7 @@ void ShowInFolder(const QString &filepath);
namespace internal {
inline QString UrlToLocalDefault(const QUrl &url) {
return Core::UrlIsLocal(url) ? url.toLocalFile() : QString();
return url.toLocalFile();
}
void UnsafeOpenUrlDefault(const QString &url);

View File

@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/update_checker.h"
#include "core/application.h"
#include "core/click_handler_types.h"
#include "dialogs/ui/dialogs_suggestions.h"
#include "boxes/background_preview_box.h"
#include "ui/boxes/confirm_box.h"
#include "ui/boxes/edit_birthday_box.h"
@@ -923,6 +924,17 @@ bool ShowCollectibleUsername(
return true;
}
bool ShowStarsExamples(
Window::SessionController *controller,
const Match &match,
const QVariant &context) {
if (!controller) {
return false;
}
controller->show(Dialogs::StarsExamplesBox(controller));
return true;
}
void ExportTestChatTheme(
not_null<Window::SessionController*> controller,
not_null<const Data::CloudTheme*> theme) {
@@ -1380,6 +1392,10 @@ const std::vector<LocalUrlHandler> &InternalUrlHandlers() {
u"^collectible_username/([a-zA-Z0-9\\-\\_\\.]+)@([0-9]+)$"_q,
ShowCollectibleUsername,
},
{
u"^stars_examples$"_q,
ShowStarsExamples,
},
};
return Result;
}

View File

@@ -226,24 +226,13 @@ bool CanSendFiles(not_null<const QMimeData*> data) {
if (data->hasImage()) {
return true;
} else if (const auto urls = ReadMimeUrls(data); !urls.empty()) {
if (ranges::all_of(urls, UrlIsLocal)) {
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
return true;
}
}
return false;
}
bool UrlIsLocal(const QUrl &url) {
if (!url.isLocalFile()) {
return false;
}
const auto result = url.toLocalFile();
if (result.startsWith("//")) {
return false;
}
return !result.isEmpty();
}
QString FileExtension(const QString &filepath) {
const auto reversed = ranges::views::reverse(filepath);
const auto last = ranges::find_first_of(reversed, ".\\/");

View File

@@ -68,7 +68,6 @@ struct MimeImageData {
[[nodiscard]] QString ReadMimeText(not_null<const QMimeData*> data);
[[nodiscard]] QList<QUrl> ReadMimeUrls(not_null<const QMimeData*> data);
[[nodiscard]] bool CanSendFiles(not_null<const QMimeData*> data);
[[nodiscard]] bool UrlIsLocal(const QUrl &url);
enum class NameType : uchar {
Unknown,

View File

@@ -13,7 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "core/sandbox.h"
#include "core/click_handler_types.h"
#include "data/components/sponsored_messages.h"
#include "data/stickers/data_custom_emoji.h"
#include "data/data_session.h"
#include "iv/iv_instance.h"
@@ -296,16 +295,6 @@ Fn<void()> UiIntegration::createSpoilerRepaint(const std::any &context) {
return my ? my->customEmojiRepaint : nullptr;
}
bool UiIntegration::allowClickHandlerActivation(
const std::shared_ptr<ClickHandler> &handler,
const ClickContext &context) {
const auto my = context.other.value<ClickHandlerContext>();
if (const auto window = my.sessionWindow.get()) {
window->session().sponsoredMessages().clicked(my.itemId);
}
return true;
}
rpl::producer<> UiIntegration::forcePopupMenuHideRequests() {
return Core::App().passcodeLockChanges() | rpl::to_empty;
}

View File

@@ -61,9 +61,6 @@ public:
QStringView data,
const std::any &context) override;
Fn<void()> createSpoilerRepaint(const std::any &context) override;
bool allowClickHandlerActivation(
const std::shared_ptr<ClickHandler> &handler,
const ClickContext &context) override;
QString phraseContextCopyText() override;
QString phraseContextCopyEmail() override;

View File

@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
constexpr auto AppName = "Telegram Desktop"_cs;
constexpr auto AppFile = "Telegram"_cs;
constexpr auto AppVersion = 5004003;
constexpr auto AppVersionStr = "5.4.3";
constexpr auto AppVersion = 5005008;
constexpr auto AppVersionStr = "5.5.8";
constexpr auto AppBetaVersion = true;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View File

@@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/click_handler_types.h"
#include "data/data_channel.h"
#include "data/data_document.h"
#include "data/data_file_origin.h"
#include "data/data_media_preload.h"
#include "data/data_photo.h"
#include "data/data_session.h"
#include "data/data_user.h"
@@ -69,16 +71,17 @@ void SponsoredMessages::clearOldRequests() {
}
}
bool SponsoredMessages::append(not_null<History*> history) {
SponsoredMessages::AppendResult SponsoredMessages::append(
not_null<History*> history) {
const auto it = _data.find(history);
if (it == end(_data)) {
return false;
return SponsoredMessages::AppendResult::None;
}
auto &list = it->second;
if (list.showedAll
|| !TooEarlyForRequest(list.received)
|| list.postsBetween) {
return false;
return SponsoredMessages::AppendResult::None;
}
const auto entryIt = ranges::find_if(list.entries, [](const Entry &e) {
@@ -86,19 +89,16 @@ bool SponsoredMessages::append(not_null<History*> history) {
});
if (entryIt == end(list.entries)) {
list.showedAll = true;
return false;
return SponsoredMessages::AppendResult::None;
} else if (entryIt->preload) {
return SponsoredMessages::AppendResult::MediaLoading;
}
// SponsoredMessages::Details can be requested within
// the constructor of HistoryItem, so itemFullId is used as a key.
entryIt->itemFullId = FullMsgId(
history->peer->id,
_session->data().nextLocalMessageId());
entryIt->item.reset(history->addSponsoredMessage(
entryIt->itemFullId.msg,
entryIt->sponsored.from,
entryIt->sponsored.textWithEntities));
return true;
return SponsoredMessages::AppendResult::Appended;
}
void SponsoredMessages::inject(
@@ -221,8 +221,7 @@ void SponsoredMessages::request(not_null<History*> history, Fn<void()> done) {
const auto channel = history->peer->asChannel();
Assert(channel != nullptr);
request.requestId = _session->api().request(
MTPchannels_GetSponsoredMessages(
channel->inputChannel)
MTPchannels_GetSponsoredMessages(channel->inputChannel)
).done([=](const MTPmessages_sponsoredMessages &result) {
parse(history, result);
if (done) {
@@ -270,15 +269,14 @@ void SponsoredMessages::append(
const MTPSponsoredMessage &message) {
const auto &data = message.data();
const auto randomId = data.vrandom_id().v;
auto mediaPhotoId = PhotoId(0);
auto mediaDocumentId = DocumentId(0);
auto mediaPhoto = (PhotoData*)nullptr;
auto mediaDocument = (DocumentData*)nullptr;
{
if (data.vmedia()) {
data.vmedia()->match([&](const MTPDmessageMediaPhoto &media) {
if (const auto tlPhoto = media.vphoto()) {
tlPhoto->match([&](const MTPDphoto &data) {
const auto p = history->owner().processPhoto(data);
mediaPhotoId = p->id;
mediaPhoto = history->owner().processPhoto(data);
}, [](const MTPDphotoEmpty &) {
});
}
@@ -290,7 +288,7 @@ void SponsoredMessages::append(
|| d->isSilentVideo()
|| d->isAnimation()
|| d->isGifv()) {
mediaDocumentId = d->id;
mediaDocument = d;
}
}, [](const MTPDdocumentEmpty &) {
});
@@ -306,8 +304,8 @@ void SponsoredMessages::append(
.photoId = data.vphoto()
? history->session().data().processPhoto(*data.vphoto())->id
: PhotoId(0),
.mediaPhotoId = mediaPhotoId,
.mediaDocumentId = mediaDocumentId,
.mediaPhotoId = (mediaPhoto ? mediaPhoto->id : 0),
.mediaDocumentId = (mediaDocument ? mediaDocument->id : 0),
.backgroundEmojiId = data.vcolor().has_value()
? data.vcolor()->data().vbackground_emoji_id().value_or_empty()
: uint64(0),
@@ -341,7 +339,56 @@ void SponsoredMessages::append(
.sponsorInfo = std::move(sponsorInfo),
.additionalInfo = std::move(additionalInfo),
};
list.entries.push_back({ nullptr, {}, std::move(sharedMessage) });
list.entries.push_back({
.sponsored = std::move(sharedMessage),
});
auto &entry = list.entries.back();
const auto itemId = entry.itemFullId = FullMsgId(
history->peer->id,
_session->data().nextLocalMessageId());
const auto fileOrigin = FileOrigin(); // No way to refresh in ads.
static const auto kFlaggedPreload = ((MediaPreload*)quintptr(0x01));
const auto preloaded = [=] {
const auto i = _data.find(history);
if (i == end(_data)) {
return;
}
auto &entries = i->second.entries;
const auto j = ranges::find(entries, itemId, &Entry::itemFullId);
if (j == end(entries)) {
return;
}
auto &entry = *j;
if (entry.preload.get() == kFlaggedPreload) {
entry.preload.release();
} else {
entry.preload = nullptr;
}
};
auto preload = std::unique_ptr<MediaPreload>();
entry.preload.reset(kFlaggedPreload);
if (mediaPhoto) {
preload = std::make_unique<PhotoPreload>(
mediaPhoto,
fileOrigin,
preloaded);
} else if (mediaDocument && VideoPreload::Can(mediaDocument)) {
preload = std::make_unique<VideoPreload>(
mediaDocument,
fileOrigin,
preloaded);
}
// Preload constructor may have called preloaded(), which zero-ed
// entry.preload, that way we're ready and don't need to save it.
// Otherwise we're preloading and need to save the task.
if (entry.preload.get() == kFlaggedPreload) {
entry.preload.release();
if (preload) {
entry.preload = std::move(preload);
}
}
}
void SponsoredMessages::clearItems(not_null<History*> history) {
@@ -433,7 +480,10 @@ SponsoredMessages::Details SponsoredMessages::lookupDetails(
};
}
void SponsoredMessages::clicked(const FullMsgId &fullId) {
void SponsoredMessages::clicked(
const FullMsgId &fullId,
bool isMedia,
bool isFullscreen) {
const auto entryPtr = find(fullId);
if (!entryPtr) {
return;
@@ -441,7 +491,11 @@ void SponsoredMessages::clicked(const FullMsgId &fullId) {
const auto randomId = entryPtr->sponsored.randomId;
const auto channel = entryPtr->item->history()->peer->asChannel();
Assert(channel != nullptr);
using Flag = MTPchannels_ClickSponsoredMessage::Flag;
_session->api().request(MTPchannels_ClickSponsoredMessage(
MTP_flags(Flag(0)
| (isMedia ? Flag::f_media : Flag(0))
| (isFullscreen ? Flag::f_fullscreen : Flag(0))),
channel->inputChannel,
MTP_bytes(randomId)
)).send();

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