Compare commits

...

220 Commits

Author SHA1 Message Date
AlexeyZavar f73edfec94 Merge tag 'v5.2.2' into dev 2024-07-02 22:53:55 +03:00
AlexeyZavar a851bebc75 fix: a bunch of useful fixes 2024-07-02 22:06:56 +03:00
AlexeyZavar c4e1e8415c feat: hide notification badge on windows 2024-07-02 18:05:10 +03:00
John Preston a507d28b49 Version 5.2.2.
- Fix topics search in topic groups.
- Fix Instant View pages content updating.
2024-07-02 19:03:07 +04:00
AlexeyZavar b2efc2ad14 feat: jump to beginning 2024-07-02 17:29:20 +03:00
John Preston ec2faca145 Fix couple of crashes in secondary windows. 2024-07-02 18:08:24 +04:00
John Preston 17bb430006 Register tg:// scheme on first launch.
Also, allow disabling tg:// re-registration on update.
2024-07-02 13:34:52 +04:00
John Preston 8cbeadc68a Register tg:// scheme on initial launch. 2024-07-02 13:22:33 +04:00
John Preston 3947056654 Use cached views count from not modified page. 2024-07-02 10:40:39 +04:00
John Preston ad7d1fddf0 Reload IV on each open, take hash into account.
Fixes #28111.
2024-07-02 10:27:26 +04:00
John Preston ab20f8eb31 Fix topics search in topic groups.
Fixes #28110.
2024-07-02 09:53:56 +04:00
AlexeyZavar 257b8552f7 feat: channel bottom button configuration
Co-authored-by: Eric Kotato <radrussianrus@gmail.com>
2024-07-02 05:37:39 +03:00
AlexeyZavar bbeeaa95c0 feat: add win95 icon
Co-authored-by: Windukk <Windukk@users.noreply.github.com>
2024-07-02 01:21:54 +03:00
AlexeyZavar 81938514f1 feat: add chibi icons
meet AyuChan <3
2024-07-02 00:23:29 +03:00
AlexeyZavar 4e0fde560c fix: generate more ico sizes 2024-07-01 22:54:32 +03:00
AlexeyZavar 27d3721646 feat: webview settings 2024-07-01 22:47:39 +03:00
AlexeyZavar dbb234097c feat: round stickers in list 2024-07-01 21:33:02 +03:00
John Preston f75429cbaa Version 5.2.1: Shorten webview socket path.
Fixes #28106.
2024-07-01 21:35:39 +04:00
John Preston dc8c4a8332 Version 5.2.1: No auto-enable system password unlock on macOS. 2024-07-01 21:03:05 +04:00
John Preston 096530c96a Version 5.2.1: Fix drafts / translations crash on macOS. 2024-07-01 19:21:27 +04:00
23rd ed0850d823 Renamed files for bot and channel earn sections with different names. 2024-07-01 15:40:39 +03:00
John Preston 4a2173deaf Version 5.2.1.
- Fix crash when opening topic in a new window.
- Fix crash in topic search scope dropdown.
- Fix crash in video player.
- Fix feeze and crash in Instant View (Windows).
- Allow unlock by Apple Watch or System Password (macOS).
2024-07-01 15:01:35 +04:00
John Preston f40a584905 Support unlock with Watch/SystemPassword. 2024-07-01 15:01:35 +04:00
John Preston e54204b136 Don't allow forwarding local items by drag. 2024-07-01 13:20:45 +04:00
John Preston 715dff0a3e Fix a crash and a memory leak in video player.
Fixes #28104.
2024-07-01 11:03:19 +04:00
23rd 558daa3382 Fixed align of icons in list of top-up credit options. 2024-07-01 10:50:52 +04:00
GitHub Action 7265297b19 Update User-Agent for DNS to Chrome 126.0.0.0. 2024-07-01 10:49:45 +04:00
John Preston 1fac6db8bd Fix crash in topic search context menu destruction. 2024-07-01 10:46:34 +04:00
John Preston c9bd776d1e Fix freeze in IV due to cyclic focus request. 2024-07-01 10:38:41 +04:00
John Preston 179e81478e Ignore filter switching in separate window archive. 2024-07-01 09:21:18 +04:00
John Preston 9ef74c510c Fix crash in opening topics in a new window. 2024-07-01 09:07:45 +04:00
Ilya Fedin 36f6917bd3 Query QWindow::windowState in media viewer 2024-07-01 07:56:55 +04:00
AlexeyZavar c185f40acd feat: enter with ghost mode from taskbar or command line 2024-07-01 06:04:14 +03:00
AlexeyZavar 75bcd2b24b feat: show DC for users 2024-07-01 04:58:39 +03:00
AlexeyZavar ab7e4bce1a fix: make it build 2024-07-01 04:38:41 +03:00
AlexeyZavar da797a2b07 Merge tag 'v5.2.0' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/calls/calls_call.cpp
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/history/view/media/history_view_gif.cpp
#	Telegram/SourceFiles/window/notifications_manager_default.cpp
#	Telegram/lib_ui
#	snap/snapcraft.yaml
2024-07-01 04:17:59 +03:00
John Preston 707951accb Version 5.2: Fix build with GCC. 2024-06-30 23:59:03 +04:00
John Preston 7eb98b50ec Version 5.2.
- Pay for content with Telegram Stars.
- Enable local passcode unlock by Windows Hello and Touch ID.
- Allow opening forums, topics and archive in a separate window.
2024-06-30 21:21:51 +04:00
John Preston 65f7bdb914 Update API scheme on layer 183. 2024-06-30 21:16:11 +04:00
John Preston 876c47c436 Add 'section_separator_color' to webview palette. 2024-06-30 21:16:11 +04:00
John Preston e8f16840de Fix wrong search focusing.
Fixes #28052.
2024-06-30 21:16:11 +04:00
John Preston dd57ad567f Don't break by '/', '.' in the middle of the word.
Fixes #27999.
2024-06-30 21:16:11 +04:00
John Preston 54934fb835 Fix problems with message effect preview. 2024-06-30 21:16:11 +04:00
John Preston bd49887607 Fix paid media price tag background. 2024-06-30 21:16:11 +04:00
John Preston aaa72b7c30 Improve system unlock button area. 2024-06-30 21:16:10 +04:00
John Preston 4cafacc8db Add message effects promo section. 2024-06-30 21:16:10 +04:00
John Preston 374b3c68ac Fix cancel search with a similar channel open.
Fixes #28079.
2024-06-30 21:16:10 +04:00
John Preston 69d21f73ef Separate window for forums/topics/sublists/archive. 2024-06-30 21:16:10 +04:00
23rd 6dc3bd65e8 Improved spell checking on macOS. 2024-06-30 21:16:10 +04:00
23rd deb9aa435b Improved first display of personal channel in user profiles. 2024-06-30 21:16:10 +04:00
23rd 68cb568898 Fixed build with Qt6. 2024-06-30 21:16:10 +04:00
23rd 1ed81b1c9c Improved process of mtp updates for revenue credits in earn section. 2024-06-30 21:16:10 +04:00
23rd a95fb5b28d Slightly improved withdraw phrases to fit small buttons. 2024-06-30 21:16:10 +04:00
23rd 4f7b5ca7da Added process of server notification for disabled withdrawal feature. 2024-06-30 21:16:10 +04:00
23rd 29b7673b88 Simplified handle of incoming credit history entries. 2024-06-30 21:16:10 +04:00
23rd 66f375d2c6 Fixed endless memory copying in list of credits history entries. 2024-06-30 21:16:10 +04:00
John Preston 77d214d2a5 Support paid_media_allowed flag in ChannelFull. 2024-06-30 21:16:10 +04:00
John Preston 09e6077e97 Suggest global search of cashtags. 2024-06-30 21:16:10 +04:00
John Preston 631d6abb06 Improve formatting in message field. 2024-06-30 21:16:10 +04:00
John Preston c833b8a1b0 Make purchased media badge better looking. 2024-06-30 21:16:10 +04:00
John Preston b58c03f0de Fix build with Xcode. 2024-06-30 21:16:10 +04:00
John Preston 1988435cdf Add a Windows Hello / Touch ID system unlock. 2024-06-30 21:16:10 +04:00
John Preston 7e704d9529 Show price in my/purchased paid media. 2024-06-30 21:16:10 +04:00
John Preston a39a8dbd2c Show paid media from transactions history. 2024-06-30 21:16:10 +04:00
John Preston 90dfae52f5 Show nice thumbnails for paid albums. 2024-06-30 21:16:10 +04:00
John Preston dfc422b505 Show paid media albums with context. 2024-06-30 21:16:10 +04:00
John Preston 54cc12cf22 Show media payments as outgoing. 2024-06-30 21:16:10 +04:00
John Preston d81e832ae6 Use lang key for about stars link. 2024-06-30 21:16:10 +04:00
John Preston 1399d2501d Show first paid media in transactions history. 2024-06-30 21:16:09 +04:00
John Preston 57254ca259 Show a credits emoji in chats list preview. 2024-06-30 21:16:09 +04:00
John Preston 043e3ae97e Use star emoji fallback for credits custom emoji. 2024-06-30 21:16:09 +04:00
John Preston 68b9a8bc6a Fix file reference refresh for paid media. 2024-06-30 21:16:09 +04:00
23rd 157d5c743b Renamed file for data of credits earn statistics. 2024-06-30 21:16:09 +04:00
23rd 54d0290ba2 Added warning to channel earn section when user has no cloud password. 2024-06-30 21:16:09 +04:00
23rd 0fc2df8eec Added transaction link and date to details of credits history entries. 2024-06-30 21:16:09 +04:00
23rd d9caf15d1d Added initial ability to reinvest existing credits for channels. 2024-06-30 21:16:09 +04:00
23rd b674826392 Added special widget for credits input to section of channel earn. 2024-06-30 21:16:09 +04:00
23rd 37181f9d0a Moved out special widget for credits input to single place. 2024-06-30 21:16:09 +04:00
23rd 93aebc747d Moved out special input for credits to td_ui. 2024-06-30 21:16:09 +04:00
23rd a84ac933dd Added support of api update to history lists in section of channel earn. 2024-06-30 21:16:09 +04:00
23rd b79c306bfe Added list of credits history to section of channel earn. 2024-06-30 21:16:09 +04:00
23rd 57d62423b3 Moved out custom slider class with natural width to single place. 2024-06-30 21:16:09 +04:00
23rd f4674389d5 Added chart of credits revenue to section of channel earn. 2024-06-30 21:16:09 +04:00
23rd 63c4c5064f Added support of api updates for overview in channel earn section. 2024-06-30 21:16:09 +04:00
23rd ae1f364730 Added rpl support to label with icon in section of channel earn. 2024-06-30 21:16:09 +04:00
23rd c6e322de86 Added credits oveview to section of channel earn. 2024-06-30 21:16:09 +04:00
23rd 68bf6f991c Moved out util for wrapping credits icon to widget. 2024-06-30 21:16:09 +04:00
23rd b15f5f8596 Added credits data to saved state of channel earn section. 2024-06-30 21:16:09 +04:00
23rd 27a71a8dcd Renamed BotEarnStatistics to CreditsEarnStatistics. 2024-06-30 21:16:08 +04:00
John Preston 2044f8f9ad Update API scheme on layer 183. 2024-06-30 21:16:08 +04:00
23rd ffa4b1db87 Fixed withdrawal button for credits with minimal amount. 2024-06-30 21:16:08 +04:00
23rd cad25ae644 Fixed unique row id in lists of credits history entries. 2024-06-30 21:16:08 +04:00
23rd 21094fe11b Slightly improved process of incoming credit history entries. 2024-06-30 21:16:08 +04:00
23rd 101dbdf243 Added support of MTP updates to lists of credits history entries. 2024-06-30 21:16:08 +04:00
John Preston 0dc92762bc Show link to message in transactions history. 2024-06-30 21:16:08 +04:00
John Preston 5fdaa6b91f Record bareMsgId in CreditsHistoryEntry. 2024-06-30 21:16:08 +04:00
John Preston 968d036834 Use Ui::NumberInput for the paid media price. 2024-06-30 21:16:08 +04:00
John Preston d47c5df73d Nice price tag on sending media. 2024-06-30 21:16:08 +04:00
John Preston 6c1e7357c6 Nice unlock media stars, unlock done tooltip. 2024-06-30 21:16:08 +04:00
John Preston 479b63c33a Customize pay-by-stars box for paid media. 2024-06-30 21:16:08 +04:00
John Preston 950a946a16 Show correct chat preview for paid media. 2024-06-30 21:16:08 +04:00
John Preston 5f8da27c86 Display nice price tag, handle pay in albums. 2024-06-30 21:16:08 +04:00
John Preston a9bd7803e6 Edit price on send, send single paid media. 2024-06-30 21:16:08 +04:00
John Preston 3ece9b1566 Update API scheme to layer 183. Paid media. 2024-06-30 21:16:08 +04:00
John Preston e71a067f4b Fix build on Windows. 2024-06-30 21:16:08 +04:00
23rd ebf456abe4 Added initial support of lists for credits history entries in bot earn. 2024-06-30 21:16:08 +04:00
23rd 3552da5ce7 Added additional row in table for some types of credits history entries. 2024-06-30 21:16:08 +04:00
23rd b5bd0f53ad Added support of new statuses of credits history entries. 2024-06-30 21:16:08 +04:00
23rd 7d115b3fab Improved api support to credit history entries. 2024-06-30 21:16:08 +04:00
23rd d0a030ab58 Added support of minimal amount of credits to withdrawal button. 2024-06-30 21:16:08 +04:00
23rd 712c06756e Added icon to label in withdrawal button from bot earn section. 2024-06-30 21:16:08 +04:00
23rd 301ffc15ef Added countdown label to withdrawal button in bot earn section. 2024-06-30 21:16:07 +04:00
23rd 3c4a711b5d Added withdrawal button to bot earn sections. 2024-06-30 21:16:07 +04:00
23rd 989145726d Made withdrawal button handler in earn sections more universal. 2024-06-30 21:16:07 +04:00
23rd 9eebd3b514 Added statistical chart and balance overview to bot earn section. 2024-06-30 21:16:07 +04:00
23rd eb997ae9e3 Added initial implementation of filter for MTP updates. 2024-06-30 21:16:07 +04:00
23rd db4c9b83f3 Added credits icon to statistical charts. 2024-06-30 21:16:07 +04:00
23rd 1196b6a3fb Moved out generating of credits icon to td_ui. 2024-06-30 21:16:07 +04:00
23rd bef216bc93 Moved out colorizing of svg star to td_ui. 2024-06-30 21:16:07 +04:00
23rd 811d75e383 Improved display of different inner currencies in statistical charts. 2024-06-30 21:16:07 +04:00
23rd 049cde48ee Added initial api support of bot earn statistics. 2024-06-30 21:16:07 +04:00
23rd cb65c50c19 Moved out deserialization of MTP statistical graph to separated file. 2024-06-30 21:16:07 +04:00
23rd f23c9a61bc Moved out StatisticsRequestSender to separated file. 2024-06-30 21:16:07 +04:00
23rd b5d5ff3cbb Improved naming of classes for channel earn. 2024-06-30 21:16:07 +04:00
23rd c5ba0fa705 Added initial structure for bot earn data. 2024-06-30 21:16:07 +04:00
23rd 71893f4ef7 Added initial implementation of entry point to bot earn section. 2024-06-30 21:16:07 +04:00
23rd 4a60c57661 Added dummy files of bot earn section. 2024-06-30 21:16:07 +04:00
John Preston fbbcc21198 Update API scheme to layer 182. 2024-06-30 21:16:07 +04:00
Ilya Fedin d993386756 Fix debug-only openssl build on Windows 2024-06-30 11:31:57 +04:00
Ilya Fedin 30819509d3 Set shortcut context for global menu shortcuts 2024-06-30 10:11:40 +04:00
mrbesen 10c3fe0f63 add option to export html and json in global export 2024-06-27 10:49:39 +04:00
arenekosreal bad2ff00a8 fix: use correct executable path (#12)
This file was added by https://github.com/AyuGram/AyuGramDesktop/pull/10, but it did not use correct executable name. After installing, the executable name is `ayugram-desktop`, which will result that AyuGramDesktop cannot be activated by DBus on Linux.
2024-06-27 03:54:30 +03:00
Ilya Fedin 3498a7f0ee Update submodules 2024-06-24 16:23:32 +04:00
Ilya Fedin 648b23b548 Do non-getting XCB requests synchronously 2024-06-24 16:23:32 +04:00
Ilya Fedin ba89912834 Switch more XCB code to base::Platform::XCB::Connection 2024-06-24 16:23:32 +04:00
Ilya Fedin c1bc7e6ab1 Simplify PipPanel::handleWaylandResize 2024-06-22 11:32:36 +04:00
Ilya Fedin eea50ed6b0 Delay UpdatePowerSaveBlocker to show in media viewer 2024-06-22 11:32:36 +04:00
Ilya Fedin 006d6fe2c0 Use RpWidget::screenValue 2024-06-22 11:32:36 +04:00
Ilya Fedin 5180e0ec57 Use QWidget::setScreen with Qt 6 2024-06-22 11:32:36 +04:00
Ilya Fedin 490ec7949f Don't call hide/createWinId just to call show right after that in Window::Notifications::Default::HideAllButton 2024-06-22 11:32:36 +04:00
Ilya Fedin 671a15d763 Update skip taskbar hint on Linux without QWindow events 2024-06-22 11:32:36 +04:00
Ilya Fedin d2d5226dc7 Update exposed state for connecting widgets without QWindow events 2024-06-22 11:32:36 +04:00
Ilya Fedin b58ece3a38 Update lib_ui 2024-06-22 11:32:36 +04:00
Ilya Fedin 2b4a2b5b97 Fix a crash in Dialogs::Widget::setupStories 2024-06-22 11:32:36 +04:00
Ilya Fedin 382b175db2 Fix build on Linux 2024-06-22 11:32:36 +04:00
John Preston 2db81211c8 Fix configure on macOS. 2024-06-21 22:38:49 +04:00
John Preston 46157c99c4 Allow saving empty syntax highlight language. 2024-06-21 22:38:49 +04:00
John Preston c3ed5224c2 Use tripple-enter to jump out of a block. 2024-06-21 22:38:49 +04:00
John Preston acee7c7cfc More delay-load libraries on Windows with Qt 6. 2024-06-21 13:25:48 +04:00
John Preston 002fe9a72a Fix build. 2024-06-21 11:55:25 +04:00
John Preston 93b7c47cda Support building on Windows with Qt 6. 2024-06-21 11:36:18 +04:00
Ilya Fedin 053f8ad1c0 Ensure media viewer has native window handle before using it 2024-06-21 08:19:44 +04:00
Ilya Fedin 60ca6895db Update submodules 2024-06-19 10:33:33 +04:00
Ilya Fedin fc5e9414b7 Subscribe to QEvent::WindowStateChange instead of QWindow::windowStateChanged 2024-06-19 10:33:33 +04:00
Ilya Fedin f768e405fa Use RpWidget::shownValue instead of QWindow::visibleChanged 2024-06-19 10:33:33 +04:00
Ilya Fedin a22cf8e303 Use RpWidget::windowActiveValue 2024-06-19 10:33:33 +04:00
Ilya Fedin 8a5797e1bd Re-create QSystemTrayIcon on SNI watcher owner change 2024-06-19 10:31:59 +04:00
Ilya Fedin 750ad600be Store media viewer geometry the same way as main window 2024-06-19 10:08:14 +04:00
Ilya Fedin eaf4575eb8 Fix IV window geometry restoration 2024-06-19 10:08:14 +04:00
Ilya Fedin b9677fe1db Update Qt to 6.7.2 on Linux 2024-06-18 22:01:23 +04:00
Ilya Fedin 4047f1733d Update submodules 2024-06-16 20:59:32 +04:00
John Preston 3d114131e0 Fix premium gifting recipient choosing. 2024-06-16 10:27:38 +04:00
John Preston 5810149a77 Improve chats search loading indication. 2024-06-16 10:27:38 +04:00
Ilya Fedin 032fe3e0fc Remove std::optional indrection for nullable XCB types 2024-06-16 09:54:04 +04:00
John Preston 81d7fcba7e Beta version 5.1.8: Fix build with GCC. 2024-06-15 23:03:55 +04:00
John Preston 4e9b5b0d33 Beta version 5.1.8: Fix build. 2024-06-15 22:45:21 +04:00
John Preston 90068f6261 Beta version 5.1.8: Update tg_owt on Linux. 2024-06-15 21:16:55 +04:00
John Preston f37d056c14 Beta version 5.1.8.
- Support nice blockquotes and code blocks edition when composing messages.
- Support collapsing blockquotes and specifying syntax highlight language.
- Support nice spoiler animation in the message composing input field.
2024-06-15 21:06:23 +04:00
John Preston f748988ae3 Update Qt patches. 2024-06-15 20:59:19 +04:00
John Preston 9a25d2c413 Simplify correct unicode characters counting. 2024-06-15 20:57:48 +04:00
John Preston ec40292cbf Allow editing of collapsed quotes. 2024-06-15 20:57:30 +04:00
John Preston 5e8c3fb146 Allow editing syntax highlighting language. 2024-06-15 20:57:00 +04:00
John Preston fa8ed186d8 Improve field fade conditions. 2024-06-15 20:56:45 +04:00
John Preston c1f36d43d0 Support modern blockquote/pre display. 2024-06-15 20:56:44 +04:00
John Preston 501cae2200 Change InputField::font to InputField::style in styles. 2024-06-15 20:56:24 +04:00
John Preston 8ad5117495 Update lib_ui. 2024-06-15 20:55:09 +04:00
Ilya Fedin d79da3d884 Remove old notification descturction workaround for old X11 systems
There seem to be no need in it anymore
2024-06-15 11:08:06 +04:00
Ilya Fedin e4d88f829c Remove old window activation workaround for X11 systems
There seem to be no need in it anymore
2024-06-15 11:08:06 +04:00
Ilya Fedin 2673e1df53 Fix IV window on Linux 2024-06-15 11:04:45 +04:00
AlexeyZavar 081890ef61 fix: mono font when none is selected 2024-06-14 22:28:09 +03:00
AlexeyZavar cbcde7d2f5 fix: make it build 2024-06-14 22:27:52 +03:00
AlexeyZavar 68ad4aeaf8 Merge tag 'v5.1.7' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/lib_ui
#	snap/snapcraft.yaml
2024-06-14 22:10:29 +03:00
John Preston 99e88d74bc Version 5.1.7: Fix build with Qt 6. 2024-06-14 19:06:19 +04:00
John Preston 43ffc9d67c Version 5.1.7.
- Fix recently searched hashtags in chats search.
- Fix formatting shortcuts on macOS.
- Fix non-Telegram-Stars-invoice bot buttons with star emoji.
2024-06-14 18:36:28 +04:00
John Preston 053c462dc0 Fix recent hashtags in chats search. 2024-06-14 18:34:59 +04:00
John Preston 174b627a78 Fix markdown shortcuts on macOS / some Linux. 2024-06-14 17:39:16 +04:00
23rd bb33d0b997 Replaced credits currency with icon only in buttons with Buy type. 2024-06-14 15:32:02 +03:00
pandaninjas 6f6fb3d1b6 Add xlsb to list of executable extensions 2024-06-14 13:49:15 +04:00
Ilya Fedin 3f216ad946 Enable parallelism for more dependencies 2024-06-13 21:35:34 +04:00
John Preston c49eb7041f Version 5.1.6: Fix sticker effect filtering. 2024-06-13 20:55:49 +04:00
John Preston a1d8202644 Version 5.1.6.
- Fix search in archived chats in single-column layout.
- Improve chat previews for topics, Saved Messages and groups.
- Fix formatting shortcuts on Linux.
- Fix options for Telegram Stars buying in case of large amounts.
2024-06-13 18:48:35 +04:00
23rd 82428aef28 Added support for quoted-printable encoding to contact media. 2024-06-13 18:44:33 +04:00
23rd 10f7b985c7 Added decimal separators to count of members in shared similar channels. 2024-06-13 18:44:33 +04:00
23rd 06075411a5 Fixed cases when list of top-up credit options is empty. 2024-06-13 18:44:33 +04:00
23rd 7e01b12825 Replaced credits currency with icon in buttons of reply keyboard. 2024-06-13 18:44:33 +04:00
John Preston 273119fc55 Fix preview messages load in migrated groups. 2024-06-13 18:43:58 +04:00
John Preston e47e4ba338 Update submodules. 2024-06-13 18:08:43 +04:00
John Preston cbcdeae200 Don't show topic buttons in topic preview. 2024-06-13 18:08:36 +04:00
John Preston c585112e37 Fix jump to archive from search in chat. 2024-06-13 16:33:58 +04:00
John Preston 392df8b56f Fix search in archived chats and return back. 2024-06-13 16:24:41 +04:00
John Preston 0e6470a087 Don't restrict Saved Messages by premium-only privacy. 2024-06-13 15:47:40 +04:00
John Preston 6c0ea0eb9f Version 5.1.5.
- Return WebView on Windows.
2024-06-07 06:57:27 +04:00
John Preston 9229de2658 Return webview on Windows. 2024-06-07 06:57:06 +04:00
John Preston 2935721cd0 Version 5.1.4.
- Improve design of search in chat.
- Show vCard information for shared contacts.
- Allow scheduling media in topic groups.
- Several minor bugfixes.
2024-06-06 22:19:53 +04:00
John Preston a48cd5f15a Don't show IV buttons on old Windows. 2024-06-06 22:17:30 +04:00
John Preston 9e77e80f92 Moderation on context menu album delete.
Fixes #28012.
2024-06-06 22:16:57 +04:00
John Preston deb50ee528 Fix video full-window toggle in windowed mode. 2024-06-06 22:16:53 +04:00
John Preston 14909ae913 Fix empty space to the right of photo media. 2024-06-06 22:16:48 +04:00
John Preston d5d9da7d0a Allow scheduling media in topic groups. 2024-06-06 22:16:43 +04:00
John Preston 86a048a021 Update libvpx to 1.14.1. 2024-06-06 22:16:38 +04:00
23rd aafa8631e0 Moved out url for credits terms to lang pack. 2024-06-06 22:16:38 +04:00
Ilya Fedin 9176bf2e47 Update lib_webview 2024-06-06 21:08:54 +04:00
John Preston 72c667b153 Redesign search scope selection. 2024-06-06 09:12:23 +04:00
23rd fe6f65b3ab Fixed text elision of peer name in section of chat preview. 2024-06-06 09:12:23 +04:00
23rd 5db2821f8c Removed unused refund api support for credits. 2024-06-06 09:12:23 +04:00
23rd 9e3e7265d2 Improved display of cached message preview in profile sections. 2024-06-06 09:12:23 +04:00
23rd 749b2e0e95 Added ability to see vcard if available to all types if contacts media. 2024-06-06 09:12:23 +04:00
Ilya Fedin 5b45397383 Update lib_webview 2024-06-06 09:12:03 +04:00
Ilya Fedin 61c17c0a93 libasound2 -> libasound2t64 2024-06-04 15:48:18 +04:00
John Preston 93e592472c Version 5.1.3.
- Rebuild version for macOS to fix the phrases.
2024-06-04 14:38:05 +04:00
356 changed files with 9559 additions and 3515 deletions
-8
View File
@@ -57,14 +57,6 @@ include(cmake/validate_d3d_compiler.cmake)
include(cmake/target_prepare_qrc.cmake)
include(cmake/options.cmake)
if (NOT DESKTOP_APP_USE_PACKAGED)
if (WIN32)
set(qt_version 5.15.13)
elseif (APPLE)
set(qt_version 6.2.8)
endif()
endif()
include(cmake/external/qt/package.cmake)
set(desktop_app_skip_libs
+48 -7
View File
@@ -195,6 +195,7 @@ PRIVATE
api/api_earn.h
api/api_editing.cpp
api/api_editing.h
api/api_filter_updates.h
api/api_global_privacy.cpp
api/api_global_privacy.h
api/api_hash.cpp
@@ -233,6 +234,10 @@ PRIVATE
api/api_single_message_search.h
api/api_statistics.cpp
api/api_statistics.h
api/api_statistics_data_deserialize.cpp
api/api_statistics_data_deserialize.h
api/api_statistics_sender.cpp
api/api_statistics_sender.h
api/api_text_entities.cpp
api/api_text_entities.h
api/api_toggling_media.cpp
@@ -791,8 +796,6 @@ PRIVATE
history/view/media/history_view_dice.h
history/view/media/history_view_document.cpp
history/view/media/history_view_document.h
history/view/media/history_view_extended_preview.cpp
history/view/media/history_view_extended_preview.h
history/view/media/history_view_file.cpp
history/view/media/history_view_file.h
history/view/media/history_view_game.cpp
@@ -956,6 +959,10 @@ PRIVATE
history/history_view_highlight_manager.h
history/history_widget.cpp
history/history_widget.h
info/bot/earn/info_bot_earn_list.cpp
info/bot/earn/info_bot_earn_list.h
info/bot/earn/info_bot_earn_widget.cpp
info/bot/earn/info_bot_earn_widget.h
info/channel_statistics/boosts/create_giveaway_box.cpp
info/channel_statistics/boosts/create_giveaway_box.h
info/channel_statistics/boosts/giveaway/giveaway_list_controllers.cpp
@@ -964,10 +971,10 @@ PRIVATE
info/channel_statistics/boosts/info_boosts_inner_widget.h
info/channel_statistics/boosts/info_boosts_widget.cpp
info/channel_statistics/boosts/info_boosts_widget.h
info/channel_statistics/earn/info_earn_inner_widget.cpp
info/channel_statistics/earn/info_earn_inner_widget.h
info/channel_statistics/earn/info_earn_widget.cpp
info/channel_statistics/earn/info_earn_widget.h
info/channel_statistics/earn/info_channel_earn_list.cpp
info/channel_statistics/earn/info_channel_earn_list.h
info/channel_statistics/earn/info_channel_earn_widget.cpp
info/channel_statistics/earn/info_channel_earn_widget.h
info/common_groups/info_common_groups_inner_widget.cpp
info/common_groups/info_common_groups_inner_widget.h
info/common_groups/info_common_groups_widget.cpp
@@ -1608,6 +1615,8 @@ PRIVATE
window/window_peer_menu.cpp
window/window_peer_menu.h
window/window_section_common.h
window/window_separate_id.cpp
window/window_separate_id.h
window/window_session_controller.cpp
window/window_session_controller.h
window/window_session_controller_link_info.h
@@ -1899,12 +1908,44 @@ if (WIN32)
/DELAYLOAD:uxtheme.dll
/DELAYLOAD:crypt32.dll
/DELAYLOAD:bcrypt.dll
/DELAYLOAD:imm32.dll
/DELAYLOAD:netapi32.dll
/DELAYLOAD:imm32.dll
/DELAYLOAD:userenv.dll
/DELAYLOAD:wtsapi32.dll
/DELAYLOAD:propsys.dll
)
if (QT_VERSION GREATER 6)
target_link_options(Telegram
PRIVATE
/DELAYLOAD:API-MS-Win-EventLog-Legacy-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-Console-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-Fibers-l2-1-0.dll
/DELAYLOAD:API-MS-Win-Core-Fibers-l2-1-1.dll
/DELAYLOAD:API-MS-Win-Core-File-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-LibraryLoader-l1-2-0.dll
/DELAYLOAD:API-MS-Win-Core-Localization-l1-2-0.dll
/DELAYLOAD:API-MS-Win-Core-Memory-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-Memory-l1-1-1.dll
/DELAYLOAD:API-MS-Win-Core-ProcessThreads-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-Synch-l1-2-0.dll # Synchronization.lib
/DELAYLOAD:API-MS-Win-Core-SysInfo-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-Timezone-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-WinRT-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-WinRT-Error-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Core-WinRT-String-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Security-CryptoAPI-l1-1-0.dll
/DELAYLOAD:API-MS-Win-Shcore-Scaling-l1-1-1.dll
/DELAYLOAD:authz.dll # Authz.lib
/DELAYLOAD:comdlg32.dll
/DELAYLOAD:dwrite.dll # DWrite.lib
/DELAYLOAD:dxgi.dll # DXGI.lib
/DELAYLOAD:d3d9.dll # D3D9.lib
/DELAYLOAD:d3d11.dll # D3D11.lib
/DELAYLOAD:d3d12.dll # D3D12.lib
/DELAYLOAD:setupapi.dll # SetupAPI.lib
/DELAYLOAD:winhttp.dll
)
endif()
endif()
target_prepare_qrc(Telegram)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+94 -4
View File
@@ -683,6 +683,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_privacy_premium_link" = "Telegram Premium";
"lng_settings_passcode_disable" = "Disable Passcode";
"lng_settings_passcode_disable_sure" = "Are you sure you want to disable passcode?";
"lng_settings_use_winhello" = "Unlock with Windows Hello";
"lng_settings_use_winhello_about" = "You need to enter your passcode once before unlocking Telegram with Windows Hello.";
"lng_settings_use_touchid" = "Unlock with Touch ID";
"lng_settings_use_touchid_about" = "You need to enter your passcode once before unlocking Telegram with Touch ID.";
"lng_settings_use_applewatch" = "Unlock with Apple Watch";
"lng_settings_use_applewatch_about" = "You need to enter your passcode once before unlocking Telegram with Apple Watch.";
"lng_settings_use_systempwd" = "Unlock with System Password";
"lng_settings_use_systempwd_about" = "You need to enter your passcode once before unlocking Telegram with System Password.";
"lng_settings_password_disable" = "Disable Cloud Password";
"lng_settings_password_abort" = "Abort two-step verification setup";
"lng_settings_about_bio" = "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco";
@@ -897,6 +905,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_gift_premium_users_confirm" = "Proceed";
"lng_settings_gift_premium_users_error#one" = "You can select maximum {count} user.";
"lng_settings_gift_premium_users_error#other" = "You can select maximum {count} users.";
"lng_settings_gift_premium_choose" = "Please choose at least one recipient.";
"lng_backgrounds_header" = "Choose Wallpaper";
"lng_theme_sure_keep" = "Keep this theme?";
@@ -991,6 +1000,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passcode_ph" = "Your passcode";
"lng_passcode_submit" = "Submit";
"lng_passcode_logout" = "Log out";
"lng_passcode_winhello" = "You need to enter your passcode\nbefore you can use Windows Hello.";
"lng_passcode_touchid" = "You need to enter your passcode\nbefore you can use Touch ID.";
"lng_passcode_applewatch" = "You need to enter your passcode\nbefore you can use Watch to unlock.";
"lng_passcode_systempwd" = "You need to enter your passcode\nbefore you can use system password.";
"lng_passcode_winhello_unlock" = "Telegram wants to unlock with Windows Hello.";
"lng_passcode_touchid_unlock" = "unlock";
"lng_passcode_create_button" = "Save Passcode";
"lng_passcode_check_button" = "Submit";
"lng_passcode_change_button" = "Save Passcode";
@@ -1560,6 +1575,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_bot_public_link" = "Public Link";
"lng_manage_peer_bot_public_links" = "Public Links";
"lng_manage_peer_bot_balance" = "Balance";
"lng_manage_peer_bot_edit_intro" = "Edit Intro";
"lng_manage_peer_bot_edit_commands" = "Edit Commands";
"lng_manage_peer_bot_edit_settings" = "Change Bot Settings";
@@ -2185,6 +2201,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_summary_about_translation" = "Real-time translation of channels and chats into other languages.";
"lng_premium_summary_subtitle_business" = "Telegram Business";
"lng_premium_summary_about_business" = "Upgrade your account with business features such as location, opening hours and quick replies.";
"lng_premium_summary_subtitle_effects" = "Message Effects";
"lng_premium_summary_about_effects" = "Add over 500 animated effects to private messages.";
"lng_premium_summary_bottom_subtitle" = "About Telegram Premium";
"lng_premium_summary_bottom_about" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";
"lng_premium_summary_button" = "Subscribe for {cost} per month";
@@ -2316,6 +2334,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_credits_summary_options_more" = "More Options";
"lng_credits_summary_options_about" = "By proceeding and purchasing Stars, you agree with the {link}.";
"lng_credits_summary_options_about_link" = "Terms and Conditions";
"lng_credits_summary_options_about_url" = "https://telegram.org/tos/stars";
"lng_credits_summary_history_tab_full" = "All Transactions";
"lng_credits_summary_history_tab_in" = "Incoming";
"lng_credits_summary_history_tab_out" = "Outgoing";
@@ -2324,15 +2343,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_credits_box_out_title" = "Confirm Your Purchase";
"lng_credits_box_out_sure#one" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Star**?";
"lng_credits_box_out_sure#other" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Stars**?";
"lng_credits_box_out_media#one" = "Do you want to unlock {media} in {chat} for **{count} Star**?";
"lng_credits_box_out_media#other" = "Do you want to unlock {media} in {chat} for **{count} Stars**?";
"lng_credits_box_out_photo" = "a photo";
"lng_credits_box_out_photos#one" = "{count} photo";
"lng_credits_box_out_photos#other" = "{count} photos";
"lng_credits_box_out_video" = "a video";
"lng_credits_box_out_videos#one" = "{count} video";
"lng_credits_box_out_videos#other" = "{count} videos";
"lng_credits_box_out_both" = "{photo} and {video}";
"lng_credits_box_out_confirm#one" = "Confirm and Pay {emoji} {count} Star";
"lng_credits_box_out_confirm#other" = "Confirm and Pay {emoji} {count} Stars";
"lng_credits_box_out_about" = "Review the {link} for Stars.";
"lng_credits_media_done_title" = "Media Unlocked";
"lng_credits_media_done_text#one" = "**{count} Star** transferred to {chat}.";
"lng_credits_media_done_text#other" = "**{count} Stars** transferred to {chat}.";
"lng_credits_summary_in_toast_title" = "Stars Acquired";
"lng_credits_summary_in_toast_about#one" = "**{count}** Star added to your balance.";
"lng_credits_summary_in_toast_about#other" = "**{count}** Stars added to your balance.";
"lng_credits_box_history_entry_peer" = "Recipient";
"lng_credits_box_history_entry_via" = "Via";
"lng_credits_box_history_entry_play_market" = "Play Market";
"lng_credits_box_history_entry_app_store" = "App Store";
"lng_credits_box_history_entry_fragment" = "Fragment";
"lng_credits_box_history_entry_ads" = "Ads Platform";
"lng_credits_box_history_entry_id" = "Transaction ID";
"lng_credits_box_history_entry_id_copied" = "Transaction ID copied to clipboard.";
"lng_credits_box_history_entry_success_date" = "Transaction date";
"lng_credits_box_history_entry_success_url" = "Transaction link";
"lng_credits_box_history_entry_media" = "Media";
"lng_credits_box_history_entry_about" = "You can dispute this transaction {link}.";
"lng_credits_box_history_entry_about_link" = "here";
"lng_credits_small_balance_title#one" = "{count} Star Needed";
@@ -3304,6 +3343,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_spoiler_effect" = "Hide with Spoiler";
"lng_context_disable_spoiler" = "Remove Spoiler";
"lng_context_make_paid" = "Make This Content Paid";
"lng_context_change_price" = "Change Price";
"lng_factcheck_title" = "Fact Check";
"lng_factcheck_placeholder" = "Add Facts or Context";
@@ -3315,6 +3356,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_factcheck_bottom" = "This clarification was provided by a fact checking agency assigned by the department of the government of your country ({country}) responsible for combatting misinformation.";
"lng_factcheck_links" = "Only **t.me/** links are allowed.";
"lng_paid_title" = "Paid Content";
"lng_paid_enter_cost" = "Enter Unlock Cost";
"lng_paid_cost_placeholder" = "Stars to Unlock";
"lng_paid_about" = "Users will have to transfer this amount of Stars to your channel in order to view this media. {link}";
"lng_paid_about_link" = "More about stars >";
"lng_paid_about_link_url" = "https://telegram.org/blog/telegram-stars";
"lng_paid_price" = "Unlock for {price}";
"lng_translate_show_original" = "Show Original";
"lng_translate_bar_to" = "Translate to {name}";
"lng_translate_bar_to_other" = "Translate to {name}";
@@ -3581,6 +3630,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_formatting_link_text" = "Text";
"lng_formatting_link_url" = "URL";
"lng_formatting_link_create" = "Create";
"lng_formatting_code_title" = "Code Language";
"lng_formatting_code_language" = "Language for syntax highlighting.";
"lng_formatting_code_auto" = "Auto-Detect";
"lng_text_copied" = "Text copied to clipboard.";
"lng_code_copied" = "Block copied to clipboard.";
@@ -4131,6 +4183,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_restricted_send_polls_all" = "Posting polls isn't allowed in this group.";
"lng_restricted_send_public_polls" = "Sorry, public polls can't be forwarded to channels.";
"lng_restricted_send_paid_media" = "Sorry, paid media can't be sent to this channel.";
"lng_restricted_send_voice_messages" = "{user} restricted sending of voice messages to them.";
"lng_restricted_send_video_messages" = "{user} restricted sending of video messages to them.";
@@ -5158,6 +5211,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_channel_earn_history_return" = "Refund";
"lng_channel_earn_history_return_about" = "Refunded back";
"lng_channel_earn_history_pending" = "Pending";
"lng_channel_earn_history_failed" = "Failed";
"lng_channel_earn_history_show_more#one" = "Show {count} More Transaction";
"lng_channel_earn_history_show_more#other" = "Show {count} More Transactions";
"lng_channel_earn_off" = "Switch Off Ads";
@@ -5180,6 +5234,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_channel_earn_chart_revenue" = "Ad revenue";
"lng_channel_earn_chart_overriden_detail_currency" = "Revenue in TON";
"lng_channel_earn_chart_overriden_detail_usd" = "Revenue in USD";
"lng_channel_earn_currency_history" = "TON Transactions";
"lng_channel_earn_credits_history" = "Stars Transactions";
"lng_channel_earn_out_check_password_about" = "You can withdraw only if you have:";
"lng_bot_earn_title" = "Stars Balance";
"lng_bot_earn_chart_revenue" = "Revenue";
"lng_bot_earn_overview_title" = "Proceeds overview";
"lng_bot_earn_available" = "Available balance";
"lng_bot_earn_total" = "Total lifetime proceeds";
"lng_bot_earn_balance_title" = "Available balance";
"lng_bot_earn_balance_about" = "Stars from your total balance become available for spending on ads and rewards 21 days after they are earned.";
"lng_bot_earn_balance_about_url" = "https://telegram.org/tos/stars";
"lng_bot_earn_balance_button#one" = "Withdraw {emoji} {count}";
"lng_bot_earn_balance_button#other" = "Withdraw {emoji} {count}";
"lng_bot_earn_balance_button_all" = "Withdraw all stars";
"lng_bot_earn_balance_button_locked" = "Withdraw";
"lng_bot_earn_balance_button_buy_ads" = "Buy Ads";
"lng_bot_earn_learn_credits_out_about" = "You can withdraw Stars using Fragment, or use Stars to advertise your bot. {link}";
"lng_bot_earn_out_ph" = "Enter amount to withdraw";
"lng_bot_earn_balance_password_title" = "Two-step verification";
"lng_bot_earn_balance_password_description" = "Please enter your password to collect.";
"lng_bot_earn_credits_out_minimal" = "You cannot withdraw less then {link}.";
"lng_bot_earn_credits_out_minimal_link#one" = "{count} star";
"lng_bot_earn_credits_out_minimal_link#other" = "{count} stars";
"lng_contact_add" = "Add";
"lng_contact_send_message" = "message";
@@ -5384,7 +5462,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_EditedMarkText" = "Edited Mark";
"ayu_SemiTransparentDeletedMessages" = "Translucent Deleted Messages";
"ayu_HideNotificationCounters" = "Hide Notification Counters";
"ayu_HideNotificationBadge" = "Hide Notification Badge";
"ayu_HideAllChats" = "Hide \"All Chats\" Tab";
"ayu_ChannelBottomButton" = "Channel Bottom Button";
"ayu_ChannelBottomButtonHide" = "Hide";
"ayu_ChannelBottomButtonMute" = "Mute";
"ayu_ChannelBottomButtonDiscuss" = "Discuss";
"ayu_SettingsShowID" = "Show Peer ID";
"ayu_SettingsShowID_Hide" = "Hide";
"ayu_SettingsShowMessageShot" = "Show Message Shot";
@@ -5400,6 +5483,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_ContextMenuElementsHeader" = "Context Menu Elements";
"ayu_DrawerElementsHeader" = "Drawer Elements";
"ayu_TrayElementsHeader" = "Tray Elements";
"ayu_SettingsSpoofWebviewAsAndroid" = "Spoof Client as Android";
"ayu_SettingsBiggerWindow" = "Bigger Window";
"ayu_SettingsIncreaseWebviewHeight" = "Increase Content Height";
"ayu_SettingsIncreaseWebviewWidth" = "Increase Content Width";
"ayu_ExportDataTitle" = "Export AyuGram Database?";
"ayu_ExportDataDescription" = "It will be exported to the public folder, to Saved Attachments.";
"ayu_ExportDataConfirm" = "Yes, export";
@@ -5595,10 +5682,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_MessageShotShowReactions" = "Show reactions";
"ayu_MessageShotShowColorfulReplies" = "Show colorful replies";
"ayu_SendAsSticker" = "Send as Sticker";
"ayu_AyuForwardStatusForwarding" = "Forwarding messages";
"ayu_AyuForwardStatusLoadingMedia" = "Loading media";
"ayu_AyuForwardForwardingDescription" = "Please keep this window open while AyuGram is forwarding your messages.";
"ayu_AyuForwardLoadingMediaDescription" = "Please keep this window open while AyuGram is downloading media from your messages.";
"ayu_AyuForwardStatusPreparing" = "Forwarding messages";
"ayu_AyuForwardStatusLoadingMedia" = "Loading media";
"ayu_AyuForwardStatusForwarding" = "Forwarding messages";
"ayu_AyuForwardStatusFinished" = "Done";
"ayu_AyuForwardStatusSentCount" = "sent %1$d of %2$d";
"ayu_AyuForwardStatusChunkCount" = "chunk %1$d of %2$d";
"ayu_JumpToBeginning" = "To Beginning";
"ayu_ExpireMediaContextMenuText" = "Burn";
"ayu_ExpiringVoiceMessageNote" = "This voice message can be played as many times as you want.";
"ayu_ExpiringVideoMessageNote" = "This video message can be played as many times as you want.";
+9
View File
@@ -6,6 +6,12 @@
<file alias="art/ayu/bard/app.png">../../art/ayu/bard/app.png</file>
<file alias="art/ayu/bard/app_preview.png">../../art/ayu/bard/app_preview.png</file>
<file alias="art/ayu/bard/app_icon.ico">../../art/ayu/bard/app_icon.ico</file>
<file alias="art/ayu/chibi/app.png">../../art/ayu/chibi/app.png</file>
<file alias="art/ayu/chibi/app_preview.png">../../art/ayu/chibi/app_preview.png</file>
<file alias="art/ayu/chibi/app_icon.ico">../../art/ayu/chibi/app_icon.ico</file>
<file alias="art/ayu/chibi2/app.png">../../art/ayu/chibi2/app.png</file>
<file alias="art/ayu/chibi2/app_preview.png">../../art/ayu/chibi2/app_preview.png</file>
<file alias="art/ayu/chibi2/app_icon.ico">../../art/ayu/chibi2/app_icon.ico</file>
<file alias="art/ayu/default/app.png">../../art/ayu/default/app.png</file>
<file alias="art/ayu/default/app_preview.png">../../art/ayu/default/app_preview.png</file>
<file alias="art/ayu/default/app_icon.ico">../../art/ayu/default/app_icon.ico</file>
@@ -21,6 +27,9 @@
<file alias="art/ayu/spotify/app.png">../../art/ayu/spotify/app.png</file>
<file alias="art/ayu/spotify/app_preview.png">../../art/ayu/spotify/app_preview.png</file>
<file alias="art/ayu/spotify/app_icon.ico">../../art/ayu/spotify/app_icon.ico</file>
<file alias="art/ayu/win95/app.png">../../art/ayu/win95/app.png</file>
<file alias="art/ayu/win95/app_preview.png">../../art/ayu/win95/app_preview.png</file>
<file alias="art/ayu/win95/app_icon.ico">../../art/ayu/win95/app_icon.ico</file>
<file alias="art/ayu/yaplus/app.png">../../art/ayu/yaplus/app.png</file>
<file alias="art/ayu/yaplus/app_preview.png">../../art/ayu/yaplus/app_preview.png</file>
<file alias="art/ayu/yaplus/app_icon.ico">../../art/ayu/yaplus/app_icon.ico</file>
+1 -1
View File
@@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="5.1.2.0" />
Version="5.2.2.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
+4 -4
View File
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,1,2,0
PRODUCTVERSION 5,1,2,0
FILEVERSION 5,2,2,0
PRODUCTVERSION 5,2,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "5.1.2.0"
VALUE "FileVersion", "5.2.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "5.1.2.0"
VALUE "ProductVersion", "5.2.2.0"
END
END
BLOCK "VarFileInfo"
+4 -4
View File
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,1,2,0
PRODUCTVERSION 5,1,2,0
FILEVERSION 5,2,2,0
PRODUCTVERSION 5,2,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
VALUE "FileVersion", "5.1.2.0"
VALUE "FileVersion", "5.2.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "5.1.2.0"
VALUE "ProductVersion", "5.2.2.0"
END
END
BLOCK "VarFileInfo"
+1
View File
@@ -20,6 +20,7 @@ namespace Api {
inline constexpr auto kScheduledUntilOnlineTimestamp = TimeId(0x7FFFFFFE);
struct SendOptions {
uint64 price = 0;
PeerData *sendAs = nullptr;
TimeId scheduled = 0;
BusinessShortcutId shortcutId = 0;
+110 -26
View File
@@ -7,9 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_credits.h"
#include "apiwrap.h"
#include "api/api_statistics_data_deserialize.h"
#include "api/api_updates.h"
#include "apiwrap.h"
#include "base/unixtime.h"
#include "data/data_channel.h"
#include "data/data_document.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_session.h"
@@ -20,25 +23,62 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Api {
namespace {
constexpr auto kTransactionsLimit = 100;
[[nodiscard]] Data::CreditsHistoryEntry HistoryFromTL(
const MTPStarsTransaction &tl,
not_null<PeerData*> peer) {
using HistoryPeerTL = MTPDstarsTransactionPeer;
using namespace Data;
const auto owner = &peer->owner();
const auto photo = tl.data().vphoto()
? peer->owner().photoFromWeb(*tl.data().vphoto(), ImageLocation())
? owner->photoFromWeb(*tl.data().vphoto(), ImageLocation())
: nullptr;
auto extended = std::vector<CreditsHistoryMedia>();
if (const auto list = tl.data().vextended_media()) {
extended.reserve(list->v.size());
for (const auto &media : list->v) {
media.match([&](const MTPDmessageMediaPhoto &photo) {
if (const auto inner = photo.vphoto()) {
const auto photo = owner->processPhoto(*inner);
if (!photo->isNull()) {
extended.push_back(CreditsHistoryMedia{
.type = CreditsHistoryMediaType::Photo,
.id = photo->id,
});
}
}
}, [&](const MTPDmessageMediaDocument &document) {
if (const auto inner = document.vdocument()) {
const auto document = owner->processDocument(*inner);
if (document->isAnimation()
|| document->isVideoFile()
|| document->isGifv()) {
extended.push_back(CreditsHistoryMedia{
.type = CreditsHistoryMediaType::Video,
.id = document->id,
});
}
}
}, [&](const auto &) {});
}
}
const auto barePeerId = tl.data().vpeer().match([](
const HistoryPeerTL &p) {
return peerFromMTP(p.vpeer());
}, [](const auto &) {
return PeerId(0);
}).value;
return Data::CreditsHistoryEntry{
.id = qs(tl.data().vid()),
.title = qs(tl.data().vtitle().value_or_empty()),
.description = qs(tl.data().vdescription().value_or_empty()),
.date = base::unixtime::parse(tl.data().vdate().v),
.photoId = photo ? photo->id : 0,
.extended = std::move(extended),
.credits = tl.data().vstars().v,
.bareId = tl.data().vpeer().match([](const HistoryPeerTL &p) {
return peerFromMTP(p.vpeer());
}, [](const auto &) {
return PeerId(0);
}).value,
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
.barePeerId = barePeerId,
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
return Data::CreditsHistoryEntry::PeerType::Peer;
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
@@ -51,8 +91,17 @@ namespace {
return Data::CreditsHistoryEntry::PeerType::Unsupported;
}, [](const MTPDstarsTransactionPeerPremiumBot &) {
return Data::CreditsHistoryEntry::PeerType::PremiumBot;
}, [](const MTPDstarsTransactionPeerAds &) {
return Data::CreditsHistoryEntry::PeerType::Ads;
}),
.refunded = tl.data().is_refund(),
.pending = tl.data().is_pending(),
.failed = tl.data().is_failed(),
.successDate = tl.data().vtransaction_date()
? base::unixtime::parse(tl.data().vtransaction_date()->v)
: QDateTime(),
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
.in = (int64(tl.data().vstars().v) >= 0),
};
}
@@ -152,7 +201,8 @@ void CreditsHistory::request(
_requestId = _api.request(MTPpayments_GetStarsTransactions(
MTP_flags(_flags),
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input,
MTP_string(token)
MTP_string(token),
MTP_int(kTransactionsLimit)
)).done([=](const MTPpayments_StarsStatus &result) {
_requestId = 0;
done(StatusFromTL(result, _peer));
@@ -199,24 +249,58 @@ rpl::producer<not_null<PeerData*>> PremiumPeerBot(
};
}
void CreditsRefund(
not_null<PeerData*> peer,
const QString &entryId,
Fn<void()> done,
Fn<void(QString)> fail) {
const auto user = peer->asUser();
if (!user) {
return;
}
peer->session().api().request(MTPpayments_RefundStarsCharge(
user->inputUser,
MTP_string(entryId)
)).done([=](const MTPUpdates &result) {
peer->session().api().updates().applyUpdates(result);
done();
}).fail([=](const MTP::Error &error) {
fail(error.type());
}).send();
CreditsEarnStatistics::CreditsEarnStatistics(not_null<PeerData*> peer)
: StatisticsRequestSender(peer)
, _isUser(peer->isUser()) {
}
rpl::producer<rpl::no_value, QString> CreditsEarnStatistics::request() {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
const auto finish = [=](const QString &url) {
makeRequest(MTPpayments_GetStarsRevenueStats(
MTP_flags(0),
(_isUser ? user()->input : channel()->input)
)).done([=](const MTPpayments_StarsRevenueStats &result) {
const auto &data = result.data();
const auto &status = data.vstatus().data();
_data = Data::CreditsEarnStatistics{
.revenueGraph = StatisticalGraphFromTL(
data.vrevenue_graph()),
.currentBalance = status.vcurrent_balance().v,
.availableBalance = status.vavailable_balance().v,
.overallRevenue = status.voverall_revenue().v,
.usdRate = data.vusd_rate().v,
.isWithdrawalEnabled = status.is_withdrawal_enabled(),
.nextWithdrawalAt = status.vnext_withdrawal_at()
? base::unixtime::parse(
status.vnext_withdrawal_at()->v)
: QDateTime(),
.buyAdsUrl = url,
};
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
};
makeRequest(
MTPpayments_GetStarsRevenueAdsAccountUrl(
(_isUser ? user()->input : channel()->input))
).done([=](const MTPpayments_StarsRevenueAdsAccountUrl &result) {
finish(qs(result.data().vurl()));
}).fail([=](const MTP::Error &error) {
finish({});
}).send();
return lifetime;
};
}
Data::CreditsEarnStatistics CreditsEarnStatistics::data() const {
return _data;
}
} // namespace Api
+18 -5
View File
@@ -7,13 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "api/api_statistics_sender.h"
#include "data/data_credits.h"
#include "data/data_credits_earn.h"
#include "mtproto/sender.h"
namespace Main {
class Session;
} // namespace Main
class UserData;
namespace Api {
class CreditsTopupOptions final {
@@ -68,11 +72,20 @@ private:
};
void CreditsRefund(
not_null<PeerData*> peer,
const QString &entryId,
Fn<void()> done,
Fn<void(QString)> fail);
class CreditsEarnStatistics final : public StatisticsRequestSender {
public:
explicit CreditsEarnStatistics(not_null<PeerData*>);
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
[[nodiscard]] Data::CreditsEarnStatistics data() const;
private:
Data::CreditsEarnStatistics _data;
bool _isUser = false;
mtpRequestId _requestId = 0;
};
[[nodiscard]] rpl::producer<not_null<PeerData*>> PremiumPeerBot(
not_null<Main::Session*> session);
+74 -19
View File
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_cloud_password.h"
#include "apiwrap.h"
#include "ui/layers/generic_box.h"
#include "boxes/passcode_box.h"
#include "data/data_channel.h"
#include "data/data_session.h"
@@ -34,22 +35,33 @@ void RestrictSponsored(
}
void HandleWithdrawalButton(
not_null<ChannelData*> channel,
RewardReceiver receiver,
not_null<Ui::RippleButton*> button,
std::shared_ptr<Ui::Show> show) {
Expects(receiver.currencyReceiver
|| (receiver.creditsReceiver && receiver.creditsAmount));
struct State {
rpl::lifetime lifetime;
bool loading = false;
};
const auto channel = receiver.currencyReceiver;
const auto peer = receiver.creditsReceiver;
const auto state = button->lifetime().make_state<State>();
const auto session = &channel->session();
const auto session = (channel ? &channel->session() : &peer->session());
using ChannelOutUrl = MTPstats_BroadcastRevenueWithdrawalUrl;
using CreditsOutUrl = MTPpayments_StarsRevenueWithdrawalUrl;
session->api().cloudPassword().reload();
button->setClickedCallback([=] {
const auto processOut = [=] {
if (state->loading) {
return;
}
if (peer && !receiver.creditsAmount()) {
return;
}
state->loading = true;
state->lifetime = session->api().cloudPassword().state(
) | rpl::take(
@@ -58,10 +70,12 @@ void HandleWithdrawalButton(
state->loading = false;
auto fields = PasscodeBox::CloudFields::From(pass);
fields.customTitle
= tr::lng_channel_earn_balance_password_title();
fields.customDescription
= tr::lng_channel_earn_balance_password_description(tr::now);
fields.customTitle = channel
? tr::lng_channel_earn_balance_password_title()
: tr::lng_bot_earn_balance_password_title();
fields.customDescription = channel
? tr::lng_channel_earn_balance_password_description(tr::now)
: tr::lng_bot_earn_balance_password_description(tr::now);
fields.customSubmitButton = tr::lng_passcode_submit();
fields.customCheckCallback = crl::guard(button, [=](
const Core::CloudPasswordResult &result,
@@ -74,22 +88,63 @@ void HandleWithdrawalButton(
}
}
};
const auto fail = [=](const QString &error) {
show->showToast(error);
const auto fail = [=](const MTP::Error &error) {
show->showToast(error.type());
};
session->api().request(
MTPstats_GetBroadcastRevenueWithdrawalUrl(
channel->inputChannel,
result.result
)).done([=](const MTPstats_BroadcastRevenueWithdrawalUrl &r) {
done(qs(r.data().vurl()));
}).fail([=](const MTP::Error &error) {
fail(error.type());
}).send();
if (channel) {
session->api().request(
MTPstats_GetBroadcastRevenueWithdrawalUrl(
channel->inputChannel,
result.result
)).done([=](const ChannelOutUrl &r) {
done(qs(r.data().vurl()));
}).fail(fail).send();
} else if (peer) {
session->api().request(
MTPpayments_GetStarsRevenueWithdrawalUrl(
peer->input,
MTP_long(receiver.creditsAmount()),
result.result
)).done([=](const CreditsOutUrl &r) {
done(qs(r.data().vurl()));
}).fail(fail).send();
}
});
show->show(Box<PasscodeBox>(session, fields));
});
};
button->setClickedCallback([=] {
if (state->loading) {
return;
}
const auto fail = [=](const MTP::Error &error) {
auto box = PrePasswordErrorBox(
error.type(),
session,
TextWithEntities{
tr::lng_channel_earn_out_check_password_about(tr::now),
});
if (box) {
show->show(std::move(box));
state->loading = false;
} else {
processOut();
}
};
if (channel) {
session->api().request(
MTPstats_GetBroadcastRevenueWithdrawalUrl(
channel->inputChannel,
MTP_inputCheckPasswordEmpty()
)).fail(fail).send();
} else if (peer) {
session->api().request(
MTPpayments_GetStarsRevenueWithdrawalUrl(
peer->input,
MTP_long(std::numeric_limits<int64_t>::max()),
MTP_inputCheckPasswordEmpty()
)).fail(fail).send();
}
});
}
+7 -1
View File
@@ -21,8 +21,14 @@ void RestrictSponsored(
bool restricted,
Fn<void(QString)> failed);
struct RewardReceiver final {
ChannelData *currencyReceiver = nullptr;
PeerData *creditsReceiver = nullptr;
Fn<uint64()> creditsAmount;
};
void HandleWithdrawalButton(
not_null<ChannelData*> channel,
RewardReceiver receiver,
not_null<Ui::RippleButton*> button,
std::shared_ptr<Ui::Show> show);
@@ -0,0 +1,27 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Api {
template <typename Type>
void PerformForUpdate(
const MTPUpdates &updates,
Fn<void(const Type &)> callback) {
updates.match([&](const MTPDupdates &updates) {
for (const auto &update : updates.vupdates().v) {
update.match([&](const Type &d) {
callback(d);
}, [](const auto &) {
});
}
}, [](const auto &) {
});
}
} // namespace Api
+5 -82
View File
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_statistics.h"
#include "api/api_statistics_data_deserialize.h"
#include "apiwrap.h"
#include "base/unixtime.h"
#include "data/data_channel.h"
@@ -15,33 +16,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_story.h"
#include "history/history.h"
#include "main/main_session.h"
#include "statistics/statistics_data_deserialize.h"
namespace Api {
namespace {
constexpr auto kCheckRequestsTimer = 10 * crl::time(1000);
[[nodiscard]] Data::StatisticalGraph StatisticalGraphFromTL(
const MTPStatsGraph &tl) {
return tl.match([&](const MTPDstatsGraph &d) {
using namespace Statistic;
const auto zoomToken = d.vzoom_token().has_value()
? qs(*d.vzoom_token()).toUtf8()
: QByteArray();
return Data::StatisticalGraph{
StatisticalChartFromJSON(qs(d.vjson().data().vdata()).toUtf8()),
zoomToken,
};
}, [&](const MTPDstatsGraphAsync &data) {
return Data::StatisticalGraph{
.zoomToken = qs(data.vtoken()).toUtf8(),
};
}, [&](const MTPDstatsGraphError &data) {
return Data::StatisticalGraph{ .error = qs(data.verror()) };
});
}
[[nodiscard]] Data::StatisticalValue StatisticalValueFromTL(
const MTPStatsAbsValueAndPrev &tl) {
const auto current = tl.data().vcurrent().v;
@@ -223,61 +201,6 @@ Statistics::Statistics(not_null<ChannelData*> channel)
: StatisticsRequestSender(channel) {
}
StatisticsRequestSender::StatisticsRequestSender(not_null<ChannelData *> channel)
: _channel(channel)
, _api(&_channel->session().api().instance())
, _timer([=] { checkRequests(); }) {
}
StatisticsRequestSender::~StatisticsRequestSender() {
for (const auto &[dcId, ids] : _requests) {
for (const auto id : ids) {
_channel->session().api().unregisterStatsRequest(dcId, id);
}
}
}
void StatisticsRequestSender::checkRequests() {
for (auto i = begin(_requests); i != end(_requests);) {
for (auto j = begin(i->second); j != end(i->second);) {
if (_api.pending(*j)) {
++j;
} else {
_channel->session().api().unregisterStatsRequest(
i->first,
*j);
j = i->second.erase(j);
}
}
if (i->second.empty()) {
i = _requests.erase(i);
} else {
++i;
}
}
if (_requests.empty()) {
_timer.cancel();
}
}
template <typename Request, typename, typename>
auto StatisticsRequestSender::makeRequest(Request &&request) {
const auto id = _api.allocateRequestId();
const auto dcId = _channel->owner().statsDcId(_channel);
if (dcId) {
_channel->session().api().registerStatsRequest(dcId, id);
_requests[dcId].emplace(id);
if (!_timer.isActive()) {
_timer.callEach(kCheckRequestsTimer);
}
}
return std::move(_api.request(
std::forward<Request>(request)
).toDC(
dcId ? MTP::ShiftDcId(dcId, MTP::kStatsDcShift) : 0
).overrideId(id));
}
rpl::producer<rpl::no_value, QString> Statistics::request() {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
@@ -747,11 +670,11 @@ Data::BoostStatus Boosts::boostStatus() const {
return _boostStatus;
}
EarnStatistics::EarnStatistics(not_null<ChannelData*> channel)
ChannelEarnStatistics::ChannelEarnStatistics(not_null<ChannelData*> channel)
: StatisticsRequestSender(channel) {
}
rpl::producer<rpl::no_value, QString> EarnStatistics::request() {
rpl::producer<rpl::no_value, QString> ChannelEarnStatistics::request() {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
@@ -795,7 +718,7 @@ rpl::producer<rpl::no_value, QString> EarnStatistics::request() {
};
}
void EarnStatistics::requestHistory(
void ChannelEarnStatistics::requestHistory(
const Data::EarnHistorySlice::OffsetToken &token,
Fn<void(Data::EarnHistorySlice)> done) {
if (_requestId) {
@@ -865,7 +788,7 @@ void EarnStatistics::requestHistory(
}).send();
}
Data::EarnStatistics EarnStatistics::data() const {
Data::EarnStatistics ChannelEarnStatistics::data() const {
return _data;
}
+3 -32
View File
@@ -7,45 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/timer.h"
#include "api/api_statistics_sender.h"
#include "data/data_boosts.h"
#include "data/data_channel_earn.h"
#include "data/data_statistics.h"
#include "mtproto/sender.h"
class ChannelData;
class PeerData;
namespace Api {
class StatisticsRequestSender {
protected:
explicit StatisticsRequestSender(not_null<ChannelData*> channel);
~StatisticsRequestSender();
template <
typename Request,
typename = std::enable_if_t<!std::is_reference_v<Request>>,
typename = typename Request::Unboxed>
[[nodiscard]] auto makeRequest(Request &&request);
[[nodiscard]] MTP::Sender &api() {
return _api;
}
[[nodiscard]] not_null<ChannelData*> channel() {
return _channel;
}
private:
void checkRequests();
const not_null<ChannelData*> _channel;
MTP::Sender _api;
base::Timer _timer;
base::flat_map<MTP::DcId, base::flat_set<mtpRequestId>> _requests;
};
class Statistics final : public StatisticsRequestSender {
public:
explicit Statistics(not_null<ChannelData*> channel);
@@ -108,9 +79,9 @@ private:
};
class EarnStatistics final : public StatisticsRequestSender {
class ChannelEarnStatistics final : public StatisticsRequestSender {
public:
explicit EarnStatistics(not_null<ChannelData*> channel);
explicit ChannelEarnStatistics(not_null<ChannelData*> channel);
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
void requestHistory(
@@ -0,0 +1,35 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_statistics_data_deserialize.h"
#include "data/data_statistics_chart.h"
#include "statistics/statistics_data_deserialize.h"
namespace Api {
Data::StatisticalGraph StatisticalGraphFromTL(const MTPStatsGraph &tl) {
return tl.match([&](const MTPDstatsGraph &d) {
using namespace Statistic;
const auto zoomToken = d.vzoom_token().has_value()
? qs(*d.vzoom_token()).toUtf8()
: QByteArray();
return Data::StatisticalGraph{
StatisticalChartFromJSON(qs(d.vjson().data().vdata()).toUtf8()),
zoomToken,
};
}, [&](const MTPDstatsGraphAsync &data) {
return Data::StatisticalGraph{
.zoomToken = qs(data.vtoken()).toUtf8(),
};
}, [&](const MTPDstatsGraphError &data) {
return Data::StatisticalGraph{ .error = qs(data.verror()) };
});
}
} // namespace Api
@@ -0,0 +1,19 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Data {
struct StatisticalGraph;
} // namespace Data
namespace Api {
[[nodiscard]] Data::StatisticalGraph StatisticalGraphFromTL(
const MTPStatsGraph &tl);
} // namespace Api
@@ -0,0 +1,86 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_statistics_sender.h"
#include "apiwrap.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "main/main_session.h"
namespace Api {
StatisticsRequestSender::StatisticsRequestSender(
not_null<PeerData*> peer)
: _peer(peer)
, _channel(peer->asChannel())
, _user(peer->asUser())
, _api(&_peer->session().api().instance())
, _timer([=] { checkRequests(); }) {
}
MTP::Sender &StatisticsRequestSender::api() {
return _api;
}
not_null<ChannelData*> StatisticsRequestSender::channel() {
Expects(_channel);
return _channel;
}
not_null<UserData*> StatisticsRequestSender::user() {
Expects(_user);
return _user;
}
void StatisticsRequestSender::checkRequests() {
for (auto i = begin(_requests); i != end(_requests);) {
for (auto j = begin(i->second); j != end(i->second);) {
if (_api.pending(*j)) {
++j;
} else {
_peer->session().api().unregisterStatsRequest(
i->first,
*j);
j = i->second.erase(j);
}
}
if (i->second.empty()) {
i = _requests.erase(i);
} else {
++i;
}
}
if (_requests.empty()) {
_timer.cancel();
}
}
auto StatisticsRequestSender::ensureRequestIsRegistered()
-> StatisticsRequestSender::Registered {
const auto id = _api.allocateRequestId();
const auto dcId = _peer->owner().statsDcId(_peer);
if (dcId) {
_peer->session().api().registerStatsRequest(dcId, id);
_requests[dcId].emplace(id);
if (!_timer.isActive()) {
constexpr auto kCheckRequestsTimer = 10 * crl::time(1000);
_timer.callEach(kCheckRequestsTimer);
}
}
return StatisticsRequestSender::Registered{ id, dcId };
}
StatisticsRequestSender::~StatisticsRequestSender() {
for (const auto &[dcId, ids] : _requests) {
for (const auto id : ids) {
_peer->session().api().unregisterStatsRequest(dcId, id);
}
}
}
} // namespace Api
@@ -0,0 +1,58 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/timer.h"
#include "mtproto/sender.h"
class ChannelData;
class PeerData;
class UserData;
namespace Api {
class StatisticsRequestSender {
protected:
explicit StatisticsRequestSender(not_null<PeerData*> peer);
~StatisticsRequestSender();
template <
typename Request,
typename = std::enable_if_t<!std::is_reference_v<Request>>,
typename = typename Request::Unboxed>
[[nodiscard]] auto makeRequest(Request &&request) {
const auto [id, dcId] = ensureRequestIsRegistered();
return std::move(_api.request(
std::forward<Request>(request)
).toDC(
dcId ? MTP::ShiftDcId(dcId, MTP::kStatsDcShift) : 0
).overrideId(id));
}
[[nodiscard]] MTP::Sender &api();
[[nodiscard]] not_null<ChannelData*> channel();
[[nodiscard]] not_null<UserData*> user();
private:
struct Registered final {
mtpRequestId id;
MTP::DcId dcId;
};
[[nodiscard]] Registered ensureRequestIsRegistered();
void checkRequests();
const not_null<PeerData*> _peer;
ChannelData * const _channel;
UserData * const _user;
MTP::Sender _api;
base::Timer _timer;
base::flat_map<MTP::DcId, base::flat_set<mtpRequestId>> _requests;
};
} // namespace Api
+7 -1
View File
@@ -1704,7 +1704,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
const auto peerId = peerFromMTP(d.vpeer());
const auto msgId = d.vmsg_id().v;
if (const auto item = session().data().message(peerId, msgId)) {
item->applyEdition(d.vextended_media());
item->applyEdition(d.vextended_media().v);
}
} break;
@@ -2129,6 +2129,8 @@ void Updates::feedUpdate(const MTPUpdate &update) {
};
if (IsForceLogoutNotification(d)) {
Core::App().forceLogOut(&session().account(), text);
} else if (IsWithdrawalNotification(d)) {
return;
} else if (d.is_popup()) {
const auto &windows = session().windows();
if (!windows.empty()) {
@@ -2630,4 +2632,8 @@ void Updates::feedUpdate(const MTPUpdate &update) {
}
}
bool IsWithdrawalNotification(const MTPDupdateServiceNotification &data) {
return qs(data.vtype()).startsWith(u"API_WITHDRAWAL_FEATURE_DISABLED_"_q);
}
} // namespace Api
+3
View File
@@ -211,4 +211,7 @@ private:
};
[[nodiscard]] bool IsWithdrawalNotification(
const MTPDupdateServiceNotification &);
} // namespace Api
+20 -9
View File
@@ -55,7 +55,9 @@ void ViewsManager::removeIncremented(not_null<PeerData*> peer) {
_incremented.remove(peer);
}
void ViewsManager::pollExtendedMedia(not_null<HistoryItem*> item) {
void ViewsManager::pollExtendedMedia(
not_null<HistoryItem*> item,
bool force) {
if (!item->isRegular()) {
return;
}
@@ -63,14 +65,20 @@ void ViewsManager::pollExtendedMedia(not_null<HistoryItem*> item) {
const auto peer = item->history()->peer;
auto &request = _pollRequests[peer];
if (request.ids.contains(id) || request.sent.contains(id)) {
return;
if (!force || request.forced) {
return;
}
}
request.ids.emplace(id);
if (!request.id && !request.when) {
request.when = crl::now() + kPollExtendedMediaPeriod;
if (force) {
request.forced = true;
}
if (!_pollTimer.isActive()) {
_pollTimer.callOnce(kPollExtendedMediaPeriod);
const auto delay = force ? 1 : kPollExtendedMediaPeriod;
if (!request.id && (!request.when || force)) {
request.when = crl::now() + delay;
}
if (!_pollTimer.isActive() || force) {
_pollTimer.callOnce(delay);
}
}
@@ -160,9 +168,12 @@ void ViewsManager::sendPollRequests(
if (i->second.ids.empty()) {
i = _pollRequests.erase(i);
} else {
i->second.when = now + kPollExtendedMediaPeriod;
if (!_pollTimer.isActive()) {
_pollTimer.callOnce(kPollExtendedMediaPeriod);
const auto delay = i->second.forced
? 1
: kPollExtendedMediaPeriod;
i->second.when = now + delay;
if (!_pollTimer.isActive() || i->second.forced) {
_pollTimer.callOnce(delay);
}
++i;
}
+2 -1
View File
@@ -26,7 +26,7 @@ public:
void scheduleIncrement(not_null<HistoryItem*> item);
void removeIncremented(not_null<PeerData*> peer);
void pollExtendedMedia(not_null<HistoryItem*> item);
void pollExtendedMedia(not_null<HistoryItem*> item, bool force = false);
private:
struct PollExtendedMediaRequest {
@@ -34,6 +34,7 @@ private:
mtpRequestId id = 0;
base::flat_set<MsgId> ids;
base::flat_set<MsgId> sent;
bool forced = false;
};
void viewsIncrement();
+99 -10
View File
@@ -1352,27 +1352,30 @@ void ApiWrap::migrateFail(not_null<PeerData*> peer, const QString &error) {
void ApiWrap::markContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) {
const auto settings = &AyuSettings::getInstance();
auto markedIds = QVector<MTPint>();
auto channelMarkedIds = base::flat_map<
not_null<ChannelData*>,
QVector<MTPint>>();
markedIds.reserve(items.size());
for (const auto &item : items) {
const auto passthrough = (item->isUnreadMention() || item->hasUnreadReaction()) && !item->isUnreadMedia();
if (!item->markContentsRead(true) || !item->isRegular()) {
continue;
}
if (!settings->sendReadMessages && !passthrough) {
continue;
}
if (const auto channel = item->history()->peer->asChannel()) {
channelMarkedIds[channel].push_back(MTP_int(item->id));
} else {
markedIds.push_back(MTP_int(item->id));
}
}
const auto settings = &AyuSettings::getInstance();
if (!settings->sendReadMessages) {
return;
}
if (!markedIds.isEmpty()) {
request(MTPmessages_ReadMessageContents(
MTP_vector<MTPint>(markedIds)
@@ -1389,12 +1392,14 @@ void ApiWrap::markContentsRead(
}
void ApiWrap::markContentsRead(not_null<HistoryItem*> item) {
const auto passthrough = (item->isUnreadMention() || item->hasUnreadReaction()) && !item->isUnreadMedia();
if (!item->markContentsRead(true) || !item->isRegular()) {
return;
}
const auto settings = &AyuSettings::getInstance();
if (!settings->sendReadMessages) {
if (!settings->sendReadMessages && !passthrough) {
return;
}
@@ -2204,7 +2209,8 @@ void ApiWrap::saveDraftsToCloud() {
entities,
Data::WebPageForMTP(
cloudDraft->webpage,
textWithTags.text.isEmpty())
textWithTags.text.isEmpty()),
MTP_long(0) // effect
)).done([=](const MTPBool &result, const MTP::Response &response) {
const auto requestId = response.requestId;
history->finishSavingCloudDraft(
@@ -4259,7 +4265,11 @@ void ApiWrap::sendMediaWithRandomId(
MTP_flags(flags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
media,
(options.price
? MTPInputMedia(MTP_inputMediaPaidMedia(
MTP_long(options.price),
MTP_vector<MTPInputMedia>(1, media)))
: media),
MTP_string(caption.text),
MTP_long(randomId),
MTPReplyMarkup(),
@@ -4281,6 +4291,82 @@ void ApiWrap::sendMediaWithRandomId(
});
}
void ApiWrap::sendMultiPaidMedia(
not_null<HistoryItem*> item,
not_null<SendingAlbum*> album,
Fn<void(bool)> done) {
Expects(album->options.price > 0);
const auto groupId = album->groupId;
const auto &options = album->options;
const auto randomId = album->items.front().randomId;
auto medias = album->items | ranges::view::transform([](
const SendingAlbum::Item &part) {
Assert(part.media.has_value());
return MTPInputMedia(part.media->data().vmedia());
}) | ranges::to<QVector<MTPInputMedia>>();
const auto history = item->history();
const auto replyTo = item->replyTo();
auto caption = item->originalText();
TextUtilities::Trim(caption);
auto sentEntities = Api::EntitiesToMTP(
_session,
caption.entities,
Api::ConvertOption::SkipLocal);
using Flag = MTPmessages_SendMedia::Flag;
const auto flags = Flag(0)
| (replyTo ? Flag::f_reply_to : Flag(0))
| (ShouldSendSilent(history->peer, options)
? Flag::f_silent
: Flag(0))
| (!sentEntities.v.isEmpty() ? Flag::f_entities : Flag(0))
| (options.scheduled ? Flag::f_schedule_date : Flag(0))
| (options.sendAs ? Flag::f_send_as : Flag(0))
| (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0))
| (options.effectId ? Flag::f_effect : Flag(0))
| (options.invertCaption ? Flag::f_invert_media : Flag(0));
auto &histories = history->owner().histories();
const auto peer = history->peer;
const auto itemId = item->fullId();
histories.sendPreparedMessage(
history,
replyTo,
randomId,
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
MTP_flags(flags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
MTP_inputMediaPaidMedia(
MTP_long(options.price),
MTP_vector<MTPInputMedia>(std::move(medias))),
MTP_string(caption.text),
MTP_long(randomId),
MTPReplyMarkup(),
sentEntities,
MTP_int(options.scheduled),
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(_session, options.shortcutId),
MTP_long(options.effectId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
if (const auto album = _sendingAlbums.take(groupId)) {
const auto copy = (*album)->items;
for (const auto &part : copy) {
if (const auto item = history->owner().message(part.msgId)) {
item->destroy();
}
}
}
if (done) done(true);
}, [=](const MTP::Error &error, const MTP::Response &response) {
if (done) done(false);
sendMessageFail(error, peer, randomId, itemId);
});
}
void ApiWrap::sendAlbumWithUploaded(
not_null<HistoryItem*> item,
const MessageGroupId &groupId,
@@ -4334,8 +4420,11 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
if (!sample) {
_sendingAlbums.remove(groupId);
return;
} else if (album->options.price > 0) {
sendMultiPaidMedia(sample, album);
return;
} else if (medias.size() < 2) {
const auto &single = medias.front().c_inputSingleMedia();
const auto &single = medias.front().data();
sendMediaWithRandomId(
sample,
single.vmedia(),
+4
View File
@@ -545,6 +545,10 @@ private:
Api::SendOptions options,
uint64 randomId,
Fn<void(bool)> done = nullptr);
void sendMultiPaidMedia(
not_null<HistoryItem*> item,
not_null<SendingAlbum*> album,
Fn<void(bool)> done = nullptr);
void getTopPromotionDelayed(TimeId now, TimeId next);
void topPromotionDone(const MTPhelp_PromoData &proxy);
+41
View File
@@ -164,6 +164,15 @@ void load() {
} catch (...) {
LOG(("AyuGramSettings: failed to read settings file (not json-like)"));
}
if (cGhost()) {
settings->sendReadMessages = false;
settings->sendReadStories = false;
settings->sendOnlinePackets = false;
settings->sendUploadProgress = false;
settings->sendOfflinePacketAfterOnline = true;
}
postinitialize();
}
@@ -205,6 +214,10 @@ AyuGramSettings::AyuGramSettings() {
collapseSimilarChannels = true;
hideSimilarChannels = false;
spoofWebviewAsAndroid = false;
increaseWebviewHeight = false;
increaseWebviewWidth = false;
disableNotificationsDelay = false;
localPremium = false;
@@ -236,8 +249,16 @@ AyuGramSettings::AyuGramSettings() {
monoFont = "";
hideNotificationCounters = false;
hideNotificationBadge = false;
hideAllChatsFolder = false;
/*
* channelBottomButton = 0 means "Hide"
* channelBottomButton = 1 means "Mute"/"Unmute"
* channelBottomButton = 2 means "Discuss" + fallback to "Mute"/"Unmute"
*/
channelBottomButton = 2;
/*
* showPeerId = 0 means no ID shown
* showPeerId = 1 means ID shown as for Telegram API devs
@@ -332,6 +353,18 @@ void AyuGramSettings::set_hideSimilarChannels(bool val) {
hideSimilarChannels = val;
}
void AyuGramSettings::set_spoofWebviewAsAndroid(bool val) {
spoofWebviewAsAndroid = val;
}
void AyuGramSettings::set_increaseWebviewHeight(bool val) {
increaseWebviewHeight = val;
}
void AyuGramSettings::set_increaseWebviewWidth(bool val) {
increaseWebviewWidth = val;
}
void AyuGramSettings::set_disableNotificationsDelay(bool val) {
disableNotificationsDelay = val;
}
@@ -419,10 +452,18 @@ void AyuGramSettings::set_hideNotificationCounters(bool val) {
hideNotificationCounters = val;
}
void AyuGramSettings::set_hideNotificationBadge(bool val) {
hideNotificationBadge = val;
}
void AyuGramSettings::set_hideAllChatsFolder(bool val) {
hideAllChatsFolder = val;
}
void AyuGramSettings::set_channelBottomButton(int val) {
channelBottomButton = val;
}
void AyuGramSettings::set_showMessageSeconds(bool val) {
showMessageSeconds = val;
}
+19
View File
@@ -37,6 +37,10 @@ public:
bool collapseSimilarChannels;
bool hideSimilarChannels;
bool spoofWebviewAsAndroid;
bool increaseWebviewHeight;
bool increaseWebviewWidth;
bool disableNotificationsDelay;
bool localPremium;
@@ -63,8 +67,11 @@ public:
QString monoFont;
bool hideNotificationCounters;
bool hideNotificationBadge;
bool hideAllChatsFolder;
int channelBottomButton;
int showPeerId;
bool showMessageSeconds;
bool showMessageShot;
@@ -95,6 +102,10 @@ public:
void set_collapseSimilarChannels(bool val);
void set_hideSimilarChannels(bool val);
void set_spoofWebviewAsAndroid(bool val);
void set_increaseWebviewHeight(bool val);
void set_increaseWebviewWidth(bool val);
void set_disableNotificationsDelay(bool val);
void set_localPremium(bool val);
@@ -121,8 +132,11 @@ public:
void set_monoFont(QString val);
void set_hideNotificationCounters(bool val);
void set_hideNotificationBadge(bool val);
void set_hideAllChatsFolder(bool val);
void set_channelBottomButton(int val);
void set_showPeerId(int val);
void set_showMessageSeconds(bool val);
void set_showMessageShot(bool val);
@@ -149,6 +163,9 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
disableCustomBackgrounds,
collapseSimilarChannels,
hideSimilarChannels,
spoofWebviewAsAndroid,
increaseWebviewHeight,
increaseWebviewWidth,
disableNotificationsDelay,
localPremium,
appIcon,
@@ -169,7 +186,9 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
showStreamerToggleInTray,
monoFont,
hideNotificationCounters,
hideNotificationBadge,
hideAllChatsFolder,
channelBottomButton,
showPeerId,
showMessageSeconds,
showMessageShot,
@@ -24,6 +24,10 @@ void enable() {
auto handle = Core::App().activeWindow()->widget()->psHwnd();
SetWindowDisplayAffinity(handle, WDA_EXCLUDEFROMCAPTURE);
Core::App().enumerateWindows([&](not_null<Window::Controller*> w) {
SetWindowDisplayAffinity(w->widget()->psHwnd(), WDA_EXCLUDEFROMCAPTURE);
});
isEnabledVal = true;
}
@@ -31,6 +35,10 @@ void disable() {
auto handle = Core::App().activeWindow()->widget()->psHwnd();
SetWindowDisplayAffinity(handle, WDA_NONE);
Core::App().enumerateWindows([&](not_null<Window::Controller*> w) {
SetWindowDisplayAffinity(w->widget()->psHwnd(), WDA_NONE);
});
isEnabledVal = false;
}
@@ -17,9 +17,13 @@ ayuLReadMenuIcon: icon {{ "ayu/lread", menuIconColor }};
ayuSReadMenuIcon: icon {{ "ayu/sread", menuIconColor }};
ayuStreamerModeMenuIcon: icon {{ "ayu/streamer", menuIconColor }};
ayuMenuIconToBeginning: icon {{ "ayu/to_beginning", menuIconColor }};
inChannelBadgeIcon: icon {{ "ayu/channel", msgInDateFg }};
inChannelBadgeSelectedIcon: icon {{ "ayu/channel", msgInDateFgSelected }};
outChannelBadgeIcon: icon {{ "ayu/channel", msgOutDateFg }};
outChannelBadgeSelectedIcon: icon {{ "ayu/channel", msgOutDateFgSelected }};
infoExteraBadge: icon {{ "ayu/exterabadge", profileVerifiedCheckBg }};
winEnterWithGuestIcon: icon {{ "ayu/ghost_tray", windowFg }};
+3
View File
@@ -18,6 +18,9 @@ ICON(EXTERA, "extera");
ICON(NOTHING, "nothing");
ICON(BARD, "bard");
ICON(YAPLUS, "yaplus");
ICON(WIN95, "win95");
ICON(CHIBI, "chibi");
ICON(CHIBI2, "chibi2");
void loadAppIco();
+6 -3
View File
@@ -12,12 +12,10 @@ using "ui/colors.palette";
using "ui/widgets/widgets.style";
using "info/info.style";
iconPreviewStroke: activeButtonBg;
/* Color Picker */
cpPadding: 14px;
cpSelectedPadding: 2px;
cpPenSize: 2px;
cpSelectedRounding: 12px;
cpImagePadding: 4px;
cpSpacingX: 16px;
cpSpacingY: 8px;
@@ -27,6 +25,11 @@ recentStickersLimitPadding: margins(22px, 4px, 22px, 8px);
imageViewPadding: margins(22px, 10px, 22px, 10px);
imageViewInnerPadding: margins(16px, 16px, 16px, 16px);
botWebViewPanelHeightIncreased: 782px;
botWebViewPanelWidthIncreased: 512px;
stickerRoundingSize: 5px;
messageShotPadding: 4px;
topBarAdmins: IconButton {
@@ -626,6 +626,10 @@ QString InnerWidget::elementAuthorRank(not_null<const Element*> view) {
return {};
}
bool InnerWidget::elementHideTopicButton(not_null<const Element*> view) {
return false;
}
void InnerWidget::saveState(not_null<SectionMemento*> memento) {
if (!_filterChanged) {
for (auto &item : _items) {
@@ -132,6 +132,7 @@ public:
not_null<const HistoryView::Element*> view,
HistoryView::Element *replacing) override;
QString elementAuthorRank(not_null<const HistoryView::Element*> view) override;
bool elementHideTopicButton(not_null<const HistoryView::Element*> view) override;
~InnerWidget();
@@ -28,7 +28,10 @@ const QVector<QString> icons{
AyuAssets::EXTERA_ICON,
AyuAssets::NOTHING_ICON,
AyuAssets::BARD_ICON,
AyuAssets::YAPLUS_ICON
AyuAssets::YAPLUS_ICON,
AyuAssets::WIN95_ICON,
AyuAssets::CHIBI_ICON,
AyuAssets::CHIBI2_ICON,
};
const auto rows = static_cast<int>(icons.size()) / 4 + std::min(1, static_cast<int>(icons.size()) % 4);
@@ -36,18 +39,26 @@ const auto rows = static_cast<int>(icons.size()) / 4 + std::min(1, static_cast<i
void drawIcon(QPainter &p, const QImage &icon, int xOffset, int yOffset, float strokeOpacity) {
xOffset += st::cpPadding;
// stroke
p.save();
p.setPen(QPen(st::iconPreviewStroke, st::cpPenSize));
p.setPen(QPen(st::boxDividerBg, 0));
p.setBrush(QBrush(st::boxDividerBg));
p.setOpacity(strokeOpacity);
p.drawEllipse(xOffset + st::cpSelectedPadding,
yOffset + st::cpSelectedPadding,
st::cpIconSize + st::cpSelectedPadding * 2,
st::cpIconSize + st::cpSelectedPadding * 2);
p.drawRoundedRect(
xOffset + st::cpSelectedPadding,
yOffset + st::cpSelectedPadding,
st::cpIconSize + st::cpSelectedPadding * 2,
st::cpIconSize + st::cpSelectedPadding * 2,
st::cpSelectedRounding,
st::cpSelectedRounding
);
p.restore();
// /stroke
auto rect = QRect(xOffset + st::cpImagePadding, yOffset + st::cpImagePadding, st::cpIconSize, st::cpIconSize);
auto rect = QRect(
xOffset + st::cpImagePadding,
yOffset + st::cpImagePadding,
st::cpIconSize,
st::cpIconSize
);
p.drawImage(rect, icon);
}
@@ -65,7 +76,7 @@ void applyIcon() {
IconPicker::IconPicker(QWidget *parent)
: RpWidget(parent) {
setMinimumSize(st::boxWidth, (st::cpIconSize + st::cpPadding) * rows);
setMinimumSize(st::boxWidth, (st::cpIconSize + st::cpPadding) * rows - st::cpPadding);
}
void IconPicker::paintEvent(QPaintEvent *e) {
@@ -80,21 +91,27 @@ void IconPicker::paintEvent(QPaintEvent *e) {
auto const idx = i + row * 4;
const auto &iconName = icons[idx];
if (iconName.isEmpty()) {
continue;
}
auto icon = AyuAssets::loadPreview(iconName)
.scaled(st::cpIconSize, st::cpIconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
auto opacity = 0.0f;
if (iconName == wasSelected) {
if (iconName == wasSelected) {
opacity = 1.0f - animation.value(1.0f);
} else if (iconName == AyuAssets::currentAppLogoName()) {
opacity = wasSelected.isEmpty() ? 1.0f : animation.value(1.0f);
}
drawIcon(p,
icon,
(st::cpIconSize + st::cpSpacingX) * i + offset,
row * (st::cpIconSize + st::cpSpacingY),
opacity);
drawIcon(
p,
icon,
(st::cpIconSize + st::cpSpacingX) * i + offset,
row * (st::cpIconSize + st::cpSpacingY),
opacity
);
}
}
}
@@ -114,6 +131,10 @@ void IconPicker::mousePressEvent(QMouseEvent *e) {
if (x >= xOffset && x <= xOffset + st::cpIconSize && e->pos().y() >= yOffset
&& e->pos().y() <= yOffset + st::cpIconSize) {
const auto &iconName = icons[idx];
if (iconName.isEmpty()) {
break;
}
if (settings->appIcon != iconName) {
wasSelected = settings->appIcon;
animation.start(
@@ -124,7 +145,8 @@ void IconPicker::mousePressEvent(QMouseEvent *e) {
0.0,
1.0,
200,
anim::easeOutCubic);
anim::easeOutCubic
);
settings->set_appIcon(iconName);
changed = true;
@@ -26,7 +26,9 @@
#include "styles/style_widgets.h"
#include "icon_picker.h"
#include "tray.h"
#include "core/application.h"
#include "main/main_domain.h"
#include "styles/style_ayu_icons.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
@@ -343,13 +345,14 @@ void AddCollapsibleToggle(not_null<Ui::VerticalLayout*> container,
raw->lifetime());
}
void AddChooseButtonWithIconAndRightText(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::icon &icon,
const style::SettingsButton & st,
Settings::IconDescriptor && descriptor,
const Fn<void(int)> &setter) {
auto reactiveVal = container->lifetime().make_state<rpl::variable<int>>(initialState);
@@ -363,8 +366,8 @@ void AddChooseButtonWithIconAndRightText(not_null<Ui::VerticalLayout*> container
container,
std::move(text),
rightTextReactive,
st::settingsButton,
{&icon})->addClickHandler(
st,
std::move(descriptor))->addClickHandler(
[=]
{
controller->show(Box(
@@ -387,6 +390,45 @@ void AddChooseButtonWithIconAndRightText(not_null<Ui::VerticalLayout*> container
});
}
void AddChooseButtonWithIconAndRightText(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::icon &icon,
const Fn<void(int)> &setter) {
AddChooseButtonWithIconAndRightTextInner(
container,
controller,
initialState,
options,
std::move(text),
std::move(boxTitle),
st::settingsButton,
{&icon},
setter);
}
void AddChooseButtonWithIconAndRightText(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 Fn<void(int)> &setter) {
AddChooseButtonWithIconAndRightTextInner(
container,
controller,
initialState,
options,
std::move(text),
std::move(boxTitle),
st::settingsButtonNoIcon,
{},
setter);
}
namespace Settings {
rpl::producer<QString> Ayu::title() {
@@ -1163,7 +1205,7 @@ void SetupMarks(not_null<Ui::VerticalLayout*> container) {
});
}
void SetupFolderSettings(not_null<Ui::VerticalLayout*> container) {
void SetupFolderSettings(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
auto settings = &AyuSettings::getInstance();
AddButtonWithIcon(
@@ -1185,6 +1227,32 @@ void SetupFolderSettings(not_null<Ui::VerticalLayout*> container) {
},
container->lifetime());
// not about folders, but it's a good place for it
#ifdef Q_OS_WIN
AddButtonWithIcon(
container,
tr::ayu_HideNotificationBadge(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->hideNotificationBadge)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->hideNotificationBadge);
}) | start_with_next(
[=](bool enabled)
{
settings->set_hideNotificationBadge(enabled);
AyuSettings::save();
Core::App().refreshApplicationIcon();
Core::App().tray().updateIconCounters();
Core::App().domain().notifyUnreadBadgeChanged();
},
container->lifetime());
#endif
AddButtonWithIcon(
container,
tr::ayu_HideAllChats(),
@@ -1205,6 +1273,29 @@ void SetupFolderSettings(not_null<Ui::VerticalLayout*> container) {
container->lifetime());
}
void SetupChannelSettings(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
auto settings = &AyuSettings::getInstance();
const auto options = std::vector{
tr::ayu_ChannelBottomButtonHide(tr::now),
tr::ayu_ChannelBottomButtonMute(tr::now),
tr::ayu_ChannelBottomButtonDiscuss(tr::now),
};
AddChooseButtonWithIconAndRightText(
container,
controller,
settings->channelBottomButton,
options,
tr::ayu_ChannelBottomButton(),
tr::ayu_ChannelBottomButton(),
[=](int index)
{
settings->set_channelBottomButton(index);
AyuSettings::save();
});
}
void SetupNerdSettings(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> controller) {
auto settings = &AyuSettings::getInstance();
@@ -1249,6 +1340,50 @@ void SetupNerdSettings(not_null<Ui::VerticalLayout*> container, not_null<Window:
container->lifetime());
}
void SetupWebviewSettings(not_null<Ui::VerticalLayout*> container) {
auto settings = &AyuSettings::getInstance();
AddSubsectionTitle(container, rpl::single(QString("Webview")));
AddButtonWithIcon(
container,
tr::ayu_SettingsSpoofWebviewAsAndroid(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->spoofWebviewAsAndroid)
)->toggledValue(
) | rpl::filter(
[=](bool enabled)
{
return (enabled != settings->spoofWebviewAsAndroid);
}) | start_with_next(
[=](bool enabled)
{
settings->set_spoofWebviewAsAndroid(enabled);
AyuSettings::save();
},
container->lifetime());
std::vector checkboxes = {
NestedEntry{
tr::ayu_SettingsIncreaseWebviewHeight(tr::now), settings->increaseWebviewHeight, [=](bool enabled)
{
settings->set_increaseWebviewHeight(enabled);
AyuSettings::save();
}
},
NestedEntry{
tr::ayu_SettingsIncreaseWebviewWidth(tr::now), settings->increaseWebviewWidth, [=](bool enabled)
{
settings->set_increaseWebviewWidth(enabled);
AyuSettings::save();
}
}
};
AddCollapsibleToggle(container, tr::ayu_SettingsBiggerWindow(), checkboxes, false);
}
void SetupCustomization(not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionController*> controller) {
AddSubsectionTitle(container, tr::ayu_CustomizationHeader());
@@ -1270,7 +1405,12 @@ void SetupCustomization(not_null<Ui::VerticalLayout*> container,
AddDivider(container);
AddSkip(container);
SetupFolderSettings(container);
SetupFolderSettings(container, controller);
AddSkip(container);
AddDivider(container);
AddSkip(container);
SetupChannelSettings(container, controller);
AddSkip(container);
AddDivider(container);
@@ -1318,6 +1458,12 @@ void SetupAyuGramSettings(not_null<Ui::VerticalLayout*> container,
AddSkip(container);
AddDividerText(container, tr::ayu_SettingsCustomizationHint());
AddSkip(container);
SetupWebviewSettings(container);
AddSkip(container);
AddDivider(container);
AddSkip(container);
SetupSendConfirmations(container);
AddSkip(container);
@@ -517,6 +517,50 @@ QString getMediaDC(not_null<HistoryItem*> message) {
return {};
}
QString getPeerDC(not_null<PeerData*> peer) {
if (peer->hasUserpic()) {
const auto dc = v::match(
peer->userpicLocation().file().data,
[&](const StorageFileLocation &data)
{
return data.dcId();
},
[&](const WebFileLocation &)
{
// should't happen, but still
// all webpages are on DC4
return 4;
},
[&](const GeoPointLocation &)
{
// shouldn't happen naturally
return 0;
},
[&](const AudioAlbumThumbLocation &)
{
// shouldn't happen naturally
return 0;
},
[&](const PlainUrlLocation &)
{
// should't happen, but still
// all webpages are on DC4
return 4;
},
[&](const InMemoryLocation &)
{
// shouldn't happen naturally
return 0;
});
if (dc > 0) {
return getDCName(dc);
}
}
return {};
}
int getScheduleTime(int64 sumSize) {
auto time = 12;
time += (int) std::ceil(std::max(6.0, std::ceil(sumSize / 1024.0 / 1024.0 * 0.7))) + 1;
@@ -43,6 +43,8 @@ QString getMediaName(not_null<HistoryItem*> message);
QString getMediaResolution(not_null<HistoryItem*> message);
QString getMediaDC(not_null<HistoryItem*> message);
QString getPeerDC(not_null<PeerData*> peer);
int getScheduleTime(int64 sumSize);
void searchById(ID userId, Main::Session *session, bool retry, const Callback &callback);
+22 -5
View File
@@ -237,7 +237,7 @@ shareColumnSkip: 6px;
shareActivateDuration: 150;
shareScrollDuration: 300;
shareComment: InputField(defaultInputField) {
font: normalFont;
style: defaultTextStyle;
textMargins: margins(8px, 8px, 8px, 6px);
heightMin: 36px;
heightMax: 72px;
@@ -290,6 +290,26 @@ passcodeTextLine: 28px;
passcodeLittleSkip: 5px;
passcodeAboutSkip: 7px;
passcodeSkip: 23px;
passcodeSystemUnlock: IconButton(defaultIconButton) {
width: 32px;
height: 36px;
icon: icon{{ "menu/passcode_winhello", lightButtonFg }};
iconOver: icon{{ "menu/passcode_winhello", lightButtonFg }};
iconPosition: point(4px, 4px);
rippleAreaSize: 32px;
rippleAreaPosition: point(0px, 0px);
ripple: RippleAnimation(defaultRippleAnimation) {
color: lightButtonBgOver;
}
}
passcodeSystemTouchID: icon{{ "menu/passcode_finger", lightButtonFg }};
passcodeSystemAppleWatch: icon{{ "menu/passcode_watch", lightButtonFg }};
passcodeSystemSystemPwd: icon{{ "menu/permissions", lightButtonFg }};
passcodeSystemUnlockLater: FlatLabel(defaultFlatLabel) {
align: align(top);
textFg: windowSubTextFg;
}
passcodeSystemUnlockSkip: 12px;
newGroupAboutFg: windowSubTextFg;
newGroupPadding: margins(4px, 6px, 4px, 3px);
@@ -585,7 +605,7 @@ groupStickersRemovePosition: point(6px, 6px);
groupStickersFieldPadding: margins(8px, 6px, 8px, 6px);
groupStickersField: InputField(defaultMultiSelectSearchField) {
placeholderFont: boxTextFont;
font: boxTextFont;
style: boxTextStyle;
placeholderMargins: margins(0px, 0px, 0px, 0px);
textMargins: margins(0px, 7px, 0px, 0px);
textBg: boxBg;
@@ -672,7 +692,6 @@ themesMenuToggle: IconButton(defaultIconButton) {
themesMenuPosition: point(-2px, 25px);
createPollField: InputField(defaultInputField) {
font: boxTextFont;
textMargins: margins(0px, 4px, 0px, 4px);
textAlign: align(left);
heightMin: 36px;
@@ -877,7 +896,6 @@ scheduleDateField: InputField(defaultInputField) {
placeholderScale: 0.;
heightMin: 30px;
textAlign: align(top);
font: font(14px);
}
scheduleTimeField: InputField(scheduleDateField) {
border: 0px;
@@ -905,7 +923,6 @@ muteBoxTimeField: InputField(scheduleDateField) {
placeholderScale: 0.;
heightMin: 30px;
textAlign: align(left);
font: font(14px);
}
muteBoxTimeFieldPadding: margins(5px, 0px, 5px, 0px);
@@ -81,7 +81,7 @@ void ChangeFilterById(
MTP_int(filter.id()),
filter.tl()
)).done([=, chat = history->peer->name(), name = filter.title()] {
const auto account = &history->session().account();
const auto account = not_null(&history->session().account());
if (const auto controller = Core::App().windowFor(account)) {
controller->showToast((add
? tr::lng_filters_toast_add
+10 -1
View File
@@ -1044,7 +1044,16 @@ not_null<Ui::InputField*> CreatePollBox::setupSolution(
solution->setInstantReplaces(Ui::InstantReplaces::Default());
solution->setInstantReplacesEnabled(
Core::App().settings().replaceEmojiValue());
solution->setMarkdownReplacesEnabled(true);
solution->setMarkdownReplacesEnabled(rpl::single(
Ui::MarkdownEnabledState{ Ui::MarkdownEnabled{ {
Ui::InputField::kTagBold,
Ui::InputField::kTagItalic,
Ui::InputField::kTagUnderline,
Ui::InputField::kTagStrikeOut,
Ui::InputField::kTagCode,
Ui::InputField::kTagSpoiler,
} } }
));
solution->setEditLinkCallback(
DefaultEditLinkCallback(_controller->uiShow(), solution));
solution->customTab(true);
@@ -463,6 +463,7 @@ void EditCaptionBox::rebuildPreview() {
st::defaultComposeControls,
gifPaused,
file,
[] { return true; },
Ui::AttachControls::Type::EditOnly);
_isPhoto = (media && media->isPhoto());
const auto withCheckbox = _isPhoto && CanBeCompressed(_albumType);
+74 -11
View File
@@ -1011,14 +1011,16 @@ void GiftPremiumValidator::showChoosePeerBox(const QString &ref) {
}) | ranges::views::filter([](UserData *u) -> bool {
return u;
}) | ranges::to<std::vector<not_null<UserData*>>>();
if (!users.empty()) {
const auto giftBox = show->show(
Box(GiftsBox, _controller, users, api, ref));
giftBox->boxClosing(
) | rpl::start_with_next([=] {
_manyGiftsLifetime.destroy();
}, giftBox->lifetime());
if (users.empty()) {
show->showToast(
tr::lng_settings_gift_premium_choose(tr::now));
}
const auto giftBox = show->show(
Box(GiftsBox, _controller, users, api, ref));
giftBox->boxClosing(
) | rpl::start_with_next([=] {
_manyGiftsLifetime.destroy();
}, giftBox->lifetime());
(*ignoreClose) = true;
peersBox->closeBox();
};
@@ -1644,12 +1646,60 @@ void AddCreditsHistoryEntryTable(
container,
st::giveawayGiftCodeTable),
st::giveawayGiftCodeTableMargin);
if (entry.bareId) {
const auto peerId = PeerId(entry.barePeerId);
if (peerId) {
auto text = tr::lng_credits_box_history_entry_peer();
AddTableRow(table, std::move(text), controller, peerId);
}
if (const auto msgId = MsgId(peerId ? entry.bareMsgId : 0)) {
const auto session = &controller->session();
const auto peer = session->data().peer(peerId);
if (const auto channel = peer->asBroadcast()) {
const auto username = channel->username();
const auto base = username.isEmpty()
? u"c/%1"_q.arg(peerToChannel(channel->id).bare)
: username;
const auto query = base + '/' + QString::number(msgId.bare);
const auto link = session->createInternalLink(query);
auto label = object_ptr<Ui::FlatLabel>(
table,
rpl::single(Ui::Text::Link(link)),
st::giveawayGiftCodeValue);
label->setClickHandlerFilter([=](const auto &...) {
controller->showPeerHistory(channel, {}, msgId);
return false;
});
AddTableRow(
table,
tr::lng_credits_box_history_entry_media(),
std::move(label),
st::giveawayGiftCodeValueMargin);
}
}
using Type = Data::CreditsHistoryEntry::PeerType;
if (entry.peerType == Type::AppStore) {
AddTableRow(
table,
tr::lng_credits_box_history_entry_peer(),
controller,
PeerId(entry.bareId));
tr::lng_credits_box_history_entry_via(),
tr::lng_credits_box_history_entry_app_store(
Ui::Text::RichLangValue));
} else if (entry.peerType == Type::PlayMarket) {
AddTableRow(
table,
tr::lng_credits_box_history_entry_via(),
tr::lng_credits_box_history_entry_play_market(
Ui::Text::RichLangValue));
} else if (entry.peerType == Type::Fragment) {
AddTableRow(
table,
tr::lng_credits_box_history_entry_via(),
tr::lng_credits_box_history_entry_fragment(
Ui::Text::RichLangValue));
} else if (entry.peerType == Type::Ads) {
AddTableRow(
table,
tr::lng_credits_box_history_entry_via(),
tr::lng_credits_box_history_entry_ads(Ui::Text::RichLangValue));
}
if (!entry.id.isEmpty()) {
constexpr auto kOneLineCount = 18;
@@ -1680,4 +1730,17 @@ void AddCreditsHistoryEntryTable(
tr::lng_gift_link_label_date(),
rpl::single(Ui::Text::WithEntities(langDateTime(entry.date))));
}
if (!entry.successDate.isNull()) {
AddTableRow(
table,
tr::lng_credits_box_history_entry_success_date(),
rpl::single(Ui::Text::WithEntities(langDateTime(entry.date))));
}
if (!entry.successLink.isEmpty()) {
AddTableRow(
table,
tr::lng_credits_box_history_entry_success_url(),
rpl::single(
Ui::Text::Link(entry.successLink, entry.successLink)));
}
}
@@ -133,8 +133,8 @@ void MaxInviteBox::paintEvent(QPaintEvent *e) {
auto option = QTextOption(style::al_left);
option.setWrapMode(QTextOption::WrapAnywhere);
p.setFont(_linkOver
? st::defaultInputField.font->underline()
: st::defaultInputField.font);
? st::defaultInputField.style.font->underline()
: st::defaultInputField.style.font);
p.setPen(st::defaultLinkButton.color);
const auto inviteLinkText = _channel->inviteLink().isEmpty()
? tr::lng_group_invite_create(tr::now)
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_peer_info_box.h"
#include "apiwrap.h"
#include "api/api_credits.h"
#include "api/api_peer_photo.h"
#include "api/api_user_names.h"
#include "main/main_session.h"
@@ -42,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_premium_limits.h"
#include "data/data_user.h"
#include "history/admin_log/history_admin_log_section.h"
#include "info/bot/earn/info_bot_earn_widget.h"
#include "info/channel_statistics/boosts/info_boosts_widget.h"
#include "info/profile/info_profile_values.h"
#include "info/info_memento.h"
@@ -52,6 +54,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/boost_box.h"
#include "ui/controls/emoji_button.h"
#include "ui/controls/userpic_button.h"
#include "ui/effects/premium_graphics.h"
#include "ui/rect.h"
#include "ui/rp_widget.h"
#include "ui/vertical_list.h"
#include "ui/toast/toast.h"
@@ -71,6 +75,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h"
#include "styles/style_info.h"
#include <QtSvg/QSvgRenderer>
namespace {
constexpr auto kBotManagerUsername = "BotFather"_cs;
@@ -343,6 +349,7 @@ private:
void fillPendingRequestsButton();
void fillBotUsernamesButton();
void fillBotBalanceButton();
void fillBotEditIntroButton();
void fillBotEditCommandsButton();
void fillBotEditSettingsButton();
@@ -1126,6 +1133,7 @@ void Controller::fillManageSection() {
::AddSkip(container, 0);
fillBotUsernamesButton();
fillBotBalanceButton();
fillBotEditIntroButton();
fillBotEditCommandsButton();
fillBotEditSettingsButton();
@@ -1536,6 +1544,84 @@ void Controller::fillBotUsernamesButton() {
{ &st::menuIconLinks });
}
void Controller::fillBotBalanceButton() {
Expects(_isBot);
struct State final {
rpl::variable<QString> balance;
};
auto &lifetime = _controls.buttonsLayout->lifetime();
const auto state = lifetime.make_state<State>();
const auto wrap = _controls.buttonsLayout->add(
object_ptr<Ui::SlideWrap<Ui::SettingsButton>>(
_controls.buttonsLayout,
EditPeerInfoBox::CreateButton(
_controls.buttonsLayout,
tr::lng_manage_peer_bot_balance(),
state->balance.value(),
[controller = _navigation->parentController(), peer = _peer] {
controller->showSection(Info::BotEarn::Make(peer));
},
st::manageGroupButton,
{})));
wrap->toggle(false, anim::type::instant);
const auto button = wrap->entity();
{
const auto api = button->lifetime().make_state<Api::CreditsStatus>(
_peer);
api->request({}, [=](Data::CreditsStatusSlice data) {
if (data.balance) {
wrap->toggle(true, anim::type::normal);
}
state->balance = QString::number(data.balance);
});
}
{
constexpr auto kSizeShift = 3;
constexpr auto kStrokeWidth = 5;
const auto icon = Ui::CreateChild<Ui::RpWidget>(button);
icon->resize(Size(st::menuIconLinks.width() - kSizeShift));
auto colorized = [&] {
auto f = QFile(Ui::Premium::Svg());
if (!f.open(QIODevice::ReadOnly)) {
return QString();
}
return QString::fromUtf8(
f.readAll()).replace(u"#fff"_q, u"#ffffff00"_q);
}();
colorized.replace(
u"stroke=\"none\""_q,
u"stroke=\"%1\""_q.arg(st::menuIconColor->c.name()));
colorized.replace(
u"stroke-width=\"1\""_q,
u"stroke-width=\"%1\""_q.arg(kStrokeWidth));
const auto svg = icon->lifetime().make_state<QSvgRenderer>(
colorized.toUtf8());
svg->setViewBox(svg->viewBox() + Margins(kStrokeWidth));
const auto starSize = Size(icon->height());
icon->paintRequest(
) | rpl::start_with_next([=] {
auto p = QPainter(icon);
svg->render(&p, Rect(starSize));
}, icon->lifetime());
button->sizeValue(
) | rpl::start_with_next([=](const QSize &size) {
icon->moveToLeft(
button->st().iconLeft + kSizeShift / 2.,
(size.height() - icon->height()) / 2);
}, icon->lifetime());
}
}
void Controller::fillBotEditIntroButton() {
Expects(_isBot);
@@ -2114,8 +2200,11 @@ void Controller::saveForum() {
channel->inputChannel,
MTP_bool(*_savingData.forum)
)).done([=](const MTPUpdates &result) {
const auto weak = base::make_weak(this);
channel->session().api().applyUpdates(result);
continueSave();
if (weak) { // todo better to be able to save in closed already box.
continueSave();
}
}).fail([=](const MTP::Error &error) {
if (error.type() == u"CHAT_NOT_MODIFIED"_q) {
continueSave();
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/event_filter.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "core/ui_integration.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_document.h"
@@ -351,8 +352,8 @@ object_ptr<Ui::RpWidget> AddReactionsSelector(
const auto customEmojiPaused = [controller = args.controller] {
return controller->isGifPausedAtLeastFor(PauseReason::Layer);
};
raw->setCustomEmojiFactory([=](QStringView data, Fn<void()> update)
-> std::unique_ptr<Ui::Text::CustomEmoji> {
auto factory = [=](QStringView data, Fn<void()> update)
-> std::unique_ptr<Ui::Text::CustomEmoji> {
const auto id = Data::ParseCustomEmojiData(data);
auto result = owner->customEmojiManager().create(
data,
@@ -364,7 +365,13 @@ object_ptr<Ui::RpWidget> AddReactionsSelector(
}
using namespace Ui::Text;
return std::make_unique<FirstFrameEmoji>(std::move(result));
}, std::move(customEmojiPaused));
};
raw->setCustomTextContext([=](Fn<void()> repaint) {
return std::any(Core::MarkedTextContext{
.session = session,
.customEmojiRepaint = std::move(repaint),
});
}, customEmojiPaused, customEmojiPaused, std::move(factory));
const auto callback = args.callback;
const auto isCustom = [=](DocumentId id) {
@@ -131,6 +131,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
return tr::lng_premium_summary_subtitle_translation();
case PremiumFeature::Business:
return tr::lng_premium_summary_subtitle_business();
case PremiumFeature::Effects:
return tr::lng_premium_summary_subtitle_effects();
case PremiumFeature::BusinessLocation:
return tr::lng_business_subtitle_location();
@@ -192,6 +194,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
return tr::lng_premium_summary_about_translation();
case PremiumFeature::Business:
return tr::lng_premium_summary_about_business();
case PremiumFeature::Effects:
return tr::lng_premium_summary_about_effects();
case PremiumFeature::BusinessLocation:
return tr::lng_business_about_location();
@@ -529,6 +533,7 @@ struct VideoPreviewDocument {
case PremiumFeature::Wallpapers: return "wallpapers";
case PremiumFeature::LastSeen: return "last_seen";
case PremiumFeature::MessagePrivacy: return "message_privacy";
case PremiumFeature::Effects: return "effects";
case PremiumFeature::BusinessLocation: return "business_location";
case PremiumFeature::BusinessHours: return "business_hours";
@@ -70,6 +70,7 @@ enum class PremiumFeature {
LastSeen,
MessagePrivacy,
Business,
Effects,
// Business features.
BusinessLocation,
+167 -36
View File
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "core/ui_integration.h" // Core::MarkedTextContext.
#include "data/data_credits.h"
#include "data/data_photo.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h"
@@ -39,6 +40,147 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_settings.h"
namespace Ui {
namespace {
struct PaidMediaData {
const Data::Invoice *invoice = nullptr;
HistoryItem *item = nullptr;
PeerData *peer = nullptr;
int photos = 0;
int videos = 0;
explicit operator bool() const {
return invoice && item && peer && (photos || videos);
}
};
[[nodiscard]] PaidMediaData LookupPaidMediaData(
not_null<Main::Session*> session,
not_null<Payments::CreditsFormData*> form) {
using namespace Payments;
const auto message = std::get_if<InvoiceMessage>(&form->id.value);
const auto item = message
? session->data().message(message->peer, message->itemId)
: nullptr;
const auto media = item ? item->media() : nullptr;
const auto invoice = media ? media->invoice() : nullptr;
if (!invoice || !invoice->isPaidMedia) {
return {};
}
auto photos = 0;
auto videos = 0;
for (const auto &media : invoice->extendedMedia) {
const auto photo = media->photo();
if (photo && !photo->extendedMediaVideoDuration().has_value()) {
++photos;
} else {
++videos;
}
}
const auto sender = item->originalSender();
const auto broadcast = (sender && sender->isBroadcast())
? sender
: message->peer.get();
return {
.invoice = invoice,
.item = item,
.peer = broadcast,
.photos = photos,
.videos = videos,
};
}
[[nodiscard]] rpl::producer<TextWithEntities> SendCreditsConfirmText(
not_null<Main::Session*> session,
not_null<Payments::CreditsFormData*> form) {
if (const auto data = LookupPaidMediaData(session, form)) {
auto photos = 0;
auto videos = 0;
for (const auto &media : data.invoice->extendedMedia) {
const auto photo = media->photo();
if (photo && !photo->extendedMediaVideoDuration().has_value()) {
++photos;
} else {
++videos;
}
}
auto photosBold = tr::lng_credits_box_out_photos(
lt_count,
rpl::single(photos) | tr::to_count(),
Ui::Text::Bold);
auto videosBold = tr::lng_credits_box_out_videos(
lt_count,
rpl::single(videos) | tr::to_count(),
Ui::Text::Bold);
auto media = (!videos)
? ((photos > 1)
? std::move(photosBold)
: tr::lng_credits_box_out_photo(Ui::Text::WithEntities))
: (!photos)
? ((videos > 1)
? std::move(videosBold)
: tr::lng_credits_box_out_video(Ui::Text::WithEntities))
: tr::lng_credits_box_out_both(
lt_photo,
std::move(photosBold),
lt_video,
std::move(videosBold),
Ui::Text::WithEntities);
return tr::lng_credits_box_out_media(
lt_count,
rpl::single(form->invoice.amount) | tr::to_count(),
lt_media,
std::move(media),
lt_chat,
rpl::single(Ui::Text::Bold(data.peer->name())),
Ui::Text::RichLangValue);
}
const auto bot = session->data().user(form->botId);
return tr::lng_credits_box_out_sure(
lt_count,
rpl::single(form->invoice.amount) | tr::to_count(),
lt_text,
rpl::single(TextWithEntities{ form->title }),
lt_bot,
rpl::single(TextWithEntities{ bot->name() }),
Ui::Text::RichLangValue);
}
[[nodiscard]] object_ptr<Ui::RpWidget> SendCreditsThumbnail(
not_null<Ui::RpWidget*> parent,
not_null<Main::Session*> session,
not_null<Payments::CreditsFormData*> form,
int photoSize) {
if (const auto data = LookupPaidMediaData(session, form)) {
const auto first = data.invoice->extendedMedia[0]->photo();
const auto second = (data.photos > 1)
? data.invoice->extendedMedia[1]->photo()
: nullptr;
const auto totalCount = int(data.invoice->extendedMedia.size());
if (first && first->extendedMediaPreview()) {
return Settings::PaidMediaThumbnail(
parent,
first,
second,
totalCount,
photoSize);
}
}
if (form->photo) {
return Settings::HistoryEntryPhoto(parent, form->photo, photoSize);
}
const auto bot = session->data().user(form->botId);
return object_ptr<Ui::UserpicButton>(
parent,
bot,
st::defaultUserpicButton);
}
} // namespace
void SendCreditsBox(
not_null<Ui::GenericBox*> box,
@@ -89,22 +231,10 @@ void SendCreditsBox(
}, ministarsContainer->lifetime());
}
const auto bot = session->data().user(form->botId);
if (form->photo) {
box->addRow(object_ptr<Ui::CenterWrap<>>(
content,
Settings::HistoryEntryPhoto(content, form->photo, photoSize)));
} else {
const auto widget = box->addRow(
object_ptr<Ui::CenterWrap<>>(
content,
object_ptr<Ui::UserpicButton>(
content,
bot,
st::defaultUserpicButton)));
widget->setAttribute(Qt::WA_TransparentForMouseEvents);
}
const auto thumb = box->addRow(object_ptr<Ui::CenterWrap<>>(
content,
SendCreditsThumbnail(content, session, form.get(), photoSize)));
thumb->setAttribute(Qt::WA_TransparentForMouseEvents);
Ui::AddSkip(content);
box->addRow(object_ptr<Ui::CenterWrap<>>(
@@ -118,14 +248,7 @@ void SendCreditsBox(
box,
object_ptr<Ui::FlatLabel>(
box,
tr::lng_credits_box_out_sure(
lt_count,
rpl::single(form->invoice.amount) | tr::to_count(),
lt_text,
rpl::single(TextWithEntities{ form->title }),
lt_bot,
rpl::single(TextWithEntities{ bot->name() }),
Ui::Text::RichLangValue),
SendCreditsConfirmText(session, form.get()),
st::creditsBoxAbout)));
Ui::AddSkip(content);
Ui::AddSkip(content);
@@ -158,26 +281,16 @@ void SendCreditsBox(
loadingAnimation->showOn(state->confirmButtonBusy.value());
}
{
const auto emojiMargin = QMargins(
0,
-st::moderateBoxExpandInnerSkip,
0,
0);
const auto buttonEmoji = Ui::Text::SingleCustomEmoji(
session->data().customEmojiManager().registerInternalEmoji(
st::settingsPremiumIconStar,
emojiMargin,
true));
auto buttonText = tr::lng_credits_box_out_confirm(
lt_count,
rpl::single(form->invoice.amount) | tr::to_count(),
lt_emoji,
rpl::single(buttonEmoji),
rpl::single(CreditsEmojiSmall(session)),
Ui::Text::RichLangValue);
const auto buttonLabel = Ui::CreateChild<Ui::FlatLabel>(
button,
rpl::single(QString()),
st::defaultFlatLabel);
st::creditsBoxButtonLabel);
std::move(
buttonText
) | rpl::start_with_next([=](const TextWithEntities &text) {
@@ -247,4 +360,22 @@ void SendCreditsBox(
}
}
TextWithEntities CreditsEmoji(not_null<Main::Session*> session) {
return Ui::Text::SingleCustomEmoji(
session->data().customEmojiManager().registerInternalEmoji(
st::settingsPremiumIconStar,
QMargins{ 0, -st::moderateBoxExpandInnerSkip, 0, 0 },
true),
QString(QChar(0x2B50)));
}
TextWithEntities CreditsEmojiSmall(not_null<Main::Session*> session) {
return Ui::Text::SingleCustomEmoji(
session->data().customEmojiManager().registerInternalEmoji(
st::starIconSmall,
st::starIconSmallPadding,
true),
QString(QChar(0x2B50)));
}
} // namespace Ui
@@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class HistoryItem;
namespace Main {
class Session;
} // namespace Main
namespace Payments {
struct CreditsFormData;
} // namespace Payments
@@ -22,4 +26,10 @@ void SendCreditsBox(
std::shared_ptr<Payments::CreditsFormData> data,
Fn<void()> sent);
[[nodiscard]] TextWithEntities CreditsEmoji(
not_null<Main::Session*> session);
[[nodiscard]] TextWithEntities CreditsEmojiSmall(
not_null<Main::Session*> session);
} // namespace Ui
+262 -7
View File
@@ -10,7 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "storage/storage_media_prepare.h"
#include "iv/iv_instance.h"
#include "mainwidget.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
#include "main/main_session_settings.h"
#include "mtproto/mtproto_config.h"
@@ -24,11 +26,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/controls/history_view_characters_limit.h"
#include "history/view/history_view_schedule_box.h"
#include "core/mime_type.h"
#include "core/ui_integration.h"
#include "base/event_filter.h"
#include "base/call_delayed.h"
#include "boxes/premium_limits_box.h"
#include "boxes/premium_preview_box.h"
#include "boxes/send_credits_box.h"
#include "ui/effects/scroll_content_shadow.h"
#include "ui/widgets/fields/number_input.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/popup_menu.h"
@@ -36,10 +41,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/attach/attach_single_file_preview.h"
#include "ui/chat/attach/attach_single_media_preview.h"
#include "ui/grouped_layout.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "ui/controls/emoji_button.h"
#include "ui/painter.h"
#include "ui/vertical_list.h"
#include "lottie/lottie_single_player.h"
#include "data/data_channel.h"
#include "data/data_document.h"
#include "data/data_user.h"
#include "data/data_peer_values.h" // Data::AmPremiumValue.
@@ -111,6 +119,84 @@ rpl::producer<QString> FieldPlaceholder(
: tr::lng_photos_comment();
}
void EditPriceBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session,
uint64 price,
Fn<void(uint64)> apply) {
box->setTitle(tr::lng_paid_title());
AddSubsectionTitle(
box->verticalLayout(),
tr::lng_paid_enter_cost(),
(st::boxRowPadding - QMargins(
st::defaultSubsectionTitlePadding.left(),
0,
st::defaultSubsectionTitlePadding.right(),
0)));
const auto limit = session->appConfig().get<int>(
u"stars_paid_post_amount_max"_q,
10'000);
const auto wrap = box->addRow(object_ptr<Ui::FixedHeightWidget>(
box,
st::editTagField.heightMin));
auto owned = object_ptr<Ui::NumberInput>(
wrap,
st::editTagField,
tr::lng_paid_cost_placeholder(),
price ? QString::number(price) : QString(),
limit);
const auto field = owned.data();
wrap->widthValue() | rpl::start_with_next([=](int width) {
field->move(0, 0);
field->resize(width, field->height());
wrap->resize(width, field->height());
}, wrap->lifetime());
field->selectAll();
box->setFocusCallback([=] {
field->setFocusFast();
});
const auto about = box->addRow(
object_ptr<Ui::FlatLabel>(
box,
tr::lng_paid_about(
lt_link,
tr::lng_paid_about_link() | Ui::Text::ToLink(),
Ui::Text::WithEntities),
st::paidAmountAbout),
st::boxRowPadding + QMargins(0, st::sendMediaRowSkip, 0, 0));
about->setClickHandlerFilter([=](const auto &...) {
Core::App().iv().openWithIvPreferred(
session,
tr::lng_paid_about_link_url(tr::now));
return false;
});
field->paintRequest() | rpl::start_with_next([=](QRect clip) {
auto p = QPainter(field);
st::paidStarIcon.paint(p, 0, st::paidStarIconTop, field->width());
}, field->lifetime());
const auto save = [=] {
const auto now = field->getLastText().toULongLong();
if (now > limit) {
field->showError();
return;
}
const auto weak = Ui::MakeWeak(box);
apply(now);
if (const auto strong = weak.data()) {
strong->closeBox();
}
};
QObject::connect(field, &Ui::NumberInput::submitted, box, save);
box->addButton(tr::lng_settings_save(), save);
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});
}
} // namespace
SendFilesLimits DefaultLimitsForPeer(not_null<PeerData*> peer) {
@@ -161,7 +247,8 @@ SendFilesBox::Block::Block(
int from,
int till,
Fn<bool()> gifPaused,
SendFilesWay way)
SendFilesWay way,
Fn<bool()> canToggleSpoiler)
: _items(items)
, _from(from)
, _till(till) {
@@ -178,14 +265,16 @@ SendFilesBox::Block::Block(
parent.get(),
st,
my,
way);
way,
std::move(canToggleSpoiler));
_preview.reset(preview);
} else {
const auto media = Ui::SingleMediaPreview::Create(
parent,
st,
gifPaused,
first);
first,
std::move(canToggleSpoiler));
if (media) {
_isSingleMedia = true;
_preview.reset(media);
@@ -261,6 +350,14 @@ rpl::producer<int> SendFilesBox::Block::itemModifyRequest() const {
}
}
rpl::producer<> SendFilesBox::Block::orderUpdated() const {
if (_isAlbum) {
const auto album = static_cast<Ui::AlbumPreview*>(_preview.get());
return album->orderUpdated();
}
return rpl::never<>();
}
void SendFilesBox::Block::setSendWay(Ui::SendFilesWay way) {
if (!_isAlbum) {
if (_isSingleMedia) {
@@ -329,6 +426,18 @@ void SendFilesBox::Block::applyChanges() {
}
}
QImage SendFilesBox::Block::generatePriceTagBackground() const {
const auto preview = _preview.get();
if (_isAlbum) {
const auto album = static_cast<Ui::AlbumPreview*>(preview);
return album->generatePriceTagBackground();
} else if (_isSingleMedia) {
const auto media = static_cast<Ui::SingleMediaPreview*>(preview);
return media->generatePriceTagBackground();
}
return QImage();
}
SendFilesBox::SendFilesBox(
QWidget*,
not_null<Window::SessionController*> controller,
@@ -393,6 +502,9 @@ Fn<SendMenu::Details()> SendFilesBox::prepareSendMenuDetails(
: _invertCaption
? SendMenu::CaptionState::Above
: SendMenu::CaptionState::Below;
result.price = canChangePrice()
? _price.current()
: std::optional<uint64>();
return result;
});
}
@@ -406,6 +518,7 @@ auto SendFilesBox::prepareSendMenuCallback()
case Type::CaptionUp: _invertCaption = true; break;
case Type::SpoilerOn: toggleSpoilers(true); break;
case Type::SpoilerOff: toggleSpoilers(false); break;
case Type::ChangePrice: changePrice(); break;
default:
SendMenu::DefaultCallback(
_show,
@@ -596,14 +709,27 @@ void SendFilesBox::refreshButtons() {
addMenuButton();
}
bool SendFilesBox::hasSendMenu(const SendMenu::Details &details) const {
bool SendFilesBox::hasSendMenu(const MenuDetails &details) const {
return (details.type != SendMenu::Type::Disabled)
|| (details.spoiler != SendMenu::SpoilerState::None)
|| (details.caption != SendMenu::CaptionState::None);
}
bool SendFilesBox::hasSpoilerMenu() const {
return _list.hasSpoilerMenu(_sendWay.current().sendImagesAsPhotos());
return !hasPrice()
&& _list.hasSpoilerMenu(_sendWay.current().sendImagesAsPhotos());
}
bool SendFilesBox::canChangePrice() const {
const auto way = _sendWay.current();
const auto broadcast = _captionToPeer
? _captionToPeer->asBroadcast()
: nullptr;
return broadcast
&& broadcast->canPostPaidMedia()
&& _list.canChangePrice(
way.groupFiles() && way.sendImagesAsPhotos(),
way.sendImagesAsPhotos());
}
void SendFilesBox::applyBlockChanges() {
@@ -626,6 +752,118 @@ void SendFilesBox::toggleSpoilers(bool enabled) {
}
}
void SendFilesBox::changePrice() {
const auto weak = Ui::MakeWeak(this);
const auto session = &_show->session();
const auto now = _price.current();
_show->show(Box(EditPriceBox, session, now, [=](uint64 price) {
if (weak && price != now) {
_price = price;
refreshPriceTag();
}
}));
}
bool SendFilesBox::hasPrice() const {
return canChangePrice() && _price.current() > 0;
}
void SendFilesBox::refreshPriceTag() {
const auto resetSpoilers = hasPrice() || _priceTag;
if (resetSpoilers) {
for (auto &file : _list.files) {
file.spoiler = false;
}
for (auto &block : _blocks) {
block.toggleSpoilers(hasPrice());
}
}
if (!hasPrice()) {
_priceTag = nullptr;
_priceTagBg = QImage();
} else if (!_priceTag) {
_priceTag = std::make_unique<Ui::RpWidget>(_inner.data());
const auto raw = _priceTag.get();
raw->show();
raw->paintRequest() | rpl::start_with_next([=] {
if (_priceTagBg.isNull()) {
_priceTagBg = preparePriceTagBg(raw->size());
}
QPainter(raw).drawImage(0, 0, _priceTagBg);
}, raw->lifetime());
const auto session = &_show->session();
auto price = _price.value() | rpl::map([=](uint64 amount) {
auto result = Ui::Text::Colorized(Ui::CreditsEmoji(session));
result.append(Lang::FormatCountDecimal(amount));
return result;
});
auto text = tr::lng_paid_price(
lt_price,
std::move(price),
Ui::Text::WithEntities);
const auto label = Ui::CreateChild<Ui::FlatLabel>(
raw,
QString(),
st::paidTagLabel);
std::move(text) | rpl::start_with_next([=](TextWithEntities &&text) {
label->setMarkedText(text, Core::MarkedTextContext{
.session = session,
.customEmojiRepaint = [=] { label->update(); },
});
}, label->lifetime());
label->show();
label->sizeValue() | rpl::start_with_next([=](QSize size) {
const auto inner = QRect(QPoint(), size);
const auto rect = inner.marginsAdded(st::paidTagPadding);
raw->resize(rect.size());
label->move(-rect.topLeft());
}, label->lifetime());
_inner->sizeValue() | rpl::start_with_next([=](QSize size) {
raw->move(
(size.width() - raw->width()) / 2,
(size.height() - raw->height()) / 2);
}, raw->lifetime());
} else {
_priceTag->raise();
_priceTag->update();
_priceTagBg = QImage();
}
}
QImage SendFilesBox::preparePriceTagBg(QSize size) const {
const auto ratio = style::DevicePixelRatio();
const auto outer = _blocks.empty()
? size
: _inner->widgetAt(0)->geometry().size();
auto bg = _blocks.empty()
? QImage()
: _blocks.front().generatePriceTagBackground();
if (bg.isNull()) {
bg = QImage(ratio, ratio, QImage::Format_ARGB32_Premultiplied);
bg.fill(Qt::black);
}
auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(ratio);
result.fill(Qt::black);
auto p = QPainter(&result);
auto hq = PainterHighQualityEnabler(p);
p.drawImage(
QRect(
(size.width() - outer.width()) / 2,
(size.height() - outer.height()) / 2,
outer.width(),
outer.height()),
bg);
p.fillRect(QRect(QPoint(), size), st::msgDateImgBg);
p.end();
const auto radius = std::min(size.width(), size.height()) / 2;
return Images::Round(std::move(result), Images::CornersMask(radius));
}
void SendFilesBox::addMenuButton() {
const auto details = _sendMenuDetails();
if (!hasSendMenu(details)) {
@@ -719,6 +957,7 @@ void SendFilesBox::initSendWay() {
block.setSendWay(value);
}
refreshButtons();
refreshPriceTag();
if (was != hidden()) {
updateBoxSize();
updateControlsGeometry();
@@ -804,7 +1043,8 @@ void SendFilesBox::pushBlock(int from, int till) {
from,
till,
gifPaused,
_sendWay.current());
_sendWay.current(),
[=] { return !hasPrice(); });
auto &block = _blocks.back();
const auto widget = _inner->add(
block.takeWidget(),
@@ -927,10 +1167,18 @@ void SendFilesBox::pushBlock(int from, int till) {
st::sendMediaPreviewSize,
[=] { refreshAllAfterChanges(from); });
}, widget->lifetime());
block.orderUpdated() | rpl::start_with_next([=]{
if (_priceTag) {
_priceTagBg = QImage();
_priceTag->update();
}
}, widget->lifetime());
}
void SendFilesBox::refreshControls(bool initial) {
refreshButtons();
refreshPriceTag();
refreshTitleText();
updateSendWayControls();
updateCaptionPlaceholder();
@@ -1499,6 +1747,7 @@ void SendFilesBox::send(
auto child = _sendMenuDetails();
child.spoiler = SendMenu::SpoilerState::None;
child.caption = SendMenu::CaptionState::None;
child.price = std::nullopt;
return SendMenu::DefaultCallback(_show, sendCallback())(
{ .type = SendMenu::ActionType::Schedule },
child);
@@ -1526,10 +1775,16 @@ void SendFilesBox::send(
auto caption = (_caption && !_caption->isHidden())
? _caption->getTextWithAppliedMarkdown()
: TextWithTags();
options.invertCaption = _invertCaption;
if (!validateLength(caption.text)) {
return;
}
options.invertCaption = _invertCaption;
options.price = hasPrice() ? _price.current() : 0;
if (options.price > 0) {
for (auto &file : _list.files) {
file.spoiler = false;
}
}
_confirmedCallback(
std::move(_list),
_sendWay.current(),
+14 -1
View File
@@ -149,7 +149,8 @@ private:
int from,
int till,
Fn<bool()> gifPaused,
Ui::SendFilesWay way);
Ui::SendFilesWay way,
Fn<bool()> canToggleSpoiler);
Block(Block &&other) = default;
Block &operator=(Block &&other) = default;
@@ -160,11 +161,14 @@ private:
[[nodiscard]] rpl::producer<int> itemDeleteRequest() const;
[[nodiscard]] rpl::producer<int> itemReplaceRequest() const;
[[nodiscard]] rpl::producer<int> itemModifyRequest() const;
[[nodiscard]] rpl::producer<> orderUpdated() const;
void setSendWay(Ui::SendFilesWay way);
void toggleSpoilers(bool enabled);
void applyChanges();
[[nodiscard]] QImage generatePriceTagBackground() const;
private:
base::unique_qptr<Ui::RpWidget> _preview;
not_null<std::vector<Ui::PreparedFile>*> _items;
@@ -190,6 +194,12 @@ private:
void addMenuButton();
void applyBlockChanges();
void toggleSpoilers(bool enabled);
void changePrice();
[[nodiscard]] bool canChangePrice() const;
[[nodiscard]] bool hasPrice() const;
void refreshPriceTag();
[[nodiscard]] QImage preparePriceTagBg(QSize size) const;
bool validateLength(const QString &text) const;
void refreshButtons();
@@ -251,6 +261,9 @@ private:
SendFilesCheck _check;
SendFilesConfirmed _confirmedCallback;
Fn<void()> _cancelledCallback;
rpl::variable<uint64> _price = 0;
std::unique_ptr<Ui::RpWidget> _priceTag;
QImage _priceTagBg;
bool _confirmed = false;
bool _invertCaption = false;
@@ -63,6 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
// AyuGram includes
#include "ayu/utils/telegram_helpers.h"
#include "styles/style_ayu_styles.h"
#include "window/window_session_controller.h"
#include "data/data_user.h"
@@ -1392,6 +1393,18 @@ void StickerSetBox::Inner::paintSticker(
(_singleSize.width() - size.width()) / 2,
(_singleSize.height() - size.height()) / 2);
auto lottieFrame = QImage();
if (sticker->setType == Data::StickersType::Stickers) {
QPainterPath path;
path.addRoundedRect(QRectF(ppos, size), st::stickerRoundingSize, st::stickerRoundingSize);
p.save();
p.setRenderHint(QPainter::Antialiasing, true);
p.setClipPath(path);
p.setRenderHint(QPainter::Antialiasing, false);
}
if (element.emoji) {
element.emoji->paint(p, {
.textColor = st::windowFg->c,
@@ -1425,6 +1438,11 @@ void StickerSetBox::Inner::paintSticker(
QRect(ppos, size),
_pathGradient.get());
}
if (sticker->setType == Data::StickersType::Stickers) {
p.restore();
}
if (premium) {
_premiumMark.paint(
p,
-1
View File
@@ -1393,7 +1393,6 @@ groupCallScheduleDateField: InputField(groupCallField) {
placeholderScale: 0.;
heightMin: 30px;
textAlign: align(top);
font: font(14px);
}
groupCallScheduleTimeField: InputField(groupCallScheduleDateField) {
textBg: groupCallMembersBg;
+6 -3
View File
@@ -706,7 +706,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
}
}
if (false && data.is_need_rating() && _id && _accessHash) {
const auto window = Core::App().windowFor(_user);
const auto window = Core::App().windowFor(
Window::SeparateId(_user));
const auto session = &_user->session();
const auto callId = _id;
const auto callAccessHash = _accessHash;
@@ -1402,7 +1403,8 @@ void Call::handleRequestError(const QString &error) {
_user->name())
: QString();
if (!inform.isEmpty()) {
if (const auto window = Core::App().windowFor(_user)) {
if (const auto window = Core::App().windowFor(
Window::SeparateId(_user))) {
window->show(Ui::MakeInformBox(inform));
} else {
Ui::show(Ui::MakeInformBox(inform));
@@ -1420,7 +1422,8 @@ void Call::handleControllerError(const QString &error) {
? tr::lng_call_error_audio_io(tr::now)
: QString();
if (!inform.isEmpty()) {
if (const auto window = Core::App().windowFor(_user)) {
if (const auto window = Core::App().windowFor(
Window::SeparateId(_user))) {
window->show(Ui::MakeInformBox(inform));
} else {
Ui::show(Ui::MakeInformBox(inform));
@@ -383,20 +383,14 @@ void Panel::initWindow() {
&& _fullScreenOrMaximized.current()) {
toggleFullScreen();
}
} else if (e->type() == QEvent::WindowStateChange && _call->rtmp()) {
const auto state = window()->windowState();
_fullScreenOrMaximized = (state & Qt::WindowFullScreen)
|| (state & Qt::WindowMaximized);
}
return base::EventFilterResult::Continue;
});
if (_call->rtmp()) {
QObject::connect(
window()->windowHandle(),
&QWindow::windowStateChanged,
[=](Qt::WindowState state) {
_fullScreenOrMaximized = (state == Qt::WindowFullScreen)
|| (state == Qt::WindowMaximized);
});
}
window()->setBodyTitleArea([=](QPoint widgetPoint) {
using Flag = Ui::WindowTitleHitTestFlag;
const auto titleRect = QRect(
@@ -585,7 +585,6 @@ void ChooseSourceProcess::setupSourcesGeometry() {
void ChooseSourceProcess::setupGeometryWithParent(
not_null<QWidget*> parent) {
_window->createWinId();
const auto parentScreen = [&] {
if (const auto screen = QGuiApplication::screenAt(
parent->geometry().center())) {
@@ -595,7 +594,12 @@ void ChooseSourceProcess::setupGeometryWithParent(
}();
const auto myScreen = _window->screen();
if (parentScreen && myScreen != parentScreen) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
_window->setScreen(parentScreen);
#else // Qt >= 6.0.0
_window->createWinId();
_window->windowHandle()->setScreen(parentScreen);
#endif // Qt < 6.0.0
}
_window->setFixedSize(_fixedSize);
_window->move(
@@ -71,6 +71,7 @@ ComposeIcons {
menuSpoilerOff: icon;
menuBelow: icon;
menuAbove: icon;
menuPrice: icon;
stripBubble: icon;
stripExpandPanel: icon;
@@ -610,6 +611,7 @@ defaultComposeIcons: ComposeIcons {
menuSpoilerOff: menuIconSpoilerOff;
menuBelow: menuIconBelow;
menuAbove: menuIconAbove;
menuPrice: menuIconEarn;
stripBubble: icon{
{ "chat/reactions_bubble_shadow", windowShadowFg },
@@ -989,8 +991,33 @@ historyUnreadReactions: TwoIconButton(historyToDown) {
}
historyUnreadThingsSkip: 4px;
historyQuoteStyle: QuoteStyle(defaultQuoteStyle) {
padding: margins(10px, 2px, 4px, 2px);
verticalSkip: 4px;
outline: 3px;
outlineShift: 2px;
radius: 5px;
}
historyTextStyle: TextStyle(defaultTextStyle) {
blockquote: QuoteStyle(historyQuoteStyle) {
padding: margins(10px, 2px, 20px, 2px);
icon: icon{{ "chat/mini_quote", windowFg }};
iconPosition: point(4px, 4px);
expand: icon{{ "intro_country_dropdown", windowFg }};
expandPosition: point(6px, 4px);
collapse: icon{{ "intro_country_dropdown-flip_vertical", windowFg }};
collapsePosition: point(6px, 4px);
}
pre: QuoteStyle(historyQuoteStyle) {
header: 20px;
headerPosition: point(10px, 2px);
scrollable: true;
icon: icon{{ "chat/mini_copy", windowFg }};
iconPosition: point(4px, 2px);
}
}
historyComposeField: InputField(defaultInputField) {
font: normalFont;
style: historyTextStyle;
textMargins: margins(0px, 0px, 0px, 0px);
textAlign: align(left);
textFg: historyComposeAreaFg;
@@ -1381,3 +1408,18 @@ editTagField: InputField(defaultInputField) {
editTagLimit: FlatLabel(defaultFlatLabel) {
textFg: windowSubTextFg;
}
paidStarIcon: icon {{ "settings/premium/star", creditsBg1 }};
paidStarIconTop: 7px;
paidAmountAbout: FlatLabel(defaultFlatLabel) {
minWidth: 256px;
textFg: windowSubTextFg;
}
paidTagLabel: FlatLabel(defaultFlatLabel) {
textFg: radialFg;
palette: TextPalette(defaultTextPalette) {
linkFg: creditsBg1;
}
style: semiboldTextStyle;
}
paidTagPadding: margins(16px, 6px, 16px, 6px);
@@ -30,15 +30,15 @@ ResolveWindow ResolveWindowDefault() {
return (Window::SessionController*)nullptr;
};
auto &app = Core::App();
const auto account = not_null(&session->account());
if (const auto a = check(app.activeWindow())) {
return a;
} else if (const auto b = check(app.activePrimaryWindow())) {
return b;
} else if (const auto c = check(app.windowFor(&session->account()))) {
} else if (const auto c = check(app.windowFor(account))) {
return c;
} else if (const auto d = check(
app.ensureSeparateWindowForAccount(
&session->account()))) {
} else if (const auto d = check(app.ensureSeparateWindowFor(
account))) {
return d;
}
return nullptr;
@@ -14,11 +14,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qthelp_regex.h"
#include "base/qthelp_url.h"
#include "base/event_filter.h"
#include "ui/chat/chat_style.h"
#include "ui/layers/generic_box.h"
#include "ui/rect.h"
#include "core/shortcuts.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "core/ui_integration.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "ui/wrap/vertical_layout.h"
@@ -40,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h"
#include "styles/style_chat.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_settings.h"
#include "base/qt/qt_common_adapters.h"
#include <QtCore/QMimeData>
@@ -58,6 +61,7 @@ using EditLinkSelection = Ui::InputField::EditLinkSelection;
constexpr auto kParseLinksTimeout = crl::time(500);
constexpr auto kTypesDuration = 4 * crl::time(1000);
constexpr auto kCodeLanguageLimit = 32;
// For mention / custom emoji tags save and validate selfId,
// ignore tags for different users.
@@ -222,6 +226,51 @@ void EditLinkBox(
}, text->lifetime());
}
void EditCodeLanguageBox(
not_null<Ui::GenericBox*> box,
QString now,
Fn<void(QString)> save) {
Expects(save != nullptr);
box->setTitle(tr::lng_formatting_code_title());
box->addRow(object_ptr<Ui::FlatLabel>(
box,
tr::lng_formatting_code_language(),
st::settingsAddReplyLabel));
const auto field = box->addRow(object_ptr<Ui::InputField>(
box,
st::settingsAddReplyField,
tr::lng_formatting_code_auto(),
now.trimmed()));
box->setFocusCallback([=] {
field->setFocusFast();
});
field->selectAll();
field->setMaxLength(kCodeLanguageLimit);
Ui::AddLengthLimitLabel(field, kCodeLanguageLimit);
const auto callback = [=] {
const auto name = field->getLastText().trimmed();
const auto check = QRegularExpression("^[a-zA-Z0-9\\+\\-]*$");
if (check.match(name).hasMatch()) {
auto weak = Ui::MakeWeak(box);
save(name);
if (const auto strong = weak.data()) {
strong->closeBox();
}
} else {
field->showError();
}
};
field->submits(
) | rpl::start_with_next(callback, field->lifetime());
box->addButton(tr::lng_settings_save(), callback);
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});
}
TextWithEntities StripSupportHashtag(TextWithEntities text) {
static const auto expression = QRegularExpression(
u"\\n?#tsf[a-z0-9_-]*[\\s#a-z0-9_-]*$"_q,
@@ -274,15 +323,24 @@ TextWithTags PrepareEditText(not_null<HistoryItem*> item) {
bool EditTextChanged(
not_null<HistoryItem*> item,
const TextWithTags &updated) {
TextWithTags updated) {
const auto original = PrepareEditText(item);
auto originalWithEntities = TextWithEntities{
std::move(original.text),
TextUtilities::ConvertTextTagsToEntities(original.tags)
};
auto updatedWithEntities = TextWithEntities{
std::move(updated.text),
TextUtilities::ConvertTextTagsToEntities(updated.tags)
};
TextUtilities::PrepareForSending(originalWithEntities, 0);
TextUtilities::PrepareForSending(updatedWithEntities, 0);
// Tags can be different for the same entities, because for
// animated emoji each tag contains a different random number.
// So we compare entities instead of tags.
return (original.text != updated.text)
|| (TextUtilities::ConvertTextTagsToEntities(original.tags)
!= TextUtilities::ConvertTextTagsToEntities(updated.tags));
return originalWithEntities != updatedWithEntities;
}
Fn<bool(
@@ -320,6 +378,13 @@ Fn<bool(
};
}
Fn<void(QString now, Fn<void(QString)> save)> DefaultEditLanguageCallback(
std::shared_ptr<Ui::Show> show) {
return [=](QString now, Fn<void(QString)> save) {
show->showBox(Box(EditCodeLanguageBox, now, save));
};
}
void InitMessageFieldHandlers(
not_null<Main::Session*> session,
std::shared_ptr<Main::SessionShow> show,
@@ -329,12 +394,16 @@ void InitMessageFieldHandlers(
const style::InputField *fieldStyle) {
field->setTagMimeProcessor(
FieldTagMimeProcessor(session, allowPremiumEmoji));
const auto paused = [customEmojiPaused] {
field->setCustomTextContext([=](Fn<void()> repaint) {
return std::any(Core::MarkedTextContext{
.session = session,
.customEmojiRepaint = std::move(repaint),
});
}, [customEmojiPaused] {
return On(PowerSaving::kEmojiChat) || customEmojiPaused();
};
field->setCustomEmojiFactory(
session->data().customEmojiManager().factory(),
std::move(customEmojiPaused));
}, [customEmojiPaused] {
return On(PowerSaving::kChatSpoiler) || customEmojiPaused();
});
field->setInstantReplaces(Ui::InstantReplaces::Default());
field->setInstantReplacesEnabled(
Core::App().settings().replaceEmojiValue());
@@ -342,8 +411,18 @@ void InitMessageFieldHandlers(
if (show) {
field->setEditLinkCallback(
DefaultEditLinkCallback(show, field, fieldStyle));
field->setEditLanguageCallback(DefaultEditLanguageCallback(show));
InitSpellchecker(show, field, fieldStyle != nullptr);
}
const auto style = field->lifetime().make_state<Ui::ChatStyle>(
session->colorIndicesValue());
field->setPreCache([=] {
return style->messageStyle(false, false).preCache.get();
});
field->setBlockquoteCache([=] {
const auto colorIndex = session->user()->colorIndex();
return style->coloredQuoteCache(false, colorIndex).get();
});
}
[[nodiscard]] bool IsGoodFactcheckUrl(QStringView url) {
@@ -569,12 +648,26 @@ void InitMessageFieldFade(
Ui::DestroyChild(b.data());
}, topFade->lifetime());
topFade->show();
bottomFade->showOn(
field->scrollTop().value(
) | rpl::map([field, descent = field->st().font->descent](int scroll) {
return (scroll + descent) < field->scrollTopMax();
}) | rpl::distinct_until_changed());
const auto descent = field->st().style.font->descent;
rpl::merge(
field->changes(),
field->scrollTop().changes() | rpl::to_empty,
field->sizeValue() | rpl::to_empty
) | rpl::start_with_next([=] {
// InputField::changes fires before the auto-resize is being applied,
// so for the scroll values to be accurate we enqueue the check.
InvokeQueued(field, [=] {
const auto topHidden = !field->scrollTop().current();
if (topFade->isHidden() != topHidden) {
topFade->setVisible(!topHidden);
}
const auto adjusted = field->scrollTop().current() + descent;
const auto bottomHidden = (adjusted >= field->scrollTopMax());
if (bottomFade->isHidden() != bottomHidden) {
bottomFade->setVisible(!bottomHidden);
}
});
}, topFade->lifetime());
}
InlineBotQuery ParseInlineBotQuery(
@@ -766,11 +859,7 @@ bool MessageLinksParser::eventFilter(QObject *object, QEvent *event) {
const auto text = static_cast<QKeyEvent*>(event)->text();
if (!text.isEmpty() && text.size() < 3) {
const auto ch = text[0];
if (false
|| ch == '\n'
|| ch == '\r'
|| ch.isSpace()
|| ch == QChar::LineSeparator) {
if (IsSpace(ch)) {
_timer.callOnce(0);
}
}
@@ -1097,7 +1186,9 @@ base::unique_qptr<Ui::RpWidget> PremiumRequiredSendRestriction(
const auto margins = (st.textMargins + st.placeholderMargins);
const auto available = width - margins.left() - margins.right();
label->resizeToWidth(available);
label->moveToLeft(margins.left(), margins.top(), width);
const auto height = label->height() + link->height();
const auto top = (raw->height() - height) / 2;
label->moveToLeft(margins.left(), top, width);
link->move(
(width - link->width()) / 2,
label->y() + label->height());
@@ -1117,8 +1208,8 @@ void SelectTextInFieldWithMargins(
auto textCursor = field->textCursor();
// Try to set equal margins for top and bottom sides.
const auto charsCountInLine = field->width()
/ field->st().font->width('W');
const auto linesCount = (field->height() / field->st().font->height);
/ field->st().style.font->width('W');
const auto linesCount = field->height() / field->st().style.font->height;
const auto selectedLines = (selection.to - selection.from)
/ charsCountInLine;
constexpr auto kMinDiff = ushort(3);

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