Compare commits

...

165 Commits

Author SHA1 Message Date
ZavaruKitsu 95f18f2120 fix: tray and serialization 2023-11-10 18:36:47 +03:00
ZavaruKitsu ae3dfacdf9 feat: add toggles to customization 2023-11-10 17:36:37 +03:00
ZavaruKitsu aa0d733cde feat: simple quotes & replies
Just like in 64Gram, but with ripples

Co-authored-by: c0re100 <corehusky@gmail.com>
2023-11-10 15:54:23 +03:00
ZavaruKitsu a5b446f6df Merge tag 'v4.11.6' into dev
# Conflicts:
#	Telegram/CMakeLists.txt
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/lib_ui
2023-11-10 13:26:08 +03:00
John Preston 2afc171bec Version 4.11.6: Fix build with GCC. 2023-11-10 00:32:52 +04:00
John Preston d6bd88d119 Version 4.11.6.
- Support multiple boosts and reassignment.
- Improve giveaway creation flow.
- Fix crash in topics creation.
2023-11-09 23:18:50 +04:00
John Preston 639a82ce28 Add confirmation for prepared giveaway start. 2023-11-09 23:18:50 +04:00
Ilya Fedin ef1b197771 Update lib_ui & patches 2023-11-09 22:44:52 +04:00
John Preston ad05998575 Update reply / forward icons in context menu. 2023-11-09 22:40:09 +04:00
John Preston b403f600e7 Use correct color for channels in giveaway. 2023-11-09 22:33:14 +04:00
John Preston 9b2f2b104f Show enlarge photo button in webpage preview. 2023-11-09 22:33:14 +04:00
John Preston e4d920b148 Show multiboost "x5" badge in boost box. 2023-11-09 22:33:14 +04:00
John Preston c5d1739e95 Implement multiboost reassign box. 2023-11-09 22:33:14 +04:00
John Preston a41bbd27c8 Start multiboosts, support dynamic state. 2023-11-09 22:33:14 +04:00
John Preston 2d67557a91 Drag correct element from file album. 2023-11-09 22:33:14 +04:00
23rd ca1a548fb8 Added boost badge to buttons for prepaid giveaways. 2023-11-09 16:27:54 +03:00
23rd 97bd865916 Added terms to bottom of giveaway box for prepaid giveaways. 2023-11-09 16:02:18 +03:00
23rd f7ab8298cf Added show more button to statistics info for list of recent messages. 2023-11-09 16:02:18 +03:00
23rd 33cf9a0702 Fixed expiration date of boosts in boosts list. 2023-11-09 16:02:18 +03:00
23rd 282c076931 Removed redundant peerListShowBox / peerListHideLayer from delegates. 2023-11-09 16:02:18 +03:00
23rd 135ffb13fd Added all joined channels to list in giveaway box. 2023-11-09 16:02:18 +03:00
23rd 9d4e1689fa Added state restoring to list for boost awarding members. 2023-11-09 16:02:18 +03:00
23rd 27e2a4b5d2 Fixed width of tabs for different boosts lists. 2023-11-09 16:02:18 +03:00
23rd c9cad4186b Added initial list of prepaid giveaway to boosts info. 2023-11-09 16:02:18 +03:00
23rd 3522d9c62e Added API support for prepaid giveaways. 2023-11-09 14:18:26 +03:00
23rd 43aa8825a5 Added badge and loading state to confirm button in giveaway box. 2023-11-09 14:18:26 +03:00
ZavaruKitsu 4b28e910e8 Merge tag 'v4.11.5' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/platform/win/tray_win.cpp
#	Telegram/lib_ui
2023-11-08 21:33:14 +03:00
23rd 4150cdff86 Moved out badge for giveaway list to td_ui. 2023-11-08 15:22:48 +03:00
23rd 474fa56cc0 Improved processing of giveaway creation after payment. 2023-11-08 15:22:48 +03:00
23rd 6ca777102c Added ability to paint non-optimized ministars to fix possible glitches. 2023-11-07 20:23:42 +03:00
23rd 49d5cf939c Added special fading-in top bar with title to giveaway box. 2023-11-07 20:23:42 +03:00
23rd b56b9b1fb9 Added ability to set background color for premium top bar via styles. 2023-11-07 20:23:42 +03:00
23rd 0293700e0f Added ability to ignore dark themes in premium top bar via styles. 2023-11-07 20:23:42 +03:00
John Preston 524a7a6a23 Fix wrong popup menu click-through on macOS 14.1.
Fixes #27025.
2023-11-07 12:40:29 +04:00
John Preston b1459e41d3 Fix system version check for dark taskbar support.
Fixes #27056.
2023-11-07 11:47:10 +04:00
John Preston ef685aa0da Fix via @bot badge in unwrapped media.
Fixes #27048.
2023-11-07 09:14:32 +04:00
John Preston 3ac222db62 Fix initial scroll to search result in bots. 2023-11-07 09:09:09 +04:00
Julian Sparber 642b0ed032 Install monochrome icon as symbolic app icon on Linux
GNOME Shell uses the symbolic icon in the topbar and notifications.
2023-11-07 08:38:10 +04:00
John Preston a7090c5fba Fix possible crash in topic replies. 2023-11-07 08:35:58 +04:00
23rd ebcd4eb97b Added box for pending giftcodes. 2023-11-07 05:35:28 +03:00
23rd a76534b19f Fixed opening of same boosts info multiple times. 2023-11-07 03:27:20 +03:00
23rd ee33d139cd Improved style of tabs in boosts info. 2023-11-07 03:27:20 +03:00
23rd c9cabfb084 Fixed API support for different boosts lists. 2023-11-07 03:27:20 +03:00
23rd 3dd415d0c2 Removed wheel support from slider in giveaway box. 2023-11-07 03:27:20 +03:00
23rd 4592e4e4bb Slightly improved style of boosts info. 2023-11-07 03:27:20 +03:00
23rd 1cb762913c Fixed text of confirm box in giveaway box. 2023-11-07 03:27:04 +03:00
John Preston 6eb7d68d49 Version 4.11.5.
- Giveaway phrases and sticker fixes.
- Show quoted part in channel comments.
- Show replies with icons and multiline preview.
- Send correct replies in topics and channel comments.
- In monochrome Windows tray icon use dot instead of counter.
2023-11-06 22:21:00 +04:00
John Preston 36662c51dd Fix giveaway sticker and phrases. 2023-11-06 22:16:12 +04:00
John Preston 4e915e9d1a Beta version 4.11.4: Fix build with GCC. 2023-11-06 20:31:11 +04:00
John Preston 86d6280776 Fix bidi data init. 2023-11-06 20:30:41 +04:00
John Preston eea7caeb94 Fix a phrase in giveaway info. 2023-11-06 20:29:41 +04:00
John Preston b77e74de7f Beta version 4.11.4.
- Show quoted part in channel comments.
- Show replies with icons and multiline preview.
- Send correct replies in topics and channel comments.
- In monochrome Windows tray icon use dot instead of counter.
2023-11-06 14:50:21 +04:00
John Preston 8a804fcfad Add toasts about giveaway/gift start. 2023-11-06 14:41:42 +04:00
John Preston f7ad91e80c Fix round video link preview with reactions. 2023-11-06 13:39:05 +04:00
John Preston 61a9d9c01d Don't close schedule media box by outside click. 2023-11-06 12:47:37 +04:00
23rd e98f56b0b7 Fixed aspect ratio of non-standard stickers in photo editor. 2023-11-06 12:41:15 +04:00
John Preston b2eeab53c5 Improve 5-line reply text elision. 2023-11-06 12:35:27 +04:00
John Preston d7539349c7 Always show manual quote replies, hide redundant. 2023-11-06 12:35:08 +04:00
John Preston 5350c97f82 Fix sending replies in forums. 2023-11-06 12:31:59 +04:00
John Preston 20ba417ddd Fix sending messages from "View as Messages". 2023-11-06 12:06:21 +04:00
ZavaruKitsu 5b6f26af21 fix: make it compile 2023-11-05 21:40:56 +03:00
ZavaruKitsu ac1da83401 Merge tag 'v4.11.3' into dev
# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/info/profile/info_profile_values.cpp
#	Telegram/lib_ui
#	snap/snapcraft.yaml
2023-11-05 21:23:03 +03:00
ZavaruKitsu 7b32e9af5e feat: add ease like on Android 2023-11-05 21:14:16 +03:00
John Preston 332ae22111 Fix build of crashpad with Xcode < 15. 2023-11-05 11:01:49 +04:00
John Preston b8c76cac61 Use dot in monochrome tray icon on Windows. 2023-11-05 00:03:44 +04:00
John Preston 150432e4d1 Add explicit CMAKE_MSVC_RUNTIME_LIBRARY. 2023-11-04 23:19:12 +04:00
John Preston d6c3760646 Improve external reply icons paddings. 2023-11-04 21:24:21 +04:00
John Preston 537c656ee1 Show external reply media preview. 2023-11-04 21:24:21 +04:00
John Preston 4e0490494e Extract reply view to a separate component. 2023-11-04 21:24:21 +04:00
John Preston 56ad825693 Attempt to fix build on Clang. 2023-11-04 21:24:21 +04:00
John Preston aab4ac8526 Fix story replies. 2023-11-04 21:24:21 +04:00
John Preston 5c98406e1a Expandable quote snippets in replies. 2023-11-04 21:24:19 +04:00
John Preston 3b40bc6297 Show full reply names with icons. 2023-11-04 21:24:14 +04:00
John Preston 12e164c4df Fix multiline terms checkbox. 2023-11-04 21:24:12 +04:00
23rd 855cc8e900 Updated some dependencies. 2023-11-04 21:24:02 +04:00
23rd 0a38cf2501 Updated Qt to 5.15.11 on Windows. 2023-11-04 21:24:02 +04:00
23rd 6def067e98 Updated Qt to 6.2.6 on macOS. 2023-11-04 21:24:02 +04:00
23rd a4e5ea01dc Added icon to language button in settings from intro. 2023-11-04 21:24:02 +04:00
23rd f4cfbc5ed8 Improved behavior of show more button in boosts list from boosts info. 2023-11-04 21:24:02 +04:00
23rd 336705a503 Fixed description in box for boosting.
Regression was introduced in d82c422ea1.
2023-11-04 21:24:02 +04:00
23rd 764b0d3dcd Added loading label to boosts info. 2023-11-04 21:24:01 +04:00
23rd 72c8999e50 Added initial tabbed selector for different boosts lists in boosts info. 2023-11-04 21:24:01 +04:00
23rd 79b5f7eda9 Added initial API support for different boosts lists. 2023-11-04 21:24:01 +04:00
23rd 6fcf80c6cf Added initial right badges for complex boost entries in boosts info. 2023-11-04 21:24:01 +04:00
23rd e9a8acdc54 Added initial click handler to boosts list in boosts info. 2023-11-04 21:24:01 +04:00
23rd 01573af0de Added initial support of complex boosts list in boosts info. 2023-11-04 21:24:01 +04:00
23rd 69b24c494e Added multiplier badge to boosts list in boosts info. 2023-11-04 21:24:01 +04:00
23rd 2b4047b20d Added support of some backend limitations for giveaways. 2023-11-04 21:24:01 +04:00
23rd 2b1a46356a Slightly improved style of giveaway box. 2023-11-04 21:24:01 +04:00
23rd 36a91dd32b Moved out giveaway styles to separated file. 2023-11-04 21:24:01 +04:00
23rd d8e38b43d9 Added simple label for loading state to giveaway box. 2023-11-04 21:24:01 +04:00
23rd d2d69a7a36 Added premium star to top of giveaway box. 2023-11-04 21:24:01 +04:00
23rd 85fdc04d48 Added ability to create giveaways from giveaway box. 2023-11-04 21:24:01 +04:00
23rd 5e28b2d601 Added ability to select channels to giveaway box. 2023-11-04 21:24:01 +04:00
23rd 33f6fc7d8c Added list controller to giveaway box to display selected channels. 2023-11-04 21:24:01 +04:00
23rd 3c8188e0b4 Added channel list controller to giveaway box for channel selecting. 2023-11-04 21:24:01 +04:00
23rd 3ecf3f7c55 Moved out peer list controller for giveaway box to separated file. 2023-11-04 21:24:01 +04:00
23rd fc6d4d66b7 Added ability to filter users by countries for giveaway to giveaway box. 2023-11-04 21:24:01 +04:00
23rd 2d097ca9ae Added box for selecting countries. 2023-11-04 21:24:01 +04:00
23rd af03660cab Added ability to choose date for giveaway to giveaway box. 2023-11-04 21:24:01 +04:00
23rd 986d347ea4 Added slider for prize quantity to giveaway box. 2023-11-04 21:24:01 +04:00
23rd 2dcd8a9640 Added ability to award specific users in giveaway box. 2023-11-04 21:24:01 +04:00
23rd 5a55e850d9 Added subtext to list of giftcode options in giveaway box. 2023-11-04 21:24:01 +04:00
23rd aa6edea33a Added list of giftcode options to giveaway box. 2023-11-04 21:24:01 +04:00
23rd e67d2e5db2 Added API support for premium giftcode options. 2023-11-04 21:24:01 +04:00
23rd 67bbb477c7 Added ability to select users for awarding in giveaway box. 2023-11-04 21:24:01 +04:00
23rd 5b0c48bb52 Added dummy box for creating giveaway. 2023-11-04 21:24:01 +04:00
23rd e00016312e Added button for giveaway creating to boosts info. 2023-11-04 21:24:01 +04:00
23rd 9df551a145 Improved API support of boosts list. 2023-11-04 21:24:00 +04:00
23rd 1852161fbf Moved out generating unique PeerListRowId from string to single place. 2023-11-04 21:24:00 +04:00
GitHub Action 1851b6ff30 Update User-Agent for DNS to Chrome 118.0.5993.117. 2023-11-04 20:51:41 +04:00
Ilya Fedin 98f3fa76a2 Add CI for macOS packaged build 2023-11-04 20:51:26 +04:00
Ilya Fedin 6db4b8821e Add support for building iconset and plist without Xcode 2023-11-04 20:51:26 +04:00
Ilya Fedin 0f45abd534 Make WithSmallCounter adaptive 2023-11-04 20:50:58 +04:00
ZavaruKitsu 4ad0804d55 fix: refactor a bit 2023-11-03 22:21:48 +03:00
John Preston 9e10a80e00 Version 4.11.3.
- Fix adding a link to media captions in scheduled / comments.
- Fix crash in link preview options saving.
- Fix possible crash in statistics.
2023-11-02 20:31:53 +04:00
John Preston 01d9864036 Workaround crash in statistics. 2023-11-02 20:30:48 +04:00
John Preston 8927a1b9a2 Fix media caption adding link in replies/scheduled. 2023-11-02 20:30:48 +04:00
John Preston b41c94be29 Fix crash in link preview edit. 2023-11-02 20:30:48 +04:00
John Preston 8ebf329cd9 Display group / channel id in profile. 2023-11-02 20:30:48 +04:00
ZavaruKitsu c3251aaf7b feat: really MD3 switches
Also removed icons for rights, because Android version doesn't have them.
2023-11-02 18:16:35 +03:00
John Preston d031046edb Version 4.11.2: Fix build with GCC. 2023-11-02 00:06:42 +04:00
John Preston 7808cc6d41 Version 4.11.2: Fix build with Xcode. 2023-11-01 22:57:36 +04:00
John Preston a7b60c43b5 Version 4.11.2.
- Highlight quoted parts in jump-to-message from replies.
- Ctrl+Click on message field reply bar to jump to message.
- Fix empty link preview displaying when generation failed.
- Fix external replies in topic groups.
- Allow enabling legacy tray icon on Windows.
2023-11-01 22:26:15 +04:00
John Preston a8b959826c Don't activate main window in case of visible call window.
Fixes #27017.
2023-11-01 22:24:09 +04:00
John Preston 42f96f3c43 Fix build with Xcode. 2023-11-01 22:24:09 +04:00
John Preston cc97093c5a Instantly jump-to-message on reply bar ctrl+click. 2023-11-01 22:13:21 +04:00
John Preston 7d5d086ade Allow messages when accepting miniapp terms. 2023-11-01 21:04:25 +04:00
John Preston 3da44eb5dd Fix attach menu suggested bot launch. 2023-11-01 21:04:25 +04:00
John Preston 4955cdcdce Wait for main menu bot icon to load. 2023-11-01 21:04:25 +04:00
ZavaruKitsu b806e714a6 fix: badge improvements 2023-11-01 18:37:11 +03:00
23rd 597195a2e2 Replaced Session Controller with Navigation for resolving of giftcodes. 2023-11-01 17:01:25 +03:00
23rd 5966c74a27 Added ability to go to message from message preview in statistics info. 2023-11-01 17:00:26 +03:00
John Preston caa1ae4436 Fix inline bots with secondary usernames. 2023-11-01 16:39:46 +04:00
ZavaruKitsu 15ee46dab4 fix: pin without sound by default
https://github.com/kotatogram/kotatogram-desktop/commit/faee00a9aa0c2ef815b5567fc699a1b3f41745aa
2023-11-01 15:07:16 +03:00
ZavaruKitsu acea390f3a feat: show controls for GIFs 2023-11-01 14:48:26 +03:00
John Preston af5ad84e72 Fix crashpad_handler linking workaround.
Fixes #26873.
2023-11-01 09:27:06 +04:00
John Preston 728ed02a1c Allow selecting text in webpage previews. 2023-11-01 09:17:08 +04:00
John Preston 8e369a4aa5 Fix moved up link preview with long text. 2023-11-01 08:44:25 +04:00
ZavaruKitsu 1f66e8ebeb feat: more branding 2023-11-01 01:00:37 +03:00
ZavaruKitsu d0b0b02b62 fix: crashes in confirmations 2023-11-01 00:17:47 +03:00
John Preston 35e457c924 Fix quote create in RepliesWidget. 2023-10-31 23:41:41 +04:00
John Preston 097c3c4a5a Allow changing album quote before sending. 2023-10-31 23:25:26 +04:00
John Preston 10022a3c6d Highlight quotes in replies to file albums. 2023-10-31 23:06:21 +04:00
John Preston 0dbb195106 Highlight quotes in replies to albums. 2023-10-31 22:37:59 +04:00
23rd 6493cb9ed8 Fixed mouse wheel handling in vertical drum picker without animation. 2023-10-31 13:11:01 +03:00
John Preston 1cfda38345 Fix reply in topic after creation. 2023-10-31 13:20:30 +04:00
John Preston bf20dbe3bc Fix external replies to different topic groups. 2023-10-31 13:13:31 +04:00
John Preston 46d3f232af Don't drop reply info on empty message submit. 2023-10-31 13:08:32 +04:00
John Preston ade97fd2d2 Fix unwrapped reply to monospace. 2023-10-31 13:00:03 +04:00
John Preston 39614aab3f Fix unwrapped reply overlapping timestamp. 2023-10-31 12:59:52 +04:00
John Preston 6bab2b4df6 Improve quotes composing. 2023-10-31 12:59:32 +04:00
John Preston b4c7272351 Keep external replies in forwards. 2023-10-31 12:21:07 +04:00
John Preston d831775e2f Fix replying in the same history. 2023-10-31 11:19:57 +04:00
John Preston bde39970a0 Fix boost reassign. 2023-10-31 11:17:55 +04:00
John Preston 076291b98f Fix reply invalidation on message removal. 2023-10-31 10:53:20 +04:00
John Preston 1341907cfd Disable external replies for non-forwardable. 2023-10-31 10:50:17 +04:00
John Preston b793c06759 Fix external replies in topic groups. 2023-10-31 10:39:54 +04:00
John Preston 475b2ac739 Fix external quote-reply to topic message. 2023-10-31 09:01:20 +04:00
John Preston d1c310de00 Highlight reply quote in original message. 2023-10-31 09:01:20 +04:00
John Preston 8615a25cd1 Fix empty preview if sent while failing generating.
Fixes #27004.
2023-10-31 09:01:20 +04:00
Ilya Fedin de4eb1e59b Disable glib tests and introspection generation in snap 2023-10-31 08:16:05 +04:00
Ilya Fedin 8e8f6f905f Build newer meson in snap 2023-10-31 08:16:05 +04:00
John Preston a57eecd420 Add option to use old tray icon.
New monochrome icon is default for the new installations.

Fixes #26983, fixes #26988, fixes #26989, fixes #26991, fixes #27005.
2023-10-30 11:16:17 +04:00
John Preston f306b11676 Add id-s only when displayed in profile. 2023-10-30 10:51:11 +04:00
260 changed files with 8484 additions and 2819 deletions
+158
View File
@@ -0,0 +1,158 @@
name: MacOS Packaged.
on:
push:
paths-ignore:
- 'docs/**'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/mac_packaged.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/configure.bat'
pull_request:
paths-ignore:
- 'docs/**'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/mac_packaged.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/configure.bat'
jobs:
macos:
name: MacOS
runs-on: macos-latest
strategy:
matrix:
defines:
- ""
env:
GIT: "https://github.com"
OPENALDIR: "/usr/local/opt/openal-soft"
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
MANUAL_CACHING: "1"
AUTO_CACHING: "1"
steps:
- name: Get repository name.
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone.
uses: actions/checkout@v3.1.0
with:
submodules: recursive
path: ${{ env.REPO_NAME }}
- name: First set up.
run: |
brew install autoconf automake boost cmake ffmpeg openal-soft openssl opus ninja pkg-config python qt yasm xz
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
xcodebuild -version > CACHE_KEY.txt
echo $MANUAL_CACHING >> CACHE_KEY.txt
echo "$GITHUB_WORKSPACE" >> CACHE_KEY.txt
if [ "$AUTO_CACHING" = "1" ]; then
thisFile=$REPO_NAME/.github/workflows/mac_packaged.yml
echo `md5 -q $thisFile` >> CACHE_KEY.txt
fi
echo "CACHE_KEY=`md5 -q CACHE_KEY.txt`" >> $GITHUB_ENV
echo "LibrariesPath=`pwd`" >> $GITHUB_ENV
curl -o tg_owt-version.json https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master
- name: RNNoise.
run: |
cd $LibrariesPath
git clone --depth=1 https://gitlab.xiph.org/xiph/rnnoise.git
cd rnnoise
./autogen.sh
./configure --disable-examples --disable-doc
make -j$(sysctl -n hw.logicalcpu)
make install
- name: WebRTC cache.
id: cache-webrtc
uses: actions/cache@v3.0.11
with:
path: ${{ env.LibrariesPath }}/tg_owt
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }}
- name: WebRTC.
if: steps.cache-webrtc.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
git clone --recursive --depth=1 $GIT/desktop-app/tg_owt.git
cd tg_owt
cmake -B build . -GNinja -DCMAKE_BUILD_TYPE=Debug
cmake --build build --parallel
- name: Telegram Desktop build.
if: env.ONLY_CACHE == 'false'
env:
tg_owt_DIR: ${{ env.LibrariesPath }}/tg_owt/build
run: |
cd $REPO_NAME
DEFINE=""
if [ -n "${{ matrix.defines }}" ]; then
DEFINE="-D ${{ matrix.defines }}=ON"
echo Define from matrix: $DEFINE
echo "ARTIFACT_NAME=Telegram_${{ matrix.defines }}" >> $GITHUB_ENV
else
echo "ARTIFACT_NAME=Telegram" >> $GITHUB_ENV
fi
cmake -Bbuild -GNinja . \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_FIND_FRAMEWORK=LAST \
-DTDESKTOP_API_TEST=ON \
-DDESKTOP_APP_USE_PACKAGED_LAZY=ON \
$DEFINE
cmake --build build --parallel
cd build
macdeployqt Telegram.app
codesign --remove-signature Telegram.app
mkdir dmgsrc
mv Telegram.app dmgsrc
hdiutil create -volname Telegram -srcfolder dmgsrc -ov -format UDZO Telegram.dmg
- name: Move artifact.
if: env.UPLOAD_ARTIFACT == 'true'
run: |
cd $REPO_NAME/build
mkdir artifact
mv Telegram.dmg artifact/
- uses: actions/upload-artifact@master
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.REPO_NAME }}/build/artifact/
+2 -2
View File
@@ -59,9 +59,9 @@ include(cmake/options.cmake)
if (NOT DESKTOP_APP_USE_PACKAGED)
if (WIN32)
set(qt_version 5.15.10)
set(qt_version 5.15.11)
elseif (APPLE)
set(qt_version 6.2.5)
set(qt_version 6.2.6)
endif()
endif()
include(cmake/external/qt/package.cmake)
+68 -18
View File
@@ -288,6 +288,8 @@ PRIVATE
boxes/peers/peer_short_info_box.h
boxes/peers/prepare_short_info_box.cpp
boxes/peers/prepare_short_info_box.h
boxes/peers/replace_boost_box.cpp
boxes/peers/replace_boost_box.h
boxes/about_box.cpp
boxes/about_box.h
boxes/about_sponsored_box.cpp
@@ -837,6 +839,8 @@ PRIVATE
history/view/history_view_quick_action.h
history/view/history_view_replies_section.cpp
history/view/history_view_replies_section.h
history/view/history_view_reply.cpp
history/view/history_view_reply.h
history/view/history_view_requests_bar.cpp
history/view/history_view_requests_bar.h
history/view/history_view_schedule_box.cpp
@@ -891,6 +895,10 @@ PRIVATE
history/history_view_highlight_manager.h
history/history_widget.cpp
history/history_widget.h
info/boosts/giveaway/giveaway_list_controllers.cpp
info/boosts/giveaway/giveaway_list_controllers.h
info/boosts/create_giveaway_box.cpp
info/boosts/create_giveaway_box.h
info/boosts/info_boosts_inner_widget.cpp
info/boosts/info_boosts_inner_widget.h
info/boosts/info_boosts_widget.cpp
@@ -1609,7 +1617,39 @@ elseif (APPLE)
endif()
set(icons_path ${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Images.xcassets)
target_add_resource(Telegram ${icons_path})
if (CMAKE_GENERATOR STREQUAL Xcode)
target_add_resource(Telegram ${icons_path})
else()
set(icon_path ${icons_path}/Icon.iconset)
find_program(ICONUTIL iconutil)
find_program(PNG2ICNS png2icns)
if (ICONUTIL)
add_custom_command(
OUTPUT Icon.icns
COMMAND ${ICONUTIL}
ARGS
--convert icns
--output Icon.icns
${icon_path}
)
elseif (PNG2ICNS)
add_custom_command(
OUTPUT Icon.icns
COMMAND ${PNG2ICNS}
ARGS
Icon.icns
${icon_path}/icon_16x16.png
${icon_path}/icon_32x32.png
${icon_path}/icon_128x128.png
${icon_path}/icon_256x256.png
${icon_path}/icon_512x512.png
)
endif()
if (ICONUTIL OR PNG2ICNS)
set_source_files_properties(Icon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
target_add_resource(Telegram Icon.icns)
endif()
endif()
set(lang_packs
en
@@ -1636,24 +1676,17 @@ elseif (APPLE)
COMMAND cp ${CMAKE_BINARY_DIR}/lib_ui.rcc $<TARGET_FILE_DIR:Telegram>/../Resources
COMMAND cp ${CMAKE_BINARY_DIR}/lib_spellcheck.rcc $<TARGET_FILE_DIR:Telegram>/../Resources
)
if (NOT build_macstore)
if (NOT build_macstore AND NOT DESKTOP_APP_DISABLE_CRASH_REPORTS)
if (DESKTOP_APP_MAC_ARCH STREQUAL "x86_64" OR DESKTOP_APP_MAC_ARCH STREQUAL "arm64")
set(crashpad_dir_part ".${DESKTOP_APP_MAC_ARCH}")
else()
set(crashpad_dir_part "")
endif()
add_custom_command(TARGET Telegram
PRE_LINK
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Frameworks
COMMAND cp $<TARGET_FILE:Updater> $<TARGET_FILE_DIR:Telegram>/../Frameworks/
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Helpers
COMMAND cp ${libs_loc}/crashpad/out/$<IF:$<CONFIG:Debug>,Debug,Release>${crashpad_dir_part}/crashpad_handler $<TARGET_FILE_DIR:Telegram>/../Helpers/
)
if (NOT DESKTOP_APP_DISABLE_CRASH_REPORTS)
if (DESKTOP_APP_MAC_ARCH STREQUAL "x86_64" OR DESKTOP_APP_MAC_ARCH STREQUAL "arm64")
set(crashpad_dir_part ".${DESKTOP_APP_MAC_ARCH}")
else()
set(crashpad_dir_part "")
endif()
add_custom_command(TARGET Telegram
PRE_LINK
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Helpers
COMMAND cp ${libs_loc}/crashpad/out/$<IF:$<CONFIG:Debug>,Debug,Release>${crashpad_dir_part}/crashpad_handler $<TARGET_FILE_DIR:Telegram>/../Helpers/
)
endif()
endif()
else()
target_link_libraries(Telegram
@@ -1702,7 +1735,11 @@ if (build_macstore)
COMMAND rm -rf $<TARGET_FILE_DIR:Telegram>/../Frameworks/Breakpad.framework/Resources/Inspector
)
else()
set(bundle_identifier "com.tdesktop.Telegram$<$<CONFIG:Debug>:Debug>")
if (CMAKE_GENERATOR STREQUAL Xcode)
set(bundle_identifier "com.tdesktop.Telegram$<$<CONFIG:Debug>:Debug>")
else()
set(bundle_identifier "com.tdesktop.Telegram")
endif()
set(bundle_entitlements "Telegram.entitlements")
if (LINUX AND DESKTOP_APP_USE_PACKAGED)
set(output_name "ayugram-desktop")
@@ -1711,6 +1748,12 @@ else()
endif()
endif()
if (CMAKE_GENERATOR STREQUAL Xcode)
set(bundle_identifier_plist "$(PRODUCT_BUNDLE_IDENTIFIER)")
else()
set(bundle_identifier_plist ${bundle_identifier})
endif()
set_target_properties(Telegram PROPERTIES
OUTPUT_NAME ${output_name}
MACOSX_BUNDLE_GUI_IDENTIFIER ${bundle_identifier}
@@ -1784,7 +1827,7 @@ endif()
target_prepare_qrc(Telegram)
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT build_winstore)
if (NOT DESKTOP_APP_DISABLE_AUTOUPDATE AND NOT build_macstore AND NOT build_winstore)
add_executable(Updater WIN32)
init_non_host_target(Updater)
@@ -1822,6 +1865,12 @@ if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT
else()
target_link_options(Updater PRIVATE -municode)
endif()
elseif (APPLE)
add_custom_command(TARGET Updater
PRE_LINK
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Frameworks
COMMAND cp $<TARGET_FILE:Updater> $<TARGET_FILE_DIR:Telegram>/../Frameworks/
)
endif()
if (DESKTOP_APP_SPECIAL_TARGET)
@@ -1875,6 +1924,7 @@ if (LINUX AND DESKTOP_APP_USE_PACKAGED)
install(FILES "Resources/art/icon128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "ayugram.png")
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "ayugram.png")
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "ayugram.png")
install(FILES "Resources/icons/tray_monochrome.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/symbolic/apps" RENAME "telegram-symbolic.svg")
install(FILES "../lib/xdg/ayugram.desktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ayugram.desktop.service" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/dbus-1/services")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ayugram.desktop.metainfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 B

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 B

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 B

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 603 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 B

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="plane" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M1.3311718,6.36592184 C5.3576954,4.67244493 8.04267511,3.5560013 9.38611094,3.01659096 C13.2218932,1.47646481 14.0189359,1.2089284 14.5384372,1.2 C14.6526967,1.19815119 14.9081723,1.22548649 15.0736587,1.35511219 C15.2133922,1.4645656 15.2518384,1.61242159 15.2702362,1.71619544 C15.288634,1.81996929 15.3115436,2.05636876 15.2933322,2.24108442 C15.0854698,4.34939964 14.1860526,9.46572464 13.7284802,11.8270738 C13.5348641,12.8262491 13.1536281,13.1612675 12.7845475,13.1940535 C11.9824498,13.265305 11.3733733,12.6823476 10.5965026,12.190753 C9.3808532,11.4215044 8.69408865,10.9426448 7.51409044,10.1920004 C6.15039834,9.32450079 7.03442319,8.84770795 7.81158733,8.06849502 C8.01497489,7.86457129 11.5490353,4.7615061 11.6174372,4.48000946 C11.625992,4.44480359 11.6339313,4.31357282 11.5531696,4.24427815 C11.472408,4.17498349 11.3532107,4.19867957 11.2671947,4.21752527 C11.1452695,4.24423848 9.20325394,5.48334063 5.44114787,7.93483171 C4.88991321,8.30022994 4.39062196,8.47826423 3.94327414,8.46893456 C3.45010907,8.45864936 2.50145729,8.19975808 1.79623221,7.97846422 C0.931244952,7.70703829 0.243770289,7.56353344 0.303633888,7.10256824 C0.334814555,6.86246904 0.677327192,6.61692024 1.3311718,6.36592184 Z" id="Path-3" fill="#FFFFFF"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+90 -15
View File
@@ -546,6 +546,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_workmode_tray" = "Show tray icon";
"lng_settings_workmode_window" = "Show taskbar icon";
"lng_settings_close_to_taskbar" = "Close to taskbar";
"lng_settings_monochrome_icon" = "Use monochrome icon";
"lng_settings_window_system" = "Window title";
"lng_settings_title_chat_name" = "Show chat name";
"lng_settings_title_account_name" = "Show active account";
@@ -2029,6 +2030,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_gift_terms_link" = "here";
"lng_boost_channel_button" = "Boost Channel";
"lng_boost_again_button" = "Boost Again";
"lng_boost_level#one" = "Level {count}";
"lng_boost_level#other" = "Level {count}";
"lng_boost_channel_title_first" = "Enable stories for channel";
@@ -2050,6 +2052,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_boost_channel_post_stories#other" = "post **{count} stories** per day";
"lng_boost_error_gifted_title" = "Can't boost with gifted Premium!";
"lng_boost_error_gifted_text" = "Because your **Telegram Premium** subscription was gifted to you, you can't use it to boost channels.";
"lng_boost_need_more" = "More boosts needed";
"lng_boost_need_more_text#one" = "To boost {channel}, gift **Telegram Premium** to a friend and get **{count}** boosts.";
"lng_boost_need_more_text#other" = "To boost {channel}, gift **Telegram Premium** to a friend and get **{count}** boosts.";
"lng_boost_need_more_again#one" = "To boost {channel} again, gift **Telegram Premium** to a friend and get **{count}** additional boost.";
"lng_boost_need_more_again#other" = "To boost {channel} again, gift **Telegram Premium** to a friend and get **{count}** additional boosts.";
"lng_boost_error_already_title" = "Already Boosted!";
"lng_boost_error_already_text" = "You are already boosting this channel.";
"lng_boost_error_premium_title" = "Premium needed!";
@@ -2059,6 +2066,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_boost_error_flood_text" = "You can change the channel you boost only once a day. Next time you can boost is in {left}.";
"lng_boost_now_instead" = "You currently boost {channel}. Do you want to boost {other} instead?";
"lng_boost_now_replace" = "Replace";
"lng_boost_reassign_title" = "Reassign boost";
"lng_boost_reassign_text" = "To boost {channel}, reassign a previous boost or {gift}.";
"lng_boost_reassign_gift#one" = "gift **Telegram Premium** to a friend to get **{count}** additional boost";
"lng_boost_reassign_gift#other" = "gift **Telegram Premium** to a friend to get **{count}** additional boosts";
"lng_boost_remove_title" = "Remove your boost from";
"lng_boost_reassign_button" = "Reassign";
"lng_boost_available_in" = "available in {duration}";
"lng_boost_available_in_toast#one" = "Wait until the boost is available or get **{count}** more boost by gifting a **Telegram Premium** subscription.";
"lng_boost_available_in_toast#other" = "Wait until the boost is available or get **{count}** more boosts by gifting a **Telegram Premium** subscription.";
"lng_boost_reassign_done#one" = "{count} boost is reassigned from {channels}.";
"lng_boost_reassign_done#other" = "{count} boosts are reassigned from {channels}.";
"lng_boost_reassign_channels#one" = "{count} channel";
"lng_boost_reassign_channels#other" = "{count} channels";
"lng_boost_channel_title_color" = "Enable colors";
"lng_boost_channel_needs_level_color#one" = "Your channel needs to reach **Level {count}** to change channel color.";
@@ -2077,9 +2097,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_giveaway_award_subtitle" = "Select recipients >";
"lng_giveaway_award_chosen#one" = "{count} recipient >";
"lng_giveaway_award_chosen#other" = "{count} recipients >";
"lng_giveaway_quantity_title" = "Quantity of prizes / boosts";
"lng_giveaway_quantity#one" = "{count} Subscription / Boost";
"lng_giveaway_quantity#other" = "{count} Subscriptions / Boosts";
"lng_giveaway_quantity_title" = "Quantity of prizes";
"lng_giveaway_quantity#one" = "{count} boost";
"lng_giveaway_quantity#other" = "{count} boosts";
"lng_giveaway_quantity_about" = "Choose how many Premium subscriptions to give away and boosts to receive.";
"lng_giveaway_channels_title" = "Channels included in the giveaway";
"lng_giveaway_channels_this#one" = "this channel will receive {count} boost";
@@ -2088,10 +2108,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_giveaway_channels_about" = "Choose the channels the users need to join to take part in the giveaway.";
"lng_giveaway_users_title" = "Users eligible for the giveaway";
"lng_giveaway_users_all" = "All subscribers";
"lng_giveaway_users_from_all_countries" = "from all countries";
"lng_giveaway_users_from_one_country" = "from {country}";
"lng_giveaway_users_from_countries#one" = "from {count} country";
"lng_giveaway_users_from_countries#other" = "from {count} countries";
"lng_giveaway_users_new" = "Only new subscribers";
"lng_giveaway_users_about" = "Choose if you want to limit the giveaway only to the newly joined subscribers.";
"lng_giveaway_users_about" = "Choose if you want to limit the giveaway only to those who joined the channel after the giveaway started or to users from specific countries.";
"lng_giveaway_start" = "Start Giveaway";
"lng_giveaway_award" = "Gift Premium";
"lng_giveaway_start_sure" = "Are you sure you want to start this prepaid giveaway now? This action cannot be undone.";
"lng_giveaway_date_title" = "Date when giveaway ends";
"lng_giveaway_date" = "Date and Time";
"lng_giveaway_date_about#one" = "Choose when {count} subscriber of your channel will be randomly selected to receive Telegram Premium.";
@@ -2099,14 +2124,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_giveaway_duration_title#one" = "Duration of Premium subscription";
"lng_giveaway_duration_title#other" = "Duration of Premium subscriptions";
"lng_giveaway_duration_price" = "{price} x {amount}";
"lng_giveaway_duration_about" = "You can review the list of features and terms of use for Telegram Premium {link}.";
"lng_giveaway_duration_about_link" = "here";
"lng_giveaway_date_select" = "Select Date and Time";
"lng_giveaway_date_confirm" = "Confirm";
"lng_giveaway_channels_select#one" = "Select up to {count} channel";
"lng_giveaway_channels_select#other" = "Select up to {count} channels";
"lng_giveaway_recipients_save" = "Save Recipients";
"lng_giveaway_recipients_deselect" = "Deselect All";
"lng_giveaway_maximum_countries_error#one" = "You can select maximum {count} country.";
"lng_giveaway_maximum_countries_error#other" = "You can select maximum {count} countries.";
"lng_giveaway_maximum_channels_error#one" = "You can select maximum {count} channel.";
"lng_giveaway_maximum_channels_error#other" = "You can select maximum {count} channels.";
"lng_giveaway_maximum_users_error#one" = "You can select maximum {count} user.";
"lng_giveaway_maximum_users_error#other" = "You can select maximum {count} users.";
"lng_giveaway_channels_confirm_title" = "Channel is Private";
"lng_giveaway_channels_confirm_about" = "Are you sure you want to add a private channel? Users won't be able to join it without an invite link.";
"lng_giveaway_created_title" = "Giveaway created";
"lng_giveaway_created_body" = "Check your channels' {link} to see how this giveaway boosted your channel.";
"lng_giveaway_awarded_title" = "Premium subscriptions gifted";
"lng_giveaway_awarded_body" = "Check your channels' {link} to see how gifts boosted your channel.";
"lng_giveaway_created_link" = "Statistics";
"lng_prize_title" = "Congratulations!";
"lng_prize_about" = "You won a prize in a giveaway organized by {channel}.";
@@ -2142,10 +2179,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_prizes_end_when_finish" = "On {date}, Telegram automatically selected {winners}.";
"lng_prizes_end_activated#one" = "**{count}** of the winners already used their gift link.";
"lng_prizes_end_activated#other" = "**{count}** of the winners already used their gift links.";
"lng_prizes_winners_all_of_one#one" = "{count} random subscribers of {channel}.";
"lng_prizes_winners_all_of_one#other" = "{count} random subscribers of {channel}.";
"lng_prizes_winners_all_of_many#one" = "{count} random subscribers of {channel} and other listed channels.";
"lng_prizes_winners_all_of_many#other" = "{count} random subscribers of {channel} and other listed channels.";
"lng_prizes_winners_all_of_one#one" = "{count} random subscribers of {channel}";
"lng_prizes_winners_all_of_one#other" = "{count} random subscribers of {channel}";
"lng_prizes_winners_all_of_many#one" = "{count} random subscribers of {channel} and other listed channels";
"lng_prizes_winners_all_of_many#other" = "{count} random subscribers of {channel} and other listed channels";
"lng_prizes_winners_new_of_one#one" = "{count} random user that joined {channel} after {start_date}";
"lng_prizes_winners_new_of_one#other" = "{count} random users that joined {channel} after {start_date}";
"lng_prizes_winners_new_of_many#one" = "{count} random user that joined {channel} and other listed channels after {start_date}";
@@ -2182,6 +2219,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gift_link_used_about" = "This link was used to activate\na **Telegram Premium** subscription.";
"lng_gift_link_used_footer" = "This link was used on {date}.";
"lng_gift_link_expired" = "Gift code link expired";
"lng_gift_link_pending_about" = "This link allows {user} to activate\na **Telegram Premium** subscription.";
"lng_gift_link_pending_toast" = "Only the recipient can see the link.";
"lng_gift_link_pending_footer" = "This link hasn't been activated yet.";
"lng_accounts_limit_title" = "Limit Reached";
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected accounts.";
@@ -2684,6 +2724,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_reply_options_quote" = "Update Quote";
"lng_reply_header_short" = "Reply";
"lng_reply_quote_selected" = "Quote Selected";
"lng_reply_from_private_chat" = "This reply is from a private chat.";
"lng_link_options_header" = "Link Preview Settings";
"lng_link_header_short" = "Link";
"lng_link_move_up" = "Move Up";
@@ -4307,13 +4348,32 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_boosts_existing" = "Existing boosts";
"lng_boosts_premium_audience" = "Premium subscribers";
"lng_boosts_next_level" = "Boosts to level up";
"lng_boosts_list_title#one" = "{count} booster";
"lng_boosts_list_title#other" = "{count} boosters";
"lng_boosts_list_title#one" = "{count} Boost";
"lng_boosts_list_title#other" = "{count} Boosts";
"lng_boosts_list_subtext" = "Your channel is currently boosted by these users.";
"lng_boosts_show_more" = "Show More Boosts";
"lng_boosts_show_more_boosts#one" = "Show {count} More Boosts";
"lng_boosts_show_more_boosts#other" = "Show {count} More Boosts";
"lng_boosts_show_more_gifts#one" = "Show {count} More Boosts";
"lng_boosts_show_more_gifts#other" = "Show {count} More Boosts";
"lng_boosts_list_status" = "boost expires on {date}";
"lng_boosts_link_title" = "Link for boosting";
"lng_boosts_link_subtext" = "Share this link with your subscribers to get more boosts.";
"lng_boosts_get_boosts" = "Get Boosts via Gifts";
"lng_boosts_get_boosts_subtext" = "Get more boosts for your channel by gifting Telegram Premium to your subscribers.";
"lng_boosts_list_unclaimed" = "Unclaimed";
"lng_boosts_list_pending" = "To be distributed";
"lng_boosts_list_pending_about" = "The recipient will be selected when the giveaway ends.";
"lng_boosts_list_tab_gifts#one" = "{count} Gifts";
"lng_boosts_list_tab_gifts#other" = "{count} Gifts";
"lng_boosts_prepaid_giveaway_title" = "Prepaid giveaways";
"lng_boosts_prepaid_giveaway_single" = "Prepaid giveaway";
"lng_boosts_prepaid_giveaway_quantity#one" = "{count} Telegram Premium";
"lng_boosts_prepaid_giveaway_quantity#other" = "{count} Telegram Premium";
"lng_boosts_prepaid_giveaway_moths#one" = "{count}-month subscriptions";
"lng_boosts_prepaid_giveaway_moths#other" = "{count}-month subscriptions";
"lng_boosts_prepaid_giveaway_status#one" = "{count} subscription {duration}";
"lng_boosts_prepaid_giveaway_status#other" = "{count} subscriptions {duration}";
// Wnd specific
@@ -4385,6 +4445,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
// AyuGram keys generated
"ayu_AyuPreferences" = "AyuGram Preferences";
"ayu_DocsText" = "Documentation";
"ayu_GhostEssentialsHeader" = "Ghost essentials";
"ayu_DontReadMessages" = "Don't read messages";
"ayu_DontReadStories" = "Don't read stories";
@@ -4432,6 +4493,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_SettingsShowID_Hide" = "Hide";
"ayu_SettingsRecentStickersCount" = "Recent stickers count";
"ayu_SettingsCustomizationHint" = "After making changes to the \"Customization\" section, you must restart the application.";
"ayu_DrawerElementsHeader" = "Drawer Elements";
"ayu_TrayElementsHeader" = "Tray Elements";
"ayu_RegexFilters" = "Message Filters";
"ayu_RegexFiltersAmount" = "filters";
"ayu_RegexFiltersHeader" = "Filters";
@@ -4445,6 +4508,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_EnableExpression" = "Enable expression";
"ayu_CaseInsensitiveExpression" = "Case insensitive expression";
"ayu_RegexFiltersAddError" = "Regex syntax error";
"ayu_RegexFilterQuickAdd" = "Add filter";
"ayu_AyuSyncHeader" = "AyuSync";
"ayu_AyuSyncStatusTitle" = "Sync status";
"ayu_AyuSyncStatusOk" = "connected";
@@ -4467,7 +4531,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_AyuSyncDownloadAgent" = "Download agent";
"ayu_IconDefault" = "Default";
"ayu_IconAlternative" = "AyuGram Alt";
"ayu_IconDiscord" = "Discord";
"ayu_IconSpotify" = "Spotify";
"ayu_IconExtera" = "extera";
"ayu_IconNothing" = "Nothing";
"ayu_IconBard" = "Google Bard";
"ayu_IconYaPlus" = "Yandex Plus";
"ayu_WALMode" = "Enable WAL mode";
"ayu_PushNotificationCount" = "FCM notifications received";
"ayu_ClearAyuDatabase" = "Clear Ayu Database";
@@ -4494,8 +4563,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_DisableStreamerModeTray" = "Disable Streamer Mode";
"ayu_EditsHistoryTitle" = "Edits history";
"ayu_EditsHistoryMenuText" = "History";
"ayu_PeekOnlineMenuText" = "Peek Online";
"ayu_ClearDeletedMenuText" = "Clear Deleted";
"ayu_ViewFiltersMenuText" = "View Filters";
"ayu_PeekOnlineSuccess" = "Peeked via";
"ayu_OneViewTTL" = "one view";
"ayu_ReadUntilMenuText" = "Read Message";
"ayu_DeleteKeepLocally" = "Keep locally";
@@ -4506,11 +4577,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_ClearDeletedMessagesText" = "Are you sure you want to clear all deleted messages in this chat?";
"ayu_ClearDeletedMessagesActionText" = "Clear";
"ayu_SuggestGhostModeTitle" = "Ghost Mode";
"ayu_SuggestGhostModeStoryText" = "Do you want to enable Ghost Mode before viewing the story?";
"ayu_SuggestGhostModeStoryActionText" = "Enable";
"ayu_SuggestGhostModeStoryText" = "Do you want to enable **Ghost Mode** before viewing the story?";
"ayu_SuggestGhostModeStoryActionTextYes" = "Yes";
"ayu_SuggestGhostModeStoryActionTextNo" = "No";
"ayu_HideNextViewsDescriptionAyu" = "Hide my views forever, until Ghost Mode disabled.";
"ayu_EnableGhostModeStories" = "Enable Ghost Mode";
"ayu_GhostModeIsActive" = "Ghost Mode Is Active";
"ayu_SimpleQuotesAndReplies" = "Simple quotes & replies";
"ayu_MainFont" = "Application font";
"ayu_MonospaceFont" = "Monospace font";
"ayu_FontDefault" = "Default";
@@ -4520,6 +4593,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"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_DeleteDateMenuText" = "Delete Date";
"ayu_ForwardableMenuText" = "Forwardable";
"ayu_ForwardableMenuTextNo" = "No";
"ayu_LikelyOfflineStatus" = "offline ?";
"ayu_GhostModeShortcut" = "Enter with Ghost";
"ayu_SettingsShowMessageSeconds" = "Show message seconds";
@@ -28,6 +28,7 @@
<file alias="icons/settings/dino.svg">../../icons/settings/dino.svg</file>
<file alias="icons/settings/star.svg">../../icons/settings/star.svg</file>
<file alias="icons/settings/starmini.svg">../../icons/settings/starmini.svg</file>
<file alias="icons/tray/monochrome.svg">../../icons/tray_monochrome.svg</file>
<file alias="topic_icons/blue.svg">../../art/topic_icons/blue.svg</file>
<file alias="topic_icons/yellow.svg">../../art/topic_icons/yellow.svg</file>
<file alias="topic_icons/violet.svg">../../art/topic_icons/violet.svg</file>
+1 -1
View File
@@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="4.11.1.0" />
Version="4.11.6.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
+4 -4
View File
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,11,1,0
PRODUCTVERSION 4,11,1,0
FILEVERSION 4,11,6,0
PRODUCTVERSION 4,11,6,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "4.11.1.0"
VALUE "FileVersion", "4.11.6.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.11.1.0"
VALUE "ProductVersion", "4.11.6.0"
END
END
BLOCK "VarFileInfo"
+4 -4
View File
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,11,1,0
PRODUCTVERSION 4,11,1,0
FILEVERSION 4,11,6,0
PRODUCTVERSION 4,11,6,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
VALUE "FileVersion", "4.11.1.0"
VALUE "FileVersion", "4.11.6.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.11.1.0"
VALUE "ProductVersion", "4.11.6.0"
END
END
BLOCK "VarFileInfo"
+189 -5
View File
@@ -9,12 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_premium_option.h"
#include "api/api_text_entities.h"
#include "main/main_session.h"
#include "data/data_peer_values.h"
#include "data/data_document.h"
#include "data/data_session.h"
#include "data/data_peer.h"
#include "apiwrap.h"
#include "base/random.h"
#include "data/data_document.h"
#include "data/data_peer.h"
#include "data/data_peer_values.h"
#include "data/data_session.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
#include "payments/payments_form.h"
#include "ui/text/format_values.h"
namespace Api {
namespace {
@@ -31,6 +36,24 @@ namespace {
};
}
[[nodiscard]] Data::SubscriptionOptions GiftCodesFromTL(
const QVector<MTPPremiumGiftCodeOption> &tlOptions) {
auto options = SubscriptionOptionsFromTL(tlOptions);
for (auto i = 0; i < options.size(); i++) {
const auto &tlOption = tlOptions[i].data();
const auto perUserText = Ui::FillAmountAndCurrency(
tlOption.vamount().v / float64(tlOption.vusers().v),
qs(tlOption.vcurrency()),
false);
options[i].costPerMonth = perUserText
+ ' '
+ QChar(0x00D7)
+ ' '
+ QString::number(tlOption.vusers().v);
}
return options;
}
} // namespace
Premium::Premium(not_null<ApiWrap*> api)
@@ -311,4 +334,165 @@ const Data::SubscriptionOptions &Premium::subscriptionOptions() const {
return _subscriptionOptions;
}
PremiumGiftCodeOptions::PremiumGiftCodeOptions(not_null<PeerData*> peer)
: _peer(peer)
, _api(&peer->session().api().instance()) {
}
rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::request() {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
const auto channel = _peer->asChannel();
if (!channel) {
return lifetime;
}
using TLOption = MTPPremiumGiftCodeOption;
_api.request(MTPpayments_GetPremiumGiftCodeOptions(
MTP_flags(
MTPpayments_GetPremiumGiftCodeOptions::Flag::f_boost_peer),
_peer->input
)).done([=](const MTPVector<TLOption> &result) {
auto tlMapOptions = base::flat_map<Amount, QVector<TLOption>>();
for (const auto &tlOption : result.v) {
const auto &data = tlOption.data();
tlMapOptions[data.vusers().v].push_back(tlOption);
const auto token = Token{ data.vusers().v, data.vmonths().v };
_stores[token] = Store{
.amount = data.vamount().v,
.product = qs(data.vstore_product().value_or_empty()),
.quantity = data.vstore_quantity().value_or_empty(),
};
if (!ranges::contains(_availablePresets, data.vusers().v)) {
_availablePresets.push_back(data.vusers().v);
}
}
for (const auto &[amount, tlOptions] : tlMapOptions) {
if (amount == 1 && _optionsForOnePerson.currency.isEmpty()) {
_optionsForOnePerson.currency = qs(
tlOptions.front().data().vcurrency());
for (const auto &option : tlOptions) {
_optionsForOnePerson.months.push_back(
option.data().vmonths().v);
_optionsForOnePerson.totalCosts.push_back(
option.data().vamount().v);
}
}
_subscriptionOptions[amount] = GiftCodesFromTL(tlOptions);
}
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return lifetime;
};
}
rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::applyPrepaid(
const Payments::InvoicePremiumGiftCode &invoice,
uint64 prepaidId) {
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
const auto channel = _peer->asChannel();
if (!channel) {
return lifetime;
}
_api.request(MTPpayments_LaunchPrepaidGiveaway(
_peer->input,
MTP_long(prepaidId),
Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
}).send();
return lifetime;
};
}
const std::vector<int> &PremiumGiftCodeOptions::availablePresets() const {
return _availablePresets;
}
[[nodiscard]] int PremiumGiftCodeOptions::monthsFromPreset(int monthsIndex) {
return _optionsForOnePerson.months[monthsIndex];
}
Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
int users,
int months) {
const auto randomId = base::RandomValue<uint64>();
const auto token = Token{ users, months };
const auto &store = _stores[token];
return Payments::InvoicePremiumGiftCode{
.randomId = randomId,
.currency = _optionsForOnePerson.currency,
.amount = store.amount,
.storeProduct = store.product,
.storeQuantity = store.quantity,
.users = token.users,
.months = token.months,
};
}
Data::SubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
const auto it = _subscriptionOptions.find(amount);
if (it != end(_subscriptionOptions)) {
return it->second;
} else {
auto tlOptions = QVector<MTPPremiumGiftCodeOption>();
for (auto i = 0; i < _optionsForOnePerson.months.size(); i++) {
tlOptions.push_back(MTP_premiumGiftCodeOption(
MTP_flags(MTPDpremiumGiftCodeOption::Flags(0)),
MTP_int(amount),
MTP_int(_optionsForOnePerson.months[i]),
MTPstring(),
MTPint(),
MTP_string(_optionsForOnePerson.currency),
MTP_long(_optionsForOnePerson.totalCosts[i] * amount)));
}
_subscriptionOptions[amount] = GiftCodesFromTL(tlOptions);
return _subscriptionOptions[amount];
}
}
int PremiumGiftCodeOptions::giveawayBoostsPerPremium() const {
constexpr auto kFallbackCount = 4;
return _peer->session().account().appConfig().get<int>(
u"giveaway_boosts_per_premium"_q,
kFallbackCount);
}
int PremiumGiftCodeOptions::giveawayCountriesMax() const {
constexpr auto kFallbackCount = 10;
return _peer->session().account().appConfig().get<int>(
u"giveaway_countries_max"_q,
kFallbackCount);
}
int PremiumGiftCodeOptions::giveawayAddPeersMax() const {
constexpr auto kFallbackCount = 10;
return _peer->session().account().appConfig().get<int>(
u"giveaway_add_peers_max"_q,
kFallbackCount);
}
int PremiumGiftCodeOptions::giveawayPeriodMax() const {
constexpr auto kFallbackCount = 3600 * 24 * 7;
return _peer->session().account().appConfig().get<int>(
u"giveaway_period_max"_q,
kFallbackCount);
}
bool PremiumGiftCodeOptions::giveawayGiftsPurchaseAvailable() const {
return _peer->session().account().appConfig().get<bool>(
u"giveaway_gifts_purchase_available"_q,
false);
}
} // namespace Api
+55
View File
@@ -16,6 +16,10 @@ namespace Main {
class Session;
} // namespace Main
namespace Payments {
struct InvoicePremiumGiftCode;
} // namespace Payments
namespace Api {
struct GiftCode {
@@ -141,4 +145,55 @@ private:
};
class PremiumGiftCodeOptions final {
public:
PremiumGiftCodeOptions(not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
[[nodiscard]] Data::SubscriptionOptions options(int amount);
[[nodiscard]] const std::vector<int> &availablePresets() const;
[[nodiscard]] int monthsFromPreset(int monthsIndex);
[[nodiscard]] Payments::InvoicePremiumGiftCode invoice(
int users,
int months);
[[nodiscard]] rpl::producer<rpl::no_value, QString> applyPrepaid(
const Payments::InvoicePremiumGiftCode &invoice,
uint64 prepaidId);
[[nodiscard]] int giveawayBoostsPerPremium() const;
[[nodiscard]] int giveawayCountriesMax() const;
[[nodiscard]] int giveawayAddPeersMax() const;
[[nodiscard]] int giveawayPeriodMax() const;
[[nodiscard]] bool giveawayGiftsPurchaseAvailable() const;
private:
struct Token final {
int users = 0;
int months = 0;
friend inline constexpr auto operator<=>(Token, Token) = default;
};
struct Store final {
uint64 amount = 0;
QString product;
int quantity = 0;
};
using Amount = int;
const not_null<PeerData*> _peer;
base::flat_map<Amount, Data::SubscriptionOptions> _subscriptionOptions;
struct {
std::vector<int> months;
std::vector<float64> totalCosts;
QString currency;
} _optionsForOnePerson;
std::vector<int> _availablePresets;
base::flat_map<Token, Store> _stores;
MTP::Sender _api;
};
} // namespace Api
@@ -36,7 +36,10 @@ template<typename Option>
result.reserve(tlOptions.size());
for (const auto &tlOption : tlOptions) {
const auto &option = tlOption.data();
const auto botUrl = qs(option.vbot_url());
auto botUrl = QString();
if constexpr (!std::is_same_v<Option, MTPPremiumGiftCodeOption>) {
botUrl = qs(option.vbot_url());
}
const auto months = option.vmonths().v;
const auto amount = option.vamount().v;
const auto currency = qs(option.vcurrency());
-2
View File
@@ -270,7 +270,6 @@ bool SendDice(MessageToSend &message) {
flags |= MessageFlag::HasReplyInfo;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
}
const auto replyHeader = NewMessageReplyHeader(message.action);
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, message.action.options);
InnerFillMessagePostFlags(message.action.options, peer, flags);
@@ -399,7 +398,6 @@ void SendConfirmedFile(
if (file->to.replyTo) {
flags |= MessageFlag::HasReplyInfo;
}
const auto replyHeader = NewMessageReplyHeader(action);
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, file->to.options);
FillMessagePostFlags(action, peer, flags);
+56 -10
View File
@@ -518,8 +518,9 @@ rpl::producer<rpl::no_value, QString> Boosts::request() {
? (100. * premiumMemberCount / participantCount)
: 0;
const auto slots = data.vmy_boost_slots();
_boostStatus.overview = Data::BoostsOverview{
.isBoosted = data.is_my_boost(),
.mine = slots ? int(slots->v.size()) : 0,
.level = std::max(data.vlevel().v, 0),
.boostCount = std::max(
data.vboosts().v,
@@ -533,9 +534,27 @@ rpl::producer<rpl::no_value, QString> Boosts::request() {
};
_boostStatus.link = qs(data.vboost_url());
requestBoosts({}, [=](Data::BoostsListSlice &&slice) {
_boostStatus.firstSlice = std::move(slice);
consumer.put_done();
if (data.vprepaid_giveaways()) {
_boostStatus.prepaidGiveaway = ranges::views::all(
data.vprepaid_giveaways()->v
) | ranges::views::transform([](const MTPPrepaidGiveaway &r) {
return Data::BoostPrepaidGiveaway{
.months = r.data().vmonths().v,
.id = r.data().vid().v,
.quantity = r.data().vquantity().v,
.date = QDateTime::fromSecsSinceEpoch(
r.data().vdate().v),
};
}) | ranges::to_vector;
}
using namespace Data;
requestBoosts({ .gifts = false }, [=](BoostsListSlice &&slice) {
_boostStatus.firstSliceBoosts = std::move(slice);
requestBoosts({ .gifts = true }, [=](BoostsListSlice &&s) {
_boostStatus.firstSliceGifts = std::move(s);
consumer.put_done();
});
});
}).fail([=](const MTP::Error &error) {
consumer.put_error_copy(error.type());
@@ -553,8 +572,11 @@ void Boosts::requestBoosts(
}
constexpr auto kTlFirstSlice = tl::make_int(kFirstSlice);
constexpr auto kTlLimit = tl::make_int(kLimit);
const auto gifts = token.gifts;
_requestId = _api.request(MTPpremium_GetBoostsList(
MTP_flags(0),
gifts
? MTP_flags(MTPpremium_GetBoostsList::Flag::f_gifts)
: MTP_flags(0),
_peer->input,
MTP_string(token.next),
token.next.isEmpty() ? kTlFirstSlice : kTlLimit
@@ -566,20 +588,44 @@ void Boosts::requestBoosts(
auto list = std::vector<Data::Boost>();
list.reserve(data.vboosts().v.size());
constexpr auto kMonthsDivider = int(30 * 86400);
for (const auto &boost : data.vboosts().v) {
const auto &data = boost.data();
const auto path = data.vused_gift_slug()
? (u"giftcode/"_q + qs(data.vused_gift_slug()->v))
: QString();
auto giftCodeLink = !path.isEmpty()
? Data::GiftCodeLink{
_peer->session().createInternalLink(path),
_peer->session().createInternalLinkFull(path),
qs(data.vused_gift_slug()->v),
}
: Data::GiftCodeLink();
list.push_back({
boost.data().vuser_id().value_or_empty(),
QDateTime::fromSecsSinceEpoch(boost.data().vexpires().v),
data.is_gift(),
data.is_giveaway(),
data.is_unclaimed(),
qs(data.vid()),
data.vuser_id().value_or_empty(),
data.vgiveaway_msg_id()
? FullMsgId{ _peer->id, data.vgiveaway_msg_id()->v }
: FullMsgId(),
QDateTime::fromSecsSinceEpoch(data.vdate().v),
QDateTime::fromSecsSinceEpoch(data.vexpires().v),
(data.vexpires().v - data.vdate().v) / kMonthsDivider,
std::move(giftCodeLink),
data.vmultiplier().value_or_empty(),
});
}
done(Data::BoostsListSlice{
.list = std::move(list),
.total = data.vcount().v,
.multipliedTotal = data.vcount().v,
.allLoaded = (data.vcount().v == data.vboosts().v.size()),
.token = Data::BoostsListSlice::OffsetToken{
data.vnext_offset()
.next = data.vnext_offset()
? qs(*data.vnext_offset())
: QString()
: QString(),
.gifts = gifts,
},
});
}).fail([=] {
+4 -7
View File
@@ -3391,7 +3391,6 @@ void ApiWrap::sendSharedContact(
if (action.replyTo) {
flags |= MessageFlag::HasReplyInfo;
}
const auto replyHeader = NewMessageReplyHeader(action);
FillMessagePostFlags(action, peer, flags);
if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled;
@@ -3614,13 +3613,14 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
action.generateLocal = true;
sendAction(action);
const auto clearCloudDraft = action.clearDraft;
const auto replyTo = action.replyTo.messageId
? peer->owner().message(action.replyTo.messageId)
: nullptr;
const auto topicRootId = replyTo
? replyTo->topicRootId()
: action.replyTo.topicRootId
const auto topicRootId = action.replyTo.topicRootId
? action.replyTo.topicRootId
: replyTo
? replyTo->topicRootId()
: Data::ForumTopic::kGeneralId;
const auto topic = peer->forumTopicFor(topicRootId);
if (!(topic ? Data::CanSendTexts(topic) : Data::CanSendTexts(peer))
@@ -3674,7 +3674,6 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
const auto manualWebPage = exactWebPage
&& !ignoreWebPage
&& (message.webPage.manual || (isLast && !isFirst));
const auto replyHeader = NewMessageReplyHeader(action);
MTPMessageMedia media = MTP_messageMediaEmpty();
if (ignoreWebPage) {
sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage;
@@ -3718,8 +3717,6 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
mediaFlags |= MTPmessages_SendMedia::Flag::f_entities;
}
const auto clearCloudDraft = action.clearDraft;
const auto topicRootId = action.replyTo.topicRootId;
if (clearCloudDraft) {
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
mediaFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
+29
View File
@@ -265,6 +265,10 @@ void AyuGramSettings::set_appIcon(QString val)
appIcon = std::move(val);
}
void AyuGramSettings::set_simpleQuotesAndReplies(bool val) {
simpleQuotesAndReplies = val;
}
void AyuGramSettings::set_deletedMark(QString val)
{
deletedMark = std::move(val);
@@ -282,11 +286,36 @@ void AyuGramSettings::set_recentStickersCount(int val)
recentStickersCount = val;
}
void AyuGramSettings::set_showLReadToggleInDrawer(bool val)
{
showLReadToggleInDrawer = val;
}
void AyuGramSettings::set_showSReadToggleInDrawer(bool val)
{
showSReadToggleInDrawer = val;
}
void AyuGramSettings::set_showGhostToggleInDrawer(bool val)
{
showGhostToggleInDrawer = val;
}
void AyuGramSettings::set_showStreamerToggleInDrawer(bool val)
{
showStreamerToggleInDrawer = val;
}
void AyuGramSettings::set_showGhostToggleInTray(bool val)
{
showGhostToggleInTray = val;
}
void AyuGramSettings::set_showStreamerToggleInTray(bool val)
{
showStreamerToggleInTray = val;
}
void AyuGramSettings::set_mainFont(QString val)
{
mainFont = val;
+34 -1
View File
@@ -60,10 +60,19 @@ public:
// ~ Customization
appIcon = DEFAULT_ICON;
simpleQuotesAndReplies = true;
deletedMark = "🧹";
editedMark = tr::lng_edited(tr::now);
recentStickersCount = 20;
recentStickersCount = 50;
showLReadToggleInDrawer = true;
showSReadToggleInDrawer = true;
showGhostToggleInDrawer = true;
showStreamerToggleInDrawer = false;
showGhostToggleInTray = true;
showStreamerToggleInTray = false;
mainFont = "";
monoFont = "";
@@ -100,10 +109,16 @@ public:
bool localPremium;
bool copyUsernameAsLink;
QString appIcon;
bool simpleQuotesAndReplies;
QString deletedMark;
QString editedMark;
int recentStickersCount;
bool showLReadToggleInDrawer;
bool showSReadToggleInDrawer;
bool showGhostToggleInDrawer;
bool showStreamerToggleInDrawer;
bool showGhostToggleInTray;
bool showStreamerToggleInTray;
QString mainFont;
QString monoFont;
int showPeerId;
@@ -150,14 +165,26 @@ public:
void set_appIcon(QString val);
void set_simpleQuotesAndReplies(bool val);
void set_deletedMark(QString val);
void set_editedMark(QString val);
void set_recentStickersCount(int val);
void set_showLReadToggleInDrawer(bool val);
void set_showSReadToggleInDrawer(bool val);
void set_showGhostToggleInDrawer(bool val);
void set_showStreamerToggleInDrawer(bool val);
void set_showGhostToggleInTray(bool val);
void set_showStreamerToggleInTray(bool val);
void set_mainFont(QString val);
void set_monoFont(QString val);
@@ -194,10 +221,16 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
localPremium,
copyUsernameAsLink,
appIcon,
simpleQuotesAndReplies,
deletedMark,
editedMark,
recentStickersCount,
showLReadToggleInDrawer,
showSReadToggleInDrawer,
showGhostToggleInDrawer,
showStreamerToggleInDrawer,
showGhostToggleInTray,
showStreamerToggleInTray,
mainFont,
monoFont,
showPeerId,
@@ -531,12 +531,6 @@ bool InnerWidget::elementUnderCursor(
return (Element::Hovered() == view);
}
float64 InnerWidget::elementHighlightOpacity(
not_null<const HistoryItem *> item) const
{
return 0.;
}
bool InnerWidget::elementInSelectionMode()
{
return false;
@@ -93,8 +93,6 @@ public:
HistoryView::Context elementContext() override;
bool elementUnderCursor(
not_null<const HistoryView::Element *> view) override;
[[nodiscard]] float64 elementHighlightOpacity(
not_null<const HistoryItem *> item) const override;
bool elementInSelectionMode() override;
bool elementIntersectsRange(
not_null<const HistoryView::Element *> view,
@@ -46,39 +46,22 @@
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
#include "styles/style_ayu_icons.h"
class PainterHighQualityEnabler;
const char kStreamerMode[] =
"streamer-mode";
base::options::toggle StreamerMode(
{
.id = kStreamerMode,
.name = "Show streamer mode toggles",
.description = "Streamer mode completely hides AyuGram windows and notifications from capture apps.",
.scope = base::options::windows,
.restartRequired = true
}
);
not_null<Ui::RpWidget *> AddInnerToggle(
not_null<Ui::VerticalLayout *> container,
const style::SettingsButton &st,
std::vector<not_null<Ui::AbstractCheckView *>> innerCheckViews,
not_null<Ui::SlideWrap<> *> wrap,
rpl::producer<QString> buttonLabel,
std::optional<QString> locked,
bool toggledWhenAll,
Settings::IconDescriptor &&icon)
not_null<Ui::RpWidget *> AddInnerToggle(not_null<Ui::VerticalLayout *> container,
const style::SettingsButton &st,
std::vector<not_null<Ui::AbstractCheckView *>> innerCheckViews,
not_null<Ui::SlideWrap<> *> wrap,
rpl::producer<QString> buttonLabel,
bool toggledWhenAll)
{
const auto button = container->add(object_ptr<Ui::SettingsButton>(
container,
nullptr,
st));
if (icon) {
AddButtonIcon(button, st, std::move(icon));
}
st::settingsButtonNoIcon));
const auto toggleButton = Ui::CreateChild<Ui::SettingsButton>(
container.get(),
@@ -175,7 +158,7 @@ not_null<Ui::RpWidget *> AddInnerToggle(
anim::type::normal);
}
}, toggleButton->lifetime());
checkView->setLocked(locked.has_value());
checkView->setLocked(false);
checkView->finishAnimating();
const auto label = Ui::CreateChild<Ui::FlatLabel>(
@@ -241,34 +224,23 @@ not_null<Ui::RpWidget *> AddInnerToggle(
{ arrow->update(); },
toggled ? 0. : 1.,
toggled ? 1. : 0.,
st::slideWrapDuration);
st::slideWrapDuration,
anim::easeOutCubic);
}, button->lifetime());
const auto handleLocked = [=]
{
if (locked.has_value()) {
Ui::Toast::Show(container, *locked);
return true;
}
return false;
};
wrap->ease = anim::easeOutCubic;
button->clicks(
) | start_with_next([=]
{
if (!handleLocked()) {
wrap->toggle(!wrap->toggled(), anim::type::normal);
}
wrap->toggle(!wrap->toggled(), anim::type::normal);
}, button->lifetime());
toggleButton->clicks(
) | start_with_next([=]
{
if (!handleLocked()) {
const auto checked = !checkView->checked();
for (const auto &innerCheck : state->innerChecks) {
innerCheck->setChecked(checked, anim::type::normal);
}
const auto checked = !checkView->checked();
for (const auto &innerCheck : state->innerChecks) {
innerCheck->setChecked(checked, anim::type::normal);
}
}, toggleButton->lifetime());
@@ -476,9 +448,7 @@ void Ayu::SetupGhostModeToggle(not_null<Ui::VerticalLayout *> container)
innerChecks,
raw,
tr::ayu_GhostModeToggle(),
std::nullopt,
true,
{});
true);
container->add(std::move(wrap));
container->widthValue(
) | start_with_next([=](int w)
@@ -598,9 +568,7 @@ void Ayu::SetupReadAfterActionToggle(not_null<Ui::VerticalLayout *> container)
innerChecks,
raw,
tr::ayu_MarkReadAfterAction(),
std::nullopt,
false,
{});
false);
container->add(std::move(wrap));
container->widthValue(
) | start_with_next([=](int w)
@@ -823,17 +791,17 @@ void Ayu::SetupCustomization(not_null<Ui::VerticalLayout *> container,
AddButton(
container,
tr::ayu_ShowGhostToggleInDrawer(),
tr::ayu_SimpleQuotesAndReplies(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->showGhostToggleInDrawer)
rpl::single(settings->simpleQuotesAndReplies)
)->toggledValue(
) | rpl::filter([=](bool enabled)
{
return (enabled != settings->showGhostToggleInDrawer);
return (enabled != settings->simpleQuotesAndReplies);
}) | start_with_next([=](bool enabled)
{
settings->set_showGhostToggleInDrawer(enabled);
settings->set_simpleQuotesAndReplies(enabled);
AyuSettings::save();
}, container->lifetime());
@@ -853,12 +821,134 @@ void Ayu::SetupCustomization(not_null<Ui::VerticalLayout *> container,
AyuSettings::save();
}, container->lifetime());
AddSkip(container);
AddDivider(container);
SetupDrawerElements(container);
AddSkip(container);
AddDivider(container);
SetupTrayElements(container);
AddSkip(container);
AddDivider(container);
AddSkip(container);
SetupFonts(container, controller);
}
void Ayu::SetupDrawerElements(not_null<Ui::VerticalLayout *> container)
{
auto settings = &AyuSettings::getInstance();
AddSkip(container);
AddSubsectionTitle(container, tr::ayu_DrawerElementsHeader());
AddButton(
container,
tr::ayu_LReadMessages(),
st::settingsButton,
{&st::ayuLReadMenuIcon}
)->toggleOn(
rpl::single(settings->showLReadToggleInDrawer)
)->toggledValue(
) | rpl::filter([=](bool enabled)
{
return (enabled != settings->showLReadToggleInDrawer);
}) | start_with_next([=](bool enabled)
{
settings->set_showLReadToggleInDrawer(enabled);
AyuSettings::save();
}, container->lifetime());
AddButton(
container,
tr::ayu_SReadMessages(),
st::settingsButton,
{&st::ayuSReadMenuIcon}
)->toggleOn(
rpl::single(settings->showSReadToggleInDrawer)
)->toggledValue(
) | rpl::filter([=](bool enabled)
{
return (enabled != settings->showSReadToggleInDrawer);
}) | start_with_next([=](bool enabled)
{
settings->set_showSReadToggleInDrawer(enabled);
AyuSettings::save();
}, container->lifetime());
AddButton(
container,
tr::ayu_GhostModeToggle(),
st::settingsButton,
{&st::ayuGhostIcon}
)->toggleOn(
rpl::single(settings->showGhostToggleInDrawer)
)->toggledValue(
) | rpl::filter([=](bool enabled)
{
return (enabled != settings->showGhostToggleInDrawer);
}) | start_with_next([=](bool enabled)
{
settings->set_showGhostToggleInDrawer(enabled);
AyuSettings::save();
}, container->lifetime());
AddButton(
container,
tr::ayu_StreamerModeToggle(),
st::settingsButton,
{&st::ayuStreamerModeMenuIcon}
)->toggleOn(
rpl::single(settings->showStreamerToggleInDrawer)
)->toggledValue(
) | rpl::filter([=](bool enabled)
{
return (enabled != settings->showStreamerToggleInDrawer);
}) | start_with_next([=](bool enabled)
{
settings->set_showStreamerToggleInDrawer(enabled);
AyuSettings::save();
}, container->lifetime());
}
void Ayu::SetupTrayElements(not_null<Ui::VerticalLayout *> container)
{
auto settings = &AyuSettings::getInstance();
AddSkip(container);
AddSubsectionTitle(container, tr::ayu_TrayElementsHeader());
AddButton(
container,
tr::ayu_EnableGhostModeTray(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->showGhostToggleInTray)
)->toggledValue(
) | rpl::filter([=](bool enabled)
{
return (enabled != settings->showGhostToggleInTray);
}) | start_with_next([=](bool enabled)
{
settings->set_showGhostToggleInTray(enabled);
AyuSettings::save();
}, container->lifetime());
AddButton(
container,
tr::ayu_EnableStreamerModeTray(),
st::settingsButtonNoIcon
)->toggleOn(
rpl::single(settings->showStreamerToggleInTray)
)->toggledValue(
) | rpl::filter([=](bool enabled)
{
return (enabled != settings->showStreamerToggleInTray);
}) | start_with_next([=](bool enabled)
{
settings->set_showStreamerToggleInTray(enabled);
AyuSettings::save();
}, container->lifetime());
}
void Ayu::SetupShowPeerId(not_null<Ui::VerticalLayout *> container,
not_null<Window::SessionController *> controller)
{
@@ -1062,13 +1152,6 @@ void Ayu::SetupSendConfirmations(not_null<Ui::VerticalLayout *> container)
}, container->lifetime());
}
void Ayu::SetupExperimental(not_null<Ui::VerticalLayout *> container,
not_null<Window::SessionController *> controller)
{
AddSubsectionTitle(container, tr::lng_settings_experimental());
AddPlatformOption(controller, container, StreamerMode, rpl::producer<>());
}
void Ayu::SetupAyuGramSettings(not_null<Ui::VerticalLayout *> container,
not_null<Window::SessionController *> controller)
{
@@ -1107,10 +1190,7 @@ void Ayu::SetupAyuGramSettings(not_null<Ui::VerticalLayout *> container,
AddSkip(container);
SetupSendConfirmations(container);
AddSkip(container);
AddDivider(container);
AddSkip(container);
SetupExperimental(container, controller);
AddDividerText(container, tr::ayu_SettingsWatermark());
}
@@ -17,10 +17,6 @@ class Controller;
class SessionController;
} // namespace Window
extern const char kStreamerMode[];
extern base::options::toggle StreamerMode;
namespace Settings
{
@@ -53,6 +49,10 @@ private:
void SetupCustomization(not_null<Ui::VerticalLayout *> container,
not_null<Window::SessionController *> controller);
void SetupDrawerElements(not_null<Ui::VerticalLayout *> container);
void SetupTrayElements(not_null<Ui::VerticalLayout *> container);
void SetupShowPeerId(not_null<Ui::VerticalLayout *> container, not_null<Window::SessionController *> controller);
void SetupRecentStickersLimitSlider(not_null<Ui::VerticalLayout *> container);
@@ -63,9 +63,6 @@ private:
void SetupSendConfirmations(not_null<Ui::VerticalLayout *> container);
void SetupExperimental(not_null<Ui::VerticalLayout *> container,
not_null<Window::SessionController *> controller);
void SetupAyuGramSettings(not_null<Ui::VerticalLayout *> container, not_null<Window::SessionController *> null);
void setupContent(not_null<Window::SessionController *> controller);
+2 -2
View File
@@ -542,8 +542,8 @@ rightsToggle: Toggle(defaultToggle) {
toggledFg: windowBgActive;
untoggledFg: attentionButtonFg;
lockIcon: icon {{ "info/info_rights_lock", windowBgActive }};
xsize: 8px;
vsize: 5px;
xsize: 0px;
vsize: 0px;
vshift: 1px;
stroke: 2px;
duration: 120;
@@ -362,7 +362,7 @@ void EditFilterChatsListController::rowClicked(not_null<PeerListRow*> row) {
delegate()->peerListSetRowChecked(row, !row->checked());
updateTitle();
} else {
delegate()->peerListShowBox(_limitBox(count));
delegate()->peerListUiShow()->showBox(_limitBox(count));
}
}
@@ -37,8 +37,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
#include <xxhash.h>
namespace {
constexpr auto kMaxLinkTitleLength = 32;
@@ -223,14 +221,6 @@ private:
};
[[nodiscard]] uint64 ComputeRowId(const QString &link) {
return XXH64(link.data(), link.size() * sizeof(ushort), 0);
}
[[nodiscard]] uint64 ComputeRowId(const InviteLinkData &data) {
return ComputeRowId(data.url);
}
[[nodiscard]] Color ComputeColor(const InviteLinkData &link) {
return Color::Permanent;
}
@@ -242,7 +232,7 @@ private:
LinkRow::LinkRow(
not_null<LinkRowDelegate*> delegate,
const InviteLinkData &data)
: PeerListRow(ComputeRowId(data))
: PeerListRow(UniqueRowIdFromString(data.url))
, _delegate(delegate)
, _data(data)
, _color(ComputeColor(data)) {
@@ -585,19 +575,19 @@ void LinkController::addLinkBlock(not_null<Ui::VerticalLayout*> container) {
CopyInviteLink(delegate()->peerListUiShow(), link);
});
const auto shareLink = crl::guard(weak, [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
ShareInviteLinkBox(&_window->session(), link));
});
const auto getLinkQr = crl::guard(weak, [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
InviteLinkQrBox(link, tr::lng_filters_link_qr_about()));
});
const auto editLink = crl::guard(weak, [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
Box(ChatFilterLinkBox, &_window->session(), _data));
});
const auto deleteLink = crl::guard(weak, [=] {
delegate()->peerListShowBox(DeleteLinkBox(_window, _data));
delegate()->peerListUiShow()->showBox(DeleteLinkBox(_window, _data));
});
const auto createMenu = [=] {
@@ -856,7 +846,7 @@ void LinksController::rebuild(const std::vector<InviteLinkData> &rows) {
void LinksController::rowClicked(not_null<PeerListRow*> row) {
const auto link = static_cast<LinkRow*>(row.get())->data();
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
ShowLinkBox(_window, _currentFilter(), link));
}
@@ -891,19 +881,19 @@ base::unique_qptr<Ui::PopupMenu> LinksController::createRowContextMenu(
CopyInviteLink(delegate()->peerListUiShow(), link);
};
const auto shareLink = [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
ShareInviteLinkBox(&_window->session(), link));
};
const auto getLinkQr = [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
InviteLinkQrBox(link, tr::lng_filters_link_qr_about()));
};
const auto editLink = [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
Box(ChatFilterLinkBox, &_window->session(), data));
};
const auto deleteLink = [=] {
delegate()->peerListShowBox(DeleteLinkBox(_window, data));
delegate()->peerListUiShow()->showBox(DeleteLinkBox(_window, data));
};
auto result = base::make_unique_q<Ui::PopupMenu>(
parent,
+195 -80
View File
@@ -7,12 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/gift_premium_box.h"
#include "apiwrap.h"
#include "api/api_premium.h"
#include "api/api_premium_option.h"
#include "apiwrap.h"
#include "base/unixtime.h"
#include "base/weak_ptr.h"
#include "boxes/peers/prepare_short_info_box.h"
#include "data/data_boosts.h"
#include "data/data_changes.h"
#include "data/data_channel.h"
#include "data/data_media_types.h" // Data::Giveaway
@@ -30,8 +31,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/premium_graphics.h"
#include "ui/effects/premium_stars_colored.h"
#include "ui/effects/premium_top_bar.h"
#include "ui/effects/spoiler_mess.h"
#include "ui/layers/generic_box.h"
#include "ui/text/format_values.h"
#include "ui/rect.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/gradient_round_button.h"
@@ -40,9 +42,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_peer_menu.h" // ShowChooseRecipientBox.
#include "window/window_session_controller.h"
#include "styles/style_boxes.h"
#include "styles/style_layers.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_giveaway.h"
#include "styles/style_info.h"
#include "styles/style_layers.h"
#include "styles/style_premium.h"
#include <QtGui/QGuiApplication>
@@ -93,7 +95,7 @@ void GiftBox(
+ st::defaultUserpicButton.size.height()));
using ColoredMiniStars = Ui::Premium::ColoredMiniStars;
const auto stars = box->lifetime().make_state<ColoredMiniStars>(top);
const auto stars = box->lifetime().make_state<ColoredMiniStars>(top, true);
const auto userpic = Ui::CreateChild<Ui::UserpicButton>(
top,
@@ -237,11 +239,7 @@ void GiftBox(
}, box->lifetime());
}
struct GiftCodeLink {
QString text;
QString link;
};
[[nodiscard]] GiftCodeLink MakeGiftCodeLink(
[[nodiscard]] Data::GiftCodeLink MakeGiftCodeLink(
not_null<Main::Session*> session,
const QString &slug) {
const auto path = u"giftcode/"_q + slug;
@@ -281,7 +279,7 @@ struct GiftCodeLink {
[[nodiscard]] object_ptr<Ui::RpWidget> MakePeerTableValue(
not_null<QWidget*> parent,
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
PeerId id) {
auto result = object_ptr<Ui::AbstractButton>(parent);
const auto raw = result.data();
@@ -309,7 +307,7 @@ struct GiftCodeLink {
label->setTextColorOverride(st::windowActiveTextFg->c);
raw->setClickedCallback([=] {
controller->show(PrepareShortInfoBox(peer, controller));
controller->uiShow()->showBox(PrepareShortInfoBox(peer, controller));
});
return result;
@@ -350,7 +348,7 @@ not_null<Ui::FlatLabel*> AddTableRow(
void AddTableRow(
not_null<Ui::TableLayout*> table,
rpl::producer<QString> label,
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
PeerId id) {
if (!id) {
return;
@@ -362,6 +360,73 @@ void AddTableRow(
st::giveawayGiftCodePeerMargin);
}
void AddTable(
not_null<Ui::VerticalLayout*> container,
not_null<Window::SessionNavigation*> controller,
const Api::GiftCode &current,
bool skipReason) {
auto table = container->add(
object_ptr<Ui::TableLayout>(
container,
st::giveawayGiftCodeTable),
st::giveawayGiftCodeTableMargin);
AddTableRow(
table,
tr::lng_gift_link_label_from(),
controller,
current.from);
if (current.to) {
AddTableRow(
table,
tr::lng_gift_link_label_to(),
controller,
current.to);
} else {
AddTableRow(
table,
tr::lng_gift_link_label_to(),
tr::lng_gift_link_label_to_unclaimed(Ui::Text::WithEntities));
}
AddTableRow(
table,
tr::lng_gift_link_label_gift(),
tr::lng_gift_link_gift_premium(
lt_duration,
GiftDurationValue(current.months) | Ui::Text::ToWithEntities(),
Ui::Text::WithEntities));
if (!skipReason) {
const auto reason = AddTableRow(
table,
tr::lng_gift_link_label_reason(),
(current.giveawayId
? ((current.to
? tr::lng_gift_link_reason_giveaway
: tr::lng_gift_link_reason_unclaimed)(
) | Ui::Text::ToLink())
: current.giveaway
? ((current.to
? tr::lng_gift_link_reason_giveaway
: tr::lng_gift_link_reason_unclaimed)(
Ui::Text::WithEntities
) | rpl::type_erased())
: tr::lng_gift_link_reason_chosen(Ui::Text::WithEntities)));
reason->setClickHandlerFilter([=](const auto &...) {
controller->showPeerHistory(
current.from,
Window::SectionShow::Way::Forward,
current.giveawayId);
return false;
});
}
if (current.date) {
AddTableRow(
table,
tr::lng_gift_link_label_date(),
rpl::single(Ui::Text::WithEntities(
langDateTime(base::unixtime::parse(current.date)))));
}
}
} // namespace
GiftPremiumValidator::GiftPremiumValidator(
@@ -416,7 +481,7 @@ QString GiftDuration(int months) {
void GiftCodeBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
const QString &slug) {
struct State {
rpl::variable<Api::GiftCode> data;
@@ -466,65 +531,7 @@ void GiftCodeBox(
MakeLinkCopyIcon(box)),
st::giveawayGiftCodeLinkMargin);
auto table = box->addRow(
object_ptr<Ui::TableLayout>(
box,
st::giveawayGiftCodeTable),
st::giveawayGiftCodeTableMargin);
const auto current = state->data.current();
AddTableRow(
table,
tr::lng_gift_link_label_from(),
controller,
current.from);
if (current.to) {
AddTableRow(
table,
tr::lng_gift_link_label_to(),
controller,
current.to);
} else {
AddTableRow(
table,
tr::lng_gift_link_label_to(),
tr::lng_gift_link_label_to_unclaimed(Ui::Text::WithEntities));
}
AddTableRow(
table,
tr::lng_gift_link_label_gift(),
tr::lng_gift_link_gift_premium(
lt_duration,
GiftDurationValue(current.months) | Ui::Text::ToWithEntities(),
Ui::Text::WithEntities));
const auto reason = AddTableRow(
table,
tr::lng_gift_link_label_reason(),
(current.giveawayId
? ((current.to
? tr::lng_gift_link_reason_giveaway
: tr::lng_gift_link_reason_unclaimed)(
) | Ui::Text::ToLink())
: current.giveaway
? ((current.to
? tr::lng_gift_link_reason_giveaway
: tr::lng_gift_link_reason_unclaimed)(
Ui::Text::WithEntities
) | rpl::type_erased())
: tr::lng_gift_link_reason_chosen(Ui::Text::WithEntities)));
reason->setClickHandlerFilter([=](const auto &...) {
controller->showPeerHistory(
current.from,
Window::SectionShow::Way::Forward,
current.giveawayId);
return false;
});
if (current.date) {
AddTableRow(
table,
tr::lng_gift_link_label_date(),
rpl::single(Ui::Text::WithEntities(
langDateTime(base::unixtime::parse(current.date)))));
}
AddTable(box->verticalLayout(), controller, state->data.current(), false);
auto shareLink = tr::lng_gift_link_also_send_link(
) | rpl::map([](const QString &text) {
@@ -552,7 +559,7 @@ void GiftCodeBox(
st::giveawayGiftCodeFooterMargin);
footer->setClickHandlerFilter([=](const auto &...) {
const auto chosen = [=](not_null<Data::Thread*> thread) {
const auto content = controller->content();
const auto content = controller->parentController()->content();
return content->shareUrl(
thread,
MakeGiftCodeLink(&controller->session(), slug).link,
@@ -607,14 +614,121 @@ void GiftCodeBox(
}, button->lifetime());
}
void GiftCodePendingBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionNavigation*> controller,
const Api::GiftCode &data) {
box->setWidth(st::boxWideWidth);
box->setStyle(st::giveawayGiftCodeBox);
box->setNoContentMargin(true);
{
const auto peerTo = controller->session().data().peer(data.to);
const auto clickContext = [=, weak = base::make_weak(controller)] {
if (const auto strong = weak.get()) {
strong->uiShow()->showBox(
PrepareShortInfoBox(peerTo, strong));
}
return QVariant();
};
const auto &st = st::giveawayGiftCodeCover;
const auto resultToName = st.about.style.font->elided(
peerTo->shortName(),
st.about.minWidth / 2,
Qt::ElideMiddle);
const auto bar = box->setPinnedToTopContent(
object_ptr<Ui::Premium::TopBar>(
box,
st,
clickContext,
tr::lng_gift_link_title(),
tr::lng_gift_link_pending_about(
lt_user,
rpl::single(Ui::Text::Link(resultToName)),
Ui::Text::RichLangValue),
true));
const auto max = st::giveawayGiftCodeTopHeight;
bar->setMaximumHeight(max);
bar->setMinimumHeight(st::infoLayerTopBarHeight);
bar->resize(bar->width(), bar->maximumHeight());
}
{
const auto linkLabel = box->addRow(
Ui::MakeLinkLabel(box, nullptr, nullptr, nullptr, nullptr),
st::giveawayGiftCodeLinkMargin);
const auto spoiler = Ui::CreateChild<Ui::AbstractButton>(linkLabel);
spoiler->lifetime().make_state<Ui::Animations::Basic>([=] {
spoiler->update();
})->start();
linkLabel->sizeValue(
) | rpl::start_with_next([=](const QSize &s) {
spoiler->setGeometry(Rect(s));
}, spoiler->lifetime());
const auto spoilerCached = Ui::SpoilerMessCached(
Ui::DefaultTextSpoilerMask(),
st::giveawayGiftCodeLink.textFg->c);
const auto textHeight = st::giveawayGiftCodeLink.style.font->height;
spoiler->paintRequest(
) | rpl::start_with_next([=] {
auto p = QPainter(spoiler);
const auto rect = spoiler->rect();
const auto r = rect
- QMargins(
st::boxRowPadding.left(),
(rect.height() - textHeight) / 2,
st::boxRowPadding.right(),
(rect.height() - textHeight) / 2);
Ui::FillSpoilerRect(p, r, spoilerCached.frame());
}, spoiler->lifetime());
spoiler->setClickedCallback([show = box->uiShow()] {
show->showToast(tr::lng_gift_link_pending_toast(tr::now));
});
spoiler->show();
}
AddTable(box->verticalLayout(), controller, data, true);
box->addRow(
object_ptr<Ui::FlatLabel>(
box,
tr::lng_gift_link_pending_footer(),
st::giveawayGiftCodeFooter),
st::giveawayGiftCodeFooterMargin);
const auto close = Ui::CreateChild<Ui::IconButton>(
box.get(),
st::boxTitleClose);
const auto closeCallback = [=] { box->closeBox(); };
close->setClickedCallback(closeCallback);
box->widthValue(
) | rpl::start_with_next([=](int width) {
close->moveToRight(0, 0);
}, box->lifetime());
const auto button = box->addButton(tr::lng_close(), closeCallback);
const auto buttonPadding = st::giveawayGiftCodeBox.buttonPadding;
const auto buttonWidth = st::boxWideWidth
- buttonPadding.left()
- buttonPadding.right();
button->widthValue() | rpl::filter([=] {
return (button->widthNoMargins() != buttonWidth);
}) | rpl::start_with_next([=] {
button->resizeToWidth(buttonWidth);
}, button->lifetime());
}
void ResolveGiftCode(
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
const QString &slug) {
const auto done = [=](Api::GiftCode code) {
if (!code) {
controller->showToast(tr::lng_gift_link_expired(tr::now));
} else {
controller->show(Box(GiftCodeBox, controller, slug));
controller->uiShow()->showBox(Box(GiftCodeBox, controller, slug));
}
};
controller->session().api().premium().checkGiftCode(
@@ -624,7 +738,7 @@ void ResolveGiftCode(
void GiveawayInfoBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
Data::Giveaway giveaway,
Api::GiveawayInfo info) {
using State = Api::GiveawayState;
@@ -693,7 +807,8 @@ void GiveawayInfoBox(
text.append(' ').append(tr::lng_prizes_end_activated(
tr::now,
lt_count,
info.activatedCount));
info.activatedCount,
Ui::Text::RichLangValue));
}
if (!info.giftCode.isEmpty()) {
text.append("\n\n");
@@ -784,7 +899,7 @@ void GiveawayInfoBox(
}
void ResolveGiveawayInfo(
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
not_null<PeerData*> peer,
MsgId messageId,
Data::Giveaway giveaway) {
@@ -793,7 +908,7 @@ void ResolveGiveawayInfo(
controller->showToast(
tr::lng_confirm_phone_link_invalid(tr::now));
} else {
controller->show(
controller->uiShow()->showBox(
Box(GiveawayInfoBox, controller, giveaway, info));
}
};
@@ -25,6 +25,7 @@ class GenericBox;
namespace Window {
class SessionController;
class SessionNavigation;
} // namespace Window
class GiftPremiumValidator final {
@@ -47,14 +48,18 @@ private:
void GiftCodeBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
const QString &slug);
void GiftCodePendingBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionNavigation*> controller,
const Api::GiftCode &data);
void ResolveGiftCode(
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
const QString &slug);
void ResolveGiveawayInfo(
not_null<Window::SessionController*> controller,
not_null<Window::SessionNavigation*> controller,
not_null<PeerData*> peer,
MsgId messageId,
Data::Giveaway giveaway);
+4 -6
View File
@@ -567,12 +567,10 @@ void PasscodeBox::validateEmail(
} else if (error.type() == u"EMAIL_HASH_EXPIRED"_q) {
const auto weak = Ui::MakeWeak(this);
_clearUnconfirmedPassword.fire({});
if (weak) {
auto box = Ui::MakeInformBox({
Lang::Hard::EmailConfirmationExpired()
});
weak->getDelegate()->show(
std::move(box),
if (const auto strong = weak.data()) {
strong->getDelegate()->show(
Ui::MakeInformBox(
Lang::Hard::EmailConfirmationExpired()),
Ui::LayerOption::CloseOther);
}
} else {
+17 -21
View File
@@ -35,6 +35,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_dialogs.h"
#include "styles/style_widgets.h"
#include <xxhash.h> // XXH64.
[[nodiscard]] PeerListRowId UniqueRowIdFromString(const QString &d) {
return XXH64(d.data(), d.size() * sizeof(ushort), 0);
}
PaintRoundImageCallback PaintUserpicCallback(
not_null<PeerData*> peer,
bool respectSavedMessagesChat) {
@@ -79,16 +85,6 @@ PeerListContentDelegateShow::PeerListContentDelegateShow(
: _show(show) {
}
void PeerListContentDelegateShow::peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options) {
_show->showBox(std::move(content), options);
}
void PeerListContentDelegateShow::peerListHideLayer() {
_show->hideLayer();
}
auto PeerListContentDelegateShow::peerListUiShow()
-> std::shared_ptr<Main::SessionShow>{
return _show;
@@ -318,16 +314,6 @@ void PeerListBox::peerListSetSearchMode(PeerListSearchMode mode) {
}
}
void PeerListBox::peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options) {
_show->showBox(std::move(content), options);
}
void PeerListBox::peerListHideLayer() {
_show->hideLayer();
}
std::shared_ptr<Main::SessionShow> PeerListBox::peerListUiShow() {
return _show;
}
@@ -760,7 +746,7 @@ int PeerListRow::paintNameIconGetWidth(
nameWidth,
outerWidth,
{
.peer = _peer,
.peer = peer(),
.verified = &(selected
? st::dialogsVerifiedIconOver
: st::dialogsVerifiedIcon),
@@ -1696,9 +1682,19 @@ crl::time PeerListContent::paintRow(
return refreshStatusIn;
}
const auto opacity = row->opacity();
const auto &bg = selected
? _st.item.button.textBgOver
: _st.item.button.textBg;
if (opacity < 1.) {
p.setOpacity(opacity);
}
const auto guard = gsl::finally([&] {
if (opacity < 1.) {
p.setOpacity(1.);
}
});
p.fillRect(0, 0, outerWidth, _rowHeight, bg);
row->paintRipple(p, 0, 0, outerWidth);
row->paintUserpic(
+5 -20
View File
@@ -54,6 +54,8 @@ using PaintRoundImageCallback = Fn<void(
using PeerListRowId = uint64;
[[nodiscard]] PeerListRowId UniqueRowIdFromString(const QString &d);
class PeerListRow {
public:
enum class State {
@@ -139,6 +141,9 @@ public:
}
virtual void rightActionStopLastRipple() {
}
[[nodiscard]] virtual float64 opacity() {
return 1.;
}
// By default elements code falls back to a simple right action code.
virtual int elementsCount() const;
@@ -330,10 +335,6 @@ public:
virtual std::optional<QPoint> peerListLastRowMousePosition() = 0;
virtual void peerListSortRows(Fn<bool(const PeerListRow &a, const PeerListRow &b)> compare) = 0;
virtual int peerListPartitionRows(Fn<bool(const PeerListRow &a)> border) = 0;
virtual void peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options = Ui::LayerOption::KeepOther) = 0;
virtual void peerListHideLayer() = 0;
virtual std::shared_ptr<Main::SessionShow> peerListUiShow() = 0;
template <typename PeerDataRange>
@@ -1005,14 +1006,6 @@ public:
object_ptr<Ui::FlatLabel> description) override {
description.destroy();
}
void peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options = Ui::LayerOption::KeepOther) override {
Unexpected("...DelegateSimple::peerListShowBox");
}
void peerListHideLayer() override {
Unexpected("...DelegateSimple::peerListHideLayer");
}
std::shared_ptr<Main::SessionShow> peerListUiShow() override {
Unexpected("...DelegateSimple::peerListUiShow");
}
@@ -1023,10 +1016,6 @@ class PeerListContentDelegateShow : public PeerListContentDelegateSimple {
public:
explicit PeerListContentDelegateShow(
std::shared_ptr<Main::SessionShow> show);
void peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options = Ui::LayerOption::KeepOther) override;
void peerListHideLayer() override;
std::shared_ptr<Main::SessionShow> peerListUiShow() override;
private:
@@ -1062,10 +1051,6 @@ public:
bool peerListIsRowChecked(not_null<PeerListRow*> row) override;
int peerListSelectedRowsCount() override;
void peerListScrollToTop() override;
void peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options = Ui::LayerOption::KeepOther) override;
void peerListHideLayer() override;
std::shared_ptr<Main::SessionShow> peerListUiShow() override;
void setAddedTopScrollSkip(int skip);
@@ -685,7 +685,7 @@ void ChooseRecipientBoxController::rowClicked(not_null<PeerListRow*> row) {
}, box->lifetime());
});
*weak = owned.data();
delegate()->peerListShowBox(std::move(owned));
delegate()->peerListUiShow()->showBox(std::move(owned));
return;
}
const auto history = peer->owner().history(peer);
@@ -372,16 +372,6 @@ void PeerListsBox::Delegate::peerListFinishSelectedRowsBunch() {
_box->_select->entity()->finishItemsBunch();
}
void PeerListsBox::Delegate::peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options) {
_show->showBox(std::move(content), options);
}
void PeerListsBox::Delegate::peerListHideLayer() {
_show->hideLayer();
}
auto PeerListsBox::Delegate::peerListUiShow()
-> std::shared_ptr<Main::SessionShow> {
return _show;
@@ -54,10 +54,6 @@ private:
_box->addSelectItem(row, anim::type::instant);
}
void peerListFinishSelectedRowsBunch() override;
void peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options = Ui::LayerOption::KeepOther) override;
void peerListHideLayer() override;
std::shared_ptr<Main::SessionShow> peerListUiShow() override;
private:
@@ -366,7 +366,7 @@ bool AddParticipantsBoxController::needsInviteLinkButton() {
QPointer<Ui::BoxContent> AddParticipantsBoxController::showBox(
object_ptr<Ui::BoxContent> box) const {
const auto weak = Ui::MakeWeak(box.data());
delegate()->peerListShowBox(std::move(box));
delegate()->peerListUiShow()->showBox(std::move(box));
return weak;
}
@@ -668,7 +668,7 @@ void AddSpecialBoxController::migrate(
QPointer<Ui::BoxContent> AddSpecialBoxController::showBox(
object_ptr<Ui::BoxContent> box) const {
const auto weak = Ui::MakeWeak(box.data());
delegate()->peerListShowBox(std::move(box));
delegate()->peerListUiShow()->showBox(std::move(box));
return weak;
}
@@ -433,7 +433,7 @@ void ChoosePeerBoxController::rowClicked(not_null<PeerListRow*> row) {
if (const auto user = peer->asUser()) {
done();
} else {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
MakeConfirmBox(_bot, peer, _query, done));
}
}
@@ -55,6 +55,7 @@ public:
rpl::producer<DefaultIcon> value,
Fn<void()> repaint);
int width() override;
QString entityData() override;
void paint(QPainter &p, const Context &context) override;
@@ -80,6 +81,10 @@ DefaultIconEmoji::DefaultIconEmoji(
}, _lifetime);
}
int DefaultIconEmoji::width() {
return st::emojiSize + 2 * st::emojiPadding;
}
QString DefaultIconEmoji::entityData() {
return u"topic_icon:%1"_q.arg(_icon.colorId);
}
@@ -168,7 +168,7 @@ void Controller::choose(not_null<ChannelData*> chat) {
const auto onstack = _callback;
onstack(chat);
};
delegate()->peerListShowBox(Ui::MakeConfirmBox({
delegate()->peerListUiShow()->showBox(Ui::MakeConfirmBox({
.text = text,
.confirmed = sure,
.confirmText = tr::lng_manage_discussion_group_link(tr::now),
@@ -199,7 +199,7 @@ void Controller::choose(not_null<ChatData*> chat) {
};
chat->session().api().migrateChat(chat, crl::guard(this, done));
};
delegate()->peerListShowBox(Ui::MakeConfirmBox({
delegate()->peerListUiShow()->showBox(Ui::MakeConfirmBox({
.text = text,
.confirmed = sure,
.confirmText = tr::lng_manage_discussion_group_link(tr::now),
@@ -1281,7 +1281,7 @@ void ParticipantsBoxController::rebuild() {
QPointer<Ui::BoxContent> ParticipantsBoxController::showBox(
object_ptr<Ui::BoxContent> box) const {
const auto weak = Ui::MakeWeak(box.data());
delegate()->peerListShowBox(std::move(box));
delegate()->peerListUiShow()->showBox(std::move(box));
return weak;
}
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "base/unixtime.h"
#include "boxes/peers/replace_boost_box.h"
#include "chat_helpers/compose/compose_show.h"
#include "data/data_changes.h"
#include "data/data_channel.h"
@@ -514,21 +515,17 @@ void Apply(
close();
return;
}
const auto next = data.vnext_level_boosts().value_or_empty();
const auto openStatistics = [=] {
if (const auto controller = show->resolveWindow(
ChatHelpers::WindowUsage::PremiumPromo)) {
controller->showSection(Info::Boosts::Make(peer));
}
};
auto counters = ParseBoostCounters(result);
counters.mine = 0; // Don't show current level as just-reached.
show->show(Box(Ui::AskBoostBox, Ui::AskBoostBoxData{
.link = qs(data.vboost_url()),
.boost = {
.level = data.vlevel().v,
.boosts = data.vboosts().v,
.thisLevelBoosts = data.vcurrent_level_boosts().v,
.nextLevelBoosts = next,
},
.boost = counters,
.requiredLevel = required,
}, openStatistics, nullptr));
cancel();
@@ -347,21 +347,24 @@ void Controller::addHeaderBlock(not_null<Ui::VerticalLayout*> container) {
const auto copyLink = crl::guard(weak, [=] {
CopyInviteLink(delegate()->peerListUiShow(), link);
});
const auto shareLink = crl::guard(weak, [=] {
delegate()->peerListShowBox(ShareInviteLinkBox(_peer, link));
const auto shareLink = crl::guard(weak, [=, peer = _peer] {
delegate()->peerListUiShow()->showBox(ShareInviteLinkBox(peer, link));
});
const auto getLinkQr = crl::guard(weak, [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
InviteLinkQrBox(link, tr::lng_group_invite_qr_about()));
});
const auto revokeLink = crl::guard(weak, [=] {
delegate()->peerListShowBox(RevokeLinkBox(_peer, admin, link));
delegate()->peerListUiShow()->showBox(
RevokeLinkBox(_peer, admin, link));
});
const auto editLink = crl::guard(weak, [=] {
delegate()->peerListShowBox(EditLinkBox(_peer, _data.current()));
delegate()->peerListUiShow()->showBox(
EditLinkBox(_peer, _data.current()));
});
const auto deleteLink = crl::guard(weak, [=] {
delegate()->peerListShowBox(DeleteLinkBox(_peer, admin, link));
delegate()->peerListUiShow()->showBox(
DeleteLinkBox(_peer, admin, link));
});
const auto createMenu = [=] {
@@ -1332,7 +1335,7 @@ object_ptr<Ui::BoxContent> ShowInviteLinkBox(
auto data = rpl::single(link) | rpl::then(std::move(updates));
auto initBox = [=, data = rpl::duplicate(data)](
not_null<Ui::BoxContent*> box) {
not_null<Ui::BoxContent*> box) {
rpl::duplicate(
data
) | rpl::start_with_next([=](const LinkData &link) {
@@ -32,8 +32,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_settings.h" // st::settingsDividerLabelPadding
#include "styles/style_menu_icons.h"
#include <xxhash.h>
namespace {
enum class Color {
@@ -112,12 +110,8 @@ private:
};
[[nodiscard]] uint64 ComputeRowId(const QString &link) {
return XXH64(link.data(), link.size() * sizeof(ushort), 0);
}
[[nodiscard]] uint64 ComputeRowId(const InviteLinkData &data) {
return ComputeRowId(data.link);
return UniqueRowIdFromString(data.link);
}
[[nodiscard]] float64 ComputeProgress(
@@ -543,7 +537,7 @@ void LinksController::appendSlice(const InviteLinksSlice &slice) {
}
void LinksController::rowClicked(not_null<PeerListRow*> row) {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
ShowInviteLinkBox(_peer, static_cast<Row*>(row.get())->data()));
}
@@ -579,25 +573,27 @@ base::unique_qptr<Ui::PopupMenu> LinksController::createRowContextMenu(
st::popupMenuWithIcons);
if (data.revoked) {
result->addAction(tr::lng_group_invite_context_delete(tr::now), [=] {
delegate()->peerListShowBox(DeleteLinkBox(_peer, _admin, link));
delegate()->peerListUiShow()->showBox(
DeleteLinkBox(_peer, _admin, link));
}, &st::menuIconDelete);
} else {
result->addAction(tr::lng_group_invite_context_copy(tr::now), [=] {
CopyInviteLink(delegate()->peerListUiShow(), link);
}, &st::menuIconCopy);
result->addAction(tr::lng_group_invite_context_share(tr::now), [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
ShareInviteLinkBox(_peer, link));
}, &st::menuIconShare);
result->addAction(tr::lng_group_invite_context_qr(tr::now), [=] {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
InviteLinkQrBox(link, tr::lng_group_invite_qr_about()));
}, &st::menuIconQrCode);
result->addAction(tr::lng_group_invite_context_edit(tr::now), [=] {
delegate()->peerListShowBox(EditLinkBox(_peer, data));
delegate()->peerListUiShow()->showBox(EditLinkBox(_peer, data));
}, &st::menuIconEdit);
result->addAction(tr::lng_group_invite_context_revoke(tr::now), [=] {
delegate()->peerListShowBox(RevokeLinkBox(_peer, _admin, link));
delegate()->peerListUiShow()->showBox(
RevokeLinkBox(_peer, _admin, link));
}, &st::menuIconRemove);
}
return result;
@@ -628,7 +624,8 @@ void LinksController::updateRow(const InviteLinkData &data, TimeId now) {
}
bool LinksController::removeRow(const QString &link) {
if (const auto row = delegate()->peerListFindRow(ComputeRowId(link))) {
const auto id = UniqueRowIdFromString(link);
if (const auto row = delegate()->peerListFindRow(id)) {
delegate()->peerListRemoveRow(row);
return true;
}
@@ -804,7 +801,7 @@ void AdminsController::loadMoreRows() {
}
void AdminsController::rowClicked(not_null<PeerListRow*> row) {
delegate()->peerListShowBox(
delegate()->peerListUiShow()->showBox(
Box(ManageInviteLinksBox, _peer, row->peer()->asUser(), 0, 0));
}
@@ -468,8 +468,10 @@ not_null<Ui::RpWidget*> AddInnerToggle(
[=] { arrow->update(); },
toggled ? 0. : 1.,
toggled ? 1. : 0.,
st::slideWrapDuration);
st::slideWrapDuration,
anim::easeOutCubic);
}, button->lifetime());
wrap->ease = anim::easeOutCubic;
const auto handleLocked = [=] {
if (locked.has_value()) {
@@ -0,0 +1,613 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/peers/replace_boost_box.h"
#include "base/event_filter.h"
#include "base/unixtime.h"
#include "boxes/peer_list_box.h"
#include "data/data_channel.h"
#include "data/data_session.h"
#include "lang/lang_keys.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
#include "main/session/session_show.h"
#include "ui/boxes/boost_box.h"
#include "ui/boxes/confirm_box.h"
#include "ui/chat/chat_style.h"
#include "ui/controls/userpic_button.h"
#include "ui/effects/premium_graphics.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/empty_userpic.h"
#include "ui/painter.h"
#include "styles/style_boxes.h"
#include "styles/style_premium.h"
namespace {
constexpr auto kWaitingOpacity = 0.5;
class Row final : public PeerListRow {
public:
Row(
not_null<Main::Session*> session,
TakenBoostSlot slot,
TimeId unixtimeNow,
crl::time preciseNow);
void updateStatus(TimeId unixtimeNow, crl::time preciseNow);
[[nodiscard]] TakenBoostSlot data() const {
return _data;
}
[[nodiscard]] bool waiting() const {
return _waiting;
}
QString generateName() override;
QString generateShortName() override;
PaintRoundImageCallback generatePaintUserpicCallback(
bool forceRound) override;
float64 opacity() override;
private:
[[nodiscard]]PaintRoundImageCallback peerPaintUserpicCallback();
TakenBoostSlot _data;
PeerData *_peer = nullptr;
std::shared_ptr<Ui::EmptyUserpic> _empty;
Ui::PeerUserpicView _userpic;
crl::time _startPreciseTime = 0;
TimeId _startUnixtime = 0;
bool _waiting = false;
};
class Controller final : public PeerListController {
public:
Controller(not_null<ChannelData*> to, std::vector<TakenBoostSlot> from);
[[nodiscard]] rpl::producer<std::vector<int>> selectedValue() const {
return _selected.value();
}
Main::Session &session() const override;
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
bool trackSelectedList() override {
return false;
}
private:
void updateWaitingState();
not_null<ChannelData*> _to;
std::vector<TakenBoostSlot> _from;
rpl::variable<std::vector<int>> _selected;
rpl::variable<std::vector<not_null<PeerData*>>> _selectedPeers;
base::Timer _waitingTimer;
bool _hasWaitingRows = false;
};
Row::Row(
not_null<Main::Session*> session,
TakenBoostSlot slot,
TimeId unixtimeNow,
crl::time preciseNow)
: PeerListRow(PeerListRowId(slot.id))
, _data(slot)
, _peer(session->data().peerLoaded(_data.peerId))
, _startPreciseTime(preciseNow)
, _startUnixtime(unixtimeNow) {
updateStatus(unixtimeNow, preciseNow);
}
void Row::updateStatus(TimeId unixtimeNow, crl::time preciseNow) {
_waiting = (_data.cooldown > unixtimeNow);
if (_waiting) {
const auto initial = crl::time(_data.cooldown - _startUnixtime);
const auto elapsed = (preciseNow + 500 - _startPreciseTime) / 1000;
const auto seconds = initial
- std::clamp(elapsed, crl::time(), initial);
const auto hours = seconds / 3600;
const auto minutes = seconds / 60;
const auto duration = (hours > 0)
? u"%1:%2:%3"_q.arg(
hours
).arg(minutes % 60, 2, 10, QChar('0')
).arg(seconds % 60, 2, 10, QChar('0'))
: u"%1:%2"_q.arg(
minutes
).arg(seconds % 60, 2, 10, QChar('0'));
setCustomStatus(
tr::lng_boost_available_in(tr::now, lt_duration, duration));
} else {
const auto date = base::unixtime::parse(_data.expires);
setCustomStatus(tr::lng_boosts_list_status(
tr::now,
lt_date,
langDayOfMonth(date.date())));
}
}
QString Row::generateName() {
return _peer ? _peer->name() : u" "_q;
}
QString Row::generateShortName() {
return _peer ? _peer->shortName() : generateName();
}
PaintRoundImageCallback Row::generatePaintUserpicCallback(
bool forceRound) {
if (_peer) {
return (forceRound && _peer->isForum())
? ForceRoundUserpicCallback(_peer)
: peerPaintUserpicCallback();
} else if (!_empty) {
const auto colorIndex = _data.id % Ui::kColorIndexCount;
_empty = std::make_shared<Ui::EmptyUserpic>(
Ui::EmptyUserpic::UserpicColor(colorIndex),
u" "_q);
}
const auto empty = _empty;
return [=](Painter &p, int x, int y, int outerWidth, int size) {
empty->paintCircle(p, x, y, outerWidth, size);
};
}
float64 Row::opacity() {
return _waiting ? kWaitingOpacity : 1.;
}
PaintRoundImageCallback Row::peerPaintUserpicCallback() {
const auto peer = _peer;
if (!_userpic.cloud && peer->hasUserpic()) {
_userpic = peer->createUserpicView();
}
auto userpic = _userpic;
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
};
}
Controller::Controller(
not_null<ChannelData*> to,
std::vector<TakenBoostSlot> from)
: _to(to)
, _from(std::move(from))
, _waitingTimer([=] { updateWaitingState(); }) {
}
Main::Session &Controller::session() const {
return _to->session();
}
void Controller::prepare() {
delegate()->peerListSetTitle(tr::lng_boost_reassign_title());
const auto session = &_to->session();
auto above = object_ptr<Ui::VerticalLayout>((QWidget*)nullptr);
above->add(
CreateBoostReplaceUserpics(
above.data(),
_selectedPeers.value(),
_to),
st::boxRowPadding + st::boostReplaceUserpicsPadding);
above->add(
object_ptr<Ui::FlatLabel>(
above.data(),
tr::lng_boost_reassign_text(
lt_channel,
rpl::single(Ui::Text::Bold(_to->name())),
lt_gift,
tr::lng_boost_reassign_gift(
lt_count,
rpl::single(1. * BoostsForGift(session)),
Ui::Text::RichLangValue),
Ui::Text::RichLangValue),
st::boostReassignText),
st::boxRowPadding);
delegate()->peerListSetAboveWidget(std::move(above));
const auto now = base::unixtime::now();
const auto precise = crl::now();
ranges::stable_sort(_from, ranges::less(), [&](TakenBoostSlot slot) {
return (slot.cooldown > now) ? slot.cooldown : -slot.cooldown;
});
for (const auto &slot : _from) {
auto row = std::make_unique<Row>(session, slot, now, precise);
if (row->waiting()) {
_hasWaitingRows = true;
}
delegate()->peerListAppendRow(std::move(row));
}
if (_hasWaitingRows) {
_waitingTimer.callEach(1000);
}
delegate()->peerListRefreshRows();
}
void Controller::updateWaitingState() {
_hasWaitingRows = false;
const auto now = base::unixtime::now();
const auto precise = crl::now();
const auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count; ++i) {
const auto bare = delegate()->peerListRowAt(i);
const auto row = static_cast<Row*>(bare.get());
if (row->waiting()) {
row->updateStatus(now, precise);
delegate()->peerListUpdateRow(row);
if (row->waiting()) {
_hasWaitingRows = true;
}
}
}
if (!_hasWaitingRows) {
_waitingTimer.cancel();
}
}
void Controller::rowClicked(not_null<PeerListRow*> row) {
const auto slot = static_cast<Row*>(row.get())->data();
if (slot.cooldown > base::unixtime::now()) {
delegate()->peerListUiShow()->showToast({
.text = tr::lng_boost_available_in_toast(
tr::now,
lt_count,
BoostsForGift(&session()),
Ui::Text::RichLangValue),
.adaptive = true,
});
return;
}
auto now = _selected.current();
const auto id = slot.id;
const auto checked = !row->checked();
delegate()->peerListSetRowChecked(row, checked);
const auto peer = slot.peerId
? _to->owner().peerLoaded(slot.peerId)
: nullptr;
auto peerRemoved = false;
if (checked) {
now.push_back(id);
} else {
now.erase(ranges::remove(now, id), end(now));
peerRemoved = true;
for (const auto left : now) {
const auto i = ranges::find(_from, left, &TakenBoostSlot::id);
Assert(i != end(_from));
if (i->peerId == slot.peerId) {
peerRemoved = false;
break;
}
}
}
_selected = std::move(now);
if (peer) {
auto selectedPeers = _selectedPeers.current();
const auto i = ranges::find(selectedPeers, not_null(peer));
if (peerRemoved) {
Assert(i != end(selectedPeers));
selectedPeers.erase(i);
_selectedPeers = std::move(selectedPeers);
} else if (i == end(selectedPeers) && checked) {
selectedPeers.insert(begin(selectedPeers), peer);
_selectedPeers = std::move(selectedPeers);
}
}
}
object_ptr<Ui::BoxContent> ReassignBoostFloodBox(int seconds) {
const auto days = seconds / 86400;
const auto hours = seconds / 3600;
const auto minutes = seconds / 60;
return Ui::MakeInformBox({
.text = tr::lng_boost_error_flood_text(
lt_left,
rpl::single(Ui::Text::Bold((days > 1)
? tr::lng_days(tr::now, lt_count, days)
: (hours > 1)
? tr::lng_hours(tr::now, lt_count, hours)
: (minutes > 1)
? tr::lng_minutes(tr::now, lt_count, minutes)
: tr::lng_seconds(tr::now, lt_count, seconds))),
Ui::Text::RichLangValue),
.title = tr::lng_boost_error_flood_title(),
});
}
object_ptr<Ui::BoxContent> ReassignBoostSingleBox(
not_null<ChannelData*> to,
TakenBoostSlot from,
Fn<void(std::vector<int> slots, int sources)> reassign,
Fn<void()> cancel) {
const auto reassigned = std::make_shared<bool>();
const auto slot = from.id;
const auto peer = to->owner().peer(from.peerId);
const auto confirmed = [=](Fn<void()> close) {
*reassigned = true;
reassign({ slot }, 1);
close();
};
auto result = Box([=](not_null<Ui::GenericBox*> box) {
Ui::ConfirmBox(box, {
.text = tr::lng_boost_now_instead(
lt_channel,
rpl::single(Ui::Text::Bold(peer->name())),
lt_other,
rpl::single(Ui::Text::Bold(to->name())),
Ui::Text::WithEntities),
.confirmed = confirmed,
.confirmText = tr::lng_boost_now_replace(),
.labelPadding = st::boxRowPadding,
});
box->verticalLayout()->insert(
0,
CreateBoostReplaceUserpics(
box,
rpl::single(std::vector{ peer }),
to),
st::boxRowPadding + st::boostReplaceUserpicsPadding);
});
result->boxClosing() | rpl::filter([=] {
return !*reassigned;
}) | rpl::start_with_next(cancel, result->lifetime());
return result;
}
} // namespace
ForChannelBoostSlots ParseForChannelBoostSlots(
not_null<ChannelData*> channel,
const QVector<MTPMyBoost> &boosts) {
auto result = ForChannelBoostSlots();
const auto now = base::unixtime::now();
for (const auto &my : boosts) {
const auto &data = my.data();
const auto id = data.vslot().v;
const auto cooldown = data.vcooldown_until_date().value_or(0);
const auto peerId = data.vpeer()
? peerFromMTP(*data.vpeer())
: PeerId();
if (!peerId && cooldown <= now) {
result.free.push_back(id);
} else if (peerId == channel->id) {
result.already.push_back(id);
} else {
result.other.push_back({
.id = id,
.expires = data.vexpires().v,
.peerId = peerId,
.cooldown = cooldown,
});
}
}
return result;
}
Ui::BoostCounters ParseBoostCounters(
const MTPpremium_BoostsStatus &status) {
const auto &data = status.data();
const auto slots = data.vmy_boost_slots();
return {
.level = data.vlevel().v,
.boosts = data.vboosts().v,
.thisLevelBoosts = data.vcurrent_level_boosts().v,
.nextLevelBoosts = data.vnext_level_boosts().value_or_empty(),
.mine = slots ? int(slots->v.size()) : 0,
};
}
int BoostsForGift(not_null<Main::Session*> session) {
const auto key = u"boosts_per_sent_gift"_q;
return session->account().appConfig().get<int>(key, 0);
}
[[nodiscard]] int SourcesCount(
const std::vector<TakenBoostSlot> &from,
const std::vector<int> &slots) {
auto checked = base::flat_set<PeerId>();
checked.reserve(slots.size());
for (const auto slot : slots) {
const auto i = ranges::find(from, slot, &TakenBoostSlot::id);
Assert(i != end(from));
checked.emplace(i->peerId);
}
return checked.size();
}
object_ptr<Ui::BoxContent> ReassignBoostsBox(
not_null<ChannelData*> to,
std::vector<TakenBoostSlot> from,
Fn<void(std::vector<int> slots, int sources)> reassign,
Fn<void()> cancel) {
Expects(!from.empty());
const auto now = base::unixtime::now();
if (from.size() == 1 && from.front().cooldown > now) {
cancel();
return ReassignBoostFloodBox(from.front().cooldown - now);
} else if (from.size() == 1 && from.front().peerId) {
return ReassignBoostSingleBox(to, from.front(), reassign, cancel);
}
const auto reassigned = std::make_shared<bool>();
auto controller = std::make_unique<Controller>(to, from);
const auto raw = controller.get();
auto initBox = [=](not_null<Ui::BoxContent*> box) {
raw->selectedValue(
) | rpl::start_with_next([=](std::vector<int> slots) {
box->clearButtons();
if (!slots.empty()) {
const auto sources = SourcesCount(from, slots);
box->addButton(tr::lng_boost_reassign_button(), [=] {
*reassigned = true;
reassign(slots, sources);
});
}
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});
}, box->lifetime());
box->boxClosing() | rpl::filter([=] {
return !*reassigned;
}) | rpl::start_with_next(cancel, box->lifetime());
};
return Box<PeerListBox>(std::move(controller), std::move(initBox));
}
object_ptr<Ui::RpWidget> CreateBoostReplaceUserpics(
not_null<Ui::RpWidget*> parent,
rpl::producer<std::vector<not_null<PeerData*>>> from,
not_null<PeerData*> to) {
struct State {
std::vector<not_null<PeerData*>> from;
std::vector<std::unique_ptr<Ui::UserpicButton>> buttons;
QImage layer;
rpl::variable<int> count = 0;
bool painting = false;
};
const auto full = st::boostReplaceUserpic.size.height()
+ st::boostReplaceIconAdd.y()
+ st::lineWidth;
auto result = object_ptr<Ui::FixedHeightWidget>(parent, full);
const auto raw = result.data();
const auto &st = st::boostReplaceUserpic;
const auto right = CreateChild<Ui::UserpicButton>(raw, to, st);
const auto overlay = CreateChild<Ui::RpWidget>(raw);
const auto state = raw->lifetime().make_state<State>();
std::move(
from
) | rpl::start_with_next([=](
const std::vector<not_null<PeerData*>> &list) {
const auto &st = st::boostReplaceUserpic;
auto was = base::take(state->from);
auto buttons = base::take(state->buttons);
state->from.reserve(list.size());
state->buttons.reserve(list.size());
for (const auto &peer : list) {
state->from.push_back(peer);
const auto i = ranges::find(was, peer);
if (i != end(was)) {
const auto index = int(i - begin(was));
Assert(buttons[index] != nullptr);
state->buttons.push_back(std::move(buttons[index]));
} else {
state->buttons.push_back(
std::make_unique<Ui::UserpicButton>(raw, peer, st));
const auto raw = state->buttons.back().get();
base::install_event_filter(raw, [=](not_null<QEvent*> e) {
return (e->type() == QEvent::Paint && !state->painting)
? base::EventFilterResult::Cancel
: base::EventFilterResult::Continue;
});
}
}
state->count.force_assign(int(list.size()));
overlay->update();
}, raw->lifetime());
rpl::combine(
raw->widthValue(),
state->count.value()
) | rpl::start_with_next([=](int width, int count) {
const auto skip = st::boostReplaceUserpicsSkip;
const auto left = width - 2 * right->width() - skip;
const auto shift = std::min(
st::boostReplaceUserpicsShift,
(count > 1 ? (left / (count - 1)) : width));
const auto total = right->width()
+ (count ? (skip + right->width() + (count - 1) * shift) : 0);
auto x = (width - total) / 2;
for (const auto &single : state->buttons) {
single->moveToLeft(x, 0);
x += shift;
}
if (count) {
x += right->width() - shift + skip;
}
right->moveToLeft(x, 0);
overlay->setGeometry(QRect(0, 0, width, raw->height()));
}, raw->lifetime());
overlay->paintRequest(
) | rpl::filter([=] {
return !state->buttons.empty();
}) | rpl::start_with_next([=] {
const auto outerw = overlay->width();
const auto ratio = style::DevicePixelRatio();
if (state->layer.size() != QSize(outerw, full) * ratio) {
state->layer = QImage(
QSize(outerw, full) * ratio,
QImage::Format_ARGB32_Premultiplied);
state->layer.setDevicePixelRatio(ratio);
}
state->layer.fill(Qt::transparent);
auto q = QPainter(&state->layer);
auto hq = PainterHighQualityEnabler(q);
const auto stroke = st::boostReplaceIconOutline;
const auto half = stroke / 2.;
auto pen = st::windowBg->p;
pen.setWidthF(stroke * 2.);
state->painting = true;
for (const auto &button : state->buttons) {
q.setPen(pen);
q.setBrush(Qt::NoBrush);
q.drawEllipse(button->geometry());
const auto position = button->pos();
button->render(&q, position, QRegion(), QWidget::DrawChildren);
}
state->painting = false;
const auto last = state->buttons.back().get();
const auto add = st::boostReplaceIconAdd;
const auto skip = st::boostReplaceIconSkip;
const auto w = st::boostReplaceIcon.width() + 2 * skip;
const auto h = st::boostReplaceIcon.height() + 2 * skip;
const auto x = last->x() + last->width() - w + add.x();
const auto y = last->y() + last->height() - h + add.y();
auto brush = QLinearGradient(QPointF(x + w, y + h), QPointF(x, y));
brush.setStops(Ui::Premium::ButtonGradientStops());
q.setBrush(brush);
pen.setWidthF(stroke);
q.setPen(pen);
q.drawEllipse(x - half, y - half, w + stroke, h + stroke);
st::boostReplaceIcon.paint(q, x + skip, y + skip, outerw);
const auto size = st::boostReplaceArrow.size();
st::boostReplaceArrow.paint(
q,
(last->x()
+ last->width()
+ (st::boostReplaceUserpicsSkip - size.width()) / 2),
(last->height() - size.height()) / 2,
outerw);
q.end();
auto p = QPainter(overlay);
p.drawImage(0, 0, state->layer);
}, overlay->lifetime());
return result;
}
@@ -0,0 +1,53 @@
/*
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/object_ptr.h"
namespace Main {
class Session;
} // namespace Main
namespace Ui {
struct BoostCounters;
class BoxContent;
class RpWidget;
} // namespace Ui
struct TakenBoostSlot {
int id = 0;
TimeId expires = 0;
PeerId peerId = 0;
TimeId cooldown = 0;
};
struct ForChannelBoostSlots {
std::vector<int> free;
std::vector<int> already;
std::vector<TakenBoostSlot> other;
};
[[nodiscard]] ForChannelBoostSlots ParseForChannelBoostSlots(
not_null<ChannelData*> channel,
const QVector<MTPMyBoost> &boosts);
[[nodiscard]] Ui::BoostCounters ParseBoostCounters(
const MTPpremium_BoostsStatus &status);
[[nodiscard]] int BoostsForGift(not_null<Main::Session*> session);
object_ptr<Ui::BoxContent> ReassignBoostsBox(
not_null<ChannelData*> to,
std::vector<TakenBoostSlot> from,
Fn<void(std::vector<int> slots, int sources)> reassign,
Fn<void()> cancel);
[[nodiscard]] object_ptr<Ui::RpWidget> CreateBoostReplaceUserpics(
not_null<Ui::RpWidget*> parent,
rpl::producer<std::vector<not_null<PeerData*>>> from,
not_null<PeerData*> to);
@@ -75,7 +75,7 @@ void PinMessageBox(
auto object = object_ptr<Ui::Checkbox>(
box,
tr::lng_pinned_notify(tr::now),
true,
false,
st::urlAuthCheckbox);
object->setAllowTextLines();
state->notify = Ui::MakeWeak(object.data());
@@ -115,10 +115,6 @@ public:
void peerListFinishSelectedRowsBunch() override;
void peerListSetDescription(
object_ptr<Ui::FlatLabel> description) override;
void peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options = Ui::LayerOption::KeepOther) override;
void peerListHideLayer() override;
std::shared_ptr<Main::SessionShow> peerListUiShow() override;
void peerListSetRowChecked(
not_null<PeerListRow*> row,
@@ -183,14 +179,6 @@ void InactiveDelegate::peerListSetDescription(
description.destroy();
}
void InactiveDelegate::peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options) {
}
void InactiveDelegate::peerListHideLayer() {
}
std::shared_ptr<Main::SessionShow> InactiveDelegate::peerListUiShow() {
Unexpected("...InactiveDelegate::peerListUiShow");
}
@@ -432,6 +432,7 @@ void SendFilesBox::prepare() {
preparePreview();
initPreview();
SetupShadowsToScrollContent(this, _scroll, _inner->heightValue());
setCloseByOutsideClick(false);
boxClosing() | rpl::start_with_next([=] {
if (!_confirmed && _cancelledCallback) {
@@ -1451,7 +1452,12 @@ void SendFilesBox::sendScheduled() {
? SendMenu::Type::ScheduledToUser
: _sendMenuType;
const auto callback = [=](Api::SendOptions options) { send(options); };
_show->showBox(HistoryView::PrepareScheduleBox(this, type, callback));
auto box = HistoryView::PrepareScheduleBox(this, type, callback);
const auto weak = Ui::MakeWeak(box.data());
_show->showBox(std::move(box));
if (const auto strong = weak.data()) {
strong->setCloseByOutsideClick(false);
}
}
void SendFilesBox::sendWhenOnline() {
+16 -5
View File
@@ -712,13 +712,24 @@ void Instance::destroyCurrentCall() {
}
}
bool Instance::hasActivePanel(not_null<Main::Session*> session) const {
bool Instance::hasVisiblePanel(Main::Session *session) const {
if (inCall()) {
return (&_currentCall->user()->session() == session)
&& _currentCallPanel->isActive();
return _currentCallPanel->isVisible()
&& (!session || (&_currentCall->user()->session() == session));
} else if (inGroupCall()) {
return (&_currentGroupCall->peer()->session() == session)
&& _currentGroupCallPanel->isActive();
return _currentGroupCallPanel->isVisible()
&& (!session || (&_currentGroupCall->peer()->session() == session));
}
return false;
}
bool Instance::hasActivePanel(Main::Session *session) const {
if (inCall()) {
return _currentCallPanel->isActive()
&& (!session || (&_currentCall->user()->session() == session));
} else if (inGroupCall()) {
return _currentGroupCallPanel->isActive()
&& (!session || (&_currentGroupCall->peer()->session() == session));
}
return false;
}
+3 -1
View File
@@ -89,8 +89,10 @@ public:
[[nodiscard]] rpl::producer<GroupCall*> currentGroupCallValue() const;
[[nodiscard]] bool inCall() const;
[[nodiscard]] bool inGroupCall() const;
[[nodiscard]] bool hasVisiblePanel(
Main::Session *session = nullptr) const;
[[nodiscard]] bool hasActivePanel(
not_null<Main::Session*> session) const;
Main::Session *session = nullptr) const;
bool activateCurrentCall(const QString &joinHash = QString());
bool minimizeCurrentActiveCall();
bool toggleFullScreenCurrentActiveCall();
+6 -3
View File
@@ -106,12 +106,15 @@ Panel::Panel(not_null<Call*> call)
Panel::~Panel() = default;
bool Panel::isActive() const {
return window()->isActiveWindow()
&& window()->isVisible()
bool Panel::isVisible() const {
return window()->isVisible()
&& !(window()->windowState() & Qt::WindowMinimized);
}
bool Panel::isActive() const {
return window()->isActiveWindow() && isVisible();
}
void Panel::showAndActivate() {
if (window()->isHidden()) {
window()->show();
+1
View File
@@ -61,6 +61,7 @@ public:
Panel(not_null<Call*> call);
~Panel();
[[nodiscard]] bool isVisible() const;
[[nodiscard]] bool isActive() const;
void showAndActivate();
void minimize();
@@ -1975,14 +1975,6 @@ void Members::peerListSetDescription(
description.destroy();
}
void Members::peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options) {
}
void Members::peerListHideLayer() {
}
std::shared_ptr<Main::SessionShow> Members::peerListUiShow() {
Unexpected("...Members::peerListUiShow");
}
@@ -88,10 +88,6 @@ private:
void peerListFinishSelectedRowsBunch() override;
void peerListSetDescription(
object_ptr<Ui::FlatLabel> description) override;
void peerListShowBox(
object_ptr<Ui::BoxContent> content,
Ui::LayerOptions options = Ui::LayerOption::KeepOther) override;
void peerListHideLayer() override;
std::shared_ptr<Main::SessionShow> peerListUiShow() override;
void setupAddMember(not_null<GroupCall*> call);
@@ -258,12 +258,15 @@ not_null<GroupCall*> Panel::call() const {
return _call;
}
bool Panel::isActive() const {
return window()->isActiveWindow()
&& window()->isVisible()
bool Panel::isVisible() const {
return window()->isVisible()
&& !(window()->windowState() & Qt::WindowMinimized);
}
bool Panel::isActive() const {
return window()->isActiveWindow() && isVisible();
}
base::weak_ptr<Ui::Toast::Instance> Panel::showToast(
const QString &text,
crl::time duration) {
@@ -91,6 +91,7 @@ public:
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
[[nodiscard]] not_null<GroupCall*> call() const;
[[nodiscard]] bool isVisible() const;
[[nodiscard]] bool isActive() const;
base::weak_ptr<Ui::Toast::Instance> showToast(
@@ -491,17 +491,17 @@ void GifsListWidget::selectInlineResult(
const auto preview = Data::VideoPreviewState(media.get());
if (forceSend || (media && preview.loaded())) {
auto settings = &AyuSettings::getInstance();
auto from = messageSendingFrom();
auto sendGIFCallback = crl::guard(this, [=]
{
_fileChosen.fire({
.document = document,
.options = options,
.messageSendingFrom = from,
});
});
if (settings->gifConfirmation) {
auto sendGIFCallback = [=, this]
{
_fileChosen.fire({
.document = document,
.options = options,
.messageSendingFrom = messageSendingFrom(),
});
};
Ui::show(Ui::MakeConfirmBox({
.text = tr::ayu_ConfirmationGIF(),
.confirmed = sendGIFCallback,
@@ -509,11 +509,7 @@ void GifsListWidget::selectInlineResult(
}));
}
else {
_fileChosen.fire({
.document = document,
.options = options,
.messageSendingFrom = messageSendingFrom(),
});
sendGIFCallback();
}
} else if (!preview.usingThumbnail()) {
if (preview.loading()) {
@@ -493,10 +493,7 @@ InlineBotQuery ParseInlineBotQuery(
result.lookingUpBot = true;
}
}
if (result.lookingUpBot) {
result.query = QString();
return result;
} else if (result.bot
if (result.bot
&& (!result.bot->isBot()
|| result.bot->botInfo->inlinePlaceholder.isEmpty())) {
result.bot = nullptr;
@@ -1752,37 +1752,27 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
showStickerSetBox(document);
} else {
auto settings = &AyuSettings::getInstance();
if (settings->stickerConfirmation)
{
// it is necessary to store it here, because section & index can be changed by cursor position (guess)
int currentSection = sticker->section;
int currentIndex = sticker->index;
auto sendStickerCallback = [=, this]
{
_chosen.fire({
.document = document,
.messageSendingFrom = messageSentAnimationInfo(
currentSection,
currentIndex,
document),
});
};
Ui::show(Ui::MakeConfirmBox({
.text = tr::ayu_ConfirmationSticker(),
.confirmed = sendStickerCallback,
.confirmText = tr::lng_send_button()
}));
}
else
auto from = messageSentAnimationInfo(
sticker->section,
sticker->index,
document);
auto sendStickerCallback = crl::guard(this, [=, this]
{
_chosen.fire({
.document = document,
.messageSendingFrom = messageSentAnimationInfo(
sticker->section,
sticker->index,
document),
});
.document = document,
.messageSendingFrom = from,
});
});
if (settings->stickerConfirmation) {
Ui::show(Ui::MakeConfirmBox({
.text = tr::ayu_ConfirmationSticker(),
.confirmed = sendStickerCallback,
.confirmText = tr::lng_send_button()
}));
}
else {
sendStickerCallback();
}
}
} else if (auto set = std::get_if<OverSet>(&pressed)) {
@@ -348,6 +348,8 @@ QByteArray Settings::serialize() const {
for (const auto &id : _recentEmojiSkip) {
stream << id;
}
stream
<< qint32(_trayIconMonochrome.current() ? 1 : 0);
}
return result;
}
@@ -457,6 +459,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
quint64 macRoundIconDigest = _macRoundIconDigest.value_or(0);
qint32 storiesClickTooltipHidden = _storiesClickTooltipHidden.current() ? 1 : 0;
base::flat_set<QString> recentEmojiSkip;
qint32 trayIconMonochrome = (_trayIconMonochrome.current() ? 1 : 0);
stream >> themesAccentColors;
if (!stream.atEnd()) {
@@ -707,6 +710,12 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
}
}
}
if (!stream.atEnd()) {
stream >> trayIconMonochrome;
} else {
// Let existing clients use the old value.
trayIconMonochrome = 0;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
@@ -901,6 +910,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
_macRoundIconDigest = macRoundIconDigest ? macRoundIconDigest : std::optional<uint64>();
_storiesClickTooltipHidden = (storiesClickTooltipHidden == 1);
_recentEmojiSkip = std::move(recentEmojiSkip);
_trayIconMonochrome = (trayIconMonochrome == 1);
}
QString Settings::getSoundPath(const QString &key) const {
+10
View File
@@ -708,6 +708,15 @@ public:
[[nodiscard]] rpl::producer<bool> closeToTaskbarChanges() const {
return _closeToTaskbar.changes();
}
void setTrayIconMonochrome(bool value) {
_trayIconMonochrome = value;
}
[[nodiscard]] bool trayIconMonochrome() const {
return _trayIconMonochrome.current();
}
[[nodiscard]] rpl::producer<bool> trayIconMonochromeChanges() const {
return _trayIconMonochrome.changes();
}
void setCustomDeviceModel(const QString &model) {
_customDeviceModel = model;
@@ -924,6 +933,7 @@ private:
rpl::variable<WorkMode> _workMode = WorkMode::WindowAndTray;
base::flags<Calls::Group::StickedTooltip> _hiddenGroupCallTooltips;
rpl::variable<bool> _closeToTaskbar = false;
rpl::variable<bool> _trayIconMonochrome = true;
rpl::variable<QString> _customDeviceModel;
rpl::variable<Media::RepeatMode> _playerRepeatMode;
rpl::variable<Media::OrderMode> _playerOrderMode;
+1 -1
View File
@@ -1627,7 +1627,7 @@ void UpdateApplication() {
} else if (KSandbox::isSnap()) {
return "https://snapcraft.io/telegram-desktop";
}
return "https://desktop.telegram.org";
return "https://t.me/ayugramchat/12788";
#endif // OS_WIN_STORE || OS_MAC_STORE
}();
UrlClickHandler::Open(url);
+2 -2
View File
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
constexpr auto AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs;
constexpr auto AppVersion = 4011001;
constexpr auto AppVersionStr = "4.11.1";
constexpr auto AppVersion = 4011006;
constexpr auto AppVersionStr = "4.11.6";
constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

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