Compare commits

...

437 Commits

Author SHA1 Message Date
AlexeyZavar 214f48922e fix: remove restriction notice 2024-10-22 00:44:23 +03:00
AlexeyZavar 84e7ff2637 fix: schedule stickers & set min for paid reactions 2024-10-22 00:28:38 +03:00
AlexeyZavar 40e1f307a7 feat: display seconds for reactions 2024-10-16 16:52:49 +03:00
AlexeyZavar 27f4f73690 fix: make it build 2024-10-16 16:23:07 +03:00
AlexeyZavar 7321b654bf Merge tag 'v5.6.3' into dev 2024-10-16 13:42:36 +03:00
John Preston 754d467440 Version 5.6.3: Fix build with Xcode. 2024-10-15 22:13:06 +04:00
John Preston 598f08d6c7 Version 5.6.3.
- Add ability to change page scale in Instant View pages.
- Fix unnecessary timestamp jump to a new line.
- Fix secondary button positioning in miniapps.
- Fix a crash in QR code copy for a chat without a photo.
- Fix a crash in share options menu showing.
- Fix a crash on monitor disconnect.
2024-10-15 21:01:27 +04:00
23rd 224fdc1864 Returned back freedom to copy links even in non-forwardable histories.
This reverts commits b64c610abb
and 9cd194e60e.
2024-10-15 13:04:57 +03:00
23rd e646b4dc9a Slightly improved position of selection marks for wide chats. 2024-10-15 12:59:15 +03:00
23rd 9077db2e97 Added verified mark of web view bots to box of confirmation to open. 2024-10-15 12:46:13 +03:00
23rd 7e14277ead Added ability to change zoom in IV. 2024-10-15 12:46:13 +03:00
John Preston d351a7d697 Fix crash on monitor arrangement change. 2024-10-15 12:13:53 +04:00
John Preston 70ed43b811 Fix crash on send options menu show.
Fixes #28532.
2024-10-15 12:13:53 +04:00
John Preston 913083ebc6 Fix miniapp buttons positioning. 2024-10-15 12:13:52 +04:00
John Preston 588a95a7ae Fix time jumping to a new line. 2024-10-15 12:13:52 +04:00
23rd c0a0ad4ec5 Added info to context menu for non-forwardable history. 2024-10-15 01:15:04 +03:00
23rd 5eafe96525 Fixed crash in share QR box on copy without profile photo. 2024-10-15 01:15:00 +03:00
John Preston b41ac0fc2a Version 5.6.2: Fix build with GCC. 2024-10-14 16:34:45 +04:00
John Preston cfe93530b8 Version 5.6.2.
- Message selection marks.
- Better copy username / public link / ID menu in profiles.
- Keyboard navigation (Up/Down/PageUp/PageDown) in chat preview.
- Improved QR options for profile links.
- Fix calls color problems on Windows.
- Fix scroll problems on Linux.
2024-10-14 13:58:27 +04:00
John Preston 4492e72ffa Fix web app window resize on macOS. 2024-10-14 13:55:29 +04:00
John Preston 1a0fd35f36 Check gift sold out error on sending. 2024-10-14 12:49:55 +04:00
John Preston db475ef0b4 Update API scheme to layer 190.
Support adding messages to gifts of Premium subscriptions.
2024-10-14 12:49:55 +04:00
John Preston b3dddc1dfe Fix indent of RTL text with as skip block.
Fixes #27748.
2024-10-14 12:49:54 +04:00
23rd b64c610abb Fixed ability to copy shared links for channels with select restriction.
Fixed #28492.
2024-10-14 12:49:33 +04:00
23rd c5add2fca9 Revert "Added experimental option to disable floating reactions strip."
This reverts commit a32a9aa3fc.
2024-10-14 12:49:33 +04:00
23rd 9ea78f7d28 Fixed display of message highlights in selection mode. 2024-10-14 12:49:33 +04:00
23rd 54b0d965ae Slightly eased conditions for selection mode to avoid shaky animations. 2024-10-14 12:49:33 +04:00
23rd 7b4bd5696b Added check views to selection mode of messages. 2024-10-14 12:49:33 +04:00
23rd 9064f3ba4b Fixed behavior of checkbox to remove background from QR in share QR box. 2024-10-14 12:49:33 +04:00
23rd e00e562b5f Fixed update of width for usernames label in profile section as well. 2024-10-14 12:49:32 +04:00
John Preston 73f38c896f Use new phrase for miniapp launch confirmation. 2024-10-14 12:49:32 +04:00
John Preston 5767cbd0e3 Fix send menus with additional items. 2024-10-14 12:49:32 +04:00
John Preston ba31756bf9 Fix build with MSVC. 2024-10-14 12:49:32 +04:00
Ilya Fedin a88f48cd93 Fallback to portal on Linux if QStyleHints::colorScheme is unknown 2024-10-14 12:39:41 +04:00
K900 f2e0e481de Update for lib_ui API change 2024-10-12 19:54:34 +04:00
K900 566f279137 Fix build without QT_IMPLICIT_QCHAR_CONSTRUCTION 2024-10-12 19:54:34 +04:00
John Preston 394ef13955 Fix code block language change.
Fixes #28513.
2024-10-11 09:32:21 +04:00
John Preston 6812e17d07 Improve star gift size in the box. 2024-10-11 09:31:45 +04:00
John Preston fdf826b686 Improve gifts layout a bit. 2024-10-11 09:31:45 +04:00
John Preston e57742e7de Don't show non-working wallpaper button. 2024-10-11 09:31:45 +04:00
23rd 73b63aa414 Fixed update of width for username label in profile section. 2024-10-10 18:56:20 +03:00
23rd 44aa2aec5d Added ability to change font size in share QR box. 2024-10-10 18:56:20 +03:00
23rd 8d9d7c4cea Added ability to remove background from QR in share QR box. 2024-10-10 18:56:20 +03:00
23rd 9557f0c844 Improved quality of profile photo in share QR box. 2024-10-10 18:56:20 +03:00
23rd a32a9aa3fc Added experimental option to disable floating reactions strip. 2024-10-10 18:56:20 +03:00
23rd 86fa98dfbb Fixed position of mini stars in header if gift box. 2024-10-10 18:56:20 +03:00
23rd 6a69447d90 Fixed non focused window when process credits payment from web view bot. 2024-10-10 18:56:20 +03:00
John Preston 2d20e7a9e2 Add keyboard navigation to chat preview. 2024-10-10 14:16:43 +04:00
John Preston ac7b2e0da0 Keyboard navigation in closed topics.
Fixes #27319.
Fixes #28288.
2024-10-10 14:16:34 +04:00
John Preston 388325a496 Set dpi awareness in the manifest. 2024-10-10 13:53:06 +04:00
John Preston af728e82fc Unify channel links and usernames clicks. 2024-10-10 13:53:06 +04:00
John Preston 3cb33f0825 Custom "Copy ID" for peer ID context menu. 2024-10-10 13:53:06 +04:00
John Preston 1038baf467 Allow timestamp links under spoilers. 2024-10-10 13:53:05 +04:00
John Preston 828ecabc78 Don't show user badge in star stats rows. 2024-10-10 13:53:05 +04:00
Ilya Fedin 88703ba1eb Toggle fullscreen by double click in media viewe title area 2024-10-10 09:21:29 +02:00
Ilya Fedin b0ecb2c535 Update patches and lib_ui 2024-10-09 11:34:24 +02:00
Ilya Fedin c70482dbc4 Qt 6.8.0-rc1 -> 6.8.0 2024-10-09 11:34:24 +02:00
John Preston 51f1999412 Version 5.6.1: Fix build with Xcode. 2024-10-07 15:03:59 +04:00
John Preston dd4fbc256c Version 5.6.1: Support sold out gifts better. 2024-10-07 14:50:18 +04:00
John Preston cc2265583f Remove assert in GL init. 2024-10-07 14:49:00 +04:00
John Preston 1e7a4db57f Version 5.6.1.
- Fix media viewer sometimes blocking the app after launch.
2024-10-07 13:43:01 +04:00
John Preston 9a9e30c88b Fix commands list show after scheduled visit. 2024-10-07 13:42:36 +04:00
John Preston 3d98ebff42 Hide layer when showing topics list. 2024-10-07 13:23:10 +04:00
John Preston a6f4b1ae8e Fix build with Qt 6. 2024-10-07 12:50:20 +04:00
Ilya Fedin 3e6ea8109c Don't treat window controls as continuous 2024-10-07 10:48:56 +02:00
Ilya Fedin ec407d57a5 Use one side controls in group call 2024-10-07 10:48:56 +02:00
John Preston 838ad66166 Improve hidpi/window geometry init. 2024-10-07 12:48:06 +04:00
23rd c6bf905253 Slightly improved style of button to install update from dialogs list. 2024-10-06 12:21:23 +03:00
John Preston 8310230582 Version 5.6: Fix builds. 2024-10-05 21:41:22 +04:00
John Preston 1f21af0bdb Version 5.6.
- Gifts for Telegram Stars.
- Mention / hashtag autocomplete in media caption field.
- Resizing the window used for web apps and games.
- "Include muted chats in folder counters" notifications setting.
- Emoji from Unicode 15.1.
2024-10-05 20:46:11 +04:00
John Preston 127e4a5086 Attempt to fix screen dpi changes on Windows. 2024-10-05 20:36:33 +04:00
John Preston 6a30967f23 Attempt to fix media viewer with OpenGL. 2024-10-05 20:33:51 +04:00
John Preston df2b020b42 Add debug logs for recent/top peers resetting. 2024-10-05 20:32:09 +04:00
23rd a74c5a89a6 Added manage channel button to profile section of owned channels. 2024-10-05 18:50:03 +03:00
23rd 3cb0be5be5 Added administrators button to profile section of owned channels. 2024-10-05 18:50:03 +03:00
23rd d56f3cfecf Added credits balance to profile section of owned bots. 2024-10-05 18:50:03 +03:00
23rd 9716a901d1 Added ability to cache credits balance by peer. 2024-10-05 18:50:03 +03:00
23rd 649d242e9a Added userpic of web view bots to box of confirmation to open. 2024-10-05 18:50:03 +03:00
23rd 8ac3c2157f Removed redundant code from swipe-to-reply for macOS. 2024-10-05 18:50:03 +03:00
23rd 7ca4ca21fa Fixed middle elision in filenames from document views. 2024-10-05 18:50:03 +03:00
23rd e565acba91 Added api support for stories reports with server options. 2024-10-05 18:49:21 +03:00
AlexeyZavar 260678634e fix: most frequent crashes 2024-10-05 05:30:56 +03:00
AlexeyZavar 45461836e1 fix: don't use scheduled messages if not in a full ghost mode 2024-10-05 03:14:24 +03:00
AlexeyZavar 1fc230624d chore: update packer for macOS 2024-10-05 02:47:20 +03:00
John Preston ede771e51b Focus gift message field. 2024-10-04 10:06:21 +04:00
John Preston 0282786b4c Generalize gift sending. 2024-10-04 10:06:21 +04:00
John Preston 42dd08ace5 Use a separate title for star gift recipient box. 2024-10-04 10:06:21 +04:00
John Preston cf1d274b0d Return gift_credits_box with gifting stars. 2024-10-04 10:06:21 +04:00
John Preston d361d5f3b2 Move gift_credits_box -> star_gift_box, strip old code. 2024-10-04 10:06:21 +04:00
John Preston 3e63b40564 Server-side star gift message length limit. 2024-10-04 10:06:21 +04:00
John Preston c5139ed06a Fix emoji panel position in star gift box. 2024-10-04 10:06:21 +04:00
23rd 3dc93526ff Renamed report_box with report_box_graphics. 2024-10-04 10:06:21 +04:00
23rd 3edf8e10e2 Added api support for reports with server options. 2024-10-04 10:06:21 +04:00
John Preston 00215622cc Update API scheme on layer 189. Build broken. 2024-10-04 10:06:21 +04:00
John Preston 479b7c3140 Add emoji selector to star gift sending. 2024-10-04 10:06:21 +04:00
John Preston a3ca8ddcfc Support entities in star gift message in box. 2024-10-04 10:06:21 +04:00
John Preston 9ace04d2c9 Support entities in star gift messages. 2024-10-04 10:06:21 +04:00
John Preston 8b11d2d5e7 Show nice star gift transactions in history. 2024-10-04 10:06:21 +04:00
John Preston 05fb0f81f9 Show gifts about text. 2024-10-04 10:06:21 +04:00
John Preston da49efa1ed Simple profile page for Verification Codes. 2024-10-04 10:06:21 +04:00
John Preston 39fb0a5b66 Remove custom PeerData::isVerifyCodes() userpic. 2024-10-04 10:06:21 +04:00
John Preston 962d4d29ee Process gift updates in list. 2024-10-04 10:06:21 +04:00
John Preston 779e9b658b Update API scheme on layer 189. 2024-10-04 10:06:20 +04:00
John Preston f9ee4dcb51 Show 'hidden from profile' icon in my gifts. 2024-10-04 10:06:20 +04:00
John Preston 1acdbb69ae Show correct gift sender. 2024-10-04 10:06:20 +04:00
John Preston c022a1c838 Fix gifts list loading both ways. 2024-10-04 10:06:20 +04:00
John Preston 52afd3d5a8 Display gifts list in the profile. 2024-10-04 10:06:20 +04:00
John Preston 79b1c0edee Support PeerData::isVerifyCodes() peer type. 2024-10-04 10:06:20 +04:00
John Preston 4803bd4b3f Started gifts list in profile. 2024-10-04 10:06:20 +04:00
John Preston 215a262076 Allow converting gifts to stars. 2024-10-04 10:06:20 +04:00
John Preston 7a35577d3a Save/unsave gifts to the profile page. 2024-10-04 10:06:20 +04:00
John Preston efbd3ca8fa Implement star gift view box. 2024-10-04 10:06:20 +04:00
John Preston 18904412cd Show chat and toast about sent gift. 2024-10-04 10:06:20 +04:00
John Preston 0d0d0ab994 Allow sending premium / star gifts. 2024-10-04 10:06:20 +04:00
John Preston 71deef61f5 Add support for star gifts API. 2024-10-04 10:06:20 +04:00
John Preston 46c8a55f56 Make nicer discount/limited gift badges. 2024-10-04 10:06:20 +04:00
John Preston 37f837dcb7 Add sending gift preview. 2024-10-04 10:06:20 +04:00
John Preston a5be0a685a Extract gift button into separate widget. 2024-10-04 10:06:20 +04:00
John Preston 4cdd1fec95 Start UI of the gifts. 2024-10-04 10:06:20 +04:00
John Preston 761617c1ce Start UI of the new gift sending box. 2024-10-04 10:06:20 +04:00
John Preston e3bc4dab85 Update API scheme to layer 189. 2024-10-04 10:06:20 +04:00
John Preston 335095a332 Beta version 5.5.8: Fix build with Xcode. 2024-10-03 12:21:06 +04:00
John Preston 15fcb73e19 Beta version 5.5.8.
- Allow drag-to-scroll in reply quote edit box.
- Add bot verified badge to web app title.
- Fix crash when opening some channels.
- Fix some visual glitches.
2024-10-03 11:59:57 +04:00
John Preston a8b0f2934b Scroll quote selection in the draft options box. 2024-10-03 11:56:04 +04:00
John Preston 7d67b3d00a Use circle userpics in reactions from forums. 2024-10-03 11:55:57 +04:00
John Preston b60c7e97ab Don't show full query in "nothing found" info. 2024-10-03 11:55:57 +04:00
23rd 440ebfcbf6 Removed display of userpic for sponsored messages. 2024-10-03 11:55:57 +04:00
23rd 8d93eb919b Added verified badge to title in panel for web view bots. 2024-10-03 11:55:55 +04:00
John Preston d3df2dc1e5 Use Data::MediaPreload in sponsored messages. 2024-10-03 11:54:28 +04:00
John Preston 677314dacb Extract Data::MediaPreload. 2024-10-03 11:54:28 +04:00
John Preston 20f53c89ad Fix poll bottom ripple.
Fixes #28471.
2024-10-03 11:54:28 +04:00
John Preston 1cb92ef69a Beta version 5.5.7: Workaround MSVC bug. 2024-10-01 10:55:42 +04:00
John Preston b518f7c4c4 Beta version 5.5.7.
- Add ability to share QR code of bots.
- Add mention/hashtag autocomplete to Saved GIF caption.
- Fixed display of working hours in profiles.
- Respect the maximum reply quote length.
2024-10-01 10:06:45 +04:00
John Preston 9fdc099c3a Update lib_webview. 2024-10-01 08:57:59 +04:00
23rd 1db8ada2aa Slightly improved code style of history widget. 2024-10-01 08:57:39 +04:00
23rd b753448052 Changed behavior for sponsored messages to display them only when ready. 2024-10-01 08:57:38 +04:00
23rd e29c6d2f23 Fixed infinite attempts to draw foreground in userpic builder. 2024-10-01 08:57:37 +04:00
GitHub Action 1ee53ee0c1 Update User-Agent for DNS to Chrome 129.0.0.0. 2024-10-01 08:52:46 +04:00
John Preston 57438867b6 Respect the maximum quote length. 2024-09-30 14:46:18 +04:00
John Preston 86c04424f6 Add mention/hashtag autocomplete to GIF caption. 2024-09-30 14:46:18 +04:00
John Preston 632639d581 Allow custom tab action on all autocomplete fields.
Fixes #28455.
2024-09-30 14:46:18 +04:00
23rd 99c8edb3eb Fixed display of working hours in profiles. 2024-09-30 13:29:19 +03:00
23rd 4582e61cfc Improved code style in newest code from export submodule. 2024-09-30 13:12:28 +03:00
Bohdan Tkachenko a970fe93c1 Add reactions to export chat history (#28252)
Co-authored-by: 23rd <23rd@vivaldi.net>
2024-09-30 03:02:22 -07:00
GitHub Action 91f5c72cf0 Update User-Agent for DNS to Chrome 128.0.0.0. 2024-09-30 11:03:36 +02:00
John Preston d2f3d04ad4 Update cmake/lib_base submodules. 2024-09-30 12:47:22 +04:00
John Preston 07b93e1e02 Fix media editing in topics. 2024-09-30 12:47:22 +04:00
23rd ab5e7b1588 Fixed color of mini icon for drafts with reply when dialog is selected. 2024-09-30 12:47:22 +04:00
23rd 0f4aadddfc Fixed display of corner status of video in sponsored messages. 2024-09-30 12:47:22 +04:00
John Preston a3c79feeba Always show My Stars menu. 2024-09-30 12:47:22 +04:00
John Preston e6b76fefa1 Show correct error for discuss groups. 2024-09-30 12:47:22 +04:00
23rd a37f512949 Fixed emoji display in filenames from document views. 2024-09-30 12:47:22 +04:00
23rd 3f34c0ce37 Slightly improved style of box for warning of web view box. 2024-09-30 12:47:22 +04:00
23rd 7cc9a0b9aa Added ability to share QR code of bots. 2024-09-30 12:47:22 +04:00
23rd fbaa79f168 Fixed display of outline in box for share of QR code on non-retina. 2024-09-30 12:47:22 +04:00
AlexeyZavar 87808ef317 chore: edit readme 2024-09-27 22:16:43 +03:00
Kaeeraa 80c7e4e74c chore: ru readme 2024-09-27 22:09:48 +03:00
AlexeyZavar e778aab8b7 fix: read media 2024-09-27 22:04:04 +03:00
AlexeyZavar 976db74ece Merge tag 'v5.5.5' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
2024-09-27 20:40:18 +03:00
AlexeyZavar b073810bab feat: ability to disable save deleted messages in bot dialogs 2024-09-27 20:36:34 +03:00
Ilya Fedin 2b0aa8e418 Add description for external video player option 2024-09-27 14:37:51 +02:00
Vladislav Grudinin 1fa2e76c9b Updated codegen submodule. 2024-09-27 14:37:29 +02:00
Vladislav Grudinin cb166e2591 Fix build with clang 19.1.0.
Fixes #28283.
2024-09-27 14:37:29 +02:00
xmdn 187c2dda20 Check more protocols while adding link (#28407) 2024-09-26 10:54:16 -07:00
Ilya Fedin b962d2b550 Update Qt 6.8.0-beta4 -> 6.8.0-rc1 2024-09-26 16:15:25 +02:00
Ilya Fedin d69bcfa138 Update lib_webview & lib_ui 2024-09-26 16:15:25 +02:00
AlexeyZavar 157b25ea43 chore: refactor languages 2024-09-25 19:05:57 +03:00
AlexeyZavar 2b01b63ee1 fix: sticker confirmation for media editor 2024-09-23 17:08:49 +03:00
AlexeyZavar 3d91d2c80a chore: refactor a bit 2024-09-23 16:46:41 +03:00
AlexeyZavar 625f9ef816 feat: store text deleted messages in db 2024-09-23 02:01:41 +03:00
c0re100 0960a3b21d Fix restrict user in recent actions 2024-09-19 17:48:37 +03:00
John Preston aec220fd2c Beta version 5.5.6.
- Allow resizing the window used for web apps and games.
- Add mention / hashtag autocomplete in media caption field.
- Add "Include muted chats in folder counters" notifications setting.
- Auto-select URL suggested from clipboard when creating a custom link.
- Update emoji to Unicode 15.1.
- Fix replying with a quote from media album caption.
- Fix viewing custom emoji packs from media album caption.
2024-09-19 15:02:16 +04:00
John Preston 666dacf73b Add 'tonsite' handler information to lib/xdg/*. 2024-09-19 13:19:50 +04:00
John Preston 67ce27afaa Update patches for Qt 6.8 on Windows. 2024-09-19 12:52:18 +04:00
23rd 3f6d184435 Added api support for clicks on sponsored messages with media. 2024-09-19 12:47:54 +04:00
John Preston a2fad84dae Update API scheme to layer 188. 2024-09-19 12:47:54 +04:00
John Preston 4a84f9fa00 Allow resizing window of web apps / games. 2024-09-19 12:47:46 +04:00
Ilya Fedin 7abc921d20 Revert "Fullscreen hack for Windows 11 native resize"
This reverts commit f7bff01793.
2024-09-19 10:46:46 +02:00
Ilya Fedin a307e7a798 Replace fullscreen mask workaround with Qt one 2024-09-19 10:46:46 +02:00
Ilya Fedin 3a9eb8463d Try to always use QWidget::screen 2024-09-19 10:46:10 +02:00
John Preston 4befb125e3 Update emoji to Unicode 15.1. 2024-09-19 12:26:52 +04:00
John Preston ca00a19736 Updated emoji resources to Unicode 15.1. 2024-09-19 10:26:30 +02:00
John Preston 296969bcd1 Add "Ada" library mention to README. 2024-09-19 10:43:38 +04:00
John Preston 3218c30983 Add "Include muted chats in folder counters". 2024-09-19 10:34:01 +04:00
John Preston 3658b32db5 Correctly count 'other accounts unread' in menu. 2024-09-19 10:34:01 +04:00
John Preston 592d46c8f2 Fix emoji packs from album captions. 2024-09-19 10:34:01 +04:00
John Preston 8b86f12c23 Fix quote-reply to album captions. 2024-09-19 10:34:01 +04:00
John Preston 2e2d8d2af3 Add FieldAutocomplete to EditCaptionBox. 2024-09-19 10:34:01 +04:00
John Preston 3eec43cacd Add FieldAutocomplete to SendFilesBox. 2024-09-19 10:34:01 +04:00
John Preston ba7cd25f21 Extract FieldAutocomplete code. 2024-09-19 10:34:01 +04:00
John Preston 969152e949 Move FieldAutocomplete to ChatHelpers. 2024-09-19 10:34:01 +04:00
23rd b78443cf2d Added mini icon to drafts with reply. 2024-09-19 10:34:01 +04:00
23rd 4288ba2449 Improved UX in box for link creation when user has link in clipboard. 2024-09-19 10:34:01 +04:00
Ilya Fedin 22a3093815 Check updater exit status on Linux 2024-09-18 08:27:18 +02:00
John Preston 98ba2c7ce4 Version 5.5.5.
- Suggest URL from clipboard when creating a custom link.
- Fix animated topic icons in topic info page.
- Fix excessive getChannelDifference requests.
2024-09-13 21:04:07 +04:00
John Preston 36962b8c62 Fix possible crash in swipe-to-reply. 2024-09-13 21:04:07 +04:00
John Preston d0a8bd1f03 Use colored topic icons only when required. 2024-09-13 20:06:38 +04:00
John Preston c9e0f50f0f Revert "Improved color of topic icon in TopicIconView."
This reverts commit a38dcb6ee5.
2024-09-13 20:06:32 +04:00
John Preston 1dc310586d Unregister channel from shortpoll. 2024-09-13 20:06:19 +04:00
23rd 6f71d21bb7 Slightly improved box for link creation when user has link in clipboard. 2024-09-13 17:14:48 +03:00
AlexeyZavar 7caf421074 Merge tag 'v5.5.4' into dev
# Conflicts:
#	.github/workflows/mac_packaged.yml
#	.github/workflows/snap.yml
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
2024-09-12 23:13:38 +03:00
Ilya Fedin c93f047056 Add run0 support 2024-09-12 23:08:06 +04:00
AlexeyZavar 392f2e633c feat: message field configuration 2024-09-12 16:10:03 +03:00
John Preston ef98d4ece7 Version 5.5.4.
- Fix channel updates stopping after difference request failing.
- Add QR code generation for your username in Settings.
- Fix swipe-to-reply gestures stopping. (macOS)
2024-09-12 14:41:33 +04:00
23rd 2383bf2c71 Fit amount of available colors in box for share of QR code to 8. 2024-09-12 13:39:13 +03:00
23rd 2c8c92c2a4 Slightly increased max width for username in QR code. 2024-09-12 13:38:36 +03:00
23rd bad2dc30c3 Added button to generate QR code for self to main section of settings. 2024-09-12 13:28:10 +03:00
Ilya Fedin fe7f4233b9 Add missing ThirdParty cache to Windows action 2024-09-12 14:13:53 +04:00
Ilya Fedin 68454a9841 Migrate almost all actions to latest OS versions 2024-09-12 14:13:53 +04:00
John Preston d3bcf63cf7 Fix repeated request of channel difference. 2024-09-12 14:08:09 +04:00
John Preston a5f1209f28 Remove redundant web apps code. 2024-09-12 14:08:09 +04:00
AlexeyZavar 66b7a48352 feat: send without sound 2024-09-11 22:41:03 +03:00
AlexeyZavar 5bd66f9a76 fix: schedule tokenless bot start 2024-09-11 21:58:14 +03:00
AlexeyZavar 6da6817037 fix: channel messages 2024-09-11 21:44:10 +03:00
AlexeyZavar 11b3880f8e fix: set device pixel ratio 2024-09-11 21:32:53 +03:00
AlexeyZavar a3d87ff26a fix: make it build 2024-09-11 21:15:51 +03:00
AlexeyZavar 409eedf58d Merge tag 'v5.5.3' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/history/history_widget.cpp
#	Telegram/SourceFiles/history/view/history_view_element.cpp
#	Telegram/lib_tl
#	Telegram/lib_ui
#	lib/xdg/org.telegram.desktop.metainfo.xml
#	snap/snapcraft.yaml
2024-09-11 20:23:00 +03:00
23rd 9a44ca2769 Fixed display of message without text in section of shared links. 2024-09-11 16:31:46 +03:00
23rd 155305f0f7 Added ability to generate QR code for self from settings. 2024-09-11 15:25:05 +03:00
23rd 6abce8d976 Added attention style to menu item to delete all call logs. 2024-09-11 15:25:05 +03:00
23rd f16d1f034f Switched swipe-to-reply processing on macOS from touch to scroll events. 2024-09-11 00:37:47 +03:00
John Preston dab107cf90 Version 5.5.3.
- Fix custom emoji sending.
- Add mention link QR code sharing.
- Fix sending files from network drives. (Windows)
2024-09-10 15:07:14 +04:00
23rd d1d1aa3d21 Moved premium gradient in box for share of QR code to first place. 2024-09-10 13:51:23 +03:00
23rd d0536cc31f Replaced boxes for QR code of invite links with box for share QR code. 2024-09-10 13:51:23 +03:00
23rd c47f5e9995 Added ability to create box for share QR code without peer. 2024-09-10 13:51:23 +03:00
23rd 0916836ff9 Added ability to provide description and custom link to FillPeerQrBox. 2024-09-10 13:51:23 +03:00
John Preston 5dd9ff1062 Accept only CF_HDROP for uri-list mime.
Additional types lead to such problem: some programs, like JetBrains
IDEs, like PyCharm, copy "file://[ip-address]/file" as an URI in
uri-list, that way you can't paste it in the messenger, because it
will make a request to that address and reveal clients IP address.
2024-09-10 14:19:37 +04:00
John Preston d1e3b9f15d Revert "Check for local URLs more strictly."
This reverts commit c3fda41224.
2024-09-10 14:19:37 +04:00
John Preston ca3c179b75 Use full available width for text in some places.
Fixes #28384.
2024-09-10 14:19:37 +04:00
John Preston c2d5924508 Fix build with MSVC. 2024-09-10 14:19:37 +04:00
John Preston 016d0395c3 Fix custom emoji sending. 2024-09-10 14:17:32 +04:00
23rd 925c9239bd Added ability to share QR code from channels. 2024-09-10 11:34:55 +03:00
23rd fdcbe3cf3a Fixed width of username label with right button in profile section. 2024-09-10 11:08:42 +03:00
23rd f6b9cc5ce1 Improved padding in box for share QR box on different scales. 2024-09-10 10:56:02 +03:00
23rd 8c915e6dc3 Renamed FillProfileQrBox to FillPeerQrBox. 2024-09-10 03:26:15 +03:00
23rd 1db426da2e Added ability to choose quality in box for share of QR code. 2024-09-10 03:26:15 +03:00
23rd d9be363962 Added ability to hide userpic from box for share of QR code. 2024-09-10 02:00:26 +03:00
23rd 88daa37e34 Added ability to generate QR code independently from ui scale. 2024-09-10 02:00:26 +03:00
23rd 931fa01337 Added premium gradient to box for share of QR code. 2024-09-10 02:00:26 +03:00
23rd 8e1595eb29 Adapted display of longest usernames in box for share of QR code. 2024-09-10 02:00:26 +03:00
23rd 29e97232d8 Added initial ability to share QR code from user profile. 2024-09-10 02:00:26 +03:00
John Preston f05191e668 Version 5.5.2: Fix build. 2024-09-09 21:30:15 +04:00
John Preston 1ba189e59d Version 5.5.2.
- Support two bottom buttons in web apps.
- Fix text layout outside of the message bubble glitch.
- Don't stop video when dragging media viewer in window mode.
2024-09-09 21:12:33 +04:00
23rd c40ca70aa6 Added date of admin promotional to EditAdminBox. 2024-09-09 17:20:52 +03:00
23rd 521f991167 Replaced float labels with text in dividers in EditAdminBox. 2024-09-09 17:20:52 +03:00
23rd edf1417bbb Added date of restriction to EditRestrictedBox. 2024-09-09 17:20:52 +03:00
23rd 686e9643ad Replaced channel participant parsing with modern way in admin log. 2024-09-09 17:20:52 +03:00
23rd 975460d268 Added api support for dates of chat participant data. 2024-09-09 17:20:52 +03:00
23rd 6b0c606d25 Switched type of subscription date from Qt to TimeId. 2024-09-09 17:20:52 +03:00
23rd 93ff0bdcff Slightly improved style of box for sending GIF with caption. 2024-09-09 17:20:52 +03:00
23rd bf9d90ca4e Fixed emoji display in header of link for dialog filters. 2024-09-09 17:20:52 +03:00
23rd d6e5e1e8f7 Added handle of flood errors in request of join to chatlist. 2024-09-09 17:20:52 +03:00
23rd d3ae2ef9ea Synced local English phrases with server. 2024-09-09 17:20:52 +03:00
John Preston 40b0854704 Don't pause video on viewer drag. 2024-09-09 17:54:16 +04:00
John Preston 9aec6b6496 Set min width for field collapsed quotes. 2024-09-09 17:24:15 +04:00
John Preston d01f977960 Don't offer hello-sticker to user you've blocked. 2024-09-09 16:42:02 +04:00
John Preston 1444009ee2 Update submodules. 2024-09-09 14:58:40 +04:00
John Preston 14ee9bee26 Fix quotes starting with custom urls. 2024-09-09 14:58:40 +04:00
Ilya Fedin 93587ddc3c Allow scale preview in separate window on Wayland 2024-09-09 14:49:44 +04:00
John Preston 0c4d03477e Fix text layout in some cases. 2024-09-09 14:28:37 +04:00
John Preston a35092f012 Support second button in web apps. 2024-09-09 13:29:00 +04:00
John Preston 49ee7ee52b Version 5.5.1: Update cmake_helpers. 2024-09-07 00:25:47 +04:00
John Preston 52c77a1970 Version 5.5.1.
- Fix crash in peer short info box.
2024-09-06 23:30:32 +04:00
John Preston e4269ae7fb Fix crash in PeerShortInfoBox. 2024-09-06 23:28:43 +04:00
John Preston bd6011c524 Version 5.5.
- Star Giveaways.
- Swipe-to-Reply.
- Audio device selection in one-on-one calls.
- Text selection in collapsed / expanded quotes.
2024-09-06 21:57:47 +04:00
23rd 46cb3ec103 Added box for boosts with credits. 2024-09-06 21:57:47 +04:00
23rd 0241129948 Added support of admin log filter for extended subscriptions. 2024-09-06 21:57:47 +04:00
23rd e44aca06cb Added support of admin log event of extended subscriptions. 2024-09-06 21:57:47 +04:00
23rd 19d386f977 Added support of credits to giveaway info results. 2024-09-06 21:57:47 +04:00
John Preston a67fdda913 Fix the Release build for macOS. 2024-09-06 21:57:47 +04:00
John Preston 5286c7b1c3 Allow selecting text in collapsed quotes. 2024-09-06 21:57:47 +04:00
23rd d9d96d0a6f Fixed display of custom badge in selected messages for giveaways. 2024-09-06 21:57:47 +04:00
23rd 13353bb615 Improved phrases in service message for giveaway results with credits. 2024-09-06 21:57:47 +04:00
23rd d78348fd16 Fixed crash in box for giveaway create when winners number is constant. 2024-09-06 21:57:46 +04:00
23rd 1e8e660133 Improved phrases in top bar from box for giveaway creation with credits. 2024-09-06 21:57:46 +04:00
23rd 5196982c98 Improved phrases in box for information of giveaway with credits. 2024-09-06 21:57:46 +04:00
23rd 99f857fbf6 Improved phrases in service message for started giveaway with credits. 2024-09-06 21:57:46 +04:00
23rd 0982aa166a Added support of prepaid giveaway with credits. 2024-09-06 21:57:46 +04:00
23rd 3ae9f86097 Slightly improved display of credits in boosts from statistics list. 2024-09-06 21:57:46 +04:00
23rd 9efd9b0d68 Slightly improved timestamp parsing in Api::Boosts. 2024-09-06 21:57:46 +04:00
John Preston 267a73f355 Update API scheme on layer 187. 2024-09-06 21:57:46 +04:00
John Preston 437d8ea890 Fix build with MSVC. 2024-09-06 21:57:46 +04:00
23rd 7ed92ec402 Added credits icon to boosts in statistics list. 2024-09-06 21:57:46 +04:00
23rd 678d9ffbf9 Added support of giveaway prize action messages to export to JSON. 2024-09-06 21:57:46 +04:00
23rd bc4b427ed1 Added support of giveaway prize action messages to export to HTML. 2024-09-06 21:57:46 +04:00
23rd 36141a9df9 Added support of giveaway results messages to export to JSON. 2024-09-06 21:57:46 +04:00
23rd d68ba75457 Improved process of giveaway messages for export to JSON. 2024-09-06 21:57:46 +04:00
23rd 00ad32c5f4 Added support of giveaway results messages to export to HTML. 2024-09-06 21:57:46 +04:00
23rd 064bab60ff Improved process of giveaway messages for export to HTML. 2024-09-06 21:57:46 +04:00
23rd 5b146217c0 Added support for credits in messages of prize in giveaways. 2024-09-06 21:57:46 +04:00
23rd 202c81b2e5 Added support for credits in messages for starting and ending giveaways. 2024-09-06 21:57:46 +04:00
23rd 4520480604 Added support of credits giveaway to ReceiptCreditsBox. 2024-09-06 21:57:46 +04:00
23rd aea87bb5cb United buttons for premium giveaway and premium gifts to single button. 2024-09-06 21:57:46 +04:00
23rd 19492f7e7b Improved prize description for credits in box for giveaway creation. 2024-09-06 21:57:46 +04:00
23rd 51030e3c45 Added list of options to box for giveaway creation with credits. 2024-09-06 21:57:46 +04:00
23rd e6b8b4be18 Added initial payment support for credits giveaway. 2024-09-06 21:36:03 +04:00
23rd 6ac13b7f80 Added button for credits giveaway to box for giveaway creation. 2024-09-06 21:36:03 +04:00
23rd 7e5e6003a9 Added initial api support for credits giveaway options. 2024-09-06 21:36:03 +04:00
23rd f445440995 Added initial data structure for credits giveaway options. 2024-09-06 21:36:03 +04:00
John Preston d81547f091 Support cloud-saved paid reaction privacy. 2024-09-06 21:36:03 +04:00
John Preston 2b185d491b Update API scheme to layer 187. 2024-09-06 21:36:03 +04:00
John Preston ca47440950 Don't treat .gif as "small image". 2024-09-06 21:07:17 +04:00
John Preston 5e32602f4a Add elastic overscroll to swipe-to-reply. 2024-09-06 21:07:02 +04:00
23rd 1f4516028c Fixed desync of repaint of userpics and messages while swipe-on-reply. 2024-09-06 19:52:29 +03:00
23rd 7f29d269a3 Changed swipe-on-reply detection only when scroll has began. 2024-09-06 17:11:16 +03:00
23rd 62c3374911 Disabled swipe-to-reply for channels. 2024-09-06 12:04:42 +03:00
23rd 2116e04af5 Allowed to swipe-to-reply only with started initial of touches. 2024-09-06 11:56:21 +03:00
John Preston a97d5e80c7 Fix custom reaction as a quick one. 2024-09-05 19:13:52 +04:00
John Preston b5098038d0 Add two-year ttl time for account. 2024-09-05 17:05:09 +04:00
John Preston 6fce718252 Add jump-to-end button to chat preview. 2024-09-05 14:50:38 +04:00
John Preston 40cf96202d Add 1.5 years account ttl value. 2024-09-05 14:11:41 +04:00
John Preston c18e59218e Show internal list of apps as Stars Examples. 2024-09-05 13:14:07 +04:00
John Preston 216865a20d Fix file albums with inline keyboard buttons. 2024-09-05 12:01:43 +04:00
John Preston 6c5036ee8d Fix typo in swipe-to-reply through QWheelEvent. 2024-09-05 11:52:25 +04:00
Viliansh dc2f59ca24 Added org.telegram as developer_id in the flatpak metainfo.xml
Co-authored-by: ilya-fedin <fedin-ilja2010@ya.ru>
2024-09-05 09:47:43 +02:00
Viliansh 6f6457137e removed update_contact from flatpak metainfo.xml 2024-09-05 09:47:43 +02:00
Viliansh bc5cb6e2a2 Changed dev name in org.telegram.desktop.metainfo.xml
In flathub, and it's front-ends like KDE's Discover or GNOME Software, Telegram shows "By John Preston", and some users were hesitant to install it afraid that was "fake", so i changed it to Telegram, this would also make it consistent with snap, thanks!
2024-09-05 09:47:43 +02:00
John Preston 16825fff41 Use QWheelEvent::inverted() in swipe gesture. 2024-09-05 11:30:37 +04:00
John Preston 5024f1db8c Beta version 5.4.6.
- Add Swipe-To-Reply for modern touchpads and touchscreens.
- Add text selection in collapsed and expanded blockquotes.
- Fix text rendering in 100% interface scale on Windows.
2024-09-04 18:39:16 +04:00
23rd a60385fc3d Removed QGraphicsOpacityEffect usage from media view overlay widget. 2024-09-04 18:39:16 +04:00
23rd b20e2c37c1 Fixed build on Qt6. 2024-09-04 18:39:16 +04:00
John Preston acd40cbeb6 Apply invert_media flag on message send finish. 2024-09-04 18:32:48 +04:00
23rd 6a45a862dd Removed wheel events from scale slider in section of main settings. 2024-09-04 16:01:55 +02:00
23rd 5bd45e9a20 Fixed updating of left userpic with offset from swipe-on-reply. 2024-09-04 16:01:55 +02:00
23rd 52e42f23ab Improved animation speed on release of swipe-on-reply with various x. 2024-09-04 16:01:54 +02:00
23rd 96b7755cde Fixed updating of message on bounce animation of swipe-on-reply icon. 2024-09-04 16:01:54 +02:00
23rd c589ee1ca5 Fixed overlap of reply icon on left swipe of message with right action. 2024-09-04 16:01:54 +02:00
23rd 18c9ee093b Fixed unwanted top offset of dialogs widget when float player opened. 2024-09-04 16:01:54 +02:00
John Preston b82fa3112c Improve touchscreen swipt-to-reply. 2024-09-04 16:01:20 +02:00
John Preston 8d0f66d562 Fix touchscreen history scrolling. 2024-09-04 14:06:11 +02:00
John Preston 20a5e0ba73 Fix controls layout after adding a bot to a group.
Fixes https://bugs.telegram.org/c/19451
2024-09-04 14:56:50 +04:00
John Preston 5a2667c71e Fix reply previews to blockquotes / codeblocks. 2024-09-04 14:45:35 +04:00
John Preston 1f4a8d7eb6 Fix build with MSVC. 2024-09-04 14:45:07 +04:00
John Preston 4430bd0328 Improve lottie icon layout in group calls. 2024-09-04 14:14:12 +04:00
John Preston ab2e7f4c03 Fix media viewer create on non-primary screen. 2024-09-04 14:14:12 +04:00
John Preston 54e5c06b4d Revert updated Harfbuzz-NG in Qt 5.15.15.
This fixes the regression with text rendering in 100% scale.

Fixes #28340.
2024-09-04 14:14:12 +04:00
23rd add5a6a0be Added debug util to ensure end of life of objects. 2024-09-04 14:14:12 +04:00
23rd 89c2ba4293 Weakened gesture orientation check within swipe-to-reply. 2024-09-04 14:14:12 +04:00
23rd dd100fb709 Fixed back gesture responsiveness for swipe-to-reply on macOS. 2024-09-04 14:14:12 +04:00
John Preston e8dd2b9e7b Use only integer translations in reply swipe. 2024-09-04 14:14:12 +04:00
23rd 71e3cd227c Added initial swipe-to-reply to section for replies. 2024-09-04 14:14:12 +04:00
23rd 1648c31a22 Moved out swipe-to-reply setup to inner method in HistoryInner. 2024-09-04 14:14:12 +04:00
23rd f8c820f319 Fixed swipe-to-reply on macOS. 2024-09-04 14:14:12 +04:00
John Preston 300f35e78f Implement both touch and wheel swipe-to-reply. 2024-09-04 14:14:12 +04:00
23rd 2aa5849997 Improved horizontal animation for reply icon on left swipe. 2024-09-04 14:14:12 +04:00
23rd fb1b845211 Improved process of message repaint on swipe to reply. 2024-09-04 14:14:11 +04:00
23rd 3d2af9db8e Improved distance of reply icon on left swipe. 2024-09-04 14:14:11 +04:00
23rd 6129e5a1cf Added bounce animation on finish of replying with left swipe. 2024-09-04 14:14:11 +04:00
23rd 7f70ee1227 Added initial ability to reply with left swipe. 2024-09-04 14:14:11 +04:00
23rd c9f7da6e82 Added ability to paint icons in center of QRectF. 2024-09-04 10:33:28 +03:00
23rd f956c0f227 Added experimental option to disable touch bar on macOS. 2024-09-04 10:12:08 +03:00
23rd df935e0477 Improved code style of gifMaxStatusWidth static function. 2024-09-04 10:11:57 +03:00
23rd 841f1afe1e Improved subtitle space in permissions and restrictions edit boxes. 2024-09-04 10:11:54 +03:00
23rd fb8b88557e Added ability to kick participants from section of admin log. 2024-09-04 10:11:49 +03:00
23rd 2b502b22b9 Replaced PeerData::generateUserpicImage with static function. 2024-09-04 10:11:44 +03:00
23rd 5ac80d2655 Fixed text clipping at bottom in settings section for cloud password. 2024-09-04 10:11:41 +03:00
23rd 8aa7499e63 Fixed width of stats PointDetailsWidget for charts with currency. 2024-09-04 10:11:36 +03:00
23rd 8cd5e51982 Added missed handler of server error when try to reset cloud password. 2024-09-04 10:11:31 +03:00
23rd e5c2133446 Disabled Qt build on Windows without successful applied patches. 2024-09-04 10:11:17 +03:00
John Preston 3dccdf2f05 Beta version 5.4.5.
- Fix possible crash in text rendering.
2024-09-01 10:19:39 +04:00
John Preston 8a708c6655 Update Qt to 5.15.15 on Windows. 2024-09-01 10:19:39 +04:00
Ilya Fedin 9e1d9eee4b Fix snap build 2024-08-31 20:09:36 +02:00
Ilya Fedin f30aabc365 Update Qt 6.7.2 -> 6.8.0 2024-08-31 19:54:58 +02:00
John Preston a5546d016f Fix possible crash in long-word texts. 2024-08-31 21:48:52 +04:00
John Preston f79d70d112 Use Ui::Text::String in Ui::RoundButton. 2024-08-31 21:48:52 +04:00
John Preston ec28f258fb Use full bubble width in message text rendering.
Fixes #28331.
2024-08-31 21:48:52 +04:00
John Preston 08f3a6fb40 Fix local group sent-as display. 2024-08-31 21:48:52 +04:00
John Preston 8823d5256f Fix indentation. 2024-08-31 21:48:52 +04:00
23rd 60e7aa90d2 Added ability to report profile photo from peer info section. 2024-08-31 12:34:50 +03:00
John Preston 71357a9546 Fix archive chats list bidi support. 2024-08-29 17:48:06 +04:00
John Preston a5b06e9c56 Fix possible crash in text elision. 2024-08-29 17:41:15 +04:00
23rd 0f94419f6d Improved fix of crash in video messages playback.
Regression was introduced in ad3e447f08.
2024-08-29 17:37:55 +04:00
John Preston 94e7aabea5 Fix spaces after emoji in text rendering. 2024-08-29 17:19:28 +04:00
John Preston f6c816cafe Beta version 5.4.4.
- Fix wrong layout and crashes in text shaping.
- Fix crashes in voice / video messages playback.
2024-08-29 13:01:06 +04:00
John Preston 4cf160e8dc Fix UB in text shaping. 2024-08-29 12:54:52 +04:00
John Preston 9252be5e8c Fix crash in video messages playback.
Regression was introduced in ad3e447f08.
2024-08-29 12:13:51 +04:00
John Preston ed342eea64 Beta version 5.4.3. (Windows only)
- Fix working on Windows 7.
2024-08-29 10:32:53 +04:00
John Preston e6405bc455 Beta version 5.4.2.
- Select audio devices from one-on-one call window.
- Bug fixes and other minor improvements.
- New text layout testing.
2024-08-28 21:50:05 +04:00
John Preston fed09461ce Fix spaces after newline rendering. 2024-08-28 19:16:55 +04:00
John Preston 6e1ddef4fe Fix strings for group profile colors. 2024-08-28 17:45:29 +04:00
John Preston 76be4a3eb9 Fix build on Windows. 2024-08-28 17:45:18 +04:00
John Preston 997a9e2fe3 Fix text elision under spoiler. 2024-08-28 17:29:43 +04:00
23rd 03790f3da0 Removed include directive for ui_utility from rp_widget header. 2024-08-28 15:15:58 +03:00
23rd e46a703c7d Removed include directive for ui/integration from ui_utility header. 2024-08-28 14:39:05 +03:00
23rd ae17acdfd4 Removed include directive for ui_utility from rp_widget header. 2024-08-28 14:38:33 +03:00
23rd 2422c9ce9e Moved out Ui::MakeWeak to separate file. 2024-08-28 14:37:56 +03:00
23rd 7f75d7082a Moved out Ui::CreateChild to separate file. 2024-08-28 14:37:07 +03:00
23rd 4749ab175e Fixed build with Apple clang. 2024-08-28 14:37:07 +03:00
John Preston e651699e1d Fix thumbnailed document layout. 2024-08-28 14:58:21 +04:00
John Preston 3f4157bab2 Fix crash in unlock with chat in separate window.
Fixes #28306, fixes #28319.
2024-08-28 14:58:21 +04:00
John Preston a98f559066 Add test_text test app. 2024-08-28 14:58:09 +04:00
John Preston ffd54c452c Support DirectManipulation in chat preview. 2024-08-28 14:58:02 +04:00
John Preston 61424eeab9 Fix build with Qt 5. 2024-08-28 14:57:49 +04:00
John Preston c131d6637d Don't force LTR direction on texts. 2024-08-28 14:57:42 +04:00
John Preston 24b0b33f1d Wrap names in LRM/RLM for correct layout. 2024-08-28 14:55:41 +04:00
23rd 675198d361 Fixed gradient in Ui::Premium::BubbleWidget with large ui scale. 2024-08-28 12:38:07 +03:00
23rd ed667a42ad Moved out MainWidget::clearBotStartToken to static function. 2024-08-28 09:49:53 +03:00
23rd 920484d540 Fixed update of submit way in all opened windows. 2024-08-28 09:32:39 +03:00
23rd 07c5e6542b Replaced Info::Controller with navigation in box for giveaway creation. 2024-08-28 09:10:10 +03:00
23rd 6a43f2e508 Fixed display of round edges in box for giveaway creation. 2024-08-28 09:06:44 +03:00
23rd ad3e447f08 Added ability to player to go to message for songs from another session. 2024-08-28 08:50:28 +03:00
23rd 1840da1d68 Moved out creation of button for paging of stats lists to single place. 2024-08-27 18:48:19 +03:00
23rd c82b86cea3 Added ability to convert scale float values. 2024-08-27 18:48:19 +03:00
23rd 0fb383c466 Added ability to block bot from moderate box. 2024-08-27 18:27:15 +03:00
23rd 69fc2f48bf Removed unused include directives from MainWidget. 2024-08-27 18:27:15 +03:00
23rd 7c604fc86a Added ability to send GIF with caption. 2024-08-27 18:27:15 +03:00
23rd ec7fbb8952 Added ability to provide text with tags when send existing document. 2024-08-22 17:10:17 +03:00
23rd 679350e23d Removed unused simple sendExistingDocument methods from sections. 2024-08-22 17:10:12 +03:00
23rd f0209c9d6e Removed unused MainWidget::sendExistingDocument. 2024-08-22 17:10:06 +03:00
23rd 5020aec6ec Moved out AddEmojiToggleToField to separate file. 2024-08-22 17:08:25 +03:00
23rd 13737577e7 Fixed updating over state in history widget when edit spoiler of media. 2024-08-21 20:00:48 +03:00
23rd 4ee7d46d78 Improved static infinite radial animation in panel of webview bot. 2024-08-21 19:25:58 +03:00
23rd d143e32022 Fixed loading of credits history list with offset. 2024-08-21 18:26:24 +03:00
23rd 0a0dab74a1 Added ability to rejoin to subscribed channel after left. 2024-08-21 17:46:36 +03:00
23rd c6ea91e671 Replaced AdminLog::FilterBox with GenericBox. 2024-08-21 17:18:12 +03:00
23rd 8011adb219 Replaced bool with std::optional in AdminLog::FilterValue. 2024-08-21 17:18:12 +03:00
23rd 6ba5d5f16b Removed old AdminLog::FilterBox. 2024-08-21 17:18:12 +03:00
23rd d5774830d8 Added ability to provide data to Ui::ExpandablePeerListController. 2024-08-21 17:18:12 +03:00
23rd eb268102fc Moved out functions to create expandable moderate list to separate file. 2024-08-21 17:18:12 +03:00
23rd b364c4f23a Moved out graphic of button for expandable moderate list to view. 2024-08-21 17:18:12 +03:00
23rd 91b9266a91 Moved out lambdas to create expandable moderate list to functions. 2024-08-21 17:18:12 +03:00
23rd 1e6236a987 Wrapped filter value labels with EditFlagsControl. 2024-08-21 17:18:12 +03:00
23rd 10ebd7e6ef Moved out AdminLog::FilterValue to separate file. 2024-08-21 17:18:12 +03:00
John Preston 6b83c52c7c Improve top senders rebuild.
Fixes #28296.
2024-08-21 10:54:30 +02:00
John Preston 46304c7a2d Fix build in Release. 2024-08-21 09:35:46 +02:00
John Preston c3fda41224 Check for local URLs more strictly. 2024-08-21 09:35:46 +02:00
John Preston a4017e930e Add device selectors to one-on-one calls. 2024-08-21 09:35:46 +02:00
John Preston 95bdb925d5 Fix paddings in text messages disabler. 2024-08-20 16:10:27 +02:00
23rd a26bae70c7 Added Enter shortcut to EditForumTopicBox for confirmation. 2024-08-19 12:53:42 +03:00
23rd a38dcb6ee5 Improved color of topic icon in TopicIconView. 2024-08-19 12:02:12 +03:00
23rd eb27c12117 Added icon and name of contact to deletion confirmation box. 2024-08-18 21:53:12 +03:00
23rd c03fcf9a23 Added icon and name of topic to deletion confirmation box. 2024-08-18 21:44:34 +03:00
23rd 71f83b5993 Made creation of title with userpic more generic. 2024-08-18 21:44:23 +03:00
23rd fd2d12d6b1 Removed time shift when reschedule history item. 2024-08-18 20:32:21 +03:00
23rd 50f9f36c3d Fixed padding for history entries in channel earn section. 2024-08-18 13:02:39 +03:00
23rd f650c679e0 Improved text padding in ShowOrPremiumBox. 2024-08-18 12:41:00 +03:00
23rd 8349cb0dd4 Removed currency column from channel earn section when it's empty. 2024-08-18 12:29:56 +03:00
567 changed files with 33340 additions and 14144 deletions
+9 -1
View File
@@ -42,7 +42,7 @@ jobs:
windows:
name: Windows
runs-on: windows-2022
runs-on: windows-latest
strategy:
matrix:
@@ -94,6 +94,14 @@ jobs:
nuget sources Disable -Name "Microsoft Visual Studio Offline Packages"
nuget sources Add -Source https://api.nuget.org/v3/index.json & exit 0
- name: ThirdParty cache.
id: cache-third-party
uses: actions/cache@v4
with:
path: ${{ env.TBUILD }}\ThirdParty
key: ${{ runner.OS }}-${{ matrix.arch }}-third-party-${{ env.CACHE_KEY }}
restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-third-party-
- name: Libraries cache.
id: cache-libs
uses: actions/cache@v4
+3
View File
@@ -51,3 +51,6 @@ stage
*.*~
.idea/
cmake-build-debug/
# Project specific
Telegram/SourceFiles/_other/packer_private.h
+97
View File
@@ -0,0 +1,97 @@
# AyuGram
![AyuGram Лого](.github/AyuGram.png) ![AyuChan](.github/AyuChan.png)
[ [English](README.md) | Русский ]
## Функции и Фишки
- Полный режим призрака (настраиваемый)
- История удалений и изменений сообщений
- Кастомизация шрифта
- Режим Стримера
- Локальный телеграм премиум
- Превью медиа и быстрая реакция при сильном нажатии на тачпад (macOS)
- Улучшенный вид
И многое другое. Посмотрите нашу [Документацию](https://docs.ayugram.one/desktop/) для более подробной информации.
## Скриншоты настроек
<img src='.github/demos/demo1.png' width='268'>
<img src='.github/demos/demo3.png' width='268'>
<img src='.github/demos/demo2.png' width='268'>
<img src='.github/demos/demo4.png' width='268'>
## Установка
### Windows
#### Официальный вариант
Вы можете скачать готовый бинарный файл со [вкладки Releases](https://github.com/AyuGram/AyuGramDesktop/releases) или из
[Телеграм чата](https://t.me/ayugramchat/12788).
#### Winget
```bash
winget install RadolynLabs.AyuGramDesktop
```
#### Scoop
```bash
scoop bucket add extras
scoop install ayugram
```
#### Сборка вручную
Следуйте [официальному руководству](https://github.com/AyuGram/AyuGramDesktop/blob/dev/docs/building-win-x64.md), если
вы хотите собрать AyuGram сами.
### Arch Linux
Вы можете установить `ayugram-desktop` или `ayugram-desktop-git`
из [AUR](https://aur.archlinux.org/packages?O=0&K=ayugram).
### NixOS
Попробуйте [этот репозиторий](https://github.com/kaeeraa/ayugram-desktop).
### Любой другой Линукс дистрибутив
Следуйте [официальному руководству](https://github.com/AyuGram/AyuGramDesktop/blob/dev/docs/building-linux.md).
### Примечания для Windows
Убедитесь что у вас присутствуют эти зависимости:
- C++ MFC latest (x86 & x64)
- C++ ATL latest (x86 & x64)
- последний Windows 11 SDK
## Пожертвования
Вам нравится использовать **AyuGram**? Оставьте нам чаевые!
[Здесь доступные варианты.](https://docs.ayugram.one/donate/)
## Использованные материалы
### Телеграм клиенты
- [Telegram Desktop](https://github.com/telegramdesktop/tdesktop)
- [Kotatogram](https://github.com/kotatogram/kotatogram-desktop)
- [64Gram](https://github.com/TDesktop-x64/tdesktop)
- [Forkgram](https://github.com/forkgram/tdesktop)
### Использованные библиотеки
- [JSON for Modern C++](https://github.com/nlohmann/json)
- [SQLite](https://github.com/sqlite/sqlite)
- [sqlite_orm](https://github.com/fnc12/sqlite_orm)
### Иконки
- [Solar Icon Set](https://www.figma.com/community/file/1166831539721848736)
+3
View File
@@ -2,6 +2,8 @@
![AyuGram Logo](.github/AyuGram.png) ![AyuChan](.github/AyuChan.png)
[ English | [Русский](README-RU.md) ]
## Features
- Full ghost mode (flexible)
@@ -10,6 +12,7 @@
- Font customization
- Streamer mode
- Local Telegram Premium
- Media preview & quick reaction on force click (macOS)
- Enhanced appearance
And many more. Check out our [Documentation](https://docs.ayugram.one/desktop/).
+27 -6
View File
@@ -37,6 +37,10 @@ include(cmake/td_scheme.cmake)
include(cmake/td_ui.cmake)
include(cmake/generate_appdata_changelog.cmake)
if (DESKTOP_APP_TEST_APPS)
include(cmake/tests.cmake)
endif()
if (WIN32)
include(cmake/generate_midl.cmake)
generate_midl(Telegram ${src_loc}
@@ -132,12 +136,12 @@ set(ayugram_files
ayu/ui/context_menu/context_menu.h
ayu/ui/context_menu/menu_item_subtext.cpp
ayu/ui/context_menu/menu_item_subtext.h
ayu/ui/sections/edited/edited_log_inner.cpp
ayu/ui/sections/edited/edited_log_inner.h
ayu/ui/sections/edited/edited_log_item.cpp
ayu/ui/sections/edited/edited_log_item.h
ayu/ui/sections/edited/edited_log_section.cpp
ayu/ui/sections/edited/edited_log_section.h
ayu/ui/message_history/history_inner.cpp
ayu/ui/message_history/history_inner.h
ayu/ui/message_history/history_item.cpp
ayu/ui/message_history/history_item.h
ayu/ui/message_history/history_section.cpp
ayu/ui/message_history/history_section.h
ayu/ui/boxes/edit_deleted_mark.cpp
ayu/ui/boxes/edit_deleted_mark.h
ayu/ui/boxes/edit_edited_mark.cpp
@@ -390,12 +394,16 @@ PRIVATE
boxes/self_destruction_box.h
boxes/send_credits_box.cpp
boxes/send_credits_box.h
boxes/send_gif_with_caption_box.cpp
boxes/send_gif_with_caption_box.h
boxes/send_files_box.cpp
boxes/send_files_box.h
boxes/sessions_box.cpp
boxes/sessions_box.h
boxes/share_box.cpp
boxes/share_box.h
boxes/star_gift_box.cpp
boxes/star_gift_box.h
boxes/sticker_set_box.cpp
boxes/sticker_set_box.h
boxes/stickers_box.cpp
@@ -643,6 +651,8 @@ PRIVATE
data/data_lastseen_status.h
data/data_location.cpp
data/data_location.h
data/data_media_preload.cpp
data/data_media_preload.h
data/data_media_rotation.cpp
data/data_media_rotation.h
data/data_media_types.cpp
@@ -678,6 +688,7 @@ PRIVATE
data/data_replies_list.h
data/data_reply_preview.cpp
data/data_reply_preview.h
data/data_report.h
data/data_saved_messages.cpp
data/data_saved_messages.h
data/data_saved_sublist.cpp
@@ -1021,6 +1032,10 @@ PRIVATE
info/media/info_media_widget.h
info/members/info_members_widget.cpp
info/members/info_members_widget.h
info/peer_gifts/info_peer_gifts_common.cpp
info/peer_gifts/info_peer_gifts_common.h
info/peer_gifts/info_peer_gifts_widget.cpp
info/peer_gifts/info_peer_gifts_widget.h
info/polls/info_polls_results_inner_widget.cpp
info/polls/info_polls_results_inner_widget.h
info/polls/info_polls_results_widget.cpp
@@ -1556,6 +1571,8 @@ PRIVATE
support/support_templates.h
ui/boxes/edit_invite_link_session.cpp
ui/boxes/edit_invite_link_session.h
ui/boxes/peer_qr_box.cpp
ui/boxes/peer_qr_box.h
ui/chat/attach/attach_item_single_file_preview.cpp
ui/chat/attach/attach_item_single_file_preview.h
ui/chat/attach/attach_item_single_media_preview.cpp
@@ -1564,6 +1581,8 @@ PRIVATE
ui/chat/choose_send_as.h
ui/chat/choose_theme_controller.cpp
ui/chat/choose_theme_controller.h
ui/controls/emoji_button_factory.cpp
ui/controls/emoji_button_factory.h
ui/controls/location_picker.cpp
ui/controls/location_picker.h
ui/controls/silent_toggle.cpp
@@ -1589,6 +1608,8 @@ PRIVATE
ui/image/image_location_factory.h
ui/text/format_song_document_name.cpp
ui/text/format_song_document_name.h
ui/widgets/expandable_peer_list.cpp
ui/widgets/expandable_peer_list.h
ui/widgets/label_with_custom_emoji.cpp
ui/widgets/label_with_custom_emoji.h
ui/countryinput.cpp
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 KiB

After

Width:  |  Height:  |  Size: 935 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 234 KiB

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

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

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

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -12,6 +12,7 @@ body {
margin: 0;
background-color: var(--td-window-bg);
color: var(--td-window-fg);
zoom: var(--td-zoom-percentage);
}
html.custom_scroll ::-webkit-scrollbar {
File diff suppressed because it is too large Load Diff
@@ -31,6 +31,7 @@
<file alias="topic_icons/gray.svg">../../art/topic_icons/gray.svg</file>
<file alias="topic_icons/general.svg">../../art/topic_icons/general.svg</file>
<file alias="links_subscription.svg">../../icons/info/edit/links_subscription.svg</file>
<file alias="plane_white.svg">../../icons/plane_white.svg</file>
</qresource>
<qresource prefix="/icons">
<file alias="calls/hands.lottie">../../icons/calls/hands.lottie</file>
+1 -1
View File
@@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="5.4.1.0" />
Version="5.6.3.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
@@ -16,6 +16,8 @@
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
+4 -4
View File
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,4,1,0
PRODUCTVERSION 5,4,1,0
FILEVERSION 5,6,3,0
PRODUCTVERSION 5,6,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "5.4.1.0"
VALUE "FileVersion", "5.6.3.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "5.4.1.0"
VALUE "ProductVersion", "5.6.3.0"
END
END
BLOCK "VarFileInfo"
+4 -4
View File
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,4,1,0
PRODUCTVERSION 5,4,1,0
FILEVERSION 5,6,3,0
PRODUCTVERSION 5,6,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
VALUE "FileVersion", "5.4.1.0"
VALUE "FileVersion", "5.6.3.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "5.4.1.0"
VALUE "ProductVersion", "5.6.3.0"
END
END
BLOCK "VarFileInfo"
+4 -5
View File
@@ -13,9 +13,9 @@ bool OnlyAlphaKey = false;
const char *PublicKey = "\
-----BEGIN RSA PUBLIC KEY-----\n\
MIGJAoGBAMA4ViQrjkPZ9xj0lrer3r23JvxOnrtE8nI69XLGSr+sRERz9YnUptnU\n\
BZpkIfKaRcl6XzNJiN28cVwO1Ui5JSa814UAiDHzWUqCaXUiUEQ6NmNTneiGx2sQ\n\
+9PKKlb8mmr3BB9A45ZNwLT6G9AK3+qkZLHojeSA+m84/a6GP4svAgMBAAE=\n\
MIGJAoGBAOIENxe1sfT2t7b+HUMpnT6RnN/sCqY0JjK7/1A/59daDc6i/K4023jw\n\
Us+187Pa2VSaPh3kDywp9PfLDFgFiPTD9BsBvpaSK9p3zyG8k6an3+GbUTlUgmFv\n\
eI0pg7vmceIl0Lcy9nndfEx27UQId3Y3dQTMuwwFYGtjJAMHNNq5AgMBAAE=\n\
-----END RSA PUBLIC KEY-----\
";
@@ -29,8 +29,7 @@ w/CVnbwQOw0g5GBwwFV3r0uTTvy44xx8XXxk+Qknu4eBCsmrAFNnAgMBAAE=\n\
extern const char *PrivateKey;
extern const char *PrivateBetaKey;
#include "../../../../DesktopPrivate/packer_private.h" // RSA PRIVATE KEYS for update signing
#include "../../../../DesktopPrivate/alpha_private.h" // private key for alpha version file generation
#include "packer_private.h" // RSA PRIVATE KEYS for update signing
QString countAlphaVersionSignature(quint64 version);
+4 -4
View File
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#import <Cocoa/Cocoa.h>
#include <sys/xattr.h>
NSString *appName = @"Telegram.app";
NSString *appName = @"AyuGram.app";
NSString *appDir = nil;
NSString *workDir = nil;
@@ -56,7 +56,7 @@ void RemoveQuarantineAttribute(NSString *path) {
void RemoveQuarantineFromBundle(NSString *path) {
RemoveQuarantineAttribute(path);
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/MacOS/Telegram"]);
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/MacOS/AyuGram"]);
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/Helpers/crashpad_handler"]);
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/Frameworks/Updater"]);
}
@@ -163,9 +163,9 @@ int main(int argc, const char * argv[]) {
writeLog([@"Starting update files iteration, path: " stringByAppendingString: srcEnum]);
// Take the Updater (this currently running binary) from the place where it was placed by Telegram
// Take the Updater (this currently running binary) from the place where it was placed by AyuGram
// and copy it to the folder with the new version of the app (ready),
// so it won't be deleted when we will clear the "Telegram.app/Contents" folder.
// so it won't be deleted when we will clear the "AyuGram.app/Contents" folder.
NSString *oldVersionUpdaterPath = [appDirFull stringByAppendingString: @"/Contents/Frameworks/Updater" ];
NSString *newVersionUpdaterPath = [srcEnum stringByAppendingString:[[NSArray arrayWithObjects:@"/", appName, @"/Contents/Frameworks/Updater", nil] componentsJoinedByString:@""]];
writeLog([[NSArray arrayWithObjects: @"Copying Updater from old path ", oldVersionUpdaterPath, @" to new path ", newVersionUpdaterPath, nil] componentsJoinedByString:@""]);
+13 -1
View File
@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/url_auth_box.h"
#include "boxes/peers/choose_peer_box.h"
#include "lang/lang_keys.h"
#include "chat_helpers/bot_command.h"
#include "core/core_cloud_password.h"
#include "core/click_handler_types.h"
#include "data/data_changes.h"
@@ -38,6 +39,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QClipboard>
namespace Api {
namespace {
@@ -502,11 +506,19 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
bot->session().attachWebView().open({
.bot = bot,
.context = { .controller = controller },
.button = {.text = button->text, .url = button->data },
.button = { .text = button->text, .url = button->data },
.source = InlineBots::WebViewSourceButton{ .simple = true },
});
}
} break;
case ButtonType::CopyText: {
const auto text = QString::fromUtf8(button->data);
if (!text.isEmpty()) {
QGuiApplication::clipboard()->setText(text);
controller->showToast(tr::lng_text_copied(tr::now));
}
} break;
}
}
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/filter_icons.h"
#include "ui/vertical_list.h"
#include "ui/ui_utility.h"
#include "window/window_session_controller.h"
#include "styles/style_filter_icons.h"
#include "styles/style_layers.h"
@@ -231,12 +232,12 @@ void ImportInvite(
api->request(MTPchatlists_JoinChatlistInvite(
MTP_string(slug),
MTP_vector<MTPInputPeer>(std::move(inputs))
)).done(callback).fail(error).send();
)).done(callback).fail(error).handleFloodErrors().send();
} else {
api->request(MTPchatlists_JoinChatlistUpdates(
MTP_inputChatlistDialogFilter(MTP_int(filterId)),
MTP_vector<MTPInputPeer>(std::move(inputs))
)).done(callback).fail(error).send();
)).done(callback).fail(error).handleFloodErrors().send();
}
}
@@ -516,6 +517,8 @@ void ShowImportError(
} else {
window->showToast((error == u"INVITE_SLUG_EXPIRED"_q)
? tr::lng_group_invite_bad_link(tr::now)
: error.startsWith(u"FLOOD_WAIT_"_q)
? tr::lng_flood_error(tr::now)
: error);
}
}
+5 -3
View File
@@ -275,7 +275,6 @@ void ConfirmSubscriptionBox(
: 0;
state->api->request(
MTPpayments_SendStarsForm(
MTP_flags(0),
MTP_long(formId),
MTP_inputInvoiceChatInviteSubscription(MTP_string(hash)))
).done([=](const MTPpayments_PaymentResult &result) {
@@ -367,12 +366,15 @@ void CheckChatInvite(
result.match([=](const MTPDchatInvite &data) {
const auto isGroup = !data.is_broadcast();
const auto hasPricing = !!data.vsubscription_pricing();
if (hasPricing && !data.vsubscription_form_id()) {
const auto canRefulfill = data.is_can_refulfill_subscription();
if (hasPricing
&& !canRefulfill
&& !data.vsubscription_form_id()) {
strong->uiShow()->showToast(
tr::lng_confirm_phone_link_invalid(tr::now));
return;
}
const auto box = hasPricing
const auto box = (hasPricing && !canRefulfill)
? strong->show(Box(
ConfirmSubscriptionBox,
session,
@@ -264,14 +264,24 @@ ChatParticipant::ChatParticipant(
_rank = qs(data.vrank().value_or_empty());
_rights = ChatAdminRightsInfo(data.vadmin_rights());
_by = peerToUser(peerFromUser(data.vpromoted_by()));
_date = data.vdate().v;
}, [&](const MTPDchannelParticipantSelf &data) {
_type = Type::Member;
_date = data.vdate().v;
_by = peerToUser(peerFromUser(data.vinviter_id()));
if (data.vsubscription_until_date()) {
_subscriptionDate = data.vsubscription_until_date()->v;
}
}, [&](const MTPDchannelParticipant &data) {
_type = Type::Member;
_date = data.vdate().v;
if (data.vsubscription_until_date()) {
_subscriptionDate = data.vsubscription_until_date()->v;
}
}, [&](const MTPDchannelParticipantBanned &data) {
_restrictions = ChatRestrictionsInfo(data.vbanned_rights());
_by = peerToUser(peerFromUser(data.vkicked_by()));
_date = data.vdate().v;
_type = (_restrictions.flags & ChatRestriction::ViewMessages)
? Type::Banned
@@ -348,6 +358,24 @@ ChatAdminRightsInfo ChatParticipant::rights() const {
return _rights;
}
TimeId ChatParticipant::subscriptionDate() const {
return _subscriptionDate;
}
TimeId ChatParticipant::promotedSince() const {
return (_type == Type::Admin) ? _date : TimeId(0);
}
TimeId ChatParticipant::restrictedSince() const {
return (_type == Type::Restricted || _type == Type::Banned)
? _date
: TimeId(0);
}
TimeId ChatParticipant::memberSince() const {
return (_type == Type::Member) ? _date : TimeId(0);
}
ChatParticipant::Type ChatParticipant::type() const {
return _type;
}
@@ -60,6 +60,11 @@ public:
ChatRestrictionsInfo restrictions() const;
ChatAdminRightsInfo rights() const;
TimeId subscriptionDate() const;
TimeId promotedSince() const;
TimeId restrictedSince() const;
TimeId memberSince() const;
Type type() const;
QString rank() const;
@@ -73,6 +78,8 @@ private:
bool _canBeEdited = false;
QString _rank;
TimeId _subscriptionDate = 0;
TimeId _date = 0;
ChatRestrictionsInfo _restrictions;
ChatAdminRightsInfo _rights;
@@ -12,6 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/core_cloud_password.h"
#include "passport/passport_encryption.h"
#include "base/unixtime.h"
#include "base/call_delayed.h"
namespace Api {
namespace {
+75 -7
View File
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_updates.h"
#include "apiwrap.h"
#include "base/unixtime.h"
#include "data/components/credits.h"
#include "data/data_channel.h"
#include "data/data_document.h"
#include "data/data_peer.h"
@@ -69,16 +70,23 @@ constexpr auto kTransactionsLimit = 100;
}, [](const auto &) {
return PeerId(0);
}).value;
const auto stargift = tl.data().vstargift();
const auto incoming = (int64(tl.data().vstars().v) >= 0);
return Data::CreditsHistoryEntry{
.id = qs(tl.data().vid()),
.title = qs(tl.data().vtitle().value_or_empty()),
.description = qs(tl.data().vdescription().value_or_empty()),
.description = { qs(tl.data().vdescription().value_or_empty()) },
.date = base::unixtime::parse(tl.data().vdate().v),
.photoId = photo ? photo->id : 0,
.extended = std::move(extended),
.credits = tl.data().vstars().v,
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
.barePeerId = barePeerId,
.bareGiveawayMsgId = uint64(
tl.data().vgiveaway_post_id().value_or_empty()),
.bareGiftStickerId = (stargift
? owner->processDocument(stargift->data().vsticker())->id
: 0),
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
return Data::CreditsHistoryEntry::PeerType::Peer;
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
@@ -102,12 +110,16 @@ constexpr auto kTransactionsLimit = 100;
? base::unixtime::parse(tl.data().vtransaction_date()->v)
: QDateTime(),
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
.convertStars = int(stargift
? stargift->data().vconvert_stars().v
: 0),
.converted = stargift && incoming,
.reaction = tl.data().is_reaction(),
.refunded = tl.data().is_refund(),
.pending = tl.data().is_pending(),
.failed = tl.data().is_failed(),
.in = (int64(tl.data().vstars().v) >= 0),
.gift = tl.data().is_gift(),
.in = incoming,
.gift = tl.data().is_gift() || stargift.has_value(),
};
}
@@ -215,6 +227,10 @@ rpl::producer<rpl::no_value, QString> CreditsTopupOptions::request() {
};
}
Data::CreditTopupOptions CreditsTopupOptions::options() const {
return _options;
}
CreditsStatus::CreditsStatus(not_null<PeerData*> peer)
: _peer(peer)
, _api(&peer->session().api().instance()) {
@@ -233,6 +249,8 @@ void CreditsStatus::request(
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input
)).done([=](const TLResult &result) {
_requestId = 0;
const auto balance = result.data().vbalance().v;
_peer->session().credits().apply(_peer->id, balance);
if (const auto onstack = done) {
onstack(StatusFromTL(result, _peer));
}
@@ -294,10 +312,6 @@ void CreditsHistory::requestSubscriptions(
}).send();
}
Data::CreditTopupOptions CreditsTopupOptions::options() const {
return _options;
}
rpl::producer<not_null<PeerData*>> PremiumPeerBot(
not_null<Main::Session*> session) {
const auto username = session->appConfig().get<QString>(
@@ -385,4 +399,58 @@ Data::CreditsEarnStatistics CreditsEarnStatistics::data() const {
return _data;
}
CreditsGiveawayOptions::CreditsGiveawayOptions(not_null<PeerData*> peer)
: _peer(peer)
, _api(&peer->session().api().instance()) {
}
rpl::producer<rpl::no_value, QString> CreditsGiveawayOptions::request() {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
using TLOption = MTPStarsGiveawayOption;
const auto optionsFromTL = [=](const auto &options) {
return ranges::views::all(
options
) | ranges::views::transform([=](const auto &option) {
return Data::CreditsGiveawayOption{
.winners = ranges::views::all(
option.data().vwinners().v
) | ranges::views::transform([](const auto &winner) {
return Data::CreditsGiveawayOption::Winner{
.users = winner.data().vusers().v,
.perUserStars = winner.data().vper_user_stars().v,
.isDefault = winner.data().is_default(),
};
}) | ranges::to_vector,
.storeProduct = qs(
option.data().vstore_product().value_or_empty()),
.currency = qs(option.data().vcurrency()),
.amount = option.data().vamount().v,
.credits = option.data().vstars().v,
.yearlyBoosts = option.data().vyearly_boosts().v,
.isExtended = option.data().is_extended(),
.isDefault = option.data().is_default(),
};
}) | ranges::to_vector;
};
const auto fail = [=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
};
_api.request(MTPpayments_GetStarsGiveawayOptions(
)).done([=](const MTPVector<TLOption> &result) {
_options = optionsFromTL(result.v);
consumer.put_done();
}).fail(fail).send();
return lifetime;
};
}
Data::CreditsGiveawayOptions CreditsGiveawayOptions::options() const {
return _options;
}
} // namespace Api
+16
View File
@@ -36,6 +36,22 @@ private:
};
class CreditsGiveawayOptions final {
public:
CreditsGiveawayOptions(not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
[[nodiscard]] Data::CreditsGiveawayOptions options() const;
private:
const not_null<PeerData*> _peer;
Data::CreditsGiveawayOptions _options;
MTP::Sender _api;
};
class CreditsStatus final {
public:
CreditsStatus(not_null<PeerData*> peer);
@@ -115,6 +115,28 @@ rpl::producer<bool> GlobalPrivacy::newRequirePremium() const {
return _newRequirePremium.value();
}
void GlobalPrivacy::loadPaidReactionAnonymous() {
if (_paidReactionAnonymousLoaded) {
return;
}
_paidReactionAnonymousLoaded = true;
_api.request(MTPmessages_GetPaidReactionPrivacy(
)).done([=](const MTPUpdates &result) {
_session->api().applyUpdates(result);
}).send();
}
void GlobalPrivacy::updatePaidReactionAnonymous(bool value) {
_paidReactionAnonymous = value;
}
bool GlobalPrivacy::paidReactionAnonymousCurrent() const {
return _paidReactionAnonymous.current();
}
rpl::producer<bool> GlobalPrivacy::paidReactionAnonymous() const {
return _paidReactionAnonymous.value();
}
void GlobalPrivacy::updateArchiveAndMute(bool value) {
update(
@@ -49,6 +49,11 @@ public:
[[nodiscard]] bool newRequirePremiumCurrent() const;
[[nodiscard]] rpl::producer<bool> newRequirePremium() const;
void loadPaidReactionAnonymous();
void updatePaidReactionAnonymous(bool value);
[[nodiscard]] bool paidReactionAnonymousCurrent() const;
[[nodiscard]] rpl::producer<bool> paidReactionAnonymous() const;
private:
void apply(const MTPGlobalPrivacySettings &data);
@@ -67,7 +72,9 @@ private:
rpl::variable<bool> _showArchiveAndMute = false;
rpl::variable<bool> _hideReadTime = false;
rpl::variable<bool> _newRequirePremium = false;
rpl::variable<bool> _paidReactionAnonymous = false;
std::vector<Fn<void()>> _callbacks;
bool _paidReactionAnonymousLoaded = false;
};
+2 -1
View File
@@ -37,7 +37,8 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
MTP_int(dimensions.width()),
MTP_int(dimensions.height()),
MTPint(), // preload_prefix_size
MTPdouble())); // video_start_ts
MTPdouble(), // video_start_ts
MTPstring())); // video_codec
} else {
attributes.push_back(MTP_documentAttributeImageSize(
MTP_int(dimensions.width()),
+112 -4
View File
@@ -361,9 +361,10 @@ void Premium::resolveGiveawayInfo(
? GiveawayState::Refunded
: GiveawayState::Finished;
info.giftCode = qs(data.vgift_code_slug().value_or_empty());
info.activatedCount = data.vactivated_count().v;
info.activatedCount = data.vactivated_count().value_or_empty();
info.finishDate = data.vfinish_date().v;
info.startDate = data.vstart_date().v;
info.credits = data.vstars_prize().value_or_empty();
});
_giveawayInfoDone(std::move(info));
}).fail([=] {
@@ -508,7 +509,9 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::applyPrepaid(
_api.request(MTPpayments_LaunchPrepaidGiveaway(
_peer->input,
MTP_long(prepaidId),
Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
invoice.creditsAmount
? Payments::InvoiceCreditsGiveawayToTL(invoice)
: Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
consumer.put_done();
@@ -537,16 +540,34 @@ Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
const auto token = Token{ users, months };
const auto &store = _stores[token];
return Payments::InvoicePremiumGiftCode{
.randomId = randomId,
.currency = _optionsForOnePerson.currency,
.amount = store.amount,
.storeProduct = store.product,
.randomId = randomId,
.amount = store.amount,
.storeQuantity = store.quantity,
.users = token.users,
.months = token.months,
};
}
std::vector<GiftOptionData> PremiumGiftCodeOptions::optionsForPeer() const {
auto result = std::vector<GiftOptionData>();
if (!_optionsForOnePerson.currency.isEmpty()) {
const auto count = int(_optionsForOnePerson.months.size());
result.reserve(count);
for (auto i = 0; i != count; ++i) {
Assert(i < _optionsForOnePerson.totalCosts.size());
result.push_back({
.cost = _optionsForOnePerson.totalCosts[i],
.currency = _optionsForOnePerson.currency,
.months = _optionsForOnePerson.months[i],
});
}
}
return result;
}
Data::PremiumSubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
const auto it = _subscriptionOptions.find(amount);
if (it != end(_subscriptionOptions)) {
@@ -568,6 +589,41 @@ Data::PremiumSubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
}
}
auto PremiumGiftCodeOptions::requestStarGifts()
-> rpl::producer<rpl::no_value, QString> {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
_api.request(MTPpayments_GetStarGifts(
MTP_int(0)
)).done([=](const MTPpayments_StarGifts &result) {
result.match([&](const MTPDpayments_starGifts &data) {
_giftsHash = data.vhash().v;
const auto &list = data.vgifts().v;
const auto session = &_peer->session();
auto gifts = std::vector<StarGift>();
gifts.reserve(list.size());
for (const auto &gift : list) {
if (auto parsed = FromTL(session, gift)) {
gifts.push_back(std::move(*parsed));
}
}
_gifts = std::move(gifts);
}, [&](const MTPDpayments_starGiftsNotModified &) {
});
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return lifetime;
};
}
const std::vector<StarGift> &PremiumGiftCodeOptions::starGifts() const {
return _gifts;
}
int PremiumGiftCodeOptions::giveawayBoostsPerPremium() const {
constexpr auto kFallbackCount = 4;
return _peer->session().appConfig().get<int>(
@@ -702,4 +758,56 @@ rpl::producer<DocumentData*> RandomHelloStickerValue(
}) | rpl::take(1) | rpl::map(random));
}
std::optional<StarGift> FromTL(
not_null<Main::Session*> session,
const MTPstarGift &gift) {
const auto &data = gift.data();
const auto document = session->data().processDocument(
data.vsticker());
const auto remaining = data.vavailability_remains();
const auto total = data.vavailability_total();
if (!document->sticker()) {
return {};
}
return StarGift{
.id = uint64(data.vid().v),
.stars = int64(data.vstars().v),
.convertStars = int64(data.vconvert_stars().v),
.document = document,
.limitedLeft = remaining.value_or_empty(),
.limitedCount = total.value_or_empty(),
};
}
std::optional<UserStarGift> FromTL(
not_null<UserData*> to,
const MTPuserStarGift &gift) {
const auto session = &to->session();
const auto &data = gift.data();
auto parsed = FromTL(session, data.vgift());
if (!parsed) {
return {};
}
return UserStarGift{
.gift = std::move(*parsed),
.message = (data.vmessage()
? TextWithEntities{
.text = qs(data.vmessage()->data().vtext()),
.entities = Api::EntitiesFromMTP(
session,
data.vmessage()->data().ventities().v),
}
: TextWithEntities()),
.convertStars = int64(data.vconvert_stars().value_or_empty()),
.fromId = (data.vfrom_id()
? peerFromUser(data.vfrom_id()->v)
: PeerId()),
.messageId = data.vmsg_id().value_or_empty(),
.date = data.vdate().v,
.anonymous = data.is_name_hidden(),
.hidden = data.is_unsaved(),
.mine = to->isSelf(),
};
}
} // namespace Api
+43 -1
View File
@@ -57,6 +57,7 @@ struct GiveawayInfo {
TimeId tooEarlyDate = 0;
TimeId finishDate = 0;
TimeId startDate = 0;
uint64 credits = 0;
int winnersCount = 0;
int activatedCount = 0;
bool participating = false;
@@ -66,6 +67,33 @@ struct GiveawayInfo {
}
};
struct GiftOptionData {
int64 cost = 0;
QString currency;
int months = 0;
};
struct StarGift {
uint64 id = 0;
int64 stars = 0;
int64 convertStars = 0;
not_null<DocumentData*> document;
int limitedLeft = 0;
int limitedCount = 0;
};
struct UserStarGift {
StarGift gift;
TextWithEntities message;
int64 convertStars = 0;
PeerId fromId = 0;
MsgId messageId = 0;
TimeId date = 0;
bool anonymous = false;
bool hidden = false;
bool mine = false;
};
class Premium final {
public:
explicit Premium(not_null<ApiWrap*> api);
@@ -170,6 +198,7 @@ public:
PremiumGiftCodeOptions(not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
[[nodiscard]] std::vector<GiftOptionData> optionsForPeer() const;
[[nodiscard]] Data::PremiumSubscriptionOptions options(int amount);
[[nodiscard]] const std::vector<int> &availablePresets() const;
[[nodiscard]] int monthsFromPreset(int monthsIndex);
@@ -186,6 +215,9 @@ public:
[[nodiscard]] int giveawayPeriodMax() const;
[[nodiscard]] bool giveawayGiftsPurchaseAvailable() const;
[[nodiscard]] rpl::producer<rpl::no_value, QString> requestStarGifts();
[[nodiscard]] const std::vector<StarGift> &starGifts() const;
private:
struct Token final {
int users = 0;
@@ -205,7 +237,7 @@ private:
base::flat_map<Amount, PremiumSubscriptionOptions> _subscriptionOptions;
struct {
std::vector<int> months;
std::vector<float64> totalCosts;
std::vector<int64> totalCosts;
QString currency;
} _optionsForOnePerson;
@@ -213,6 +245,9 @@ private:
base::flat_map<Token, Store> _stores;
int32 _giftsHash = 0;
std::vector<StarGift> _gifts;
MTP::Sender _api;
};
@@ -241,4 +276,11 @@ enum class RequirePremiumState {
[[nodiscard]] rpl::producer<DocumentData*> RandomHelloStickerValue(
not_null<Main::Session*> session);
[[nodiscard]] std::optional<StarGift> FromTL(
not_null<Main::Session*> session,
const MTPstarGift &gift);
[[nodiscard]] std::optional<UserStarGift> FromTL(
not_null<UserData*> to,
const MTPuserStarGift &gift);
} // namespace Api
+93 -29
View File
@@ -10,10 +10,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_report.h"
#include "data/data_user.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/boxes/report_box.h"
#include "ui/boxes/report_box_graphics.h"
#include "ui/layers/show.h"
namespace Api {
@@ -40,15 +41,11 @@ MTPreportReason ReasonToTL(const Ui::ReportReason &reason) {
} // namespace
void SendReport(
std::shared_ptr<Ui::Show> show,
not_null<PeerData*> peer,
Ui::ReportReason reason,
const QString &comment,
std::variant<
v::null_t,
MessageIdsList,
not_null<PhotoData*>,
StoryId> data) {
std::shared_ptr<Ui::Show> show,
not_null<PeerData*> peer,
Ui::ReportReason reason,
const QString &comment,
std::variant<v::null_t, not_null<PhotoData*>> data) {
auto done = [=] {
show->showToast(tr::lng_report_thanks(tr::now));
};
@@ -58,18 +55,6 @@ void SendReport(
ReasonToTL(reason),
MTP_string(comment)
)).done(std::move(done)).send();
}, [&](const MessageIdsList &ids) {
auto apiIds = QVector<MTPint>();
apiIds.reserve(ids.size());
for (const auto &fullId : ids) {
apiIds.push_back(MTP_int(fullId.msg));
}
peer->session().api().request(MTPmessages_Report(
peer->input,
MTP_vector<MTPint>(apiIds),
ReasonToTL(reason),
MTP_string(comment)
)).done(std::move(done)).send();
}, [&](not_null<PhotoData*> photo) {
peer->session().api().request(MTPaccount_ReportProfilePhoto(
peer->input,
@@ -77,14 +62,93 @@ void SendReport(
ReasonToTL(reason),
MTP_string(comment)
)).done(std::move(done)).send();
}, [&](StoryId id) {
peer->session().api().request(MTPstories_Report(
peer->input,
MTP_vector<MTPint>(1, MTP_int(id)),
ReasonToTL(reason),
MTP_string(comment)
)).done(std::move(done)).send();
});
}
auto CreateReportMessagesOrStoriesCallback(
std::shared_ptr<Ui::Show> show,
not_null<PeerData*> peer)
-> Fn<void(Data::ReportInput, Fn<void(ReportResult)>)> {
using TLChoose = MTPDreportResultChooseOption;
using TLAddComment = MTPDreportResultAddComment;
using TLReported = MTPDreportResultReported;
using Result = ReportResult;
struct State final {
#ifdef _DEBUG
~State() {
qDebug() << "Messages or Stories Report ~State().";
}
#endif
mtpRequestId requestId = 0;
};
const auto state = std::make_shared<State>();
return [=](
Data::ReportInput reportInput,
Fn<void(Result)> done) {
auto apiIds = QVector<MTPint>();
apiIds.reserve(reportInput.ids.size() + reportInput.stories.size());
for (const auto &id : reportInput.ids) {
apiIds.push_back(MTP_int(id));
}
for (const auto &story : reportInput.stories) {
apiIds.push_back(MTP_int(story));
}
const auto received = [=](
const MTPReportResult &result,
mtpRequestId requestId) {
if (state->requestId != requestId) {
return;
}
state->requestId = 0;
done(result.match([&](const TLChoose &data) {
const auto t = qs(data.vtitle());
auto list = Result::Options();
list.reserve(data.voptions().v.size());
for (const auto &tl : data.voptions().v) {
list.emplace_back(Result::Option{
.id = tl.data().voption().v,
.text = qs(tl.data().vtext()),
});
}
return Result{ .options = std::move(list), .title = t };
}, [&](const TLAddComment &data) -> Result {
return {
.commentOption = ReportResult::CommentOption{
.optional = data.is_optional(),
.id = data.voption().v,
}
};
}, [&](const TLReported &data) -> Result {
return { .successful = true };
}));
};
const auto fail = [=](const MTP::Error &error) {
state->requestId = 0;
done({ .error = error.type() });
};
if (!reportInput.stories.empty()) {
state->requestId = peer->session().api().request(
MTPstories_Report(
peer->input,
MTP_vector<MTPint>(apiIds),
MTP_bytes(reportInput.optionId),
MTP_string(reportInput.comment))
).done(received).fail(fail).send();
} else {
state->requestId = peer->session().api().request(
MTPmessages_Report(
peer->input,
MTP_vector<MTPint>(apiIds),
MTP_bytes(reportInput.optionId),
MTP_string(reportInput.comment))
).done(received).fail(fail).send();
}
};
}
} // namespace Api
+30 -5
View File
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class HistoryItem;
class PeerData;
class PhotoData;
@@ -15,17 +16,41 @@ class Show;
enum class ReportReason;
} // namespace Ui
namespace Data {
struct ReportInput;
} // namespace Data
namespace Api {
struct ReportResult final {
using Id = QByteArray;
struct Option final {
Id id = 0;
QString text;
};
using Options = std::vector<Option>;
Options options;
QString title;
QString error;
QString comment;
struct CommentOption {
bool optional = false;
Id id = 0;
};
std::optional<CommentOption> commentOption;
bool successful = false;
};
void SendReport(
std::shared_ptr<Ui::Show> show,
not_null<PeerData*> peer,
Ui::ReportReason reason,
const QString &comment,
std::variant<
v::null_t,
MessageIdsList,
not_null<PhotoData*>,
StoryId> data);
std::variant<v::null_t, not_null<PhotoData*>> data);
[[nodiscard]] auto CreateReportMessagesOrStoriesCallback(
std::shared_ptr<Ui::Show> show,
not_null<PeerData*> peer)
-> Fn<void(Data::ReportInput, Fn<void(ReportResult)>)>;
} // namespace Api
+6 -3
View File
@@ -44,7 +44,10 @@ void InnerFillMessagePostFlags(
if (ShouldSendSilent(peer, options)) {
flags |= MessageFlag::Silent;
}
if (!peer->amAnonymous()) {
if (!peer->amAnonymous()
|| (!peer->isBroadcast()
&& options.sendAs
&& options.sendAs != peer)) {
flags |= MessageFlag::HasFromId;
}
const auto channel = peer->asBroadcast();
@@ -544,7 +547,7 @@ void SendConfirmedFile(
MTP_flags(Flag::f_document
| (file->spoiler ? Flag::f_spoiler : Flag())),
file->document,
MTPDocument(), // alt_document
MTPVector<MTPDocument>(), // alt_documents
MTPint());
} else if (file->type == SendMediaType::Audio) {
const auto ttlSeconds = file->to.options.ttlSeconds;
@@ -569,7 +572,7 @@ void SendConfirmedFile(
| (isVoice ? Flag::f_voice : Flag())
| (ttlSeconds ? Flag::f_ttl_seconds : Flag())),
file->document,
MTPDocument(), // alt_document
MTPVector<MTPDocument>(), // alt_documents
MTP_int(ttlSeconds));
} else {
Unexpected("Type in sendFilesConfirmed.");
+29 -18
View File
@@ -571,13 +571,22 @@ rpl::producer<rpl::no_value, QString> Boosts::request() {
_boostStatus.prepaidGiveaway = ranges::views::all(
data.vprepaid_giveaways()->v
) | ranges::views::transform([](const MTPPrepaidGiveaway &r) {
return Data::BoostPrepaidGiveaway{
.months = r.data().vmonths().v,
.id = r.data().vid().v,
.quantity = r.data().vquantity().v,
.date = QDateTime::fromSecsSinceEpoch(
r.data().vdate().v),
};
return r.match([&](const MTPDprepaidGiveaway &data) {
return Data::BoostPrepaidGiveaway{
.date = base::unixtime::parse(data.vdate().v),
.id = data.vid().v,
.months = data.vmonths().v,
.quantity = data.vquantity().v,
};
}, [&](const MTPDprepaidStarsGiveaway &data) {
return Data::BoostPrepaidGiveaway{
.date = base::unixtime::parse(data.vdate().v),
.id = data.vid().v,
.credits = data.vstars().v,
.quantity = data.vquantity().v,
.boosts = data.vboosts().v,
};
});
}) | ranges::to_vector;
}
@@ -635,19 +644,21 @@ void Boosts::requestBoosts(
}
: Data::GiftCodeLink();
list.push_back({
data.is_gift(),
data.is_giveaway(),
data.is_unclaimed(),
qs(data.vid()),
data.vuser_id().value_or_empty(),
data.vgiveaway_msg_id()
.id = qs(data.vid()),
.userId = UserId(data.vuser_id().value_or_empty()),
.giveawayMessage = data.vgiveaway_msg_id()
? FullMsgId{ _peer->id, data.vgiveaway_msg_id()->v }
: FullMsgId(),
QDateTime::fromSecsSinceEpoch(data.vdate().v),
QDateTime::fromSecsSinceEpoch(data.vexpires().v),
(data.vexpires().v - data.vdate().v) / kMonthsDivider,
std::move(giftCodeLink),
data.vmultiplier().value_or_empty(),
.date = base::unixtime::parse(data.vdate().v),
.expiresAt = base::unixtime::parse(data.vexpires().v),
.expiresAfterMonths = ((data.vexpires().v - data.vdate().v)
/ kMonthsDivider),
.giftCodeLink = std::move(giftCodeLink),
.multiplier = data.vmultiplier().value_or_empty(),
.credits = data.vstars().value_or_empty(),
.isGift = data.is_gift(),
.isGiveaway = data.is_giveaway(),
.isUnclaimed = data.is_unclaimed(),
});
}
done(Data::BoostsListSlice{
+40 -10
View File
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_authorizations.h"
#include "api/api_user_names.h"
#include "api/api_chat_participants.h"
#include "api/api_global_privacy.h"
#include "api/api_ringtones.h"
#include "api/api_text_entities.h"
#include "api/api_user_privacy.h"
@@ -420,13 +421,12 @@ void Updates::channelDifferenceDone(
"{ good - after not final channelDifference was received }%1"
).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
getChannelDifference(channel);
} else if (ranges::contains(
_activeChats,
channel,
[](const auto &pair) { return pair.second.peer; })) {
channel->ptsWaitingForShortPoll(timeout
} else if (inActiveChats(channel)) {
channel->ptsSetWaitingForShortPoll(timeout
? (timeout * crl::time(1000))
: kWaitForChannelGetDifference);
} else {
channel->ptsSetWaitingForShortPoll(-1);
}
}
@@ -658,6 +658,7 @@ void Updates::getDifferenceAfterFail() {
wait = wait ? std::min(wait, i->second - now) : (i->second - now);
++i;
} else {
i->first->ptsSetRequesting(false);
getChannelDifference(i->first, ChannelDifferenceRequest::AfterFail);
i = _whenGetDiffAfterFail.erase(i);
}
@@ -706,7 +707,9 @@ void Updates::getChannelDifference(
_whenGetDiffByPts.remove(channel);
}
if (!channel->ptsInited() || channel->ptsRequesting()) return;
if (!channel->ptsInited() || channel->ptsRequesting()) {
return;
}
if (from != ChannelDifferenceRequest::AfterFail) {
_whenGetDiffAfterFail.remove(channel);
@@ -743,16 +746,32 @@ void Updates::addActiveChat(rpl::producer<PeerData*> chat) {
std::move(
chat
) | rpl::start_with_next_done([=](PeerData *peer) {
_activeChats[key].peer = peer;
if (const auto channel = peer ? peer->asChannel() : nullptr) {
channel->ptsWaitingForShortPoll(
kWaitForChannelGetDifference);
auto &active = _activeChats[key];
const auto was = active.peer;
if (was != peer) {
active.peer = peer;
if (const auto channel = was ? was->asChannel() : nullptr) {
if (!inActiveChats(channel)) {
channel->ptsSetWaitingForShortPoll(-1);
}
}
if (const auto channel = peer ? peer->asChannel() : nullptr) {
channel->ptsSetWaitingForShortPoll(
kWaitForChannelGetDifference);
}
}
}, [=] {
_activeChats.erase(key);
}, _activeChats[key].lifetime);
}
bool Updates::inActiveChats(not_null<PeerData*> peer) const {
return ranges::contains(
_activeChats,
peer.get(),
[](const auto &pair) { return pair.second.peer; });
}
void Updates::requestChannelRangeDifference(not_null<History*> history) {
Expects(history->peer->isChannel());
@@ -1561,6 +1580,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
}
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping new channel message because getting the difference."));
return;
}
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -1653,6 +1673,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping channel message edit because getting the difference."));
return;
} else {
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -1668,6 +1689,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping pinned channel messages because getting the difference."));
return;
} else {
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -1782,6 +1804,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping delete channel messages because getting the difference."));
return;
}
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -1845,6 +1868,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
auto channel = session().data().channelLoaded(d.vchannel_id());
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping channel web page update because getting the difference."));
return;
} else {
channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
@@ -2630,6 +2654,12 @@ void Updates::feedUpdate(const MTPUpdate &update) {
_session->credits().apply(data);
} break;
case mtpc_updatePaidReactionPrivacy: {
const auto &data = update.c_updatePaidReactionPrivacy();
_session->api().globalPrivacy().updatePaidReactionAnonymous(
mtpIsTrue(data.vprivate()));
} break;
}
}
+1
View File
@@ -63,6 +63,7 @@ public:
void requestChannelRangeDifference(not_null<History*> history);
void addActiveChat(rpl::producer<PeerData*> chat);
[[nodiscard]] bool inActiveChats(not_null<PeerData*> peer) const;
private:
enum class ChannelDifferenceRequest {
+7 -4
View File
@@ -214,7 +214,10 @@ struct State {
[[nodiscard]] QImage GenerateUserpic(Userpic &userpic, int size) {
size *= style::DevicePixelRatio();
auto result = userpic.peer->generateUserpicImage(userpic.view, size);
auto result = PeerData::GenerateUserpicImage(
userpic.peer,
userpic.view,
size);
result.setDevicePixelRatio(style::DevicePixelRatio());
return result;
}
@@ -653,12 +656,12 @@ QString FormatReadDate(TimeId date, const QDateTime &now) {
return tr::lng_mediaview_today(
tr::now,
lt_time,
QLocale().toString(parsed.time(), QLocale::ShortFormat));
QLocale().toString(parsed.time(), "HH:mm:ss"));
} else if (readDate.addDays(1) == nowDate) {
return tr::lng_mediaview_yesterday(
tr::now,
lt_time,
QLocale().toString(parsed.time(), QLocale::ShortFormat));
QLocale().toString(parsed.time(), "HH:mm:ss"));
}
return tr::lng_mediaview_date_time(
tr::now,
@@ -670,7 +673,7 @@ QString FormatReadDate(TimeId date, const QDateTime &now) {
lt_day,
QString::number(readDate.day())),
lt_time,
QLocale().toString(parsed.time(), QLocale::ShortFormat));
QLocale().toString(parsed.time(), "HH:mm:ss"));
}
bool WhoReadExists(not_null<HistoryItem*> item) {
+17 -15
View File
@@ -2072,7 +2072,7 @@ void ApiWrap::deleteHistory(
}
if (const auto channel = peer->asChannel()) {
if (!justClear && !revoke) {
channel->ptsWaitingForShortPoll(-1);
channel->ptsSetWaitingForShortPoll(-1);
leaveChannel(channel);
} else {
if (const auto migrated = peer->migrateFrom()) {
@@ -3661,9 +3661,7 @@ void ApiWrap::sendUploadedPhoto(
Api::RemoteFileInfo info,
Api::SendOptions options) {
if (const auto item = _session->data().message(localId)) {
// AyuGram useScheduledMessages
const auto settings = &AyuSettings::getInstance();
if (settings->useScheduledMessages && !options.scheduled) {
if (AyuSettings::isUseScheduledMessages() && !options.scheduled) {
auto current = base::unixtime::now();
options.scheduled = current + 12;
}
@@ -3686,9 +3684,7 @@ void ApiWrap::sendUploadedDocument(
return;
}
// AyuGram useScheduledMessages
const auto settings = &AyuSettings::getInstance();
if (settings->useScheduledMessages && !options.scheduled) {
if (AyuSettings::isUseScheduledMessages() && !options.scheduled) {
auto current = base::unixtime::now();
options.scheduled = current + 12;
}
@@ -3978,6 +3974,12 @@ void ApiWrap::sendBotStart(
if (chat) {
message.textWithTags.text += '@' + bot->username();
}
if (AyuSettings::isUseScheduledMessages()) {
auto current = base::unixtime::now();
message.action.options.scheduled = current + 12;
}
sendMessage(std::move(message));
return;
}
@@ -4192,9 +4194,7 @@ void ApiWrap::sendMediaWithRandomId(
Api::SendOptions options,
uint64 randomId,
Fn<void(bool)> done) {
// AyuGram useScheduledMessages
const auto settings = &AyuSettings::getInstance();
if (settings->useScheduledMessages && !options.scheduled) {
if (AyuSettings::isUseScheduledMessages() && !options.scheduled) {
auto current = base::unixtime::now();
options.scheduled = current + 12;
}
@@ -4237,8 +4237,10 @@ void ApiWrap::sendMediaWithRandomId(
Data::Histories::ReplyToPlaceholder(),
(options.price
? MTPInputMedia(MTP_inputMediaPaidMedia(
MTP_flags(0),
MTP_long(options.price),
MTP_vector<MTPInputMedia>(1, media)))
MTP_vector<MTPInputMedia>(1, media),
MTPstring()))
: media),
MTP_string(caption.text),
MTP_long(randomId),
@@ -4311,8 +4313,10 @@ void ApiWrap::sendMultiPaidMedia(
peer->input,
Data::Histories::ReplyToPlaceholder(),
MTP_inputMediaPaidMedia(
MTP_flags(0),
MTP_long(options.price),
MTP_vector<MTPInputMedia>(std::move(medias))),
MTP_vector<MTPInputMedia>(std::move(medias)),
MTPstring()),
MTP_string(caption.text),
MTP_long(randomId),
MTPReplyMarkup(),
@@ -4404,9 +4408,7 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
return;
}
// AyuGram useScheduledMessages
const auto settings = &AyuSettings::getInstance();
if (settings->useScheduledMessages && !album->options.scheduled) {
if (AyuSettings::isUseScheduledMessages() && !album->options.scheduled) {
auto current = base::unixtime::now();
album->options.scheduled = current + 12;
}
+6 -6
View File
@@ -17,14 +17,14 @@
namespace AyuInfra {
void initLang() {
QString langPackBaseId = Lang::GetInstance().baseId();
QString langPackId = Lang::GetInstance().id();
if (langPackId.isEmpty()) {
LOG(("Lang ID not found! Re-use old language pack..."));
QString id = Lang::GetInstance().id();
QString baseId = Lang::GetInstance().baseId();
if (id.isEmpty()) {
LOG(("Language ID not found!"));
return;
}
CustomLangPack::initInstance();
CustomLangPack::currentInstance()->fetchCustomLangPack(langPackId, langPackBaseId);
AyuLanguage::init();
AyuLanguage::currentInstance()->fetchLanguage(id, baseId);
}
void initFonts() {
+42 -57
View File
@@ -20,49 +20,45 @@ std::map<QString, QString> langMapping = {
{"zh-hant-raw", "zh-hant"},
};
CustomLangPack *CustomLangPack::instance = nullptr;
AyuLanguage *AyuLanguage::instance = nullptr;
CustomLangPack::CustomLangPack() = default;
AyuLanguage::AyuLanguage() = default;
void CustomLangPack::initInstance() {
if (!instance) instance = new CustomLangPack;
void AyuLanguage::init() {
if (!instance) instance = new AyuLanguage;
}
CustomLangPack *CustomLangPack::currentInstance() {
AyuLanguage *AyuLanguage::currentInstance() {
return instance;
}
void CustomLangPack::fetchCustomLangPack(const QString &langPackId, const QString &langPackBaseId) {
LOG(("Current Language pack ID: %1, Base ID: %2").arg(langPackId, langPackBaseId));
void AyuLanguage::fetchLanguage(const QString &id, const QString &baseId) {
auto finalLangPackId = langMapping.contains(id) ? langMapping[id] : id;
auto finalLangPackId = langMapping.contains(langPackId) ? langMapping[langPackId] : langPackId;
const auto proxy = Core::App().settings().proxy().isEnabled()
? Core::App().settings().proxy().selected()
: MTP::ProxyData();
if (proxy.type == MTP::ProxyData::Type::Socks5 || proxy.type == MTP::ProxyData::Type::Http) {
QNetworkProxy LocaleProxy = ToNetworkProxy(ToDirectIpProxy(proxy));
networkManager.setProxy(LocaleProxy);
if (Core::App().settings().proxy().isEnabled()) {
const auto proxy = Core::App().settings().proxy().selected();
if (proxy.type == MTP::ProxyData::Type::Socks5 || proxy.type == MTP::ProxyData::Type::Http) {
const auto networkProxy = ToNetworkProxy(ToDirectIpProxy(Core::App().settings().proxy().selected()));
networkManager.setProxy(networkProxy);
}
}
// using `jsdelivr` since China (...and maybe other?) users have some problems with GitHub
// https://crowdin.com/project/ayugram/discussions/6
QUrl url;
if (!finalLangPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
if (!finalLangPackId.isEmpty() && !baseId.isEmpty() && !needFallback) {
url.setUrl(qsl("https://cdn.jsdelivr.net/gh/AyuGram/Languages@l10n_main/values/langs/%1/Shared.json").arg(
finalLangPackId));
} else {
url.setUrl(qsl("https://cdn.jsdelivr.net/gh/AyuGram/Languages@l10n_main/values/langs/%1/Shared.json").arg(
needFallback ? langPackBaseId : finalLangPackId));
needFallback ? baseId : finalLangPackId));
}
_chkReply = networkManager.get(QNetworkRequest(url));
connect(_chkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(fetchError(QNetworkReply::NetworkError)));
connect(_chkReply, SIGNAL(finished()), this, SLOT(fetchFinished()));
LOG(("Fetching %1 lang pack...").arg(
needFallback ? (langPackBaseId.isEmpty() ? finalLangPackId : langPackBaseId) : finalLangPackId));
}
void CustomLangPack::fetchFinished() {
void AyuLanguage::fetchFinished() {
if (!_chkReply) return;
QString langPackBaseId = Lang::GetInstance().baseId();
@@ -70,72 +66,61 @@ void CustomLangPack::fetchFinished() {
auto statusCode = _chkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 404 && !langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
LOG(("AyuGram Language pack not found! Fallback to main language: %1...").arg(langPackBaseId));
LOG(("AyuGram Language not found! Fallback to main language: %1...").arg(langPackBaseId));
needFallback = true;
_chkReply->disconnect();
fetchCustomLangPack("", langPackBaseId);
fetchLanguage("", langPackBaseId);
} else {
QByteArray result = _chkReply->readAll().trimmed();
const auto result = _chkReply->readAll().trimmed();
QJsonParseError error{};
QJsonDocument str = QJsonDocument::fromJson(result, &error);
const auto doc = QJsonDocument::fromJson(result, &error);
if (error.error == QJsonParseError::NoError) {
parseLangFile(str);
applyLanguageJson(doc);
} else {
LOG(("Incorrect JSON File. Fallback to default language: English..."));
loadDefaultLangFile();
LOG(("Incorrect language JSON File."));
}
_chkReply = nullptr;
}
}
void CustomLangPack::fetchError(QNetworkReply::NetworkError e) {
void AyuLanguage::fetchError(QNetworkReply::NetworkError e) {
LOG(("Network error: %1").arg(e));
if (e == QNetworkReply::NetworkError::ContentNotFoundError) {
QString langPackBaseId = Lang::GetInstance().baseId();
QString langPackId = Lang::GetInstance().id();
const auto baseId = Lang::GetInstance().baseId();
const auto id = Lang::GetInstance().id();
if (!langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
LOG(("AyuGram Language pack not found! Fallback to main language: %1...").arg(langPackBaseId));
if (!id.isEmpty() && !baseId.isEmpty() && !needFallback) {
LOG(("AyuGram Language not found! Fallback to main language: %1...").arg(baseId));
needFallback = true;
_chkReply->disconnect();
fetchCustomLangPack("", langPackBaseId);
fetchLanguage("", baseId);
} else {
LOG(("AyuGram Language pack not found! Fallback to default language: English..."));
loadDefaultLangFile();
LOG(("AyuGram Language not found!"));
_chkReply = nullptr;
}
}
}
void CustomLangPack::loadDefaultLangFile() {
QFile file(":/localization/en.json");
if (file.open(QIODevice::ReadOnly)) {
QJsonDocument str = QJsonDocument::fromJson(file.readAll());
QJsonObject json = str.object();
for (const QString &key : json.keys()) {
Lang::GetInstance().applyValue(key.toUtf8(), json.value(key).toString().toUtf8());
}
Lang::GetInstance().updatePluralRules();
file.close();
}
}
void CustomLangPack::parseLangFile(QJsonDocument str) {
QJsonObject json = str.object();
void AyuLanguage::applyLanguageJson(QJsonDocument doc) {
const auto json = doc.object();
for (const QString &brokenKey : json.keys()) {
auto key = qsl("ayu_") + brokenKey;
auto val = json.value(brokenKey).toString().replace(qsl("&amp;"), qsl("&")).toUtf8();
const auto val = json.value(brokenKey).toString().replace(qsl("&amp;"), qsl("&")).toUtf8();
if (key.endsWith("_zero") || key.endsWith("_two") || key.endsWith("_few") || key.endsWith("_many")) {
continue;
}
if (key.endsWith("_one")) {
key = key.replace("_one", "#one");
} else if (key.endsWith("_other")) {
key = key.replace("_other", "#other");
}
Lang::GetInstance().resetValue(key.toUtf8());
Lang::GetInstance().applyValue(key.toUtf8(), val);
if (key.contains("#other")) {
Lang::GetInstance().resetValue(key.toUtf8().replace("#other", "#few"));
Lang::GetInstance().resetValue(key.toUtf8().replace("#other", "#few"));
Lang::GetInstance().applyValue(key.toUtf8().replace("#other", "#few"), val);
Lang::GetInstance().applyValue(key.toUtf8().replace("#other", "#many"), val);
}
}
Lang::GetInstance().updatePluralRules();
}
+9 -10
View File
@@ -9,27 +9,26 @@
#include <QtNetwork/QNetworkReply>
#include <QtXml/QDomDocument>
class CustomLangPack : public QObject
class AyuLanguage : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(CustomLangPack)
Q_DISABLE_COPY(AyuLanguage)
public:
static CustomLangPack *currentInstance();
static void initInstance();
static CustomLangPack *instance;
static AyuLanguage *currentInstance();
static void init();
static AyuLanguage *instance;
void fetchCustomLangPack(const QString &langPackId, const QString &langPackBaseId);
void loadDefaultLangFile();
void parseLangFile(QJsonDocument str);
void fetchLanguage(const QString &id, const QString &baseId);
void applyLanguageJson(QJsonDocument doc);
public Q_SLOTS:
void fetchFinished();
void fetchError(QNetworkReply::NetworkError e);
private:
CustomLangPack();
~CustomLangPack() override = default;
AyuLanguage();
~AyuLanguage() override = default;
QNetworkAccessManager networkManager;
QNetworkReply *_chkReply = nullptr;
+70 -1
View File
@@ -42,6 +42,7 @@ rpl::variable<QString> editedMarkReactive;
rpl::variable<int> showPeerIdReactive;
rpl::variable<bool> hideFromBlockedReactive;
rpl::event_stream<> historyUpdateReactive;
rpl::lifetime lifetime = rpl::lifetime();
@@ -203,11 +204,14 @@ AyuGramSettings::AyuGramSettings() {
markReadAfterAction = true;
useScheduledMessages = false;
sendWithoutSound = false;
// ~ Message edits & deletion history
saveDeletedMessages = true;
saveMessagesHistory = true;
saveForBots = false;
// ~ Message filters
hideFromBlocked = false;
@@ -248,6 +252,15 @@ AyuGramSettings::AyuGramSettings() {
showUserMessagesInContextMenu = 2;
showMessageDetailsInContextMenu = 2;
showAttachButtonInMessageField = true;
showCommandsButtonInMessageField = true;
showEmojiButtonInMessageField = true;
showMicrophoneButtonInMessageField = true;
showAutoDeleteButtonInMessageField = true;
showAttachPopup = true;
showEmojiPopup = true;
showLReadToggleInDrawer = false;
showSReadToggleInDrawer = true;
showGhostToggleInDrawer = true;
@@ -331,6 +344,10 @@ void AyuGramSettings::set_useScheduledMessages(bool val) {
useScheduledMessages = val;
}
void AyuGramSettings::set_sendWithoutSound(bool val) {
sendWithoutSound = val;
}
void AyuGramSettings::set_saveDeletedMessages(bool val) {
saveDeletedMessages = val;
}
@@ -339,6 +356,10 @@ void AyuGramSettings::set_saveMessagesHistory(bool val) {
saveMessagesHistory = val;
}
void AyuGramSettings::set_saveForBots(bool val) {
saveForBots = val;
}
void AyuGramSettings::set_hideFromBlocked(bool val) {
hideFromBlocked = val;
hideFromBlockedReactive = val;
@@ -426,6 +447,41 @@ void AyuGramSettings::set_showMessageDetailsInContextMenu(int val) {
showMessageDetailsInContextMenu = val;
}
void AyuGramSettings::set_showAttachButtonInMessageField(bool val) {
showAttachButtonInMessageField = val;
triggerHistoryUpdate();
}
void AyuGramSettings::set_showCommandsButtonInMessageField(bool val) {
showCommandsButtonInMessageField = val;
triggerHistoryUpdate();
}
void AyuGramSettings::set_showEmojiButtonInMessageField(bool val) {
showEmojiButtonInMessageField = val;
triggerHistoryUpdate();
}
void AyuGramSettings::set_showMicrophoneButtonInMessageField(bool val) {
showMicrophoneButtonInMessageField = val;
triggerHistoryUpdate();
}
void AyuGramSettings::set_showAutoDeleteButtonInMessageField(bool val) {
showAutoDeleteButtonInMessageField = val;
triggerHistoryUpdate();
}
void AyuGramSettings::set_showAttachPopup(bool val) {
showAttachPopup = val;
triggerHistoryUpdate();
}
void AyuGramSettings::set_showEmojiPopup(bool val) {
showEmojiPopup = val;
triggerHistoryUpdate();
}
void AyuGramSettings::set_showLReadToggleInDrawer(bool val) {
showLReadToggleInDrawer = val;
}
@@ -495,7 +551,12 @@ void AyuGramSettings::set_voiceConfirmation(bool val) {
voiceConfirmation = val;
}
bool get_ghostModeEnabled() {
bool isUseScheduledMessages() {
const auto settings = &getInstance();
return isGhostModeActive() && settings->useScheduledMessages;
}
bool isGhostModeActive() {
return ghostModeEnabled.current();
}
@@ -519,4 +580,12 @@ rpl::producer<bool> get_hideFromBlockedReactive() {
return hideFromBlockedReactive.value();
}
void triggerHistoryUpdate() {
historyUpdateReactive.fire({});
}
rpl::producer<> get_historyUpdateReactive() {
return historyUpdateReactive.events();
}
}
+39 -1
View File
@@ -25,10 +25,13 @@ public:
bool markReadAfterAction;
bool useScheduledMessages;
bool sendWithoutSound;
bool saveDeletedMessages;
bool saveMessagesHistory;
bool saveForBots;
bool hideFromBlocked;
bool disableAds;
@@ -56,6 +59,15 @@ public:
int showUserMessagesInContextMenu;
int showMessageDetailsInContextMenu;
bool showAttachButtonInMessageField;
bool showCommandsButtonInMessageField;
bool showEmojiButtonInMessageField;
bool showMicrophoneButtonInMessageField;
bool showAutoDeleteButtonInMessageField;
bool showAttachPopup;
bool showEmojiPopup;
bool showLReadToggleInDrawer;
bool showSReadToggleInDrawer;
bool showGhostToggleInDrawer;
@@ -90,10 +102,13 @@ public:
void set_markReadAfterAction(bool val);
void set_useScheduledMessages(bool val);
void set_sendWithoutSound(bool val);
void set_saveDeletedMessages(bool val);
void set_saveMessagesHistory(bool val);
void set_saveForBots(bool val);
void set_hideFromBlocked(bool val);
void set_disableAds(bool val);
@@ -121,6 +136,15 @@ public:
void set_showUserMessagesInContextMenu(int val);
void set_showMessageDetailsInContextMenu(int val);
void set_showAttachButtonInMessageField(bool val);
void set_showCommandsButtonInMessageField(bool val);
void set_showEmojiButtonInMessageField(bool val);
void set_showMicrophoneButtonInMessageField(bool val);
void set_showAutoDeleteButtonInMessageField(bool val);
void set_showAttachPopup(bool val);
void set_showEmojiPopup(bool val);
void set_showLReadToggleInDrawer(bool val);
void set_showSReadToggleInDrawer(bool val);
void set_showGhostToggleInDrawer(bool val);
@@ -155,8 +179,10 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
sendOfflinePacketAfterOnline,
markReadAfterAction,
useScheduledMessages,
sendWithoutSound,
saveDeletedMessages,
saveMessagesHistory,
saveForBots,
hideFromBlocked,
disableAds,
disableStories,
@@ -178,6 +204,13 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
showHideMessageInContextMenu,
showUserMessagesInContextMenu,
showMessageDetailsInContextMenu,
showAttachButtonInMessageField,
showCommandsButtonInMessageField,
showEmojiButtonInMessageField,
showMicrophoneButtonInMessageField,
showAutoDeleteButtonInMessageField,
showAttachPopup,
showEmojiPopup,
showLReadToggleInDrawer,
showSReadToggleInDrawer,
showGhostToggleInDrawer,
@@ -207,9 +240,14 @@ rpl::producer<QString> get_editedMarkReactive();
rpl::producer<int> get_showPeerIdReactive();
bool get_ghostModeEnabled();
bool isGhostModeActive();
bool isUseScheduledMessages();
rpl::producer<bool> get_ghostModeEnabledReactive();
rpl::producer<bool> get_hideFromBlockedReactive();
void triggerHistoryUpdate();
rpl::producer<> get_historyUpdateReactive();
}
+62 -18
View File
@@ -16,7 +16,7 @@
using namespace sqlite_orm;
auto storage = make_storage(
"./tdata/ayudata.db",
make_table(
make_table<DeletedMessage>(
"DeletedMessage",
make_column("fakeId", &DeletedMessage::fakeId, primary_key().autoincrement()),
make_column("userId", &DeletedMessage::userId),
@@ -52,7 +52,7 @@ auto storage = make_storage(
make_column("documentAttributesSerialized", &DeletedMessage::documentAttributesSerialized),
make_column("mimeType", &DeletedMessage::mimeType)
),
make_table(
make_table<EditedMessage>(
"EditedMessage",
make_column("fakeId", &EditedMessage::fakeId, primary_key().autoincrement()),
make_column("userId", &EditedMessage::userId),
@@ -88,7 +88,7 @@ auto storage = make_storage(
make_column("documentAttributesSerialized", &EditedMessage::documentAttributesSerialized),
make_column("mimeType", &EditedMessage::mimeType)
),
make_table(
make_table<DeletedDialog>(
"DeletedDialog",
make_column("fakeId", &DeletedDialog::fakeId, primary_key().autoincrement()),
make_column("userId", &DeletedDialog::userId),
@@ -100,21 +100,22 @@ auto storage = make_storage(
make_column("flags", &DeletedDialog::flags),
make_column("entityCreateDate", &DeletedDialog::entityCreateDate)
),
make_table(
make_table<RegexFilter>(
"RegexFilter",
make_column("id", &RegexFilter::id),
make_column("text", &RegexFilter::text),
make_column("enabled", &RegexFilter::enabled),
make_column("reversed", &RegexFilter::reversed),
make_column("caseInsensitive", &RegexFilter::caseInsensitive),
make_column("dialogId", &RegexFilter::dialogId)
),
make_table(
make_table<RegexFilterGlobalExclusion>(
"RegexFilterGlobalExclusion",
make_column("fakeId", &RegexFilterGlobalExclusion::fakeId, primary_key().autoincrement()),
make_column("dialogId", &RegexFilterGlobalExclusion::dialogId),
make_column("filterId", &RegexFilterGlobalExclusion::filterId)
),
make_table(
make_table<SpyMessageRead>(
"SpyMessageRead",
make_column("fakeId", &SpyMessageRead::fakeId, primary_key().autoincrement()),
make_column("userId", &SpyMessageRead::userId),
@@ -122,7 +123,7 @@ auto storage = make_storage(
make_column("messageId", &SpyMessageRead::messageId),
make_column("entityCreateDate", &SpyMessageRead::entityCreateDate)
),
make_table(
make_table<SpyMessageContentsRead>(
"SpyMessageContentsRead",
make_column("fakeId", &SpyMessageContentsRead::fakeId, primary_key().autoincrement()),
make_column("userId", &SpyMessageContentsRead::userId),
@@ -135,7 +136,7 @@ auto storage = make_storage(
namespace AyuDatabase {
void moveCurrentDatabase() {
auto time = base::unixtime::now();
const auto time = base::unixtime::now();
if (QFile::exists("./tdata/ayudata.db")) {
QFile::rename("./tdata/ayudata.db", QString("./tdata/ayudata_%1.db").arg(time));
@@ -190,18 +191,22 @@ void addEditedMessage(const EditedMessage &message) {
storage.begin_transaction();
storage.insert(message);
storage.commit();
} catch (std::exception& ex) {
} catch (std::exception &ex) {
LOG(("Failed to save edited message for some reason: %1").arg(ex.what()));
}
}
std::vector<EditedMessage> getEditedMessages(ID userId, ID dialogId, ID messageId) {
std::vector<EditedMessage> getEditedMessages(ID userId, ID dialogId, ID messageId, ID minId, ID maxId, int totalLimit) {
return storage.get_all<EditedMessage>(
where(
c(&EditedMessage::userId) == userId and
c(&EditedMessage::dialogId) == dialogId and
c(&EditedMessage::messageId) == messageId
)
column<EditedMessage>(&EditedMessage::userId) == userId and
column<EditedMessage>(&EditedMessage::dialogId) == dialogId and
column<EditedMessage>(&EditedMessage::messageId) == messageId and
(column<EditedMessage>(&EditedMessage::fakeId) > minId or minId == 0) and
(column<EditedMessage>(&EditedMessage::fakeId) < maxId or maxId == 0)
),
order_by(column<EditedMessage>(&EditedMessage::fakeId)).desc(),
limit(totalLimit)
);
}
@@ -209,15 +214,54 @@ bool hasRevisions(ID userId, ID dialogId, ID messageId) {
try {
return storage.count<EditedMessage>(
where(
c(&EditedMessage::userId) == userId and
c(&EditedMessage::dialogId) == dialogId and
c(&EditedMessage::messageId) == messageId
column<EditedMessage>(&EditedMessage::userId) == userId and
column<EditedMessage>(&EditedMessage::dialogId) == dialogId and
column<EditedMessage>(&EditedMessage::messageId) == messageId
)
) > 0;
} catch (std::exception& ex) {
} catch (std::exception &ex) {
LOG(("Failed to check if message has revisions: %1").arg(ex.what()));
return false;
}
}
void addDeletedMessage(const DeletedMessage &message) {
try {
storage.begin_transaction();
storage.insert(message);
storage.commit();
} catch (std::exception &ex) {
LOG(("Failed to save edited message for some reason: %1").arg(ex.what()));
}
}
std::vector<DeletedMessage> getDeletedMessages(ID userId, ID dialogId, ID topicId, ID minId, ID maxId, int totalLimit) {
return storage.get_all<DeletedMessage>(
where(
column<DeletedMessage>(&DeletedMessage::userId) == userId and
column<DeletedMessage>(&DeletedMessage::dialogId) == dialogId and
(column<DeletedMessage>(&DeletedMessage::topicId) == topicId or topicId == 0) and
(column<DeletedMessage>(&DeletedMessage::messageId) > minId or minId == 0) and
(column<DeletedMessage>(&DeletedMessage::messageId) < maxId or maxId == 0)
),
order_by(column<DeletedMessage>(&DeletedMessage::messageId)).desc(),
limit(totalLimit)
);
}
bool hasDeletedMessages(ID userId, ID dialogId, ID topicId) {
try {
return storage.count<DeletedMessage>(
where(
column<DeletedMessage>(&DeletedMessage::userId) == userId and
column<DeletedMessage>(&DeletedMessage::dialogId) == dialogId and
(column<DeletedMessage>(&DeletedMessage::topicId) == topicId or topicId == 0)
)
) > 0;
} catch (std::exception &ex) {
LOG(("Failed to check if dialog has deleted message: %1").arg(ex.what()));
return false;
}
}
}
+5 -1
View File
@@ -13,7 +13,11 @@ namespace AyuDatabase {
void initialize();
void addEditedMessage(const EditedMessage &message);
std::vector<EditedMessage> getEditedMessages(ID userId, ID dialogId, ID messageId);
std::vector<EditedMessage> getEditedMessages(ID userId, ID dialogId, ID messageId, ID minId, ID maxId, int totalLimit);
bool hasRevisions(ID userId, ID dialogId, ID messageId);
void addDeletedMessage(const DeletedMessage &message);
std::vector<DeletedMessage> getDeletedMessages(ID userId, ID dialogId, ID topicId, ID minId, ID maxId, int totalLimit);
bool hasDeletedMessages(ID userId, ID dialogId, ID topicId);
}
+9 -3
View File
@@ -10,7 +10,6 @@
#define ID long long
template<typename TableName>
class AyuMessageBase
{
public:
@@ -31,12 +30,14 @@ public:
std::string fwdName;
int fwdDate;
std::string fwdPostAuthor;
std::string postAuthor;
int replyFlags;
int replyMessageId;
ID replyPeerId;
int replyTopId;
bool replyForumTopic;
std::vector<char> replySerialized;
std::vector<char> replyMarkupSerialized;
int entityCreateDate;
std::string text;
std::vector<char> textEntities;
@@ -49,9 +50,13 @@ public:
std::string mimeType;
};
using DeletedMessage = AyuMessageBase<struct DeletedMessageTag>;
class DeletedMessage : public AyuMessageBase
{
};
using EditedMessage = AyuMessageBase<struct EditedMessageTag>;
class EditedMessage : public AyuMessageBase
{
};
class DeletedDialog
{
@@ -73,6 +78,7 @@ public:
std::vector<char> id;
std::string text;
bool enabled;
bool reversed;
bool caseInsensitive;
std::unique_ptr<ID> dialogId; // nullable
};
@@ -24,27 +24,54 @@
namespace AyuMessages {
void map(HistoryMessageEdition &edition, not_null<HistoryItem*> item, EditedMessage &message) {
message.userId = item->history()->owner().session().userId().bare;
template<typename DerivedMessage>
std::vector<AyuMessageBase> convertToBase(const std::vector<DerivedMessage> &messages) {
std::vector<AyuMessageBase> based;
based.reserve(messages.size());
for (const auto &msg : messages) {
based.push_back(static_cast<AyuMessageBase>(msg));
}
return based;
}
void map(not_null<HistoryItem*> item, AyuMessageBase &message) {
const ID userId = item->history()->owner().session().userId().bare & PeerId::kChatTypeMask;
message.userId = userId;
message.dialogId = getDialogIdFromPeer(item->history()->peer);
message.groupedId = item->groupId().value;
message.peerId = item->from()->id.value; // todo: ???
message.fromId = item->from()->id.value;
if (auto topic = item->history()->asTopic()) {
message.topicId = topic->rootId().bare;
message.groupedId = item->groupId().raw();
message.peerId = item->history()->peer->id.value & PeerId::kChatTypeMask;
message.fromId = item->from()->id.value & PeerId::kChatTypeMask;
if (item->topic()) {
message.topicId = item->topicRootId().bare;
}
message.messageId = item->id.bare;
message.date = item->date();
message.flags = AyuMapper::mapItemFlagsToMTPFlags(item);
if (auto edited = item->Get<HistoryMessageEdited>()) {
if (const auto edited = item->Get<HistoryMessageEdited>()) {
message.editDate = edited->date;
} else {
message.editDate = base::unixtime::now();
}
message.views = item->viewsCount();
message.entityCreateDate = base::unixtime::now(); // todo: rework
message.fwdFlags = 0;
message.fwdFromId = 0;
// message.fwdName
message.fwdDate = 0;
// message.fwdPostAuthor
if (const auto msgsigned = item->Get<HistoryMessageSigned>()) {
message.postAuthor = msgsigned->author.toStdString();
}
message.replyFlags = 0;
message.replyMessageId = 0;
message.replyPeerId = 0;
message.replyTopId = 0;
message.replyForumTopic = false;
// message.replySerialized
// message.replyMarkupSerialized
message.entityCreateDate = base::unixtime::now();
auto serializedText = AyuMapper::serializeTextWithEntities(item);
message.text = serializedText.first;
@@ -52,35 +79,62 @@ void map(HistoryMessageEdition &edition, not_null<HistoryItem*> item, EditedMess
// todo: implement mapping
message.mediaPath = "/";
// message.hqThumbPath
message.documentType = DOCUMENT_TYPE_NONE;
// message.documentSerialized;
// message.thumbsSerialized;
// message.documentAttributesSerialized;
// message.mimeType;
// message.documentSerialized
// message.thumbsSerialized
// message.documentAttributesSerialized
// message.mimeType
}
void addEditedMessage(HistoryMessageEdition &edition, not_null<HistoryItem*> item) {
void addEditedMessage(not_null<HistoryItem *> item) {
EditedMessage message;
map(edition, item, message);
map(item, message);
if (message.text.empty()) {
return;
}
AyuDatabase::addEditedMessage(message);
}
std::vector<EditedMessage> getEditedMessages(not_null<HistoryItem*> item) {
auto userId = item->history()->owner().session().userId().bare;
auto dialogId = getDialogIdFromPeer(item->history()->peer);
auto msgId = item->id.bare;
std::vector<AyuMessageBase> getEditedMessages(not_null<HistoryItem*> item, ID minId, ID maxId, int totalLimit) {
const ID userId = item->history()->owner().session().userId().bare & PeerId::kChatTypeMask;
const auto dialogId = getDialogIdFromPeer(item->history()->peer);
const auto msgId = item->id.bare;
return AyuDatabase::getEditedMessages(userId, dialogId, msgId);
return convertToBase(AyuDatabase::getEditedMessages(userId, dialogId, msgId, minId, maxId, totalLimit));
}
bool hasRevisions(not_null<HistoryItem*> item) {
auto userId = item->history()->owner().session().userId().bare;
auto dialogId = getDialogIdFromPeer(item->history()->peer);
auto msgId = item->id.bare;
const ID userId = item->history()->owner().session().userId().bare & PeerId::kChatTypeMask;
const auto dialogId = getDialogIdFromPeer(item->history()->peer);
const auto msgId = item->id.bare;
return AyuDatabase::hasRevisions(userId, dialogId, msgId);
}
void addDeletedMessage(not_null<HistoryItem*> item) {
DeletedMessage message;
map(item, message);
if (message.text.empty()) {
return;
}
AyuDatabase::addDeletedMessage(message);
}
std::vector<AyuMessageBase>
getDeletedMessages(not_null<PeerData*> peer, ID topicId, ID minId, ID maxId, int totalLimit) {
const ID userId = peer->session().userId().bare & PeerId::kChatTypeMask;
return convertToBase(
AyuDatabase::getDeletedMessages(userId, getDialogIdFromPeer(peer), topicId, minId, maxId, totalLimit));
}
bool hasDeletedMessages(not_null<PeerData*> peer, ID topicId) {
const ID userId = peer->session().userId().bare & PeerId::kChatTypeMask;
return AyuDatabase::hasDeletedMessages(userId, getDialogIdFromPeer(peer), topicId);
}
}
@@ -12,8 +12,12 @@
namespace AyuMessages {
void addEditedMessage(HistoryMessageEdition &edition, not_null<HistoryItem*> item);
std::vector<EditedMessage> getEditedMessages(not_null<HistoryItem*> item);
void addEditedMessage(not_null<HistoryItem *> item);
std::vector<AyuMessageBase> getEditedMessages(not_null<HistoryItem*> item, ID minId, ID maxId, int totalLimit);
bool hasRevisions(not_null<HistoryItem*> item);
void addDeletedMessage(not_null<HistoryItem*> item);
std::vector<AyuMessageBase> getDeletedMessages(not_null<PeerData*> peer, ID topicId, ID minId, ID maxId, int totalLimit);
bool hasDeletedMessages(not_null<PeerData*> peer, ID topicId);
}
@@ -251,6 +251,7 @@ QImage addPadding(const QImage &original) {
original.height() + 2 * st::messageShotPadding,
QImage::Format_ARGB32_Premultiplied
);
paddedImage.setDevicePixelRatio(style::DevicePixelRatio());
paddedImage.fill(Qt::transparent);
Painter painter(&paddedImage);
@@ -351,11 +352,11 @@ QImage Make(not_null<QWidget*> box, const ShotConfig &config) {
height += view->resizeGetHeight(width);
}
// width *= style::DevicePixelRatio();
height *= style::DevicePixelRatio();
// create the image
QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(style::DevicePixelRatio());
image.fill(Qt::transparent);
const auto viewport = QRect(0, 0, width, height);
@@ -408,15 +409,6 @@ QImage Make(not_null<QWidget*> box, const ShotConfig &config) {
picY,
width,
st::msgPhotoSize);
} else {
auto &userpic = hiddenSenderUserpics[message->id];
const auto valid = info->paintCustomUserpic(
p,
userpic,
picX,
picY,
width,
st::msgPhotoSize);
}
}
}
@@ -432,6 +424,7 @@ QImage Make(not_null<QWidget*> box, const ShotConfig &config) {
}
auto newResult = QImage(result.size(), QImage::Format_ARGB32_Premultiplied);
newResult.setDevicePixelRatio(style::DevicePixelRatio());
newResult.fill(makeDefaultBackgroundColor());
Painter painter(&newResult);
@@ -13,14 +13,12 @@
namespace AyuFeatures::StreamerMode::Impl {
void enableHook() {
auto handle = Core::App().activeWindow()->widget()->psHwnd();
Core::App().enumerateWindows([&](not_null<Window::Controller*> w) {
SetWindowDisplayAffinity(w->widget()->psHwnd(), WDA_EXCLUDEFROMCAPTURE);
});
}
void disableHook() {
auto handle = Core::App().activeWindow()->widget()->psHwnd();
Core::App().enumerateWindows([&](not_null<Window::Controller*> w) {
SetWindowDisplayAffinity(w->widget()->psHwnd(), WDA_NONE);
});
File diff suppressed because it is too large Load Diff
+74 -23
View File
@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.45.3"
#define SQLITE_VERSION_NUMBER 3045003
#define SQLITE_SOURCE_ID "2024-04-15 13:34:05 8653b758870e6ef0c98d46b3ace27849054af85da891eb121e9aaa537f1e8355"
#define SQLITE_VERSION "3.46.1"
#define SQLITE_VERSION_NUMBER 3046001
#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -764,11 +764,11 @@ struct sqlite3_file {
** </ul>
** xLock() upgrades the database file lock. In other words, xLock() moves the
** database file lock in the direction NONE toward EXCLUSIVE. The argument to
** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** SQLITE_LOCK_NONE. If the database file lock is already at or above the
** requested lock, then the call to xLock() is a no-op.
** xUnlock() downgrades the database file lock to either SHARED or NONE.
* If the lock is already at or below the requested lock state, then the call
** If the lock is already at or below the requested lock state, then the call
** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
@@ -3305,8 +3305,8 @@ SQLITE_API int sqlite3_set_authorizer(
#define SQLITE_RECURSIVE 33 /* NULL NULL */
/*
** CAPI3REF: Tracing And Profiling Functions
** METHOD: sqlite3
** CAPI3REF: Deprecated Tracing And Profiling Functions
** DEPRECATED
**
** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
** instead of the routines described here.
@@ -6887,6 +6887,12 @@ SQLITE_API int sqlite3_autovacuum_pages(
** The exceptions defined in this paragraph might change in a future
** release of SQLite.
**
** Whether the update hook is invoked before or after the
** corresponding change is currently unspecified and may differ
** depending on the type of change. Do not rely on the order of the
** hook call with regards to the final result of the operation which
** triggers the hook.
**
** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the
@@ -8357,7 +8363,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
** The sqlite3_keyword_count() interface returns the number of distinct
** keywords understood by SQLite.
**
** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
** The sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and
** makes *Z point to that keyword expressed as UTF8 and writes the number
** of bytes in the keyword into *L. The string that *Z points to is not
** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns
@@ -9936,24 +9942,45 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
** <li value="2"><p>
** ^(If the sqlite3_vtab_distinct() interface returns 2, that means
** that the query planner does not need the rows returned in any particular
** order, as long as rows with the same values in all "aOrderBy" columns
** are adjacent.)^ ^(Furthermore, only a single row for each particular
** combination of values in the columns identified by the "aOrderBy" field
** needs to be returned.)^ ^It is always ok for two or more rows with the same
** values in all "aOrderBy" columns to be returned, as long as all such rows
** are adjacent. ^The virtual table may, if it chooses, omit extra rows
** that have the same value for all columns identified by "aOrderBy".
** ^However omitting the extra rows is optional.
** order, as long as rows with the same values in all columns identified
** by "aOrderBy" are adjacent.)^ ^(Furthermore, when two or more rows
** contain the same values for all columns identified by "colUsed", all but
** one such row may optionally be omitted from the result.)^
** The virtual table is not required to omit rows that are duplicates
** over the "colUsed" columns, but if the virtual table can do that without
** too much extra effort, it could potentially help the query to run faster.
** This mode is used for a DISTINCT query.
** <li value="3"><p>
** ^(If the sqlite3_vtab_distinct() interface returns 3, that means
** that the query planner needs only distinct rows but it does need the
** rows to be sorted.)^ ^The virtual table implementation is free to omit
** rows that are identical in all aOrderBy columns, if it wants to, but
** it is not required to omit any rows. This mode is used for queries
** ^(If the sqlite3_vtab_distinct() interface returns 3, that means the
** virtual table must return rows in the order defined by "aOrderBy" as
** if the sqlite3_vtab_distinct() interface had returned 0. However if
** two or more rows in the result have the same values for all columns
** identified by "colUsed", then all but one such row may optionally be
** omitted.)^ Like when the return value is 2, the virtual table
** is not required to omit rows that are duplicates over the "colUsed"
** columns, but if the virtual table can do that without
** too much extra effort, it could potentially help the query to run faster.
** This mode is used for queries
** that have both DISTINCT and ORDER BY clauses.
** </ol>
**
** <p>The following table summarizes the conditions under which the
** virtual table is allowed to set the "orderByConsumed" flag based on
** the value returned by sqlite3_vtab_distinct(). This table is a
** restatement of the previous four paragraphs:
**
** <table border=1 cellspacing=0 cellpadding=10 width="90%">
** <tr>
** <td valign="top">sqlite3_vtab_distinct() return value
** <td valign="top">Rows are returned in aOrderBy order
** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
** <td valign="top">Duplicates over all colUsed columns may be omitted
** <tr><td>0<td>yes<td>yes<td>no
** <tr><td>1<td>no<td>yes<td>no
** <tr><td>2<td>no<td>yes<td>yes
** <tr><td>3<td>yes<td>yes<td>yes
** </table>
**
** ^For the purposes of comparing virtual table output values to see if the
** values are same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS"
@@ -11998,6 +12025,30 @@ SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const c
*/
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
/*
** CAPI3REF: Add A Single Change To A Changegroup
** METHOD: sqlite3_changegroup
**
** This function adds the single change currently indicated by the iterator
** passed as the second argument to the changegroup object. The rules for
** adding the change are just as described for [sqlite3changegroup_add()].
**
** If the change is successfully added to the changegroup, SQLITE_OK is
** returned. Otherwise, an SQLite error code is returned.
**
** The iterator must point to a valid entry when this function is called.
** If it does not, SQLITE_ERROR is returned and no change is added to the
** changegroup. Additionally, the iterator must not have been opened with
** the SQLITE_CHANGESETAPPLY_INVERT flag. In this case SQLITE_ERROR is also
** returned.
*/
SQLITE_API int sqlite3changegroup_add_change(
sqlite3_changegroup*,
sqlite3_changeset_iter*
);
/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
** METHOD: sqlite3_changegroup
@@ -12802,8 +12853,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
** Return a copy of the context pointer the extension function was
** registered with.
** Return a copy of the pUserData pointer passed to the xCreateFunction()
** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
File diff suppressed because it is too large Load Diff
@@ -19,6 +19,12 @@ ayuStreamerModeMenuIcon: icon {{ "ayu/streamer", menuIconColor }};
ayuMenuIconToBeginning: icon {{ "ayu/to_beginning", menuIconColor }};
messageFieldAttachIcon: icon {{ "ayu/message_field/attach", menuIconColor }};
messageFieldCommandsIcon: icon {{ "ayu/message_field/commands", menuIconColor }};
messageFieldEmojiIcon: icon {{ "ayu/message_field/emoji", menuIconColor }};
messageFieldVoiceIcon: icon {{ "ayu/message_field/voice", menuIconColor }};
messageFieldTTLIcon: icon {{ "ayu/message_field/ttl", menuIconColor }};
inChannelBadgeIcon: icon {{ "ayu/channel", msgInDateFg }};
inChannelBadgeSelectedIcon: icon {{ "ayu/channel", msgInDateFgSelected }};
outChannelBadgeIcon: icon {{ "ayu/channel", msgOutDateFg }};
@@ -45,6 +45,7 @@
#include <ayu/ayu_settings.h>
#include "ayu/ayu_fonts.h"
#include "ui/ui_utility.h"
struct Font
{
@@ -6,27 +6,32 @@
// Copyright @Radolyn, 2024
#include "ayu/ui/context_menu/context_menu.h"
#include <styles/style_menu_icons.h>
#include "apiwrap.h"
#include "lang_auto.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "ayu/ayu_settings.h"
#include "ayu/ayu_state.h"
#include "../../data/messages_storage.h"
#include "ayu/data/messages_storage.h"
#include "ayu/ui/context_menu/menu_item_subtext.h"
#include "ayu/utils/qt_key_modifiers_extended.h"
#include "history/history_item_components.h"
#include "core/mime_type.h"
#include "styles/style_ayu_icons.h"
#include "styles/style_menu_icons.h"
#include "ui/widgets/popup_menu.h"
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
#include "window/window_peer_menu.h"
#include "ayu/ui/sections/edited/edited_log_section.h"
#include "ayu/ui/message_history/history_section.h"
#include "ayu/utils/telegram_helpers.h"
#include "base/unixtime.h"
#include "data/data_channel.h"
#include "data/data_user.h"
#include "data/data_chat.h"
#include "data/data_forum_topic.h"
#include "data/data_session.h"
#include "history/view/history_view_context_menu.h"
#include "history/view/history_view_element.h"
#include "window/window_session_controller.h"
@@ -37,13 +42,119 @@ bool needToShowItem(int state) {
return state == 1 || (state == 2 && base::IsExtendedContextMenuModifierPressed());
}
void AddDeletedMessagesActions(PeerData *peerData,
Data::Thread *thread,
not_null<Window::SessionController*> sessionController,
const Window::PeerMenuCallback &addCallback) {
if (!peerData) {
return;
}
const auto topic = peerData->isForum() ? thread->asTopic() : nullptr;
const auto topicId = topic ? topic->rootId().bare : 0;
const auto has = AyuMessages::hasDeletedMessages(peerData, topicId);
if (!has) {
return;
}
addCallback(tr::ayu_ViewDeletedMenuText(tr::now),
[=]
{
sessionController->session().tryResolveWindow()
->showSection(std::make_shared<MessageHistory::SectionMemento>(peerData, nullptr, topicId));
},
&st::menuIconArchive);
}
void AddJumpToBeginningAction(PeerData *peerData,
Data::Thread *thread,
not_null<Window::SessionController*> sessionController,
const Window::PeerMenuCallback &addCallback) {
const auto user = peerData->asUser();
const auto group = peerData->isChat() ? peerData->asChat() : nullptr;
const auto chat = peerData->isMegagroup()
? peerData->asMegagroup()
: peerData->isChannel()
? peerData->asChannel()
: nullptr;
const auto topic = peerData->isForum() ? thread->asTopic() : nullptr;
if (!user && !group && !chat && !topic) {
return;
}
if (topic && topic->creating()) {
return;
}
const auto controller = sessionController;
const auto jumpToDate = [=](auto history, auto callback)
{
const auto weak = base::make_weak(controller);
controller->session().api().resolveJumpToDate(
history,
QDate(2013, 8, 1),
[=](not_null<PeerData*> peer, MsgId id)
{
if (const auto strong = weak.get()) {
callback(peer, id);
}
});
};
const auto showPeerHistory = [=](auto peer, MsgId id)
{
controller->showPeerHistory(
peer,
Window::SectionShow::Way::Forward,
id);
};
const auto showTopic = [=](auto topic, MsgId id)
{
controller->showTopic(
topic,
id,
Window::SectionShow::Way::Forward);
};
addCallback(
tr::ayu_JumpToBeginning(tr::now),
[=]
{
if (user) {
jumpToDate(controller->session().data().history(user), showPeerHistory);
} else if (group && !chat) {
jumpToDate(controller->session().data().history(group), showPeerHistory);
} else if (chat && !topic) {
if (!chat->migrateFrom() && chat->availableMinId() == 1) {
showPeerHistory(chat, 1);
} else {
jumpToDate(controller->session().data().history(chat), showPeerHistory);
}
} else if (topic) {
if (topic->isGeneral()) {
showTopic(topic, 1);
} else {
jumpToDate(
topic,
[=](not_null<PeerData*>, MsgId id)
{
showTopic(topic, id);
});
}
}
},
&st::ayuMenuIconToBeginning);
}
void AddHistoryAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
if (AyuMessages::hasRevisions(item)) {
menu->addAction(tr::ayu_EditsHistoryMenuText(tr::now),
[=]
{
item->history()->session().tryResolveWindow()
->showSection(std::make_shared<EditedLog::SectionMemento>(item->history()->peer, item));
->showSection(
std::make_shared<MessageHistory::SectionMemento>(item->history()->peer, item, 0));
},
&st::ayuEditsHistoryIcon);
}
@@ -90,7 +201,7 @@ void AddUserMessagesAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
? Dialogs::Key{item->topic()}
: Dialogs::Key{item->history()}
: Dialogs::Key();
mainWidget->content()->searchMessages(QString(), key, item->from()->asUser());
mainWidget->content()->searchMessages(QString(), key, item->from());
}
}
},
@@ -120,7 +231,7 @@ void AddMessageDetailsAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
if (!containsSingleCustomEmojiPack && emojiPacks.size() > 1) {
const auto author = emojiPacks.front().id >> 32;
auto sameAuthor = true;
for (const auto &pack : emojiPacks) {
for (const auto &pack : emojiPacks) {
if (pack.id >> 32 != author) {
sameAuthor = false;
break;
@@ -310,7 +421,7 @@ void AddMessageDetailsAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
}
void AddReadUntilAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
if (item->isLocal() || item->isService()) {
if (item->isLocal() || item->isService() || item->out() || item->isDeleted()) {
return;
}
@@ -327,6 +438,25 @@ void AddReadUntilAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
[=]()
{
readHistory(item);
if (item->media() && !item->media()->ttlSeconds()) {
const auto ids = MTP_vector<MTPint>(1, MTP_int(item->id));
if (const auto channel = item->history()->peer->asChannel()) {
item->history()->session().api().request(MTPchannels_ReadMessageContents(
channel->inputChannel,
ids
)).send();
} else {
item->history()->session().api().request(MTPmessages_ReadMessageContents(
ids
)).done([=](const MTPmessages_AffectedMessages &result)
{
item->history()->session().api().applyAffectedMessages(
item->history()->peer,
result);
}).send();
}
item->markContentsRead();
}
},
&st::menuIconShowInChat);
}
@@ -8,11 +8,23 @@
#include "data/data_document.h"
#include "ui/widgets/popup_menu.h"
#include "window/window_peer_menu.h"
#include "window/window_session_controller.h"
namespace AyuUi {
bool needToShowItem(int state);
void AddDeletedMessagesActions(PeerData *peerData,
Data::Thread *thread,
not_null<Window::SessionController*> sessionController,
const Window::PeerMenuCallback &addCallback);
void AddJumpToBeginningAction(PeerData *peerData,
Data::Thread *thread,
not_null<Window::SessionController*> sessionController,
const Window::PeerMenuCallback &addCallback);
void AddHistoryAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item);
void AddHideMessageAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item);
void AddUserMessagesAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item);
@@ -4,14 +4,14 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2024
#include "ayu/ui/sections/edited/edited_log_inner.h"
#include "ayu/ui/message_history/history_inner.h"
#include "apiwrap.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "api/api_attached_stickers.h"
#include "ayu/data/messages_storage.h"
#include "ayu/ui/sections/edited/edited_log_section.h"
#include "ayu/ui/message_history/history_section.h"
#include "base/call_delayed.h"
#include "base/unixtime.h"
#include "base/platform/base_platform_info.h"
@@ -57,17 +57,17 @@
#include <QtGui/QClipboard>
#include <QtWidgets/QApplication>
namespace EditedLog {
namespace {
#include "history/view/history_view_context_menu.h"
#include "ui/ui_utility.h"
// If we require to support more admins we'll have to rewrite this anyway.
constexpr auto kMaxChannelAdmins = 200;
namespace MessageHistory {
namespace {
constexpr auto kScrollDateHideTimeout = 1000;
constexpr auto kEventsFirstPage = 20;
constexpr auto kMessagesFirstPage = 20;
constexpr auto kEventsPerPage = 50;
constexpr auto kMessagesPerPage = 30;
constexpr auto kClearUserpicsAfter = 50;
@@ -247,11 +247,13 @@ InnerWidget::InnerWidget(
QWidget *parent,
not_null<Window::SessionController*> controller,
not_null<PeerData*> peer,
not_null<HistoryItem*> item)
HistoryItem *item,
ID topicId)
: RpWidget(parent),
_controller(controller),
_peer(peer),
_item(item),
_topicId(topicId),
_history(peer->owner().history(peer)),
_api(&_peer->session().mtp()),
_pathGradient(
@@ -331,7 +333,6 @@ InnerWidget::InnerWidget(
const Data::Session::ItemVisibilityQuery &query)
{
return (_history == query.item->history())
&& query.item->isAdminLogEntry()
&& isVisible();
}) | rpl::start_with_next([=](
const Data::Session::ItemVisibilityQuery &query)
@@ -378,9 +379,7 @@ void InnerWidget::visibleTopBottomUpdated(
}
updateVisibleTopItem();
if (_items.size() == 0) {
addEvents(Direction::Up);
}
checkPreloadMore();
if (scrolledUp) {
_scrollDateCheck.call();
} else {
@@ -463,17 +462,17 @@ void InnerWidget::repaintScrollDateCallback() {
update(0, updateTop, width(), updateHeight);
}
void InnerWidget::checkPreloadMore() {
if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop) > height()) {
preloadMore(Direction::Down);
}
if (_visibleTop < PreloadHeightsCount * (_visibleBottom - _visibleTop)) {
preloadMore(Direction::Up);
}
}
void InnerWidget::updateEmptyText() {
auto hasSearch = false;
auto hasFilter = false;
auto text = Ui::Text::Semibold((hasSearch || hasFilter)
? tr::lng_admin_log_no_results_title(tr::now)
: tr::lng_admin_log_no_events_title(tr::now));
auto description = _peer->isMegagroup()
? tr::lng_admin_log_no_events_text(tr::now)
: tr::lng_admin_log_no_events_text_channel(tr::now);
text.text.append(u"\n\n"_q + description);
_emptyText.setMarkedText(st::defaultTextStyle, text);
_emptyText.setMarkedText(st::defaultTextStyle, Ui::Text::Semibold(tr::lng_search_messages_none(tr::now)));
}
QString InnerWidget::tooltipText() const {
@@ -523,8 +522,8 @@ bool InnerWidget::elementUnderCursor(
return (Element::Hovered() == view);
}
bool InnerWidget::elementInSelectionMode() {
return false;
HistoryView::SelectionModeResult InnerWidget::elementInSelectionMode() {
return {};
}
bool InnerWidget::elementIntersectsRange(
@@ -611,7 +610,7 @@ void InnerWidget::elementStartInteraction(not_null<const Element*> view) {
void InnerWidget::elementStartPremium(
not_null<const HistoryView::Element*> view,
HistoryView::Element *replacing) {
HistoryView::Element *replacing) {
}
void InnerWidget::elementCancelPremium(not_null<const Element*> view) {
@@ -631,17 +630,15 @@ bool InnerWidget::elementHideTopicButton(not_null<const Element*> view) {
}
void InnerWidget::saveState(not_null<SectionMemento*> memento) {
if (!_filterChanged) {
for (auto &item : _items) {
item.clearView();
}
memento->setItems(
base::take(_items),
base::take(_eventIds),
_upLoaded,
_downLoaded);
base::take(_itemsByData);
for (auto &item : _items) {
item.clearView();
}
memento->setItems(
base::take(_items),
base::take(_messageIds),
_upLoaded,
_downLoaded);
base::take(_itemsByData);
_upLoaded = _downLoaded = true; // Don't load or handle anything anymore.
}
@@ -651,23 +648,63 @@ void InnerWidget::restoreState(not_null<SectionMemento*> memento) {
item.refreshView(this);
_itemsByData.emplace(item->data(), item.get());
}
_eventIds = memento->takeEventIds();
_messageIds = memento->takeMessageIds();
_upLoaded = memento->upLoaded();
_downLoaded = memento->downLoaded();
_filterChanged = false;
updateMinMaxIds();
updateSize();
}
void InnerWidget::addEvents(Direction direction) {
auto messages = AyuMessages::getEditedMessages(_item);
if (messages.empty()) {
void InnerWidget::preloadMore(Direction direction) {
auto &loadedFlag = (direction == Direction::Up) ? _upLoaded : _downLoaded;
if (loadedFlag) {
return;
}
const auto size = messages.size();
auto &container = _items;
auto maxId = (direction == Direction::Up) ? _minId : 0;
auto minId = (direction == Direction::Up) ? 0 : _maxId;
auto perPage = _items.empty() ? kMessagesFirstPage : kMessagesPerPage;
std::vector<AyuMessageBase> messages;
if (_item) {
// viewing edited history
messages = AyuMessages::getEditedMessages(_item, minId, maxId, perPage);
} else {
// viewing deleted messages
messages = AyuMessages::getDeletedMessages(_peer, _topicId, minId, maxId, perPage);
}
crl::on_main([=]
{
addMessages(direction, messages);
});
}
void InnerWidget::addMessages(Direction direction, const std::vector<AyuMessageBase> &messages) {
auto up = (direction == Direction::Up);
if (messages.empty()) {
(up ? _upLoaded : _downLoaded) = true;
update();
return;
}
// When loading items up we just add them to the back of the _items vector.
// When loading items down we add them to a new vector and copy _items after them.
auto newItemsForDownDirection = std::vector<OwnedItem>();
auto oldItemsCount = _items.size();
auto &addToItems = (direction == Direction::Up)
? _items
: newItemsForDownDirection;
addToItems.reserve(oldItemsCount + messages.size() * 2);
for (const auto &message : messages) {
const auto id = _item
? message.fakeId // viewing edited history
: message.messageId; // viewing deleted messages
if (_messageIds.find(id) != _messageIds.end()) {
return;
}
auto count = 0;
const auto addOne = [&](
OwnedItem item,
TimeId sentDate,
@@ -676,19 +713,50 @@ void InnerWidget::addEvents(Direction direction) {
if (sentDate) {
_itemDates.emplace(item->data(), sentDate);
}
_messageIds.emplace(id);
_itemsByData.emplace(item->data(), item.get());
container.push_back(std::move(item));
addToItems.push_back(std::move(item));
++count;
};
GenerateItems(
this,
_history,
message,
addOne);
if (count > 1) {
// Reverse the inner order of the added messages, because we load messages
// from bottom to top but inside one message they go from top to bottom.
auto full = addToItems.size();
auto from = full - count;
for (auto i = 0, toReverse = count / 2; i != toReverse; ++i) {
std::swap(addToItems[from + i], addToItems[full - i - 1]);
}
}
}
auto newItemsCount = _items.size() + ((direction == Direction::Up) ? 0 : newItemsForDownDirection.size());
if (newItemsCount != oldItemsCount) {
if (direction == Direction::Down) {
for (auto &item : _items) {
newItemsForDownDirection.push_back(std::move(item));
}
_items = std::move(newItemsForDownDirection);
}
updateMinMaxIds();
itemsAdded(direction, newItemsCount - oldItemsCount);
}
itemsAdded(direction, size);
update();
repaint();
}
void InnerWidget::updateMinMaxIds() {
if (_messageIds.empty()) {
_maxId = _minId = 0;
} else {
_maxId = *_messageIds.rbegin();
_minId = *_messageIds.begin();
if (_minId == 1) {
_upLoaded = true;
}
}
}
void InnerWidget::itemsAdded(Direction direction, int addedCount) {
@@ -718,6 +786,7 @@ void InnerWidget::updateSize() {
TWidget::resizeToWidth(width());
restoreScrollPosition();
updateVisibleTopItem();
checkPreloadMore();
}
int InnerWidget::resizeGetHeight(int newWidth) {
@@ -1103,6 +1172,13 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
saveDocumentToFile(lnkDocument);
}),
&st::menuIconDownload);
HistoryView::AddCopyFilename(
_menu,
lnkDocument,
[] { return false; });
if (lnkDocument->hasAttachedStickers()) {
const auto controller = _controller;
auto callback = [=]
@@ -1634,4 +1710,4 @@ QPoint InnerWidget::mapPointToItem(QPoint point, const Element *view) const {
InnerWidget::~InnerWidget() = default;
} // namespace EditedLog
} // namespace MessageHistory
@@ -6,8 +6,8 @@
// Copyright @Radolyn, 2024
#pragma once
#include "ayu/ui/sections/edited/edited_log_item.h"
#include "ayu/ui/sections/edited/edited_log_section.h"
#include "ayu/ui/message_history/history_item.h"
#include "ayu/ui/message_history/history_section.h"
#include "base/timer.h"
#include "history/view/history_view_element.h"
#include "menu/menu_antispam_validator.h"
@@ -40,7 +40,7 @@ namespace Window {
class SessionController;
} // namespace Window
namespace EditedLog {
namespace MessageHistory {
class SectionMemento;
@@ -52,7 +52,8 @@ public:
QWidget *parent,
not_null<Window::SessionController*> controller,
not_null<PeerData*> peer,
not_null<HistoryItem*> item);
HistoryItem *item,
ID topicId);
[[nodiscard]] Main::Session &session() const;
@@ -62,7 +63,7 @@ public:
[[nodiscard]] rpl::producer<int> scrollToSignal() const;
[[nodiscard]] not_null<PeerData*> channel() const {
[[nodiscard]] not_null<PeerData*> peer() const {
return _peer;
}
@@ -86,7 +87,7 @@ public:
HistoryView::Context elementContext() override;
bool elementUnderCursor(
not_null<const HistoryView::Element*> view) override;
bool elementInSelectionMode() override;
HistoryView::SelectionModeResult elementInSelectionMode() override;
bool elementIntersectsRange(
not_null<const HistoryView::Element*> view,
int from,
@@ -207,15 +208,18 @@ private:
TextForMimeData getSelectedText() const;
void updateVisibleTopItem();
void preloadMore(Direction direction);
void itemsAdded(Direction direction, int addedCount);
void updateSize();
void updateMinMaxIds();
void updateEmptyText();
void paintEmpty(Painter &p, not_null<const Ui::ChatStyle*> st);
void addEvents(Direction direction);
void addMessages(Direction direction, const std::vector<AyuMessageBase> &messages);
Element *viewForItem(const HistoryItem *item);
void toggleScrollDateShown();
void repaintScrollDateCallback();
void checkPreloadMore();
bool displayScrollDate() const;
void scrollDateHide();
void scrollDateCheck();
@@ -247,7 +251,8 @@ private:
const not_null<Window::SessionController*> _controller;
const not_null<PeerData*> _peer;
const not_null<HistoryItem*> _item;
HistoryItem *_item;
ID _topicId;
const not_null<History*> _history;
MTP::Sender _api;
@@ -255,7 +260,7 @@ private:
std::shared_ptr<Ui::ChatTheme> _theme;
std::vector<OwnedItem> _items;
std::set<uint64> _eventIds;
std::set<uint64> _messageIds;
std::map<not_null<const HistoryItem*>, not_null<Element*>> _itemsByData;
base::flat_map<not_null<const HistoryItem*>, TimeId> _itemDates;
base::flat_set<FullMsgId> _animatedStickersPlayed;
@@ -279,10 +284,13 @@ private:
Element *_scrollDateLastItem = nullptr;
int _scrollDateLastItemTop = 0;
// Up - max, Down - min.
ID _maxId = 0;
ID _minId = 0;
// Don't load anything until the memento was read.
bool _upLoaded = true;
bool _downLoaded = true;
bool _filterChanged = false;
Ui::Text::String _emptyText;
MouseAction _mouseAction = MouseAction::None;
@@ -308,4 +316,4 @@ private:
};
} // namespace EditedLog
} // namespace MessageHistory
@@ -0,0 +1,124 @@
// This is the source code of AyuGram for Desktop.
//
// We do not and cannot prevent the use of our code,
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2024
#include "ayu/ui/message_history/history_item.h"
#include "ayu/data/entities.h"
#include "api/api_chat_participants.h"
#include "api/api_text_entities.h"
#include "ayu/ui/message_history/history_inner.h"
#include "base/unixtime.h"
#include "core/application.h"
#include "core/click_handler_types.h"
#include "data/data_channel.h"
#include "data/data_file_origin.h"
#include "data/data_forum_topic.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "history/history.h"
#include "history/history_item.h"
#include "history/history_item_helpers.h"
#include "history/view/history_view_element.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/basic_click_handlers.h"
#include "ui/text/text_utilities.h"
namespace MessageHistory {
OwnedItem::OwnedItem(std::nullptr_t) {
}
OwnedItem::OwnedItem(
not_null<HistoryView::ElementDelegate*> delegate,
not_null<HistoryItem*> data)
: _data(data), _view(_data->createView(delegate)) {
}
OwnedItem::OwnedItem(OwnedItem &&other)
: _data(base::take(other._data)), _view(base::take(other._view)) {
}
OwnedItem &OwnedItem::operator=(OwnedItem &&other) {
_data = base::take(other._data);
_view = base::take(other._view);
return *this;
}
OwnedItem::~OwnedItem() {
clearView();
if (_data) {
_data->destroy();
}
}
void OwnedItem::refreshView(
not_null<HistoryView::ElementDelegate*> delegate) {
_view = _data->createView(delegate);
}
void OwnedItem::clearView() {
_view = nullptr;
}
void GenerateItems(
not_null<HistoryView::ElementDelegate*> delegate,
not_null<History*> history,
AyuMessageBase message,
Fn<void(OwnedItem item, TimeId sentDate, MsgId)> callback) {
PeerData *from = history->owner().userLoaded(message.fromId);
if (!from) {
from = history->owner().channelLoaded(message.fromId);
}
if (!from) {
from = reinterpret_cast<PeerData*>(history->owner().chatLoaded(message.fromId));
}
const auto date = message.entityCreateDate;
const auto addPart = [&](
not_null<HistoryItem*> item,
TimeId sentDate = 0,
MsgId realId = MsgId())
{
return callback(OwnedItem(delegate, item), sentDate, realId);
};
const auto makeSimpleTextMessage = [&](TextWithEntities &&text)
{
base::flags<MessageFlag> flags = MessageFlag::AdminLogEntry;
if (from) {
flags |= MessageFlag::HasFromId;
} else {
flags |= MessageFlag::HasPostAuthor;
}
if (!message.postAuthor.empty()) {
flags |= MessageFlag::HasPostAuthor;
}
return history->makeMessage({
.id = history->nextNonHistoryEntryId(),
.flags = flags,
.from = from ? from->id : 0,
.date = date,
.postAuthor = !message.postAuthor.empty()
? QString::fromStdString(message.postAuthor)
: from
? QString()
: QString("unknown user: %1").arg(message.fromId),
},
std::move(text),
MTP_messageMediaEmpty());
};
const auto addSimpleTextMessage = [&](TextWithEntities &&text)
{
addPart(makeSimpleTextMessage(std::move(text)));
};
const auto text = QString::fromStdString(message.text);
addSimpleTextMessage(Ui::Text::WithEntities(text));
}
} // namespace MessageHistory
@@ -15,14 +15,14 @@ class ElementDelegate;
class Element;
} // namespace HistoryView
namespace EditedLog {
namespace MessageHistory {
class OwnedItem;
void GenerateItems(
not_null<HistoryView::ElementDelegate*> delegate,
not_null<History*> history,
EditedMessage message,
AyuMessageBase message,
Fn<void(OwnedItem item, TimeId sentDate, MsgId)> callback);
// Smart pointer wrapper for HistoryItem* that destroys the owned item.
@@ -60,4 +60,4 @@ private:
};
} // namespace EditedLog
} // namespace MessageHistory
@@ -4,10 +4,10 @@
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2024
#include "ayu/ui/sections/edited/edited_log_section.h"
#include "ayu/ui/message_history/history_section.h"
#include "apiwrap.h"
#include "ayu/ui/sections/edited/edited_log_inner.h"
#include "ayu/ui/message_history/history_inner.h"
#include "base/timer.h"
#include "data/data_channel.h"
#include "data/data_session.h"
@@ -25,7 +25,7 @@
#include "window/window_session_controller.h"
#include "window/themes/window_theme.h"
namespace EditedLog {
namespace MessageHistory {
class FixedBar final : public TWidget
{
@@ -63,7 +63,7 @@ object_ptr<Window::SectionWidget> SectionMemento::createWidget(
if (column == Window::Column::Third) {
return nullptr;
}
auto result = object_ptr<Widget>(parent, controller, _peer, _item);
auto result = object_ptr<Widget>(parent, controller, _peer, _item, _topicId);
result->setInternalState(geometry, this);
return result;
}
@@ -142,12 +142,14 @@ Widget::Widget(
QWidget *parent,
not_null<Window::SessionController*> controller,
not_null<PeerData*> peer,
not_null<HistoryItem*> item)
HistoryItem *item,
ID topicId)
: Window::SectionWidget(parent, controller, rpl::single<PeerData*>(peer)),
_scroll(this, st::historyScroll, false),
_fixedBar(this, controller, peer),
_fixedBarShadow(this),
_item(item) {
_item(item),
_topicId(topicId) {
_fixedBar->move(0, 0);
_fixedBar->resizeToWidth(width());
_fixedBar->show();
@@ -161,7 +163,7 @@ Widget::Widget(
},
lifetime());
_inner = _scroll->setOwnedWidget(object_ptr<InnerWidget>(this, controller, peer, item));
_inner = _scroll->setOwnedWidget(object_ptr<InnerWidget>(this, controller, peer, item, topicId));
_inner->scrollToSignal(
) | rpl::start_with_next([=](int top)
{
@@ -190,7 +192,7 @@ void Widget::updateAdaptiveLayout() {
}
not_null<PeerData*> Widget::channel() const {
return _inner->channel();
return _inner->peer();
}
Dialogs::RowDescriptor Widget::activeChat() const {
@@ -234,7 +236,7 @@ void Widget::setupShortcuts() {
}
std::shared_ptr<Window::SectionMemento> Widget::createMemento() {
auto result = std::make_shared<SectionMemento>(channel(), _item);
auto result = std::make_shared<SectionMemento>(channel(), _item, _topicId);
saveState(result.get());
return result;
}
@@ -321,4 +323,4 @@ QRect Widget::floatPlayerAvailableRect() {
return mapToGlobal(_scroll->geometry());
}
} // namespace EditedLog
} // namespace MessageHistory
@@ -8,7 +8,7 @@
#include "window/section_widget.h"
#include "window/section_memento.h"
#include "ayu/ui/sections/edited/edited_log_item.h"
#include "ayu/ui/message_history/history_item.h"
#include "mtproto/sender.h"
// don't reformat includes above
@@ -22,7 +22,7 @@ namespace Profile {
class BackButton;
} // namespace Profile
namespace EditedLog {
namespace MessageHistory {
class FixedBar;
class InnerWidget;
@@ -35,7 +35,8 @@ public:
QWidget *parent,
not_null<Window::SessionController*> controller,
not_null<PeerData*> peer,
not_null<HistoryItem*> item);
HistoryItem *item,
ID topicId);
not_null<PeerData*> channel() const;
Dialogs::RowDescriptor activeChat() const override;
@@ -77,7 +78,8 @@ private:
QPointer<InnerWidget> _inner;
object_ptr<FixedBar> _fixedBar;
object_ptr<Ui::PlainShadow> _fixedBarShadow;
not_null<HistoryItem*> _item;
HistoryItem *_item;
ID _topicId;
};
@@ -86,9 +88,10 @@ class SectionMemento : public Window::SectionMemento
public:
using Element = HistoryView::Element;
SectionMemento(not_null<PeerData*> peer, not_null<HistoryItem*> item)
SectionMemento(not_null<PeerData*> peer, HistoryItem *item, ID topicId)
: _peer(peer),
_item(item) {
_item(item),
_topicId(topicId) {
}
object_ptr<Window::SectionWidget> createWidget(
@@ -115,7 +118,7 @@ public:
bool upLoaded,
bool downLoaded) {
_items = std::move(items);
_eventIds = std::move(eventIds);
_messageIds = std::move(eventIds);
_upLoaded = upLoaded;
_downLoaded = downLoaded;
}
@@ -124,8 +127,8 @@ public:
return std::move(_items);
}
std::set<uint64> takeEventIds() {
return std::move(_eventIds);
std::set<uint64> takeMessageIds() {
return std::move(_messageIds);
}
bool upLoaded() const {
@@ -138,14 +141,13 @@ public:
private:
not_null<PeerData*> _peer;
not_null<HistoryItem*> _item;
HistoryItem *_item;
ID _topicId;
int _scrollTop = 0;
std::vector<not_null<UserData*>> _admins;
std::vector<not_null<UserData*>> _adminsCanEdit;
std::vector<OwnedItem> _items;
std::set<uint64> _eventIds;
std::set<uint64> _messageIds;
bool _upLoaded = false;
bool _downLoaded = true;
};
} // namespace EditedLog
} // namespace MessageHistory
@@ -1,659 +0,0 @@
// This is the source code of AyuGram for Desktop.
//
// We do not and cannot prevent the use of our code,
// but be respectful and credit the original author.
//
// Copyright @Radolyn, 2024
#include "ayu/ui/sections/edited/edited_log_item.h"
#include "ayu/data/entities.h"
#include "api/api_chat_participants.h"
#include "api/api_text_entities.h"
#include "ayu/ui/sections/edited/edited_log_inner.h"
#include "base/unixtime.h"
#include "core/application.h"
#include "core/click_handler_types.h"
#include "data/data_channel.h"
#include "data/data_file_origin.h"
#include "data/data_forum_topic.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "history/history.h"
#include "history/history_item.h"
#include "history/history_item_helpers.h"
#include "history/view/history_view_element.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/basic_click_handlers.h"
#include "ui/text/text_utilities.h"
namespace EditedLog {
namespace {
const auto CollectChanges = [](
auto &phraseMap,
auto plusFlags,
auto minusFlags)
{
auto withPrefix = [&phraseMap](auto flags, QChar prefix)
{
auto result = QString();
for (auto &phrase : phraseMap) {
if (flags & phrase.first) {
result.append('\n' + (prefix + phrase.second(tr::now)));
}
}
return result;
};
const auto kMinus = QChar(0x2212);
return withPrefix(plusFlags & ~minusFlags, '+')
+ withPrefix(minusFlags & ~plusFlags, kMinus);
};
TextWithEntities GenerateAdminChangeText(
not_null<ChannelData*> channel,
const TextWithEntities &user,
ChatAdminRightsInfo newRights,
ChatAdminRightsInfo prevRights) {
using Flag = ChatAdminRight;
using Flags = ChatAdminRights;
auto result = tr::lng_admin_log_promoted(
tr::now,
lt_user,
user,
Ui::Text::WithEntities);
const auto useInviteLinkPhrase = channel->isMegagroup()
&& channel->anyoneCanAddMembers();
const auto invitePhrase = useInviteLinkPhrase
? tr::lng_admin_log_admin_invite_link
: tr::lng_admin_log_admin_invite_users;
const auto callPhrase = channel->isBroadcast()
? tr::lng_admin_log_admin_manage_calls_channel
: tr::lng_admin_log_admin_manage_calls;
static auto phraseMap = std::map<Flags, tr::phrase<>>{
{Flag::ChangeInfo, tr::lng_admin_log_admin_change_info},
{Flag::PostMessages, tr::lng_admin_log_admin_post_messages},
{Flag::EditMessages, tr::lng_admin_log_admin_edit_messages},
{Flag::DeleteMessages, tr::lng_admin_log_admin_delete_messages},
{Flag::BanUsers, tr::lng_admin_log_admin_ban_users},
{Flag::InviteByLinkOrAdd, invitePhrase},
{Flag::ManageTopics, tr::lng_admin_log_admin_manage_topics},
{Flag::PinMessages, tr::lng_admin_log_admin_pin_messages},
{Flag::ManageCall, tr::lng_admin_log_admin_manage_calls},
{Flag::AddAdmins, tr::lng_admin_log_admin_add_admins},
{Flag::Anonymous, tr::lng_admin_log_admin_remain_anonymous},
};
phraseMap[Flag::InviteByLinkOrAdd] = invitePhrase;
phraseMap[Flag::ManageCall] = callPhrase;
if (!channel->isMegagroup()) {
// Don't display "Ban users" changes in channels.
newRights.flags &= ~Flag::BanUsers;
prevRights.flags &= ~Flag::BanUsers;
}
const auto changes = CollectChanges(
phraseMap,
newRights.flags,
prevRights.flags);
if (!changes.isEmpty()) {
result.text.append('\n' + changes);
}
return result;
};
QString GeneratePermissionsChangeText(
ChatRestrictionsInfo newRights,
ChatRestrictionsInfo prevRights) {
using Flag = ChatRestriction;
using Flags = ChatRestrictions;
static auto phraseMap = std::map<Flags, tr::phrase<>>{
{Flag::ViewMessages, tr::lng_admin_log_banned_view_messages},
{Flag::SendOther, tr::lng_admin_log_banned_send_messages},
{Flag::SendPhotos, tr::lng_admin_log_banned_send_photos},
{Flag::SendVideos, tr::lng_admin_log_banned_send_videos},
{Flag::SendMusic, tr::lng_admin_log_banned_send_music},
{Flag::SendFiles, tr::lng_admin_log_banned_send_files},
{
Flag::SendVoiceMessages,
tr::lng_admin_log_banned_send_voice_messages
},
{
Flag::SendVideoMessages,
tr::lng_admin_log_banned_send_video_messages
},
{
Flag::SendStickers
| Flag::SendGifs
| Flag::SendInline
| Flag::SendGames,
tr::lng_admin_log_banned_send_stickers
},
{Flag::EmbedLinks, tr::lng_admin_log_banned_embed_links},
{Flag::SendPolls, tr::lng_admin_log_banned_send_polls},
{Flag::ChangeInfo, tr::lng_admin_log_admin_change_info},
{Flag::AddParticipants, tr::lng_admin_log_admin_invite_users},
{Flag::CreateTopics, tr::lng_admin_log_admin_create_topics},
{Flag::PinMessages, tr::lng_admin_log_admin_pin_messages},
};
return CollectChanges(phraseMap, prevRights.flags, newRights.flags);
}
TextWithEntities GeneratePermissionsChangeText(
PeerId participantId,
const TextWithEntities &user,
ChatRestrictionsInfo newRights,
ChatRestrictionsInfo prevRights) {
using Flag = ChatRestriction;
const auto newFlags = newRights.flags;
const auto newUntil = newRights.until;
const auto prevFlags = prevRights.flags;
const auto indefinitely = ChannelData::IsRestrictedForever(newUntil);
if (newFlags & Flag::ViewMessages) {
return tr::lng_admin_log_banned(
tr::now,
lt_user,
user,
Ui::Text::WithEntities);
} else if (newFlags == 0
&& (prevFlags & Flag::ViewMessages)
&& !peerIsUser(participantId)) {
return tr::lng_admin_log_unbanned(
tr::now,
lt_user,
user,
Ui::Text::WithEntities);
}
const auto untilText = indefinitely
? tr::lng_admin_log_restricted_forever(tr::now)
: tr::lng_admin_log_restricted_until(
tr::now,
lt_date,
langDateTime(base::unixtime::parse(newUntil)));
auto result = tr::lng_admin_log_restricted(
tr::now,
lt_user,
user,
lt_until,
TextWithEntities{untilText},
Ui::Text::WithEntities);
const auto changes = GeneratePermissionsChangeText(newRights, prevRights);
if (!changes.isEmpty()) {
result.text.append('\n' + changes);
}
return result;
}
QString PublicJoinLink() {
return u"(public_join_link)"_q;
}
QString ExtractInviteLink(const MTPExportedChatInvite &data) {
return data.match([&](const MTPDchatInviteExported &data)
{
return qs(data.vlink());
},
[&](const MTPDchatInvitePublicJoinRequests &data)
{
return PublicJoinLink();
});
}
QString ExtractInviteLinkLabel(const MTPExportedChatInvite &data) {
return data.match([&](const MTPDchatInviteExported &data)
{
return qs(data.vtitle().value_or_empty());
},
[&](const MTPDchatInvitePublicJoinRequests &data)
{
return PublicJoinLink();
});
}
QString InternalInviteLinkUrl(const MTPExportedChatInvite &data) {
const auto base64 = ExtractInviteLink(data).toUtf8().toBase64();
return "internal:show_invite_link/?link=" + QString::fromLatin1(base64);
}
QString GenerateInviteLinkText(const MTPExportedChatInvite &data) {
const auto label = ExtractInviteLinkLabel(data);
return label.isEmpty()
? ExtractInviteLink(data).replace(
u"https://"_q,
QString()
).replace(
u"t.me/joinchat/"_q,
QString()
)
: label;
}
TextWithEntities GenerateInviteLinkLink(const MTPExportedChatInvite &data) {
const auto text = GenerateInviteLinkText(data);
return text.endsWith(Ui::kQEllipsis)
? TextWithEntities{.text = text}
: Ui::Text::Link(text, InternalInviteLinkUrl(data));
}
TextWithEntities GenerateInviteLinkChangeText(
const MTPExportedChatInvite &newLink,
const MTPExportedChatInvite &prevLink) {
auto link = TextWithEntities{GenerateInviteLinkText(newLink)};
if (!link.text.endsWith(Ui::kQEllipsis)) {
link.entities.push_back({
EntityType::CustomUrl,
0,
int(link.text.size()),
InternalInviteLinkUrl(newLink)
});
}
auto result = tr::lng_admin_log_edited_invite_link(
tr::now,
lt_link,
link,
Ui::Text::WithEntities);
result.text.append('\n');
const auto label = [](const MTPExportedChatInvite &link)
{
return link.match([](const MTPDchatInviteExported &data)
{
return qs(data.vtitle().value_or_empty());
},
[&](const MTPDchatInvitePublicJoinRequests &data)
{
return PublicJoinLink();
});
};
const auto expireDate = [](const MTPExportedChatInvite &link)
{
return link.match([](const MTPDchatInviteExported &data)
{
return data.vexpire_date().value_or_empty();
},
[&](const MTPDchatInvitePublicJoinRequests &data)
{
return TimeId();
});
};
const auto usageLimit = [](const MTPExportedChatInvite &link)
{
return link.match([](const MTPDchatInviteExported &data)
{
return data.vusage_limit().value_or_empty();
},
[&](const MTPDchatInvitePublicJoinRequests &data)
{
return 0;
});
};
const auto requestApproval = [](const MTPExportedChatInvite &link)
{
return link.match([](const MTPDchatInviteExported &data)
{
return data.is_request_needed();
},
[&](const MTPDchatInvitePublicJoinRequests &data)
{
return true;
});
};
const auto wrapDate = [](TimeId date)
{
return date
? langDateTime(base::unixtime::parse(date))
: tr::lng_group_invite_expire_never(tr::now);
};
const auto wrapUsage = [](int count)
{
return count
? QString::number(count)
: tr::lng_group_invite_usage_any(tr::now);
};
const auto wasLabel = label(prevLink);
const auto nowLabel = label(newLink);
const auto wasExpireDate = expireDate(prevLink);
const auto nowExpireDate = expireDate(newLink);
const auto wasUsageLimit = usageLimit(prevLink);
const auto nowUsageLimit = usageLimit(newLink);
const auto wasRequestApproval = requestApproval(prevLink);
const auto nowRequestApproval = requestApproval(newLink);
if (wasLabel != nowLabel) {
result.text.append('\n').append(
tr::lng_admin_log_invite_link_label(
tr::now,
lt_previous,
wasLabel,
lt_limit,
nowLabel));
}
if (wasExpireDate != nowExpireDate) {
result.text.append('\n').append(
tr::lng_admin_log_invite_link_expire_date(
tr::now,
lt_previous,
wrapDate(wasExpireDate),
lt_limit,
wrapDate(nowExpireDate)));
}
if (wasUsageLimit != nowUsageLimit) {
result.text.append('\n').append(
tr::lng_admin_log_invite_link_usage_limit(
tr::now,
lt_previous,
wrapUsage(wasUsageLimit),
lt_limit,
wrapUsage(nowUsageLimit)));
}
if (wasRequestApproval != nowRequestApproval) {
result.text.append('\n').append(
nowRequestApproval
? tr::lng_admin_log_invite_link_request_needed(tr::now)
: tr::lng_admin_log_invite_link_request_not_needed(tr::now));
}
result.entities.push_front(
EntityInText(EntityType::Italic, 0, result.text.size()));
return result;
};
auto GenerateParticipantString(
not_null<Main::Session*> session,
PeerId participantId) {
// User name in "User name (@username)" format with entities.
const auto peer = session->data().peer(participantId);
auto name = TextWithEntities{peer->name()};
if (const auto user = peer->asUser()) {
const auto data = TextUtilities::MentionNameDataFromFields({
.selfId = session->userId().bare,
.userId = peerToUser(user->id).bare,
.accessHash = user->accessHash(),
});
name.entities.push_back({
EntityType::MentionName,
0,
int(name.text.size()),
data,
});
}
const auto username = peer->username();
if (username.isEmpty()) {
return name;
}
auto mention = TextWithEntities{'@' + username};
mention.entities.push_back({
EntityType::Mention,
0,
int(mention.text.size())
});
return tr::lng_admin_log_user_with_username(
tr::now,
lt_name,
name,
lt_mention,
mention,
Ui::Text::WithEntities);
}
auto GenerateParticipantChangeText(
not_null<ChannelData*> channel,
const Api::ChatParticipant &participant,
std::optional<Api::ChatParticipant> oldParticipant = std::nullopt) {
using Type = Api::ChatParticipant::Type;
const auto oldRights = oldParticipant
? oldParticipant->rights()
: ChatAdminRightsInfo();
const auto oldRestrictions = oldParticipant
? oldParticipant->restrictions()
: ChatRestrictionsInfo();
const auto generateOther = [&](PeerId participantId)
{
auto user = GenerateParticipantString(
&channel->session(),
participantId);
if (oldParticipant && oldParticipant->type() == Type::Admin) {
return GenerateAdminChangeText(
channel,
user,
ChatAdminRightsInfo(),
oldRights);
} else if (oldParticipant && oldParticipant->type() == Type::Banned) {
return GeneratePermissionsChangeText(
participantId,
user,
ChatRestrictionsInfo(),
oldRestrictions);
} else if (oldParticipant
&& oldParticipant->type() == Type::Restricted
&& (participant.type() == Type::Member
|| participant.type() == Type::Left)) {
return GeneratePermissionsChangeText(
participantId,
user,
ChatRestrictionsInfo(),
oldRestrictions);
}
return tr::lng_admin_log_invited(
tr::now,
lt_user,
user,
Ui::Text::WithEntities);
};
auto result = [&]
{
const auto &peerId = participant.id();
switch (participant.type()) {
case Api::ChatParticipant::Type::Creator: {
// No valid string here :(
const auto user = GenerateParticipantString(
&channel->session(),
peerId);
if (peerId == channel->session().userPeerId()) {
return GenerateAdminChangeText(
channel,
user,
participant.rights(),
oldRights);
}
return tr::lng_admin_log_transferred(
tr::now,
lt_user,
user,
Ui::Text::WithEntities);
}
case Api::ChatParticipant::Type::Admin: {
const auto user = GenerateParticipantString(
&channel->session(),
peerId);
return GenerateAdminChangeText(
channel,
user,
participant.rights(),
oldRights);
}
case Api::ChatParticipant::Type::Restricted:
case Api::ChatParticipant::Type::Banned: {
const auto user = GenerateParticipantString(
&channel->session(),
peerId);
return GeneratePermissionsChangeText(
peerId,
user,
participant.restrictions(),
oldRestrictions);
}
case Api::ChatParticipant::Type::Left:
case Api::ChatParticipant::Type::Member: return generateOther(peerId);
};
Unexpected("Participant type in GenerateParticipantChangeText.");
}();
result.entities.push_front(
EntityInText(EntityType::Italic, 0, result.text.size()));
return result;
}
TextWithEntities GenerateParticipantChangeText(
not_null<ChannelData*> channel,
const MTPChannelParticipant &participant,
std::optional<MTPChannelParticipant> oldParticipant = std::nullopt) {
return GenerateParticipantChangeText(
channel,
Api::ChatParticipant(participant, channel),
oldParticipant
? std::make_optional(Api::ChatParticipant(
*oldParticipant,
channel))
: std::nullopt);
}
TextWithEntities GenerateDefaultBannedRightsChangeText(
not_null<ChannelData*> channel,
ChatRestrictionsInfo rights,
ChatRestrictionsInfo oldRights) {
auto result = TextWithEntities{
tr::lng_admin_log_changed_default_permissions(tr::now)
};
const auto changes = GeneratePermissionsChangeText(rights, oldRights);
if (!changes.isEmpty()) {
result.text.append('\n' + changes);
}
result.entities.push_front(
EntityInText(EntityType::Italic, 0, result.text.size()));
return result;
}
[[nodiscard]] bool IsTopicClosed(const MTPForumTopic &topic) {
return topic.match([](const MTPDforumTopic &data)
{
return data.is_closed();
},
[](const MTPDforumTopicDeleted &)
{
return false;
});
}
[[nodiscard]] bool IsTopicHidden(const MTPForumTopic &topic) {
return topic.match([](const MTPDforumTopic &data)
{
return data.is_hidden();
},
[](const MTPDforumTopicDeleted &)
{
return false;
});
}
[[nodiscard]] TextWithEntities GenerateTopicLink(
not_null<ChannelData*> channel,
const MTPForumTopic &topic) {
return topic.match([&](const MTPDforumTopic &data)
{
return Ui::Text::Link(
Data::ForumTopicIconWithTitle(
data.vid().v,
data.vicon_emoji_id().value_or_empty(),
qs(data.vtitle())),
u"internal:url:https://t.me/c/%1/%2"_q.arg(
peerToChannel(channel->id).bare).arg(
data.vid().v));
},
[](const MTPDforumTopicDeleted &)
{
return TextWithEntities{u"Deleted"_q};
});
}
} // namespace
OwnedItem::OwnedItem(std::nullptr_t) {
}
OwnedItem::OwnedItem(
not_null<HistoryView::ElementDelegate*> delegate,
not_null<HistoryItem*> data)
: _data(data), _view(_data->createView(delegate)) {
}
OwnedItem::OwnedItem(OwnedItem &&other)
: _data(base::take(other._data)), _view(base::take(other._view)) {
}
OwnedItem &OwnedItem::operator=(OwnedItem &&other) {
_data = base::take(other._data);
_view = base::take(other._view);
return *this;
}
OwnedItem::~OwnedItem() {
clearView();
if (_data) {
_data->destroy();
}
}
void OwnedItem::refreshView(
not_null<HistoryView::ElementDelegate*> delegate) {
_view = _data->createView(delegate);
}
void OwnedItem::clearView() {
_view = nullptr;
}
void GenerateItems(
not_null<HistoryView::ElementDelegate*> delegate,
not_null<History*> history,
EditedMessage message,
Fn<void(OwnedItem item, TimeId sentDate, MsgId)> callback) {
PeerData *from = history->owner().userLoaded(message.fromId);
if (!from) {
from = history->owner().channelLoaded(message.fromId);
}
if (!from) {
from = reinterpret_cast<PeerData*>(history->owner().chatLoaded(message.fromId));
}
if (!from) {
return;
}
const auto date = message.entityCreateDate;
const auto addPart = [&](
not_null<HistoryItem*> item,
TimeId sentDate = 0,
MsgId realId = MsgId())
{
return callback(OwnedItem(delegate, item), sentDate, realId);
};
const auto fromName = from->name();
const auto fromLink = from->createOpenLink();
const auto fromLinkText = Ui::Text::Link(fromName, QString());
const auto makeSimpleTextMessage = [&](TextWithEntities &&text)
{
return history->makeMessage({
.id = history->nextNonHistoryEntryId(),
.flags = MessageFlag::HasFromId | MessageFlag::AdminLogEntry,
.from = from->id,
.date = date,
}, std::move(text), MTP_messageMediaEmpty());
};
const auto addSimpleTextMessage = [&](TextWithEntities &&text)
{
addPart(makeSimpleTextMessage(std::move(text)));
};
const auto text = QString::fromStdString(message.text);
addSimpleTextMessage(Ui::Text::WithEntities(text));
}
} // namespace EditedLog
@@ -5,6 +5,7 @@
//
// Copyright @Radolyn, 2024
#include "settings_ayu.h"
#include "ayu/ayu_settings.h"
#include "ayu/ui/boxes/edit_deleted_mark.h"
#include "ayu/ui/boxes/edit_edited_mark.h"
@@ -17,6 +18,7 @@
#include "main/main_session.h"
#include "settings/settings_common.h"
#include "storage/localstorage.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_ayu_styles.h"
#include "styles/style_basic.h"
#include "styles/style_boxes.h"
@@ -346,14 +348,14 @@ void AddCollapsibleToggle(not_null<Ui::VerticalLayout*> container,
}
void AddChooseButtonWithIconAndRightTextInner(not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller,
int initialState,
std::vector<QString> options,
rpl::producer<QString> text,
rpl::producer<QString> boxTitle,
const style::SettingsButton & st,
Settings::IconDescriptor && descriptor,
const Fn<void(int)> &setter) {
not_null<Window::SessionController*> controller,
int initialState,
std::vector<QString> options,
rpl::producer<QString> text,
rpl::producer<QString> boxTitle,
const style::SettingsButton &st,
Settings::IconDescriptor &&descriptor,
const Fn<void(int)> &setter) {
auto reactiveVal = container->lifetime().make_state<rpl::variable<int>>(initialState);
rpl::producer<QString> rightTextReactive = reactiveVal->value() | rpl::map(
@@ -505,7 +507,8 @@ void SetupGhostEssentials(not_null<Ui::VerticalLayout*> container) {
SetupGhostModeToggle(container);
auto markReadAfterActionVal = container->lifetime().make_state<rpl::variable<bool>>(settings->markReadAfterAction);
auto useScheduledMessagesVal = container->lifetime().make_state<rpl::variable<bool>>(settings->useScheduledMessages);
auto useScheduledMessagesVal = container->lifetime().make_state<rpl::variable<
bool>>(settings->useScheduledMessages);
AddButtonWithIcon(
container,
@@ -559,6 +562,28 @@ void SetupGhostEssentials(not_null<Ui::VerticalLayout*> container) {
container->lifetime());
AddSkip(container);
AddDividerText(container, tr::ayu_UseScheduledMessagesDescription());
AddSkip(container);
AddButtonWithIcon(
container,
tr::ayu_SendWithoutSoundByDefault(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->sendWithoutSound)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->sendWithoutSound);
}) | start_with_next(
[=](bool enabled)
{
settings->set_sendWithoutSound(enabled);
AyuSettings::save();
},
container->lifetime());
AddSkip(container);
AddDividerText(container, tr::ayu_SendWithoutSoundByDefaultDescription());
}
void SetupSpyEssentials(not_null<Ui::VerticalLayout*> container) {
@@ -603,6 +628,29 @@ void SetupSpyEssentials(not_null<Ui::VerticalLayout*> container) {
AyuSettings::save();
},
container->lifetime());
AddSkip(container);
AddDivider(container);
AddSkip(container);
AddButtonWithIcon(
container,
tr::ayu_MessageSavingSaveForBots(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->saveForBots)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->saveForBots);
}) | start_with_next(
[=](bool enabled)
{
settings->set_saveForBots(enabled);
AyuSettings::save();
},
container->lifetime());
}
void SetupMessageFilters(not_null<Ui::VerticalLayout*> container) {
@@ -863,6 +911,166 @@ void SetupContextMenuElements(not_null<Ui::VerticalLayout*> container,
AddDividerText(container, tr::ayu_SettingsContextMenuDescription());
}
void SetupMessageFieldElements(not_null<Ui::VerticalLayout*> container) {
auto settings = &AyuSettings::getInstance();
AddSkip(container);
AddSubsectionTitle(container, tr::ayu_MessageFieldElementsHeader());
AddButtonWithIcon(
container,
tr::ayu_MessageFieldElementAttach(),
st::settingsButton,
{&st::messageFieldAttachIcon}
)->toggleOn(
rpl::single(settings->showAttachButtonInMessageField)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->showAttachButtonInMessageField);
}) | start_with_next(
[=](bool enabled)
{
settings->set_showAttachButtonInMessageField(enabled);
AyuSettings::save();
},
container->lifetime());
AddButtonWithIcon(
container,
tr::ayu_MessageFieldElementCommands(),
st::settingsButton,
{&st::messageFieldCommandsIcon}
)->toggleOn(
rpl::single(settings->showCommandsButtonInMessageField)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->showCommandsButtonInMessageField);
}) | start_with_next(
[=](bool enabled)
{
settings->set_showCommandsButtonInMessageField(enabled);
AyuSettings::save();
},
container->lifetime());
AddButtonWithIcon(
container,
tr::ayu_MessageFieldElementTTL(),
st::settingsButton,
{&st::messageFieldTTLIcon}
)->toggleOn(
rpl::single(settings->showAutoDeleteButtonInMessageField)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->showAutoDeleteButtonInMessageField);
}) | start_with_next(
[=](bool enabled)
{
settings->set_showAutoDeleteButtonInMessageField(enabled);
AyuSettings::save();
},
container->lifetime());
AddButtonWithIcon(
container,
tr::ayu_MessageFieldElementEmoji(),
st::settingsButton,
{&st::messageFieldEmojiIcon}
)->toggleOn(
rpl::single(settings->showEmojiButtonInMessageField)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->showEmojiButtonInMessageField);
}) | start_with_next(
[=](bool enabled)
{
settings->set_showEmojiButtonInMessageField(enabled);
AyuSettings::save();
},
container->lifetime());
AddButtonWithIcon(
container,
tr::ayu_MessageFieldElementVoice(),
st::settingsButton,
{&st::messageFieldVoiceIcon}
)->toggleOn(
rpl::single(settings->showMicrophoneButtonInMessageField)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->showMicrophoneButtonInMessageField);
}) | start_with_next(
[=](bool enabled)
{
settings->set_showMicrophoneButtonInMessageField(enabled);
AyuSettings::save();
},
container->lifetime());
AddSkip(container);
AddDivider(container);
}
void SetupMessageFieldPopups(not_null<Ui::VerticalLayout*> container) {
auto settings = &AyuSettings::getInstance();
AddSkip(container);
AddSubsectionTitle(container, tr::ayu_MessageFieldPopupsHeader());
AddButtonWithIcon(
container,
tr::ayu_MessageFieldElementAttach(),
st::settingsButton,
{&st::messageFieldAttachIcon}
)->toggleOn(
rpl::single(settings->showAttachPopup)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->showAttachPopup);
}) | start_with_next(
[=](bool enabled)
{
settings->set_showAttachPopup(enabled);
AyuSettings::save();
},
container->lifetime());
AddButtonWithIcon(
container,
tr::ayu_MessageFieldElementEmoji(),
st::settingsButton,
{&st::messageFieldEmojiIcon}
)->toggleOn(
rpl::single(settings->showEmojiPopup)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->showEmojiPopup);
}) | start_with_next(
[=](bool enabled)
{
settings->set_showEmojiPopup(enabled);
AyuSettings::save();
},
container->lifetime());
AddSkip(container);
AddDivider(container);
}
void SetupDrawerElements(not_null<Ui::VerticalLayout*> container) {
auto settings = &AyuSettings::getInstance();
@@ -1178,8 +1386,6 @@ void SetupSendConfirmations(not_null<Ui::VerticalLayout*> container) {
}
void SetupMarks(not_null<Ui::VerticalLayout*> container) {
auto settings = &AyuSettings::getInstance();
AddButtonWithLabel(
container,
tr::ayu_DeletedMarkText(),
@@ -1230,9 +1436,9 @@ void SetupFolderSettings(not_null<Ui::VerticalLayout*> container, not_null<Windo
// not about folders, but it's a good place for it
#ifdef Q_OS_WIN
AddButtonWithIcon(
container,
tr::ayu_HideNotificationBadge(),
st::settingsButtonNoIcon
container,
tr::ayu_HideNotificationBadge(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->hideNotificationBadge)
)->toggledValue(
@@ -1420,6 +1626,8 @@ void SetupCustomization(not_null<Ui::VerticalLayout*> container,
AddSkip(container);
AddDivider(container);
SetupContextMenuElements(container, controller);
SetupMessageFieldElements(container);
SetupMessageFieldPopups(container);
SetupDrawerElements(container);
AddSkip(container);
AddDivider(container);
+99 -24
View File
@@ -12,6 +12,33 @@
namespace AyuMapper {
constexpr auto kMessageFlagUnread = 0x00000001;
constexpr auto kMessageFlagOut = 0x00000002;
constexpr auto kMessageFlagForwarded = 0x00000004;
constexpr auto kMessageFlagReply = 0x00000008;
constexpr auto kMessageFlagMention = 0x00000010;
constexpr auto kMessageFlagContentUnread = 0x00000020;
constexpr auto kMessageFlagHasMarkup = 0x00000040;
constexpr auto kMessageFlagHasEntities = 0x00000080;
constexpr auto kMessageFlagHasFromId = 0x00000100;
constexpr auto kMessageFlagHasMedia = 0x00000200;
constexpr auto kMessageFlagHasViews = 0x00000400;
constexpr auto kMessageFlagHasBotId = 0x00000800;
constexpr auto kMessageFlagIsSilent = 0x00001000;
constexpr auto kMessageFlagIsPost = 0x00004000;
constexpr auto kMessageFlagEdited = 0x00008000;
constexpr auto kMessageFlagHasPostAuthor = 0x00010000;
constexpr auto kMessageFlagIsGrouped = 0x00020000;
constexpr auto kMessageFlagFromScheduled = 0x00040000;
constexpr auto kMessageFlagHasReactions = 0x00100000;
constexpr auto kMessageFlagHideEdit = 0x00200000;
constexpr auto kMessageFlagRestricted = 0x00400000;
constexpr auto kMessageFlagHasReplies = 0x00800000;
constexpr auto kMessageFlagIsPinned = 0x01000000;
constexpr auto kMessageFlagHasTTL = 0x02000000;
constexpr auto kMessageFlagInvertMedia = 0x08000000;
constexpr auto kMessageFlagHasSavedPeer = 0x10000000;
std::pair<std::string, std::vector<char>> serializeTextWithEntities(not_null<HistoryItem*> item) {
if (item->emptyText()) {
return std::make_pair("", std::vector<char>());
@@ -27,64 +54,112 @@ int mapItemFlagsToMTPFlags(not_null<HistoryItem*> item) {
int flags = 0;
const auto thread = item->topic()
? (Data::Thread*) item->topic()
? reinterpret_cast<Data::Thread*>(item->topic())
: item->history();
const auto unseen = item->unread(thread);
if (unseen) {
flags |= 1;
if (item->unread(thread)) {
flags |= kMessageFlagUnread;
}
if (item->out()) {
flags |= 2;
flags |= kMessageFlagOut;
}
if (const auto reply = item->Get<HistoryMessageForwarded>()) {
flags |= 4;
if (item->Get<HistoryMessageForwarded>()) {
flags |= kMessageFlagForwarded;
}
if (const auto reply = item->Get<HistoryMessageReply>()) {
flags |= 8;
if (item->Get<HistoryMessageReply>()) {
flags |= kMessageFlagReply;
}
if (item->mentionsMe()) {
flags |= 16;
flags |= kMessageFlagMention;
}
if (item->isUnreadMedia()) {
flags |= 32;
flags |= kMessageFlagContentUnread;
}
if (item->definesReplyKeyboard()) {
flags |= kMessageFlagHasMarkup;
}
if (!item->originalText().entities.empty()) {
flags |= kMessageFlagHasEntities;
}
if (item->displayFrom()) {
// todo: maybe wrong
flags |= kMessageFlagHasFromId;
}
if (item->media()) {
flags |= kMessageFlagHasMedia;
}
if (item->hasViews()) {
flags |= kMessageFlagHasViews;
}
if (item->viaBot()) {
flags |= kMessageFlagHasBotId;
}
if (item->isSilent()) {
flags |= 8192;
flags |= kMessageFlagIsSilent;
}
if (item->isPost()) {
flags |= 16384;
flags |= kMessageFlagIsPost;
}
if (item->Get<HistoryMessageEdited>()) {
flags |= kMessageFlagEdited;
}
if (item->Get<HistoryMessageSigned>()) {
flags |= kMessageFlagHasPostAuthor;
}
if (item->groupId()) {
flags |= kMessageFlagIsGrouped;
}
if (item->isScheduled()) {
flags |= 262144;
flags |= kMessageFlagFromScheduled;
}
// todo: legacy
// if (item->isLegacy()) {
// flags |= 524288;
// }
if (!item->reactions().empty()) {
flags |= kMessageFlagHasReactions;
}
if (item->hideEditedBadge()) {
flags |= 2097152;
flags |= kMessageFlagHideEdit;
}
if (item->hasPossibleRestrictions()) {
flags |= kMessageFlagRestricted;
}
if (item->repliesCount() > 0) {
flags |= kMessageFlagHasReplies;
}
if (item->isPinned()) {
flags |= 16777216;
flags |= kMessageFlagIsPinned;
}
if (item->forbidsForward()) {
flags |= 67108864;
if (item->ttlDestroyAt() > 0) {
flags |= kMessageFlagHasTTL;
}
if (item->topic() && item->topicRootId() == item->id) {
flags |= 134217728;
if (item->invertMedia()) {
flags |= kMessageFlagInvertMedia;
}
if (item->savedFromSender()) {
// todo: maybe wrong
flags |= kMessageFlagHasSavedPeer;
}
return flags;

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