Compare commits

..

479 Commits

Author SHA1 Message Date
AlexeyZavar c86ea4807a feat: emoji pack author 2024-06-05 04:32:56 +03:00
AlexeyZavar b5c769196a fix: channel badge 2024-06-05 03:36:18 +03:00
Nikhil Singh 6027bad788 fix: add telegram string in keywords (#11)
This will make AyuGram easy to search in linux app menu's and other drun utilities like rofi/dmenu
2024-06-04 04:15:58 +03:00
AlexeyZavar 0b1e6bd1de fix: make it build 2024-06-04 04:11:16 +03:00
AlexeyZavar 01b8602437 Merge tag 'v5.1.2' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/boxes/send_files_box.cpp
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/data/data_search_controller.cpp
#	Telegram/SourceFiles/dialogs/dialogs_widget.cpp
#	Telegram/SourceFiles/dialogs/dialogs_widget.h
#	Telegram/SourceFiles/history/view/media/history_view_gif.cpp
#	Telegram/SourceFiles/mainwidget.cpp
#	Telegram/lib_ui
2024-06-04 03:29:15 +03:00
AlexeyZavar cc16922673 feat: copy username for channels too
fix: purge useless
2024-06-04 03:21:44 +03:00
John Preston 379a94db42 Version 5.1.2.
- Several bugs fixed including a couple of crashes.
2024-06-04 00:00:12 +04:00
23rd 4f4d216987 Fixed display of button in channel earn section when balance is low. 2024-06-03 23:00:48 +04:00
23rd 6400875d55 Replaced text drawing in menu from phone handler with Text::String. 2024-06-03 23:00:47 +04:00
John Preston 06d0e78b00 Fix a crash in forwarded sender avatars. 2024-06-03 22:59:14 +04:00
John Preston 9043c18725 Don't drop search on non-empty backspace. 2024-06-03 22:27:15 +04:00
Ilya Fedin 88e742927f File descriptor fixes for XDPOpenWithDialog
- Open it with O_CLOEXEC
- Remove unneseccary std::array complication
- Rely on Gio::UnixFDList to close it
2024-06-03 17:49:16 +04:00
Ilya Fedin a6fcc6d51d Rely on media viewer code to close itself before ShowInFolder 2024-06-03 17:49:16 +04:00
John Preston 23a13ab54e Close chats search when selecting a folder. 2024-06-03 17:13:14 +04:00
John Preston e8a929bdbd Fix bottom info display in media. 2024-06-03 15:03:41 +04:00
John Preston eafc01e02b Fix small photo display in wide enough chat.
Fixes #28004.
2024-06-03 14:14:42 +04:00
John Preston f817504d67 Fix formatting drop on zero cursor position. 2024-06-03 13:52:00 +04:00
John Preston f91eb65239 Fix channel reactions editing. 2024-06-03 13:40:04 +04:00
John Preston e978770fbd Fix crash in theme IV opening. 2024-06-03 12:48:11 +04:00
23rd 9c83b8bac5 Fixed emoji display in reply markup button from bar for pinned messages. 2024-06-02 23:11:09 +03:00
23rd 47ce34e987 Added initial support of vcard from media contacts. 2024-06-02 22:06:49 +03:00
John Preston 1656a9c3e2 Fix bot about title display. 2024-06-02 10:55:13 +04:00
John Preston 47e06cf385 Fix dropping invertCaption on reschedule. 2024-06-02 10:55:13 +04:00
John Preston f61f649a7e Add a power saving setting for effects. 2024-06-02 10:55:13 +04:00
John Preston a7bffe7abd Version 5.1.1: Fix misspelled attribute. 2024-06-01 23:58:31 +04:00
John Preston 51b866293f Version 5.1.1.
- Fix caption display on some media.
- Fix collapsed blockquotes rendering.
- Fully close search in chat by "Cancel" click.
- Allow editing caption placement and spoiler in topics.
- Disable effects on forwarded messages and inline results.
2024-06-01 23:40:20 +04:00
John Preston bd20a3cfe4 Fix filtered premium sticker effects selection. 2024-06-01 23:35:04 +04:00
John Preston 86778aa4d9 Fix cancel search glitch with the new search. 2024-06-01 23:26:02 +04:00
John Preston 12eecec501 Disable effects for inline results sending. 2024-06-01 23:21:48 +04:00
John Preston 26345208a9 Fix caption disappearance on album sending. 2024-06-01 23:02:29 +04:00
John Preston ee680ac1f1 Don't try adding effects to forwarded messages. 2024-06-01 22:49:51 +04:00
John Preston bb79a07262 Move SendMenu additional actions to bottom. 2024-06-01 22:43:19 +04:00
John Preston 70fe649743 Hide media viewer on macOS when showing IV. 2024-06-01 22:31:43 +04:00
John Preston 400f0f8785 Empty line between description and ID. 2024-06-01 22:09:01 +04:00
John Preston eac7bf1c48 Show "View as Messages" preview on forum preview. 2024-06-01 22:02:17 +04:00
John Preston f4abe37dff Display peer IDs with delimeters. 2024-06-01 21:53:41 +04:00
John Preston b7f165a259 Fix albums with wide captions. 2024-06-01 21:53:26 +04:00
John Preston c1b95afd88 Fix media spoiler/caption-above edit in topics/scheduled. 2024-06-01 21:17:09 +04:00
John Preston 36766e7546 Fix collapsed blockquotes in the end of the text. 2024-06-01 21:16:31 +04:00
John Preston 59c016e4ce Fix search input not in the end of the query. 2024-06-01 20:39:31 +04:00
John Preston e9e347fa6c Fix crash in stories privacy handling. 2024-06-01 20:34:16 +04:00
23rd 7aef0b0a83 Fixed frame size of video userpic in short info boxes on Retina. 2024-06-01 16:55:01 +03:00
23rd d9572949f6 Replaced confirmation box for proxy links with generic box. 2024-06-01 16:02:59 +03:00
23rd 233e80d22d Fixed display of confirmation box for proxy links in correspond window. 2024-06-01 16:02:59 +03:00
John Preston 5c83858a50 Remove empty space below video without caption. 2024-06-01 10:58:48 +04:00
John Preston c681569349 Fix info display in video with caption above. 2024-06-01 10:53:00 +04:00
John Preston bb43afdd93 Fix search in chat close by "Cancel" link. 2024-06-01 10:52:48 +04:00
John Preston 3ba1941808 Version 5.1: Fix build on macOS. 2024-05-31 23:03:06 +04:00
John Preston 72d1b43453 Version 5.1.
- Send messages with effects.
- Move photo or video captions above the media.
- Chat preview on chat photo long press or Alt+Click.
2024-05-31 21:30:18 +04:00
John Preston 0c1b487956 Fix dragging of non-leader media. 2024-05-31 21:30:18 +04:00
23rd ba611d0f2d Added initial api support of text phone entity in messages. 2024-05-31 18:58:21 +03:00
23rd 50ce847b31 Fixed display of info in media from chat preview. 2024-05-31 19:52:36 +04:00
23rd dd0d88ccd3 Fixed userpic views in headers of forwarded messages with via bots. 2024-05-31 19:52:36 +04:00
John Preston a1049ec7ce Add touchscreen preview to recent / channels. 2024-05-31 19:52:36 +04:00
John Preston 0fffeac8da Fix drag-n-drop forward of selected album. 2024-05-31 19:52:36 +04:00
John Preston 1f0acae151 Show frequent/recent selected when preview. 2024-05-31 19:52:36 +04:00
John Preston 521c17b76c Show chat previews in suggestions. 2024-05-31 19:52:36 +04:00
John Preston f9f51b4e41 Show preview in Frequent Contacts. 2024-05-31 19:52:32 +04:00
John Preston 4e8895ddd9 Show "View as Messages" preview by Alt+Click. 2024-05-31 19:52:32 +04:00
John Preston ad342a5324 Extract chat preview as a SessionController part. 2024-05-31 19:52:25 +04:00
John Preston 5cfd86b829 Use Ui::Text::String to show topic names.
Fixes #27956.
2024-05-31 19:52:22 +04:00
John Preston 27eb3e45be Allow only t.me links in factchecks. 2024-05-31 19:52:22 +04:00
John Preston 4953246c5d Support touchscreen pinned chats reordering. 2024-05-31 19:52:18 +04:00
John Preston 4df5372dab Support chat preview on touchscreens. 2024-05-31 19:52:12 +04:00
John Preston 40fbd415ef Support collapsible blockquotes in Ui::Text::String. 2024-05-30 21:35:10 +04:00
John Preston 974bf99921 Allow editing spoiler/caption-above in EditCaptionBox. 2024-05-30 21:35:10 +04:00
John Preston 8c0351be4e Allow editing caption above/below media. 2024-05-30 21:35:10 +04:00
John Preston 67f7816088 Allow sending photo/video captions above media. 2024-05-30 21:35:10 +04:00
John Preston 924d80ecba Use message text rendering for media captions. 2024-05-30 21:35:10 +04:00
23rd d219bccf2b Fixed position of via bot header above reply in message view. 2024-05-30 21:35:10 +04:00
23rd 02bd2bca64 Removed display of credits button in settings when user has no credits. 2024-05-30 21:35:10 +04:00
23rd 57ecc2be1d Improved style of list of credits history entries for refunded entry. 2024-05-30 21:35:10 +04:00
23rd d3a01b6235 Improved style of list of credits history entries for entry photo. 2024-05-30 21:35:10 +04:00
23rd 58c060c59d Improved style of box for credits history entries for refunded entry. 2024-05-30 21:35:10 +04:00
23rd cd7507fb23 Respected accessibility of premium for credits purchasing. 2024-05-30 21:35:10 +04:00
23rd 9a5923676a Added posting of payment event to webview bot after credits sending. 2024-05-30 21:35:09 +04:00
John Preston c0f3d263a3 Remove webpage length limit for factcheck. 2024-05-30 21:35:08 +04:00
John Preston 056ba644ed Fix empty search placeholder. 2024-05-30 21:35:08 +04:00
23rd ebaffc333e Added initial api support of refund flag to credits history entries. 2024-05-30 21:35:08 +04:00
23rd be099880d8 Added initial ability to claim refund credits from history entries list. 2024-05-30 21:35:08 +04:00
John Preston 885dcf0b28 Update API scheme on layer 181. 2024-05-30 21:35:08 +04:00
John Preston a0d97f03cb Add factcheck footer support. 2024-05-30 21:35:08 +04:00
23rd c942034ca4 Added link to terms to box of credits history entries. 2024-05-30 21:35:08 +04:00
23rd 0bd780b20f Added fireworks effect on success credit sending. 2024-05-30 21:35:08 +04:00
23rd 7d75c25214 Added box for small balance of credits. 2024-05-30 21:35:08 +04:00
23rd 5defb9fb17 Fixed display of credit spending. 2024-05-30 21:35:08 +04:00
23rd 0549c8f037 Moved out list of top-up options to single place. 2024-05-30 21:35:08 +04:00
23rd 3c246e1e92 Split functions for credits settings. 2024-05-30 21:35:08 +04:00
23rd 58da617e3f Added description and optional photo to credits receipts. 2024-05-30 21:35:08 +04:00
23rd 1edf0ed70b Moved out widget of photo for credits history entries to single place. 2024-05-30 21:35:08 +04:00
23rd c27c567225 Added initial support for non-panel credits receipts. 2024-05-30 21:35:08 +04:00
23rd 93eff78cd6 Replaced all credits currency name at least with simple star. 2024-05-30 21:35:08 +04:00
23rd a2a27e115c Moved out box for credits history entries to single place. 2024-05-30 21:35:08 +04:00
23rd e9fb580ba4 Moved out credits currency to single place. 2024-05-30 21:35:08 +04:00
23rd d73313479b Partly reverted "Processed payments form with API scheme on layer 181.". 2024-05-30 21:35:08 +04:00
23rd e4e343b871 Removed unused Ui::IsCreditsInvoice. 2024-05-30 21:35:08 +04:00
23rd dda6b92bec Added initial ability to process non-panel payment forms. 2024-05-30 21:35:07 +04:00
23rd 3dd894ad30 Improved SendCreditsBox for data from credits payment form. 2024-05-30 21:35:07 +04:00
23rd f08ff92470 Added initial ability to provide data for non-panel payment forms. 2024-05-30 21:35:07 +04:00
23rd 923aaec085 Returned media to messages with credits invoice. 2024-05-30 21:35:07 +04:00
John Preston 1d3110228d Fix phrase in factcheck toast. 2024-05-30 21:35:07 +04:00
23rd 7194781bb8 Added api support for premium bot peer type for credits history entries. 2024-05-30 21:35:07 +04:00
John Preston 97a5e0c6ea Support limited formatting input in factcheck. 2024-05-30 21:35:07 +04:00
John Preston a3ef36f9f7 Fix build on Windows. 2024-05-30 21:35:07 +04:00
John Preston d13bf19b79 Show length limit when editing a factcheck. 2024-05-30 21:35:07 +04:00
John Preston 493f0450b4 Implement factcheck edition. 2024-05-30 21:35:07 +04:00
John Preston 74861a334d Show expand/collapse icon in factcheck. 2024-05-30 21:35:07 +04:00
John Preston a87a221f26 Force red for factcheck. 2024-05-30 21:35:07 +04:00
John Preston 923a9ec6a8 Show toggle-able factcheck footer. 2024-05-30 21:35:07 +04:00
John Preston b299881bf8 Track factcheck text and create media. 2024-05-30 21:35:07 +04:00
John Preston 5ee2bca616 Update API scheme on layer 181. 2024-05-30 21:35:07 +04:00
23rd d1e914fb30 Added initial implementation of box for credits history entries. 2024-05-30 21:35:07 +04:00
23rd 43cb315f47 Replaced PeerId with BareId in credits history entries. 2024-05-30 21:35:07 +04:00
23rd dcc52a7333 Moved out painting of userpic for credits entries to single place. 2024-05-30 21:35:07 +04:00
23rd 84cde1354d Slightly improved invoice view in messages for credits. 2024-05-30 21:35:07 +04:00
23rd 3d81414c71 Added initial implementation of box for sending credits. 2024-05-30 21:35:07 +04:00
23rd 69c48e2b5b Moved out credits balance widget to single place. 2024-05-30 21:35:07 +04:00
23rd 5ca9b74142 Fixed effect for successful payments in credits settings. 2024-05-30 21:35:07 +04:00
23rd e11755af46 Added credits balance to main session. 2024-05-30 21:35:07 +04:00
23rd 174fb62c32 Fixed purchases of credits. 2024-05-30 21:35:07 +04:00
23rd 0e30e306ff Added second type of stars to animation of mini stars. 2024-05-30 21:35:07 +04:00
23rd 5e29f382cd Fixed build with Xcode. 2024-05-30 21:35:07 +04:00
John Preston 8eb24f620d Update API scheme on layer 181. 2024-05-30 21:35:07 +04:00
John Preston 5adde6c93a Fix build on Windows. 2024-05-30 21:35:07 +04:00
23rd 42d6d0d58a Added tooltip to balance label in credits settings for high values. 2024-05-30 21:35:07 +04:00
23rd 6336df2bd6 Slightly improved code style for decimal counts. 2024-05-30 21:35:07 +04:00
23rd 030d35ea7e Added initial implementation of balance in credits settings. 2024-05-30 21:35:07 +04:00
23rd d81c3554cc Added multiple icons to credits topup options. 2024-05-30 21:35:07 +04:00
23rd ca37ffa086 Added list of credit history entries to credits settings. 2024-05-30 21:35:07 +04:00
23rd 154fe63b43 Implemented list of credit history entries. 2024-05-30 21:35:06 +04:00
23rd 65384d54f1 Added random debug data to credits history. 2024-05-30 21:35:06 +04:00
23rd 2bf8cb84d0 Added api support of credits status and credits history. 2024-05-30 21:35:06 +04:00
23rd f0a82de784 Fixed editing of last message with uploading media. 2024-05-30 21:35:06 +04:00
23rd 1a393ddebb Added star icons with gradient to main settings for premium buttons. 2024-05-30 21:35:06 +04:00
23rd 9b11b95c5b Added api support of invoice payments for credits. 2024-05-30 21:35:06 +04:00
23rd d0bfee6963 Added initial list for topup options in settings section for credits. 2024-05-30 21:35:06 +04:00
23rd f1636de572 Added initial api support for credits topup options. 2024-05-30 21:35:06 +04:00
23rd b5eb195f43 Added initial dummy settings section for credits. 2024-05-30 21:35:06 +04:00
23rd 4a0bffe618 Added ability to provide custom gradient to star in premium top bar. 2024-05-30 21:35:06 +04:00
23rd 53d97b4146 Added ability to provide custom gradient to colored premium stars. 2024-05-30 21:35:06 +04:00
23rd 2a224c839e Added initial phrases for settings section for credits. 2024-05-30 21:35:06 +04:00
23rd bc7aa91fbb Removed redundant constructor from Ui::Premium::TopBar. 2024-05-30 21:35:06 +04:00
23rd ac2f35f12b Processed payments form with API scheme on layer 181. 2024-05-30 21:35:06 +04:00
John Preston 39e03c3ca7 Update API scheme to layer181. 2024-05-30 21:35:06 +04:00
John Preston 1ce49df123 Fix saved / replies userpics in chats search. 2024-05-30 21:35:06 +04:00
John Preston 1865fd382c Show loading placeholders in chats list. 2024-05-30 21:35:06 +04:00
John Preston e00c6ecfb8 Show empty / placeholder in chats search. 2024-05-30 21:35:06 +04:00
John Preston 279db771cf Support dynamic search tabs with emoji. 2024-05-30 21:35:06 +04:00
John Preston 7b7438cd7b Make chats list tabs closer to each other. 2024-05-30 21:35:06 +04:00
John Preston 42d53e5543 Fix saved messages tags search. 2024-05-30 21:35:06 +04:00
John Preston fce520c9c0 Clear saved messages tags on cancel search. 2024-05-30 21:35:06 +04:00
John Preston b21bcb86cc Fix search from user in forums. 2024-05-30 21:35:06 +04:00
John Preston 7d61ab9412 Improve forum search support. 2024-05-30 21:35:06 +04:00
John Preston 701bf0d553 Fix searching with "from:" prefix. 2024-05-30 21:35:06 +04:00
John Preston 583bcca6a9 Fix forum search open by Ctrl+F. 2024-05-30 21:35:06 +04:00
John Preston 6a8edefc87 Fix some bugs in new chats search. 2024-05-30 21:35:06 +04:00
John Preston dd5643ac67 Start chats search rewrite. 2024-05-30 21:35:06 +04:00
John Preston 787cf7853e Implement simple chats search bar. 2024-05-30 21:35:06 +04:00
John Preston 5bfbae3afc Update API scheme on layer 180. 2024-05-30 21:35:06 +04:00
John Preston 363b700f1f Fix chat preview and new emoji interactions. 2024-05-30 21:35:05 +04:00
John Preston cde70b9807 Play effects in a separate layer over MainWidget. 2024-05-30 21:35:05 +04:00
John Preston f7ab8a2174 Fix Chat / Effect previews in custom themes. 2024-05-30 21:35:05 +04:00
John Preston a011a7c316 Fix sending scheduled effects. 2024-05-30 21:35:05 +04:00
John Preston 487fa9728a Fade in/out effect preview. 2024-05-30 21:35:05 +04:00
John Preston 8a58ded582 Show effect loading animation. 2024-05-30 21:35:05 +04:00
John Preston ec5d8b7373 More robust effect icon loading. 2024-05-30 21:35:05 +04:00
John Preston 732b67ca04 Implement effects paywalls. 2024-05-30 21:35:05 +04:00
John Preston d102d256a9 Implement effects search. 2024-05-30 21:35:05 +04:00
John Preston bbb3a51b74 Fix effect selector for !_useTransparency case. 2024-05-30 21:35:05 +04:00
John Preston d0d1ef9e66 Fix effect panel jump on expand. 2024-05-30 21:35:05 +04:00
John Preston b01244fc42 Show correct sticker effects title. 2024-05-30 21:35:05 +04:00
John Preston b92a05011f Show sticker effects in a StickerListWidget. 2024-05-30 21:35:05 +04:00
John Preston 5fb7992b04 Improve effect initial auto-play. 2024-05-30 21:35:05 +04:00
John Preston f371cd1af2 Use nice fake message for effect preview. 2024-05-30 21:35:05 +04:00
John Preston 144109db05 Show effect preview before sending. 2024-05-30 21:35:05 +04:00
John Preston e120ae6ae6 Pass effect to API for sending. 2024-05-30 21:35:05 +04:00
John Preston d1106e5ae6 Check effects availability in all SendMenu-s. 2024-05-30 21:35:05 +04:00
John Preston 396ba9a984 Initial code of attaching effect selector. 2024-05-30 21:35:05 +04:00
John Preston 92133e7f50 Show effect animation with correct geometry. 2024-05-30 21:35:05 +04:00
John Preston a19e71324b Implement basic effect animation. 2024-05-30 21:35:05 +04:00
John Preston f762634036 Support effects API, show icon in info. 2024-05-30 21:35:05 +04:00
John Preston ee4f83ffde Disable bottom-info reactions view. 2024-05-30 21:35:05 +04:00
John Preston f8188f360a Update API scheme to layer 180. 2024-05-30 21:35:05 +04:00
John Preston 2bbc7406da Beta version 5.0.6.
- Fix chat preview with non-default themes.
- Fix chat preview crash when scrolling up.
- Jump to chat from preview only by Double-Click.
- Show chat preview with Force Touch on macOS.
2024-05-30 19:06:51 +04:00
John Preston a9dd9aeb90 Use InnoSetup SignTool for setup signing.
Fixes #27583.
2024-05-30 19:03:12 +04:00
John Preston aa4156d1e7 Ignore shortcuts when preview is shown. 2024-05-30 19:03:08 +04:00
John Preston 4f5594c8cc ChatNext jumps to first chat if no chat opened.
Fixes #27963.
2024-05-30 19:03:04 +04:00
John Preston 0527e9a0f7 Fix adding bot as admin to channel. 2024-05-30 17:02:28 +04:00
John Preston 28cbb02b20 Jump to chat only by Double-Click on preview. 2024-05-30 17:02:26 +04:00
John Preston 7d636820ac Show last updated topic preview on Alt+Click. 2024-05-30 17:02:23 +04:00
John Preston e2b78b673b Fix unintentional search focus. 2024-05-30 17:02:19 +04:00
John Preston a9a0fe7cf5 Fix RTL chat names in preview. 2024-05-30 17:02:13 +04:00
John Preston 2b9e7a6b25 Show preview on Force-Click on macOS. 2024-05-30 17:02:09 +04:00
John Preston d6e827e982 Fix loading of chat preview messages. 2024-05-30 17:02:02 +04:00
John Preston d2e6003521 Ignore right click on preview. 2024-05-30 17:01:59 +04:00
John Preston 465fc42718 Fix chat preview in non-default themes. 2024-05-29 09:43:40 +04:00
John Preston 0dd6ff9d9b Beta version 5.0.5.
- Long press on chat userpic to show quick preview.
- Alt+Click on chat to show quick preview.
- Show author userpics in forwarded messages.
2024-05-29 00:03:45 +04:00
23rd 8a6b1677f4 Added userpic views to headers of forwarded messages. 2024-05-28 21:42:00 +04:00
John Preston 470b3a2cbd Fix preview showing on fast userpic click. 2024-05-28 21:42:00 +04:00
John Preston a60783eae3 Implement preview top and bottom. 2024-05-28 21:42:00 +04:00
John Preston de73d8766c Open chat on exact clicked message from preview. 2024-05-28 21:42:00 +04:00
John Preston cd7cfcdf2f Show chat preview on Alt+Click. 2024-05-28 21:42:00 +04:00
John Preston aee62c7591 Fix migrated history in chat preview. 2024-05-28 21:42:00 +04:00
John Preston 0f524ac67d Don't stick to bottom while loading down. 2024-05-28 21:42:00 +04:00
John Preston f223ae7eee Implement chats preview, show from unread. 2024-05-28 21:42:00 +04:00
John Preston 68df8448a2 Use arc_angles.h from lib_ui. 2024-05-28 21:42:00 +04:00
John Preston da31fef1ae Show long-press preview of topics. 2024-05-28 21:41:59 +04:00
John Preston 4427ae4306 Empty preview widget on long userpic press. 2024-05-28 21:41:59 +04:00
John Preston ef2aa05197 Allow HistoryView::ListWidget without SessionController. 2024-05-28 21:41:59 +04:00
John Preston e5132e3fe8 Version 5.0.4
- Fix reply to last message by Ctrl+Up in topics.
- Some other bug fixes.
2024-05-28 20:32:48 +04:00
23rd 3b6870396c Added ability to hide every sponsored message to premium users. 2024-05-28 20:30:40 +04:00
23rd f6b849e4f7 Added ability to add proxy from clipboard. 2024-05-28 20:30:40 +04:00
23rd 48e3802565 Improved labels for channel and group types with restricted content. 2024-05-28 20:30:40 +04:00
23rd 26ba7e57ce Fixed color of radial animation in audio files from shared media. 2024-05-28 20:30:40 +04:00
23rd 2605e754ff Added back button to cloud password step in intro. 2024-05-28 20:30:40 +04:00
23rd 9e85b1aa23 Fixed fake ability to hide webpage media with spoiler. 2024-05-28 20:30:40 +04:00
Ilya Fedin 88cd886ec8 Update lib_webview 2024-05-28 17:50:39 +04:00
John Preston adc536b81d Fix Ctrl+Up reply in topics / comments. 2024-05-28 15:01:01 +04:00
John Preston 275327c789 Version 5.0.3.
- Ctrl+Click on Reply in menu to Reply in another chat.
- Allow Zero-Width-Space character in text rendering.
- Fix creating custom links in the message field.
- Fix jump to the topic with last unread message.
- Fix newline entering via Shift+Enter on Linux.
- Fix forum search open by Ctrl+F.
2024-05-28 11:53:51 +04:00
John Preston 72471c74d0 Limit symbols that allow diacritics after them. 2024-05-28 11:45:21 +04:00
John Preston b9f63f80f1 Reply-in-another-chat by Ctrl+Click on Reply. 2024-05-28 10:59:46 +04:00
John Preston 32cd2120ac Allow zero width space in the middle of text.
Fixes #6959.
2024-05-28 10:54:20 +04:00
John Preston 7db9abf725 Fix forum search open by Ctrl+F. 2024-05-28 10:04:57 +04:00
John Preston f09a939a7c Improve fix for markup. 2024-05-27 22:24:19 +04:00
John Preston f1c1c900bf Fix newline regression on Linux. 2024-05-27 22:08:20 +04:00
John Preston a43143d01c Separate ForceDisable from LastCheckCrashed. 2024-05-27 17:54:23 +04:00
John Preston 7357b40ba1 Fix build with updated lib_ui. 2024-05-27 17:54:23 +04:00
Ilya Fedin ad6e34f3a4 Update lib_webview 2024-05-27 14:00:26 +04:00
John Preston daf30dcab8 Fix jump to last topic in case of unread topic click. 2024-05-27 13:33:25 +04:00
Ilya Fedin 0033ad749f Update lib_webview 2024-05-27 08:06:25 +04:00
Ilya Fedin 62c249015d Update lib_webview 2024-05-26 14:20:43 +04:00
AlexeyZavar f54c82bcb3 feat: round context menu a bit 2024-05-25 04:33:05 +03:00
AlexeyZavar 57b2c69ce6 Merge tag 'v5.0.2' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/lib_ui
#	snap/snapcraft.yaml
2024-05-25 02:26:39 +03:00
John Preston 31fcca245f Version 5.0.2: Fix IME-to-search on macOS. 2024-05-24 20:54:10 +04:00
John Preston f4864cddc9 Fix possible crash in Settings of crashed web-app.
Fixes #27943.
2024-05-24 20:54:10 +04:00
John Preston 36db1105a2 Fix build with Xcode. 2024-05-24 16:09:01 +04:00
John Preston 364f62660c Version 5.0.2: Update the version number. 2024-05-24 15:26:18 +04:00
John Preston b67a1bca49 Version 5.0.2.
- Toggle chats search focus by Tab key.
- Unfocus empty search by Backspace key.
- Add a spoiler to already sent media when editing.
- Forward by drag-n-drop to frequent contacts / recent searches.
- Allow wide chats list in empty window
with narrow list when a chat is opened.
- Improve custom font support in the input fields.
- Fix input method typing from unfocused search.
- Fix possible media reordering on batch send.
- Fix crash in group emoji set saving.
- Fix possible hang on quit on macOS.
2024-05-24 15:13:04 +04:00
John Preston 000911546b Fix usernames drop on min user being received. 2024-05-24 14:50:00 +04:00
John Preston e26b8e7ebc Fix passcode lock glitch with new search. 2024-05-24 14:14:29 +04:00
John Preston f03935ad9a Kill hang processes in case of app quitting. 2024-05-24 14:08:14 +04:00
John Preston d91b75b8f8 Allow wide chats in empty window. 2024-05-24 12:55:48 +04:00
John Preston 4d4cf472c8 Fix crash in group emoji set saving. 2024-05-24 12:55:48 +04:00
John Preston 685c7a865e Use 64 iterations (like OpenSSL 3 for 2048 primes). 2024-05-24 12:55:48 +04:00
John Preston 0551550e61 Don't always open last topic in forums. 2024-05-24 12:55:48 +04:00
John Preston c3fab28e1c Improve scroll style for limited reaction selector. 2024-05-24 12:55:48 +04:00
John Preston 74db2167f9 Allow copy custom emoji from panel. 2024-05-24 12:55:48 +04:00
John Preston cedd8fc546 Fix incorrect replace media button show in reply. 2024-05-24 12:55:48 +04:00
John Preston db486e957c Fix group/channel Appearance button style. 2024-05-24 12:55:48 +04:00
John Preston 1c6f45d8d3 Fix drag-n-drop to frequent/recent contacts. 2024-05-24 12:55:48 +04:00
John Preston ba8bb2d50f Add .vscode to .gitignore. 2024-05-24 12:55:48 +04:00
John Preston ec6d6a78cf Tab toggles search focus, Backspace doesn't focus. 2024-05-24 12:55:48 +04:00
John Preston f10f3c08de Attempt to fix sending messages to broken topics. 2024-05-24 12:55:48 +04:00
John Preston 39c1da6642 Attempt to fix jump to unread in some cases. 2024-05-24 12:55:48 +04:00
John Preston 84ec2a5f74 Possibly fix wrong requests order. 2024-05-22 21:21:03 +04:00
Ilya Fedin 5e3e9ba824 Ensure Qt doesn't prevent quit due to ignored widget close events 2024-05-22 16:47:08 +04:00
Ilya Fedin 198528f79f Remove code needed for a removed patch 2024-05-21 14:20:43 +04:00
Ilya Fedin 8a5ad581b8 Update Qt to 6.7.1 on Linux 2024-05-21 14:20:43 +04:00
Ilya Fedin 7dbf8ca1f4 Remove unneeded Qt::WA_InputMethodEnabled
The widget already had it
2024-05-21 14:10:47 +04:00
dependabot[bot] df808df8d3 Bump actions/upload-artifact from 2 to 4
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-21 09:16:03 +04:00
Ilya Fedin 4fddaef112 Update lib_webview 2024-05-20 14:25:23 +04:00
John Preston 2bdc204c47 Fix geometry applying in webview windows. 2024-05-20 14:25:23 +04:00
Ilya Fedin 6734f99ba8 Update lib_ui & patches on Linux 2024-05-19 20:30:13 +04:00
Ilya Fedin af4e0178d0 Ensure window flags are set before calling SeparatePanel::setInnerSize
Setting window flags may lead to native window being re-created
2024-05-19 20:30:13 +04:00
Ilya Fedin 65b62485be Forward input method event from Dialogs::Widget to search field 2024-05-19 11:47:16 +04:00
Ilya Fedin 98b58c1168 Add missing binds for OpenGL shaders and buffers 2024-05-19 09:55:34 +04:00
Ilya Fedin ad13048cdc Update submodules 2024-05-16 22:20:08 +04:00
Ilya Fedin a753c1515b Remove unneeded wayland-client dependency from telegram part in snap 2024-05-16 22:20:08 +04:00
Ilya Fedin bd48e2fff2 Fix more package names in snap 2024-05-16 22:20:08 +04:00
John Preston 88ad1be4c3 Try to fix custom fonts in the input field. 2024-05-14 19:36:52 +04:00
John Preston 1f31d8032f Bring chosen font to the top of the box. 2024-05-14 19:36:52 +04:00
John Preston b5f5aed119 Fix search focus in a hidden window on launch.
Fixes #27853.
2024-05-14 19:36:52 +04:00
John Preston 213326a212 Update submodules. 2024-05-14 19:36:52 +04:00
23rd 264e35a6a8 Fixed rare crash in photo editor when editing media in message. 2024-05-14 17:19:39 +03:00
23rd 76137ca1cf Fixed link to premium section in box about sponsored messages. 2024-05-14 17:19:39 +03:00
23rd e4323ecd26 Slightly improved code style in processing of api text entities. 2024-05-14 17:19:39 +03:00
23rd b406e2b99b Fixed sender name for voices in overview layout when sender is hidden. 2024-05-14 17:19:39 +03:00
23rd c1c49e8ddc Added captions to voice messages in overview layout. 2024-05-14 17:19:39 +03:00
23rd 41e414af37 Removed transcribe buttons from scheduled messages. 2024-05-14 17:19:39 +03:00
23rd 2afb69e787 Fixed text state of reply bubble for messages with unwrapped media. 2024-05-14 17:19:39 +03:00
23rd 3e7d4af4a0 Fixed reply bubble width for short quotes. 2024-05-14 17:19:39 +03:00
23rd bc11c66777 Added ability to hide single sponsored message to premium users. 2024-05-14 17:19:39 +03:00
23rd 7a95b38d3c Fixed refreshing of file reference in api media spoiler editing module. 2024-05-14 17:19:39 +03:00
23rd 334fd4e951 Added ability to edit media with spoiled one without resending. 2024-05-14 17:19:39 +03:00
GoodDok 923e3ee808 Fix 25202: surrounding $PWD with double quotes
Added double quotes to work correctly with spaces in current directory's name
2024-05-14 14:43:38 +04:00
Robert-André Mauchin 3358673ba4 Add compatibility with FFMPEG 7.0
avio: Constify data pointees of write callbacks

avutil: remove deprecated FF_API_PKT_DURATION

Ref: https://github.com/FFmpeg/FFmpeg/commit/2a68d945cd74265bb71c3d38b7a2e7f7d7e87be5
     https://github.com/FFmpeg/FFmpeg/commit/02aea61d69d8f81bc285e2131bf25f96a3e27feb
     https://github.com/FFmpeg/FFmpeg/commit/b8fef7e9c520b3923b32813b6a82c154c74402dc
2024-05-14 14:39:29 +04:00
dependabot[bot] d28b9f10b4 Bump jlumbroso/free-disk-space from 1.3.0 to 1.3.1
Bumps [jlumbroso/free-disk-space](https://github.com/jlumbroso/free-disk-space) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/jlumbroso/free-disk-space/releases)
- [Commits](https://github.com/jlumbroso/free-disk-space/compare/f68fdb76e2ea636224182cfb7377ff9a1708f9b8...54081f138730dfa15788a46383842cd2f914a1be)

---
updated-dependencies:
- dependency-name: jlumbroso/free-disk-space
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-14 14:38:48 +04:00
Ilya Fedin 6ebbca58e8 Track major version for official GitHub helpers in actions 2024-05-14 09:54:25 +04:00
Ilya Fedin 15697f4f2b Fix libpng package name in snap 2024-05-08 12:10:37 +04:00
John Preston 2cb0651b04 Redirect IME to search on Windows. 2024-05-07 22:17:34 +04:00
John Preston 1f3a3ec04b Don't focus search when forum is opened. 2024-05-07 22:17:34 +04:00
John Preston c1a0172822 De-focus empty search by backspace. 2024-05-07 22:17:33 +04:00
GkvJwa 593e76479c Use jom build openssl on windows 2024-05-07 09:52:32 +04:00
dependabot[bot] 5d622b906e Bump ilammy/msvc-dev-cmd from 1.12.0 to 1.13.0
Bumps [ilammy/msvc-dev-cmd](https://github.com/ilammy/msvc-dev-cmd) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/ilammy/msvc-dev-cmd/releases)
- [Commits](https://github.com/ilammy/msvc-dev-cmd/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: ilammy/msvc-dev-cmd
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-07 09:02:31 +04:00
dependabot[bot] 7e253314ec Bump jinja2 from 3.1.3 to 3.1.4 in /Telegram/build/docker/centos_env
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.3 to 3.1.4.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.3...3.1.4)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 23:29:00 +04:00
dependabot[bot] 78a05768d8 Bump dessant/lock-threads from 3 to 5
Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 3 to 5.
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md)
- [Commits](https://github.com/dessant/lock-threads/compare/v3...v5)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 23:28:48 +04:00
dependabot[bot] ddf6514a90 Bump actions/stale from 5 to 9
Bumps [actions/stale](https://github.com/actions/stale) from 5 to 9.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v5...v9)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 20:40:31 +04:00
dependabot[bot] 3847b97f80 Bump actions/cache from 3.0.11 to 4.0.2
Bumps [actions/cache](https://github.com/actions/cache) from 3.0.11 to 4.0.2.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3.0.11...v4.0.2)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 20:40:18 +04:00
dependabot[bot] 046bc03037 Bump actions/checkout from 3.1.0 to 4.1.4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 4.1.4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3.1.0...v4.1.4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 20:40:02 +04:00
Ilya Fedin 7ff5f81b88 Try automatic actions update 2024-05-06 09:46:18 +04:00
AlexeyZavar b6de66611c feat: round context menu a bit 2024-05-05 18:28:10 +03:00
AlexeyZavar 166020723f chore: remove application font setting 2024-05-05 16:56:04 +03:00
AlexeyZavar 0bec9f742b fix: make it build 2024-05-05 16:55:09 +03:00
AlexeyZavar eeb5e5a206 Merge tag 'v5.0.1' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/info/profile/info_profile_actions.cpp
#	Telegram/lib_ui
#	snap/snapcraft.yaml
2024-05-04 21:49:27 +03:00
John Preston fb444e7dd4 Version 5.0.1.
- Fix several crashes in new interfaces.
- Fix monospace font size.
- Fix possible problem with underline font size.
2024-05-04 19:08:30 +04:00
23rd c4f0db5bc5 Fixed possible crash on slow resolving message from personal channel. 2024-05-04 18:13:30 +04:00
23rd a866ba8cdd Fixed crash on restricting users from moderation box. 2024-05-04 18:13:28 +04:00
John Preston 129d356909 Fix scrolling expanded frequent contacts. 2024-05-04 18:13:04 +04:00
Ilya Fedin 7289292f02 Update lib_ui & patches on Linux 2024-05-04 14:05:09 +04:00
Ilya Fedin 638e88ec79 Revert "Use latest mesa in snap"
This reverts commit b246328dcf.
2024-05-04 14:05:09 +04:00
John Preston 19ead551d9 Fix a typo bug in replies section scrolling. 2024-05-03 21:04:06 +04:00
John Preston fccaa587e1 Fix adjustment of size for modified fonts. 2024-05-03 21:04:06 +04:00
23rd 1709fcd0df Guarded personal channel info from possible crash on deleting message. 2024-05-03 21:04:06 +04:00
23rd de1f222bac Fixed rescheduling of selected and grouped scheduled messages. 2024-05-03 21:04:06 +04:00
Ilya Fedin 5e1f0e9f7f Move waiting for answer action 30 minutes later than lock threads 2024-05-03 19:59:24 +04:00
Alan Pope e3a14d432b Be consistent with libgtk-3-0t64
The reason it worked without explicitly updating this one is because the deb of libgtk-3-0t64 has a 'replaces' line for libgtk-3-0 - which nullifies this entry, as both were specified. But, you're right, looks better to have the right package in there.
2024-05-03 19:59:07 +04:00
Alan Pope 2b013c108f Fixes for unable to find gtk-query-immodules-3.0
The package has been updated for 2038 t64 update. This fixes that. 

Successfully build telegram 5.0.0 in arm64 after the fixes in this PR.
2024-05-03 19:59:07 +04:00
Alan Pope 0194687181 fix: Incorrect package name
Noble has libvpx9, not vpx8.

https://packages.ubuntu.com/search?keywords=libvpx9
2024-05-03 19:59:07 +04:00
John Preston bb47f4659d Don't adjust monospace font size. 2024-05-02 19:36:59 +04:00
John Preston 2b580d29ae Add .qoi to list of image extensions. 2024-05-02 17:17:40 +04:00
John Preston b7e52119bc Add .jxl to the list of image extensions. 2024-05-02 16:35:29 +04:00
John Preston fd633ecb49 Version 5.0.
- Choose custom font family in Settings > Chat settings > Font family.
- Show "Frequent contacts" when you focus the search field.
- Show "Recent chats" when you focus the search field.
- Show "Channels" list and similar channels.
- Premium users can use animated emoji in polls.
- Group admins can mass-moderate many messages.
- Fix frequent crashes on some Linux systems.
2024-05-02 14:11:20 +04:00
John Preston 9c77346f36 Fix build with Xcode and GCC. 2024-05-02 14:11:20 +04:00
John Preston 641e74763f Revert non-production-ready prepare.py changes.
Accidentally commited in b9b7d9e337.
2024-05-02 12:17:57 +04:00
John Preston 2e71427427 Improve font size edge cases. 2024-05-02 12:05:46 +04:00
John Preston 95ec0633ed Use custom-adjusted font metrics for custom fonts.
Fixes #27814.
2024-05-02 11:33:47 +04:00
23rd 14e8b8fb91 Fixed spam reporting in moderation box. 2024-05-02 04:09:25 +03:00
23rd d40951f068 Added ability to moderate non-users to moderation box. 2024-05-02 04:09:25 +03:00
23rd ab85d18cc8 Added support of personal channel with message. 2024-05-02 04:09:25 +03:00
23rd 6becaaa953 Slightly improved view style of giveaway results in dialogs list. 2024-05-02 04:09:25 +03:00
23rd 26e8c29f40 Moved formatting of dialog last date to td_ui. 2024-05-02 04:09:25 +03:00
John Preston 47800ee02d Improve font size selection a bit. 2024-05-01 19:09:54 +04:00
John Preston 12a24dd473 Fix possible crash in common groups list.
Currently Data::Session::processChat() may change adminRights(),
that may change Data::CanSendAnyOf(peer, ...), that may lead to
Window::SessionController::updateThirdColumnToCurrentChat() call,
that destroys current third column to replace it with another one.

If common groups list was opened in the third column this will crash.

Fixes #27640.
2024-05-01 17:52:40 +04:00
23rd ad6321d3ae Fixed possible crash in moderate box. 2024-05-01 14:10:37 +03:00
John Preston 7e071c770f Fix possible crash with custom wallpapered peers. 2024-05-01 14:38:06 +04:00
John Preston a62d1dfa63 Focus chats search by Ctrl[Cmd]+F. 2024-05-01 14:38:05 +04:00
John Preston b3eb1dbc14 Revert "Toggle search focus by escape."
This reverts commit 72d5a9b3e0.
2024-05-01 14:38:05 +04:00
Ilya Fedin 3170a45158 Increase snapcraft verbosity 2024-05-01 14:06:23 +04:00
John Preston 32483fa13b Just focus the search field on Space. 2024-05-01 12:57:47 +04:00
John Preston 9166a1c3a6 Update Linux Qt patches. Hope fixes crashes. 2024-05-01 12:57:07 +04:00
GitHub Action 6fa0afff37 Update User-Agent for DNS to Chrome 124.0.0.0. 2024-05-01 12:47:51 +04:00
Ilya Fedin bc649af941 Schedule no-response action runs at different times
To avoid rate limits
2024-05-01 12:47:42 +04:00
John Preston 16ce5ef046 Greeting category first in ChatIntro setup. 2024-05-01 12:47:20 +04:00
John Preston bb6fd4bc4d Update scheme, new sticker categories. 2024-05-01 12:47:20 +04:00
John Preston 63e1731d7c Fix premium preview bullet-dots.
Regression was introduced in 88751896af.
2024-05-01 12:47:20 +04:00
John Preston b9b7d9e337 Implement live location view. 2024-05-01 12:47:20 +04:00
23rd ef8c07e6eb Added ability to translate selected text in profile section. 2024-04-30 17:35:34 +03:00
23rd 20a13663a6 Slightly improved style of rpl text mapping. 2024-04-30 17:35:04 +03:00
23rd 2f0aa6ef05 Removed state sending of low level of battery to call participant. 2024-04-30 16:49:17 +03:00
23rd 62bd1354dc Replaced box for leaving or deleting chat with generic box. 2024-04-28 20:14:26 +03:00
23rd be255f1d09 Added to moderate box number of all messages that will be deleted. 2024-04-28 20:14:26 +03:00
23rd b8b02b2285 Replaced list of history items for sending now with sorted by date. 2024-04-28 13:33:04 +03:00
23rd e0db0642bd Fixed crash when deleting message from non-user. 2024-04-27 16:39:13 +03:00
23rd e81465a54e Added Enter shortcut to moderation box for confirmation. 2024-04-27 13:31:00 +03:00
23rd 6e67cfc7be Fixed possible crash in moderation box. 2024-04-27 12:59:36 +03:00
John Preston c0db5ee98a Beta version 4.16.10: Fix GCC build. 2024-04-26 23:41:28 +04:00
John Preston 372b3da09c Beta version 4.16.10.
- Group admins can mass-moderate many messages.
- Premium users can use animated emoji in polls.
- Revert the default "Open Sans" font to 1.10.
- Several crash fixes and small improvements.
2024-04-26 20:55:06 +04:00
John Preston 79532954dc Allow a bit more font size adjusting. 2024-04-26 20:18:30 +04:00
23rd aff2be605e Removed item for poll creation from menu when it is impossible. 2024-04-26 19:15:03 +03:00
John Preston 363c191a6e Skip media bottom skip in IV. 2024-04-26 20:12:30 +04:00
John Preston 2949cdab61 Don't request IV two times in a row. 2024-04-26 20:12:29 +04:00
John Preston 7addcf2d25 Add IV footer. 2024-04-26 20:12:29 +04:00
John Preston a272807a99 Remove "Create poll" button in Replies chat.
Fixes #27817.
2024-04-26 20:12:29 +04:00
23rd c803603de4 Added ability to insert custom emoji to polls. 2024-04-26 20:12:29 +04:00
23rd e6c22ec1ca Added api support for custom emoji in polls. 2024-04-26 20:12:29 +04:00
John Preston b3ae843f0e Update API scheme to layer 179. 2024-04-26 20:12:29 +04:00
John Preston 12a78c1f45 Allow pasting text to the unfocused search. 2024-04-26 20:12:29 +04:00
23rd 612b81ee87 Fixed allowed reactions for channel posts in linked chats. 2024-04-26 20:12:29 +04:00
23rd e5b91d2f3d Added entry points for moderation box. 2024-04-26 20:12:29 +04:00
23rd 82293c98eb Added arrow icon to divider link in moderation box. 2024-04-26 20:12:29 +04:00
23rd 629da68cfc Added api support to moderation box. 2024-04-26 20:12:29 +04:00
23rd 643ecd2c2c Implemented initial ui of moderation box. 2024-04-26 20:12:29 +04:00
Ilya Fedin dd1cb00c62 Update snap to core24 2024-04-26 18:39:56 +04:00
23rd 2c4d8418c1 Removed unused code for sponsored messages. 2024-04-26 11:21:41 +04:00
23rd 9fcb5d6f31 Added emoji button to input field for peer title edit. 2024-04-26 11:21:41 +04:00
23rd 38fc6bfbb9 Added special mode to emoji list widget to exclude non-unicode emoji. 2024-04-26 11:21:41 +04:00
23rd 804991a69c Added universal duration to styles. 2024-04-26 11:21:41 +04:00
23rd 7388f46adf Fixed display of subscribers count in dialogs suggestions. 2024-04-26 11:21:41 +04:00
John Preston 10c427127e Fix accidental search focusing. 2024-04-26 11:10:12 +04:00
John Preston c6d034174b Support separate webview storages. 2024-04-26 08:58:42 +04:00
Ilya Fedin 471831bcd6 Revert "Remove not really needed notification capability checks"
This reverts commit abdfa4f785.
2024-04-25 15:07:51 +04:00
Ilya Fedin b1e64419a5 Fix setting application icon in Linux notifications 2024-04-25 11:31:43 +04:00
Ilya Fedin e2f17f1131 Remove unneeded includes from notifications_manager_linux 2024-04-25 11:31:43 +04:00
John Preston ae4a73a15b Rollback OpenSans to 1.10. 2024-04-24 22:20:22 +04:00
Kolya a84ca00270 fix typo 2024-04-24 19:18:33 +04:00
John Preston c16d820b88 Move OpenSSL probing before crash reporter. 2024-04-24 19:12:46 +04:00
John Preston ef614150d5 Remove dead code in lib_ui. 2024-04-24 17:44:51 +04:00
John Preston b46ca1ec17 Use different font fallback algo on Windows. 2024-04-24 17:44:40 +04:00
John Preston d5a347ede7 Try cancelling the new search by mouse back button. 2024-04-24 17:41:12 +04:00
John Preston 72d5a9b3e0 Toggle search focus by escape. 2024-04-24 16:56:20 +04:00
John Preston e6d72b4861 Un-focus chats search on empty history click. 2024-04-24 16:54:10 +04:00
John Preston 3da51b1bc9 Fix crash on quit in sponsored messages. 2024-04-24 16:37:27 +04:00
John Preston 17b7db6219 Request 64 frequent contacts instead of 32. 2024-04-24 16:37:27 +04:00
John Preston 8353180161 Fix phrase cut-off in QR login. 2024-04-24 16:37:27 +04:00
John Preston f675a8dcf7 Attempt to fix a couple of crashes. 2024-04-24 16:37:27 +04:00
John Preston 493f1d69e2 Fix cancel search button overlap. 2024-04-24 16:37:27 +04:00
John Preston 331e8c3ec6 Beta version 4.16.9.
- Show "Frequent contacts" when you focus the search field.
- Show "Recent chats" when you focus the search field.
- Show "Channels" and channel recommendations.
- Allow changing font in Settings > Chat settings > Font family.
2024-04-23 23:14:19 +04:00
John Preston 56bce70558 Fix "long time ago" for users who blocked me. 2024-04-23 21:47:57 +04:00
John Preston d82e48f8e4 Improve ChooseFontBox navigation. 2024-04-23 19:17:42 +04:00
John Preston 97ecc57be8 Add choose font settings. 2024-04-23 19:17:42 +04:00
John Preston 25bd2b145b Update submodules. 2024-04-23 19:17:42 +04:00
John Preston 7111c92ae7 Fix keyboard navigation in top peers. 2024-04-23 19:17:42 +04:00
John Preston e066cf1589 Add "Show all" for top peers. 2024-04-23 19:17:41 +04:00
John Preston 6f328b2ef8 Fix inline query draft applying. 2024-04-23 19:17:41 +04:00
23rd 7a6c55bd8a Fixed color of icon for replies with media story. 2024-04-23 19:17:41 +04:00
23rd b35d3f57fe Slightly improved style of sub-button in sponsored messages. 2024-04-23 19:17:41 +04:00
23rd eef65af173 Slightly simplified meson usage on macOS in prepare.py. 2024-04-23 19:17:41 +04:00
23rd bea715b41c Added ICCv4 with Little CMS on macOS. 2024-04-23 19:17:41 +04:00
23rd 7be68ca82c Updated Qt to 6.2.8 on macOS. 2024-04-23 19:17:41 +04:00
John Preston 287d5a7413 Fix shadow below Chats/Channels. 2024-04-23 19:17:41 +04:00
John Preston 1448cea01c Fix ripple in active recommendation row. 2024-04-23 19:17:41 +04:00
John Preston 768e8b457b Improve second-time choose of toppeers. 2024-04-23 19:17:41 +04:00
John Preston 05474f4a3f Improve filter switching with toppeers. 2024-04-23 19:17:41 +04:00
John Preston 8acada9b0f Fix toppeers animation with expanded stories. 2024-04-23 19:17:41 +04:00
23rd a86e7f035f Slightly improved style of inner box for channel earn history entries. 2024-04-23 19:17:41 +04:00
John Preston 9caff93c35 Fix build for Xcode. 2024-04-23 19:13:48 +04:00
John Preston e6ba85e112 Keyboard navigation in channels/recommendations. 2024-04-23 19:13:48 +04:00
John Preston 046803dbed Fix rotation reading in FFmpeg. 2024-04-23 19:13:48 +04:00
John Preston 615f4b1d1c Ignore pageBlockUnsupported blocks. 2024-04-23 19:13:48 +04:00
John Preston a11535806d Always show cancel search when focused. 2024-04-23 19:13:48 +04:00
John Preston 34a7169b4f Make unread badges on top peers nicer. 2024-04-23 19:13:47 +04:00
John Preston 4f365c73ad Support active selection in recommendations. 2024-04-23 19:13:47 +04:00
John Preston 705bd9693d Load recommendations on demand. 2024-04-23 19:13:47 +04:00
John Preston a88770a8ec Don't close recommendations. 2024-04-23 19:13:47 +04:00
John Preston da423b5bd2 Add a general FastShareLink method. 2024-04-23 19:13:47 +04:00
John Preston 56080bd0e4 Fix boost group link handling for forums. 2024-04-23 19:13:47 +04:00
John Preston 63f66a1369 Show "Boost" button in boost group links. 2024-04-23 19:13:47 +04:00
John Preston ca1a30196e Fix LinkButton resizing. 2024-04-23 19:13:47 +04:00
John Preston b2d8e2a1e6 Initial version of channels/recommendations. 2024-04-23 19:13:47 +04:00
John Preston 2ab8bb13c5 Fix links preview. 2024-04-23 19:13:47 +04:00
23rd 3a2c5c6d0a Increased size of stickerset preview in webpages. 2024-04-23 19:13:47 +04:00
23rd ed13a325e9 Added stickerset preview to webpages. 2024-04-23 19:13:47 +04:00
23rd f43f99cff2 Added initial api support of stickerset attribute in web pages. 2024-04-23 19:13:47 +04:00
John Preston a3b8397361 Close chat/media if thrown out by admin. 2024-04-23 19:13:47 +04:00
John Preston 4fb03e532c Optimize stories list generation. 2024-04-23 19:13:47 +04:00
John Preston 645ad5e1bd Update pinned icon in stories list. 2024-04-23 19:13:47 +04:00
John Preston 9036e9e8e3 Show pinned icon in stories. 2024-04-23 19:13:47 +04:00
John Preston 468d8b04d6 Implement stories pin-to-top. 2024-04-23 19:13:47 +04:00
John Preston 4b98ab1246 Fix build with simplified ads. 2024-04-23 19:13:46 +04:00
John Preston d33e3dc13a Rename Story::pinned to Story::inProfile. 2024-04-23 19:13:46 +04:00
23rd df16e7c00b Added ability to change reactions limit in channels. 2024-04-23 19:13:46 +04:00
23rd 225c0e0af3 Added initial api support of reactions limit in channels and groups. 2024-04-23 19:13:46 +04:00
23rd 5543927042 Added ability to enable sponsored messages for premium self. 2024-04-23 19:13:46 +04:00
23rd 72b274a2bf Added support of simplified constructor for MTP sponsored message. 2024-04-23 19:13:46 +04:00
John Preston ac15990b48 Update API scheme to layer178, ads broke build. 2024-04-23 19:13:46 +04:00
John Preston 7387dfdd9c Don't create top/recent peers unnecessary. 2024-04-23 19:13:46 +04:00
John Preston 74a7e7d1b4 Fix non-intentional chats list search focus. 2024-04-23 19:13:46 +04:00
John Preston a0a9de1d18 Cancel search on switching folders. 2024-04-23 19:13:46 +04:00
John Preston 360366ba9e Fix opening forums from recent peers. 2024-04-23 19:13:46 +04:00
John Preston 0180fe9468 Animate search suggestions. 2024-04-23 19:13:46 +04:00
John Preston 19f5d95a3c Implement keyboard navigation for recent peers. 2024-04-23 19:13:46 +04:00
John Preston 051ca51d3b Allow clearing search results. 2024-04-23 19:13:46 +04:00
John Preston 2a6ff9203b Implement basic recent search results. 2024-04-23 19:13:46 +04:00
John Preston 2e0529bd9a Add data component for RecentPeers. 2024-04-23 19:13:46 +04:00
John Preston e24ab4f1ab Allow saving emoji to files in debug builds. 2024-04-23 19:13:46 +04:00
John Preston 3dbadeb232 Allow opening top peers in a new window. 2024-04-23 19:13:46 +04:00
John Preston 4cdd939028 Cache topPeers locally. 2024-04-23 19:13:46 +04:00
John Preston c11f4efc5c Support disabling top peers completely. 2024-04-23 19:13:46 +04:00
John Preston e1c21b908c Add keyboard navigation to top peers. 2024-04-23 19:13:46 +04:00
John Preston a6c1def6fe Add ripples to top peers. 2024-04-23 19:13:46 +04:00
John Preston 19ae76d8de Top peers context menu. 2024-04-23 19:13:46 +04:00
John Preston 56e28feb00 Top peer realtime badges. 2024-04-23 19:13:45 +04:00
John Preston b259c566b7 Top peer unread badges and online indicators. 2024-04-23 19:13:45 +04:00
John Preston 18598f8dca Initial version of top peers. 2024-04-23 19:13:45 +04:00
John Preston 11e4c45969 Don't collapse chats list on window unfocus. 2024-04-23 19:13:45 +04:00
John Preston 39658ffe52 Allow narrow chats width without main section. 2024-04-23 19:13:45 +04:00
John Preston 2f03b9aa29 Make dialogs filter onfocused by default. 2024-04-23 19:13:45 +04:00
John Preston dc438cff23 Always export file_name in json. 2024-04-23 19:13:45 +04:00
John Preston 18f5521be5 Don't look for SDL when building on macOS. 2024-04-23 19:13:45 +04:00
Ilya Fedin bae9af1076 Switch crash reporter to system fonts
This should prevent nested crashes when loading custom fonts
2024-04-23 11:01:19 +04:00
Ilya Fedin 8d2805f226 Set font weight in crash reporter 2024-04-23 10:10:43 +04:00
Ilya Fedin 0ad18c8182 Get rid of direct Wayland usage
This should get rid of a very nasty vector of misbehaving and quite a lot of code which is boilerplate over Wayland protocols at the price of losing support of niche features

Most of things served by xcb code on X11 is served by portal code on Wayland, hopefully this tendention will continue and we will be fine just with glib which provides D-Bus and other basic APIs
2024-04-22 11:04:02 +04:00
Ilya Fedin 9046b2cafb Stop using the plasma-shell protocol
Looks like this isn't really correct in combination with xdg-shell
2024-04-22 10:59:16 +04:00
Ilya Fedin 3d994b58a0 ShowXDPOpenWithDialog -> UnsafeShowOpenWith 2024-04-21 03:14:34 +04:00
Ilya Fedin 4310c4978e Fix macOS packaged action 2024-04-19 17:41:07 +04:00
23rd 01bfa46729 Fixed display of default box for message schedule in correspond window. 2024-04-18 11:57:25 +04:00
Kolya 3510ca7184 Don't use/link libsharpyuv in libavif 2024-04-18 09:23:15 +04:00
Ilya Fedin 8d7845daa1 Use --shallow-submodules in Docker 2024-04-18 09:13:37 +04:00
Ilya Fedin cb5fdac0da Replace mozjpeg with jpegli on Linux 2024-04-17 23:45:15 +04:00
508 changed files with 25096 additions and 5776 deletions
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
@@ -1,32 +1,11 @@
name: No Response
name: Can't reproduce.
# Both `issue_comment` and `scheduled` event types are required for this Action
# to work properly.
on:
issue_comment:
types: [created]
schedule:
- cron: '0 0 * * *'
- cron: '0 3 * * *'
jobs:
waiting-for-answer:
runs-on: ubuntu-latest
steps:
- uses: lee-dohm/no-response@v0.5.0
with:
token: ${{ github.token }}
responseRequiredLabel: waiting for answer
needs-user-action:
runs-on: ubuntu-latest
steps:
- uses: lee-dohm/no-response@v0.5.0
with:
token: ${{ github.token }}
responseRequiredLabel: needs user action
cant-reproduce:
if: github.event_name != 'issue_comment'
runs-on: ubuntu-latest
steps:
- uses: lee-dohm/no-response@v0.5.0
+2 -2
View File
@@ -20,7 +20,7 @@ jobs:
steps:
- name: Clone.
uses: actions/checkout@v3.1.0
uses: actions/checkout@v4
with:
submodules: recursive
@@ -31,7 +31,7 @@ jobs:
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: Free up some disk space.
uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
- name: Docker image build.
run: |
+2 -3
View File
@@ -49,7 +49,6 @@ jobs:
defines:
- ""
- "DESKTOP_APP_DISABLE_X11_INTEGRATION"
- "DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION"
env:
UPLOAD_ARTIFACT: "true"
@@ -59,7 +58,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone.
uses: actions/checkout@v3.1.0
uses: actions/checkout@v4
with:
submodules: recursive
path: ${{ env.REPO_NAME }}
@@ -117,7 +116,7 @@ jobs:
cd $REPO_NAME/out/Debug
sudo mkdir artifact
sudo mv {Telegram,Updater} artifact/
- uses: actions/upload-artifact@master
- uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
+1 -1
View File
@@ -8,7 +8,7 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v3
- uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-inactive-days: 45
+4 -4
View File
@@ -56,7 +56,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone.
uses: actions/checkout@v3.1.0
uses: actions/checkout@v4
with:
submodules: recursive
path: ${{ env.REPO_NAME }}
@@ -76,7 +76,7 @@ jobs:
- name: ThirdParty cache.
id: cache-third-party
uses: actions/cache@v3.0.11
uses: actions/cache@v4
with:
path: ThirdParty
key: ${{ runner.OS }}-third-party-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }}
@@ -84,7 +84,7 @@ jobs:
- name: Libraries cache.
id: cache-libs
uses: actions/cache@v3.0.11
uses: actions/cache@v4
with:
path: Libraries
key: ${{ runner.OS }}-libs-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }}
@@ -134,7 +134,7 @@ jobs:
mkdir artifact
mv Telegram.app artifact/
mv Updater artifact/
- uses: actions/upload-artifact@master
- uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
+5 -5
View File
@@ -49,7 +49,7 @@ jobs:
env:
GIT: "https://github.com"
OPENALDIR: "/usr/local/opt/openal-soft"
CMAKE_PREFIX_PATH: "/usr/local/opt/ffmpeg@6:/usr/local/opt/openal-soft"
UPLOAD_ARTIFACT: "true"
ONLY_CACHE: "false"
MANUAL_CACHING: "1"
@@ -60,7 +60,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone.
uses: actions/checkout@v3.1.0
uses: actions/checkout@v4
with:
submodules: recursive
path: ${{ env.REPO_NAME }}
@@ -69,7 +69,7 @@ jobs:
run: |
brew update
brew upgrade || true
brew install autoconf automake boost cmake ffmpeg openal-soft openssl opus ninja pkg-config python qt yasm xz
brew install autoconf automake boost cmake ffmpeg@6 openal-soft openssl opus ninja pkg-config python qt yasm xz
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
xcodebuild -version > CACHE_KEY.txt
@@ -99,7 +99,7 @@ jobs:
- name: WebRTC cache.
id: cache-webrtc
uses: actions/cache@v3.0.11
uses: actions/cache@v4
with:
path: ${{ env.LibrariesPath }}/tg_owt
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }}
@@ -153,7 +153,7 @@ jobs:
cd $REPO_NAME/build
mkdir artifact
mv Telegram.dmg artifact/
- uses: actions/upload-artifact@master
- uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
SKIP: "0"
to_branch: "master"
steps:
- uses: actions/checkout@v4.1.0
- uses: actions/checkout@v4
with:
fetch-depth: 0
if: env.SKIP == '0'
+16
View File
@@ -0,0 +1,16 @@
name: Needs user action.
on:
issue_comment:
types: [created]
schedule:
- cron: '0 2 * * *'
jobs:
needs-user-action:
runs-on: ubuntu-latest
steps:
- uses: lee-dohm/no-response@v0.5.0
with:
token: ${{ github.token }}
responseRequiredLabel: needs user action
+4 -4
View File
@@ -47,7 +47,7 @@ jobs:
steps:
- name: Clone.
uses: actions/checkout@v3.1.0
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
@@ -61,10 +61,10 @@ jobs:
sudo snap run lxd waitready
- name: Free up some disk space.
uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
- name: Telegram Desktop snap build.
run: sg lxd -c 'snap run snapcraft -v'
run: sg lxd -c 'snap run snapcraft --verbosity=debug'
- name: Move artifact.
if: env.UPLOAD_ARTIFACT == 'true'
@@ -75,7 +75,7 @@ jobs:
mkdir artifact
mv $artifact_name artifact
- uses: actions/upload-artifact@master
- uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
+1 -1
View File
@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5
- uses: actions/stale@v9
with:
stale-issue-message: |
Hey there!
+16
View File
@@ -0,0 +1,16 @@
name: Waiting for answer.
on:
issue_comment:
types: [created]
schedule:
- cron: '30 0 * * *'
jobs:
waiting-for-answer:
runs-on: ubuntu-latest
steps:
- uses: lee-dohm/no-response@v0.5.0
with:
token: ${{ github.token }}
responseRequiredLabel: waiting for answer
+4 -4
View File
@@ -69,13 +69,13 @@ jobs:
shell: bash
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- uses: ilammy/msvc-dev-cmd@v1.12.0
- uses: ilammy/msvc-dev-cmd@v1.13.0
name: Native Tools Command Prompt.
with:
arch: ${{ matrix.arch }}
- name: Clone.
uses: actions/checkout@v3.1.0
uses: actions/checkout@v4
with:
submodules: recursive
path: ${{ env.TBUILD }}\${{ env.REPO_NAME }}
@@ -96,7 +96,7 @@ jobs:
- name: Libraries cache.
id: cache-libs
uses: actions/cache@v3.0.11
uses: actions/cache@v4
with:
path: ${{ env.TBUILD }}\Libraries
key: ${{ runner.OS }}-${{ matrix.arch }}-libs-${{ env.CACHE_KEY }}
@@ -183,7 +183,7 @@ jobs:
mkdir artifact
move %OUT%\Telegram.exe artifact/
move %OUT%\Updater.exe artifact/
- uses: actions/upload-artifact@master
- uses: actions/upload-artifact@v4
name: Upload artifact.
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
with:
+1
View File
@@ -18,6 +18,7 @@ Release/
*.xcodeproj
ipch/
.vs/
.vscode/
/Telegram/log.txt
/Telegram/data
-9
View File
@@ -82,12 +82,6 @@
[submodule "Telegram/ThirdParty/dispatch"]
path = Telegram/ThirdParty/dispatch
url = https://github.com/apple/swift-corelibs-libdispatch
[submodule "Telegram/ThirdParty/plasma-wayland-protocols"]
path = Telegram/ThirdParty/plasma-wayland-protocols
url = https://github.com/KDE/plasma-wayland-protocols.git
[submodule "Telegram/ThirdParty/wayland-protocols"]
path = Telegram/ThirdParty/wayland-protocols
url = https://github.com/gitlab-freedesktop-mirrors/wayland-protocols.git
[submodule "Telegram/ThirdParty/kimageformats"]
path = Telegram/ThirdParty/kimageformats
url = https://github.com/KDE/kimageformats.git
@@ -97,9 +91,6 @@
[submodule "Telegram/ThirdParty/cld3"]
path = Telegram/ThirdParty/cld3
url = https://github.com/google/cld3.git
[submodule "Telegram/ThirdParty/wayland"]
path = Telegram/ThirdParty/wayland
url = https://github.com/gitlab-freedesktop-mirrors/wayland.git
[submodule "Telegram/ThirdParty/libprisma"]
path = Telegram/ThirdParty/libprisma
url = https://github.com/desktop-app/libprisma.git
+1 -1
View File
@@ -62,7 +62,7 @@ if (NOT DESKTOP_APP_USE_PACKAGED)
if (WIN32)
set(qt_version 5.15.13)
elseif (APPLE)
set(qt_version 6.2.7)
set(qt_version 6.2.8)
endif()
endif()
include(cmake/external/qt/package.cmake)
+46 -40
View File
@@ -189,6 +189,8 @@ PRIVATE
api/api_common.h
api/api_confirm_phone.cpp
api/api_confirm_phone.h
api/api_credits.cpp
api/api_credits.h
api/api_earn.cpp
api/api_earn.h
api/api_editing.cpp
@@ -342,6 +344,8 @@ PRIVATE
boxes/local_storage_box.h
boxes/max_invite_box.cpp
boxes/max_invite_box.h
boxes/moderate_messages_box.cpp
boxes/moderate_messages_box.h
boxes/peer_list_box.cpp
boxes/peer_list_box.h
boxes/peer_list_controllers.cpp
@@ -366,6 +370,8 @@ PRIVATE
boxes/ringtones_box.h
boxes/self_destruction_box.cpp
boxes/self_destruction_box.h
boxes/send_credits_box.cpp
boxes/send_credits_box.h
boxes/send_files_box.cpp
boxes/send_files_box.h
boxes/sessions_box.cpp
@@ -508,6 +514,8 @@ PRIVATE
core/launcher.h
core/local_url_handlers.cpp
core/local_url_handlers.h
core/phone_click_handler.cpp
core/phone_click_handler.h
core/sandbox.cpp
core/sandbox.h
core/shortcuts.cpp
@@ -529,10 +537,16 @@ PRIVATE
data/business/data_business_info.h
data/business/data_shortcut_messages.cpp
data/business/data_shortcut_messages.h
data/components/factchecks.cpp
data/components/factchecks.h
data/components/recent_peers.cpp
data/components/recent_peers.h
data/components/scheduled_messages.cpp
data/components/scheduled_messages.h
data/components/sponsored_messages.cpp
data/components/sponsored_messages.h
data/components/top_peers.cpp
data/components/top_peers.h
data/notify/data_notify_settings.cpp
data/notify/data_notify_settings.h
data/notify/data_peer_notify_settings.cpp
@@ -602,6 +616,8 @@ PRIVATE
data/data_groups.h
data/data_histories.cpp
data/data_histories.h
data/data_history_messages.cpp
data/data_history_messages.h
data/data_lastseen_status.h
data/data_location.cpp
data/data_location.h
@@ -677,6 +693,18 @@ PRIVATE
data/data_wall_paper.h
data/data_web_page.cpp
data/data_web_page.h
dialogs/ui/dialogs_layout.cpp
dialogs/ui/dialogs_layout.h
dialogs/ui/dialogs_message_view.cpp
dialogs/ui/dialogs_message_view.h
dialogs/ui/dialogs_stories_content.cpp
dialogs/ui/dialogs_stories_content.h
dialogs/ui/dialogs_suggestions.cpp
dialogs/ui/dialogs_suggestions.h
dialogs/ui/dialogs_topics_view.cpp
dialogs/ui/dialogs_topics_view.h
dialogs/ui/dialogs_video_userpic.cpp
dialogs/ui/dialogs_video_userpic.h
dialogs/dialogs_entry.cpp
dialogs/dialogs_entry.h
dialogs/dialogs_indexed_list.cpp
@@ -699,16 +727,6 @@ PRIVATE
dialogs/dialogs_search_tags.h
dialogs/dialogs_widget.cpp
dialogs/dialogs_widget.h
dialogs/ui/dialogs_layout.cpp
dialogs/ui/dialogs_layout.h
dialogs/ui/dialogs_message_view.cpp
dialogs/ui/dialogs_message_view.h
dialogs/ui/dialogs_stories_content.cpp
dialogs/ui/dialogs_stories_content.h
dialogs/ui/dialogs_topics_view.cpp
dialogs/ui/dialogs_topics_view.h
dialogs/ui/dialogs_video_userpic.cpp
dialogs/ui/dialogs_video_userpic.h
editor/color_picker.cpp
editor/color_picker.h
editor/controllers/controllers.h
@@ -749,6 +767,8 @@ PRIVATE
history/view/controls/compose_controls_common.h
history/view/controls/history_view_compose_controls.cpp
history/view/controls/history_view_compose_controls.h
history/view/controls/history_view_compose_media_edit_manager.cpp
history/view/controls/history_view_compose_media_edit_manager.h
history/view/controls/history_view_compose_search.cpp
history/view/controls/history_view_compose_search.h
history/view/controls/history_view_draft_options.cpp
@@ -840,6 +860,8 @@ PRIVATE
history/view/history_view_about_view.h
history/view/history_view_bottom_info.cpp
history/view/history_view_bottom_info.h
history/view/history_view_chat_preview.cpp
history/view/history_view_chat_preview.h
history/view/history_view_contact_status.cpp
history/view/history_view_contact_status.h
history/view/history_view_context_menu.cpp
@@ -854,6 +876,8 @@ PRIVATE
history/view/history_view_emoji_interactions.h
history/view/history_view_empty_list_bubble.cpp
history/view/history_view_empty_list_bubble.h
history/view/history_view_fake_items.cpp
history/view/history_view_fake_items.h
history/view/history_view_group_call_bar.cpp
history/view/history_view_group_call_bar.h
history/view/history_view_item_preview.h
@@ -884,14 +908,14 @@ PRIVATE
history/view/history_view_send_action.h
history/view/history_view_service_message.cpp
history/view/history_view_service_message.h
history/view/history_view_spoiler_click_handler.cpp
history/view/history_view_spoiler_click_handler.h
history/view/history_view_sponsored_click_handler.cpp
history/view/history_view_sponsored_click_handler.h
history/view/history_view_sticker_toast.cpp
history/view/history_view_sticker_toast.h
history/view/history_view_sublist_section.cpp
history/view/history_view_sublist_section.h
history/view/history_view_text_helper.cpp
history/view/history_view_text_helper.h
history/view/history_view_transcribe_button.cpp
history/view/history_view_transcribe_button.h
history/view/history_view_translate_bar.cpp
@@ -1268,11 +1292,8 @@ PRIVATE
payments/payments_checkout_process.h
payments/payments_form.cpp
payments/payments_form.h
platform/linux/linux_wayland_integration_dummy.cpp
platform/linux/linux_wayland_integration.cpp
platform/linux/linux_wayland_integration.h
platform/linux/linux_xdp_open_with_dialog.cpp
platform/linux/linux_xdp_open_with_dialog.h
payments/payments_non_panel_process.cpp
payments/payments_non_panel_process.h
platform/linux/file_utilities_linux.cpp
platform/linux/file_utilities_linux.h
platform/linux/launcher_linux.cpp
@@ -1418,6 +1439,10 @@ PRIVATE
settings/settings_codes.h
settings/settings_common_session.cpp
settings/settings_common_session.h
settings/settings_credits.cpp
settings/settings_credits.h
settings/settings_credits_graphics.cpp
settings/settings_credits_graphics.h
settings/settings_experimental.cpp
settings/settings_experimental.h
settings/settings_folders.cpp
@@ -1513,6 +1538,8 @@ PRIVATE
ui/controls/silent_toggle.h
ui/controls/userpic_button.cpp
ui/controls/userpic_button.h
ui/effects/credits_graphics.cpp
ui/effects/credits_graphics.h
ui/effects/emoji_fly_animation.cpp
ui/effects/emoji_fly_animation.h
ui/effects/message_sending_animation_common.h
@@ -1560,6 +1587,8 @@ PRIVATE
window/section_widget.h
window/window_adaptive.cpp
window/window_adaptive.h
window/window_chat_preview.cpp
window/window_chat_preview.h
window/window_connecting_widget.cpp
window/window_connecting_widget.h
window/window_controller.cpp
@@ -1625,16 +1654,6 @@ if (NOT build_winstore)
)
endif()
if (DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
remove_target_sources(Telegram ${src_loc}
platform/linux/linux_wayland_integration.cpp
)
else()
remove_target_sources(Telegram ${src_loc}
platform/linux/linux_wayland_integration_dummy.cpp
)
endif()
if (DESKTOP_APP_USE_PACKAGED)
remove_target_sources(Telegram ${src_loc}
platform/mac/mac_iconv_helper.c
@@ -1774,19 +1793,6 @@ else()
desktop-app::external_xcb
)
endif()
if (NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
qt_generate_wayland_protocol_client_sources(Telegram
FILES
${third_party_loc}/wayland/protocol/wayland.xml
${third_party_loc}/plasma-wayland-protocols/src/protocols/plasma-shell.xml
)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_wayland_client
)
endif()
endif()
if (build_macstore)
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

+30 -1
View File
@@ -134,9 +134,32 @@ html.custom_scroll ::-webkit-scrollbar-thumb:hover {
.page-slide {
position: relative;
width: 100%;
min-height: 100%;
margin-left: 0%;
transition: margin 240ms ease-in-out;
}
.page-footer {
height: 32px;
margin-top: -32px;
background: var(--td-window-bg-over);
}
.page-footer .content {
padding: 3px 18px;
font-size: 15px;
color: var(--td-window-sub-text-fg);
text-align: center;
}
.page-footer .wrong {
position: relative;
padding: 5px;
margin: -5px;
color: var(--td-window-sub-text-fg);
text-decoration: none;
cursor: pointer;
}
.page-footer .wrong:hover {
text-decoration: underline;
}
.hidden-left,
.hidden-right {
pointer-events: none;
@@ -148,7 +171,7 @@ html.custom_scroll ::-webkit-scrollbar-thumb:hover {
margin-left: 100%;
}
article {
padding-bottom: 12px;
padding-bottom: 40px;
overflow-y: hidden;
overflow-x: auto;
white-space: pre-wrap;
@@ -893,6 +916,9 @@ section.related a.related-link:after {
right: 0;
bottom: 0;
}
section.related a.related-link:last-child:after {
border-bottom: 0px;
}
section.related .related-link-url {
display: block;
font-size: 15px;
@@ -1027,6 +1053,9 @@ section.channel > a > h4 {
display: block;
margin: 0 auto;
}
.media-outer {
margin-bottom: 16px;
}
.photo-wrap,
.video-wrap {
width: 100%;
+9 -7
View File
@@ -26,7 +26,7 @@ var IV = {
}
target = target.parentNode;
}
if (!target || !target.hasAttribute('href')) {
if (!target || (context === '' && !target.hasAttribute('href'))) {
return;
}
var base = document.createElement('A');
@@ -413,9 +413,12 @@ var IV = {
var article = function (el) {
return el.getElementsByTagName('article')[0];
};
var from = article(IV.findPageScroll());
var to = article(IV.makeScrolledContent(data.html));
morphdom(from, to, {
var footer = function (el) {
return el.getElementsByClassName('page-footer')[0];
};
var from = IV.findPageScroll();
var to = IV.makeScrolledContent(data.html);
morphdom(article(from), article(to), {
onBeforeElUpdated: function (fromEl, toEl) {
if (fromEl.classList.contains('video')
&& toEl.classList.contains('video')
@@ -439,6 +442,7 @@ var IV = {
return !fromEl.isEqualNode(toEl);
}
});
morphdom(footer(from), footer(to));
IV.initMedia();
eval(data.js);
},
@@ -477,9 +481,7 @@ var IV = {
var result = document.createElement('div');
result.className = 'page-scroll';
result.tabIndex = '-1';
result.innerHTML = '<div class="page-slide"><article>'
+ html
+ '</article></div>';
result.innerHTML = html.trim();
result.onscroll = IV.frameScrolled;
return result;
},
+168
View File
@@ -251,6 +251,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_caption_limit2#other" = "Make the caption shorter or subscribe to **Telegram Premium** to double the limit to **{count}** characters.";
"lng_caption_limit_reached#one" = "You've reached the media caption limit. Please make the caption shorter by {count} character.";
"lng_caption_limit_reached#other" = "You've reached the media caption limit. Please make the caption shorter by {count} characters.";
"lng_caption_move_up" = "Move Caption Up";
"lng_caption_move_down" = "Move Caption Down";
"lng_file_size_limit_title" = "File Too Large";
"lng_file_size_limit#one" = "{count} Gb";
@@ -302,6 +304,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_sure_ban_admin" = "This user is an admin. Are you sure you want to go ahead and restrict them?";
"lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in the Settings (Connection Type).";
"lng_sure_enable" = "Enable";
"lng_proxy_box_title" = "Enable proxy";
"lng_proxy_box_server" = "Server";
"lng_proxy_box_port" = "Port";
"lng_proxy_box_secret" = "Secret";
"lng_proxy_box_status" = "Status";
"lng_proxy_box_username" = "Username";
"lng_proxy_box_password" = "Password";
"lng_proxy_invalid" = "The proxy link is invalid.";
"lng_proxy_unsupported" = "Your Telegram Desktop version doesn't support this proxy type or the proxy link is invalid. Please update Telegram Desktop to the latest version.";
@@ -561,6 +570,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_reaction_invoice" = "{reaction} to your invoice";
"lng_reaction_gif" = "{reaction} to your GIF";
"lng_effect_add_title" = "Add an animated effect";
"lng_effect_stickers_title" = "Effects from stickers";
"lng_effect_send" = "Send with Effect";
"lng_effect_none" = "No effects found.";
"lng_effect_premium" = "Subscribe to {link} to add this animated effect.";
"lng_effect_premium_link" = "Telegram Premium";
"lng_languages" = "Languages";
"lng_languages_none" = "No languages found.";
"lng_languages_count#one" = "{count} language";
@@ -730,6 +746,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_angle_backend_d3d11on12" = "D3D11on12";
"lng_settings_angle_backend_opengl" = "OpenGL";
"lng_settings_angle_backend_disabled" = "Disabled";
"lng_settings_top_peers_title" = "Frequent contacts";
"lng_settings_top_peers_suggest" = "Suggest frequent contacts";
"lng_settings_top_peers_about" = "Display people you message frequently at the top of the search section for quick access.";
"lng_settings_sensitive_title" = "Sensitive content";
"lng_settings_sensitive_disable_filtering" = "Disable filtering";
"lng_settings_sensitive_about" = "Display sensitive media in public channels on all your Telegram devices.";
@@ -766,6 +785,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_power_chat" = "Animations in Chats";
"lng_settings_power_chat_background" = "Background rotation";
"lng_settings_power_chat_spoiler" = "Animated spoiler effect";
"lng_settings_power_chat_effects" = "Effects in messages";
"lng_settings_power_calls" = "Animations in Calls";
"lng_settings_power_ui" = "Interface animations";
"lng_settings_power_auto" = "Save Power on Low Battery";
@@ -840,6 +860,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_auto_night_mode_on" = "System";
"lng_settings_auto_night_warning" = "You have enabled auto-night mode. If you want to change the dark mode settings, you'll need to disable it first.";
"lng_settings_auto_night_disable" = "Disable";
"lng_settings_font_family" = "Font family";
"lng_settings_color_title" = "Color preview";
"lng_settings_color_reply" = "Reply to your message";
@@ -1049,6 +1070,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_proxy_sponsor" = "Proxy sponsor";
"lng_proxy_sponsor_about" = "This channel is shown by your proxy server.\nTo remove this channel from your chats list,\ndisable the proxy in Telegram Settings.";
"lng_proxy_sponsor_warning" = "This proxy may display a sponsored channel in your chat list. This doesn't reveal any of your Telegram traffic.";
"lng_proxy_add_from_clipboard" = "Add proxy from clipboard";
"lng_proxy_add_from_clipboard_good_toast" = "Proxy was added from clipboard.";
"lng_proxy_add_from_clipboard_failed_toast" = "This is not a proxy link.";
"lng_proxy_add_from_clipboard_existing_toast" = "This proxy is already in the list.";
"lng_badge_psa_default" = "PSA";
"lng_about_psa_default" = "This message provides you with a public service announcement. To remove it from your chats list, right click it and select **Hide**.";
"lng_tooltip_psa_default" = "This message provides you with a public service announcement.";
@@ -1492,6 +1517,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_reactions_none_about" = "Members of the group can't add any reactions to messages.";
"lng_manage_peer_reactions_some_title" = "Only allow these reactions";
"lng_manage_peer_reactions_available" = "Available reactions";
"lng_manage_peer_reactions_available_ph" = "Add reactions...";
"lng_manage_peer_reactions_own" = "You can also {link} emoji packs and use them as reactions.";
"lng_manage_peer_reactions_own_link" = "create your own";
"lng_manage_peer_reactions_level#one" = "Your channel needs to reach level **{count}** to use **{same_count}** custom reaction.";
@@ -1500,6 +1526,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_reactions_boost_link" = "here";
"lng_manage_peer_reactions_limit" = "Channels can't have more custom reactions.";
"lng_manage_peer_reactions_max_title" = "Maximum number of reactions";
"lng_manage_peer_reactions_max_slider#one" = "{count} reaction per post";
"lng_manage_peer_reactions_max_slider#other" = "{count} reactions per post";
"lng_manage_peer_reactions_max_about" = "Limit the number of different reactions that can be added to a post, including already published ones.";
"lng_manage_peer_antispam" = "Aggressive Anti-Spam";
"lng_manage_peer_antispam_about" = "Telegram will filter more spam but may occasionally affect ordinary messages. You can report False Positives in Recent Actions.";
"lng_manage_peer_antispam_not_enough#one" = "Aggressive filtering can be enabled only in groups with more than **{count} member**.";
@@ -1512,8 +1543,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_link_invite" = "Invite link";
"lng_manage_peer_link_expired" = "Expired link";
"lng_manage_private_group_title" = "Private";
"lng_manage_private_group_noforwards_title" = "Private restricted";
"lng_manage_public_group_title" = "Public";
"lng_manage_private_peer_title" = "Private";
"lng_manage_private_peer_noforwards_title" = "Private restricted";
"lng_manage_public_peer_title" = "Public";
"lng_manage_peer_send_title" = "Who can send new messages?";
"lng_manage_peer_send_only_members" = "Only members";
@@ -2269,6 +2302,43 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_business_about_chat_intro" = "Customize the message people see before they start a chat with you.";
"lng_business_subtitle_chat_links" = "Links to Chat";
"lng_business_about_chat_links" = "Create links that start a chat with you, suggesting the first message.";
"lng_business_subtitle_sponsored" = "Ads in Channels";
"lng_business_button_sponsored" = "Do Not Hide Ads";
"lng_business_about_sponsored" = "As a Premium subscriber, you dont see any ads on Telegram, but you can turn them on, for example, to view your own ads that you launched on the {link}";
"lng_business_about_sponsored_link" = "Telegram Ad Platform {emoji}";
"lng_business_about_sponsored_url" = "https://ads.telegram.org";
"lng_credits_summary_title" = "Telegram Stars";
"lng_credits_summary_about" = "Buy Stars to unlock content and services in miniapps on Telegram.";
"lng_credits_summary_options_subtitle" = "Choose package";
"lng_credits_summary_options_credits#one" = "{count} Star";
"lng_credits_summary_options_credits#other" = "{count} Stars";
"lng_credits_summary_options_more" = "More Options";
"lng_credits_summary_options_about" = "By proceeding and purchasing Stars, you agree with the {link}.";
"lng_credits_summary_options_about_link" = "Terms and Conditions";
"lng_credits_summary_history_tab_full" = "All Transactions";
"lng_credits_summary_history_tab_in" = "Incoming";
"lng_credits_summary_history_tab_out" = "Outgoing";
"lng_credits_summary_history_entry_inner_in" = "In-App Purchase";
"lng_credits_summary_balance" = "Balance";
"lng_credits_box_out_title" = "Confirm Your Purchase";
"lng_credits_box_out_sure#one" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Star**?";
"lng_credits_box_out_sure#other" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Stars**?";
"lng_credits_box_out_confirm#one" = "Confirm and Pay {emoji} {count} Star";
"lng_credits_box_out_confirm#other" = "Confirm and Pay {emoji} {count} Stars";
"lng_credits_box_out_about" = "Review the {link} for Stars.";
"lng_credits_summary_in_toast_title" = "Stars Acquired";
"lng_credits_summary_in_toast_about#one" = "**{count}** Star added to your balance.";
"lng_credits_summary_in_toast_about#other" = "**{count}** Stars added to your balance.";
"lng_credits_box_history_entry_peer" = "Recipient";
"lng_credits_box_history_entry_id" = "Transaction ID";
"lng_credits_box_history_entry_id_copied" = "Transaction ID copied to clipboard.";
"lng_credits_box_history_entry_about" = "You can dispute this transaction {link}.";
"lng_credits_box_history_entry_about_link" = "here";
"lng_credits_small_balance_title#one" = "{count} Star Needed";
"lng_credits_small_balance_title#other" = "{count} Stars Needed";
"lng_credits_small_balance_about" = "Buy **Stars** and use them on **{bot}** and other miniapps.";
"lng_credits_purchase_blocked" = "Sorry, you can't purchase this item with Telegram Stars.";
"lng_location_title" = "Location";
"lng_location_about" = "Display the location of your business on your account.";
@@ -2839,7 +2909,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_in_dlg_audio_count#other" = "{count} audio";
"lng_ban_user" = "Ban User";
"lng_ban_users" = "Ban users";
"lng_restrict_users" = "Restrict users";
"lng_delete_all_from_user" = "Delete all from {user}";
"lng_delete_all_from_users" = "Delete all from users";
"lng_restrict_user_part" = "Partially restrict this user {emoji}";
"lng_restrict_users_part" = "Partially restrict users {emoji}";
"lng_restrict_user_full" = "Fully ban this user {emoji}";
"lng_restrict_users_full" = "Fully ban users {emoji}";
"lng_restrict_users_part_single_header" = "What can this user do?";
"lng_restrict_users_part_header#one" = "What can {count} selected user do?";
"lng_restrict_users_part_header#other" = "What can {count} selected users do?";
"lng_report_spam" = "Report Spam";
"lng_report_spam_and_leave" = "Report spam and leave";
"lng_report_spam_done" = "Thank you for your report.";
@@ -3067,6 +3147,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_unread_bar_some" = "Unread messages";
"lng_maps_point" = "Location";
"lng_live_location" = "Live Location";
"lng_live_location_now" = "updated just now";
"lng_live_location_minutes#one" = "updated {count} minute ago";
"lng_live_location_minutes#other" = "updated {count} minutes ago";
"lng_live_location_hours#one" = "updated {count} hour ago";
"lng_live_location_hours#other" = "updated {count} hours ago";
"lng_live_location_today" = "updated today at {time}";
"lng_live_location_yesterday" = "updated yesterday at {time}";
"lng_live_location_date_time" = "updated {date} at {time}";
"lng_save_photo" = "Save image";
"lng_save_video" = "Save video";
"lng_save_audio_file" = "Save audio file";
@@ -3143,6 +3232,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_reply_msg" = "Reply";
"lng_context_quote_and_reply" = "Quote & Reply";
"lng_context_edit_msg" = "Edit";
"lng_context_add_factcheck" = "Add Fact Check";
"lng_context_edit_factcheck" = "Edit Fact Check";
"lng_context_forward_msg" = "Forward Message";
"lng_context_send_now_msg" = "Send now";
"lng_context_reschedule" = "Reschedule";
@@ -3214,6 +3305,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_spoiler_effect" = "Hide with Spoiler";
"lng_context_disable_spoiler" = "Remove Spoiler";
"lng_factcheck_title" = "Fact Check";
"lng_factcheck_placeholder" = "Add Facts or Context";
"lng_factcheck_whats_this" = "what's this?";
"lng_factcheck_about" = "This clarification was provided by a fact checking agency assigned by the department of the government of your country ({country}) responsible for combatting misinformation.";
"lng_factcheck_add_done" = "Fact check added.";
"lng_factcheck_edit_done" = "Fact check edited.";
"lng_factcheck_remove_done" = "Fact check removed.";
"lng_factcheck_bottom" = "This clarification was provided by a fact checking agency assigned by the department of the government of your country ({country}) responsible for combatting misinformation.";
"lng_factcheck_links" = "Only **t.me/** links are allowed.";
"lng_translate_show_original" = "Show Original";
"lng_translate_bar_to" = "Translate to {name}";
"lng_translate_bar_to_other" = "Translate to {name}";
@@ -3334,6 +3435,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_add_contact" = "Create";
"lng_add_contact_button" = "New contact";
"lng_contacts_header" = "Contacts";
"lng_menu_not_contact" = "This number is not on Telegram";
"lng_contacts_hidden_stories" = "Hidden Stories";
"lng_contacts_stories_status#one" = "{count} story";
"lng_contacts_stories_status#other" = "{count} stories";
@@ -3410,6 +3512,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_mediaview_forward" = "Forward";
"lng_mediaview_delete" = "Delete";
"lng_mediaview_save_to_profile" = "Save to Profile";
"lng_mediaview_pin_story_done" = "Story pinned";
"lng_mediaview_pin_story_about" = "Now it will be always shown on the top.";
"lng_mediaview_pin_stories_done#one" = "{count} story pinned";
"lng_mediaview_pin_stories_done#other" = "{count} stories pinned";
"lng_mediaview_pin_stories_about#one" = "Now it will be always shown on the top.";
"lng_mediaview_pin_stories_about#other" = "Now they will be always shown on the top.";
"lng_mediaview_unpin_story_done" = "Story unpinned.";
"lng_mediaview_unpin_stories_done#one" = "{count} story unpinned";
"lng_mediaview_unpin_stories_done#other" = "{count} stories unpinned";
"lng_mediaview_pin_limit#one" = "You can't pin more than {count} story.";
"lng_mediaview_pin_limit#other" = "You can't pin more than {count} stories.";
"lng_mediaview_archive_story" = "Archive Story";
"lng_mediaview_photos_all" = "View all photos";
"lng_mediaview_files_all" = "View all files";
@@ -4704,6 +4817,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_view_button_boost" = "Boost";
"lng_view_button_giftcode" = "Open";
"lng_view_button_iv" = "Instant View";
"lng_view_button_stickerset" = "View stickers";
"lng_view_button_emojipack" = "View emoji";
"lng_sponsored_hide_ads" = "Hide";
"lng_sponsored_title" = "What are sponsored messages?";
@@ -5073,6 +5188,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_iv_share" = "Share";
"lng_iv_join_channel" = "Join";
"lng_iv_window_title" = "Instant View";
"lng_iv_wrong_layout" = "Wrong layout?";
"lng_limit_download_title" = "Download speed limited";
"lng_limit_download_subscribe" = "Subscribe to {link} and increase download speed {increase}.";
@@ -5087,6 +5203,58 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_limit_upload_increase_speed" = "by **{percent}**";
"lng_limit_upload_subscribe_link" = "Telegram Premium";
"lng_recent_frequent" = "Frequent contacts";
"lng_recent_frequent_all" = "Show all";
"lng_recent_frequent_collapse" = "Collapse";
"lng_recent_title" = "Recent";
"lng_recent_clear" = "Clear";
"lng_recent_clear_sure" = "Do you want to clear your search history?";
"lng_recent_remove" = "Remove from Recent";
"lng_recent_clear_all" = "Clear all";
"lng_recent_hide_top" = "Remove all & Disable";
"lng_recent_hide_sure" = "Are you sure you want to clear and disable frequent contacts list?\n\nYou can always turn this feature back on in Settings > Privacy > Suggest Frequent Contacts.";
"lng_recent_hide_button" = "Hide";
"lng_recent_none" = "Recent search results\nwill appear here.";
"lng_recent_chats" = "Chats";
"lng_recent_channels" = "Channels";
"lng_channels_none_title" = "No channels yet...";
"lng_channels_none_about" = "You are not currently subscribed to any channels.";
"lng_channels_your_title" = "Channels you joined";
"lng_channels_your_more" = "Show more";
"lng_channels_your_less" = "Show less";
"lng_channels_recommended" = "Recommended channels";
"lng_font_box_title" = "Choose font family";
"lng_font_default" = "Default";
"lng_font_system" = "System font";
"lng_font_not_found" = "Font not found.";
"lng_search_tab_my_messages" = "My Messages";
"lng_search_tab_this_topic" = "This Topic";
"lng_search_tab_this_chat" = "This Chat";
"lng_search_tab_this_channel" = "This Channel";
"lng_search_tab_this_group" = "This Group";
"lng_search_tab_public_posts" = "Public Posts";
"lng_search_tab_no_results" = "No Results";
"lng_search_tab_no_results_text" = "There were no results for \"{query}\".";
"lng_search_tab_no_results_retry" = "Try another hashtag.";
"lng_search_tab_by_hashtag" = "Enter a hashtag to find messages containing it.";
"lng_contact_details_button" = "View Contact";
"lng_contact_details_title" = "Contact details";
"lng_contact_details_phone" = "Phone";
"lng_contact_details_phone_main" = "Main Phone";
"lng_contact_details_phone_home" = "Home Phone";
"lng_contact_details_phone_mobile" = "Mobile Phone";
"lng_contact_details_phone_work" = "Work Phone";
"lng_contact_details_phone_other" = "Other Phone";
"lng_contact_details_email" = "Email";
"lng_contact_details_address" = "Address";
"lng_contact_details_url" = "URL";
"lng_contact_details_note" = "Note";
"lng_contact_details_birthday" = "Birthday";
"lng_contact_details_organization" = "Organization";
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";
@@ -24,5 +24,7 @@
<file alias="chat_link.tgs">../../animations/chat_link.tgs</file>
<file alias="collectible_username.tgs">../../animations/collectible_username.tgs</file>
<file alias="collectible_phone.tgs">../../animations/collectible_phone.tgs</file>
<file alias="search.tgs">../../animations/search.tgs</file>
<file alias="noresults.tgs">../../animations/noresults.tgs</file>
</qresource>
</RCC>
+1 -1
View File
@@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="4.16.8.0" />
Version="5.1.2.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
+4 -4
View File
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,16,8,0
PRODUCTVERSION 4,16,8,0
FILEVERSION 5,1,2,0
PRODUCTVERSION 5,1,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "4.16.8.0"
VALUE "FileVersion", "5.1.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.16.8.0"
VALUE "ProductVersion", "5.1.2.0"
END
END
BLOCK "VarFileInfo"
+4 -4
View File
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,16,8,0
PRODUCTVERSION 4,16,8,0
FILEVERSION 5,1,2,0
PRODUCTVERSION 5,1,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
VALUE "FileVersion", "4.16.8.0"
VALUE "FileVersion", "5.1.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.16.8.0"
VALUE "ProductVersion", "5.1.2.0"
END
END
BLOCK "VarFileInfo"
+3 -1
View File
@@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_components.h"
#include "inline_bots/bot_attach_web_view.h"
#include "payments/payments_checkout_process.h"
#include "payments/payments_non_panel_process.h"
#include "main/main_session.h"
#include "mainwidget.h"
#include "mainwindow.h"
@@ -335,7 +336,8 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
Payments::Mode::Payment,
crl::guard(controller, [=](auto) {
controller->widget()->activate();
}));
}),
Payments::ProcessNonPanelPaymentFormFactory(controller, item));
} break;
case ButtonType::Url: {
@@ -212,7 +212,7 @@ void ApplyBotsList(
}
[[nodiscard]] ChatParticipants::Channels ParseSimilar(
not_null<ChannelData*> channel,
not_null<Main::Session*> session,
const MTPmessages_Chats &chats) {
auto result = ChatParticipants::Channels();
std::vector<not_null<ChannelData*>>();
@@ -220,13 +220,13 @@ void ApplyBotsList(
const auto &list = data.vchats().v;
result.list.reserve(list.size());
for (const auto &chat : list) {
const auto peer = channel->owner().processChat(chat);
const auto peer = session->data().processChat(chat);
if (const auto channel = peer->asChannel()) {
result.list.push_back(channel);
}
}
if constexpr (MTPDmessages_chatsSlice::Is<decltype(data)>()) {
if (channel->session().premiumPossible()) {
if (session->premiumPossible()) {
result.more = data.vcount().v - data.vchats().v.size();
}
}
@@ -234,6 +234,12 @@ void ApplyBotsList(
return result;
}
[[nodiscard]] ChatParticipants::Channels ParseSimilar(
not_null<ChannelData*> channel,
const MTPmessages_Chats &chats) {
return ParseSimilar(&channel->session(), chats);
}
} // namespace
ChatParticipant::ChatParticipant(
@@ -351,7 +357,8 @@ QString ChatParticipant::rank() const {
}
ChatParticipants::ChatParticipants(not_null<ApiWrap*> api)
: _api(&api->instance()) {
: _session(&api->session())
, _api(&api->instance()) {
}
void ChatParticipants::requestForAdd(
@@ -585,6 +592,33 @@ ChatParticipants::Parsed ChatParticipants::ParseRecent(
return result;
}
void ChatParticipants::Restrict(
not_null<ChannelData*> channel,
not_null<PeerData*> participant,
ChatRestrictionsInfo oldRights,
ChatRestrictionsInfo newRights,
Fn<void()> onDone,
Fn<void()> onFail) {
channel->session().api().request(MTPchannels_EditBanned(
channel->inputChannel,
participant->input,
MTP_chatBannedRights(
MTP_flags(MTPDchatBannedRights::Flags::from_raw(
uint32(newRights.flags))),
MTP_int(newRights.until))
)).done([=](const MTPUpdates &result) {
channel->session().api().applyUpdates(result);
channel->applyEditBanned(participant, oldRights, newRights);
if (onDone) {
onDone();
}
}).fail([=] {
if (onFail) {
onFail();
}
}).send();
}
void ChatParticipants::requestSelf(not_null<ChannelData*> channel) {
if (_selfParticipantRequests.contains(channel)) {
return;
@@ -730,8 +764,11 @@ void ChatParticipants::loadSimilarChannels(not_null<ChannelData*> channel) {
return;
}
}
using Flag = MTPchannels_GetChannelRecommendations::Flag;
_similar[channel].requestId = _api.request(
MTPchannels_GetChannelRecommendations(channel->inputChannel)
MTPchannels_GetChannelRecommendations(
MTP_flags(Flag::f_channel),
channel->inputChannel)
).done([=](const MTPmessages_Chats &result) {
auto &similar = _similar[channel];
similar.requestId = 0;
@@ -766,4 +803,29 @@ auto ChatParticipants::similarLoaded() const
return _similarLoaded.events();
}
void ChatParticipants::loadRecommendations() {
if (_recommendationsLoaded.current() || _recommendations.requestId) {
return;
}
_recommendations.requestId = _api.request(
MTPchannels_GetChannelRecommendations(
MTP_flags(0),
MTP_inputChannelEmpty())
).done([=](const MTPmessages_Chats &result) {
_recommendations.requestId = 0;
auto parsed = ParseSimilar(_session, result);
_recommendations.channels = std::move(parsed);
_recommendations.channels.more = 0;
_recommendationsLoaded = true;
}).send();
}
const ChatParticipants::Channels &ChatParticipants::recommendations() const {
return _recommendations.channels;
}
rpl::producer<> ChatParticipants::recommendationsLoaded() const {
return _recommendationsLoaded.changes() | rpl::to_empty;
}
} // namespace Api
@@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class ApiWrap;
class ChannelData;
namespace Main {
class Session;
} // namespace Main
namespace Ui {
class Show;
} // namespace Ui
@@ -96,6 +100,13 @@ public:
static Parsed ParseRecent(
not_null<ChannelData*> channel,
const TLMembers &data);
static void Restrict(
not_null<ChannelData*> channel,
not_null<PeerData*> participant,
ChatRestrictionsInfo oldRights,
ChatRestrictionsInfo newRights,
Fn<void()> onDone,
Fn<void()> onFail);
void add(
std::shared_ptr<Ui::Show> show,
not_null<PeerData*> peer,
@@ -134,12 +145,18 @@ public:
[[nodiscard]] auto similarLoaded() const
-> rpl::producer<not_null<ChannelData*>>;
void loadRecommendations();
[[nodiscard]] const Channels &recommendations() const;
[[nodiscard]] rpl::producer<> recommendationsLoaded() const;
private:
struct SimilarChannels {
Channels channels;
mtpRequestId requestId = 0;
};
const not_null<Main::Session*> _session;
MTP::Sender _api;
using PeerRequests = base::flat_map<PeerData*, mtpRequestId>;
@@ -165,6 +182,9 @@ private:
base::flat_map<not_null<ChannelData*>, SimilarChannels> _similar;
rpl::event_stream<not_null<ChannelData*>> _similarLoaded;
SimilarChannels _recommendations;
rpl::variable<bool> _recommendationsLoaded = false;
};
} // namespace Api
+2
View File
@@ -23,8 +23,10 @@ struct SendOptions {
PeerData *sendAs = nullptr;
TimeId scheduled = 0;
BusinessShortcutId shortcutId = 0;
EffectId effectId = 0;
bool silent = false;
bool handleSupportSwitch = false;
bool invertCaption = false;
bool hideViaBot = false;
crl::time ttlSeconds = 0;
};
@@ -62,6 +62,10 @@ void ConfirmPhone::resolve(
return bad("FirebaseSms");
}, [&](const MTPDauth_sentCodeTypeEmailCode &) {
return bad("EmailCode");
}, [&](const MTPDauth_sentCodeTypeSmsWord &) {
return bad("SmsWord");
}, [&](const MTPDauth_sentCodeTypeSmsPhrase &) {
return bad("SmsPhrase");
}, [&](const MTPDauth_sentCodeTypeSetUpEmailRequired &) {
return bad("SetUpEmailRequired");
});
@@ -93,8 +97,10 @@ void ConfirmPhone::resolve(
box->resendRequests(
) | rpl::start_with_next([=] {
_api.request(MTPauth_ResendCode(
MTP_flags(0),
MTP_string(phone),
MTP_string(phoneHash)
MTP_string(phoneHash),
MTPstring() // reason
)).done([=] {
if (boxWeak) {
boxWeak->callDone();
+222
View File
@@ -0,0 +1,222 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_credits.h"
#include "apiwrap.h"
#include "api/api_updates.h"
#include "base/unixtime.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
namespace Api {
namespace {
[[nodiscard]] Data::CreditsHistoryEntry HistoryFromTL(
const MTPStarsTransaction &tl,
not_null<PeerData*> peer) {
using HistoryPeerTL = MTPDstarsTransactionPeer;
const auto photo = tl.data().vphoto()
? peer->owner().photoFromWeb(*tl.data().vphoto(), ImageLocation())
: nullptr;
return Data::CreditsHistoryEntry{
.id = qs(tl.data().vid()),
.title = qs(tl.data().vtitle().value_or_empty()),
.description = qs(tl.data().vdescription().value_or_empty()),
.date = base::unixtime::parse(tl.data().vdate().v),
.photoId = photo ? photo->id : 0,
.credits = tl.data().vstars().v,
.bareId = tl.data().vpeer().match([](const HistoryPeerTL &p) {
return peerFromMTP(p.vpeer());
}, [](const auto &) {
return PeerId(0);
}).value,
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
return Data::CreditsHistoryEntry::PeerType::Peer;
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
return Data::CreditsHistoryEntry::PeerType::PlayMarket;
}, [](const MTPDstarsTransactionPeerFragment &) {
return Data::CreditsHistoryEntry::PeerType::Fragment;
}, [](const MTPDstarsTransactionPeerAppStore &) {
return Data::CreditsHistoryEntry::PeerType::AppStore;
}, [](const MTPDstarsTransactionPeerUnsupported &) {
return Data::CreditsHistoryEntry::PeerType::Unsupported;
}, [](const MTPDstarsTransactionPeerPremiumBot &) {
return Data::CreditsHistoryEntry::PeerType::PremiumBot;
}),
.refunded = tl.data().is_refund(),
};
}
[[nodiscard]] Data::CreditsStatusSlice StatusFromTL(
const MTPpayments_StarsStatus &status,
not_null<PeerData*> peer) {
peer->owner().processUsers(status.data().vusers());
peer->owner().processChats(status.data().vchats());
return Data::CreditsStatusSlice{
.list = ranges::views::all(
status.data().vhistory().v
) | ranges::views::transform([&](const MTPStarsTransaction &tl) {
return HistoryFromTL(tl, peer);
}) | ranges::to_vector,
.balance = status.data().vbalance().v,
.allLoaded = !status.data().vnext_offset().has_value(),
.token = qs(status.data().vnext_offset().value_or_empty()),
};
}
} // namespace
CreditsTopupOptions::CreditsTopupOptions(not_null<PeerData*> peer)
: _peer(peer)
, _api(&peer->session().api().instance()) {
}
rpl::producer<rpl::no_value, QString> CreditsTopupOptions::request() {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
using TLOption = MTPStarsTopupOption;
_api.request(MTPpayments_GetStarsTopupOptions(
)).done([=](const MTPVector<TLOption> &result) {
_options = ranges::views::all(
result.v
) | ranges::views::transform([](const TLOption &option) {
return Data::CreditTopupOption{
.credits = option.data().vstars().v,
.product = qs(
option.data().vstore_product().value_or_empty()),
.currency = qs(option.data().vcurrency()),
.amount = option.data().vamount().v,
.extended = option.data().is_extended(),
};
}) | ranges::to_vector;
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return lifetime;
};
}
CreditsStatus::CreditsStatus(not_null<PeerData*> peer)
: _peer(peer)
, _api(&peer->session().api().instance()) {
}
void CreditsStatus::request(
const Data::CreditsStatusSlice::OffsetToken &token,
Fn<void(Data::CreditsStatusSlice)> done) {
if (_requestId) {
return;
}
using TLResult = MTPpayments_StarsStatus;
_requestId = _api.request(MTPpayments_GetStarsStatus(
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input
)).done([=](const TLResult &result) {
_requestId = 0;
done(StatusFromTL(result, _peer));
}).fail([=] {
_requestId = 0;
done({});
}).send();
}
CreditsHistory::CreditsHistory(not_null<PeerData*> peer, bool in, bool out)
: _peer(peer)
, _flags((in == out)
? HistoryTL::Flags(0)
: HistoryTL::Flags(0)
| (in ? HistoryTL::Flag::f_inbound : HistoryTL::Flags(0))
| (out ? HistoryTL::Flag::f_outbound : HistoryTL::Flags(0)))
, _api(&peer->session().api().instance()) {
}
void CreditsHistory::request(
const Data::CreditsStatusSlice::OffsetToken &token,
Fn<void(Data::CreditsStatusSlice)> done) {
if (_requestId) {
return;
}
_requestId = _api.request(MTPpayments_GetStarsTransactions(
MTP_flags(_flags),
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input,
MTP_string(token)
)).done([=](const MTPpayments_StarsStatus &result) {
_requestId = 0;
done(StatusFromTL(result, _peer));
}).fail([=] {
_requestId = 0;
done({});
}).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>(
u"premium_bot_username"_q,
QString());
if (username.isEmpty()) {
return rpl::never<not_null<PeerData*>>();
}
if (const auto p = session->data().peerByUsername(username)) {
return rpl::single<not_null<PeerData*>>(p);
}
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
const auto api = lifetime.make_state<MTP::Sender>(&session->mtp());
api->request(MTPcontacts_ResolveUsername(
MTP_string(username)
)).done([=](const MTPcontacts_ResolvedPeer &result) {
session->data().processUsers(result.data().vusers());
session->data().processChats(result.data().vchats());
const auto botPeer = session->data().peerLoaded(
peerFromMTP(result.data().vpeer()));
if (!botPeer) {
return consumer.put_done();
}
consumer.put_next(not_null{ botPeer });
}).send();
return lifetime;
};
}
void CreditsRefund(
not_null<PeerData*> peer,
const QString &entryId,
Fn<void()> done,
Fn<void(QString)> fail) {
const auto user = peer->asUser();
if (!user) {
return;
}
peer->session().api().request(MTPpayments_RefundStarsCharge(
user->inputUser,
MTP_string(entryId)
)).done([=](const MTPUpdates &result) {
peer->session().api().updates().applyUpdates(result);
done();
}).fail([=](const MTP::Error &error) {
fail(error.type());
}).send();
}
} // namespace Api
+80
View File
@@ -0,0 +1,80 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "data/data_credits.h"
#include "mtproto/sender.h"
namespace Main {
class Session;
} // namespace Main
namespace Api {
class CreditsTopupOptions final {
public:
CreditsTopupOptions(not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
[[nodiscard]] Data::CreditTopupOptions options() const;
private:
const not_null<PeerData*> _peer;
Data::CreditTopupOptions _options;
MTP::Sender _api;
};
class CreditsStatus final {
public:
CreditsStatus(not_null<PeerData*> peer);
void request(
const Data::CreditsStatusSlice::OffsetToken &token,
Fn<void(Data::CreditsStatusSlice)> done);
private:
const not_null<PeerData*> _peer;
mtpRequestId _requestId = 0;
MTP::Sender _api;
};
class CreditsHistory final {
public:
CreditsHistory(not_null<PeerData*> peer, bool in, bool out);
void request(
const Data::CreditsStatusSlice::OffsetToken &token,
Fn<void(Data::CreditsStatusSlice)> done);
private:
using HistoryTL = MTPpayments_GetStarsTransactions;
const not_null<PeerData*> _peer;
const HistoryTL::Flags _flags;
mtpRequestId _requestId = 0;
MTP::Sender _api;
};
void CreditsRefund(
not_null<PeerData*> peer,
const QString &entryId,
Fn<void()> done,
Fn<void(QString)> fail);
[[nodiscard]] rpl::producer<not_null<PeerData*>> PremiumPeerBot(
not_null<Main::Session*> session);
} // namespace Api
+95 -3
View File
@@ -13,9 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/confirm_box.h"
#include "data/business/data_shortcut_messages.h"
#include "data/components/scheduled_messages.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h"
#include "data/data_session.h"
#include "data/data_web_page.h"
#include "history/view/controls/history_view_compose_media_edit_manager.h"
#include "history/history.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
@@ -80,7 +82,8 @@ mtpRequestId EditMessage(
| ((!webpage.removed && !webpage.url.isEmpty())
? MTPmessages_EditMessage::Flag::f_media
: emptyFlag)
| ((!webpage.removed && !webpage.url.isEmpty() && webpage.invert)
| (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert)
|| options.invertCaption)
? MTPmessages_EditMessage::Flag::f_invert_media
: emptyFlag)
| (!sentEntities.v.isEmpty()
@@ -202,6 +205,7 @@ void RescheduleMessage(
not_null<HistoryItem*> item,
SendOptions options) {
const auto empty = [] {};
options.invertCaption = item->invertMedia();
EditMessage(item, options, empty, empty);
}
@@ -252,12 +256,100 @@ mtpRequestId EditTextMessage(
Data::WebPageDraft webpage,
SendOptions options,
Fn<void(mtpRequestId requestId)> done,
Fn<void(const QString &, mtpRequestId requestId)> fail) {
Fn<void(const QString &error, mtpRequestId requestId)> fail,
bool spoilered) {
const auto media = item->media();
if (media
&& HistoryView::MediaEditManager::CanBeSpoilered(item)
&& spoilered != media->hasSpoiler()) {
auto takeInputMedia = Fn<std::optional<MTPInputMedia>()>(nullptr);
auto takeFileReference = Fn<QByteArray()>(nullptr);
if (const auto photo = media->photo()) {
using Flag = MTPDinputMediaPhoto::Flag;
const auto flags = Flag()
| (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
| (spoilered ? Flag::f_spoiler : Flag());
takeInputMedia = [=] {
return MTP_inputMediaPhoto(
MTP_flags(flags),
photo->mtpInput(),
MTP_int(media->ttlSeconds()));
};
takeFileReference = [=] { return photo->fileReference(); };
} else if (const auto document = media->document()) {
using Flag = MTPDinputMediaDocument::Flag;
const auto flags = Flag()
| (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
| (spoilered ? Flag::f_spoiler : Flag());
takeInputMedia = [=] {
return MTP_inputMediaDocument(
MTP_flags(flags),
document->mtpInput(),
MTP_int(media->ttlSeconds()),
MTPstring()); // query
};
takeFileReference = [=] { return document->fileReference(); };
}
const auto usedFileReference = takeFileReference
? takeFileReference()
: QByteArray();
const auto origin = item->fullId();
const auto api = &item->history()->session().api();
const auto performRequest = [=](
const auto &repeatRequest,
mtpRequestId originalRequestId) -> mtpRequestId {
const auto handleReference = [=](
const QString &error,
mtpRequestId requestId) {
if (error.startsWith(u"FILE_REFERENCE_"_q)) {
api->refreshFileReference(origin, [=](const auto &) {
if (takeFileReference &&
(takeFileReference() != usedFileReference)) {
repeatRequest(
repeatRequest,
originalRequestId
? originalRequestId
: requestId);
} else {
fail(error, requestId);
}
});
} else {
fail(error, requestId);
}
};
const auto callback = [=](
Fn<void()> applyUpdates,
mtpRequestId requestId) {
applyUpdates();
done(originalRequestId ? originalRequestId : requestId);
};
const auto requestId = EditMessage(
item,
caption,
webpage,
options,
callback,
handleReference,
takeInputMedia ? takeInputMedia() : std::nullopt);
return originalRequestId ? originalRequestId : requestId;
};
return performRequest(performRequest, 0);
}
const auto callback = [=](Fn<void()> applyUpdates, mtpRequestId id) {
applyUpdates();
done(id);
};
return EditMessage(item, caption, webpage, options, callback, fail);
return EditMessage(
item,
caption,
webpage,
options,
callback,
fail,
std::nullopt);
}
} // namespace Api
+2 -1
View File
@@ -55,6 +55,7 @@ mtpRequestId EditTextMessage(
Data::WebPageDraft webpage,
SendOptions options,
Fn<void(mtpRequestId requestId)> done,
Fn<void(const QString &error, mtpRequestId requestId)> fail);
Fn<void(const QString &error, mtpRequestId requestId)> fail,
bool spoilered);
} // namespace Api
+5 -1
View File
@@ -73,6 +73,9 @@ void Polls::create(
if (action.options.shortcutId) {
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
if (action.options.effectId) {
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
}
const auto sendAs = action.options.sendAs;
if (sendAs) {
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
@@ -94,7 +97,8 @@ void Polls::create(
MTPVector<MTPMessageEntity>(),
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, action.options.shortcutId)
Data::ShortcutIdToMTP(_session, action.options.shortcutId),
MTP_long(action.options.effectId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
if (clearCloudDraft) {
history->finishSavingCloudDraft(
+35
View File
@@ -602,6 +602,41 @@ bool PremiumGiftCodeOptions::giveawayGiftsPurchaseAvailable() const {
false);
}
SponsoredToggle::SponsoredToggle(not_null<Main::Session*> session)
: _api(&session->api().instance()) {
}
rpl::producer<bool> SponsoredToggle::toggled() {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
_api.request(MTPusers_GetFullUser(
MTP_inputUserSelf()
)).done([=](const MTPusers_UserFull &result) {
consumer.put_next_copy(
result.data().vfull_user().data().is_sponsored_enabled());
}).fail([=] { consumer.put_next(false); }).send();
return lifetime;
};
}
rpl::producer<rpl::no_value, QString> SponsoredToggle::setToggled(bool v) {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
_api.request(MTPaccount_ToggleSponsoredMessages(
MTP_bool(v)
)).done([=] {
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return lifetime;
};
}
RequirePremiumState ResolveRequiresPremiumToWrite(
not_null<PeerData*> peer,
History *maybeHistory) {
+12
View File
@@ -216,6 +216,18 @@ private:
};
class SponsoredToggle final {
public:
explicit SponsoredToggle(not_null<Main::Session*> session);
[[nodiscard]] rpl::producer<bool> toggled();
[[nodiscard]] rpl::producer<rpl::no_value, QString> setToggled(bool);
private:
MTP::Sender _api;
};
enum class RequirePremiumState {
Unknown,
Yes,
+25 -2
View File
@@ -133,6 +133,13 @@ void SendExistingMedia(
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
if (action.options.effectId) {
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
}
if (action.options.invertCaption) {
flags |= MessageFlag::InvertMedia;
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
}
session->data().registerMessageRandomId(randomId, newId);
@@ -144,6 +151,7 @@ void SendExistingMedia(
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
.effectId = action.options.effectId,
}, media, caption);
const auto performRequest = [=](const auto &repeatRequest) -> void {
@@ -165,7 +173,8 @@ void SendExistingMedia(
sentEntities,
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(session, action.options.shortcutId)
Data::ShortcutIdToMTP(session, action.options.shortcutId),
MTP_long(action.options.effectId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
}, [=](const MTP::Error &error, const MTP::Response &response) {
if (error.code() == 400
@@ -306,6 +315,13 @@ bool SendDice(MessageToSend &message) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
if (action.options.effectId) {
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
}
if (action.options.invertCaption) {
flags |= MessageFlag::InvertMedia;
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
}
session->data().registerMessageRandomId(randomId, newId);
@@ -317,6 +333,7 @@ bool SendDice(MessageToSend &message) {
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
.effectId = action.options.effectId,
}, TextWithEntities(), MTP_messageMediaDice(
MTP_int(0),
MTP_string(emoji)));
@@ -335,7 +352,8 @@ bool SendDice(MessageToSend &message) {
MTP_vector<MTPMessageEntity>(),
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(session, action.options.shortcutId)
Data::ShortcutIdToMTP(session, action.options.shortcutId),
MTP_long(action.options.effectId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
}, [=](const MTP::Error &error, const MTP::Response &response) {
api->sendMessageFail(error, peer, randomId, newId);
@@ -430,6 +448,9 @@ void SendConfirmedFile(
flags |= MessageFlag::MediaIsUnread;
}
}
if (file->to.options.invertCaption) {
flags |= MessageFlag::InvertMedia;
}
const auto messageFromId = file->to.options.sendAs
? file->to.options.sendAs->id
@@ -493,6 +514,7 @@ void SendConfirmedFile(
edition.ttl = 0;
edition.mtpMedia = &media;
edition.textWithEntities = caption;
edition.invertMedia = file->to.options.invertCaption;
edition.useSameViews = true;
edition.useSameForwards = true;
edition.useSameMarkup = true;
@@ -510,6 +532,7 @@ void SendConfirmedFile(
.shortcutId = file->to.options.shortcutId,
.postAuthor = messagePostAuthor,
.groupedId = groupId,
.effectId = file->to.options.effectId,
}, caption, media);
}
+4 -4
View File
@@ -760,14 +760,14 @@ rpl::producer<rpl::no_value, QString> EarnStatistics::request() {
channel()->inputChannel
)).done([=](const MTPstats_BroadcastRevenueStats &result) {
const auto &data = result.data();
const auto &balances = data.vbalances().data();
_data = Data::EarnStatistics{
.topHoursGraph = StatisticalGraphFromTL(
data.vtop_hours_graph()),
.revenueGraph = StatisticalGraphFromTL(data.vrevenue_graph()),
.currentBalance = data.vcurrent_balance().v,
.availableBalance = data.vavailable_balance().v,
.overallRevenue = data.voverall_revenue().v,
.currentBalance = balances.vcurrent_balance().v,
.availableBalance = balances.vavailable_balance().v,
.overallRevenue = balances.voverall_revenue().v,
.usdRate = data.vusd_rate().v,
};
+241 -81
View File
@@ -7,12 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_text_entities.h"
#include "main/main_session.h"
#include "data/data_document.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h"
#include "data/stickers/data_stickers_set.h"
#include "data/data_session.h"
#include "data/data_document.h"
#include "data/data_user.h"
#include "main/main_session.h"
namespace Api {
namespace {
@@ -62,67 +62,168 @@ using namespace TextUtilities;
EntitiesInText EntitiesFromMTP(
Main::Session *session,
const QVector<MTPMessageEntity> &entities) {
if (entities.isEmpty()) {
return {};
}
auto result = EntitiesInText();
if (!entities.isEmpty()) {
result.reserve(entities.size());
for (const auto &entity : entities) {
switch (entity.type()) {
case mtpc_messageEntityUrl: { auto &d = entity.c_messageEntityUrl(); result.push_back({ EntityType::Url, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityTextUrl: { auto &d = entity.c_messageEntityTextUrl(); result.push_back({ EntityType::CustomUrl, d.voffset().v, d.vlength().v, qs(d.vurl()) }); } break;
case mtpc_messageEntityEmail: { auto &d = entity.c_messageEntityEmail(); result.push_back({ EntityType::Email, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityHashtag: { auto &d = entity.c_messageEntityHashtag(); result.push_back({ EntityType::Hashtag, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityCashtag: { auto &d = entity.c_messageEntityCashtag(); result.push_back({ EntityType::Cashtag, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityPhone: break; // Skipping phones.
case mtpc_messageEntityMention: { auto &d = entity.c_messageEntityMention(); result.push_back({ EntityType::Mention, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityMentionName: if (session) {
const auto &d = entity.c_messageEntityMentionName();
const auto userId = UserId(d.vuser_id());
const auto user = session->data().userLoaded(userId);
const auto data = MentionNameDataFromFields({
.selfId = session->userId().bare,
.userId = userId.bare,
.accessHash = user ? user->accessHash() : 0,
});
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
} break;
case mtpc_inputMessageEntityMentionName: if (session) {
const auto &d = entity.c_inputMessageEntityMentionName();
const auto data = d.vuser_id().match([&](
const MTPDinputUserSelf &) {
return MentionNameDataFromFields({
.selfId = session->userId().bare,
.userId = session->userId().bare,
.accessHash = session->user()->accessHash(),
});
}, [&](const MTPDinputUser &data) {
return MentionNameDataFromFields({
.selfId = session->userId().bare,
.userId = UserId(data.vuser_id()).bare,
.accessHash = data.vaccess_hash().v,
});
}, [&](const auto &) {
return QString();
});
if (!data.isEmpty()) {
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
}
} break;
case mtpc_messageEntityBotCommand: { auto &d = entity.c_messageEntityBotCommand(); result.push_back({ EntityType::BotCommand, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityBold: { auto &d = entity.c_messageEntityBold(); result.push_back({ EntityType::Bold, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityItalic: { auto &d = entity.c_messageEntityItalic(); result.push_back({ EntityType::Italic, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityUnderline: { auto &d = entity.c_messageEntityUnderline(); result.push_back({ EntityType::Underline, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityStrike: { auto &d = entity.c_messageEntityStrike(); result.push_back({ EntityType::StrikeOut, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset().v, d.vlength().v, qs(d.vlanguage()) }); } break;
case mtpc_messageEntityBlockquote: { auto &d = entity.c_messageEntityBlockquote(); result.push_back({ EntityType::Blockquote, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityBankCard: break; // Skipping cards. // #TODO entities
case mtpc_messageEntitySpoiler: { auto &d = entity.c_messageEntitySpoiler(); result.push_back({ EntityType::Spoiler, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityCustomEmoji: {
const auto &d = entity.c_messageEntityCustomEmoji();
result.push_back({ EntityType::CustomEmoji, d.voffset().v, d.vlength().v, CustomEmojiEntityData(d) });
} break;
result.reserve(entities.size());
for (const auto &entity : entities) {
entity.match([&](const MTPDmessageEntityUnknown &d) {
}, [&](const MTPDmessageEntityMention &d) {
result.push_back({
EntityType::Mention,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityHashtag &d) {
result.push_back({
EntityType::Hashtag,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityBotCommand &d) {
result.push_back({
EntityType::BotCommand,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityUrl &d) {
result.push_back({
EntityType::Url,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityEmail &d) {
result.push_back({
EntityType::Email,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityBold &d) {
result.push_back({
EntityType::Bold,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityItalic &d) {
result.push_back({
EntityType::Italic,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityCode &d) {
result.push_back({
EntityType::Code,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityPre &d) {
result.push_back({
EntityType::Pre,
d.voffset().v,
d.vlength().v,
qs(d.vlanguage()),
});
}, [&](const MTPDmessageEntityTextUrl &d) {
result.push_back({
EntityType::CustomUrl,
d.voffset().v,
d.vlength().v,
qs(d.vurl()),
});
}, [&](const MTPDmessageEntityMentionName &d) {
if (!session) {
return;
}
}
const auto userId = UserId(d.vuser_id());
const auto user = session->data().userLoaded(userId);
const auto data = MentionNameDataFromFields({
.selfId = session->userId().bare,
.userId = userId.bare,
.accessHash = user ? user->accessHash() : 0,
});
result.push_back({
EntityType::MentionName,
d.voffset().v,
d.vlength().v,
data,
});
}, [&](const MTPDinputMessageEntityMentionName &d) {
if (!session) {
return;
}
const auto data = d.vuser_id().match([&](
const MTPDinputUserSelf &) {
return MentionNameDataFromFields({
.selfId = session->userId().bare,
.userId = session->userId().bare,
.accessHash = session->user()->accessHash(),
});
}, [&](const MTPDinputUser &data) {
return MentionNameDataFromFields({
.selfId = session->userId().bare,
.userId = UserId(data.vuser_id()).bare,
.accessHash = data.vaccess_hash().v,
});
}, [](const auto &) {
return QString();
});
if (!data.isEmpty()) {
result.push_back({
EntityType::MentionName,
d.voffset().v,
d.vlength().v,
data,
});
}
}, [&](const MTPDmessageEntityPhone &d) {
result.push_back({
EntityType::Phone,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityCashtag &d) {
result.push_back({
EntityType::Cashtag,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityUnderline &d) {
result.push_back({
EntityType::Underline,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityStrike &d) {
result.push_back({
EntityType::StrikeOut,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityBankCard &d) {
// Skipping cards. // #TODO entities
}, [&](const MTPDmessageEntitySpoiler &d) {
result.push_back({
EntityType::Spoiler,
d.voffset().v,
d.vlength().v,
});
}, [&](const MTPDmessageEntityCustomEmoji &d) {
result.push_back({
EntityType::CustomEmoji,
d.voffset().v,
d.vlength().v,
CustomEmojiEntityData(d),
});
}, [&](const MTPDmessageEntityBlockquote &d) {
result.push_back({
EntityType::Blockquote,
d.voffset().v,
d.vlength().v,
d.is_collapsed() ? u"1"_q : QString(),
});
});
}
return result;
}
@@ -134,7 +235,9 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
auto v = QVector<MTPMessageEntity>();
v.reserve(entities.size());
for (const auto &entity : entities) {
if (entity.length() <= 0) continue;
if (entity.length() <= 0) {
continue;
}
if (option == ConvertOption::SkipLocal
&& entity.type() != EntityType::Bold
//&& entity.type() != EntityType::Semibold // Not in API.
@@ -154,28 +257,85 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
auto offset = MTP_int(entity.offset());
auto length = MTP_int(entity.length());
switch (entity.type()) {
case EntityType::Url: v.push_back(MTP_messageEntityUrl(offset, length)); break;
case EntityType::CustomUrl: v.push_back(MTP_messageEntityTextUrl(offset, length, MTP_string(entity.data()))); break;
case EntityType::Email: v.push_back(MTP_messageEntityEmail(offset, length)); break;
case EntityType::Hashtag: v.push_back(MTP_messageEntityHashtag(offset, length)); break;
case EntityType::Cashtag: v.push_back(MTP_messageEntityCashtag(offset, length)); break;
case EntityType::Mention: v.push_back(MTP_messageEntityMention(offset, length)); break;
case EntityType::Url: {
v.push_back(MTP_messageEntityUrl(offset, length));
} break;
case EntityType::CustomUrl: {
v.push_back(
MTP_messageEntityTextUrl(
offset,
length,
MTP_string(entity.data())));
} break;
case EntityType::Email: {
v.push_back(MTP_messageEntityEmail(offset, length));
} break;
case EntityType::Phone: {
v.push_back(MTP_messageEntityPhone(offset, length));
} break;
case EntityType::Hashtag: {
v.push_back(MTP_messageEntityHashtag(offset, length));
} break;
case EntityType::Cashtag: {
v.push_back(MTP_messageEntityCashtag(offset, length));
} break;
case EntityType::Mention: {
v.push_back(MTP_messageEntityMention(offset, length));
} break;
case EntityType::MentionName: {
if (const auto valid = MentionNameEntity(session, offset, length, entity.data())) {
const auto valid = MentionNameEntity(
session,
offset,
length,
entity.data());
if (valid) {
v.push_back(*valid);
}
} break;
case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break;
case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break;
case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break;
case EntityType::Underline: v.push_back(MTP_messageEntityUnderline(offset, length)); break;
case EntityType::StrikeOut: v.push_back(MTP_messageEntityStrike(offset, length)); break;
case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities
case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break;
case EntityType::Blockquote: v.push_back(MTP_messageEntityBlockquote(offset, length)); break;
case EntityType::Spoiler: v.push_back(MTP_messageEntitySpoiler(offset, length)); break;
case EntityType::BotCommand: {
v.push_back(MTP_messageEntityBotCommand(offset, length));
} break;
case EntityType::Bold: {
v.push_back(MTP_messageEntityBold(offset, length));
} break;
case EntityType::Italic: {
v.push_back(MTP_messageEntityItalic(offset, length));
} break;
case EntityType::Underline: {
v.push_back(MTP_messageEntityUnderline(offset, length));
} break;
case EntityType::StrikeOut: {
v.push_back(MTP_messageEntityStrike(offset, length));
} break;
case EntityType::Code: {
// #TODO entities.
v.push_back(MTP_messageEntityCode(offset, length));
} break;
case EntityType::Pre: {
v.push_back(
MTP_messageEntityPre(
offset,
length,
MTP_string(entity.data())));
} break;
case EntityType::Blockquote: {
using Flag = MTPDmessageEntityBlockquote::Flag;
const auto collapsed = !entity.data().isEmpty();
v.push_back(
MTP_messageEntityBlockquote(
MTP_flags(collapsed ? Flag::f_collapsed : Flag()),
offset,
length));
} break;
case EntityType::Spoiler: {
v.push_back(MTP_messageEntitySpoiler(offset, length));
} break;
case EntityType::CustomEmoji: {
if (const auto valid = CustomEmojiEntity(offset, length, entity.data())) {
const auto valid = CustomEmojiEntity(
offset,
length,
entity.data());
if (valid) {
v.push_back(*valid);
}
} break;
+17 -2
View File
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtproto_dc_options.h"
#include "data/business/data_shortcut_messages.h"
#include "data/components/scheduled_messages.h"
#include "data/components/top_peers.h"
#include "data/notify/data_notify_settings.h"
#include "data/stickers/data_stickers.h"
#include "data/data_saved_messages.h"
@@ -1144,7 +1145,9 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
MTPMessageReactions(),
MTPVector<MTPRestrictionReason>(),
MTP_int(d.vttl_period().value_or_empty()),
MTPint()), // quick_reply_shortcut_id
MTPint(), // quick_reply_shortcut_id
MTPlong(), // effect
MTPFactCheck()),
MessageFlags(),
NewMessageType::Unread);
} break;
@@ -1179,7 +1182,9 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
MTPMessageReactions(),
MTPVector<MTPRestrictionReason>(),
MTP_int(d.vttl_period().value_or_empty()),
MTPint()), // quick_reply_shortcut_id
MTPint(), // quick_reply_shortcut_id
MTPlong(), // effect
MTPFactCheck()),
MessageFlags(),
NewMessageType::Unread);
} break;
@@ -1585,6 +1590,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
} else {
if (existing) {
existing->destroy();
} else {
// Not the server-side date, but close enough.
session().topPeers().increment(
local->history()->peer,
local->date());
}
local->setRealId(d.vid().v);
}
@@ -2612,6 +2622,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
_session->data().stories().apply(data.vstealth_mode());
} break;
case mtpc_updateStarsBalance: {
const auto &data = update.c_updateStarsBalance();
_session->setCredits(data.vbalance().v);
} break;
}
}
+66 -7
View File
@@ -50,6 +50,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_chat_filters.h"
#include "data/data_histories.h"
#include "data/data_history_messages.h"
#include "core/core_cloud_password.h"
#include "core/application.h"
#include "base/unixtime.h"
@@ -3117,6 +3118,46 @@ void ApiWrap::resolveJumpToHistoryDate(
}
}
void ApiWrap::requestHistory(
not_null<History*> history,
MsgId messageId,
SliceType slice) {
const auto peer = history->peer;
const auto key = HistoryRequest{
peer,
messageId,
slice,
};
if (_historyRequests.contains(key)) {
return;
}
const auto prepared = Api::PrepareHistoryRequest(peer, messageId, slice);
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::History;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
return request(
std::move(prepared)
).done([=](const Api::HistoryRequestResult &result) {
_historyRequests.remove(key);
auto parsed = Api::ParseHistoryResult(
peer,
messageId,
slice,
result);
history->messages().addSlice(
std::move(parsed.messageIds),
parsed.noSkipRange,
parsed.fullCount);
finish();
}).fail([=] {
_historyRequests.remove(key);
finish();
}).send();
});
_historyRequests.emplace(key);
}
void ApiWrap::requestSharedMedia(
not_null<PeerData*> peer,
MsgId topicRootId,
@@ -3388,6 +3429,9 @@ void ApiWrap::forwardMessages(
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
// forwarded messages don't have effects
//.effectId = action.options.effectId,
}, item);
_session->data().registerMessageRandomId(randomId, newId);
if (!localIds) {
@@ -3488,6 +3532,7 @@ void ApiWrap::sendSharedContact(
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
.effectId = action.options.effectId,
}, TextWithEntities(), MTP_messageMediaContact(
MTP_string(phone),
MTP_string(firstName),
@@ -3790,7 +3835,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, action.options);
FillMessagePostFlags(action, peer, flags);
if (exactWebPage && !ignoreWebPage && message.webPage.invert) {
if ((exactWebPage && !ignoreWebPage && message.webPage.invert)
|| action.options.invertCaption) {
flags |= MessageFlag::InvertMedia;
sendFlags |= MTPmessages_SendMessage::Flag::f_invert_media;
mediaFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
@@ -3836,6 +3882,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
sendFlags |= MTPmessages_SendMessage::Flag::f_quick_reply_shortcut;
mediaFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
if (action.options.effectId) {
sendFlags |= MTPmessages_SendMessage::Flag::f_effect;
mediaFlags |= MTPmessages_SendMedia::Flag::f_effect;
}
lastMessage = history->addNewLocalMessage({
.id = newId.msg,
.flags = flags,
@@ -3844,6 +3894,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
.date = HistoryItem::NewMessageDate(action.options),
.shortcutId = action.options.shortcutId,
.postAuthor = messagePostAuthor,
.effectId = action.options.effectId,
}, sending, media);
const auto done = [=](
const MTPUpdates &result,
@@ -3891,7 +3942,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
sentEntities,
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
mtpShortcut
mtpShortcut,
MTP_long(action.options.effectId)
), done, fail);
} else {
histories.sendPreparedMessage(
@@ -3908,7 +3960,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
sentEntities,
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
mtpShortcut
mtpShortcut,
MTP_long(action.options.effectId)
), done, fail);
}
isFirst = false;
@@ -4191,7 +4244,9 @@ void ApiWrap::sendMediaWithRandomId(
| (!sentEntities.v.isEmpty() ? Flag::f_entities : Flag(0))
| (options.scheduled ? Flag::f_schedule_date : Flag(0))
| (options.sendAs ? Flag::f_send_as : Flag(0))
| (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0));
| (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0))
| (options.effectId ? Flag::f_effect : Flag(0))
| (options.invertCaption ? Flag::f_invert_media : Flag(0));
auto &histories = history->owner().histories();
const auto peer = history->peer;
@@ -4211,7 +4266,8 @@ void ApiWrap::sendMediaWithRandomId(
sentEntities,
MTP_int(options.scheduled),
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, options.shortcutId)
Data::ShortcutIdToMTP(_session, options.shortcutId),
MTP_long(options.effectId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
if (done) done(true);
if (updateRecentStickers) {
@@ -4309,7 +4365,9 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
| (sendAs ? Flag::f_send_as : Flag(0))
| (album->options.shortcutId
? Flag::f_quick_reply_shortcut
: Flag(0));
: Flag(0))
| (album->options.effectId ? Flag::f_effect : Flag(0))
| (album->options.invertCaption ? Flag::f_invert_media : Flag(0));
auto &histories = history->owner().histories();
const auto peer = history->peer;
histories.sendPreparedMessage(
@@ -4323,7 +4381,8 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
MTP_vector<MTPInputSingleMedia>(medias),
MTP_int(album->options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, album->options.shortcutId)
Data::ShortcutIdToMTP(_session, album->options.shortcutId),
MTP_long(album->options.effectId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
_sendingAlbums.remove(groupId);
+17 -1
View File
@@ -274,6 +274,10 @@ public:
Fn<void(not_null<PeerData*>, MsgId)> callback);
using SliceType = Data::LoadDirection;
void requestHistory(
not_null<History*> history,
MsgId messageId,
SliceType slice);
void requestSharedMedia(
not_null<PeerData*> peer,
MsgId topicRootId,
@@ -511,7 +515,8 @@ private:
not_null<PeerData*> peer,
bool justClear,
bool revoke);
void applyAffectedMessages(const MTPmessages_AffectedMessages &result) const;
void applyAffectedMessages(
const MTPmessages_AffectedMessages &result) const;
void deleteAllFromParticipantSend(
not_null<ChannelData*> channel,
@@ -645,6 +650,17 @@ private:
};
base::flat_set<SharedMediaRequest> _sharedMediaRequests;
struct HistoryRequest {
not_null<PeerData*> peer;
MsgId aroundId = 0;
SliceType sliceType = {};
friend inline auto operator<=>(
const HistoryRequest&,
const HistoryRequest&) = default;
};
base::flat_set<HistoryRequest> _historyRequests;
std::unique_ptr<DialogsLoadState> _dialogsLoadState;
TimeId _dialogsLoadTill = 0;
rpl::variable<bool> _dialogsLoadMayBlockByDate = false;
-1
View File
@@ -29,7 +29,6 @@ void initLang() {
void initFonts() {
auto settings = &AyuSettings::getInstance();
AyuFonts::setMainFont(settings->mainFont);
AyuFonts::setMonoFont(settings->monoFont);
}
-10
View File
@@ -207,7 +207,6 @@ AyuGramSettings::AyuGramSettings() {
disableNotificationsDelay = false;
localPremium = false;
copyUsernameAsLink = true;
// ~ Customization
appIcon = AyuAssets::DEFAULT_ICON;
@@ -234,7 +233,6 @@ AyuGramSettings::AyuGramSettings() {
showGhostToggleInTray = true;
showStreamerToggleInTray = false;
mainFont = "";
monoFont = "";
hideNotificationCounters = false;
@@ -342,10 +340,6 @@ void AyuGramSettings::set_localPremium(bool val) {
localPremium = val;
}
void AyuGramSettings::set_copyUsernameAsLink(bool val) {
copyUsernameAsLink = val;
}
void AyuGramSettings::set_appIcon(QString val) {
appIcon = std::move(val);
}
@@ -412,10 +406,6 @@ void AyuGramSettings::set_showStreamerToggleInTray(bool val) {
showStreamerToggleInTray = val;
}
void AyuGramSettings::set_mainFont(QString val) {
mainFont = val;
}
void AyuGramSettings::set_monoFont(QString val) {
monoFont = val;
}
-6
View File
@@ -39,7 +39,6 @@ public:
bool disableNotificationsDelay;
bool localPremium;
bool copyUsernameAsLink;
QString appIcon;
bool simpleQuotesAndReplies;
@@ -61,7 +60,6 @@ public:
bool showGhostToggleInTray;
bool showStreamerToggleInTray;
QString mainFont;
QString monoFont;
bool hideNotificationCounters;
@@ -99,7 +97,6 @@ public:
void set_disableNotificationsDelay(bool val);
void set_localPremium(bool val);
void set_copyUsernameAsLink(bool val);
void set_appIcon(QString val);
void set_simpleQuotesAndReplies(bool val);
@@ -121,7 +118,6 @@ public:
void set_showGhostToggleInTray(bool val);
void set_showStreamerToggleInTray(bool val);
void set_mainFont(QString val);
void set_monoFont(QString val);
void set_hideNotificationCounters(bool val);
@@ -155,7 +151,6 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
hideSimilarChannels,
disableNotificationsDelay,
localPremium,
copyUsernameAsLink,
appIcon,
simpleQuotesAndReplies,
deletedMark,
@@ -172,7 +167,6 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
showStreamerToggleInDrawer,
showGhostToggleInTray,
showStreamerToggleInTray,
mainFont,
monoFont,
hideNotificationCounters,
hideAllChatsFolder,
@@ -665,7 +665,7 @@ void Content::setupContent(
const std::vector<Font> &fonts) {
using namespace rpl::mappers;
const auto current = AyuFonts::getMainFont();
const auto current = AyuFonts::getMonoFont();
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
const auto add = [&](const std::vector<Font> &list)
{
@@ -27,6 +27,7 @@
#include "ayu/ui/sections/edited/edited_log_section.h"
#include "ayu/utils/telegram_helpers.h"
#include "base/unixtime.h"
#include "history/view/history_view_context_menu.h"
#include "history/view/history_view_element.h"
#include "window/window_session_controller.h"
@@ -77,22 +78,23 @@ void AddUserMessagesAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
}
if (item->history()->peer->isChat() || item->history()->peer->isMegagroup()) {
menu->addAction(tr::ayu_UserMessagesMenuText(tr::now),
[=]
{
if (const auto window = item->history()->session().tryResolveWindow()) {
if (const auto mainWidget = window->widget()->sessionController()) {
const auto peer = item->history()->peer;
const auto key = (peer && !peer->isUser())
? item->topic()
? Dialogs::Key{item->topic()}
: Dialogs::Key{item->history()}
: Dialogs::Key();
mainWidget->content()->searchMessages(QString(), key, item->from()->asUser());
}
}
},
&st::menuIconTTL);
menu->addAction(
tr::ayu_UserMessagesMenuText(tr::now),
[=]
{
if (const auto window = item->history()->session().tryResolveWindow()) {
if (const auto mainWidget = window->widget()->sessionController()) {
const auto peer = item->history()->peer;
const auto key = (peer && !peer->isUser())
? item->topic()
? Dialogs::Key{item->topic()}
: Dialogs::Key{item->history()}
: Dialogs::Key();
mainWidget->content()->searchMessages(QString(), key, item->from()->asUser());
}
}
},
&st::menuIconTTL);
}
}
@@ -112,6 +114,22 @@ void AddMessageDetailsAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
const auto media = item->media();
const auto isSticker = media && media->document() && media->document()->sticker();
const auto emojiPacks = HistoryView::CollectEmojiPacks(item, HistoryView::EmojiPacksSource::Message);
auto containsSingleCustomEmojiPack = emojiPacks.size() == 1;
if (!containsSingleCustomEmojiPack && emojiPacks.size() > 1) {
const auto author = emojiPacks.front().id >> 32;
auto sameAuthor = true;
for (const auto pack : emojiPacks) {
if (pack.id >> 32 != author) {
sameAuthor = false;
break;
}
}
containsSingleCustomEmojiPack = sameAuthor;
}
const auto isForwarded = forwarded && !forwarded->story && forwarded->psaType.isEmpty();
const auto messageId = QString::number(item->id.bare);
@@ -278,6 +296,18 @@ void AddMessageDetailsAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
}
}
}
if (containsSingleCustomEmojiPack) {
const auto authorId = emojiPacks.front().id >> 32;
if (authorId != 0) {
menu2->addAction(Ui::ContextActionStickerAuthor(
menu2->menu(),
&item->history()->session(),
authorId
));
}
}
},
});
}
@@ -610,13 +610,18 @@ void InnerWidget::elementStartInteraction(not_null<const Element*> view) {
}
void InnerWidget::elementStartPremium(
not_null<const Element*> view,
Element *replacing) {
not_null<const HistoryView::Element*> view,
HistoryView::Element *replacing) {
}
void InnerWidget::elementCancelPremium(not_null<const Element*> view) {
}
void InnerWidget::elementStartEffect(
not_null<const Element*> view,
Element *replacing) {
}
QString InnerWidget::elementAuthorRank(not_null<const Element*> view) {
return {};
}
@@ -127,10 +127,11 @@ public:
void elementStartPremium(
not_null<const HistoryView::Element*> view,
HistoryView::Element *replacing) override;
void elementCancelPremium(
not_null<const HistoryView::Element*> view) override;
QString elementAuthorRank(
not_null<const HistoryView::Element*> view) override;
void elementCancelPremium(not_null<const HistoryView::Element*> view) override;
void elementStartEffect(
not_null<const HistoryView::Element*> view,
HistoryView::Element *replacing) override;
QString elementAuthorRank(not_null<const HistoryView::Element*> view) override;
~InnerWidget();
@@ -729,25 +729,6 @@ void SetupQoLToggles(not_null<Ui::VerticalLayout*> container) {
AyuSettings::save();
},
container->lifetime());
AddButtonWithIcon(
container,
tr::ayu_CopyUsernameAsLink(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->copyUsernameAsLink)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->copyUsernameAsLink);
}) | start_with_next(
[=](bool enabled)
{
settings->set_copyUsernameAsLink(enabled);
AyuSettings::save();
},
container->lifetime());
}
void SetupAppIcon(not_null<Ui::VerticalLayout*> container) {
@@ -1068,28 +1049,6 @@ void SetupRecentStickersLimitSlider(not_null<Ui::VerticalLayout*> container) {
void SetupFonts(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
const auto settings = &AyuSettings::getInstance();
const auto commonButton = AddButtonWithLabel(
container,
tr::ayu_MainFont(),
rpl::single(
settings->mainFont.isEmpty() ? tr::ayu_FontDefault(tr::now) : settings->mainFont
),
st::settingsButtonNoIcon);
const auto commonGuard = Ui::CreateChild<base::binary_guard>(commonButton.get());
commonButton->addClickHandler(
[=]
{
*commonGuard = AyuUi::FontSelectorBox::Show(controller,
[=](QString font)
{
auto ayuSettings = &AyuSettings::getInstance();
ayuSettings->set_mainFont(std::move(font));
AyuSettings::save();
});
});
const auto monoButton = AddButtonWithLabel(
container,
tr::ayu_MonospaceFont(),
+14 -6
View File
@@ -192,20 +192,27 @@ void ShowAddParticipantsError(
&& channel
&& !channel->isMegagroup()
&& channel->canAddAdmins()) {
const auto makeAdmin = [=] {
const auto makeAdmin = [=](Fn<void()> close) {
const auto user = forbidden.users.front();
const auto weak = std::make_shared<QPointer<EditAdminBox>>();
const auto close = [=](auto&&...) {
if (*weak) {
(*weak)->closeBox();
const auto done = [=](auto&&...) {
if (const auto strong = weak->data()) {
strong->uiShow()->showToast(
tr::lng_box_done(tr::now));
strong->closeBox();
}
};
const auto fail = [=] {
if (const auto strong = weak->data()) {
strong->closeBox();
}
};
const auto saveCallback = SaveAdminCallback(
show,
channel,
user,
close,
close);
done,
fail);
auto box = Box<EditAdminBox>(
channel,
user,
@@ -214,6 +221,7 @@ void ShowAddParticipantsError(
box->setSaveCallback(saveCallback);
*weak = box.data();
show->showBox(std::move(box));
close();
};
show->showBox(
Ui::MakeConfirmBox({
@@ -940,7 +940,7 @@ int BackgroundPreviewBox::textsTop() const {
- st::historyPaddingBottom
- (_service ? _service->height() : 0)
- _text1->height()
- (forChannel() ? _text2->height() : 0);
- (forChannel() ? 0 : _text2->height());
}
QRect BackgroundPreviewBox::radialRect() const {
+31 -2
View File
@@ -546,7 +546,7 @@ rightsToggle: Toggle(defaultToggle) {
vsize: 0px;
vshift: 1px;
stroke: 2px;
duration: 120;
duration: universalDuration;
}
rightsButton: SettingsButton(defaultSettingsButton) {
@@ -642,6 +642,10 @@ proxyDropdownUpPosition: point(-2px, 20px);
proxyAboutPadding: margins(22px, 7px, 22px, 14px);
proxyAboutSponsorPadding: margins(22px, 7px, 22px, 0px);
proxyApplyBoxLabel : FlatLabel(defaultFlatLabel) {
maxHeight: 30px;
}
markdownLinkFieldPadding: margins(22px, 0px, 22px, 10px);
termsContent: FlatLabel(defaultFlatLabel) {
@@ -691,6 +695,10 @@ createPollOptionField: InputField(createPollField) {
placeholderMargins: margins(2px, 0px, 2px, 0px);
heightMax: 68px;
}
createPollOptionFieldPremium: InputField(createPollOptionField) {
textMargins: margins(22px, 11px, 68px, 11px);
}
createPollOptionFieldPremiumEmojiPosition: point(15px, -1px);
createPollSolutionField: InputField(createPollField) {
textMargins: margins(0px, 4px, 0px, 4px);
border: 1px;
@@ -704,7 +712,7 @@ createPollOptionRemove: CrossButton {
cross: CrossAnimation {
size: 22px;
skip: 6px;
stroke: 1.;
stroke: 1.5;
minScale: 0.3;
}
crossFg: boxTitleCloseFg;
@@ -718,6 +726,7 @@ createPollOptionRemove: CrossButton {
}
}
createPollOptionRemovePosition: point(11px, 9px);
createPollOptionEmojiPositionSkip: 4px;
createPollWarning: FlatLabel(defaultFlatLabel) {
textFg: windowSubTextFg;
palette: TextPalette(defaultTextPalette) {
@@ -1074,3 +1083,23 @@ collectibleBox: Box(defaultBox) {
buttonHeight: 36px;
button: collectibleCopy;
}
moderateBoxUserpic: UserpicButton(defaultUserpicButton) {
size: size(34px, 42px);
photoSize: 34px;
photoPosition: point(0px, 4px);
}
moderateBoxExpand: icon {{ "chat/reply_type_group", boxTextFg }};
moderateBoxExpandHeight: 20px;
moderateBoxExpandRight: 10px;
moderateBoxExpandInnerSkip: 2px;
moderateBoxExpandFont: font(11px);
moderateBoxExpandToggleSize: 4px;
moderateBoxExpandToggleFourStrokes: 3px;
moderateBoxExpandIcon: icon{{ "info/edit/expand_arrow_small-flip_vertical", windowActiveTextFg }};
moderateBoxExpandIconDown: icon{{ "info/edit/expand_arrow_small", windowActiveTextFg }};
moderateBoxDividerLabel: FlatLabel(boxDividerLabel) {
palette: TextPalette(defaultTextPalette) {
selectLinkFg: windowActiveTextFg;
}
}
+183 -68
View File
@@ -7,32 +7,37 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/connection_box.h"
#include "ui/boxes/confirm_box.h"
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "base/qthelp_url.h"
#include "base/call_delayed.h"
#include "base/qthelp_regex.h"
#include "base/qthelp_url.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "core/local_url_handlers.h"
#include "lang/lang_keys.h"
#include "main/main_account.h"
#include "mtproto/facade.h"
#include "ui/widgets/checkbox.h"
#include "storage/localstorage.h"
#include "ui/basic_click_handlers.h"
#include "ui/boxes/confirm_box.h"
#include "ui/effects/animations.h"
#include "ui/effects/radial_animation.h"
#include "ui/painter.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/fields/number_input.h"
#include "ui/widgets/fields/password_input.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/popup_menu.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/toast/toast.h"
#include "ui/effects/animations.h"
#include "ui/effects/radial_animation.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/basic_click_handlers.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
#include "boxes/abstract_box.h" // Ui::show().
#include "window/window_session_controller.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
@@ -48,6 +53,22 @@ constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000);
using ProxyData = MTP::ProxyData;
[[nodiscard]] ProxyData ProxyDataFromFields(
ProxyData::Type type,
const QMap<QString, QString> &fields) {
auto proxy = ProxyData();
proxy.type = type;
proxy.host = fields.value(u"server"_q);
proxy.port = fields.value(u"port"_q).toUInt();
if (type == ProxyData::Type::Socks5) {
proxy.user = fields.value(u"user"_q);
proxy.password = fields.value(u"pass"_q);
} else if (type == ProxyData::Type::Mtproto) {
proxy.password = fields.value(u"secret"_q);
}
return proxy;
};
class HostInput : public Ui::MaskedInputField {
public:
HostInput(
@@ -203,6 +224,7 @@ protected:
private:
void setupContent();
void setupTopButton();
void createNoRowsLabel();
void addNewProxy();
void applyView(View &&view);
@@ -600,9 +622,80 @@ void ProxiesBox::prepare() {
addButton(tr::lng_proxy_add(), [=] { addNewProxy(); });
addButton(tr::lng_close(), [=] { closeBox(); });
setupTopButton();
setupContent();
}
void ProxiesBox::setupTopButton() {
const auto top = addTopButton(st::infoTopBarMenu);
const auto menu
= top->lifetime().make_state<base::unique_qptr<Ui::PopupMenu>>();
const auto callback = [=] {
const auto maybeUrl = QGuiApplication::clipboard()->text();
const auto local = Core::TryConvertUrlToLocal(maybeUrl);
const auto proxyString = u"proxy"_q;
const auto socksString = u"socks"_q;
const auto protocol = u"tg://"_q;
const auto command = base::StringViewMid(
local,
protocol.size(),
8192);
if (local.startsWith(protocol + proxyString)
|| local.startsWith(protocol + socksString)) {
using namespace qthelp;
const auto options = RegExOption::CaseInsensitive;
for (const auto &[expression, _] : Core::LocalUrlHandlers()) {
const auto midExpression = base::StringViewMid(
expression,
1);
const auto isSocks = midExpression.startsWith(
socksString);
if (!midExpression.startsWith(proxyString)
&& !isSocks) {
continue;
}
const auto match = regex_match(
expression,
command,
options);
if (!match) {
continue;
}
const auto type = isSocks
? ProxyData::Type::Socks5
: ProxyData::Type::Mtproto;
const auto fields = url_parse_params(
match->captured(1),
qthelp::UrlParamNameTransform::ToLower);
const auto proxy = ProxyDataFromFields(type, fields);
const auto contains = _controller->contains(proxy);
const auto toast = (contains
? tr::lng_proxy_add_from_clipboard_existing_toast
: tr::lng_proxy_add_from_clipboard_good_toast)(tr::now);
uiShow()->showToast(toast);
if (!contains) {
_controller->addNewItem(proxy);
}
break;
}
} else {
uiShow()->showToast(
tr::lng_proxy_add_from_clipboard_failed_toast(tr::now));
}
};
top->setClickedCallback([=] {
*menu = base::make_unique_q<Ui::PopupMenu>(top, st::defaultPopupMenu);
(*menu)->addAction(
tr::lng_proxy_add_from_clipboard(tr::now),
callback);
(*menu)->popup(QCursor::pos());
return true;
});
}
void ProxiesBox::setupContent() {
const auto inner = setInnerWidget(object_ptr<Ui::VerticalLayout>(this));
@@ -1094,70 +1187,84 @@ ProxiesBoxController::ProxiesBoxController(not_null<Main::Account*> account)
}
void ProxiesBoxController::ShowApplyConfirmation(
Window::SessionController *controller,
Type type,
const QMap<QString, QString> &fields) {
const auto server = fields.value(u"server"_q);
const auto port = fields.value(u"port"_q).toUInt();
auto proxy = ProxyData();
proxy.type = type;
proxy.host = server;
proxy.port = port;
if (type == Type::Socks5) {
proxy.user = fields.value(u"user"_q);
proxy.password = fields.value(u"pass"_q);
} else if (type == Type::Mtproto) {
proxy.password = fields.value(u"secret"_q);
const auto proxy = ProxyDataFromFields(type, fields);
if (!proxy) {
auto box = Ui::MakeInformBox(
(proxy.status() == ProxyData::Status::Unsupported
? tr::lng_proxy_unsupported(tr::now)
: tr::lng_proxy_invalid(tr::now)));
if (controller) {
controller->uiShow()->showBox(std::move(box));
} else {
Ui::show(std::move(box));
}
return;
}
if (proxy) {
static const auto UrlStartRegExp = QRegularExpression(
"^https://",
QRegularExpression::CaseInsensitiveOption);
static const auto UrlEndRegExp = QRegularExpression("/$");
const auto displayed = "https://" + server + "/";
const auto parsed = QUrl::fromUserInput(displayed);
const auto displayUrl = !UrlClickHandler::IsSuspicious(displayed)
? displayed
: parsed.isValid()
? QString::fromUtf8(parsed.toEncoded())
: UrlClickHandler::ShowEncoded(displayed);
const auto displayServer = QString(
displayUrl
).replace(
UrlStartRegExp,
QString()
).replace(UrlEndRegExp, QString());
const auto text = tr::lng_sure_enable_socks(
tr::now,
lt_server,
displayServer,
lt_port,
QString::number(port))
+ (proxy.type == Type::Mtproto
? "\n\n" + tr::lng_proxy_sponsor_warning(tr::now)
: QString());
auto callback = [=](Fn<void()> &&close) {
static const auto UrlStartRegExp = QRegularExpression(
"^https://",
QRegularExpression::CaseInsensitiveOption);
static const auto UrlEndRegExp = QRegularExpression("/$");
const auto displayed = "https://" + proxy.host + "/";
const auto parsed = QUrl::fromUserInput(displayed);
const auto displayUrl = !UrlClickHandler::IsSuspicious(displayed)
? displayed
: parsed.isValid()
? QString::fromUtf8(parsed.toEncoded())
: UrlClickHandler::ShowEncoded(displayed);
const auto displayServer = QString(
displayUrl
).replace(
UrlStartRegExp,
QString()
).replace(UrlEndRegExp, QString());
const auto box = [=](not_null<Ui::GenericBox*> box) {
box->setTitle(tr::lng_proxy_box_title());
if (type == Type::Mtproto) {
box->addRow(object_ptr<Ui::FlatLabel>(
box,
tr::lng_proxy_sponsor_warning(),
st::boxDividerLabel));
Ui::AddSkip(box->verticalLayout());
Ui::AddSkip(box->verticalLayout());
}
const auto &stL = st::proxyApplyBoxLabel;
const auto &stSubL = st::boxDividerLabel;
const auto add = [&](const QString &s, tr::phrase<> phrase) {
if (!s.isEmpty()) {
box->addRow(object_ptr<Ui::FlatLabel>(box, s, stL));
box->addRow(object_ptr<Ui::FlatLabel>(box, phrase(), stSubL));
Ui::AddSkip(box->verticalLayout());
Ui::AddSkip(box->verticalLayout());
}
};
if (!displayServer.isEmpty()) {
add(displayServer, tr::lng_proxy_box_server);
}
add(QString::number(proxy.port), tr::lng_proxy_box_port);
if (type == Type::Socks5) {
add(proxy.user, tr::lng_proxy_box_username);
add(proxy.password, tr::lng_proxy_box_password);
} else if (type == Type::Mtproto) {
add(proxy.password, tr::lng_proxy_box_secret);
}
box->addButton(tr::lng_sure_enable(), [=] {
auto &proxies = Core::App().settings().proxy().list();
if (!ranges::contains(proxies, proxy)) {
proxies.push_back(proxy);
}
Core::App().setCurrentProxy(
proxy,
ProxyData::Settings::Enabled);
Core::App().setCurrentProxy(proxy, ProxyData::Settings::Enabled);
Local::writeSettings();
close();
};
Ui::show(
Ui::MakeConfirmBox({
.text = text,
.confirmed = std::move(callback),
.confirmText = tr::lng_sure_enable(),
}),
Ui::LayerOption::KeepOther);
box->closeBox();
});
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
};
if (controller) {
controller->uiShow()->showBox(Box(box));
} else {
Ui::show(Ui::MakeInformBox(
(proxy.status() == ProxyData::Status::Unsupported
? tr::lng_proxy_unsupported(tr::now)
: tr::lng_proxy_invalid(tr::now))));
Ui::show(Box(box));
}
}
@@ -1448,6 +1555,14 @@ object_ptr<Ui::BoxContent> ProxiesBoxController::addNewItemBox() {
});
}
bool ProxiesBoxController::contains(const ProxyData &proxy) const {
const auto j = ranges::find(
_list,
proxy,
[](const Item &item) { return item.data; });
return (j != end(_list));
}
void ProxiesBoxController::addNewItem(const ProxyData &proxy) {
auto &proxies = _settings.list();
proxies.push_back(proxy);
+8 -1
View File
@@ -30,6 +30,10 @@ namespace Main {
class Account;
} // namespace Main
namespace Window {
class SessionController;
} // namespace Window
class ProxiesBoxController {
public:
using ProxyData = MTP::ProxyData;
@@ -38,6 +42,7 @@ public:
explicit ProxiesBoxController(not_null<Main::Account*> account);
static void ShowApplyConfirmation(
Window::SessionController *controller,
Type type,
const QMap<QString, QString> &fields);
@@ -77,6 +82,9 @@ public:
void setTryIPv6(bool enabled);
rpl::producer<ProxyData::Settings> proxySettingsValue() const;
[[nodiscard]] bool contains(const ProxyData &proxy) const;
void addNewItem(const ProxyData &proxy);
rpl::producer<ItemView> views() const;
~ProxiesBoxController();
@@ -109,7 +117,6 @@ private:
void replaceItemValue(
std::vector<Item>::iterator which,
const ProxyData &proxy);
void addNewItem(const ProxyData &proxy);
const not_null<Main::Account*> _account;
Core::SettingsProxy &_settings;
+256 -70
View File
@@ -7,33 +7,41 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/create_poll_box.h"
#include "lang/lang_keys.h"
#include "data/data_poll.h"
#include "ui/toast/toast.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/text/text_utilities.h"
#include "ui/vertical_list.h"
#include "main/main_session.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "base/call_delayed.h"
#include "base/event_filter.h"
#include "base/random.h"
#include "base/unique_qptr.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/message_field.h"
#include "menu/menu_send.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "data/data_poll.h"
#include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h"
#include "history/view/history_view_schedule_box.h"
#include "base/unique_qptr.h"
#include "base/event_filter.h"
#include "base/call_delayed.h"
#include "base/random.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "menu/menu_send.h"
#include "ui/controls/emoji_button.h"
#include "ui/rect.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "ui/vertical_list.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/shadow.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h" // defaultComposeFiles.
#include "styles/style_layers.h"
#include "styles/style_settings.h"
namespace {
@@ -46,12 +54,107 @@ constexpr auto kSolutionLimit = 200;
constexpr auto kWarnSolutionLimit = 60;
constexpr auto kErrorLimit = 99;
[[nodiscard]] not_null<Ui::EmojiButton*> AddEmojiToggleToField(
not_null<Ui::InputField*> field,
not_null<Ui::BoxContent*> box,
not_null<Window::SessionController*> controller,
not_null<ChatHelpers::TabbedPanel*> emojiPanel,
QPoint shift) {
const auto emojiToggle = Ui::CreateChild<Ui::EmojiButton>(
field->parentWidget(),
st::defaultComposeFiles.emoji);
const auto fade = Ui::CreateChild<Ui::FadeAnimation>(
emojiToggle,
emojiToggle,
0.5);
{
const auto fadeTarget = Ui::CreateChild<Ui::RpWidget>(emojiToggle);
fadeTarget->resize(emojiToggle->size());
fadeTarget->paintRequest(
) | rpl::start_with_next([=](const QRect &rect) {
auto p = QPainter(fadeTarget);
if (fade->animating()) {
p.fillRect(fadeTarget->rect(), st::boxBg);
}
fade->paint(p);
}, fadeTarget->lifetime());
rpl::single(false) | rpl::then(
field->focusedChanges()
) | rpl::start_with_next([=](bool shown) {
if (shown) {
fade->fadeIn(st::universalDuration);
} else {
fade->fadeOut(st::universalDuration);
}
}, emojiToggle->lifetime());
fade->fadeOut(1);
fade->finish();
}
const auto outer = box->getDelegate()->outerContainer();
const auto allow = [](not_null<DocumentData*>) { return true; };
InitMessageFieldHandlers(
controller,
field,
Window::GifPauseReason::Layer,
allow);
Ui::Emoji::SuggestionsController::Init(
outer,
field,
&controller->session(),
Ui::Emoji::SuggestionsController::Options{
.suggestCustomEmoji = true,
.allowCustomWithoutPremium = allow,
});
const auto updateEmojiPanelGeometry = [=] {
const auto parent = emojiPanel->parentWidget();
const auto global = emojiToggle->mapToGlobal({ 0, 0 });
const auto local = parent->mapFromGlobal(global);
const auto right = local.x() + emojiToggle->width() * 3;
const auto isDropDown = local.y() < parent->height() / 2;
emojiPanel->setDropDown(isDropDown);
if (isDropDown) {
emojiPanel->moveTopRight(
local.y() + emojiToggle->height(),
right);
} else {
emojiPanel->moveBottomRight(local.y(), right);
}
};
rpl::combine(
box->sizeValue(),
field->geometryValue()
) | rpl::start_with_next([=](QSize outer, QRect inner) {
emojiToggle->moveToLeft(
rect::right(inner) + shift.x(),
inner.y() + shift.y());
emojiToggle->update();
}, emojiToggle->lifetime());
emojiToggle->installEventFilter(emojiPanel);
emojiToggle->addClickHandler([=] {
updateEmojiPanelGeometry();
emojiPanel->toggleAnimated();
});
const auto filterCallback = [=](not_null<QEvent*> event) {
if (event->type() == QEvent::Enter) {
updateEmojiPanelGeometry();
}
return base::EventFilterResult::Continue;
};
base::install_event_filter(emojiToggle, filterCallback);
return emojiToggle;
}
class Options {
public:
Options(
not_null<QWidget*> outer,
not_null<Ui::BoxContent*> box,
not_null<Ui::VerticalLayout*> container,
not_null<Main::Session*> session,
not_null<Window::SessionController*> controller,
ChatHelpers::TabbedPanel *emojiPanel,
bool chooseCorrectEnabled);
[[nodiscard]] bool hasOptions() const;
@@ -140,9 +243,10 @@ private:
[[nodiscard]] auto createChooseCorrectGroup()
-> std::shared_ptr<Ui::RadiobuttonGroup>;
not_null<QWidget*> _outer;
not_null<Ui::BoxContent*> _box;
not_null<Ui::VerticalLayout*> _container;
const not_null<Main::Session*> _session;
const not_null<Window::SessionController*> _controller;
ChatHelpers::TabbedPanel * const _emojiPanel;
std::shared_ptr<Ui::RadiobuttonGroup> _chooseCorrectGroup;
int _position = 0;
std::vector<std::unique_ptr<Option>> _list;
@@ -154,6 +258,7 @@ private:
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
rpl::event_stream<> _backspaceInFront;
rpl::event_stream<> _tabbed;
rpl::lifetime _emojiPanelLifetime;
};
@@ -193,8 +298,9 @@ not_null<Ui::FlatLabel*> CreateWarningLabel(
if (value >= 0) {
result->setText(QString::number(value));
} else {
constexpr auto kMinus = QChar(0x2212);
result->setMarkedText(Ui::Text::Colorized(
QString::number(value)));
kMinus + QString::number(std::abs(value))));
}
result->setVisible(shown);
}));
@@ -223,7 +329,9 @@ Options::Option::Option(
, _field(
Ui::CreateChild<Ui::InputField>(
_content.get(),
st::createPollOptionField,
session->user()->isPremium()
? st::createPollOptionFieldPremium
: st::createPollOptionField,
Ui::InputField::Mode::NoNewlines,
tr::lng_polls_create_option_add())) {
InitField(outer, _field, session);
@@ -299,7 +407,7 @@ void Options::Option::createRemove() {
const auto remove = Ui::CreateChild<Ui::CrossButton>(
field.get(),
st::createPollOptionRemove);
remove->hide(anim::type::instant);
remove->show(anim::type::instant);
const auto toggle = lifetime.make_state<rpl::variable<bool>>(false);
_removeAlways = lifetime.make_state<rpl::variable<bool>>(false);
@@ -309,6 +417,7 @@ void Options::Option::createRemove() {
// Don't capture 'this'! Because Option is a value type.
*toggle = !field->getLastText().isEmpty();
}, field->lifetime());
#if 0
rpl::combine(
toggle->value(),
_removeAlways->value(),
@@ -316,6 +425,7 @@ void Options::Option::createRemove() {
) | rpl::start_with_next([=](bool shown) {
remove->toggle(shown, anim::type::normal);
}, remove->lifetime());
#endif
field->widthValue(
) | rpl::start_with_next([=](int width) {
@@ -456,10 +566,16 @@ void Options::Option::removePlaceholder() const {
PollAnswer Options::Option::toPollAnswer(int index) const {
Expects(index >= 0 && index < kMaxOptionsCount);
const auto text = field()->getTextWithTags();
auto result = PollAnswer{
field()->getLastText().trimmed(),
QByteArray(1, ('0' + index))
TextWithEntities{
.text = text.text,
.entities = TextUtilities::ConvertTextTagsToEntities(text.tags),
},
QByteArray(1, ('0' + index)),
};
TextUtilities::Trim(result.text);
result.correct = _correct ? _correct->entity()->Checkbox::checked() : false;
return result;
}
@@ -469,13 +585,15 @@ rpl::producer<Qt::MouseButton> Options::Option::removeClicks() const {
}
Options::Options(
not_null<QWidget*> outer,
not_null<Ui::BoxContent*> box,
not_null<Ui::VerticalLayout*> container,
not_null<Main::Session*> session,
not_null<Window::SessionController*> controller,
ChatHelpers::TabbedPanel *emojiPanel,
bool chooseCorrectEnabled)
: _outer(outer)
: _box(box)
, _container(container)
, _session(session)
, _controller(controller)
, _emojiPanel(emojiPanel)
, _chooseCorrectGroup(chooseCorrectEnabled
? createChooseCorrectGroup()
: nullptr)
@@ -645,12 +763,40 @@ void Options::addEmptyOption() {
(*(_list.end() - 2))->toggleRemoveAlways(true);
}
_list.push_back(std::make_unique<Option>(
_outer,
_box,
_container,
_session,
&_controller->session(),
_position + _list.size() + _destroyed.size(),
_chooseCorrectGroup));
const auto field = _list.back()->field();
if (const auto emojiPanel = _emojiPanel) {
const auto emojiToggle = AddEmojiToggleToField(
field,
_box,
_controller,
emojiPanel,
QPoint(
-st::createPollOptionFieldPremium.textMargins.right(),
st::createPollOptionEmojiPositionSkip));
emojiToggle->shownValue() | rpl::start_with_next([=](bool shown) {
if (!shown) {
return;
}
_emojiPanelLifetime.destroy();
emojiPanel->selector()->emojiChosen(
) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
if (field->hasFocus()) {
Ui::InsertEmojiAtCursor(field->textCursor(), data.emoji);
}
}, _emojiPanelLifetime);
emojiPanel->selector()->customEmojiChosen(
) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
if (field->hasFocus()) {
Data::InsertCustomEmoji(field, data.document);
}
}, _emojiPanelLifetime);
}, emojiToggle->lifetime());
}
field->submits(
) | rpl::start_with_next([=] {
const auto index = findField(field);
@@ -697,7 +843,7 @@ void Options::addEmptyOption() {
});
_list.back()->removeClicks(
) | rpl::take(1) | rpl::start_with_next([=] {
) | rpl::start_with_next([=] {
Ui::PostponeCall(crl::guard(field, [=] {
Expects(!_list.empty());
@@ -764,12 +910,12 @@ CreatePollBox::CreatePollBox(
PollData::Flags chosen,
PollData::Flags disabled,
Api::SendType sendType,
SendMenu::Type sendMenuType)
SendMenu::Details sendMenuDetails)
: _controller(controller)
, _chosen(chosen)
, _disabled(disabled)
, _sendType(sendType)
, _sendMenuType(sendMenuType) {
, _sendMenuDetails([result = sendMenuDetails] { return result; }) {
}
rpl::producer<CreatePollBox::Result> CreatePollBox::submitRequests() const {
@@ -789,19 +935,63 @@ not_null<Ui::InputField*> CreatePollBox::setupQuestion(
using namespace Settings;
const auto session = &_controller->session();
const auto isPremium = session->user()->isPremium();
Ui::AddSubsectionTitle(container, tr::lng_polls_create_question());
const auto question = container->add(
object_ptr<Ui::InputField>(
container,
st::createPollField,
Ui::InputField::Mode::MultiLine,
tr::lng_polls_create_question_placeholder()),
st::createPollFieldPadding);
st::createPollFieldPadding
+ (isPremium
? QMargins(0, 0, st::defaultComposeFiles.emoji.inner.width, 0)
: QMargins()));
InitField(getDelegate()->outerContainer(), question, session);
question->setMaxLength(kQuestionLimit + kErrorLimit);
question->setSubmitSettings(Ui::InputField::SubmitSettings::Both);
question->customTab(true);
if (isPremium) {
using Selector = ChatHelpers::TabbedSelector;
const auto outer = getDelegate()->outerContainer();
_emojiPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
outer,
_controller,
object_ptr<Selector>(
nullptr,
_controller->uiShow(),
Window::GifPauseReason::Layer,
Selector::Mode::EmojiOnly));
const auto emojiPanel = _emojiPanel.get();
emojiPanel->setDesiredHeightValues(
1.,
st::emojiPanMinHeight / 2,
st::emojiPanMinHeight);
emojiPanel->hide();
emojiPanel->selector()->setCurrentPeer(session->user());
const auto emojiToggle = AddEmojiToggleToField(
question,
this,
_controller,
emojiPanel,
st::createPollOptionFieldPremiumEmojiPosition);
emojiPanel->selector()->emojiChosen(
) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
if (question->hasFocus()) {
Ui::InsertEmojiAtCursor(question->textCursor(), data.emoji);
}
}, emojiToggle->lifetime());
emojiPanel->selector()->customEmojiChosen(
) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
if (question->hasFocus()) {
Data::InsertCustomEmoji(question, data.document);
}
}, emojiToggle->lifetime());
}
const auto warning = CreateWarningLabel(
container,
question,
@@ -854,7 +1044,7 @@ not_null<Ui::InputField*> CreatePollBox::setupSolution(
solution->setInstantReplaces(Ui::InstantReplaces::Default());
solution->setInstantReplacesEnabled(
Core::App().settings().replaceEmojiValue());
solution->setMarkdownReplacesEnabled(rpl::single(true));
solution->setMarkdownReplacesEnabled(true);
solution->setEditLinkCallback(
DefaultEditLinkCallback(_controller->uiShow(), solution));
solution->customTab(true);
@@ -910,9 +1100,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
st::defaultSubsectionTitle),
st::createPollFieldTitlePadding);
const auto options = lifetime().make_state<Options>(
getDelegate()->outerContainer(),
this,
container,
&_controller->session(),
_controller,
_emojiPanel ? _emojiPanel.get() : nullptr,
(_chosen & PollData::Flag::Quiz));
auto limit = options->usedCount() | rpl::after_next([=](int count) {
setCloseByEscape(!count);
@@ -1029,9 +1220,13 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
};
const auto collectResult = [=] {
const auto textWithTags = question->getTextWithTags();
using Flag = PollData::Flag;
auto result = PollData(&_controller->session().data(), id);
result.question = question->getLastText().trimmed();
result.question.text = textWithTags.text;
result.question.entities = TextUtilities::ConvertTextTagsToEntities(
textWithTags.tags);
TextUtilities::Trim(result.question);
result.answers = options->toPollAnswers();
const auto solutionWithTags = quiz->checked()
? solution->getTextWithAppliedMarkdown()
@@ -1093,19 +1288,9 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
_submitRequests.fire({ collectResult(), sendOptions });
}
};
const auto sendSilent = [=] {
send({ .silent = true });
};
const auto sendScheduled = [=] {
_controller->show(
HistoryView::PrepareScheduleBox(
this,
SendMenu::Type::Scheduled,
send));
};
const auto sendWhenOnline = [=] {
send(Api::DefaultSendWhenOnlineOptions());
};
const auto sendAction = SendMenu::DefaultCallback(
_controller->uiShow(),
crl::guard(this, send));
options->scrollToWidget(
) | rpl::start_with_next([=](not_null<QWidget*> widget) {
@@ -1118,24 +1303,25 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
}, lifetime());
const auto isNormal = (_sendType == Api::SendType::Normal);
const auto schedule = [=] {
sendAction(
{ .type = SendMenu::ActionType::Schedule },
_sendMenuDetails());
};
const auto submit = addButton(
isNormal
(isNormal
? tr::lng_polls_create_button()
: tr::lng_schedule_button(),
[=] { isNormal ? send({}) : sendScheduled(); });
const auto sendMenuType = [=] {
: tr::lng_schedule_button()),
[=] { isNormal ? send({}) : schedule(); });
const auto sendMenuDetails = [=] {
collectError();
return (*error)
? SendMenu::Type::Disabled
: _sendMenuType;
return (*error) ? SendMenu::Details() : _sendMenuDetails();
};
SendMenu::SetupMenuAndShortcuts(
submit.data(),
sendMenuType,
sendSilent,
sendScheduled,
sendWhenOnline);
_controller->uiShow(),
sendMenuDetails,
sendAction);
addButton(tr::lng_cancel(), [=] { closeBox(); });
return result;
+8 -3
View File
@@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
struct PollData;
namespace ChatHelpers {
class TabbedPanel;
} // namespace ChatHelpers
namespace Ui {
class VerticalLayout;
} // namespace Ui
@@ -23,7 +27,7 @@ class SessionController;
} // namespace Window
namespace SendMenu {
enum class Type;
struct Details;
} // namespace SendMenu
class CreatePollBox : public Ui::BoxContent {
@@ -39,7 +43,7 @@ public:
PollData::Flags chosen,
PollData::Flags disabled,
Api::SendType sendType,
SendMenu::Type sendMenuType);
SendMenu::Details sendMenuDetails);
[[nodiscard]] rpl::producer<Result> submitRequests() const;
void submitFailed(const QString &error);
@@ -71,7 +75,8 @@ private:
const PollData::Flags _chosen = PollData::Flags();
const PollData::Flags _disabled = PollData::Flags();
const Api::SendType _sendType = Api::SendType();
const SendMenu::Type _sendMenuType;
const Fn<SendMenu::Details()> _sendMenuDetails;
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
Fn<void()> _setInnerFocus;
Fn<rpl::producer<bool>()> _dataIsValidValue;
rpl::event_stream<Result> _submitRequests;
@@ -379,13 +379,7 @@ auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
return result;
}
const auto items = ranges::views::all(
_ids
) | ranges::views::transform([&](FullMsgId id) {
return peer->owner().message(id);
}) | ranges::views::filter([](HistoryItem *item) {
return (item != nullptr);
}) | ranges::to_vector;
const auto items = peer->owner().idsToItems(_ids);
if (items.size() != _ids.size()) {
// We don't have information about all messages.
+67 -23
View File
@@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "main/main_session_settings.h"
#include "mainwidget.h" // controller->content() -> QWidget*
#include "menu/menu_send.h"
#include "mtproto/mtproto_config.h"
#include "platform/platform_specific.h"
#include "storage/localimageloader.h" // SendMediaType
@@ -175,7 +176,7 @@ void ChooseReplacement(
void EditPhotoImage(
not_null<Window::SessionController*> controller,
std::shared_ptr<Data::PhotoMedia> media,
bool wasSpoiler,
bool spoilered,
Fn<void(Ui::PreparedList)> done) {
const auto large = media
? media->image(Data::PhotoSize::Large)
@@ -198,7 +199,7 @@ void EditPhotoImage(
using ImageInfo = Ui::PreparedFileInformation::Image;
auto &file = list.files.front();
file.spoiler = wasSpoiler;
file.spoiler = spoilered;
const auto image = std::get_if<ImageInfo>(&file.information->media);
image->modifications = mods;
@@ -206,6 +207,9 @@ void EditPhotoImage(
Storage::UpdateImageDetails(file, previewWidth, sideLimit);
done(std::move(list));
};
if (!large) {
return;
}
const auto fileImage = std::make_shared<Image>(*large);
auto editor = base::make_unique_q<Editor::PhotoEditor>(
parent,
@@ -222,25 +226,18 @@ void EditPhotoImage(
} // namespace
EditCaptionBox::EditCaptionBox(
QWidget*,
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item)
: EditCaptionBox({}, controller, item, PrepareEditText(item), {}, {}) {
}
EditCaptionBox::EditCaptionBox(
QWidget*,
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item,
TextWithTags &&text,
bool spoilered,
bool invertCaption,
Ui::PreparedList &&list,
Fn<void()> saved)
: _controller(controller)
, _historyItem(item)
, _isAllowedEditMedia(item->media()
? item->media()->allowsEditMedia()
: false)
, _isAllowedEditMedia(item->media() && item->media()->allowsEditMedia())
, _albumType(ComputeAlbumType(item))
, _controls(base::make_unique_q<Ui::VerticalLayout>(this))
, _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll))
@@ -258,6 +255,8 @@ EditCaptionBox::EditCaptionBox(
Expects(item->media() != nullptr);
Expects(item->media()->allowsEditCaption());
_mediaEditManager.start(item, spoilered, invertCaption);
_controller->session().data().itemRemoved(
_historyItem->fullId()
) | rpl::start_with_next([=] {
@@ -271,6 +270,8 @@ void EditCaptionBox::StartMediaReplace(
not_null<Window::SessionController*> controller,
FullMsgId itemId,
TextWithTags text,
bool spoilered,
bool invertCaption,
Fn<void()> saved) {
const auto session = &controller->session();
const auto item = session->data().message(itemId);
@@ -282,6 +283,8 @@ void EditCaptionBox::StartMediaReplace(
controller,
item,
std::move(text),
spoilered,
invertCaption,
std::move(list),
std::move(saved)));
};
@@ -296,6 +299,8 @@ void EditCaptionBox::StartMediaReplace(
FullMsgId itemId,
Ui::PreparedList &&list,
TextWithTags text,
bool spoilered,
bool invertCaption,
Fn<void()> saved) {
const auto session = &controller->session();
const auto item = session->data().message(itemId);
@@ -329,6 +334,8 @@ void EditCaptionBox::StartMediaReplace(
controller,
item,
std::move(text),
spoilered,
invertCaption,
std::move(list),
std::move(saved)));
}
@@ -339,14 +346,15 @@ void EditCaptionBox::StartPhotoEdit(
std::shared_ptr<Data::PhotoMedia> media,
FullMsgId itemId,
TextWithTags text,
bool spoilered,
bool invertCaption,
Fn<void()> saved) {
const auto session = &controller->session();
const auto item = session->data().message(itemId);
if (!item) {
return;
}
const auto hasSpoiler = item->media() && item->media()->hasSpoiler();
EditPhotoImage(controller, media, hasSpoiler, [=](
EditPhotoImage(controller, media, spoilered, [=](
Ui::PreparedList &&list) mutable {
const auto item = session->data().message(itemId);
if (!item) {
@@ -356,15 +364,48 @@ void EditCaptionBox::StartPhotoEdit(
controller,
item,
std::move(text),
spoilered,
invertCaption,
std::move(list),
std::move(saved)));
});
}
void EditCaptionBox::prepare() {
addButton(tr::lng_settings_save(), [=] { save(); });
const auto button = addButton(tr::lng_settings_save(), [=] { save(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });
const auto details = crl::guard(this, [=] {
auto result = SendMenu::Details();
const auto allWithSpoilers = ranges::all_of(
_preparedList.files,
&Ui::PreparedFile::spoiler);
result.spoiler = !_preparedList.hasSpoilerMenu(!_asFile)
? SendMenu::SpoilerState::None
: allWithSpoilers
? SendMenu::SpoilerState::Enabled
: SendMenu::SpoilerState::Possible;
const auto canMoveCaption = _preparedList.canMoveCaption(
false,
!_asFile
) && _field && HasSendText(_field);
result.caption = !canMoveCaption
? SendMenu::CaptionState::None
: _mediaEditManager.invertCaption()
? SendMenu::CaptionState::Above
: SendMenu::CaptionState::Below;
return result;
});
const auto callback = [=](SendMenu::Action action, const auto &) {
_mediaEditManager.apply(action);
rebuildPreview();
};
SendMenu::SetupMenuAndShortcuts(
button,
nullptr,
details,
crl::guard(this, callback));
updateBoxSize();
setupField();
@@ -393,7 +434,6 @@ void EditCaptionBox::rebuildPreview() {
applyChanges();
_previewHasSpoiler = nullptr;
if (_preparedList.files.empty()) {
const auto media = _historyItem->media();
const auto photo = media->photo();
@@ -427,7 +467,13 @@ void EditCaptionBox::rebuildPreview() {
_isPhoto = (media && media->isPhoto());
const auto withCheckbox = _isPhoto && CanBeCompressed(_albumType);
if (media && (!withCheckbox || !_asFile)) {
_previewHasSpoiler = [media] { return media->hasSpoiler(); };
media->spoileredChanges(
) | rpl::start_with_next([=](bool spoilered) {
_mediaEditManager.apply({ .type = spoilered
? SendMenu::ActionType::SpoilerOn
: SendMenu::ActionType::SpoilerOff
});
}, media->lifetime());
_content.reset(media);
} else {
_content.reset(Ui::CreateChild<Ui::SingleFilePreview>(
@@ -754,10 +800,7 @@ bool EditCaptionBox::setPreparedList(Ui::PreparedList &&list) {
}
bool EditCaptionBox::hasSpoiler() const {
return _preparedList.files.empty()
? (_historyItem->media()
&& _historyItem->media()->hasSpoiler())
: _preparedList.files.front().spoiler;
return _mediaEditManager.spoilered();
}
void EditCaptionBox::captionResized() {
@@ -866,8 +909,8 @@ bool EditCaptionBox::validateLength(const QString &text) const {
}
void EditCaptionBox::applyChanges() {
if (!_preparedList.files.empty() && _previewHasSpoiler) {
_preparedList.files.front().spoiler = _previewHasSpoiler();
if (!_preparedList.files.empty()) {
_preparedList.files.front().spoiler = _mediaEditManager.spoilered();
}
}
@@ -896,6 +939,7 @@ void EditCaptionBox::save() {
auto options = Api::SendOptions();
options.scheduled = item->isScheduled() ? item->date() : 0;
options.shortcutId = item->shortcutId();
options.invertCaption = _mediaEditManager.invertCaption();
if (!_preparedList.files.empty()) {
if ((_albumType != Ui::AlbumType::None)
+10 -5
View File
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "history/view/controls/history_view_compose_media_edit_manager.h"
#include "ui/layers/box_content.h"
#include "ui/chat/attach/attach_prepare.h"
@@ -32,15 +33,13 @@ enum class AlbumType;
class EditCaptionBox final : public Ui::BoxContent {
public:
EditCaptionBox(
QWidget*,
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item);
EditCaptionBox(
QWidget*,
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item,
TextWithTags &&text,
bool spoilered,
bool invertCaption,
Ui::PreparedList &&list,
Fn<void()> saved);
~EditCaptionBox();
@@ -49,18 +48,24 @@ public:
not_null<Window::SessionController*> controller,
FullMsgId itemId,
TextWithTags text,
bool spoilered,
bool invertCaption,
Fn<void()> saved);
static void StartMediaReplace(
not_null<Window::SessionController*> controller,
FullMsgId itemId,
Ui::PreparedList &&list,
TextWithTags text,
bool spoilered,
bool invertCaption,
Fn<void()> saved);
static void StartPhotoEdit(
not_null<Window::SessionController*> controller,
std::shared_ptr<Data::PhotoMedia> media,
FullMsgId itemId,
TextWithTags text,
bool spoilered,
bool invertCaption,
Fn<void()> saved);
protected:
@@ -111,7 +116,6 @@ private:
const base::unique_qptr<Ui::EmojiButton> _emojiToggle;
base::unique_qptr<Ui::AbstractSinglePreview> _content;
Fn<bool()> _previewHasSpoiler;
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
base::unique_qptr<QObject> _emojiFilter;
@@ -122,6 +126,7 @@ private:
std::shared_ptr<Data::PhotoMedia> _photoMedia;
Ui::PreparedList _preparedList;
HistoryView::MediaEditManager _mediaEditManager;
mtpRequestId _saveRequestId = 0;
+69 -17
View File
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_boosts.h"
#include "data/data_changes.h"
#include "data/data_channel.h"
#include "data/data_credits.h"
#include "data/data_media_types.h" // Data::GiveawayStart.
#include "data/data_peer_values.h" // Data::PeerPremiumValue.
#include "data/data_session.h"
@@ -1147,16 +1148,18 @@ void GiftCodeBox(
object_ptr<Ui::Premium::TopBar>(
box,
st::giveawayGiftCodeCover,
nullptr,
rpl::conditional(
state->used.value(),
tr::lng_gift_link_used_title(),
tr::lng_gift_link_title()),
rpl::conditional(
state->used.value(),
tr::lng_gift_link_used_about(Ui::Text::RichLangValue),
tr::lng_gift_link_about(Ui::Text::RichLangValue)),
true));
Ui::Premium::TopBarDescriptor{
.clickContextOther = nullptr,
.title = rpl::conditional(
state->used.value(),
tr::lng_gift_link_used_title(),
tr::lng_gift_link_title()),
.about = rpl::conditional(
state->used.value(),
tr::lng_gift_link_used_about(Ui::Text::RichLangValue),
tr::lng_gift_link_about(Ui::Text::RichLangValue)),
.light = true,
}));
const auto max = st::giveawayGiftCodeTopHeight;
bar->setMaximumHeight(max);
@@ -1283,13 +1286,15 @@ void GiftCodePendingBox(
object_ptr<Ui::Premium::TopBar>(
box,
st,
clickContext,
tr::lng_gift_link_title(),
tr::lng_gift_link_pending_about(
lt_user,
rpl::single(Ui::Text::Link(resultToName)),
Ui::Text::RichLangValue),
true));
Ui::Premium::TopBarDescriptor{
.clickContextOther = clickContext,
.title = tr::lng_gift_link_title(),
.about = tr::lng_gift_link_pending_about(
lt_user,
rpl::single(Ui::Text::Link(resultToName)),
Ui::Text::RichLangValue),
.light = true,
}));
const auto max = st::giveawayGiftCodeTopHeight;
bar->setMaximumHeight(max);
@@ -1629,3 +1634,50 @@ void ResolveGiveawayInfo(
messageId,
crl::guard(controller, show));
}
void AddCreditsHistoryEntryTable(
not_null<Window::SessionNavigation*> controller,
not_null<Ui::VerticalLayout*> container,
const Data::CreditsHistoryEntry &entry) {
auto table = container->add(
object_ptr<Ui::TableLayout>(
container,
st::giveawayGiftCodeTable),
st::giveawayGiftCodeTableMargin);
if (entry.bareId) {
AddTableRow(
table,
tr::lng_credits_box_history_entry_peer(),
controller,
PeerId(entry.bareId));
}
if (!entry.id.isEmpty()) {
constexpr auto kOneLineCount = 18;
const auto oneLine = entry.id.length() <= kOneLineCount;
auto label = object_ptr<Ui::FlatLabel>(
table,
rpl::single(
Ui::Text::Wrapped({ entry.id }, EntityType::Code, {})),
oneLine
? st::giveawayGiftCodeValue
: st::giveawayGiftCodeValueMultiline);
label->setClickHandlerFilter([=](const auto &...) {
TextUtilities::SetClipboardText(
TextForMimeData::Simple(entry.id));
controller->showToast(
tr::lng_credits_box_history_entry_id_copied(tr::now));
return false;
});
AddTableRow(
table,
tr::lng_credits_box_history_entry_id(),
std::move(label),
st::giveawayGiftCodeValueMargin);
}
if (!entry.date.isNull()) {
AddTableRow(
table,
tr::lng_gift_link_label_date(),
rpl::single(Ui::Text::WithEntities(langDateTime(entry.date))));
}
}
@@ -16,12 +16,14 @@ struct GiftCode;
} // namespace Api
namespace Data {
struct CreditsHistoryEntry;
struct GiveawayStart;
struct GiveawayResults;
} // namespace Data
namespace Ui {
class GenericBox;
class VerticalLayout;
} // namespace Ui
namespace Window {
@@ -71,3 +73,8 @@ void ResolveGiveawayInfo(
MsgId messageId,
std::optional<Data::GiveawayStart> start,
std::optional<Data::GiveawayResults> results);
void AddCreditsHistoryEntryTable(
not_null<Window::SessionNavigation*> controller,
not_null<Ui::VerticalLayout*> container,
const Data::CreditsHistoryEntry &entry);
@@ -0,0 +1,856 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/moderate_messages_box.h"
#include "api/api_chat_participants.h"
#include "api/api_messages_search.h"
#include "apiwrap.h"
#include "base/event_filter.h"
#include "base/timer.h"
#include "boxes/delete_messages_box.h"
#include "boxes/peers/edit_peer_permissions_box.h"
#include "core/application.h"
#include "core/ui_integration.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_chat_participant_status.h"
#include "data/data_histories.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h"
#include "history/history.h"
#include "history/history_item.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/boxes/confirm_box.h"
#include "ui/controls/userpic_button.h"
#include "ui/effects/ripple_animation.h"
#include "ui/effects/toggle_arrow.h"
#include "ui/layers/generic_box.h"
#include "ui/painter.h"
#include "ui/rect.h"
#include "ui/rect_part.h"
#include "ui/text/text_utilities.h"
#include "ui/vertical_list.h"
#include "ui/widgets/checkbox.h"
#include "ui/wrap/slide_wrap.h"
#include "styles/style_boxes.h"
#include "styles/style_layers.h"
#include "styles/style_window.h"
namespace {
using Participants = std::vector<not_null<PeerData*>>;
struct ModerateOptions final {
bool allCanBan = false;
bool allCanDelete = false;
Participants participants;
};
ModerateOptions CalculateModerateOptions(const HistoryItemsList &items) {
Expects(!items.empty());
auto result = ModerateOptions{
.allCanBan = true,
.allCanDelete = true,
};
const auto peer = items.front()->history()->peer;
for (const auto &item : items) {
if (!result.allCanBan && !result.allCanDelete) {
return {};
}
if (peer != item->history()->peer) {
return {};
}
if (!item->suggestBanReport()) {
result.allCanBan = false;
}
if (!item->suggestDeleteAllReport()) {
result.allCanDelete = false;
}
if (const auto p = item->from()) {
if (!ranges::contains(result.participants, not_null{ p })) {
result.participants.push_back(p);
}
}
}
return result;
}
[[nodiscard]] rpl::producer<int> MessagesCountValue(
not_null<History*> history,
not_null<PeerData*> from) {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
auto search = lifetime.make_state<Api::MessagesSearch>(history);
consumer.put_next(0);
search->messagesFounds(
) | rpl::start_with_next([=](const Api::FoundMessages &found) {
consumer.put_next_copy(found.total);
}, lifetime);
search->searchMessages({ .from = from });
return lifetime;
};
}
class Button final : public Ui::RippleButton {
public:
Button(not_null<QWidget*> parent, int count);
void setChecked(bool checked);
[[nodiscard]] bool checked() const;
[[nodiscard]] static QSize ComputeSize(int);
private:
void paintEvent(QPaintEvent *event) override;
QImage prepareRippleMask() const override;
QPoint prepareRippleStartPosition() const override;
const int _count;
const QString _text;
bool _checked = false;
Ui::Animations::Simple _animation;
};
Button::Button(not_null<QWidget*> parent, int count)
: RippleButton(parent, st::defaultRippleAnimation)
, _count(count)
, _text(QString::number(std::abs(_count))) {
}
QSize Button::ComputeSize(int count) {
return QSize(
st::moderateBoxExpandHeight
+ st::moderateBoxExpand.width()
+ st::moderateBoxExpandInnerSkip * 4
+ st::moderateBoxExpandFont->width(
QString::number(std::abs(count)))
+ st::moderateBoxExpandToggleSize,
st::moderateBoxExpandHeight);
}
void Button::setChecked(bool checked) {
if (_checked == checked) {
return;
}
_checked = checked;
_animation.stop();
_animation.start(
[=] { update(); },
checked ? 0 : 1,
checked ? 1 : 0,
st::slideWrapDuration);
}
bool Button::checked() const {
return _checked;
}
void Button::paintEvent(QPaintEvent *event) {
auto p = Painter(this);
auto hq = PainterHighQualityEnabler(p);
Ui::RippleButton::paintRipple(p, QPoint());
const auto radius = height() / 2;
p.setPen(Qt::NoPen);
st::moderateBoxExpand.paint(
p,
radius,
(height() - st::moderateBoxExpand.height()) / 2,
width());
const auto innerSkip = st::moderateBoxExpandInnerSkip;
p.setBrush(Qt::NoBrush);
p.setPen(st::boxTextFg);
p.setFont(st::moderateBoxExpandFont);
p.drawText(
QRect(
innerSkip + radius + st::moderateBoxExpand.width(),
0,
width(),
height()),
_text,
style::al_left);
const auto path = Ui::ToggleUpDownArrowPath(
width() - st::moderateBoxExpandToggleSize - radius,
height() / 2,
st::moderateBoxExpandToggleSize,
st::moderateBoxExpandToggleFourStrokes,
_animation.value(_checked ? 1. : 0.));
p.fillPath(path, st::boxTextFg);
}
QImage Button::prepareRippleMask() const {
return Ui::RippleAnimation::RoundRectMask(size(), size().height() / 2);
}
QPoint Button::prepareRippleStartPosition() const {
return mapFromGlobal(QCursor::pos());
}
} // namespace
void CreateModerateMessagesBox(
not_null<Ui::GenericBox*> box,
const HistoryItemsList &items,
Fn<void()> confirmed) {
struct Controller final {
rpl::event_stream<bool> toggleRequestsFromTop;
rpl::event_stream<bool> toggleRequestsFromInner;
rpl::event_stream<bool> checkAllRequests;
Fn<Participants()> collectRequests;
};
const auto [allCanBan, allCanDelete, participants]
= CalculateModerateOptions(items);
const auto inner = box->verticalLayout();
Assert(!participants.empty());
const auto confirms = inner->lifetime().make_state<rpl::event_stream<>>();
const auto isSingle = participants.size() == 1;
const auto buttonPadding = isSingle
? QMargins()
: QMargins(0, 0, Button::ComputeSize(participants.size()).width(), 0);
const auto session = &items.front()->history()->session();
const auto historyPeerId = items.front()->history()->peer->id;
using Request = Fn<void(not_null<PeerData*>, not_null<ChannelData*>)>;
const auto sequentiallyRequest = [=](
Request request,
Participants participants) {
constexpr auto kSmallDelayMs = 5;
const auto participantIds = ranges::views::all(
participants
) | ranges::views::transform([](not_null<PeerData*> peer) {
return peer->id;
}) | ranges::to_vector;
const auto lifetime = std::make_shared<rpl::lifetime>();
const auto counter = lifetime->make_state<int>(0);
const auto timer = lifetime->make_state<base::Timer>();
timer->setCallback(crl::guard(session, [=] {
if ((*counter) < participantIds.size()) {
const auto peer = session->data().peer(historyPeerId);
const auto channel = peer ? peer->asChannel() : nullptr;
const auto from = session->data().peer(
participantIds[*counter]);
if (channel && from) {
request(from, channel);
}
(*counter)++;
} else {
lifetime->destroy();
}
}));
timer->callEach(kSmallDelayMs);
};
const auto handleConfirmation = [=](
not_null<Ui::Checkbox*> checkbox,
not_null<Controller*> controller,
Request request) {
confirms->events() | rpl::start_with_next([=] {
if (checkbox->checked() && controller->collectRequests) {
sequentiallyRequest(request, controller->collectRequests());
}
}, checkbox->lifetime());
};
const auto isEnter = [=](not_null<QEvent*> event) {
if (event->type() == QEvent::KeyPress) {
if (const auto k = static_cast<QKeyEvent*>(event.get())) {
return (k->key() == Qt::Key_Enter)
|| (k->key() == Qt::Key_Return);
}
}
return false;
};
base::install_event_filter(box, [=](not_null<QEvent*> event) {
if (isEnter(event)) {
box->triggerButton(0);
return base::EventFilterResult::Cancel;
}
return base::EventFilterResult::Continue;
});
const auto handleSubmition = [=](not_null<Ui::Checkbox*> checkbox) {
base::install_event_filter(box, [=](not_null<QEvent*> event) {
if (!isEnter(event) || !checkbox->checked()) {
return base::EventFilterResult::Continue;
}
box->uiShow()->show(Ui::MakeConfirmBox({
.text = tr::lng_gigagroup_warning_title(),
.confirmed = [=](Fn<void()> close) {
box->triggerButton(0);
close();
},
.confirmText = tr::lng_box_yes(),
.cancelText = tr::lng_box_no(),
}));
return base::EventFilterResult::Cancel;
});
};
const auto createParticipantsList = [&](
not_null<Controller*> controller) {
const auto wrap = inner->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
inner,
object_ptr<Ui::VerticalLayout>(inner)));
wrap->toggle(false, anim::type::instant);
controller->toggleRequestsFromTop.events(
) | rpl::start_with_next([=](bool toggled) {
wrap->toggle(toggled, anim::type::normal);
}, wrap->lifetime());
const auto container = wrap->entity();
Ui::AddSkip(container);
auto &lifetime = wrap->lifetime();
const auto clicks = lifetime.make_state<rpl::event_stream<>>();
const auto checkboxes = ranges::views::all(
participants
) | ranges::views::transform([&](not_null<PeerData*> peer) {
const auto line = container->add(
object_ptr<Ui::AbstractButton>(container));
const auto &st = st::moderateBoxUserpic;
line->resize(line->width(), st.size.height());
const auto userpic = Ui::CreateChild<Ui::UserpicButton>(
line,
peer,
st);
const auto checkbox = Ui::CreateChild<Ui::Checkbox>(
line,
peer->name(),
false,
st::defaultBoxCheckbox);
line->widthValue(
) | rpl::start_with_next([=](int width) {
userpic->moveToLeft(
st::boxRowPadding.left()
+ checkbox->checkRect().width()
+ st::defaultBoxCheckbox.textPosition.x(),
0);
const auto skip = st::defaultBoxCheckbox.textPosition.x();
checkbox->resizeToWidth(width
- rect::right(userpic)
- skip
- st::boxRowPadding.right());
checkbox->moveToLeft(
rect::right(userpic) + skip,
((userpic->height() - checkbox->height()) / 2)
+ st::defaultBoxCheckbox.margin.top());
}, checkbox->lifetime());
userpic->setAttribute(Qt::WA_TransparentForMouseEvents);
checkbox->setAttribute(Qt::WA_TransparentForMouseEvents);
line->setClickedCallback([=] {
checkbox->setChecked(!checkbox->checked());
clicks->fire({});
});
return checkbox;
}) | ranges::to_vector;
clicks->events(
) | rpl::start_with_next([=] {
controller->toggleRequestsFromInner.fire_copy(
ranges::any_of(checkboxes, &Ui::Checkbox::checked));
}, container->lifetime());
controller->checkAllRequests.events(
) | rpl::start_with_next([=](bool checked) {
for (const auto &c : checkboxes) {
c->setChecked(checked);
}
}, container->lifetime());
controller->collectRequests = [=] {
auto result = Participants();
for (auto i = 0; i < checkboxes.size(); i++) {
if (checkboxes[i]->checked()) {
result.push_back(participants[i]);
}
}
return result;
};
};
const auto appendList = [&](
not_null<Ui::Checkbox*> checkbox,
not_null<Controller*> controller) {
if (isSingle) {
const auto p = participants.front();
controller->collectRequests = [=] { return Participants{ p }; };
return;
}
const auto count = int(participants.size());
const auto button = Ui::CreateChild<Button>(inner, count);
button->resize(Button::ComputeSize(count));
const auto overlay = Ui::CreateChild<Ui::AbstractButton>(inner);
checkbox->geometryValue(
) | rpl::start_with_next([=](const QRect &rect) {
overlay->setGeometry(rect);
overlay->raise();
button->moveToRight(
st::moderateBoxExpandRight,
rect.top() + (rect.height() - button->height()) / 2,
box->width());
button->raise();
}, button->lifetime());
controller->toggleRequestsFromInner.events(
) | rpl::start_with_next([=](bool toggled) {
checkbox->setChecked(toggled);
}, checkbox->lifetime());
button->setClickedCallback([=] {
button->setChecked(!button->checked());
controller->toggleRequestsFromTop.fire_copy(button->checked());
});
overlay->setClickedCallback([=] {
checkbox->setChecked(!checkbox->checked());
controller->checkAllRequests.fire_copy(checkbox->checked());
});
createParticipantsList(controller);
};
Ui::AddSkip(inner);
const auto title = box->addRow(
object_ptr<Ui::FlatLabel>(
box,
(items.size() == 1)
? tr::lng_selected_delete_sure_this()
: tr::lng_selected_delete_sure(
lt_count,
rpl::single(items.size()) | tr::to_count()),
st::boxLabel));
Ui::AddSkip(inner);
Ui::AddSkip(inner);
Ui::AddSkip(inner);
{
const auto report = box->addRow(
object_ptr<Ui::Checkbox>(
box,
tr::lng_report_spam(tr::now),
false,
st::defaultBoxCheckbox),
st::boxRowPadding + buttonPadding);
const auto controller = box->lifetime().make_state<Controller>();
appendList(report, controller);
handleSubmition(report);
const auto ids = items.front()->from()->owner().itemsToIds(items);
handleConfirmation(report, controller, [=](
not_null<PeerData*> p,
not_null<ChannelData*> c) {
auto filtered = ranges::views::all(
ids
) | ranges::views::transform([](const FullMsgId &id) {
return MTP_int(id.msg);
}) | ranges::to<QVector<MTPint>>();
c->session().api().request(
MTPchannels_ReportSpam(
c->inputChannel,
p->input,
MTP_vector<MTPint>(std::move(filtered)))
).send();
});
}
if (allCanDelete) {
Ui::AddSkip(inner);
Ui::AddSkip(inner);
const auto deleteAll = inner->add(
object_ptr<Ui::Checkbox>(
inner,
!(isSingle)
? tr::lng_delete_all_from_users(
tr::now,
Ui::Text::WithEntities)
: tr::lng_delete_all_from_user(
tr::now,
lt_user,
Ui::Text::Bold(items.front()->from()->name()),
Ui::Text::WithEntities),
false,
st::defaultBoxCheckbox),
st::boxRowPadding + buttonPadding);
if (isSingle) {
const auto history = items.front()->history();
tr::lng_selected_delete_sure(
lt_count,
rpl::combine(
MessagesCountValue(history, participants.front()),
deleteAll->checkedValue()
) | rpl::map([s = items.size()](int all, bool checked) {
return float64((checked && all) ? all : s);
})
) | rpl::start_with_next([=](const QString &text) {
title->setText(text);
title->resizeToWidth(inner->width()
- rect::m::sum::h(st::boxRowPadding));
}, title->lifetime());
}
const auto controller = box->lifetime().make_state<Controller>();
appendList(deleteAll, controller);
handleSubmition(deleteAll);
handleConfirmation(deleteAll, controller, [=](
not_null<PeerData*> p,
not_null<ChannelData*> c) {
p->session().api().deleteAllFromParticipant(c, p);
});
}
if (allCanBan) {
auto ownedWrap = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
inner,
object_ptr<Ui::VerticalLayout>(inner));
Ui::AddSkip(inner);
Ui::AddSkip(inner);
const auto ban = inner->add(
object_ptr<Ui::Checkbox>(
box,
rpl::conditional(
ownedWrap->toggledValue(),
tr::lng_context_restrict_user(),
rpl::conditional(
rpl::single(isSingle),
tr::lng_ban_user(),
tr::lng_ban_users())),
false,
st::defaultBoxCheckbox),
st::boxRowPadding + buttonPadding);
const auto controller = box->lifetime().make_state<Controller>();
appendList(ban, controller);
handleSubmition(ban);
Ui::AddSkip(inner);
Ui::AddSkip(inner);
const auto wrap = inner->add(std::move(ownedWrap));
const auto container = wrap->entity();
wrap->toggle(false, anim::type::instant);
const auto session = &participants.front()->session();
const auto emojiMargin = QMargins(
-st::moderateBoxExpandInnerSkip,
-st::moderateBoxExpandInnerSkip / 2,
0,
0);
const auto emojiUp = Ui::Text::SingleCustomEmoji(
session->data().customEmojiManager().registerInternalEmoji(
st::moderateBoxExpandIcon,
emojiMargin,
false));
const auto emojiDown = Ui::Text::SingleCustomEmoji(
session->data().customEmojiManager().registerInternalEmoji(
st::moderateBoxExpandIconDown,
emojiMargin,
false));
auto label = object_ptr<Ui::FlatLabel>(
inner,
QString(),
st::moderateBoxDividerLabel);
const auto raw = label.data();
auto &lifetime = wrap->lifetime();
const auto scrollLifetime = lifetime.make_state<rpl::lifetime>();
label->setClickHandlerFilter([=](
const ClickHandlerPtr &handler,
Qt::MouseButton button) {
if (button != Qt::LeftButton) {
return false;
}
wrap->toggle(!wrap->toggled(), anim::type::normal);
{
inner->heightValue() | rpl::start_with_next([=] {
if (!wrap->animating()) {
scrollLifetime->destroy();
Ui::PostponeCall(crl::guard(box, [=] {
box->scrollToY(std::numeric_limits<int>::max());
}));
} else {
box->scrollToY(std::numeric_limits<int>::max());
}
}, *scrollLifetime);
}
return true;
});
wrap->toggledValue(
) | rpl::map([isSingle, emojiUp, emojiDown](bool toggled) {
return ((toggled && isSingle)
? tr::lng_restrict_user_part
: (toggled && !isSingle)
? tr::lng_restrict_users_part
: isSingle
? tr::lng_restrict_user_full
: tr::lng_restrict_users_full)(
lt_emoji,
rpl::single(toggled ? emojiUp : emojiDown),
Ui::Text::WithEntities);
}) | rpl::flatten_latest(
) | rpl::start_with_next([=](const TextWithEntities &text) {
raw->setMarkedText(
Ui::Text::Link(text, u"internal:"_q),
Core::MarkedTextContext{
.session = session,
.customEmojiRepaint = [=] { raw->update(); },
});
}, label->lifetime());
Ui::AddSkip(inner);
inner->add(object_ptr<Ui::DividerLabel>(
inner,
std::move(label),
st::defaultBoxDividerLabelPadding,
RectPart::Top | RectPart::Bottom));
using Flag = ChatRestriction;
using Flags = ChatRestrictions;
const auto peer = items.front()->history()->peer;
const auto chat = peer->asChat();
const auto channel = peer->asChannel();
const auto defaultRestrictions = chat
? chat->defaultRestrictions()
: channel->defaultRestrictions();
const auto prepareFlags = FixDependentRestrictions(
defaultRestrictions
| ((channel && channel->isPublic())
? (Flag::ChangeInfo | Flag::PinMessages)
: Flags(0)));
const auto disabledMessages = [&] {
auto result = base::flat_map<Flags, QString>();
{
const auto disabled = FixDependentRestrictions(
defaultRestrictions
| ((channel && channel->isPublic())
? (Flag::ChangeInfo | Flag::PinMessages)
: Flags(0)));
result.emplace(
disabled,
tr::lng_rights_restriction_for_all(tr::now));
}
return result;
}();
auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions(
box,
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())),
prepareFlags,
disabledMessages,
{ .isForum = peer->isForum() });
std::move(changes) | rpl::start_with_next([=] {
ban->setChecked(true);
}, ban->lifetime());
Ui::AddSkip(container);
Ui::AddDivider(container);
Ui::AddSkip(container);
container->add(std::move(checkboxes));
// Handle confirmation manually.
confirms->events() | rpl::start_with_next([=] {
if (ban->checked() && controller->collectRequests) {
const auto kick = !wrap->toggled();
const auto restrictions = getRestrictions();
const auto request = [=](
not_null<PeerData*> peer,
not_null<ChannelData*> channel) {
if (!kick) {
Api::ChatParticipants::Restrict(
channel,
peer,
ChatRestrictionsInfo(), // Unused.
ChatRestrictionsInfo(restrictions, 0),
nullptr,
nullptr);
} else {
channel->session().api().chatParticipants().kick(
channel,
peer,
{ channel->restrictions(), 0 });
}
};
sequentiallyRequest(request, controller->collectRequests());
}
}, ban->lifetime());
}
const auto close = crl::guard(box, [=] { box->closeBox(); });
{
const auto data = &participants.front()->session().data();
const auto ids = data->itemsToIds(items);
box->addButton(tr::lng_box_delete(), [=] {
confirms->fire({});
if (confirmed) {
confirmed();
}
data->histories().deleteMessages(ids, true);
data->sendHistoryChangeNotifications();
close();
});
}
box->addButton(tr::lng_cancel(), close);
}
bool CanCreateModerateMessagesBox(const HistoryItemsList &items) {
const auto options = CalculateModerateOptions(items);
return (options.allCanBan || options.allCanDelete)
&& !options.participants.empty();
}
void DeleteChatBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
const auto container = box->verticalLayout();
const auto maybeUser = peer->asUser();
Ui::AddSkip(container);
Ui::AddSkip(container);
base::install_event_filter(box, [=](not_null<QEvent*> event) {
if (event->type() == QEvent::KeyPress) {
if (const auto k = static_cast<QKeyEvent*>(event.get())) {
if ((k->key() == Qt::Key_Enter)
|| (k->key() == Qt::Key_Return)) {
box->uiShow()->show(Ui::MakeConfirmBox({
.text = tr::lng_gigagroup_warning_title(),
.confirmed = [=](Fn<void()> close) {
box->triggerButton(0);
close();
},
.confirmText = tr::lng_box_yes(),
.cancelText = tr::lng_box_no(),
}));
}
}
}
return base::EventFilterResult::Continue;
});
const auto line = container->add(object_ptr<Ui::RpWidget>(container));
const auto &st = st::mainMenuUserpic;
line->resize(line->width(), st.size.height());
const auto userpic = Ui::CreateChild<Ui::UserpicButton>(
line,
peer,
st);
userpic->showSavedMessagesOnSelf(true);
const auto label = Ui::CreateChild<Ui::FlatLabel>(
line,
peer->isSelf()
? tr::lng_saved_messages() | Ui::Text::ToBold()
: maybeUser
? tr::lng_profile_delete_conversation() | Ui::Text::ToBold()
: rpl::single(Ui::Text::Bold(peer->name())) | rpl::type_erased(),
box->getDelegate()->style().title);
line->widthValue(
) | rpl::start_with_next([=](int width) {
userpic->moveToLeft(st::boxRowPadding.left(), 0);
const auto skip = st::defaultBoxCheckbox.textPosition.x();
label->resizeToWidth(width
- rect::right(userpic)
- skip
- st::boxRowPadding.right());
label->moveToLeft(
rect::right(userpic) + skip,
((userpic->height() - label->height()) / 2));
}, label->lifetime());
userpic->setAttribute(Qt::WA_TransparentForMouseEvents);
label->setAttribute(Qt::WA_TransparentForMouseEvents);
Ui::AddSkip(container);
Ui::AddSkip(container);
box->addRow(
object_ptr<Ui::FlatLabel>(
container,
peer->isSelf()
? tr::lng_sure_delete_saved_messages()
: maybeUser
? tr::lng_sure_delete_history(
lt_contact,
rpl::single(peer->name()))
: (peer->isChannel() && !peer->isMegagroup())
? tr::lng_sure_leave_channel()
: tr::lng_sure_leave_group(),
st::boxLabel));
const auto maybeCheckbox = [&]() -> Ui::Checkbox* {
if (!peer->canRevokeFullHistory()) {
return nullptr;
}
Ui::AddSkip(container);
Ui::AddSkip(container);
return box->addRow(
object_ptr<Ui::Checkbox>(
container,
maybeUser
? tr::lng_delete_for_other_check(
tr::now,
lt_user,
TextWithEntities{ maybeUser->firstName },
Ui::Text::RichLangValue)
: tr::lng_delete_for_everyone_check(
tr::now,
Ui::Text::WithEntities),
false,
st::defaultBoxCheckbox));
}();
Ui::AddSkip(container);
auto buttonText = maybeUser
? tr::lng_box_delete()
: !maybeCheckbox
? tr::lng_box_leave()
: maybeCheckbox->checkedValue() | rpl::map([](bool checked) {
return checked ? tr::lng_box_delete() : tr::lng_box_leave();
}) | rpl::flatten_latest();
const auto close = crl::guard(box, [=] { box->closeBox(); });
box->addButton(std::move(buttonText), [=] {
const auto revoke = maybeCheckbox && maybeCheckbox->checked();
Core::App().closeChatFromWindows(peer);
// Don't delete old history by default,
// because Android app doesn't.
//
//if (const auto from = peer->migrateFrom()) {
// peer->session().api().deleteConversation(from, false);
//}
peer->session().api().deleteConversation(peer, revoke);
close();
}, st::attentionBoxButton);
box->addButton(tr::lng_cancel(), close);
}
@@ -0,0 +1,23 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class PeerData;
namespace Ui {
class GenericBox;
} // namespace Ui
void CreateModerateMessagesBox(
not_null<Ui::GenericBox*> box,
const HistoryItemsList &items,
Fn<void()> confirmed);
[[nodiscard]] bool CanCreateModerateMessagesBox(const HistoryItemsList &);
void DeleteChatBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer);
+101 -23
View File
@@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_widgets.h"
#include <xxhash.h> // XXH64.
#include <QtWidgets/QApplication>
[[nodiscard]] PeerListRowId UniqueRowIdFromString(const QString &d) {
return XXH64(d.data(), d.size() * sizeof(ushort), 0);
@@ -734,6 +735,10 @@ auto PeerListRow::generateNameWords() const
return peer()->nameWords();
}
const style::PeerListItem &PeerListRow::computeSt(
const style::PeerListItem &st) const {
return st;
}
void PeerListRow::invalidatePixmapsCache() {
if (_checkbox) {
@@ -816,9 +821,14 @@ void PeerListRow::stopLastRipple() {
}
}
void PeerListRow::paintRipple(Painter &p, int x, int y, int outerWidth) {
void PeerListRow::paintRipple(
Painter &p,
const style::PeerListItem &st,
int x,
int y,
int outerWidth) {
if (_ripple) {
_ripple->paint(p, x, y, outerWidth);
_ripple->paint(p, x, y, outerWidth, &st.button.ripple.color->c);
if (_ripple->empty()) {
_ripple.reset();
}
@@ -1543,15 +1553,44 @@ void PeerListContent::handleMouseMove(QPoint globalPosition) {
&& *_lastMousePosition == globalPosition) {
return;
}
if (_trackPressStart
&& ((*_trackPressStart - globalPosition).manhattanLength()
> QApplication::startDragDistance())) {
_trackPressStart = {};
_controller->rowTrackPressCancel();
}
if (!_controller->rowTrackPressSkipMouseSelection()) {
selectByMouse(globalPosition);
}
}
void PeerListContent::pressLeftToContextMenu(bool shown) {
if (shown) {
setContexted(_pressed);
setPressed(Selected());
} else {
setContexted(Selected());
}
}
bool PeerListContent::trackRowPressFromGlobal(QPoint globalPosition) {
selectByMouse(globalPosition);
if (const auto row = getRow(_selected.index)) {
if (_controller->rowTrackPress(row)) {
_trackPressStart = globalPosition;
return true;
}
}
return false;
}
void PeerListContent::mousePressEvent(QMouseEvent *e) {
_pressButton = e->button();
selectByMouse(e->globalPos());
setPressed(_selected);
if (auto row = getRow(_selected.index)) {
auto updateCallback = [this, row, hint = _selected.index] {
_trackPressStart = {};
if (const auto row = getRow(_selected.index)) {
const auto updateCallback = [this, row, hint = _selected.index] {
updateRow(row, hint);
};
if (_selected.element) {
@@ -1577,8 +1616,11 @@ void PeerListContent::mousePressEvent(QMouseEvent *e) {
row->addRipple(_st.item, maskGenerator, point, std::move(updateCallback));
}
}
if (_pressButton == Qt::LeftButton && _controller->rowTrackPress(row)) {
_trackPressStart = e->globalPos();
}
}
if (anim::Disabled() && !_selected.element) {
if (anim::Disabled() && !_trackPressStart && !_selected.element) {
mousePressReleased(e->button());
}
}
@@ -1588,6 +1630,9 @@ void PeerListContent::mouseReleaseEvent(QMouseEvent *e) {
}
void PeerListContent::mousePressReleased(Qt::MouseButton button) {
_trackPressStart = {};
_controller->rowTrackPressCancel();
updateRow(_pressed.index);
updateRow(_selected.index);
@@ -1689,7 +1734,9 @@ crl::time PeerListContent::paintRow(
const auto row = getRow(index);
Assert(row != nullptr);
row->lazyInitialize(_st.item);
const auto &st = row->computeSt(_st.item);
row->lazyInitialize(st);
const auto outerWidth = width();
auto refreshStatusAt = row->refreshStatusTime();
@@ -1717,8 +1764,8 @@ crl::time PeerListContent::paintRow(
const auto opacity = row->opacity();
const auto &bg = selected
? _st.item.button.textBgOver
: _st.item.button.textBg;
? st.button.textBgOver
: st.button.textBg;
if (opacity < 1.) {
p.setOpacity(opacity);
}
@@ -1729,36 +1776,37 @@ crl::time PeerListContent::paintRow(
});
p.fillRect(0, 0, outerWidth, _rowHeight, bg);
row->paintRipple(p, 0, 0, outerWidth);
row->paintRipple(p, st, 0, 0, outerWidth);
row->paintUserpic(
p,
_st.item,
_st.item.photoPosition.x(),
_st.item.photoPosition.y(),
st,
st.photoPosition.x(),
st.photoPosition.y(),
outerWidth);
p.setPen(st::contactsNameFg);
const auto skipRight = _st.item.photoPosition.x();
const auto skipRight = st.photoPosition.x();
const auto rightActionSize = row->rightActionSize();
const auto rightActionMargins = rightActionSize.isEmpty()
? QMargins()
: row->rightActionMargins();
const auto &name = row->name();
const auto namex = _st.item.namePosition.x();
const auto namey = _st.item.namePosition.y();
const auto namePosition = st.namePosition;
const auto namex = namePosition.x();
const auto namey = namePosition.y();
auto namew = outerWidth - namex - skipRight;
if (!rightActionSize.isEmpty()
&& (namey < rightActionMargins.top() + rightActionSize.height())
&& (namey + _st.item.nameStyle.font->height
&& (namey + st.nameStyle.font->height
> rightActionMargins.top())) {
namew -= rightActionMargins.left()
+ rightActionSize.width()
+ rightActionMargins.right()
- skipRight;
}
const auto statusx = _st.item.statusPosition.x();
const auto statusy = _st.item.statusPosition.y();
const auto statusx = st.statusPosition.x();
const auto statusy = st.statusPosition.y();
auto statusw = outerWidth - statusx - skipRight;
if (!rightActionSize.isEmpty()
&& (statusy < rightActionMargins.top() + rightActionSize.height())
@@ -1780,7 +1828,7 @@ crl::time PeerListContent::paintRow(
width(),
selected);
auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
p.setPen(anim::pen(_st.item.nameFg, _st.item.nameFgChecked, nameCheckedRatio));
p.setPen(anim::pen(st.nameFg, st.nameFgChecked, nameCheckedRatio));
name.drawLeftElided(p, namex, namey, namew, width());
p.setFont(st::contactsStatusFont);
@@ -1799,17 +1847,17 @@ crl::time PeerListContent::paintRow(
if (highlightedWidth > availableWidth) {
highlightedPart = st::contactsStatusFont->elided(highlightedPart, availableWidth);
}
p.setPen(_st.item.statusFgActive);
p.setPen(st.statusFgActive);
p.drawTextLeft(statusx, statusy, width(), highlightedPart);
} else {
grayedPart = st::contactsStatusFont->elided(grayedPart, availableWidth - highlightedWidth);
p.setPen(_st.item.statusFgActive);
p.setPen(st.statusFgActive);
p.drawTextLeft(statusx, statusy, width(), highlightedPart);
p.setPen(selected ? _st.item.statusFgOver : _st.item.statusFg);
p.setPen(selected ? st.statusFgOver : st.statusFg);
p.drawTextLeft(statusx + highlightedWidth, statusy, width(), grayedPart);
}
} else {
row->paintStatusText(p, _st.item, statusx, statusy, statusw, width(), selected);
row->paintStatusText(p, st, statusx, statusy, statusw, width(), selected);
}
row->elementsPaint(
@@ -1905,10 +1953,30 @@ void PeerListContent::selectSkipPage(int height, int direction) {
selectSkip(rowsToSkip * direction);
}
void PeerListContent::selectLast() {
const auto rowsCount = shownRowsCount();
const auto newSelectedIndex = rowsCount - 1;
_selected.index.value = newSelectedIndex;
_selected.element = 0;
if (newSelectedIndex >= 0) {
auto top = (newSelectedIndex > 0) ? getRowTop(RowIndex(newSelectedIndex)) : 0;
auto bottom = (newSelectedIndex + 1 < rowsCount) ? getRowTop(RowIndex(newSelectedIndex + 1)) : height();
_scrollToRequests.fire({ top, bottom });
}
update();
_selectedIndex = _selected.index.value;
}
rpl::producer<int> PeerListContent::selectedIndexValue() const {
return _selectedIndex.value();
}
int PeerListContent::selectedIndex() const {
return _selectedIndex.current();
}
bool PeerListContent::hasSelection() const {
return _selected.index.value >= 0;
}
@@ -2093,6 +2161,16 @@ bool PeerListContent::submitted() {
return false;
}
PeerListRowId PeerListContent::updateFromParentDrag(QPoint globalPosition) {
selectByMouse(globalPosition);
const auto row = getRow(_selected.index);
return row ? row->id() : 0;
}
void PeerListContent::dragLeft() {
clearSelection();
}
void PeerListContent::visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) {
+35 -1
View File
@@ -100,6 +100,8 @@ public:
-> const base::flat_set<QChar> &;
[[nodiscard]] virtual auto generateNameWords() const
-> const base::flat_set<QString> &;
[[nodiscard]] virtual const style::PeerListItem &computeSt(
const style::PeerListItem &st) const;
virtual void preloadUserpic();
@@ -228,7 +230,12 @@ public:
QPoint point,
UpdateCallback &&updateCallback);
void stopLastRipple();
void paintRipple(Painter &p, int x, int y, int outerWidth);
void paintRipple(
Painter &p,
const style::PeerListItem &st,
int x,
int y,
int outerWidth);
void paintUserpic(
Painter &p,
const style::PeerListItem &st,
@@ -341,6 +348,9 @@ public:
virtual int peerListPartitionRows(Fn<bool(const PeerListRow &a)> border) = 0;
virtual std::shared_ptr<Main::SessionShow> peerListUiShow() = 0;
virtual void peerListPressLeftToContextMenu(bool shown) = 0;
virtual bool peerListTrackRowPressFromGlobal(QPoint globalPosition) = 0;
template <typename PeerDataRange>
void peerListAddSelectedPeers(PeerDataRange &&range) {
for (const auto peer : range) {
@@ -471,6 +481,15 @@ public:
}
}
virtual bool rowTrackPress(not_null<PeerListRow*> row) {
return false;
}
virtual void rowTrackPressCancel() {
}
virtual bool rowTrackPressSkipMouseSelection() {
return false;
}
virtual void loadMoreRows() {
}
virtual void itemDeselectedHook(not_null<PeerData*> peer) {
@@ -601,6 +620,7 @@ public:
};
SkipResult selectSkip(int direction);
void selectSkipPage(int height, int direction);
void selectLast();
enum class Mode {
Default,
@@ -609,6 +629,7 @@ public:
void setMode(Mode mode);
[[nodiscard]] rpl::producer<int> selectedIndexValue() const;
[[nodiscard]] int selectedIndex() const;
[[nodiscard]] bool hasSelection() const;
[[nodiscard]] bool hasPressed() const;
void clearSelection();
@@ -616,6 +637,9 @@ public:
void searchQueryChanged(QString query);
bool submitted();
PeerListRowId updateFromParentDrag(QPoint globalPosition);
void dragLeft();
// Interface for the controller.
void appendRow(std::unique_ptr<PeerListRow> row);
void appendSearchRow(std::unique_ptr<PeerListRow> row);
@@ -643,6 +667,8 @@ public:
void refreshRows();
void mouseLeftGeometry();
void pressLeftToContextMenu(bool shown);
bool trackRowPressFromGlobal(QPoint globalPosition);
void setSearchMode(PeerListSearchMode mode);
void changeCheckState(
@@ -817,6 +843,7 @@ private:
bool _mouseSelection = false;
std::optional<QPoint> _lastMousePosition;
Qt::MouseButton _pressButton = Qt::LeftButton;
std::optional<QPoint> _trackPressStart;
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
@@ -980,6 +1007,13 @@ public:
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) override;
void peerListPressLeftToContextMenu(bool shown) override {
_content->pressLeftToContextMenu(shown);
}
bool peerListTrackRowPressFromGlobal(QPoint globalPosition) override {
return _content->trackRowPressFromGlobal(globalPosition);
}
protected:
not_null<PeerListContent*> content() const {
return _content;
@@ -42,16 +42,14 @@ namespace {
constexpr auto kDefaultIconId = DocumentId(0x7FFF'FFFF'FFFF'FFFFULL);
struct DefaultIcon {
QString title;
int32 colorId = 0;
};
using DefaultIcon = Data::TopicIconDescriptor;
class DefaultIconEmoji final : public Ui::Text::CustomEmoji {
public:
DefaultIconEmoji(
rpl::producer<DefaultIcon> value,
Fn<void()> repaint);
Fn<void()> repaint,
Data::CustomEmojiSizeTag tag);
int width() override;
QString entityData() override;
@@ -64,14 +62,17 @@ public:
private:
DefaultIcon _icon = {};
QImage _image;
Data::CustomEmojiSizeTag _tag = {};
rpl::lifetime _lifetime;
};
DefaultIconEmoji::DefaultIconEmoji(
rpl::producer<DefaultIcon> value,
Fn<void()> repaint) {
rpl::producer<DefaultIcon> value,
Fn<void()> repaint,
Data::CustomEmojiSizeTag tag)
: _tag(tag) {
std::move(value) | rpl::start_with_next([=](DefaultIcon value) {
_icon = value;
_image = QImage();
@@ -88,15 +89,22 @@ QString DefaultIconEmoji::entityData() {
}
void DefaultIconEmoji::paint(QPainter &p, const Context &context) {
const auto &st = (_tag == Data::CustomEmojiSizeTag::Normal)
? st::normalForumTopicIcon
: st::defaultForumTopicIcon;
if (_image.isNull()) {
_image = Data::ForumTopicIconFrame(
_icon.colorId,
_icon.title,
st::defaultForumTopicIcon);
_image = Data::IsForumGeneralIconTitle(_icon.title)
? Data::ForumTopicGeneralIconFrame(
st.size,
Data::ParseForumGeneralIconColor(_icon.colorId))
: Data::ForumTopicIconFrame(_icon.colorId, _icon.title, st);
}
const auto esize = Ui::Emoji::GetSizeLarge() / style::DevicePixelRatio();
const auto full = (_tag == Data::CustomEmojiSizeTag::Normal)
? Ui::Emoji::GetSizeNormal()
: Ui::Emoji::GetSizeLarge();
const auto esize = full / style::DevicePixelRatio();
const auto customSize = Ui::Text::AdjustCustomEmojiSize(esize);
const auto skip = (customSize - st::defaultForumTopicIcon.size) / 2;
const auto skip = (customSize - st.size) / 2;
p.drawImage(context.position + QPoint(skip, skip), _image);
}
@@ -212,7 +220,7 @@ bool DefaultIconEmoji::readyInDefaultState() {
) | rpl::start_with_next([=] {
state->frame = Data::ForumTopicGeneralIconFrame(
st::largeForumTopicIcon.size,
st::windowSubTextFg);
st::windowSubTextFg->c);
result->update();
}, result->lifetime());
@@ -261,7 +269,8 @@ struct IconSelector {
if (id == kDefaultIconId) {
return std::make_unique<DefaultIconEmoji>(
rpl::duplicate(defaultIcon),
repaint);
std::move(repaint),
tag);
}
return manager->create(id, std::move(repaint), tag);
};
@@ -572,3 +581,13 @@ void EditForumTopicBox(
box->closeBox();
});
}
std::unique_ptr<Ui::Text::CustomEmoji> MakeTopicIconEmoji(
Data::TopicIconDescriptor descriptor,
Fn<void()> repaint,
Data::CustomEmojiSizeTag tag) {
return std::make_unique<DefaultIconEmoji>(
rpl::single(descriptor),
std::move(repaint),
tag);
}
@@ -11,6 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History;
namespace Data {
struct TopicIconDescriptor;
enum class CustomEmojiSizeTag : uchar;
} // namespace Data
namespace Window {
class SessionController;
} // namespace Window
@@ -25,3 +30,8 @@ void EditForumTopicBox(
not_null<Window::SessionController*> controller,
not_null<History*> forum,
MsgId rootId);
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> MakeTopicIconEmoji(
Data::TopicIconDescriptor descriptor,
Fn<void()> repaint,
Data::CustomEmojiSizeTag tag);
@@ -166,33 +166,6 @@ void SaveChannelAdmin(
}).send();
}
void SaveChannelRestriction(
not_null<ChannelData*> channel,
not_null<PeerData*> participant,
ChatRestrictionsInfo oldRights,
ChatRestrictionsInfo newRights,
Fn<void()> onDone,
Fn<void()> onFail) {
channel->session().api().request(MTPchannels_EditBanned(
channel->inputChannel,
participant->input,
MTP_chatBannedRights(
MTP_flags(MTPDchatBannedRights::Flags::from_raw(
uint32(newRights.flags))),
MTP_int(newRights.until))
)).done([=](const MTPUpdates &result) {
channel->session().api().applyUpdates(result);
channel->applyEditBanned(participant, oldRights, newRights);
if (onDone) {
onDone();
}
}).fail([=] {
if (onFail) {
onFail();
}
}).send();
}
void SaveChatParticipantKick(
not_null<ChatData*> chat,
not_null<UserData*> user,
@@ -275,7 +248,7 @@ Fn<void(
ChatRestrictionsInfo newRights) {
const auto done = [=] { if (onDone) onDone(newRights); };
const auto saveForChannel = [=](not_null<ChannelData*> channel) {
SaveChannelRestriction(
Api::ChatParticipants::Restrict(
channel,
participant,
oldRights,
@@ -312,6 +312,7 @@ PreviewWrap::PreviewWrap(
nullptr, // document
WebPageCollage(),
nullptr, // iv
nullptr, // stickerSet
0, // duration
QString(), // author
false, // hasLargeMedia
@@ -1427,14 +1428,15 @@ void SetupPeerColorSample(
void AddPeerColorButton(
not_null<Ui::VerticalLayout*> container,
std::shared_ptr<ChatHelpers::Show> show,
not_null<PeerData*> peer) {
not_null<PeerData*> peer,
const style::SettingsButton &st) {
auto label = peer->isSelf()
? tr::lng_settings_theme_name_color()
: tr::lng_edit_channel_color();
const auto button = AddButtonWithIcon(
container,
rpl::duplicate(label),
st::settingsColorButton,
st,
{ &st::menuIconChangeColors });
const auto style = std::make_shared<Ui::ChatStyle>(
@@ -48,7 +48,8 @@ void EditPeerColorBox(
void AddPeerColorButton(
not_null<Ui::VerticalLayout*> container,
std::shared_ptr<ChatHelpers::Show> show,
not_null<PeerData*> peer);
not_null<PeerData*> peer,
const style::SettingsButton &st);
void CheckBoostLevel(
std::shared_ptr<ChatHelpers::Show> show,
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_user_names.h"
#include "main/main_session.h"
#include "ui/boxes/confirm_box.h"
#include "base/event_filter.h"
#include "boxes/peers/edit_participants_box.h"
#include "boxes/peers/edit_peer_color_box.h"
#include "boxes/peers/edit_peer_common.h"
@@ -27,6 +28,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/stickers_box.h"
#include "boxes/username_box.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "data/data_channel.h"
@@ -47,6 +50,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_app_config.h"
#include "settings/settings_common.h"
#include "ui/boxes/boost_box.h"
#include "ui/controls/emoji_button.h"
#include "ui/controls/userpic_button.h"
#include "ui/rp_widget.h"
#include "ui/vertical_list.h"
@@ -61,6 +65,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
#include "api/api_invite_links.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_layers.h"
#include "styles/style_menu_icons.h"
#include "styles/style_boxes.h"
@@ -410,7 +415,12 @@ private:
std::deque<FnMut<void()>> _saveStagesQueue;
Saving _savingData;
const rpl::event_stream<Privacy> _privacyTypeUpdates;
struct PrivacyAndForwards {
Privacy privacy;
bool noForwards = false;
};
const rpl::event_stream<PrivacyAndForwards> _privacyTypeUpdates;
const rpl::event_stream<ChannelData*> _linkedChatUpdates;
mtpRequestId _linkedChatsRequestId = 0;
@@ -533,7 +543,7 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
_wrap,
object_ptr<Ui::InputField>(
_wrap,
st::defaultInputField,
st::editPeerTitleField,
(_isBot
? tr::lng_dlg_new_bot_name
: _isGroup
@@ -555,6 +565,76 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
submitTitle();
}, result->entity()->lifetime());
{
const auto field = result->entity();
const auto container = _box->getDelegate()->outerContainer();
using Selector = ChatHelpers::TabbedSelector;
using PanelPtr = base::unique_qptr<ChatHelpers::TabbedPanel>;
const auto emojiPanelPtr = field->lifetime().make_state<PanelPtr>(
base::make_unique_q<ChatHelpers::TabbedPanel>(
container,
ChatHelpers::TabbedPanelDescriptor{
.ownedSelector = object_ptr<Selector>(
nullptr,
ChatHelpers::TabbedSelectorDescriptor{
.show = _navigation->uiShow(),
.st = st::defaultComposeControls.tabbed,
.level = Window::GifPauseReason::Layer,
.mode = Selector::Mode::PeerTitle,
}),
}));
const auto emojiPanel = emojiPanelPtr->get();
emojiPanel->setDesiredHeightValues(
1.,
st::emojiPanMinHeight / 2,
st::emojiPanMinHeight);
emojiPanel->hide();
emojiPanel->selector()->setCurrentPeer(_peer);
emojiPanel->selector()->emojiChosen(
) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
Ui::InsertEmojiAtCursor(field->textCursor(), data.emoji);
field->setFocus();
}, field->lifetime());
emojiPanel->setDropDown(true);
const auto emojiToggle = Ui::CreateChild<Ui::EmojiButton>(
field,
st::defaultComposeControls.files.emoji);
emojiToggle->show();
emojiToggle->installEventFilter(emojiPanel);
emojiToggle->addClickHandler([=] { emojiPanel->toggleAnimated(); });
const auto updateEmojiPanelGeometry = [=] {
const auto parent = emojiPanel->parentWidget();
const auto global = emojiToggle->mapToGlobal({ 0, 0 });
const auto local = parent->mapFromGlobal(global);
emojiPanel->moveTopRight(
local.y() + emojiToggle->height(),
local.x() + emojiToggle->width() * 3);
};
base::install_event_filter(container, [=](not_null<QEvent*> event) {
const auto type = event->type();
if (type == QEvent::Move || type == QEvent::Resize) {
crl::on_main(field, [=] { updateEmojiPanelGeometry(); });
}
return base::EventFilterResult::Continue;
});
field->widthValue() | rpl::start_with_next([=](int width) {
const auto &p = st::editPeerTitleEmojiPosition;
emojiToggle->moveToRight(p.x(), p.y(), width);
updateEmojiPanelGeometry();
}, emojiToggle->lifetime());
base::install_event_filter(emojiToggle, [=](not_null<QEvent*> event) {
if (event->type() == QEvent::Enter) {
updateEmojiPanelGeometry();
}
return base::EventFilterResult::Continue;
});
}
_controls.title = result->entity();
return result;
}
@@ -686,7 +766,7 @@ void Controller::refreshHistoryVisibility() {
void Controller::showEditPeerTypeBox(
std::optional<rpl::producer<QString>> error) {
const auto boxCallback = crl::guard(this, [=](EditPeerTypeData data) {
_privacyTypeUpdates.fire_copy(data.privacy);
_privacyTypeUpdates.fire({ data.privacy, data.noForwards });
_typeDataSavedValue = data;
refreshHistoryVisibility();
});
@@ -807,7 +887,8 @@ void Controller::fillPrivacyTypeButton() {
? tr::lng_manage_peer_group_type
: tr::lng_manage_peer_channel_type)(),
_privacyTypeUpdates.events(
) | rpl::map([=](Privacy flag) {
) | rpl::map([=](PrivacyAndForwards data) {
const auto flag = data.privacy;
if (flag == Privacy::HasUsername) {
_peer->session().api().usernames().requestToCache(_peer);
}
@@ -819,14 +900,21 @@ void Controller::fillPrivacyTypeButton() {
: tr::lng_manage_public_peer_title)()
: (hasLocation
? tr::lng_manage_peer_link_invite
: isGroup
: ((!data.noForwards) && isGroup)
? tr::lng_manage_private_group_title
: tr::lng_manage_private_peer_title)();
: ((!data.noForwards) && !isGroup)
? tr::lng_manage_private_peer_title
: isGroup
? tr::lng_manage_private_group_noforwards_title
: tr::lng_manage_private_peer_noforwards_title)();
}) | rpl::flatten_latest(),
[=] { showEditPeerTypeBox(); },
{ &st::menuIconCustomize });
_privacyTypeUpdates.fire_copy(_typeDataSavedValue->privacy);
_privacyTypeUpdates.fire_copy({
_typeDataSavedValue->privacy,
_typeDataSavedValue->noForwards,
});
}
void Controller::fillLinkedChatButton() {
@@ -941,7 +1029,11 @@ void Controller::fillColorIndexButton() {
Expects(_controls.buttonsLayout != nullptr);
const auto show = _navigation->uiShow();
AddPeerColorButton(_controls.buttonsLayout, show, _peer);
AddPeerColorButton(
_controls.buttonsLayout,
_navigation->uiShow(),
_peer,
st::managePeerColorsButton);
}
void Controller::fillSignaturesButton() {
@@ -7,30 +7,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/peers/edit_peer_reactions.h"
#include "apiwrap.h"
#include "base/event_filter.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "data/data_chat.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_document.h"
#include "data/data_peer_values.h" // UniqueReactionsLimit.
#include "data/data_session.h"
#include "data/data_user.h"
#include "history/view/reactions/history_view_reactions_selector.h"
#include "main/main_session.h"
#include "apiwrap.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/boxes/boost_box.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/checkbox.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/vertical_list.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/wrap/slide_wrap.h"
#include "window/window_session_controller.h"
#include "window/window_session_controller_link_info.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_info.h"
#include "styles/style_settings.h"
#include "styles/style_layers.h"
#include "styles/style_settings.h"
#include <QtWidgets/QTextEdit>
#include <QtGui/QTextBlock>
@@ -705,12 +708,16 @@ void EditAllowedReactionsBox(
}
};
changed(selected.empty() ? DefaultSelected() : std::move(selected), {});
Ui::AddSubsectionTitle(
reactions,
enabled
? tr::lng_manage_peer_reactions_available()
: tr::lng_manage_peer_reactions_some_title(),
st::manageGroupReactionsFieldPadding);
reactions->add(AddReactionsSelector(reactions, {
.outer = box->getDelegate()->outerContainer(),
.controller = args.navigation->parentController(),
.title = (enabled
? tr::lng_manage_peer_reactions_available()
: tr::lng_manage_peer_reactions_some_title()),
.title = tr::lng_manage_peer_reactions_available_ph(),
.list = all,
.selected = state->selected,
.callback = changed,
@@ -726,6 +733,7 @@ void EditAllowedReactionsBox(
}
});
const auto reactionsLimit = container->lifetime().make_state<int>(0);
if (!isGroup) {
AddReactionsText(
container,
@@ -733,9 +741,109 @@ void EditAllowedReactionsBox(
args.allowedCustomReactions,
state->customCount.value(),
args.askForBoosts);
const auto session = &args.navigation->parentController()->session();
const auto wrap = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container)));
const auto max = Data::UniqueReactionsLimit(session->user());
const auto inactiveColor = std::make_optional(st::windowSubTextFg->c);
const auto activeColor = std::make_optional(
st::windowActiveTextFg->c);
const auto inner = wrap->entity();
Ui::AddSkip(inner);
Ui::AddSubsectionTitle(
inner,
tr::lng_manage_peer_reactions_max_title(),
st::manageGroupReactionsMaxSubtitlePadding);
Ui::AddSkip(inner);
const auto line = inner->add(
object_ptr<Ui::RpWidget>(inner),
st::boxRowPadding);
Ui::AddSkip(inner);
Ui::AddSkip(inner);
const auto left = Ui::CreateChild<Ui::FlatLabel>(
line,
QString::number(1),
st::defaultFlatLabel);
const auto center = Ui::CreateChild<Ui::FlatLabel>(
line,
st::defaultFlatLabel);
const auto right = Ui::CreateChild<Ui::FlatLabel>(
line,
QString::number(max),
st::defaultFlatLabel);
const auto slider = Ui::CreateChild<Ui::MediaSlider>(
line,
st::settingsScale);
rpl::combine(
line->sizeValue(),
left->sizeValue(),
center->sizeValue(),
right->sizeValue()
) | rpl::start_with_next([=](
const QSize &s,
const QSize &leftSize,
const QSize &centerSize,
const QSize &rightSize) {
const auto sliderHeight = st::settingsScale.seekSize.height();
line->resize(
line->width(),
leftSize.height() + sliderHeight * 2);
{
const auto r = line->rect();
slider->setGeometry(
0,
r.height() - sliderHeight * 1.5,
r.width(),
sliderHeight);
}
left->moveToLeft(0, 0);
right->moveToRight(0, 0);
center->moveToLeft((s.width() - centerSize.width()) / 2, 0);
}, line->lifetime());
const auto updateLabels = [=](int limit) {
left->setTextColorOverride((limit <= 1)
? activeColor
: inactiveColor);
center->setText(tr::lng_manage_peer_reactions_max_slider(
tr::now,
lt_count,
limit));
center->setTextColorOverride(activeColor);
right->setTextColorOverride((limit >= max)
? activeColor
: inactiveColor);
(*reactionsLimit) = limit;
};
const auto current = args.allowed.maxCount
? std::clamp(1, args.allowed.maxCount, max)
: max / 2;
slider->setPseudoDiscrete(
max,
[=](int index) { return index + 1; },
current,
updateLabels,
updateLabels);
updateLabels(current);
wrap->toggleOn(rpl::single(
optionInitial != Option::None
) | rpl::then(
state->selectorState.value(
) | rpl::map(rpl::mappers::_1 == SelectorState::Active)));
Ui::AddDividerText(inner, tr::lng_manage_peer_reactions_max_about());
}
const auto collect = [=] {
auto result = AllowedReactions();
result.maxCount = (*reactionsLimit);
if (isGroup
? (state->option.current() == Option::Some)
: (enabled->toggled())) {
@@ -783,6 +891,7 @@ void SaveAllowedReactions(
Data::ReactionToMTP
) | ranges::to<QVector<MTPReaction>>;
using Flag = MTPmessages_SetChatAvailableReactions::Flag;
using Type = Data::AllowedReactionsType;
const auto updated = (allowed.type != Type::Some)
? MTP_chatReactionsAll(MTP_flags((allowed.type == Type::Default)
@@ -792,14 +901,18 @@ void SaveAllowedReactions(
? MTP_chatReactionsNone()
: MTP_chatReactionsSome(MTP_vector<MTPReaction>(ids));
peer->session().api().request(MTPmessages_SetChatAvailableReactions(
allowed.maxCount ? MTP_flags(Flag::f_reactions_limit) : MTP_flags(0),
peer->input,
updated
updated,
MTP_int(allowed.maxCount)
)).done([=](const MTPUpdates &result) {
peer->session().api().applyUpdates(result);
auto parsed = Data::Parse(updated);
parsed.maxCount = allowed.maxCount;
if (const auto chat = peer->asChat()) {
chat->setAllowedReactions(Data::Parse(updated));
chat->setAllowedReactions(parsed);
} else if (const auto channel = peer->asChannel()) {
channel->setAllowedReactions(Data::Parse(updated));
channel->setAllowedReactions(parsed);
} else {
Unexpected("Invalid peer type in SaveAllowedReactions.");
}
@@ -398,7 +398,7 @@ void PeerShortInfoCover::paintRadial(QPainter &p) {
QImage PeerShortInfoCover::currentVideoFrame() const {
const auto size = QSize(_st.size, _st.size);
const auto request = Media::Streaming::FrameRequest{
.resize = size * style::DevicePixelRatio(),
.resize = size,
.outer = size,
};
return (_videoInstance
@@ -286,7 +286,7 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
document,
media->videoThumbnailContent(),
QString(),
true);
Stickers::EffectType::PremiumSticker);
const auto update = [=] {
if (!state->readyInvoked
@@ -913,7 +913,7 @@ void PreviewBox(
auto businessOrder = Settings::BusinessFeaturesOrder(&show->session());
state->order = ranges::contains(businessOrder, descriptor.section)
? std::move(businessOrder)
: ranges::contains(businessOrder, descriptor.section)
: ranges::contains(premiumOrder, descriptor.section)
? std::move(premiumOrder)
: std::vector{ descriptor.section };
@@ -16,8 +16,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/admin_log/history_admin_log_item.h"
#include "history/history.h"
#include "history/history_item.h"
#include "history/view/history_view_element.h"
#include "history/view/reactions/history_view_reactions_strip.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_fake_items.h"
#include "lang/lang_keys.h"
#include "boxes/premium_preview_box.h"
#include "main/main_session.h"
@@ -43,53 +44,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
PeerId GenerateUser(not_null<History*> history, const QString &name) {
Expects(history->peer->isUser());
const auto peerId = Data::FakePeerIdForJustName(name);
history->owner().processUser(MTP_user(
MTP_flags(MTPDuser::Flag::f_first_name | MTPDuser::Flag::f_min),
peerToBareMTPInt(peerId),
MTP_long(0),
MTP_string(tr::lng_settings_chat_message_reply_from(tr::now)),
MTPstring(), // last name
MTPstring(), // username
MTPstring(), // phone
MTPUserProfilePhoto(), // profile photo
MTPUserStatus(), // status
MTP_int(0), // bot info version
MTPVector<MTPRestrictionReason>(), // restrictions
MTPstring(), // bot placeholder
MTPstring(), // lang code
MTPEmojiStatus(),
MTPVector<MTPUsername>(),
MTPint(), // stories_max_id
MTPPeerColor(), // color
MTPPeerColor())); // profile_color
return peerId;
}
AdminLog::OwnedItem GenerateItem(
not_null<HistoryView::ElementDelegate*> delegate,
not_null<History*> history,
PeerId from,
FullMsgId replyTo,
const QString &text) {
Expects(history->peer->isUser());
const auto item = history->addNewLocalMessage({
.id = history->nextNonHistoryEntryId(),
.flags = (MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId
| MessageFlag::HasReplyInfo),
.from = from,
.replyTo = FullReplyTo{ .messageId = replyTo },
.date = base::unixtime::now(),
}, TextWithEntities{ .text = text }, MTP_messageMediaEmpty());
return AdminLog::OwnedItem(delegate, item);
}
void AddMessage(
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller,
@@ -135,15 +89,15 @@ void AddMessage(
const auto history = controller->session().data().history(
PeerData::kServiceNotificationsId);
state->reply = GenerateItem(
state->reply = HistoryView::GenerateItem(
state->delegate.get(),
history,
GenerateUser(
HistoryView::GenerateUser(
history,
tr::lng_settings_chat_message_reply_from(tr::now)),
FullMsgId(),
tr::lng_settings_chat_message_reply(tr::now));
auto message = GenerateItem(
auto message = HistoryView::GenerateItem(
state->delegate.get(),
history,
history->peer->id,
@@ -0,0 +1,250 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/send_credits_box.h"
#include "api/api_credits.h"
#include "apiwrap.h"
#include "core/ui_integration.h" // Core::MarkedTextContext.
#include "data/data_credits.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h"
#include "history/history.h"
#include "history/history_item.h"
#include "info/channel_statistics/boosts/giveaway/boost_badge.h" // InfiniteRadialAnimationWidget.
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "payments/payments_checkout_process.h"
#include "payments/payments_form.h"
#include "settings/settings_credits_graphics.h"
#include "ui/controls/userpic_button.h"
#include "ui/effects/premium_graphics.h"
#include "ui/effects/premium_top_bar.h" // Ui::Premium::ColorizedSvg.
#include "ui/image/image_prepare.h"
#include "ui/layers/generic_box.h"
#include "ui/rect.h"
#include "ui/text/text_utilities.h"
#include "ui/vertical_list.h"
#include "ui/widgets/buttons.h"
#include "styles/style_boxes.h"
#include "styles/style_credits.h"
#include "styles/style_giveaway.h"
#include "styles/style_layers.h"
#include "styles/style_premium.h"
#include "styles/style_settings.h"
namespace Ui {
void SendCreditsBox(
not_null<Ui::GenericBox*> box,
std::shared_ptr<Payments::CreditsFormData> form,
Fn<void()> sent) {
if (!form) {
return;
}
struct State {
rpl::variable<bool> confirmButtonBusy = false;
};
const auto state = box->lifetime().make_state<State>();
box->setStyle(st::giveawayGiftCodeBox);
box->setNoContentMargin(true);
const auto session = form->invoice.session;
const auto photoSize = st::defaultUserpicButton.photoSize;
const auto content = box->verticalLayout();
Ui::AddSkip(content, photoSize / 2);
{
const auto ministarsContainer = Ui::CreateChild<Ui::RpWidget>(box);
const auto fullHeight = photoSize * 2;
using MiniStars = Ui::Premium::ColoredMiniStars;
const auto ministars = box->lifetime().make_state<MiniStars>(
ministarsContainer,
false,
Ui::Premium::MiniStars::Type::BiStars);
ministars->setColorOverride(Ui::Premium::CreditsIconGradientStops());
ministarsContainer->paintRequest(
) | rpl::start_with_next([=] {
auto p = QPainter(ministarsContainer);
ministars->paint(p);
}, ministarsContainer->lifetime());
box->widthValue(
) | rpl::start_with_next([=](int width) {
ministarsContainer->resize(width, fullHeight);
const auto w = fullHeight / 3 * 2;
ministars->setCenter(QRect(
(width - w) / 2,
(fullHeight - w) / 2,
w,
w));
}, ministarsContainer->lifetime());
}
const auto bot = session->data().user(form->botId);
if (form->photo) {
box->addRow(object_ptr<Ui::CenterWrap<>>(
content,
Settings::HistoryEntryPhoto(content, form->photo, photoSize)));
} else {
const auto widget = box->addRow(
object_ptr<Ui::CenterWrap<>>(
content,
object_ptr<Ui::UserpicButton>(
content,
bot,
st::defaultUserpicButton)));
widget->setAttribute(Qt::WA_TransparentForMouseEvents);
}
Ui::AddSkip(content);
box->addRow(object_ptr<Ui::CenterWrap<>>(
box,
object_ptr<Ui::FlatLabel>(
box,
tr::lng_credits_box_out_title(),
st::settingsPremiumUserTitle)));
Ui::AddSkip(content);
box->addRow(object_ptr<Ui::CenterWrap<>>(
box,
object_ptr<Ui::FlatLabel>(
box,
tr::lng_credits_box_out_sure(
lt_count,
rpl::single(form->invoice.amount) | tr::to_count(),
lt_text,
rpl::single(TextWithEntities{ form->title }),
lt_bot,
rpl::single(TextWithEntities{ bot->name() }),
Ui::Text::RichLangValue),
st::creditsBoxAbout)));
Ui::AddSkip(content);
Ui::AddSkip(content);
const auto button = box->addButton(rpl::single(QString()), [=] {
if (state->confirmButtonBusy.current()) {
return;
}
state->confirmButtonBusy = true;
session->api().request(
MTPpayments_SendStarsForm(
MTP_flags(0),
MTP_long(form->formId),
form->inputInvoice)
).done([=](auto result) {
state->confirmButtonBusy = false;
box->closeBox();
sent();
}).fail([=](const MTP::Error &error) {
state->confirmButtonBusy = false;
box->uiShow()->showToast(error.type());
}).send();
});
{
using namespace Info::Statistics;
const auto loadingAnimation = InfiniteRadialAnimationWidget(
button,
st::giveawayGiftCodeStartButton.height / 2);
AddChildToWidgetCenter(button.data(), loadingAnimation);
loadingAnimation->showOn(state->confirmButtonBusy.value());
}
{
const auto emojiMargin = QMargins(
0,
-st::moderateBoxExpandInnerSkip,
0,
0);
const auto buttonEmoji = Ui::Text::SingleCustomEmoji(
session->data().customEmojiManager().registerInternalEmoji(
st::settingsPremiumIconStar,
emojiMargin,
true));
auto buttonText = tr::lng_credits_box_out_confirm(
lt_count,
rpl::single(form->invoice.amount) | tr::to_count(),
lt_emoji,
rpl::single(buttonEmoji),
Ui::Text::RichLangValue);
const auto buttonLabel = Ui::CreateChild<Ui::FlatLabel>(
button,
rpl::single(QString()),
st::defaultFlatLabel);
std::move(
buttonText
) | rpl::start_with_next([=](const TextWithEntities &text) {
buttonLabel->setMarkedText(
text,
Core::MarkedTextContext{
.session = session,
.customEmojiRepaint = [=] { buttonLabel->update(); },
});
}, buttonLabel->lifetime());
buttonLabel->setTextColorOverride(
box->getDelegate()->style().button.textFg->c);
button->sizeValue(
) | rpl::start_with_next([=](const QSize &size) {
buttonLabel->moveToLeft(
(size.width() - buttonLabel->width()) / 2,
(size.height() - buttonLabel->height()) / 2);
}, buttonLabel->lifetime());
buttonLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
state->confirmButtonBusy.value(
) | rpl::start_with_next([=](bool busy) {
buttonLabel->setVisible(!busy);
}, buttonLabel->lifetime());
}
const auto buttonWidth = st::boxWidth
- rect::m::sum::h(st::giveawayGiftCodeBox.buttonPadding);
button->widthValue() | rpl::filter([=] {
return (button->widthNoMargins() != buttonWidth);
}) | rpl::start_with_next([=] {
button->resizeToWidth(buttonWidth);
}, button->lifetime());
{
const auto close = Ui::CreateChild<Ui::IconButton>(
box.get(),
st::boxTitleClose);
close->setClickedCallback([=] {
box->closeBox();
});
box->widthValue(
) | rpl::start_with_next([=](int width) {
close->moveToRight(0, 0);
close->raise();
}, close->lifetime());
}
{
const auto balance = Settings::AddBalanceWidget(
content,
session->creditsValue(),
false);
const auto api = balance->lifetime().make_state<Api::CreditsStatus>(
session->user());
api->request({}, [=](Data::CreditsStatusSlice slice) {
session->setCredits(slice.balance);
});
rpl::combine(
balance->sizeValue(),
content->sizeValue()
) | rpl::start_with_next([=](const QSize &, const QSize &) {
balance->moveToLeft(
st::creditsHistoryRightSkip * 2,
st::creditsHistoryRightSkip);
balance->update();
}, balance->lifetime());
}
}
} // namespace Ui
@@ -0,0 +1,25 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class HistoryItem;
namespace Payments {
struct CreditsFormData;
} // namespace Payments
namespace Ui {
class GenericBox;
void SendCreditsBox(
not_null<Ui::GenericBox*> box,
std::shared_ptr<Payments::CreditsFormData> data,
Fn<void()> sent);
} // namespace Ui
+80 -70
View File
@@ -336,7 +336,7 @@ SendFilesBox::SendFilesBox(
const TextWithTags &caption,
not_null<PeerData*> toPeer,
Api::SendType sendType,
SendMenu::Type sendMenuType)
SendMenu::Details sendMenuDetails)
: SendFilesBox(nullptr, {
.show = controller->uiShow(),
.list = std::move(list),
@@ -345,7 +345,7 @@ SendFilesBox::SendFilesBox(
.limits = DefaultLimitsForPeer(toPeer),
.check = DefaultCheckForPeer(controller, toPeer),
.sendType = sendType,
.sendMenuType = sendMenuType,
.sendMenuDetails = [=] { return sendMenuDetails; },
}) {
}
@@ -358,7 +358,8 @@ SendFilesBox::SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor)
, _titleHeight(st::boxTitleHeight)
, _list(std::move(descriptor.list))
, _limits(descriptor.limits)
, _sendMenuType(descriptor.sendMenuType)
, _sendMenuDetails(prepareSendMenuDetails(descriptor))
, _sendMenuCallback(prepareSendMenuCallback())
, _captionToPeer(descriptor.captionToPeer)
, _check(std::move(descriptor.check))
, _confirmedCallback(std::move(descriptor.confirmed))
@@ -372,6 +373,50 @@ SendFilesBox::SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor)
enqueueNextPrepare();
}
Fn<SendMenu::Details()> SendFilesBox::prepareSendMenuDetails(
const SendFilesBoxDescriptor &descriptor) {
auto initial = descriptor.sendMenuDetails;
return crl::guard(this, [=] {
auto result = initial ? initial() : SendMenu::Details();
result.spoiler = !hasSpoilerMenu()
? SendMenu::SpoilerState::None
: allWithSpoilers()
? SendMenu::SpoilerState::Enabled
: SendMenu::SpoilerState::Possible;
const auto way = _sendWay.current();
const auto canMoveCaption = _list.canMoveCaption(
way.groupFiles() && way.sendImagesAsPhotos(),
way.sendImagesAsPhotos()
) && _caption && HasSendText(_caption);
result.caption = !canMoveCaption
? SendMenu::CaptionState::None
: _invertCaption
? SendMenu::CaptionState::Above
: SendMenu::CaptionState::Below;
return result;
});
}
auto SendFilesBox::prepareSendMenuCallback()
-> Fn<void(MenuAction, MenuDetails)> {
return crl::guard(this, [=](MenuAction action, MenuDetails details) {
using Type = SendMenu::ActionType;
switch (action.type) {
case Type::CaptionDown: _invertCaption = false; break;
case Type::CaptionUp: _invertCaption = true; break;
case Type::SpoilerOn: toggleSpoilers(true); break;
case Type::SpoilerOff: toggleSpoilers(false); break;
default:
SendMenu::DefaultCallback(
_show,
sendCallback())(
action,
details);
break;
}
});
}
void SendFilesBox::initPreview() {
using namespace rpl::mappers;
@@ -537,10 +582,9 @@ void SendFilesBox::refreshButtons() {
if (_sendType == Api::SendType::Normal) {
SendMenu::SetupMenuAndShortcuts(
_send,
[=] { return _sendMenuType; },
[=] { sendSilent(); },
[=] { sendScheduled(); },
[=] { sendWhenOnline(); });
_show,
_sendMenuDetails,
_sendMenuCallback);
}
addButton(tr::lng_cancel(), [=] { closeBox(); });
_addFile = addLeftButton(
@@ -552,21 +596,14 @@ void SendFilesBox::refreshButtons() {
addMenuButton();
}
bool SendFilesBox::hasSendMenu() const {
return (_sendMenuType != SendMenu::Type::Disabled);
bool SendFilesBox::hasSendMenu(const SendMenu::Details &details) const {
return (details.type != SendMenu::Type::Disabled)
|| (details.spoiler != SendMenu::SpoilerState::None)
|| (details.caption != SendMenu::CaptionState::None);
}
bool SendFilesBox::hasSpoilerMenu() const {
const auto allAreVideo = !ranges::any_of(_list.files, [](const auto &f) {
using Type = Ui::PreparedFile::Type;
return (f.type != Type::Video);
});
const auto allAreMedia = !ranges::any_of(_list.files, [](const auto &f) {
using Type = Ui::PreparedFile::Type;
return (f.type != Type::Photo) && (f.type != Type::Video);
});
return allAreVideo
|| (allAreMedia && _sendWay.current().sendImagesAsPhotos());
return _list.hasSpoilerMenu(_sendWay.current().sendImagesAsPhotos());
}
void SendFilesBox::applyBlockChanges() {
@@ -590,36 +627,23 @@ void SendFilesBox::toggleSpoilers(bool enabled) {
}
void SendFilesBox::addMenuButton() {
if (!hasSendMenu() && !hasSpoilerMenu()) {
const auto details = _sendMenuDetails();
if (!hasSendMenu(details)) {
return;
}
const auto top = addTopButton(_st.files.menu);
top->setClickedCallback([=] {
const auto &tabbed = _st.tabbed;
const auto &icons = tabbed.icons;
_menu = base::make_unique_q<Ui::PopupMenu>(top, tabbed.menu);
if (hasSpoilerMenu()) {
const auto spoilered = allWithSpoilers();
_menu->addAction(
(spoilered
? tr::lng_context_disable_spoiler(tr::now)
: tr::lng_context_spoiler_effect(tr::now)),
[=] { toggleSpoilers(!spoilered); },
spoilered ? &icons.menuSpoilerOff : &icons.menuSpoiler);
if (hasSendMenu()) {
_menu->addSeparator(&tabbed.expandedSeparator);
}
}
if (hasSendMenu()) {
SendMenu::FillSendMenu(
_menu.get(),
_sendMenuType,
[=] { sendSilent(); },
[=] { sendScheduled(); },
[=] { sendWhenOnline(); },
&_st.tabbed.icons);
}
const auto position = QCursor::pos();
SendMenu::FillSendMenu(
_menu.get(),
_show,
_sendMenuDetails(),
_sendMenuCallback,
&_st.tabbed.icons,
position);
using ImageInfo = Ui::PreparedFileInformation::Image;
if (_list.files.size() == 1 && std::get_if<ImageInfo>(&_list.files[0].information->media)) {
@@ -650,10 +674,9 @@ void SendFilesBox::addMenuButton() {
},
&st::menuIconStickers);
}
_menu->popup(QCursor::pos());
_menu->popup(position);
return true;
});
}
void SendFilesBox::initSendWay() {
@@ -695,9 +718,7 @@ void SendFilesBox::initSendWay() {
for (auto &block : _blocks) {
block.setSendWay(value);
}
if (!hasSendMenu()) {
refreshButtons();
}
refreshButtons();
if (was != hidden()) {
updateBoxSize();
updateControlsGeometry();
@@ -909,9 +930,7 @@ void SendFilesBox::pushBlock(int from, int till) {
}
void SendFilesBox::refreshControls(bool initial) {
if (initial || !hasSendMenu()) {
refreshButtons();
}
refreshButtons();
refreshTitleText();
updateSendWayControls();
updateCaptionPlaceholder();
@@ -1477,7 +1496,12 @@ void SendFilesBox::send(
if ((_sendType == Api::SendType::Scheduled
|| _sendType == Api::SendType::ScheduledToUser)
&& !options.scheduled) {
return sendScheduled();
auto child = _sendMenuDetails();
child.spoiler = SendMenu::SpoilerState::None;
child.caption = SendMenu::CaptionState::None;
return SendMenu::DefaultCallback(_show, sendCallback())(
{ .type = SendMenu::ActionType::Schedule },
child);
}
if (_preparing) {
_whenReadySend = [=] {
@@ -1502,6 +1526,7 @@ void SendFilesBox::send(
auto caption = (_caption && !_caption->isHidden())
? _caption->getTextWithAppliedMarkdown()
: TextWithTags();
options.invertCaption = _invertCaption;
if (!validateLength(caption.text)) {
return;
}
@@ -1515,25 +1540,10 @@ void SendFilesBox::send(
closeBox();
}
void SendFilesBox::sendSilent() {
send({ .silent = true });
}
void SendFilesBox::sendScheduled() {
const auto type = (_sendType == Api::SendType::ScheduledToUser)
? SendMenu::Type::ScheduledToUser
: _sendMenuType;
const auto callback = [=](Api::SendOptions options) { send(options); };
auto box = HistoryView::PrepareScheduleBox(this, type, callback);
const auto weak = Ui::MakeWeak(box.data());
_show->showBox(std::move(box));
if (const auto strong = weak.data()) {
strong->setCloseByOutsideClick(false);
}
}
void SendFilesBox::sendWhenOnline() {
send(Api::DefaultSendWhenOnlineOptions());
Fn<void(Api::SendOptions)> SendFilesBox::sendCallback() {
return crl::guard(this, [=](Api::SendOptions options) {
send(options, false);
});
}
SendFilesBox::~SendFilesBox() = default;
+17 -8
View File
@@ -47,7 +47,8 @@ class SessionController;
} // namespace Window
namespace SendMenu {
enum class Type;
struct Details;
struct Action;
} // namespace SendMenu
namespace HistoryView::Controls {
@@ -96,7 +97,7 @@ struct SendFilesBoxDescriptor {
SendFilesLimits limits = {};
SendFilesCheck check;
Api::SendType sendType = {};
SendMenu::Type sendMenuType = {};
Fn<SendMenu::Details()> sendMenuDetails = nullptr;
const style::ComposeControls *stOverride = nullptr;
SendFilesConfirmed confirmed;
Fn<void()> cancelled;
@@ -115,7 +116,7 @@ public:
const TextWithTags &caption,
not_null<PeerData*> toPeer,
Api::SendType sendType,
SendMenu::Type sendMenuType);
SendMenu::Details sendMenuDetails);
SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor);
void setConfirmedCallback(SendFilesConfirmed callback) {
@@ -136,6 +137,9 @@ protected:
void resizeEvent(QResizeEvent *e) override;
private:
using MenuAction = SendMenu::Action;
using MenuDetails = SendMenu::Details;
class Block final {
public:
Block(
@@ -173,7 +177,7 @@ private:
void initSendWay();
void initPreview();
[[nodiscard]] bool hasSendMenu() const;
[[nodiscard]] bool hasSendMenu(const MenuDetails &details) const;
[[nodiscard]] bool hasSpoilerMenu() const;
[[nodiscard]] bool allWithSpoilers();
[[nodiscard]] bool checkWithWay(
@@ -202,9 +206,7 @@ private:
void generatePreviewFrom(int fromBlock);
void send(Api::SendOptions options, bool ctrlShiftEnter = false);
void sendSilent();
void sendScheduled();
void sendWhenOnline();
[[nodiscard]] Fn<void(Api::SendOptions)> sendCallback();
void captionResized();
void saveSendWaySettings();
@@ -227,6 +229,11 @@ private:
void checkCharsLimitation();
[[nodiscard]] Fn<MenuDetails()> prepareSendMenuDetails(
const SendFilesBoxDescriptor &descriptor);
[[nodiscard]] auto prepareSendMenuCallback()
-> Fn<void(MenuAction, MenuDetails)>;
const std::shared_ptr<ChatHelpers::Show> _show;
const style::ComposeControls &_st;
const Api::SendType _sendType = Api::SendType();
@@ -238,12 +245,14 @@ private:
std::optional<int> _removingIndex;
SendFilesLimits _limits = {};
SendMenu::Type _sendMenuType = {};
Fn<MenuDetails()> _sendMenuDetails;
Fn<void(MenuAction, MenuDetails)> _sendMenuCallback;
PeerData *_captionToPeer = nullptr;
SendFilesCheck _check;
SendFilesConfirmed _confirmedCallback;
Fn<void()> _cancelledCallback;
bool _confirmed = false;
bool _invertCaption = false;
object_ptr<Ui::InputField> _caption = { nullptr };
TextWithTags _prefilledCaptionText;
+143 -32
View File
@@ -239,7 +239,10 @@ void ShareBox::prepareCommentField() {
const auto field = _comment->entity();
field->submits(
) | rpl::start_with_next([=] { submit({}); }, field->lifetime());
) | rpl::start_with_next([=] {
submit({});
}, field->lifetime());
if (const auto show = uiShow(); show->valid()) {
InitMessageFieldHandlers(
_descriptor.session,
@@ -251,6 +254,14 @@ void ShareBox::prepareCommentField() {
}
field->setSubmitSettings(Core::App().settings().sendSubmitWay());
field->changes() | rpl::start_with_next([=] {
if (!field->getLastText().isEmpty()) {
setCloseByOutsideClick(false);
} else if (_inner->selected().empty()) {
setCloseByOutsideClick(true);
}
}, field->lifetime());
Ui::SendPendingMoveResizeEvents(_comment);
if (_bottomWidget) {
Ui::SendPendingMoveResizeEvents(_bottomWidget);
@@ -260,8 +271,6 @@ void ShareBox::prepareCommentField() {
void ShareBox::prepare() {
prepareCommentField();
setCloseByOutsideClick(false);
_select->resizeToWidth(st::boxWideWidth);
Ui::SendPendingMoveResizeEvents(_select);
@@ -318,6 +327,12 @@ void ShareBox::prepare() {
not_null<Data::Thread*> thread,
bool checked) {
innerSelectedChanged(thread, checked);
if (checked) {
setCloseByOutsideClick(false);
} else if (_inner->selected().empty()
&& _comment->entity()->getLastText().isEmpty()) {
setCloseByOutsideClick(true);
}
});
Ui::Emoji::SuggestionsController::Init(
@@ -463,15 +478,18 @@ void ShareBox::keyPressEvent(QKeyEvent *e) {
}
}
SendMenu::Type ShareBox::sendMenuType() const {
SendMenu::Details ShareBox::sendMenuDetails() const {
const auto selected = _inner->selected();
return ranges::all_of(
const auto type = ranges::all_of(
selected | ranges::views::transform(&Data::Thread::peer),
HistoryView::CanScheduleUntilOnline)
? SendMenu::Type::ScheduledToUser
: (selected.size() == 1 && selected.front()->peer()->isSelf())
? SendMenu::Type::Reminder
: SendMenu::Type::Scheduled;
// We can't support effect here because we don't have ChatHelpers::Show.
return { .type = type, .effectAllowed = false };
}
void ShareBox::showMenu(not_null<Ui::RpWidget*> parent) {
@@ -508,15 +526,32 @@ void ShareBox::showMenu(not_null<Ui::RpWidget*> parent) {
_menu->addSeparator();
}
const auto result = SendMenu::FillSendMenu(
using namespace SendMenu;
const auto sendAction = crl::guard(this, [=](Action action, Details) {
if (action.type == ActionType::Send) {
submit(action.options);
return;
}
uiShow()->showBox(
HistoryView::PrepareScheduleBox(
this,
nullptr, // ChatHelpers::Show for effect attachment.
sendMenuDetails(),
[=](Api::SendOptions options) { submit(options); },
action.options,
HistoryView::DefaultScheduleTime(),
_descriptor.scheduleBoxStyle));
});
_menu->setForcedVerticalOrigin(Ui::PopupMenu::VerticalOrigin::Bottom);
const auto result = FillSendMenu(
_menu.get(),
sendMenuType(),
[=] { submitSilent(); },
[=] { submitScheduled(); },
[=] { submitWhenOnline(); });
const auto success = (result == SendMenu::FillMenuResult::Success);
if (_descriptor.forwardOptions.show || success) {
_menu->setForcedVerticalOrigin(Ui::PopupMenu::VerticalOrigin::Bottom);
nullptr, // showForEffect.
sendMenuDetails(),
sendAction);
if (result == SendMenu::FillMenuResult::Prepared) {
_menu->popupPrepared();
} else if (_descriptor.forwardOptions.show
&& result != SendMenu::FillMenuResult::Failed) {
_menu->popup(QCursor::pos());
}
}
@@ -597,25 +632,6 @@ void ShareBox::submit(Api::SendOptions options) {
}
}
void ShareBox::submitSilent() {
submit({ .silent = true });
}
void ShareBox::submitScheduled() {
const auto callback = [=](Api::SendOptions options) { submit(options); };
uiShow()->showBox(
HistoryView::PrepareScheduleBox(
this,
sendMenuType(),
callback,
HistoryView::DefaultScheduleTime(),
_descriptor.scheduleBoxStyle));
}
void ShareBox::submitWhenOnline() {
submit(Api::DefaultSendWhenOnlineOptions());
}
void ShareBox::copyLink() const {
if (const auto onstack = _descriptor.copyCallback) {
onstack();
@@ -1690,6 +1706,101 @@ void FastShareMessage(
Ui::LayerOption::CloseOther);
}
void FastShareLink(
not_null<Window::SessionController*> controller,
const QString &url) {
FastShareLink(controller->uiShow(), url);
}
void FastShareLink(
std::shared_ptr<Main::SessionShow> show,
const QString &url) {
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
const auto sending = std::make_shared<bool>();
auto copyCallback = [=] {
QGuiApplication::clipboard()->setText(url);
show->showToast(tr::lng_background_link_copied(tr::now));
};
auto submitCallback = [=](
std::vector<not_null<::Data::Thread*>> &&result,
TextWithTags &&comment,
Api::SendOptions options,
::Data::ForwardOptions) {
if (*sending || result.empty()) {
return;
}
const auto error = [&] {
for (const auto thread : result) {
const auto error = GetErrorTextForSending(
thread,
{ .text = &comment });
if (!error.isEmpty()) {
return std::make_pair(error, thread);
}
}
return std::make_pair(QString(), result.front());
}();
if (!error.first.isEmpty()) {
auto text = TextWithEntities();
if (result.size() > 1) {
text.append(
Ui::Text::Bold(error.second->chatListName())
).append("\n\n");
}
text.append(error.first);
if (const auto weak = *box) {
weak->getDelegate()->show(Ui::MakeConfirmBox({
.text = text,
.inform = true,
}));
}
return;
}
*sending = true;
if (!comment.text.isEmpty()) {
comment.text = url + "\n" + comment.text;
const auto add = url.size() + 1;
for (auto &tag : comment.tags) {
tag.offset += add;
}
} else {
comment.text = url;
}
auto &api = show->session().api();
for (const auto thread : result) {
auto message = Api::MessageToSend(
Api::SendAction(thread, options));
message.textWithTags = comment;
message.action.clearDraft = false;
api.sendMessage(std::move(message));
}
if (*box) {
(*box)->closeBox();
}
show->showToast(tr::lng_share_done(tr::now));
};
auto filterCallback = [](not_null<::Data::Thread*> thread) {
if (const auto user = thread->peer()->asUser()) {
if (user->canSendIgnoreRequirePremium()) {
return true;
}
}
return ::Data::CanSend(thread, ChatRestriction::SendOther);
};
*box = show->show(
Box<ShareBox>(ShareBox::Descriptor{
.session = &show->session(),
.copyCallback = std::move(copyCallback),
.submitCallback = std::move(submitCallback),
.filterCallback = std::move(filterCallback),
.premiumRequiredError = SharePremiumRequiredError(),
}),
Ui::LayerOption::KeepOther,
anim::type::normal);
}
auto SharePremiumRequiredError()
-> Fn<RecipientPremiumRequiredError(not_null<UserData*>)> {
return WritePremiumRequiredError;
+9 -5
View File
@@ -24,7 +24,7 @@ struct PeerList;
} // namespace style
namespace SendMenu {
enum class Type;
struct Details;
} // namespace SendMenu
namespace Window {
@@ -37,6 +37,7 @@ struct SendOptions;
namespace Main {
class Session;
class SessionShow;
} // namespace Main
namespace Dialogs {
@@ -68,6 +69,12 @@ void ShareGameScoreByHash(
void FastShareMessage(
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item);
void FastShareLink(
not_null<Window::SessionController*> controller,
const QString &url);
void FastShareLink(
std::shared_ptr<Main::SessionShow> show,
const QString &url);
struct RecipientPremiumRequiredError;
[[nodiscard]] auto SharePremiumRequiredError()
@@ -123,13 +130,10 @@ private:
void scrollAnimationCallback();
void submit(Api::SendOptions options);
void submitSilent();
void submitScheduled();
void submitWhenOnline();
void copyLink() const;
bool searchByUsername(bool useCache = false);
SendMenu::Type sendMenuType() const;
[[nodiscard]] SendMenu::Details sendMenuDetails() const;
void scrollTo(Ui::ScrollToRequest request);
void needSearchByUsername();
+39 -29
View File
@@ -79,7 +79,9 @@ using Data::StickersSet;
using Data::StickersPack;
using SetFlag = Data::StickersSetFlag;
[[nodiscard]] std::optional<QColor> ComputeImageColor(const QImage &frame) {
[[nodiscard]] std::optional<QColor> ComputeImageColor(
const style::icon &lockIcon,
const QImage &frame) {
if (frame.isNull()
|| frame.format() != QImage::Format_ARGB32_Premultiplied) {
return {};
@@ -89,7 +91,7 @@ using SetFlag = Data::StickersSetFlag;
auto sb = int64();
auto sa = int64();
const auto factor = frame.devicePixelRatio();
const auto size = st::stickersPremiumLock.size() * factor;
const auto size = lockIcon.size() * factor;
const auto width = std::min(frame.width(), size.width());
const auto height = std::min(frame.height(), size.height());
const auto skipx = (frame.width() - width) / 2;
@@ -116,22 +118,30 @@ using SetFlag = Data::StickersSetFlag;
}
[[nodiscard]] QColor ComputeLockColor(const QImage &frame) {
return ComputeImageColor(frame).value_or(st::windowSubTextFg->c);
[[nodiscard]] QColor ComputeLockColor(
const style::icon &lockIcon,
const QImage &frame) {
return ComputeImageColor(
lockIcon,
frame
).value_or(st::windowSubTextFg->c);
}
void ValidatePremiumLockBg(QImage &image, const QImage &frame) {
void ValidatePremiumLockBg(
const style::icon &lockIcon,
QImage &image,
const QImage &frame) {
if (!image.isNull()) {
return;
}
const auto factor = style::DevicePixelRatio();
const auto size = st::stickersPremiumLock.size();
const auto size = lockIcon.size();
image = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(factor);
auto p = QPainter(&image);
const auto color = ComputeLockColor(frame);
const auto color = ComputeLockColor(lockIcon, frame);
p.fillRect(
QRect(QPoint(), size),
anim::color(color, st::windowSubTextFg, kGrayLockOpacity));
@@ -140,12 +150,12 @@ void ValidatePremiumLockBg(QImage &image, const QImage &frame) {
image = Images::Circle(std::move(image));
}
void ValidatePremiumStarFg(QImage &image) {
void ValidatePremiumStarFg(const style::icon &lockIcon, QImage &image) {
if (!image.isNull()) {
return;
}
const auto factor = style::DevicePixelRatio();
const auto size = st::stickersPremiumLock.size();
const auto size = lockIcon.size();
image = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
@@ -182,7 +192,10 @@ void ValidatePremiumStarFg(QImage &image) {
} // namespace
StickerPremiumMark::StickerPremiumMark(not_null<Main::Session*> session) {
StickerPremiumMark::StickerPremiumMark(
not_null<Main::Session*> session,
const style::icon &lockIcon)
: _lockIcon(lockIcon) {
style::PaletteChanged(
) | rpl::start_with_next([=] {
_lockGray = QImage();
@@ -208,16 +221,14 @@ void StickerPremiumMark::paint(
const auto factor = style::DevicePixelRatio();
const auto radius = st::roundRadiusSmall;
const auto point = position + QPoint(
(_premium
? (singleSize.width() - (bg.width() / factor) - radius)
: (singleSize.width() - (bg.width() / factor)) / 2),
(singleSize.width() - (bg.width() / factor) - radius),
singleSize.height() - (bg.height() / factor) - radius);
p.drawImage(point, bg);
if (_premium) {
validateStar();
p.drawImage(point, _star);
} else {
st::stickersPremiumLock.paint(p, point, outerWidth);
_lockIcon.paint(p, point, outerWidth);
}
}
@@ -225,11 +236,11 @@ void StickerPremiumMark::validateLock(
const QImage &frame,
QImage &backCache) {
auto &image = frame.isNull() ? _lockGray : backCache;
ValidatePremiumLockBg(image, frame);
ValidatePremiumLockBg(_lockIcon, image, frame);
}
void StickerPremiumMark::validateStar() {
ValidatePremiumStarFg(_star);
ValidatePremiumStarFg(_lockIcon, _star);
}
class StickerSetBox::Inner final : public Ui::RpWidget {
@@ -543,9 +554,9 @@ void StickerSetBox::updateButtons() {
? tr::lng_stickers_copied_emoji(tr::now)
: tr::lng_stickers_copied(tr::now));
};
const auto addAuthorPack = [=](const std::shared_ptr<base::unique_qptr<Ui::PopupMenu>> &menu)
const auto addPackOwner = [=](const std::shared_ptr<base::unique_qptr<Ui::PopupMenu>> &menu)
{
if (type == Data::StickersType::Stickers) {
if (type == Data::StickersType::Stickers || type == Data::StickersType::Emoji) {
const auto pointer = Ui::MakeWeak(this);
(*menu)->addAction(
tr::ayu_MessageDetailsPackOwnerPC(tr::now),
@@ -625,7 +636,7 @@ void StickerSetBox::updateButtons() {
: tr::lng_stickers_share_pack)(tr::now),
[=] { share(); closeBox(); },
&st::menuIconShare);
addAuthorPack(menu);
addPackOwner(menu);
(*menu)->popup(QCursor::pos());
return true;
});
@@ -675,7 +686,7 @@ void StickerSetBox::updateButtons() {
archive,
&st::menuIconArchive);
}
addAuthorPack(menu);
addPackOwner(menu);
(*menu)->popup(QCursor::pos());
return true;
});
@@ -708,7 +719,7 @@ StickerSetBox::Inner::Inner(
st::windowBgRipple,
st::windowBgOver,
[=] { repaintItems(); }))
, _premiumMark(_session)
, _premiumMark(_session, st::stickersPremiumLock)
, _updateItemsTimer([=] { updateItems(); })
, _input(set)
, _padding((type == Data::StickersType::Emoji)
@@ -1058,7 +1069,7 @@ void StickerSetBox::Inner::contextMenuEvent(QContextMenuEvent *e) {
_menu = base::make_unique_q<Ui::PopupMenu>(
this,
st::popupMenuWithIcons);
const auto type = _show->sendMenuType();
const auto details = _show->sendMenuDetails();
if (setType() == Data::StickersType::Emoji) {
if (const auto t = PrepareTextFromEmoji(_pack[index]); !t.empty()) {
_menu->addAction(tr::lng_mediaview_copy(tr::now), [=] {
@@ -1067,17 +1078,16 @@ void StickerSetBox::Inner::contextMenuEvent(QContextMenuEvent *e) {
}
}, &st::menuIconCopy);
}
} else if (type != SendMenu::Type::Disabled) {
} else if (details.type != SendMenu::Type::Disabled) {
const auto document = _pack[index];
const auto sendSelected = [=](Api::SendOptions options) {
const auto send = crl::guard(this, [=](Api::SendOptions options) {
chosen(index, document, options);
};
});
SendMenu::FillSendMenu(
_menu.get(),
type,
SendMenu::DefaultSilentCallback(sendSelected),
SendMenu::DefaultScheduleCallback(this, type, sendSelected),
SendMenu::DefaultWhenOnlineCallback(sendSelected));
_show,
details,
SendMenu::DefaultCallback(_show, send));
const auto show = _show;
const auto toggleFavedSticker = [=] {
+4 -5
View File
@@ -23,10 +23,6 @@ namespace Data {
class StickersSet;
} // namespace Data
namespace SendMenu {
enum class Type;
} // namespace SendMenu
namespace ChatHelpers {
struct FileChosen;
class Show;
@@ -34,7 +30,9 @@ class Show;
class StickerPremiumMark final {
public:
explicit StickerPremiumMark(not_null<Main::Session*> session);
StickerPremiumMark(
not_null<Main::Session*> session,
const style::icon &lockIcon);
void paint(
QPainter &p,
@@ -48,6 +46,7 @@ private:
void validateLock(const QImage &frame, QImage &backCache);
void validateStar();
const style::icon &_lockIcon;
QImage _lockGray;
QImage _star;
bool _premium = false;
+1 -1
View File
@@ -563,7 +563,7 @@ groupCallPopupMenuWithCover: PopupMenu(groupCallPopupMenu) {
}
}
groupCallMenuCover: ShortInfoCover(shortInfoCover) {
radius: roundRadiusSmall;
radius: roundRadiusLarge;
size: groupCallMenuCoverSize;
namePosition: point(17px, 28px);
statusPosition: point(17px, 8px);
+17 -17
View File
@@ -7,31 +7,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "calls/calls_call.h"
#include "main/main_session.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "apiwrap.h"
#include "lang/lang_keys.h"
#include "boxes/abstract_box.h"
#include "ui/boxes/confirm_box.h"
#include "ui/boxes/rate_call_box.h"
#include "calls/calls_instance.h"
#include "base/battery_saving.h"
#include "base/openssl_help.h"
#include "base/platform/base_platform_info.h"
#include "base/random.h"
#include "mtproto/mtproto_dh_utils.h"
#include "mtproto/mtproto_config.h"
#include "boxes/abstract_box.h"
#include "calls/calls_instance.h"
#include "calls/calls_panel.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "window/window_controller.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "lang/lang_keys.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
#include "media/audio/media_audio_track.h"
#include "base/platform/base_platform_info.h"
#include "calls/calls_panel.h"
#include "mtproto/mtproto_config.h"
#include "mtproto/mtproto_dh_utils.h"
#include "ui/boxes/confirm_box.h"
#include "ui/boxes/rate_call_box.h"
#include "webrtc/webrtc_create_adm.h"
#include "webrtc/webrtc_environment.h"
#include "webrtc/webrtc_video_track.h"
#include "webrtc/webrtc_create_adm.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "window/window_controller.h"
#include <tgcalls/Instance.h>
#include <tgcalls/VideoCaptureInterface.h>
@@ -1072,6 +1070,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
Core::App().mediaDevices().setCaptureMuted(muted);
}, _instanceLifetime);
#if 0
Core::App().batterySaving().value(
) | rpl::start_with_next([=](bool isSaving) {
crl::on_main(weak, [=] {
@@ -1080,6 +1079,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
}
});
}, _instanceLifetime);
#endif
}
void Call::handleControllerStateChange(tgcalls::State state) {

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