Compare commits
490 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dab107cf90 | ||
|
|
d1d1aa3d21 | ||
|
|
d0536cc31f | ||
|
|
c47f5e9995 | ||
|
|
0916836ff9 | ||
|
|
5dd9ff1062 | ||
|
|
d1e3b9f15d | ||
|
|
ca3c179b75 | ||
|
|
c2d5924508 | ||
|
|
016d0395c3 | ||
|
|
925c9239bd | ||
|
|
fdcbe3cf3a | ||
|
|
f6b9cc5ce1 | ||
|
|
8c915e6dc3 | ||
|
|
1db426da2e | ||
|
|
d9be363962 | ||
|
|
88daa37e34 | ||
|
|
931fa01337 | ||
|
|
8e1595eb29 | ||
|
|
29e97232d8 | ||
|
|
f05191e668 | ||
|
|
1ba189e59d | ||
|
|
c40ca70aa6 | ||
|
|
521f991167 | ||
|
|
edf1417bbb | ||
|
|
686e9643ad | ||
|
|
975460d268 | ||
|
|
6b0c606d25 | ||
|
|
93ff0bdcff | ||
|
|
bf9d90ca4e | ||
|
|
d6e5e1e8f7 | ||
|
|
d3ae2ef9ea | ||
|
|
40b0854704 | ||
|
|
9aec6b6496 | ||
|
|
d01f977960 | ||
|
|
1444009ee2 | ||
|
|
14ee9bee26 | ||
|
|
93587ddc3c | ||
|
|
0c4d03477e | ||
|
|
a35092f012 | ||
|
|
49ee7ee52b | ||
|
|
52c77a1970 | ||
|
|
e4269ae7fb | ||
|
|
bd6011c524 | ||
|
|
46cb3ec103 | ||
|
|
0241129948 | ||
|
|
e44aca06cb | ||
|
|
19d386f977 | ||
|
|
a67fdda913 | ||
|
|
5286c7b1c3 | ||
|
|
d9d96d0a6f | ||
|
|
13353bb615 | ||
|
|
d78348fd16 | ||
|
|
1e8e660133 | ||
|
|
5196982c98 | ||
|
|
99f857fbf6 | ||
|
|
0982aa166a | ||
|
|
3ae9f86097 | ||
|
|
9efd9b0d68 | ||
|
|
267a73f355 | ||
|
|
437d8ea890 | ||
|
|
7ed92ec402 | ||
|
|
678d9ffbf9 | ||
|
|
bc4b427ed1 | ||
|
|
36141a9df9 | ||
|
|
d68ba75457 | ||
|
|
00ad32c5f4 | ||
|
|
064bab60ff | ||
|
|
5b146217c0 | ||
|
|
202c81b2e5 | ||
|
|
4520480604 | ||
|
|
aea87bb5cb | ||
|
|
19492f7e7b | ||
|
|
51030e3c45 | ||
|
|
e6b8b4be18 | ||
|
|
6ac13b7f80 | ||
|
|
7e5e6003a9 | ||
|
|
f445440995 | ||
|
|
d81547f091 | ||
|
|
2b185d491b | ||
|
|
ca47440950 | ||
|
|
5e32602f4a | ||
|
|
1f4516028c | ||
|
|
7f29d269a3 | ||
|
|
62c3374911 | ||
|
|
2116e04af5 | ||
|
|
a97d5e80c7 | ||
|
|
b5098038d0 | ||
|
|
6fce718252 | ||
|
|
40cf96202d | ||
|
|
c18e59218e | ||
|
|
216865a20d | ||
|
|
6c5036ee8d | ||
|
|
dc2f59ca24 | ||
|
|
6f6457137e | ||
|
|
bc5cb6e2a2 | ||
|
|
16825fff41 | ||
|
|
5024f1db8c | ||
|
|
a60385fc3d | ||
|
|
b20e2c37c1 | ||
|
|
acd40cbeb6 | ||
|
|
6a45a862dd | ||
|
|
5bd45e9a20 | ||
|
|
52e42f23ab | ||
|
|
96b7755cde | ||
|
|
c589ee1ca5 | ||
|
|
18c9ee093b | ||
|
|
b82fa3112c | ||
|
|
8d0f66d562 | ||
|
|
20a5e0ba73 | ||
|
|
5a2667c71e | ||
|
|
1f4a8d7eb6 | ||
|
|
4430bd0328 | ||
|
|
ab2e7f4c03 | ||
|
|
54e5c06b4d | ||
|
|
add5a6a0be | ||
|
|
89c2ba4293 | ||
|
|
dd100fb709 | ||
|
|
e8dd2b9e7b | ||
|
|
71e3cd227c | ||
|
|
1648c31a22 | ||
|
|
f8c820f319 | ||
|
|
300f35e78f | ||
|
|
2aa5849997 | ||
|
|
fb1b845211 | ||
|
|
3d2af9db8e | ||
|
|
6129e5a1cf | ||
|
|
7f70ee1227 | ||
|
|
c9f7da6e82 | ||
|
|
f956c0f227 | ||
|
|
df935e0477 | ||
|
|
841f1afe1e | ||
|
|
fb8b88557e | ||
|
|
2b502b22b9 | ||
|
|
5ac80d2655 | ||
|
|
8aa7499e63 | ||
|
|
8cd5e51982 | ||
|
|
e5c2133446 | ||
|
|
3dccdf2f05 | ||
|
|
8a708c6655 | ||
|
|
9e1d9eee4b | ||
|
|
f30aabc365 | ||
|
|
a5546d016f | ||
|
|
f79d70d112 | ||
|
|
ec28f258fb | ||
|
|
08f3a6fb40 | ||
|
|
8823d5256f | ||
|
|
60e7aa90d2 | ||
|
|
71357a9546 | ||
|
|
a5b06e9c56 | ||
|
|
0f94419f6d | ||
|
|
94e7aabea5 | ||
|
|
f6c816cafe | ||
|
|
4cf160e8dc | ||
|
|
9252be5e8c | ||
|
|
ed342eea64 | ||
|
|
e6405bc455 | ||
|
|
fed09461ce | ||
|
|
6e1ddef4fe | ||
|
|
76be4a3eb9 | ||
|
|
997a9e2fe3 | ||
|
|
03790f3da0 | ||
|
|
e46a703c7d | ||
|
|
ae17acdfd4 | ||
|
|
2422c9ce9e | ||
|
|
7f75d7082a | ||
|
|
4749ab175e | ||
|
|
e651699e1d | ||
|
|
3f4157bab2 | ||
|
|
a98f559066 | ||
|
|
ffd54c452c | ||
|
|
61424eeab9 | ||
|
|
c131d6637d | ||
|
|
24b0b33f1d | ||
|
|
675198d361 | ||
|
|
ed667a42ad | ||
|
|
920484d540 | ||
|
|
07c5e6542b | ||
|
|
6a43f2e508 | ||
|
|
ad3e447f08 | ||
|
|
1840da1d68 | ||
|
|
c82b86cea3 | ||
|
|
0fb383c466 | ||
|
|
69fc2f48bf | ||
|
|
7c604fc86a | ||
|
|
ec7fbb8952 | ||
|
|
679350e23d | ||
|
|
f0209c9d6e | ||
|
|
5020aec6ec | ||
|
|
13737577e7 | ||
|
|
4ee7d46d78 | ||
|
|
d143e32022 | ||
|
|
0a0dab74a1 | ||
|
|
c6ea91e671 | ||
|
|
8011adb219 | ||
|
|
6ba5d5f16b | ||
|
|
d5774830d8 | ||
|
|
eb268102fc | ||
|
|
b364c4f23a | ||
|
|
91b9266a91 | ||
|
|
1e6236a987 | ||
|
|
10ebd7e6ef | ||
|
|
6b83c52c7c | ||
|
|
46304c7a2d | ||
|
|
c3fda41224 | ||
|
|
a4017e930e | ||
|
|
95bdb925d5 | ||
|
|
a26bae70c7 | ||
|
|
a38dcb6ee5 | ||
|
|
eb27c12117 | ||
|
|
c03fcf9a23 | ||
|
|
71f83b5993 | ||
|
|
fd2d12d6b1 | ||
|
|
50f9f36c3d | ||
|
|
f650c679e0 | ||
|
|
8349cb0dd4 | ||
|
|
2c1788a63a | ||
|
|
eec59611ef | ||
|
|
bfbdf1b935 | ||
|
|
f2ea0edc95 | ||
|
|
754b3a5ae8 | ||
|
|
62a20ba975 | ||
|
|
f3dca6efb7 | ||
|
|
dc1df14a71 | ||
|
|
73c018667d | ||
|
|
3905fc7c38 | ||
|
|
0c3cabf4ac | ||
|
|
838d5669ed | ||
|
|
3a7a485dd0 | ||
|
|
a4ac00acbd | ||
|
|
7d52c13625 | ||
|
|
520de600a0 | ||
|
|
4f8e914d53 | ||
|
|
79c8c5ec5d | ||
|
|
3548aba652 | ||
|
|
5d1812efc8 | ||
|
|
0477d43fbb | ||
|
|
73609fe5b2 | ||
|
|
e027196c8a | ||
|
|
6d00165e5a | ||
|
|
693eaf9262 | ||
|
|
3549349ffb | ||
|
|
fac20e436d | ||
|
|
63f0feaf04 | ||
|
|
3001464f6b | ||
|
|
eec9c8a46b | ||
|
|
80b3754be1 | ||
|
|
6d61caea4e | ||
|
|
b9de12fedb | ||
|
|
074dbf41e0 | ||
|
|
e51b2c0c91 | ||
|
|
e4538947c3 | ||
|
|
624e068f2f | ||
|
|
30077133d4 | ||
|
|
b0fece2fd0 | ||
|
|
5f8c007a0c | ||
|
|
a2785867b2 | ||
|
|
9ea495f59d | ||
|
|
24a7e48b75 | ||
|
|
7ef44fb621 | ||
|
|
0a1ddddd81 | ||
|
|
284f1a5210 | ||
|
|
37283a7a35 | ||
|
|
7f4b540aad | ||
|
|
83f4c53766 | ||
|
|
155f4ea252 | ||
|
|
f6c071bd18 | ||
|
|
56959398e2 | ||
|
|
d34d3a796d | ||
|
|
dca61541d6 | ||
|
|
81a79e2895 | ||
|
|
d6541d777f | ||
|
|
457301493f | ||
|
|
4f7364b798 | ||
|
|
32e8ed93e2 | ||
|
|
4760337958 | ||
|
|
f2f85a9083 | ||
|
|
70d5dd8b71 | ||
|
|
ec93a91db2 | ||
|
|
cc3baad377 | ||
|
|
d1313f38eb | ||
|
|
49e6c4f552 | ||
|
|
fb252bb644 | ||
|
|
78e09f2605 | ||
|
|
ba4c521d7a | ||
|
|
92f70a0ebb | ||
|
|
a13f0cb11e | ||
|
|
617ad38a68 | ||
|
|
fb66c85567 | ||
|
|
05fa2c381a | ||
|
|
ae18b4c851 | ||
|
|
7ed715b01c | ||
|
|
8158c52e82 | ||
|
|
44c1109798 | ||
|
|
ba6bbf54e6 | ||
|
|
75b26b1a85 | ||
|
|
c8a3b0ab80 | ||
|
|
52a199a362 | ||
|
|
e89f2b55e8 | ||
|
|
ac92e1c99e | ||
|
|
02610de010 | ||
|
|
273e041935 | ||
|
|
474c0838d1 | ||
|
|
afe30da9f4 | ||
|
|
9bb1fa8782 | ||
|
|
bb3fc17489 | ||
|
|
126fd89bb7 | ||
|
|
fb8f3ad26c | ||
|
|
cedf161e44 | ||
|
|
89dc18aaea | ||
|
|
ba99706e75 | ||
|
|
efc8417ab1 | ||
|
|
c4f45c4b7c | ||
|
|
c985b77a48 | ||
|
|
6148fb9474 | ||
|
|
fe86f5d050 | ||
|
|
916926bfa6 | ||
|
|
9eb15f7b17 | ||
|
|
2d1b1fbd44 | ||
|
|
1301c42afa | ||
|
|
0de5080874 | ||
|
|
a982560a62 | ||
|
|
4a5d8046d5 | ||
|
|
65a14bcab4 | ||
|
|
e9bb6f65e3 | ||
|
|
74f7fa80b7 | ||
|
|
2ff0ed50be | ||
|
|
281ad01b85 | ||
|
|
4864a6996f | ||
|
|
0af3028cd6 | ||
|
|
11c91c1a42 | ||
|
|
7f3dc27aa9 | ||
|
|
51fc104c60 | ||
|
|
6b96466c5e | ||
|
|
7c1510b611 | ||
|
|
993c0ee648 | ||
|
|
503c3c7b00 | ||
|
|
b7c14f17a7 | ||
|
|
0b6bd7075a | ||
|
|
148690d8b1 | ||
|
|
a422aec99a | ||
|
|
813d0501da | ||
|
|
db80096e6b | ||
|
|
cf896aeb13 | ||
|
|
76314e3c03 | ||
|
|
8959679b3c | ||
|
|
bb6c94ef4f | ||
|
|
fb9ce6d3a8 | ||
|
|
dac4389e37 | ||
|
|
a25b2e9700 | ||
|
|
699a7bdc58 | ||
|
|
4108debca0 | ||
|
|
8b2bbfba6a | ||
|
|
4f37343e8b | ||
|
|
2dcf40817e | ||
|
|
3eeb01be61 | ||
|
|
6a8a85e395 | ||
|
|
031233ea98 | ||
|
|
4b09050061 | ||
|
|
992c876930 | ||
|
|
a5ffd8b7cf | ||
|
|
5fdd4eba80 | ||
|
|
54ce85f8e6 | ||
|
|
0bfb0fd045 | ||
|
|
8ad2d3d39a | ||
|
|
b8a19b56b6 | ||
|
|
24b93a5eff | ||
|
|
127f651d5e | ||
|
|
e760a0983f | ||
|
|
3f2cb8f8c9 | ||
|
|
bcb6e9e1af | ||
|
|
847d66c973 | ||
|
|
5c797d1f31 | ||
|
|
f749616dd8 | ||
|
|
3cc92e01fe | ||
|
|
06f2b23687 | ||
|
|
6a167b33f5 | ||
|
|
850155b3be | ||
|
|
358e586801 | ||
|
|
54214ff2ad | ||
|
|
06fc813e95 | ||
|
|
0046bae53f | ||
|
|
aeb5e57061 | ||
|
|
a32b781e49 | ||
|
|
caef698e54 | ||
|
|
e9650385ad | ||
|
|
f55584b160 | ||
|
|
b0981ea8e3 | ||
|
|
a141d01a23 | ||
|
|
6a000207ee | ||
|
|
ee6edf9caa | ||
|
|
37907636e6 | ||
|
|
3f0f3a3c11 | ||
|
|
db0856f71c | ||
|
|
86cdda2277 | ||
|
|
3888e8084a | ||
|
|
517b456670 | ||
|
|
77d6e19214 | ||
|
|
fb64452495 | ||
|
|
24fabf2590 | ||
|
|
9b2847a11d | ||
|
|
c18e8fd777 | ||
|
|
f4afa762d8 | ||
|
|
5e1fb6ebbf | ||
|
|
2c7922ce7b | ||
|
|
ac78ae823c | ||
|
|
1ef6f462f6 | ||
|
|
c81f406759 | ||
|
|
889ec0c731 | ||
|
|
677fbdd84e | ||
|
|
1ebe3255e0 | ||
|
|
c70866a995 | ||
|
|
fd982b90db | ||
|
|
9461095c88 | ||
|
|
a2fa1a52e2 | ||
|
|
a847969e9c | ||
|
|
4d647e64b7 | ||
|
|
f8b756d447 | ||
|
|
484c647b5b | ||
|
|
730c968b1e | ||
|
|
8a6a749296 | ||
|
|
2f22a8f46b | ||
|
|
f123a9e16c | ||
|
|
11c45b0342 | ||
|
|
2cd6bfef06 | ||
|
|
61ca619db4 | ||
|
|
675ee9088f | ||
|
|
28a6aa45b9 | ||
|
|
08ec9e6bfd | ||
|
|
ee9f99a754 | ||
|
|
2412183b83 | ||
|
|
e83704982f | ||
|
|
6f86acf712 | ||
|
|
c22698084f | ||
|
|
8c55364afa | ||
|
|
2c3ef13b01 | ||
|
|
03454ca3b4 | ||
|
|
8a92c89f39 | ||
|
|
b83b403b75 | ||
|
|
8aac07b3c0 | ||
|
|
b4dfc25df5 | ||
|
|
917d1841c1 | ||
|
|
8ce10d5503 | ||
|
|
a130bb1be6 | ||
|
|
de52ac6b28 | ||
|
|
310837c9e1 | ||
|
|
8e6d7bb190 | ||
|
|
025ab40687 | ||
|
|
2a5071b66c | ||
|
|
2a63496054 | ||
|
|
a52d4eb4e8 | ||
|
|
4f7a124f3e | ||
|
|
4b9eb37bd5 | ||
|
|
1d5e4040f4 | ||
|
|
6818b8d8dc | ||
|
|
3f0b962ae5 | ||
|
|
8ac1ad3484 | ||
|
|
c6e1cf639e | ||
|
|
5b9278eced | ||
|
|
03d4dd00d4 | ||
|
|
f7d698b9ff | ||
|
|
46b69a938b | ||
|
|
ebba58217c | ||
|
|
94ad8f9bc3 | ||
|
|
6effac7915 | ||
|
|
78093173a9 | ||
|
|
a01d48f063 | ||
|
|
149c69c9f5 | ||
|
|
df277b366b | ||
|
|
f20475f07e | ||
|
|
b6664625ea | ||
|
|
1028219276 | ||
|
|
219671a3bc | ||
|
|
8c97e915ec | ||
|
|
b648548001 | ||
|
|
b377c02ad3 | ||
|
|
66d6b461f3 | ||
|
|
054a6db3ae | ||
|
|
bf7042df44 | ||
|
|
aa140b2919 | ||
|
|
8d0d9bb0bd | ||
|
|
9ca9904732 | ||
|
|
e6e1b9446d | ||
|
|
a507d28b49 | ||
|
|
ec2faca145 | ||
|
|
17bb430006 | ||
|
|
8cbeadc68a | ||
|
|
3947056654 | ||
|
|
ad7d1fddf0 | ||
|
|
ab20f8eb31 |
4
.github/workflows/mac_packaged.yml
vendored
@@ -69,7 +69,7 @@ jobs:
|
||||
run: |
|
||||
brew update
|
||||
brew upgrade || true
|
||||
brew install autoconf automake boost cmake ffmpeg@6 openal-soft openssl opus ninja pkg-config python qt yasm xz
|
||||
brew install ada-url autoconf automake boost cmake ffmpeg@6 openal-soft openh264 openssl opus ninja pkg-config python qt yasm xz
|
||||
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
||||
|
||||
xcodebuild -version > CACHE_KEY.txt
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone --recursive --depth=1 $GIT/desktop-app/tg_owt.git
|
||||
git clone --depth=1 --recursive --shallow-submodules $GIT/desktop-app/tg_owt.git
|
||||
cd tg_owt
|
||||
|
||||
cmake -B build . -GNinja -DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
2
.github/workflows/win.yml
vendored
@@ -169,6 +169,8 @@ jobs:
|
||||
%TDESKTOP_BUILD_GENERATOR% ^
|
||||
%TDESKTOP_BUILD_ARCH% ^
|
||||
%TDESKTOP_BUILD_API% ^
|
||||
-D CMAKE_C_FLAGS="/WX" ^
|
||||
-D CMAKE_CXX_FLAGS="/WX" ^
|
||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF ^
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF ^
|
||||
-D DESKTOP_APP_NO_PDB=ON ^
|
||||
|
||||
@@ -37,6 +37,10 @@ include(cmake/td_scheme.cmake)
|
||||
include(cmake/td_ui.cmake)
|
||||
include(cmake/generate_appdata_changelog.cmake)
|
||||
|
||||
if (DESKTOP_APP_TEST_APPS)
|
||||
include(cmake/tests.cmake)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
include(cmake/generate_midl.cmake)
|
||||
generate_midl(Telegram ${src_loc}
|
||||
@@ -272,6 +276,8 @@ PRIVATE
|
||||
boxes/edit_caption_box.h
|
||||
boxes/edit_privacy_box.cpp
|
||||
boxes/edit_privacy_box.h
|
||||
boxes/gift_credits_box.cpp
|
||||
boxes/gift_credits_box.h
|
||||
boxes/gift_premium_box.cpp
|
||||
boxes/gift_premium_box.h
|
||||
boxes/language_box.cpp
|
||||
@@ -308,6 +314,8 @@ PRIVATE
|
||||
boxes/self_destruction_box.h
|
||||
boxes/send_credits_box.cpp
|
||||
boxes/send_credits_box.h
|
||||
boxes/send_gif_with_caption_box.cpp
|
||||
boxes/send_gif_with_caption_box.h
|
||||
boxes/send_files_box.cpp
|
||||
boxes/send_files_box.h
|
||||
boxes/sessions_box.cpp
|
||||
@@ -473,8 +481,12 @@ PRIVATE
|
||||
data/business/data_business_info.h
|
||||
data/business/data_shortcut_messages.cpp
|
||||
data/business/data_shortcut_messages.h
|
||||
data/components/credits.cpp
|
||||
data/components/credits.h
|
||||
data/components/factchecks.cpp
|
||||
data/components/factchecks.h
|
||||
data/components/location_pickers.cpp
|
||||
data/components/location_pickers.h
|
||||
data/components/recent_peers.cpp
|
||||
data/components/recent_peers.h
|
||||
data/components/scheduled_messages.cpp
|
||||
@@ -820,6 +832,8 @@ PRIVATE
|
||||
history/view/history_view_message.cpp
|
||||
history/view/history_view_message.h
|
||||
history/view/history_view_object.h
|
||||
history/view/history_view_paid_reaction_toast.cpp
|
||||
history/view/history_view_paid_reaction_toast.h
|
||||
history/view/history_view_pinned_bar.cpp
|
||||
history/view/history_view_pinned_bar.h
|
||||
history/view/history_view_pinned_section.cpp
|
||||
@@ -1232,6 +1246,8 @@ PRIVATE
|
||||
payments/payments_form.h
|
||||
payments/payments_non_panel_process.cpp
|
||||
payments/payments_non_panel_process.h
|
||||
payments/payments_reaction_process.cpp
|
||||
payments/payments_reaction_process.h
|
||||
platform/linux/file_utilities_linux.cpp
|
||||
platform/linux/file_utilities_linux.h
|
||||
platform/linux/launcher_linux.cpp
|
||||
@@ -1464,6 +1480,10 @@ PRIVATE
|
||||
support/support_preload.h
|
||||
support/support_templates.cpp
|
||||
support/support_templates.h
|
||||
ui/boxes/edit_invite_link_session.cpp
|
||||
ui/boxes/edit_invite_link_session.h
|
||||
ui/boxes/peer_qr_box.cpp
|
||||
ui/boxes/peer_qr_box.h
|
||||
ui/chat/attach/attach_item_single_file_preview.cpp
|
||||
ui/chat/attach/attach_item_single_file_preview.h
|
||||
ui/chat/attach/attach_item_single_media_preview.cpp
|
||||
@@ -1472,6 +1492,10 @@ PRIVATE
|
||||
ui/chat/choose_send_as.h
|
||||
ui/chat/choose_theme_controller.cpp
|
||||
ui/chat/choose_theme_controller.h
|
||||
ui/controls/emoji_button_factory.cpp
|
||||
ui/controls/emoji_button_factory.h
|
||||
ui/controls/location_picker.cpp
|
||||
ui/controls/location_picker.h
|
||||
ui/controls/silent_toggle.cpp
|
||||
ui/controls/silent_toggle.h
|
||||
ui/controls/userpic_button.cpp
|
||||
@@ -1493,6 +1517,12 @@ PRIVATE
|
||||
ui/image/image_location.h
|
||||
ui/image/image_location_factory.cpp
|
||||
ui/image/image_location_factory.h
|
||||
ui/text/format_song_document_name.cpp
|
||||
ui/text/format_song_document_name.h
|
||||
ui/widgets/expandable_peer_list.cpp
|
||||
ui/widgets/expandable_peer_list.h
|
||||
ui/widgets/label_with_custom_emoji.cpp
|
||||
ui/widgets/label_with_custom_emoji.h
|
||||
ui/countryinput.cpp
|
||||
ui/countryinput.h
|
||||
ui/dynamic_thumbnails.cpp
|
||||
@@ -1506,10 +1536,6 @@ PRIVATE
|
||||
ui/resize_area.h
|
||||
ui/search_field_controller.cpp
|
||||
ui/search_field_controller.h
|
||||
ui/text/format_song_document_name.cpp
|
||||
ui/text/format_song_document_name.h
|
||||
ui/widgets/label_with_custom_emoji.cpp
|
||||
ui/widgets/label_with_custom_emoji.h
|
||||
ui/unread_badge.cpp
|
||||
ui/unread_badge.h
|
||||
window/main_window.cpp
|
||||
@@ -1614,6 +1640,7 @@ PRIVATE
|
||||
qrc/telegram/animations.qrc
|
||||
qrc/telegram/export.qrc
|
||||
qrc/telegram/iv.qrc
|
||||
qrc/telegram/picker.qrc
|
||||
qrc/telegram/telegram.qrc
|
||||
qrc/telegram/sounds.qrc
|
||||
winrc/Telegram.rc
|
||||
@@ -1813,7 +1840,7 @@ endif()
|
||||
|
||||
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
|
||||
|
||||
if (WIN32)
|
||||
if (WIN32 AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
delayimp
|
||||
@@ -1844,9 +1871,14 @@ if (WIN32)
|
||||
/DELAYLOAD:propsys.dll
|
||||
)
|
||||
if (QT_VERSION GREATER 6)
|
||||
if (NOT build_winarm)
|
||||
target_link_options(Telegram PRIVATE
|
||||
/DELAYLOAD:API-MS-Win-EventLog-Legacy-l1-1-0.dll
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_options(Telegram
|
||||
PRIVATE
|
||||
/DELAYLOAD:API-MS-Win-EventLog-Legacy-l1-1-0.dll
|
||||
/DELAYLOAD:API-MS-Win-Core-Console-l1-1-0.dll
|
||||
/DELAYLOAD:API-MS-Win-Core-Fibers-l2-1-0.dll
|
||||
/DELAYLOAD:API-MS-Win-Core-Fibers-l2-1-1.dll
|
||||
@@ -1863,7 +1895,7 @@ if (WIN32)
|
||||
/DELAYLOAD:API-MS-Win-Core-WinRT-Error-l1-1-0.dll
|
||||
/DELAYLOAD:API-MS-Win-Core-WinRT-String-l1-1-0.dll
|
||||
/DELAYLOAD:API-MS-Win-Security-CryptoAPI-l1-1-0.dll
|
||||
/DELAYLOAD:API-MS-Win-Shcore-Scaling-l1-1-1.dll
|
||||
# /DELAYLOAD:API-MS-Win-Shcore-Scaling-l1-1-1.dll # We shadowed GetDpiForMonitor
|
||||
/DELAYLOAD:authz.dll # Authz.lib
|
||||
/DELAYLOAD:comdlg32.dll
|
||||
/DELAYLOAD:dwrite.dll # DWrite.lib
|
||||
@@ -1905,7 +1937,7 @@ if (NOT DESKTOP_APP_DISABLE_AUTOUPDATE AND NOT build_macstore AND NOT build_wins
|
||||
base/platform/win/base_windows_safe_library.h
|
||||
)
|
||||
target_include_directories(Updater PRIVATE ${lib_base_loc})
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
target_link_libraries(Updater
|
||||
PRIVATE
|
||||
delayimp
|
||||
|
||||
BIN
Telegram/Resources/animations/star_reaction/appear.tgs
Normal file
BIN
Telegram/Resources/animations/star_reaction/center.tgs
Normal file
BIN
Telegram/Resources/animations/star_reaction/effect1.tgs
Normal file
BIN
Telegram/Resources/animations/star_reaction/effect2.tgs
Normal file
BIN
Telegram/Resources/animations/star_reaction/effect3.tgs
Normal file
BIN
Telegram/Resources/animations/star_reaction/select.tgs
Normal file
BIN
Telegram/Resources/animations/star_reaction/toast.tgs
Normal file
BIN
Telegram/Resources/animations/stats_boosts.tgs
Normal file
BIN
Telegram/Resources/animations/stats_earn.tgs
Normal file
|
Before Width: | Height: | Size: 214 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 426 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 912 B After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/calls/mini_calls_arrow.png
Normal file
|
After Width: | Height: | Size: 240 B |
BIN
Telegram/Resources/icons/calls/mini_calls_arrow@2x.png
Normal file
|
After Width: | Height: | Size: 324 B |
BIN
Telegram/Resources/icons/calls/mini_calls_arrow@3x.png
Normal file
|
After Width: | Height: | Size: 422 B |
BIN
Telegram/Resources/icons/chat/filled_location.png
Normal file
|
After Width: | Height: | Size: 536 B |
BIN
Telegram/Resources/icons/chat/filled_location@2x.png
Normal file
|
After Width: | Height: | Size: 987 B |
BIN
Telegram/Resources/icons/chat/filled_location@3x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/chat/mini_stars.png
Normal file
|
After Width: | Height: | Size: 349 B |
BIN
Telegram/Resources/icons/chat/mini_stars@2x.png
Normal file
|
After Width: | Height: | Size: 565 B |
BIN
Telegram/Resources/icons/chat/mini_stars@3x.png
Normal file
|
After Width: | Height: | Size: 740 B |
36
Telegram/Resources/icons/info/edit/links_subscription.svg
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="72px" height="72px" viewBox="0 0 72 72" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>General / menu_incomes</title>
|
||||
<defs>
|
||||
<rect id="path-1" x="0" y="0" width="72" height="37"></rect>
|
||||
<rect id="path-3" x="0" y="0" width="72" height="42"></rect>
|
||||
</defs>
|
||||
<g id="General-/-menu_incomes" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group-2">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<g id="Rectangle"></g>
|
||||
<g id="Group" mask="url(#mask-2)" stroke="#FFFFFF" stroke-linecap="round" stroke-width="5.4">
|
||||
<g transform="translate(35.056529, 35.872413) rotate(66.000000) translate(-35.056529, -35.872413) translate(5.056529, 5.872413)" id="Path">
|
||||
<path d="M7.74068421e-14,27 C7.74068421e-14,27.6514434 0.0207638485,31.2980371 0.0616658298,31.9391554 C1.06104802,47.603977 14.0829009,60 30,60 C46.5685425,60 60,46.5685425 60,30 C60,13.4314575 46.5685425,-1.34265911e-13 30,-1.34265911e-13 C20.9122281,-1.34265911e-13 12.7682399,4.04081874 7.26674545,10.4237463" transform="translate(30.000000, 30.000000) rotate(90.000000) translate(-30.000000, -30.000000) "></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-2-Copy" transform="translate(0.000000, 28.000000)">
|
||||
<mask id="mask-4" fill="white">
|
||||
<use xlink:href="#path-3"></use>
|
||||
</mask>
|
||||
<g id="Rectangle"></g>
|
||||
<g id="Group" mask="url(#mask-4)" stroke="#FFFFFF" stroke-dasharray="5,14" stroke-linecap="round" stroke-width="5.4">
|
||||
<g transform="translate(35.056529, 7.872413) rotate(66.000000) translate(-35.056529, -7.872413) translate(-2.745677, -29.929792)" id="Path">
|
||||
<path d="M7.80220532,34.8022053 C7.80220532,35.4536487 7.82296917,39.1002424 7.86387115,39.7413607 C8.86325334,55.4061823 21.8851062,67.8022053 37.8022053,67.8022053 C54.3707478,67.8022053 67.8022053,54.3707478 67.8022053,37.8022053 C67.8022053,21.2336628 54.3707478,7.80220532 37.8022053,7.80220532 C28.7144334,7.80220532 20.5704452,11.8430241 15.0689508,18.2259516" transform="translate(37.802205, 37.802205) rotate(72.000000) translate(-37.802205, -37.802205) "></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="$" transform="translate(23.000000, 16.000000)" fill="#FFFFFF" fill-rule="nonzero">
|
||||
<path d="M12.034384,39.8 C13.0659026,39.8 14.182808,39.2321492 14.182808,37.869307 L14.182808,35.752184 C20.3489971,35.093477 24,31.5046593 24,26.280431 C24,21.7830518 21.2722063,19.0573675 15.6103152,17.8308096 L10.9570201,16.7859639 C8.04584527,16.1499709 6.62464183,14.8325568 6.62464183,12.9018637 C6.62464183,10.585032 8.64183381,8.90419336 11.8051576,8.90419336 C14.3724928,8.90419336 16.1604585,9.76732673 18.1547278,11.9705882 C19.1633238,13.0154339 19.9426934,13.4015725 20.9971347,13.4015725 C22.2808023,13.4015725 23.2664756,12.5157251 23.2664756,11.198311 C23.2664756,9.92632499 22.5100287,8.54076878 21.226361,7.2914968 C19.530086,5.70151427 17.1653295,4.65666861 14.3,4.29324403 L14.3,1.907979 C14.3,0.56785087 13.2034384,0 12.1489971,0 C11.1174785,0 10,0.545136833 10,1.907979 L10,4.22510192 C4.06303725,4.77023879 0.481375358,8.29091439 0.481375358,13.3334304 C0.481375358,17.7399534 3.20916905,20.6700641 8.43553009,21.8284799 L13.0888252,22.8960396 C16.4813754,23.6910309 17.8796562,24.8721607 17.8796562,26.8709959 C17.8796562,29.460396 15.8395415,31.0958066 12.1948424,31.0958066 C9.46704871,31.0958066 7.19770774,30.073675 5.13467049,27.8704135 C3.96561605,26.7119977 3.32378223,26.4621433 2.45272206,26.4621433 C1.05444126,26.4621433 0,27.3479907 0,28.8698311 C0,30.2099592 0.779369628,31.5955154 2.17765043,32.7993593 C4.01146132,34.457484 6.67679058,35.4796156 9.863037,35.7748981 L9.863037,37.869307 C9.863037,39.2321492 10.9799427,39.8 12.034384,39.8 Z" id="Path"></path>
|
||||
</g>
|
||||
<path d="M66.2217021,28.4347599 L72.4528242,38.8199633 C72.7823745,39.3692138 72.6042723,40.0816225 72.0550218,40.4111728 C71.8747737,40.5193217 71.668522,40.5764501 71.4583183,40.5764501 L57.5551143,40.5764501 C56.9145837,40.5764501 56.3953311,40.0571975 56.3953311,39.4166669 C56.3953311,39.2064632 56.4524595,39.0002115 56.5606084,38.8199633 L62.7917304,28.4347599 C63.3600268,27.4875994 64.5885473,27.1804692 65.5357078,27.7487655 C65.817207,27.9176651 66.0528026,28.1532607 66.2217021,28.4347599 Z" id="Triangle" fill="#FFFFFF" transform="translate(64.506716, 33.076450) rotate(168.000000) translate(-64.506716, -33.076450) "></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
1
Telegram/Resources/icons/plane_white.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="1000px" height="1000px" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg"><g id="Artboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><path d="M226.328419,494.722069 C372.088573,431.216685 469.284839,389.350049 517.917216,369.122161 C656.772535,311.36743 685.625481,301.334815 704.431427,301.003532 C708.567621,300.93067 717.815839,301.955743 723.806446,306.816707 C728.864797,310.92121 730.256552,316.46581 730.922551,320.357329 C731.588551,324.248848 732.417879,333.113828 731.758626,340.040666 C724.234007,419.102486 691.675104,610.964674 675.110982,699.515267 C668.10208,736.984342 654.301336,749.547532 640.940618,750.777006 C611.904684,753.448938 589.856115,731.588035 561.733393,713.153237 C517.726886,684.306416 492.866009,666.349181 450.150074,638.200013 C400.78442,605.66878 432.786119,587.789048 460.919462,558.568563 C468.282091,550.921423 596.21508,434.556479 598.691227,424.000355 C599.00091,422.680135 599.288312,417.758981 596.36474,415.160431 C593.441168,412.561881 589.126229,413.450484 586.012448,414.157198 C581.598758,415.158943 511.297793,461.625274 375.109553,553.556189 C355.154858,567.258623 337.080515,573.934908 320.886524,573.585046 C303.033948,573.199351 268.692754,563.490928 243.163606,555.192408 C211.851067,545.013936 186.964484,539.632504 189.131547,522.346309 C190.260287,513.342589 202.659244,504.134509 226.328419,494.722069 Z" id="Path-3" fill="#FFFFFF"></path></g></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/qr_mini.png
Normal file
|
After Width: | Height: | Size: 641 B |
BIN
Telegram/Resources/icons/qr_mini@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/qr_mini@3x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 771 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
@@ -618,9 +618,6 @@ var IV = {
|
||||
element.getAnimations().forEach(
|
||||
(animation) => animation.finish());
|
||||
},
|
||||
back: function () {
|
||||
window.history.back();
|
||||
},
|
||||
menuShown: function (shown) {
|
||||
var already = document.getElementById('menu_page_blocker');
|
||||
if (already && shown) {
|
||||
|
||||
@@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"cloud_lng_forwarded_psa_covid" = "COVID-19 Notification from {channel}";
|
||||
"cloud_lng_tooltip_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. Learn more about this initiative at https://telegram.org/blog/coronavirus";
|
||||
|
||||
"cloud_lng_topup_purpose_subs" = "Buy **Stars** to keep your channel subscriptions.";
|
||||
|
||||
"cloud_lng_passport_in_ar" = "Arabic";
|
||||
"cloud_lng_passport_in_az" = "Azerbaijani";
|
||||
"cloud_lng_passport_in_bg" = "Bulgarian";
|
||||
|
||||
120
Telegram/Resources/picker_html/picker.css
Normal file
@@ -0,0 +1,120 @@
|
||||
:root {
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, avenir next, avenir, Segoe UI Variable Text, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, tahoma, arial, sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-sans);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: var(--td-window-bg);
|
||||
color: var(--td-window-fg);
|
||||
}
|
||||
|
||||
html.custom_scroll ::-webkit-scrollbar {
|
||||
border-radius: 5px !important;
|
||||
border: 3px solid transparent !important;
|
||||
background-color: var(--td-scroll-bg) !important;
|
||||
background-clip: content-box !important;
|
||||
width: 10px !important;
|
||||
}
|
||||
html.custom_scroll ::-webkit-scrollbar:hover {
|
||||
background-color: var(--td-scroll-bg-over) !important;
|
||||
}
|
||||
html.custom_scroll ::-webkit-scrollbar-thumb {
|
||||
border-radius: 5px !important;
|
||||
border: 3px solid transparent !important;
|
||||
background-color: var(--td-scroll-bar-bg) !important;
|
||||
background-clip: content-box !important;
|
||||
}
|
||||
html.custom_scroll ::-webkit-scrollbar-thumb:hover {
|
||||
background-color: var(--td-scroll-bar-bg-over) !important;
|
||||
}
|
||||
|
||||
#map {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#marker {
|
||||
pointer-events: none;
|
||||
display: none;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
#marker_drop {
|
||||
margin-bottom: 0px;
|
||||
transition: margin 160ms ease-in-out;
|
||||
}
|
||||
#marker_drop.moving {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
#marker_shadow {
|
||||
position: absolute;
|
||||
}
|
||||
#search_venues {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 2;
|
||||
top: -30px;
|
||||
transition: top 200ms ease-in-out;
|
||||
}
|
||||
#search_venues.shown {
|
||||
top: 6px;
|
||||
}
|
||||
#search_venues_inner {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
background: var(--td-window-bg);
|
||||
color: var(--td-window-active-text-fg);
|
||||
cursor: pointer;
|
||||
border-radius: 14px;
|
||||
padding: 5px 12px 6px;
|
||||
box-shadow: 0 0 3px 0px var(--td-history-to-down-shadow);
|
||||
}
|
||||
#search_venues_inner:hover {
|
||||
background: var(--td-window-bg-over);
|
||||
}
|
||||
#search_venues_content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
#search_venues_content:before {
|
||||
content: var(--td-lng-maps-places-in-area);
|
||||
}
|
||||
#search_venues_inner .ripple .inner {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
transform: scale(0);
|
||||
opacity: 1;
|
||||
animation: ripple 650ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
||||
background-color: var(--td-window-bg-ripple);
|
||||
}
|
||||
#search_venues_inner .ripple.hiding {
|
||||
animation: fadeOut 200ms linear forwards;
|
||||
}
|
||||
@keyframes ripple {
|
||||
to {
|
||||
transform: scale(2);
|
||||
}
|
||||
}
|
||||
@keyframes fadeOut {
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
199
Telegram/Resources/picker_html/picker.js
Normal file
@@ -0,0 +1,199 @@
|
||||
var LocationPicker = {
|
||||
startZoom: 14,
|
||||
flySpeed: 2.4,
|
||||
notify: function(message) {
|
||||
if (window.external && window.external.invoke) {
|
||||
window.external.invoke(JSON.stringify(message));
|
||||
}
|
||||
},
|
||||
frameKeyDown: function (e) {
|
||||
const keyW = (e.key === 'w')
|
||||
|| (e.code === 'KeyW')
|
||||
|| (e.keyCode === 87);
|
||||
const keyQ = (e.key === 'q')
|
||||
|| (e.code === 'KeyQ')
|
||||
|| (e.keyCode === 81);
|
||||
const keyM = (e.key === 'm')
|
||||
|| (e.code === 'KeyM')
|
||||
|| (e.keyCode === 77);
|
||||
if ((e.metaKey || e.ctrlKey) && (keyW || keyQ || keyM)) {
|
||||
e.preventDefault();
|
||||
LocationPicker.notify({
|
||||
event: 'keydown',
|
||||
modifier: e.ctrlKey ? 'ctrl' : 'cmd',
|
||||
key: keyW ? 'w' : keyQ ? 'q' : 'm',
|
||||
});
|
||||
} else if (e.key === 'Escape' || e.keyCode === 27) {
|
||||
e.preventDefault();
|
||||
LocationPicker.notify({
|
||||
event: 'keydown',
|
||||
key: 'escape',
|
||||
});
|
||||
}
|
||||
},
|
||||
isNight: function() {
|
||||
var html = document.getElementsByTagName('html')[0];
|
||||
return html.style.getPropertyValue('--td-night') == '1';
|
||||
},
|
||||
lightPreset: function() {
|
||||
return LocationPicker.isNight() ? 'night' : 'day';
|
||||
},
|
||||
updateStyles: function (styles) {
|
||||
if (LocationPicker.styles !== styles) {
|
||||
LocationPicker.styles = styles;
|
||||
document.getElementsByTagName('html')[0].style = styles;
|
||||
|
||||
LocationPicker.map.setConfigProperty(
|
||||
'basemap',
|
||||
'lightPreset',
|
||||
LocationPicker.lightPreset());
|
||||
}
|
||||
},
|
||||
init: function (params) {
|
||||
mapboxgl.accessToken = params.token;
|
||||
if (params.protocol) {
|
||||
mapboxgl.config.API_URL = params.protocol + '://domain/api.mapbox.com';
|
||||
}
|
||||
|
||||
var options = { container: 'map', config: {
|
||||
basemap: { lightPreset: LocationPicker.lightPreset() }
|
||||
} };
|
||||
var center = params.center;
|
||||
if (center) {
|
||||
center = [center[1], center[0]];
|
||||
options.center = center;
|
||||
options.zoom = LocationPicker.startZoom;
|
||||
} else if (params.bounds) {
|
||||
options.bounds = params.bounds;
|
||||
center = new mapboxgl.LngLatBounds(params.bounds).getCenter();
|
||||
} else {
|
||||
center = [0, 0];
|
||||
}
|
||||
LocationPicker.map = new mapboxgl.Map(options);
|
||||
LocationPicker.createMarker(center);
|
||||
LocationPicker.trackMovement();
|
||||
LocationPicker.initSearchVenueRipple();
|
||||
},
|
||||
marker: function() {
|
||||
return document.getElementById('marker_drop');
|
||||
},
|
||||
createMarker: function(center) {
|
||||
document.getElementById('marker').style.display = 'flex';
|
||||
},
|
||||
clearMovingTimer: function() {
|
||||
if (LocationPicker.clearMovingTimeoutId) {
|
||||
clearTimeout(LocationPicker.clearMovingTimeoutId);
|
||||
LocationPicker.clearMovingTimeoutId = 0;
|
||||
}
|
||||
},
|
||||
startMovingTimer: function(done) {
|
||||
LocationPicker.clearMovingTimer();
|
||||
LocationPicker.clearMovingTimeoutId = setTimeout(done, 500);
|
||||
},
|
||||
trackMovement: function() {
|
||||
LocationPicker.map.on('movestart', function() {
|
||||
LocationPicker.marker().classList.add('moving');
|
||||
LocationPicker.clearMovingTimer();
|
||||
LocationPicker.toggleSearchVenues(false);
|
||||
LocationPicker.notify({ event: 'move_start' });
|
||||
});
|
||||
LocationPicker.map.on('moveend', function() {
|
||||
LocationPicker.startMovingTimer(function() {
|
||||
LocationPicker.marker().classList.remove('moving');
|
||||
LocationPicker.notify({
|
||||
event: 'move_end',
|
||||
latitude: LocationPicker.map.getCenter().lat,
|
||||
longitude: LocationPicker.map.getCenter().lng
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
narrowTo: function (point) {
|
||||
LocationPicker.map.flyTo({
|
||||
center: [point[1], point[0]],
|
||||
zoom: LocationPicker.startZoom,
|
||||
speed: LocationPicker.flySpeed,
|
||||
});
|
||||
},
|
||||
send: function () {
|
||||
LocationPicker.notify({
|
||||
event: 'send',
|
||||
latitude: LocationPicker.map.getCenter().lat,
|
||||
longitude: LocationPicker.map.getCenter().lng
|
||||
});
|
||||
},
|
||||
addRipple: function (button, x, y) {
|
||||
const ripple = document.createElement('span');
|
||||
ripple.classList.add('ripple');
|
||||
|
||||
const inner = document.createElement('span');
|
||||
inner.classList.add('inner');
|
||||
|
||||
var rect = button.getBoundingClientRect();
|
||||
x -= rect.x;
|
||||
y -= rect.y;
|
||||
|
||||
const mx = button.clientWidth - x;
|
||||
const my = button.clientHeight - y;
|
||||
const sq1 = x * x + y * y;
|
||||
const sq2 = mx * mx + y * y;
|
||||
const sq3 = x * x + my * my;
|
||||
const sq4 = mx * mx + my * my;
|
||||
const radius = Math.sqrt(Math.max(sq1, sq2, sq3, sq4));
|
||||
|
||||
inner.style.width = inner.style.height = `${2 * radius}px`;
|
||||
inner.style.left = `${x - radius}px`;
|
||||
inner.style.top = `${y - radius}px`;
|
||||
inner.classList.add('inner');
|
||||
|
||||
ripple.addEventListener('animationend', function (e) {
|
||||
if (e.animationName === 'fadeOut') {
|
||||
ripple.remove();
|
||||
}
|
||||
});
|
||||
|
||||
ripple.appendChild(inner);
|
||||
button.appendChild(ripple);
|
||||
},
|
||||
stopRipples: function (button) {
|
||||
const id = button.id ? button.id : button;
|
||||
button = document.getElementById(id);
|
||||
const ripples = button.getElementsByClassName('ripple');
|
||||
for (var i = 0; i < ripples.length; ++i) {
|
||||
const ripple = ripples[i];
|
||||
if (!ripple.classList.contains('hiding')) {
|
||||
ripple.classList.add('hiding');
|
||||
}
|
||||
}
|
||||
},
|
||||
initSearchVenueRipple: function() {
|
||||
var button = document.getElementById('search_venues_inner');
|
||||
button.addEventListener('mousedown', function (e) {
|
||||
LocationPicker.addRipple(e.currentTarget, e.clientX, e.clientY);
|
||||
LocationPicker.searchVenuesPressed = true;
|
||||
});
|
||||
button.addEventListener('mouseup', function (e) {
|
||||
const id = e.currentTarget.id;
|
||||
setTimeout(function () {
|
||||
LocationPicker.stopRipples(id);
|
||||
}, 0);
|
||||
if (LocationPicker.searchVenuesPressed) {
|
||||
LocationPicker.searchVenuesPressed = false;
|
||||
LocationPicker.toggleSearchVenues(false);
|
||||
LocationPicker.notify({
|
||||
event: 'search_venues',
|
||||
latitude: LocationPicker.map.getCenter().lat,
|
||||
longitude: LocationPicker.map.getCenter().lng
|
||||
});
|
||||
}
|
||||
});
|
||||
button.addEventListener('mouseleave', function (e) {
|
||||
LocationPicker.stopRipples(e.currentTarget);
|
||||
LocationPicker.searchVenuesPressed = false;
|
||||
});
|
||||
},
|
||||
toggleSearchVenues: function(shown) {
|
||||
var button = document.getElementById('search_venues');
|
||||
button.classList.toggle('shown', shown);
|
||||
},
|
||||
};
|
||||
@@ -11,20 +11,41 @@
|
||||
<file alias="ttl.tgs">../../animations/ttl.tgs</file>
|
||||
<file alias="discussion.tgs">../../animations/discussion.tgs</file>
|
||||
<file alias="stats.tgs">../../animations/stats.tgs</file>
|
||||
<file alias="stats_boosts.tgs">../../animations/stats_boosts.tgs</file>
|
||||
<file alias="stats_earn.tgs">../../animations/stats_earn.tgs</file>
|
||||
<file alias="voice_ttl_idle.tgs">../../animations/voice_ttl_idle.tgs</file>
|
||||
<file alias="voice_ttl_start.tgs">../../animations/voice_ttl_start.tgs</file>
|
||||
<file alias="palette.tgs">../../animations/palette.tgs</file>
|
||||
<file alias="sleep.tgs">../../animations/sleep.tgs</file>
|
||||
<file alias="greeting.tgs">../../animations/greeting.tgs</file>
|
||||
<file alias="location.tgs">../../animations/location.tgs</file>
|
||||
<file alias="robot.tgs">../../animations/robot.tgs</file>
|
||||
<file alias="writing.tgs">../../animations/writing.tgs</file>
|
||||
<file alias="hours.tgs">../../animations/hours.tgs</file>
|
||||
<file alias="phone.tgs">../../animations/phone.tgs</file>
|
||||
<file alias="greeting.tgs">../../animations/greeting.tgs</file>
|
||||
<file alias="location.tgs">../../animations/location.tgs</file>
|
||||
<file alias="robot.tgs">../../animations/robot.tgs</file>
|
||||
<file alias="writing.tgs">../../animations/writing.tgs</file>
|
||||
<file alias="hours.tgs">../../animations/hours.tgs</file>
|
||||
<file alias="phone.tgs">../../animations/phone.tgs</file>
|
||||
<file alias="chat_link.tgs">../../animations/chat_link.tgs</file>
|
||||
<file alias="collectible_username.tgs">../../animations/collectible_username.tgs</file>
|
||||
<file alias="collectible_phone.tgs">../../animations/collectible_phone.tgs</file>
|
||||
<file alias="search.tgs">../../animations/search.tgs</file>
|
||||
<file alias="noresults.tgs">../../animations/noresults.tgs</file>
|
||||
|
||||
<file alias="dice_idle.tgs">../../animations/dice/dice_idle.tgs</file>
|
||||
<file alias="dart_idle.tgs">../../animations/dice/dart_idle.tgs</file>
|
||||
<file alias="bball_idle.tgs">../../animations/dice/bball_idle.tgs</file>
|
||||
<file alias="fball_idle.tgs">../../animations/dice/fball_idle.tgs</file>
|
||||
<file alias="slot_0_idle.tgs">../../animations/dice/slot_0_idle.tgs</file>
|
||||
<file alias="slot_1_idle.tgs">../../animations/dice/slot_1_idle.tgs</file>
|
||||
<file alias="slot_2_idle.tgs">../../animations/dice/slot_2_idle.tgs</file>
|
||||
<file alias="slot_back.tgs">../../animations/dice/slot_back.tgs</file>
|
||||
<file alias="slot_pull.tgs">../../animations/dice/slot_pull.tgs</file>
|
||||
<file alias="winners.tgs">../../animations/dice/winners.tgs</file>
|
||||
|
||||
<file alias="star_reaction_appear.tgs">../../animations/star_reaction/appear.tgs</file>
|
||||
<file alias="star_reaction_center.tgs">../../animations/star_reaction/center.tgs</file>
|
||||
<file alias="star_reaction_select.tgs">../../animations/star_reaction/select.tgs</file>
|
||||
<file alias="star_reaction_toast.tgs">../../animations/star_reaction/toast.tgs</file>
|
||||
<file alias="star_reaction_effect1.tgs">../../animations/star_reaction/effect1.tgs</file>
|
||||
<file alias="star_reaction_effect2.tgs">../../animations/star_reaction/effect2.tgs</file>
|
||||
<file alias="star_reaction_effect3.tgs">../../animations/star_reaction/effect3.tgs</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
6
Telegram/Resources/qrc/telegram/picker.qrc
Normal file
@@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/picker">
|
||||
<file alias="picker.css">../../picker_html/picker.css</file>
|
||||
<file alias="picker.js">../../picker_html/picker.js</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -7,16 +7,6 @@
|
||||
<file alias="art/logo_256.png">../../art/logo_256.png</file>
|
||||
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
|
||||
<file alias="art/themeimage.jpg">../../art/themeimage.jpg</file>
|
||||
<file alias="art/dice_idle.tgs">../../art/dice_idle.tgs</file>
|
||||
<file alias="art/dart_idle.tgs">../../art/dart_idle.tgs</file>
|
||||
<file alias="art/bball_idle.tgs">../../art/bball_idle.tgs</file>
|
||||
<file alias="art/fball_idle.tgs">../../art/fball_idle.tgs</file>
|
||||
<file alias="art/slot_0_idle.tgs">../../art/slot_0_idle.tgs</file>
|
||||
<file alias="art/slot_1_idle.tgs">../../art/slot_1_idle.tgs</file>
|
||||
<file alias="art/slot_2_idle.tgs">../../art/slot_2_idle.tgs</file>
|
||||
<file alias="art/slot_back.tgs">../../art/slot_back.tgs</file>
|
||||
<file alias="art/slot_pull.tgs">../../art/slot_pull.tgs</file>
|
||||
<file alias="art/winners.tgs">../../art/winners.tgs</file>
|
||||
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
|
||||
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
|
||||
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
|
||||
@@ -40,6 +30,8 @@
|
||||
<file alias="topic_icons/red.svg">../../art/topic_icons/red.svg</file>
|
||||
<file alias="topic_icons/gray.svg">../../art/topic_icons/gray.svg</file>
|
||||
<file alias="topic_icons/general.svg">../../art/topic_icons/general.svg</file>
|
||||
<file alias="links_subscription.svg">../../icons/info/edit/links_subscription.svg</file>
|
||||
<file alias="plane_white.svg">../../icons/plane_white.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/icons">
|
||||
<file alias="calls/hands.lottie">../../icons/calls/hands.lottie</file>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="5.2.1.0" />
|
||||
Version="5.5.3.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
@@ -38,6 +38,9 @@
|
||||
<uap3:Extension Category="windows.protocol">
|
||||
<uap3:Protocol Name="tg" Parameters="-- "%1"" />
|
||||
</uap3:Extension>
|
||||
<uap3:Extension Category="windows.protocol">
|
||||
<uap3:Protocol Name="tonsite" Parameters="-- "%1"" />
|
||||
</uap3:Extension>
|
||||
<desktop:Extension
|
||||
Category="windows.startupTask"
|
||||
Executable="StartupTask.exe"
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,2,1,0
|
||||
PRODUCTVERSION 5,2,1,0
|
||||
FILEVERSION 5,5,3,0
|
||||
PRODUCTVERSION 5,5,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "5.2.1.0"
|
||||
VALUE "FileVersion", "5.5.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "5.2.1.0"
|
||||
VALUE "ProductVersion", "5.5.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,2,1,0
|
||||
PRODUCTVERSION 5,2,1,0
|
||||
FILEVERSION 5,5,3,0
|
||||
PRODUCTVERSION 5,5,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "5.2.1.0"
|
||||
VALUE "FileVersion", "5.5.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "5.2.1.0"
|
||||
VALUE "ProductVersion", "5.5.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -155,6 +155,7 @@ int main(int argc, char *argv[])
|
||||
QString remove;
|
||||
int version = 0;
|
||||
[[maybe_unused]] bool targetwin64 = false;
|
||||
[[maybe_unused]] bool targetwinarm = false;
|
||||
[[maybe_unused]] bool targetarmac = false;
|
||||
QFileInfoList files;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
@@ -165,6 +166,7 @@ int main(int argc, char *argv[])
|
||||
if (remove.isEmpty()) remove = info.canonicalPath() + "/";
|
||||
} else if (string("-target") == argv[i] && i + 1 < argc) {
|
||||
targetwin64 = (string("win64") == argv[i + 1]);
|
||||
targetwinarm = (string("winarm") == argv[i + 1]);
|
||||
} else if (string("-arch") == argv[i] && i + 1 < argc) {
|
||||
targetarmac = (string("arm64") == argv[i + 1]);
|
||||
if (!targetarmac && string("x86_64") != argv[i + 1]) {
|
||||
@@ -493,7 +495,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Signature verified!\n";
|
||||
RSA_free(pbKey);
|
||||
#ifdef Q_OS_WIN
|
||||
QString outName((targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version));
|
||||
QString outName((targetwinarm ? QString("tarm64upd%1") : targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version));
|
||||
#elif defined Q_OS_MAC
|
||||
QString outName((targetarmac ? QString("tarmacupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version));
|
||||
#else
|
||||
|
||||
@@ -571,8 +571,8 @@ void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) {
|
||||
}
|
||||
if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) {
|
||||
WCHAR wstrPath[maxFileLen];
|
||||
DWORD wstrPathLen;
|
||||
if (wstrPathLen = GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) {
|
||||
DWORD wstrPathLen = GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen);
|
||||
if (wstrPathLen) {
|
||||
wsprintf(wstrPath + wstrPathLen, L"\\%s\\", _programName);
|
||||
hDumpFile = _generateDumpFileAtPath(wstrPath);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/url_auth_box.h"
|
||||
#include "boxes/peers/choose_peer_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "chat_helpers/bot_command.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "data/data_changes.h"
|
||||
@@ -127,11 +128,7 @@ void SendBotCallbackData(
|
||||
UrlClickHandler::Open(link);
|
||||
return;
|
||||
}
|
||||
const auto scoreLink = AppendShareGameScoreUrl(
|
||||
session,
|
||||
link,
|
||||
item->fullId());
|
||||
BotGameUrlClickHandler(bot, scoreLink).onClick({
|
||||
BotGameUrlClickHandler(bot, link).onClick({
|
||||
Qt::LeftButton,
|
||||
QVariant::fromValue(ClickHandlerContext{
|
||||
.itemId = item->fullId(),
|
||||
@@ -492,20 +489,23 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
||||
|
||||
case ButtonType::WebView: {
|
||||
if (const auto bot = item->getMessageBot()) {
|
||||
bot->session().attachWebView().request(
|
||||
controller,
|
||||
Api::SendAction(bot->owner().history(bot)),
|
||||
bot,
|
||||
{ .text = button->text, .url = button->data });
|
||||
bot->session().attachWebView().open({
|
||||
.bot = bot,
|
||||
.context = { .controller = controller },
|
||||
.button = { .text = button->text, .url = button->data },
|
||||
.source = InlineBots::WebViewSourceButton{ .simple = false },
|
||||
});
|
||||
}
|
||||
} break;
|
||||
|
||||
case ButtonType::SimpleWebView: {
|
||||
if (const auto bot = item->getMessageBot()) {
|
||||
bot->session().attachWebView().requestSimple(
|
||||
controller,
|
||||
bot,
|
||||
{ .text = button->text, .url = button->data });
|
||||
bot->session().attachWebView().open({
|
||||
.bot = bot,
|
||||
.context = { .controller = controller },
|
||||
.button = {.text = button->text, .url = button->data },
|
||||
.source = InlineBots::WebViewSourceButton{ .simple = true },
|
||||
});
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_filter_icons.h"
|
||||
#include "styles/style_layers.h"
|
||||
@@ -231,12 +232,12 @@ void ImportInvite(
|
||||
api->request(MTPchatlists_JoinChatlistInvite(
|
||||
MTP_string(slug),
|
||||
MTP_vector<MTPInputPeer>(std::move(inputs))
|
||||
)).done(callback).fail(error).send();
|
||||
)).done(callback).fail(error).handleFloodErrors().send();
|
||||
} else {
|
||||
api->request(MTPchatlists_JoinChatlistUpdates(
|
||||
MTP_inputChatlistDialogFilter(MTP_int(filterId)),
|
||||
MTP_vector<MTPInputPeer>(std::move(inputs))
|
||||
)).done(callback).fail(error).send();
|
||||
)).done(callback).fail(error).handleFloodErrors().send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,6 +517,8 @@ void ShowImportError(
|
||||
} else {
|
||||
window->showToast((error == u"INVITE_SLUG_EXPIRED"_q)
|
||||
? tr::lng_group_invite_bad_link(tr::now)
|
||||
: error.startsWith(u"FLOOD_WAIT_"_q)
|
||||
? tr::lng_flood_error(tr::now)
|
||||
: error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,26 +8,39 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_chat_invite.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "core/application.h"
|
||||
#include "data/components/credits.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "info/channel_statistics/boosts/giveaway/boost_badge.h"
|
||||
#include "info/profile/info_profile_badge.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "ui/painter.h"
|
||||
#include "core/application.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "settings/settings_credits_graphics.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/effects/premium_graphics.h"
|
||||
#include "ui/effects/premium_stars_colored.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_credits.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_premium.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
@@ -101,12 +114,237 @@ void SubmitChatInvite(
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ConfirmSubscriptionBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
const QString &hash,
|
||||
const MTPDchatInvite *data) {
|
||||
box->setWidth(st::boxWideWidth);
|
||||
const auto amount = data->vsubscription_pricing()->data().vamount().v;
|
||||
const auto formId = data->vsubscription_form_id()->v;
|
||||
const auto name = qs(data->vtitle());
|
||||
const auto maybePhoto = session->data().processPhoto(data->vphoto());
|
||||
const auto photo = maybePhoto->isNull() ? nullptr : maybePhoto.get();
|
||||
|
||||
struct State final {
|
||||
std::shared_ptr<Data::PhotoMedia> photoMedia;
|
||||
std::unique_ptr<Ui::EmptyUserpic> photoEmpty;
|
||||
|
||||
std::optional<MTP::Sender> api;
|
||||
Ui::RpWidget* saveButton = nullptr;
|
||||
rpl::variable<bool> loading;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
|
||||
const auto content = box->verticalLayout();
|
||||
|
||||
Ui::AddSkip(content, st::confirmInvitePhotoTop);
|
||||
const auto userpicWrap = content->add(
|
||||
object_ptr<Ui::CenterWrap<>>(
|
||||
content,
|
||||
object_ptr<Ui::RpWidget>(content)));
|
||||
const auto userpic = userpicWrap->entity();
|
||||
const auto photoSize = st::confirmInvitePhotoSize;
|
||||
userpic->resize(Size(photoSize));
|
||||
const auto options = Images::Option::RoundCircle;
|
||||
userpic->paintRequest(
|
||||
) | rpl::start_with_next([=, small = Data::PhotoSize::Small] {
|
||||
auto p = QPainter(userpic);
|
||||
if (state->photoMedia) {
|
||||
if (const auto image = state->photoMedia->image(small)) {
|
||||
p.drawPixmap(
|
||||
0,
|
||||
0,
|
||||
image->pix(Size(photoSize), { .options = options }));
|
||||
}
|
||||
} else if (state->photoEmpty) {
|
||||
state->photoEmpty->paintCircle(
|
||||
p,
|
||||
0,
|
||||
0,
|
||||
userpic->width(),
|
||||
photoSize);
|
||||
}
|
||||
}, userpicWrap->lifetime());
|
||||
userpicWrap->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
if (photo) {
|
||||
state->photoMedia = photo->createMediaView();
|
||||
state->photoMedia->wanted(Data::PhotoSize::Small, Data::FileOrigin());
|
||||
if (!state->photoMedia->image(Data::PhotoSize::Small)) {
|
||||
session->downloaderTaskFinished(
|
||||
) | rpl::start_with_next([=] {
|
||||
userpic->update();
|
||||
}, userpicWrap->entity()->lifetime());
|
||||
}
|
||||
} else {
|
||||
state->photoEmpty = std::make_unique<Ui::EmptyUserpic>(
|
||||
Ui::EmptyUserpic::UserpicColor(0),
|
||||
name);
|
||||
}
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
|
||||
{
|
||||
const auto widget = Ui::CreateChild<Ui::RpWidget>(content);
|
||||
using ColoredMiniStars = Ui::Premium::ColoredMiniStars;
|
||||
const auto stars = widget->lifetime().make_state<ColoredMiniStars>(
|
||||
widget,
|
||||
false,
|
||||
Ui::Premium::MiniStars::Type::BiStars);
|
||||
stars->setColorOverride(Ui::Premium::CreditsIconGradientStops());
|
||||
widget->resize(
|
||||
st::boxWideWidth - photoSize,
|
||||
photoSize * 2);
|
||||
content->sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &size) {
|
||||
widget->moveToLeft(photoSize / 2, 0);
|
||||
const auto starsRect = Rect(widget->size());
|
||||
stars->setPosition(starsRect.topLeft());
|
||||
stars->setSize(starsRect.size());
|
||||
widget->lower();
|
||||
}, widget->lifetime());
|
||||
widget->paintRequest(
|
||||
) | rpl::start_with_next([=](const QRect &r) {
|
||||
auto p = QPainter(widget);
|
||||
p.fillRect(r, Qt::transparent);
|
||||
stars->paint(p);
|
||||
}, widget->lifetime());
|
||||
}
|
||||
|
||||
box->addRow(
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_channel_invite_subscription_title(),
|
||||
st::inviteLinkSubscribeBoxTitle)));
|
||||
box->addRow(
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_channel_invite_subscription_about(
|
||||
lt_channel,
|
||||
rpl::single(Ui::Text::Bold(name)),
|
||||
lt_price,
|
||||
tr::lng_credits_summary_options_credits(
|
||||
lt_count,
|
||||
rpl::single(amount) | tr::to_count(),
|
||||
Ui::Text::Bold),
|
||||
Ui::Text::WithEntities),
|
||||
st::inviteLinkSubscribeBoxAbout)));
|
||||
Ui::AddSkip(content);
|
||||
box->addRow(
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_channel_invite_subscription_terms(
|
||||
lt_link,
|
||||
rpl::combine(
|
||||
tr::lng_paid_react_agree_link(),
|
||||
tr::lng_group_invite_subscription_about_url()
|
||||
) | rpl::map([](const QString &text, const QString &url) {
|
||||
return Ui::Text::Link(text, url);
|
||||
}),
|
||||
Ui::Text::RichLangValue),
|
||||
st::inviteLinkSubscribeBoxTerms)));
|
||||
|
||||
{
|
||||
const auto balance = Settings::AddBalanceWidget(
|
||||
content,
|
||||
session->credits().balanceValue(),
|
||||
true);
|
||||
session->credits().load(true);
|
||||
|
||||
rpl::combine(
|
||||
balance->sizeValue(),
|
||||
content->sizeValue()
|
||||
) | rpl::start_with_next([=](const QSize &, const QSize &) {
|
||||
balance->moveToRight(
|
||||
st::creditsHistoryRightSkip * 2,
|
||||
st::creditsHistoryRightSkip);
|
||||
balance->update();
|
||||
}, balance->lifetime());
|
||||
}
|
||||
|
||||
const auto sendCredits = [=, weak = Ui::MakeWeak(box)] {
|
||||
const auto show = box->uiShow();
|
||||
const auto buttonWidth = state->saveButton
|
||||
? state->saveButton->width()
|
||||
: 0;
|
||||
state->api->request(
|
||||
MTPpayments_SendStarsForm(
|
||||
MTP_flags(0),
|
||||
MTP_long(formId),
|
||||
MTP_inputInvoiceChatInviteSubscription(MTP_string(hash)))
|
||||
).done([=](const MTPpayments_PaymentResult &result) {
|
||||
state->api = std::nullopt;
|
||||
state->loading.force_assign(false);
|
||||
result.match([&](const MTPDpayments_paymentResult &data) {
|
||||
session->api().applyUpdates(data.vupdates());
|
||||
}, [](const MTPDpayments_paymentVerificationNeeded &data) {
|
||||
});
|
||||
if (weak) {
|
||||
box->closeBox();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
const auto id = error.type();
|
||||
if (weak) {
|
||||
state->api = std::nullopt;
|
||||
}
|
||||
show->showToast(id);
|
||||
state->loading.force_assign(false);
|
||||
}).send();
|
||||
if (state->saveButton) {
|
||||
state->saveButton->resizeToWidth(buttonWidth);
|
||||
}
|
||||
};
|
||||
|
||||
auto confirmText = tr::lng_channel_invite_subscription_button();
|
||||
state->saveButton = box->addButton(std::move(confirmText), [=] {
|
||||
if (state->api) {
|
||||
return;
|
||||
}
|
||||
state->api.emplace(&session->mtp());
|
||||
state->loading.force_assign(true);
|
||||
|
||||
const auto done = [=](Settings::SmallBalanceResult result) {
|
||||
if (result == Settings::SmallBalanceResult::Success
|
||||
|| result == Settings::SmallBalanceResult::Already) {
|
||||
sendCredits();
|
||||
} else {
|
||||
state->api = std::nullopt;
|
||||
state->loading.force_assign(false);
|
||||
}
|
||||
};
|
||||
Settings::MaybeRequestBalanceIncrease(
|
||||
Main::MakeSessionShow(box->uiShow(), session),
|
||||
amount,
|
||||
Settings::SmallBalanceSubscription{ .name = name },
|
||||
done);
|
||||
});
|
||||
|
||||
if (const auto saveButton = state->saveButton) {
|
||||
using namespace Info::Statistics;
|
||||
const auto loadingAnimation = InfiniteRadialAnimationWidget(
|
||||
saveButton,
|
||||
saveButton->height() / 2,
|
||||
&st::editStickerSetNameLoading);
|
||||
AddChildToWidgetCenter(saveButton, loadingAnimation);
|
||||
loadingAnimation->showOn(
|
||||
state->loading.value() | rpl::map(rpl::mappers::_1));
|
||||
}
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void CheckChatInvite(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const QString &hash,
|
||||
ChannelData *invitePeekChannel) {
|
||||
ChannelData *invitePeekChannel,
|
||||
Fn<void()> loaded) {
|
||||
const auto session = &controller->session();
|
||||
const auto weak = base::make_weak(controller);
|
||||
session->api().checkChatInvite(hash, [=](const MTPChatInvite &result) {
|
||||
@@ -114,6 +352,9 @@ void CheckChatInvite(
|
||||
if (!strong) {
|
||||
return;
|
||||
}
|
||||
if (loaded) {
|
||||
loaded();
|
||||
}
|
||||
Core::App().hideMediaView();
|
||||
const auto show = [&](not_null<PeerData*> chat) {
|
||||
const auto way = Window::SectionShow::Way::Forward;
|
||||
@@ -125,11 +366,26 @@ void CheckChatInvite(
|
||||
};
|
||||
result.match([=](const MTPDchatInvite &data) {
|
||||
const auto isGroup = !data.is_broadcast();
|
||||
const auto box = strong->show(Box<ConfirmInviteBox>(
|
||||
session,
|
||||
data,
|
||||
invitePeekChannel,
|
||||
[=] { SubmitChatInvite(weak, session, hash, isGroup); }));
|
||||
const auto hasPricing = !!data.vsubscription_pricing();
|
||||
const auto canRefulfill = data.is_can_refulfill_subscription();
|
||||
if (hasPricing
|
||||
&& !canRefulfill
|
||||
&& !data.vsubscription_form_id()) {
|
||||
strong->uiShow()->showToast(
|
||||
tr::lng_confirm_phone_link_invalid(tr::now));
|
||||
return;
|
||||
}
|
||||
const auto box = (hasPricing && !canRefulfill)
|
||||
? strong->show(Box(
|
||||
ConfirmSubscriptionBox,
|
||||
session,
|
||||
hash,
|
||||
&data))
|
||||
: strong->show(Box<ConfirmInviteBox>(
|
||||
session,
|
||||
data,
|
||||
invitePeekChannel,
|
||||
[=] { SubmitChatInvite(weak, session, hash, isGroup); }));
|
||||
if (invitePeekChannel) {
|
||||
box->boxClosing(
|
||||
) | rpl::filter([=] {
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace Api {
|
||||
void CheckChatInvite(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const QString &hash,
|
||||
ChannelData *invitePeekChannel = nullptr);
|
||||
ChannelData *invitePeekChannel = nullptr,
|
||||
Fn<void()> loaded = nullptr);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
|
||||
@@ -264,14 +264,24 @@ ChatParticipant::ChatParticipant(
|
||||
_rank = qs(data.vrank().value_or_empty());
|
||||
_rights = ChatAdminRightsInfo(data.vadmin_rights());
|
||||
_by = peerToUser(peerFromUser(data.vpromoted_by()));
|
||||
_date = data.vdate().v;
|
||||
}, [&](const MTPDchannelParticipantSelf &data) {
|
||||
_type = Type::Member;
|
||||
_date = data.vdate().v;
|
||||
_by = peerToUser(peerFromUser(data.vinviter_id()));
|
||||
if (data.vsubscription_until_date()) {
|
||||
_subscriptionDate = data.vsubscription_until_date()->v;
|
||||
}
|
||||
}, [&](const MTPDchannelParticipant &data) {
|
||||
_type = Type::Member;
|
||||
_date = data.vdate().v;
|
||||
if (data.vsubscription_until_date()) {
|
||||
_subscriptionDate = data.vsubscription_until_date()->v;
|
||||
}
|
||||
}, [&](const MTPDchannelParticipantBanned &data) {
|
||||
_restrictions = ChatRestrictionsInfo(data.vbanned_rights());
|
||||
_by = peerToUser(peerFromUser(data.vkicked_by()));
|
||||
_date = data.vdate().v;
|
||||
|
||||
_type = (_restrictions.flags & ChatRestriction::ViewMessages)
|
||||
? Type::Banned
|
||||
@@ -348,6 +358,24 @@ ChatAdminRightsInfo ChatParticipant::rights() const {
|
||||
return _rights;
|
||||
}
|
||||
|
||||
TimeId ChatParticipant::subscriptionDate() const {
|
||||
return _subscriptionDate;
|
||||
}
|
||||
|
||||
TimeId ChatParticipant::promotedSince() const {
|
||||
return (_type == Type::Admin) ? _date : TimeId(0);
|
||||
}
|
||||
|
||||
TimeId ChatParticipant::restrictedSince() const {
|
||||
return (_type == Type::Restricted || _type == Type::Banned)
|
||||
? _date
|
||||
: TimeId(0);
|
||||
}
|
||||
|
||||
TimeId ChatParticipant::memberSince() const {
|
||||
return (_type == Type::Member) ? _date : TimeId(0);
|
||||
}
|
||||
|
||||
ChatParticipant::Type ChatParticipant::type() const {
|
||||
return _type;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,11 @@ public:
|
||||
ChatRestrictionsInfo restrictions() const;
|
||||
ChatAdminRightsInfo rights() const;
|
||||
|
||||
TimeId subscriptionDate() const;
|
||||
TimeId promotedSince() const;
|
||||
TimeId restrictedSince() const;
|
||||
TimeId memberSince() const;
|
||||
|
||||
Type type() const;
|
||||
QString rank() const;
|
||||
|
||||
@@ -73,6 +78,8 @@ private:
|
||||
bool _canBeEdited = false;
|
||||
|
||||
QString _rank;
|
||||
TimeId _subscriptionDate = 0;
|
||||
TimeId _date = 0;
|
||||
|
||||
ChatRestrictionsInfo _restrictions;
|
||||
ChatAdminRightsInfo _rights;
|
||||
|
||||
@@ -12,6 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "passport/passport_encryption.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "base/call_delayed.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ struct SendOptions {
|
||||
bool invertCaption = false;
|
||||
bool hideViaBot = false;
|
||||
crl::time ttlSeconds = 0;
|
||||
|
||||
friend inline bool operator==(
|
||||
const SendOptions &,
|
||||
const SendOptions &) = default;
|
||||
};
|
||||
[[nodiscard]] SendOptions DefaultSendWhenOnlineOptions();
|
||||
|
||||
@@ -52,6 +56,10 @@ struct SendAction {
|
||||
MsgId replaceMediaOf = 0;
|
||||
|
||||
[[nodiscard]] MTPInputReplyTo mtpReplyTo() const;
|
||||
|
||||
friend inline bool operator==(
|
||||
const SendAction &,
|
||||
const SendAction &) = default;
|
||||
};
|
||||
|
||||
struct MessageToSend {
|
||||
|
||||
@@ -79,6 +79,8 @@ constexpr auto kTransactionsLimit = 100;
|
||||
.credits = tl.data().vstars().v,
|
||||
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
|
||||
.barePeerId = barePeerId,
|
||||
.bareGiveawayMsgId = uint64(
|
||||
tl.data().vgiveaway_post_id().value_or_empty()),
|
||||
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Peer;
|
||||
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
|
||||
@@ -94,31 +96,70 @@ constexpr auto kTransactionsLimit = 100;
|
||||
}, [](const MTPDstarsTransactionPeerAds &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Ads;
|
||||
}),
|
||||
.refunded = tl.data().is_refund(),
|
||||
.pending = tl.data().is_pending(),
|
||||
.failed = tl.data().is_failed(),
|
||||
.subscriptionUntil = tl.data().vsubscription_period()
|
||||
? base::unixtime::parse(base::unixtime::now()
|
||||
+ tl.data().vsubscription_period()->v)
|
||||
: QDateTime(),
|
||||
.successDate = tl.data().vtransaction_date()
|
||||
? base::unixtime::parse(tl.data().vtransaction_date()->v)
|
||||
: QDateTime(),
|
||||
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
|
||||
.reaction = tl.data().is_reaction(),
|
||||
.refunded = tl.data().is_refund(),
|
||||
.pending = tl.data().is_pending(),
|
||||
.failed = tl.data().is_failed(),
|
||||
.in = (int64(tl.data().vstars().v) >= 0),
|
||||
.gift = tl.data().is_gift(),
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] Data::SubscriptionEntry SubscriptionFromTL(
|
||||
const MTPStarsSubscription &tl) {
|
||||
return Data::SubscriptionEntry{
|
||||
.id = qs(tl.data().vid()),
|
||||
.inviteHash = qs(tl.data().vchat_invite_hash().value_or_empty()),
|
||||
.until = base::unixtime::parse(tl.data().vuntil_date().v),
|
||||
.subscription = Data::PeerSubscription{
|
||||
.credits = tl.data().vpricing().data().vamount().v,
|
||||
.period = tl.data().vpricing().data().vperiod().v,
|
||||
},
|
||||
.barePeerId = peerFromMTP(tl.data().vpeer()).value,
|
||||
.cancelled = tl.data().is_canceled(),
|
||||
.expired = (base::unixtime::now() > tl.data().vuntil_date().v),
|
||||
.canRefulfill = tl.data().is_can_refulfill(),
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] Data::CreditsStatusSlice StatusFromTL(
|
||||
const MTPpayments_StarsStatus &status,
|
||||
not_null<PeerData*> peer) {
|
||||
peer->owner().processUsers(status.data().vusers());
|
||||
peer->owner().processChats(status.data().vchats());
|
||||
const auto &data = status.data();
|
||||
peer->owner().processUsers(data.vusers());
|
||||
peer->owner().processChats(data.vchats());
|
||||
auto entries = std::vector<Data::CreditsHistoryEntry>();
|
||||
if (const auto history = data.vhistory()) {
|
||||
entries.reserve(history->v.size());
|
||||
for (const auto &tl : history->v) {
|
||||
entries.push_back(HistoryFromTL(tl, peer));
|
||||
}
|
||||
}
|
||||
auto subscriptions = std::vector<Data::SubscriptionEntry>();
|
||||
if (const auto history = data.vsubscriptions()) {
|
||||
subscriptions.reserve(history->v.size());
|
||||
for (const auto &tl : history->v) {
|
||||
subscriptions.push_back(SubscriptionFromTL(tl));
|
||||
}
|
||||
}
|
||||
return Data::CreditsStatusSlice{
|
||||
.list = ranges::views::all(
|
||||
status.data().vhistory().v
|
||||
) | ranges::views::transform([&](const MTPStarsTransaction &tl) {
|
||||
return HistoryFromTL(tl, peer);
|
||||
}) | ranges::to_vector,
|
||||
.list = std::move(entries),
|
||||
.subscriptions = std::move(subscriptions),
|
||||
.balance = status.data().vbalance().v,
|
||||
.subscriptionsMissingBalance
|
||||
= status.data().vsubscriptions_missing_balance().value_or_empty(),
|
||||
.allLoaded = !status.data().vnext_offset().has_value(),
|
||||
.token = qs(status.data().vnext_offset().value_or_empty()),
|
||||
.tokenSubscriptions = qs(
|
||||
status.data().vsubscriptions_next_offset().value_or_empty()),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -133,12 +174,12 @@ rpl::producer<rpl::no_value, QString> CreditsTopupOptions::request() {
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
|
||||
using TLOption = MTPStarsTopupOption;
|
||||
_api.request(MTPpayments_GetStarsTopupOptions(
|
||||
)).done([=](const MTPVector<TLOption> &result) {
|
||||
_options = ranges::views::all(
|
||||
result.v
|
||||
) | ranges::views::transform([](const TLOption &option) {
|
||||
const auto giftBarePeerId = !_peer->isSelf() ? _peer->id.value : 0;
|
||||
|
||||
const auto optionsFromTL = [giftBarePeerId](const auto &options) {
|
||||
return ranges::views::all(
|
||||
options
|
||||
) | ranges::views::transform([=](const auto &option) {
|
||||
return Data::CreditTopupOption{
|
||||
.credits = option.data().vstars().v,
|
||||
.product = qs(
|
||||
@@ -146,17 +187,40 @@ rpl::producer<rpl::no_value, QString> CreditsTopupOptions::request() {
|
||||
.currency = qs(option.data().vcurrency()),
|
||||
.amount = option.data().vamount().v,
|
||||
.extended = option.data().is_extended(),
|
||||
.giftBarePeerId = giftBarePeerId,
|
||||
};
|
||||
}) | ranges::to_vector;
|
||||
consumer.put_done();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
};
|
||||
const auto fail = [=](const MTP::Error &error) {
|
||||
consumer.put_error_copy(error.type());
|
||||
}).send();
|
||||
};
|
||||
|
||||
if (_peer->isSelf()) {
|
||||
using TLOption = MTPStarsTopupOption;
|
||||
_api.request(MTPpayments_GetStarsTopupOptions(
|
||||
)).done([=](const MTPVector<TLOption> &result) {
|
||||
_options = optionsFromTL(result.v);
|
||||
consumer.put_done();
|
||||
}).fail(fail).send();
|
||||
} else if (const auto user = _peer->asUser()) {
|
||||
using TLOption = MTPStarsGiftOption;
|
||||
_api.request(MTPpayments_GetStarsGiftOptions(
|
||||
MTP_flags(MTPpayments_GetStarsGiftOptions::Flag::f_user_id),
|
||||
user->inputUser
|
||||
)).done([=](const MTPVector<TLOption> &result) {
|
||||
_options = optionsFromTL(result.v);
|
||||
consumer.put_done();
|
||||
}).fail(fail).send();
|
||||
}
|
||||
|
||||
return lifetime;
|
||||
};
|
||||
}
|
||||
|
||||
Data::CreditTopupOptions CreditsTopupOptions::options() const {
|
||||
return _options;
|
||||
}
|
||||
|
||||
CreditsStatus::CreditsStatus(not_null<PeerData*> peer)
|
||||
: _peer(peer)
|
||||
, _api(&peer->session().api().instance()) {
|
||||
@@ -175,10 +239,14 @@ void CreditsStatus::request(
|
||||
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input
|
||||
)).done([=](const TLResult &result) {
|
||||
_requestId = 0;
|
||||
done(StatusFromTL(result, _peer));
|
||||
if (const auto onstack = done) {
|
||||
onstack(StatusFromTL(result, _peer));
|
||||
}
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
done({});
|
||||
if (const auto onstack = done) {
|
||||
onstack({});
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -200,6 +268,7 @@ void CreditsHistory::request(
|
||||
}
|
||||
_requestId = _api.request(MTPpayments_GetStarsTransactions(
|
||||
MTP_flags(_flags),
|
||||
MTPstring(), // subscription_id
|
||||
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input,
|
||||
MTP_string(token),
|
||||
MTP_int(kTransactionsLimit)
|
||||
@@ -212,8 +281,23 @@ void CreditsHistory::request(
|
||||
}).send();
|
||||
}
|
||||
|
||||
Data::CreditTopupOptions CreditsTopupOptions::options() const {
|
||||
return _options;
|
||||
void CreditsHistory::requestSubscriptions(
|
||||
const Data::CreditsStatusSlice::OffsetToken &token,
|
||||
Fn<void(Data::CreditsStatusSlice)> done) {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
_requestId = _api.request(MTPpayments_GetStarsSubscriptions(
|
||||
MTP_flags(0),
|
||||
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input,
|
||||
MTP_string(token)
|
||||
)).done([=](const MTPpayments_StarsStatus &result) {
|
||||
_requestId = 0;
|
||||
done(StatusFromTL(result, _peer));
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
done({});
|
||||
}).send();
|
||||
}
|
||||
|
||||
rpl::producer<not_null<PeerData*>> PremiumPeerBot(
|
||||
@@ -303,4 +387,58 @@ Data::CreditsEarnStatistics CreditsEarnStatistics::data() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
CreditsGiveawayOptions::CreditsGiveawayOptions(not_null<PeerData*> peer)
|
||||
: _peer(peer)
|
||||
, _api(&peer->session().api().instance()) {
|
||||
}
|
||||
|
||||
rpl::producer<rpl::no_value, QString> CreditsGiveawayOptions::request() {
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
|
||||
using TLOption = MTPStarsGiveawayOption;
|
||||
|
||||
const auto optionsFromTL = [=](const auto &options) {
|
||||
return ranges::views::all(
|
||||
options
|
||||
) | ranges::views::transform([=](const auto &option) {
|
||||
return Data::CreditsGiveawayOption{
|
||||
.winners = ranges::views::all(
|
||||
option.data().vwinners().v
|
||||
) | ranges::views::transform([](const auto &winner) {
|
||||
return Data::CreditsGiveawayOption::Winner{
|
||||
.users = winner.data().vusers().v,
|
||||
.perUserStars = winner.data().vper_user_stars().v,
|
||||
.isDefault = winner.data().is_default(),
|
||||
};
|
||||
}) | ranges::to_vector,
|
||||
.storeProduct = qs(
|
||||
option.data().vstore_product().value_or_empty()),
|
||||
.currency = qs(option.data().vcurrency()),
|
||||
.amount = option.data().vamount().v,
|
||||
.credits = option.data().vstars().v,
|
||||
.yearlyBoosts = option.data().vyearly_boosts().v,
|
||||
.isExtended = option.data().is_extended(),
|
||||
.isDefault = option.data().is_default(),
|
||||
};
|
||||
}) | ranges::to_vector;
|
||||
};
|
||||
const auto fail = [=](const MTP::Error &error) {
|
||||
consumer.put_error_copy(error.type());
|
||||
};
|
||||
|
||||
_api.request(MTPpayments_GetStarsGiveawayOptions(
|
||||
)).done([=](const MTPVector<TLOption> &result) {
|
||||
_options = optionsFromTL(result.v);
|
||||
consumer.put_done();
|
||||
}).fail(fail).send();
|
||||
|
||||
return lifetime;
|
||||
};
|
||||
}
|
||||
|
||||
Data::CreditsGiveawayOptions CreditsGiveawayOptions::options() const {
|
||||
return _options;
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -36,6 +36,22 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class CreditsGiveawayOptions final {
|
||||
public:
|
||||
CreditsGiveawayOptions(not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
|
||||
[[nodiscard]] Data::CreditsGiveawayOptions options() const;
|
||||
|
||||
private:
|
||||
const not_null<PeerData*> _peer;
|
||||
|
||||
Data::CreditsGiveawayOptions _options;
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
};
|
||||
|
||||
class CreditsStatus final {
|
||||
public:
|
||||
CreditsStatus(not_null<PeerData*> peer);
|
||||
@@ -60,6 +76,9 @@ public:
|
||||
void request(
|
||||
const Data::CreditsStatusSlice::OffsetToken &token,
|
||||
Fn<void(Data::CreditsStatusSlice)> done);
|
||||
void requestSubscriptions(
|
||||
const Data::CreditsStatusSlice::OffsetToken &token,
|
||||
Fn<void(Data::CreditsStatusSlice)> done);
|
||||
|
||||
private:
|
||||
using HistoryTL = MTPpayments_GetStarsTransactions;
|
||||
|
||||
@@ -128,7 +128,7 @@ mtpRequestId EditMessage(
|
||||
}
|
||||
|
||||
if (updateRecentStickers) {
|
||||
api->requestRecentStickersForce(true);
|
||||
api->requestSpecialStickersForce(false, false, true);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||
if constexpr (ErrorWithId<FailCallback>) {
|
||||
@@ -153,9 +153,7 @@ mtpRequestId EditMessage(
|
||||
const auto &text = item->originalText();
|
||||
const auto webpage = (!item->media() || !item->media()->webpage())
|
||||
? Data::WebPageDraft{ .removed = true }
|
||||
: Data::WebPageDraft{
|
||||
.id = item->media()->webpage()->id,
|
||||
};
|
||||
: Data::WebPageDraft::FromItem(item);
|
||||
return EditMessage(
|
||||
item,
|
||||
text,
|
||||
|
||||
@@ -115,6 +115,28 @@ rpl::producer<bool> GlobalPrivacy::newRequirePremium() const {
|
||||
return _newRequirePremium.value();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::loadPaidReactionAnonymous() {
|
||||
if (_paidReactionAnonymousLoaded) {
|
||||
return;
|
||||
}
|
||||
_paidReactionAnonymousLoaded = true;
|
||||
_api.request(MTPmessages_GetPaidReactionPrivacy(
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_session->api().applyUpdates(result);
|
||||
}).send();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updatePaidReactionAnonymous(bool value) {
|
||||
_paidReactionAnonymous = value;
|
||||
}
|
||||
|
||||
bool GlobalPrivacy::paidReactionAnonymousCurrent() const {
|
||||
return _paidReactionAnonymous.current();
|
||||
}
|
||||
|
||||
rpl::producer<bool> GlobalPrivacy::paidReactionAnonymous() const {
|
||||
return _paidReactionAnonymous.value();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updateArchiveAndMute(bool value) {
|
||||
update(
|
||||
|
||||
@@ -49,6 +49,11 @@ public:
|
||||
[[nodiscard]] bool newRequirePremiumCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> newRequirePremium() const;
|
||||
|
||||
void loadPaidReactionAnonymous();
|
||||
void updatePaidReactionAnonymous(bool value);
|
||||
[[nodiscard]] bool paidReactionAnonymousCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> paidReactionAnonymous() const;
|
||||
|
||||
private:
|
||||
void apply(const MTPGlobalPrivacySettings &data);
|
||||
|
||||
@@ -67,7 +72,9 @@ private:
|
||||
rpl::variable<bool> _showArchiveAndMute = false;
|
||||
rpl::variable<bool> _hideReadTime = false;
|
||||
rpl::variable<bool> _newRequirePremium = false;
|
||||
rpl::variable<bool> _paidReactionAnonymous = false;
|
||||
std::vector<Fn<void()>> _callbacks;
|
||||
bool _paidReactionAnonymousLoaded = false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_invite_links.h"
|
||||
|
||||
#include "api/api_chat_participants.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "apiwrap.h"
|
||||
@@ -69,59 +69,46 @@ JoinedByLinkSlice ParseJoinedByLinkSlice(
|
||||
InviteLinks::InviteLinks(not_null<ApiWrap*> api) : _api(api) {
|
||||
}
|
||||
|
||||
void InviteLinks::create(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void(Link)> done,
|
||||
const QString &label,
|
||||
TimeId expireDate,
|
||||
int usageLimit,
|
||||
bool requestApproval) {
|
||||
performCreate(
|
||||
peer,
|
||||
std::move(done),
|
||||
false,
|
||||
label,
|
||||
expireDate,
|
||||
usageLimit,
|
||||
requestApproval);
|
||||
void InviteLinks::create(const CreateInviteLinkArgs &args) {
|
||||
performCreate(args, false);
|
||||
}
|
||||
|
||||
void InviteLinks::performCreate(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void(Link)> done,
|
||||
bool revokeLegacyPermanent,
|
||||
const QString &label,
|
||||
TimeId expireDate,
|
||||
int usageLimit,
|
||||
bool requestApproval) {
|
||||
if (const auto i = _createCallbacks.find(peer)
|
||||
const CreateInviteLinkArgs &args,
|
||||
bool revokeLegacyPermanent) {
|
||||
if (const auto i = _createCallbacks.find(args.peer)
|
||||
; i != end(_createCallbacks)) {
|
||||
if (done) {
|
||||
i->second.push_back(std::move(done));
|
||||
if (args.done) {
|
||||
i->second.push_back(std::move(args.done));
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto &callbacks = _createCallbacks[peer];
|
||||
if (done) {
|
||||
callbacks.push_back(std::move(done));
|
||||
auto &callbacks = _createCallbacks[args.peer];
|
||||
if (args.done) {
|
||||
callbacks.push_back(std::move(args.done));
|
||||
}
|
||||
|
||||
const auto requestApproval = !args.subscription && args.requestApproval;
|
||||
using Flag = MTPmessages_ExportChatInvite::Flag;
|
||||
_api->request(MTPmessages_ExportChatInvite(
|
||||
MTP_flags((revokeLegacyPermanent
|
||||
? Flag::f_legacy_revoke_permanent
|
||||
: Flag(0))
|
||||
| (!label.isEmpty() ? Flag::f_title : Flag(0))
|
||||
| (expireDate ? Flag::f_expire_date : Flag(0))
|
||||
| ((!requestApproval && usageLimit)
|
||||
| (!args.label.isEmpty() ? Flag::f_title : Flag(0))
|
||||
| (args.expireDate ? Flag::f_expire_date : Flag(0))
|
||||
| ((!requestApproval && args.usageLimit)
|
||||
? Flag::f_usage_limit
|
||||
: Flag(0))
|
||||
| (requestApproval ? Flag::f_request_needed : Flag(0))),
|
||||
peer->input,
|
||||
MTP_int(expireDate),
|
||||
MTP_int(usageLimit),
|
||||
MTP_string(label)
|
||||
)).done([=](const MTPExportedChatInvite &result) {
|
||||
| (requestApproval ? Flag::f_request_needed : Flag(0))
|
||||
| (args.subscription ? Flag::f_subscription_pricing : Flag(0))),
|
||||
args.peer->input,
|
||||
MTP_int(args.expireDate),
|
||||
MTP_int(args.usageLimit),
|
||||
MTP_string(args.label),
|
||||
MTP_starsSubscriptionPricing(
|
||||
MTP_int(args.subscription.period),
|
||||
MTP_long(args.subscription.credits))
|
||||
)).done([=, peer = args.peer](const MTPExportedChatInvite &result) {
|
||||
const auto callbacks = _createCallbacks.take(peer);
|
||||
const auto link = prepend(peer, peer->session().user(), result);
|
||||
if (link && callbacks) {
|
||||
@@ -129,7 +116,7 @@ void InviteLinks::performCreate(
|
||||
callback(*link);
|
||||
}
|
||||
}
|
||||
}).fail([=] {
|
||||
}).fail([=, peer = args.peer] {
|
||||
_createCallbacks.erase(peer);
|
||||
}).send();
|
||||
}
|
||||
@@ -238,6 +225,15 @@ void InviteLinks::edit(
|
||||
requestApproval);
|
||||
}
|
||||
|
||||
void InviteLinks::editTitle(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> admin,
|
||||
const QString &link,
|
||||
const QString &label,
|
||||
Fn<void(Link)> done) {
|
||||
performEdit(peer, admin, link, done, false, label, 0, 0, false, true);
|
||||
}
|
||||
|
||||
void InviteLinks::performEdit(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> admin,
|
||||
@@ -247,7 +243,8 @@ void InviteLinks::performEdit(
|
||||
const QString &label,
|
||||
TimeId expireDate,
|
||||
int usageLimit,
|
||||
bool requestApproval) {
|
||||
bool requestApproval,
|
||||
bool editOnlyTitle) {
|
||||
const auto key = LinkKey{ peer, link };
|
||||
if (_deleteCallbacks.contains(key)) {
|
||||
return;
|
||||
@@ -272,7 +269,7 @@ void InviteLinks::performEdit(
|
||||
? Flag::f_request_needed
|
||||
: Flag(0));
|
||||
_api->request(MTPmessages_EditExportedChatInvite(
|
||||
MTP_flags(flags),
|
||||
MTP_flags(editOnlyTitle ? Flag::f_title : flags),
|
||||
peer->input,
|
||||
MTP_string(link),
|
||||
MTP_int(expireDate),
|
||||
@@ -344,7 +341,7 @@ void InviteLinks::revokePermanent(
|
||||
} else if (!admin->isSelf()) {
|
||||
crl::on_main(&peer->session(), done);
|
||||
} else {
|
||||
performCreate(peer, callback, true);
|
||||
performCreate({ peer, callback }, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,6 +747,12 @@ auto InviteLinks::parse(
|
||||
return std::optional<Link>(Link{
|
||||
.link = qs(data.vlink()),
|
||||
.label = qs(data.vtitle().value_or_empty()),
|
||||
.subscription = data.vsubscription_pricing()
|
||||
? Data::PeerSubscription{
|
||||
data.vsubscription_pricing()->data().vamount().v,
|
||||
data.vsubscription_pricing()->data().vperiod().v,
|
||||
}
|
||||
: Data::PeerSubscription(),
|
||||
.admin = peer->session().data().user(data.vadmin_id()),
|
||||
.date = data.vdate().v,
|
||||
.startDate = data.vstart_date().value_or_empty(),
|
||||
|
||||
@@ -9,11 +9,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
class ApiWrap;
|
||||
|
||||
#include "data/data_subscriptions.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct InviteLink {
|
||||
QString link;
|
||||
QString label;
|
||||
Data::PeerSubscription subscription;
|
||||
not_null<UserData*> admin;
|
||||
TimeId date = 0;
|
||||
TimeId startDate = 0;
|
||||
@@ -53,6 +56,16 @@ struct InviteLinkUpdate {
|
||||
not_null<PeerData*> peer,
|
||||
const MTPmessages_ChatInviteImporters &slice);
|
||||
|
||||
struct CreateInviteLinkArgs {
|
||||
not_null<PeerData*> peer;
|
||||
Fn<void(InviteLink)> done = nullptr;
|
||||
QString label;
|
||||
TimeId expireDate = 0;
|
||||
int usageLimit = 0;
|
||||
bool requestApproval = false;
|
||||
Data::PeerSubscription subscription;
|
||||
};
|
||||
|
||||
class InviteLinks final {
|
||||
public:
|
||||
explicit InviteLinks(not_null<ApiWrap*> api);
|
||||
@@ -61,13 +74,7 @@ public:
|
||||
using Links = PeerInviteLinks;
|
||||
using Update = InviteLinkUpdate;
|
||||
|
||||
void create(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void(Link)> done = nullptr,
|
||||
const QString &label = QString(),
|
||||
TimeId expireDate = 0,
|
||||
int usageLimit = 0,
|
||||
bool requestApproval = false);
|
||||
void create(const CreateInviteLinkArgs &args);
|
||||
void edit(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> admin,
|
||||
@@ -77,6 +84,12 @@ public:
|
||||
int usageLimit,
|
||||
bool requestApproval,
|
||||
Fn<void(Link)> done = nullptr);
|
||||
void editTitle(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> admin,
|
||||
const QString &link,
|
||||
const QString &label,
|
||||
Fn<void(Link)> done = nullptr);
|
||||
void revoke(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> admin,
|
||||
@@ -187,15 +200,11 @@ private:
|
||||
const QString &label = QString(),
|
||||
TimeId expireDate = 0,
|
||||
int usageLimit = 0,
|
||||
bool requestApproval = false);
|
||||
bool requestApproval = false,
|
||||
bool editOnlyTitle = false);
|
||||
void performCreate(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void(Link)> done,
|
||||
bool revokeLegacyPermanent,
|
||||
const QString &label = QString(),
|
||||
TimeId expireDate = 0,
|
||||
int usageLimit = 0,
|
||||
bool requestApproval = false);
|
||||
const CreateInviteLinkArgs &args,
|
||||
bool revokeLegacyPermanent);
|
||||
|
||||
void requestJoinedFirstSlice(LinkKey key);
|
||||
[[nodiscard]] std::optional<JoinedByLinkSlice> lookupJoinedFirstSlice(
|
||||
|
||||
@@ -36,7 +36,8 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
|
||||
MTP_double(document->duration() / 1000.),
|
||||
MTP_int(dimensions.width()),
|
||||
MTP_int(dimensions.height()),
|
||||
MTPint())); // preload_prefix_size
|
||||
MTPint(), // preload_prefix_size
|
||||
MTPdouble())); // video_start_ts
|
||||
} else {
|
||||
attributes.push_back(MTP_documentAttributeImageSize(
|
||||
MTP_int(dimensions.width()),
|
||||
|
||||
@@ -39,9 +39,9 @@ namespace {
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] Data::SubscriptionOptions GiftCodesFromTL(
|
||||
[[nodiscard]] Data::PremiumSubscriptionOptions GiftCodesFromTL(
|
||||
const QVector<MTPPremiumGiftCodeOption> &tlOptions) {
|
||||
auto options = SubscriptionOptionsFromTL(tlOptions);
|
||||
auto options = PremiumSubscriptionOptionsFromTL(tlOptions);
|
||||
for (auto i = 0; i < options.size(); i++) {
|
||||
const auto &tlOption = tlOptions[i].data();
|
||||
const auto perUserText = Ui::FillAmountAndCurrency(
|
||||
@@ -143,7 +143,7 @@ void Premium::reloadPromo() {
|
||||
const auto &data = result.data();
|
||||
_session->data().processUsers(data.vusers());
|
||||
|
||||
_subscriptionOptions = SubscriptionOptionsFromTL(
|
||||
_subscriptionOptions = PremiumSubscriptionOptionsFromTL(
|
||||
data.vperiod_options().v);
|
||||
for (const auto &option : data.vperiod_options().v) {
|
||||
if (option.data().vmonths().v == 1) {
|
||||
@@ -361,9 +361,10 @@ void Premium::resolveGiveawayInfo(
|
||||
? GiveawayState::Refunded
|
||||
: GiveawayState::Finished;
|
||||
info.giftCode = qs(data.vgift_code_slug().value_or_empty());
|
||||
info.activatedCount = data.vactivated_count().v;
|
||||
info.activatedCount = data.vactivated_count().value_or_empty();
|
||||
info.finishDate = data.vfinish_date().v;
|
||||
info.startDate = data.vstart_date().v;
|
||||
info.credits = data.vstars_prize().value_or_empty();
|
||||
});
|
||||
_giveawayInfoDone(std::move(info));
|
||||
}).fail([=] {
|
||||
@@ -372,7 +373,7 @@ void Premium::resolveGiveawayInfo(
|
||||
}).send();
|
||||
}
|
||||
|
||||
const Data::SubscriptionOptions &Premium::subscriptionOptions() const {
|
||||
const Data::PremiumSubscriptionOptions &Premium::subscriptionOptions() const {
|
||||
return _subscriptionOptions;
|
||||
}
|
||||
|
||||
@@ -508,7 +509,9 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::applyPrepaid(
|
||||
_api.request(MTPpayments_LaunchPrepaidGiveaway(
|
||||
_peer->input,
|
||||
MTP_long(prepaidId),
|
||||
Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
|
||||
invoice.creditsAmount
|
||||
? Payments::InvoiceCreditsGiveawayToTL(invoice)
|
||||
: Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_peer->session().api().applyUpdates(result);
|
||||
consumer.put_done();
|
||||
@@ -537,17 +540,17 @@ Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
|
||||
const auto token = Token{ users, months };
|
||||
const auto &store = _stores[token];
|
||||
return Payments::InvoicePremiumGiftCode{
|
||||
.randomId = randomId,
|
||||
.currency = _optionsForOnePerson.currency,
|
||||
.amount = store.amount,
|
||||
.storeProduct = store.product,
|
||||
.randomId = randomId,
|
||||
.amount = store.amount,
|
||||
.storeQuantity = store.quantity,
|
||||
.users = token.users,
|
||||
.months = token.months,
|
||||
};
|
||||
}
|
||||
|
||||
Data::SubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
|
||||
Data::PremiumSubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
|
||||
const auto it = _subscriptionOptions.find(amount);
|
||||
if (it != end(_subscriptionOptions)) {
|
||||
return it->second;
|
||||
|
||||
@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_subscription_option.h"
|
||||
#include "data/data_premium_subscription_option.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class History;
|
||||
@@ -57,6 +57,7 @@ struct GiveawayInfo {
|
||||
TimeId tooEarlyDate = 0;
|
||||
TimeId finishDate = 0;
|
||||
TimeId startDate = 0;
|
||||
uint64 credits = 0;
|
||||
int winnersCount = 0;
|
||||
int activatedCount = 0;
|
||||
bool participating = false;
|
||||
@@ -106,7 +107,7 @@ public:
|
||||
Fn<void(GiveawayInfo)> done);
|
||||
|
||||
[[nodiscard]] auto subscriptionOptions() const
|
||||
-> const Data::SubscriptionOptions &;
|
||||
-> const Data::PremiumSubscriptionOptions &;
|
||||
|
||||
[[nodiscard]] rpl::producer<> somePremiumRequiredResolved() const;
|
||||
void resolvePremiumRequired(not_null<UserData*> user);
|
||||
@@ -156,7 +157,7 @@ private:
|
||||
MsgId _giveawayInfoMessageId = 0;
|
||||
Fn<void(GiveawayInfo)> _giveawayInfoDone;
|
||||
|
||||
Data::SubscriptionOptions _subscriptionOptions;
|
||||
Data::PremiumSubscriptionOptions _subscriptionOptions;
|
||||
|
||||
rpl::event_stream<> _somePremiumRequiredResolved;
|
||||
base::flat_set<not_null<UserData*>> _resolvePremiumRequiredUsers;
|
||||
@@ -170,7 +171,7 @@ public:
|
||||
PremiumGiftCodeOptions(not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
|
||||
[[nodiscard]] Data::SubscriptionOptions options(int amount);
|
||||
[[nodiscard]] Data::PremiumSubscriptionOptions options(int amount);
|
||||
[[nodiscard]] const std::vector<int> &availablePresets() const;
|
||||
[[nodiscard]] int monthsFromPreset(int monthsIndex);
|
||||
[[nodiscard]] Payments::InvoicePremiumGiftCode invoice(
|
||||
@@ -200,8 +201,9 @@ private:
|
||||
int quantity = 0;
|
||||
};
|
||||
using Amount = int;
|
||||
using PremiumSubscriptionOptions = Data::PremiumSubscriptionOptions;
|
||||
const not_null<PeerData*> _peer;
|
||||
base::flat_map<Amount, Data::SubscriptionOptions> _subscriptionOptions;
|
||||
base::flat_map<Amount, PremiumSubscriptionOptions> _subscriptionOptions;
|
||||
struct {
|
||||
std::vector<int> months;
|
||||
std::vector<float64> totalCosts;
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Api {
|
||||
|
||||
constexpr auto kDiscountDivider = 1.;
|
||||
|
||||
Data::SubscriptionOption CreateSubscriptionOption(
|
||||
Data::PremiumSubscriptionOption CreateSubscriptionOption(
|
||||
int months,
|
||||
int monthlyAmount,
|
||||
int64 amount,
|
||||
|
||||
@@ -7,11 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_subscription_option.h"
|
||||
#include "data/data_premium_subscription_option.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
[[nodiscard]] Data::SubscriptionOption CreateSubscriptionOption(
|
||||
[[nodiscard]] Data::PremiumSubscriptionOption CreateSubscriptionOption(
|
||||
int months,
|
||||
int monthlyAmount,
|
||||
int64 amount,
|
||||
@@ -19,22 +19,22 @@ namespace Api {
|
||||
const QString &botUrl);
|
||||
|
||||
template<typename Option>
|
||||
[[nodiscard]] Data::SubscriptionOptions SubscriptionOptionsFromTL(
|
||||
const QVector<Option> &tlOptions) {
|
||||
if (tlOptions.isEmpty()) {
|
||||
[[nodiscard]] auto PremiumSubscriptionOptionsFromTL(
|
||||
const QVector<Option> &tlOpts) -> Data::PremiumSubscriptionOptions {
|
||||
if (tlOpts.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
auto result = Data::SubscriptionOptions();
|
||||
auto result = Data::PremiumSubscriptionOptions();
|
||||
const auto monthlyAmount = [&] {
|
||||
const auto &min = ranges::min_element(
|
||||
tlOptions,
|
||||
tlOpts,
|
||||
ranges::less(),
|
||||
[](const Option &o) { return o.data().vamount().v; }
|
||||
)->data();
|
||||
return min.vamount().v / float64(min.vmonths().v);
|
||||
}();
|
||||
result.reserve(tlOptions.size());
|
||||
for (const auto &tlOption : tlOptions) {
|
||||
result.reserve(tlOpts.size());
|
||||
for (const auto &tlOption : tlOpts) {
|
||||
const auto &option = tlOption.data();
|
||||
auto botUrl = QString();
|
||||
if constexpr (!std::is_same_v<Option, MTPPremiumGiftCodeOption>) {
|
||||
|
||||
@@ -41,14 +41,17 @@ void InnerFillMessagePostFlags(
|
||||
const SendOptions &options,
|
||||
not_null<PeerData*> peer,
|
||||
MessageFlags &flags) {
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
if (ShouldSendSilent(peer, options)) {
|
||||
flags |= MessageFlag::Silent;
|
||||
}
|
||||
if (!anonymousPost || options.sendAs) {
|
||||
if (!peer->amAnonymous()
|
||||
|| (!peer->isBroadcast()
|
||||
&& options.sendAs
|
||||
&& options.sendAs != peer)) {
|
||||
flags |= MessageFlag::HasFromId;
|
||||
return;
|
||||
} else if (peer->asMegagroup()) {
|
||||
}
|
||||
const auto channel = peer->asBroadcast();
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
flags |= MessageFlag::Post;
|
||||
@@ -57,11 +60,84 @@ void InnerFillMessagePostFlags(
|
||||
return;
|
||||
}
|
||||
flags |= MessageFlag::HasViews;
|
||||
if (peer->asChannel()->addsSignature()) {
|
||||
if (channel->addsSignature()) {
|
||||
flags |= MessageFlag::HasPostAuthor;
|
||||
}
|
||||
}
|
||||
|
||||
void SendSimpleMedia(SendAction action, MTPInputMedia inputMedia) {
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
const auto session = &history->session();
|
||||
const auto api = &session->api();
|
||||
|
||||
action.clearDraft = false;
|
||||
action.generateLocal = false;
|
||||
api->sendAction(action);
|
||||
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
|
||||
auto flags = NewMessageFlags(peer);
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (action.replyTo) {
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||
}
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
InnerFillMessagePostFlags(action.options, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
const auto sendAs = action.options.sendAs;
|
||||
if (sendAs) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
}
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? session->user()->name()
|
||||
: QString();
|
||||
|
||||
if (action.options.scheduled) {
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
}
|
||||
if (action.options.shortcutId) {
|
||||
flags |= MessageFlag::ShortcutMessage;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
|
||||
}
|
||||
if (action.options.effectId) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
}
|
||||
if (action.options.invertCaption) {
|
||||
flags |= MessageFlag::InvertMedia;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
||||
}
|
||||
|
||||
auto &histories = history->owner().histories();
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
action.replyTo,
|
||||
randomId,
|
||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
Data::Histories::ReplyToPlaceholder(),
|
||||
std::move(inputMedia),
|
||||
MTPstring(),
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
MTPvector<MTPMessageEntity>(),
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
||||
MTP_long(action.options.effectId)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
api->sendMessageFail(error, peer, randomId);
|
||||
});
|
||||
|
||||
api->finishForwarding(action);
|
||||
}
|
||||
|
||||
template <typename MediaData>
|
||||
void SendExistingMedia(
|
||||
MessageToSend &&message,
|
||||
@@ -92,25 +168,15 @@ void SendExistingMedia(
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
InnerFillMessagePostFlags(action.options, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
const auto sendAs = action.options.sendAs;
|
||||
const auto messageFromId = sendAs
|
||||
? sendAs->id
|
||||
: anonymousPost
|
||||
? 0
|
||||
: session->userPeerId();
|
||||
if (sendAs) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
}
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? session->user()->name()
|
||||
: QString();
|
||||
|
||||
auto caption = TextWithEntities{
|
||||
message.textWithTags.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(message.textWithTags.tags)
|
||||
@@ -146,11 +212,11 @@ void SendExistingMedia(
|
||||
history->addNewLocalMessage({
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = messageFromId,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = action.replyTo,
|
||||
.date = HistoryItem::NewMessageDate(action.options),
|
||||
.date = NewMessageDate(action.options),
|
||||
.shortcutId = action.options.shortcutId,
|
||||
.postAuthor = messagePostAuthor,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
}, media, caption);
|
||||
|
||||
@@ -288,25 +354,15 @@ bool SendDice(MessageToSend &message) {
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
InnerFillMessagePostFlags(action.options, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
const auto sendAs = action.options.sendAs;
|
||||
const auto messageFromId = sendAs
|
||||
? sendAs->id
|
||||
: anonymousPost
|
||||
? 0
|
||||
: session->userPeerId();
|
||||
if (sendAs) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
}
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? session->user()->name()
|
||||
: QString();
|
||||
|
||||
if (action.options.scheduled) {
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
@@ -328,11 +384,11 @@ bool SendDice(MessageToSend &message) {
|
||||
history->addNewLocalMessage({
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = messageFromId,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = action.replyTo,
|
||||
.date = HistoryItem::NewMessageDate(action.options),
|
||||
.date = NewMessageDate(action.options),
|
||||
.shortcutId = action.options.shortcutId,
|
||||
.postAuthor = messagePostAuthor,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
}, TextWithEntities(), MTP_messageMediaDice(
|
||||
MTP_int(0),
|
||||
@@ -362,6 +418,33 @@ bool SendDice(MessageToSend &message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SendLocation(SendAction action, float64 lat, float64 lon) {
|
||||
SendSimpleMedia(
|
||||
action,
|
||||
MTP_inputMediaGeoPoint(
|
||||
MTP_inputGeoPoint(
|
||||
MTP_flags(0),
|
||||
MTP_double(lat),
|
||||
MTP_double(lon),
|
||||
MTPint()))); // accuracy_radius
|
||||
}
|
||||
|
||||
void SendVenue(SendAction action, Data::InputVenue venue) {
|
||||
SendSimpleMedia(
|
||||
action,
|
||||
MTP_inputMediaVenue(
|
||||
MTP_inputGeoPoint(
|
||||
MTP_flags(0),
|
||||
MTP_double(venue.lat),
|
||||
MTP_double(venue.lon),
|
||||
MTPint()), // accuracy_radius
|
||||
MTP_string(venue.title),
|
||||
MTP_string(venue.address),
|
||||
MTP_string(venue.provider),
|
||||
MTP_string(venue.id),
|
||||
MTP_string(venue.venueType)));
|
||||
}
|
||||
|
||||
void FillMessagePostFlags(
|
||||
const SendAction &action,
|
||||
not_null<PeerData*> peer,
|
||||
@@ -429,7 +512,6 @@ void SendConfirmedFile(
|
||||
if (file->to.replyTo) {
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (file->to.options.scheduled) {
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
@@ -451,16 +533,6 @@ void SendConfirmedFile(
|
||||
if (file->to.options.invertCaption) {
|
||||
flags |= MessageFlag::InvertMedia;
|
||||
}
|
||||
|
||||
const auto messageFromId = file->to.options.sendAs
|
||||
? file->to.options.sendAs->id
|
||||
: anonymousPost
|
||||
? PeerId()
|
||||
: session->userPeerId();
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? session->user()->name()
|
||||
: QString();
|
||||
|
||||
const auto media = MTPMessageMedia([&] {
|
||||
if (file->type == SendMediaType::Photo) {
|
||||
using Flag = MTPDmessageMediaPhoto::Flag;
|
||||
@@ -526,11 +598,11 @@ void SendConfirmedFile(
|
||||
history->addNewLocalMessage({
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = messageFromId,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = file->to.replyTo,
|
||||
.date = HistoryItem::NewMessageDate(file->to.options),
|
||||
.date = NewMessageDate(file->to.options),
|
||||
.shortcutId = file->to.options.shortcutId,
|
||||
.postAuthor = messagePostAuthor,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.groupedId = groupId,
|
||||
.effectId = file->to.options.effectId,
|
||||
}, caption, media);
|
||||
|
||||
@@ -7,15 +7,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
class History;
|
||||
class PhotoData;
|
||||
class DocumentData;
|
||||
struct FilePrepareResult;
|
||||
|
||||
namespace Data {
|
||||
struct InputVenue;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct MessageToSend;
|
||||
@@ -33,6 +37,13 @@ void SendExistingPhoto(
|
||||
|
||||
bool SendDice(MessageToSend &message);
|
||||
|
||||
// We can't create Data::LocationPoint() and use it
|
||||
// for a local sending message, because we can't request
|
||||
// map thumbnail in messages history without access hash.
|
||||
void SendLocation(SendAction action, float64 lat, float64 lon);
|
||||
|
||||
void SendVenue(SendAction action, Data::InputVenue venue);
|
||||
|
||||
void FillMessagePostFlags(
|
||||
const SendAction &action,
|
||||
not_null<PeerData*> peer,
|
||||
|
||||
@@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kRefreshAppConfigTimeout = 3 * crl::time(1000);
|
||||
constexpr auto kRefreshAppConfigTimeout = crl::time(1);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -24,19 +24,40 @@ SensitiveContent::SensitiveContent(not_null<ApiWrap*> api)
|
||||
, _appConfigReloadTimer([=] { _session->appConfig().refresh(); }) {
|
||||
}
|
||||
|
||||
void SensitiveContent::reload() {
|
||||
if (_requestId) {
|
||||
void SensitiveContent::preload() {
|
||||
if (!_loaded) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
void SensitiveContent::reload(bool force) {
|
||||
if (_loadRequestId) {
|
||||
if (force) {
|
||||
_loadPending = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
_requestId = _api.request(MTPaccount_GetContentSettings(
|
||||
_loaded = true;
|
||||
_loadRequestId = _api.request(MTPaccount_GetContentSettings(
|
||||
)).done([=](const MTPaccount_ContentSettings &result) {
|
||||
_requestId = 0;
|
||||
result.match([&](const MTPDaccount_contentSettings &data) {
|
||||
_enabled = data.is_sensitive_enabled();
|
||||
_canChange = data.is_sensitive_can_change();
|
||||
});
|
||||
_loadRequestId = 0;
|
||||
const auto &data = result.data();
|
||||
const auto enabled = data.is_sensitive_enabled();
|
||||
const auto canChange = data.is_sensitive_can_change();
|
||||
const auto changed = (_enabled.current() != enabled)
|
||||
|| (_canChange.current() != canChange);
|
||||
if (changed) {
|
||||
_enabled = enabled;
|
||||
_canChange = canChange;
|
||||
}
|
||||
if (base::take(_appConfigReloadForce) || changed) {
|
||||
_appConfigReloadTimer.callOnce(kRefreshAppConfigTimeout);
|
||||
}
|
||||
if (base::take(_loadPending)) {
|
||||
reload();
|
||||
}
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
_loadRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -57,17 +78,24 @@ void SensitiveContent::update(bool enabled) {
|
||||
return;
|
||||
}
|
||||
using Flag = MTPaccount_SetContentSettings::Flag;
|
||||
_api.request(_requestId).cancel();
|
||||
_requestId = _api.request(MTPaccount_SetContentSettings(
|
||||
_api.request(_saveRequestId).cancel();
|
||||
if (const auto load = base::take(_loadRequestId)) {
|
||||
_api.request(load).cancel();
|
||||
_loadPending = true;
|
||||
}
|
||||
const auto finish = [=] {
|
||||
_saveRequestId = 0;
|
||||
if (base::take(_loadPending)) {
|
||||
_appConfigReloadForce = true;
|
||||
reload(true);
|
||||
} else {
|
||||
_appConfigReloadTimer.callOnce(kRefreshAppConfigTimeout);
|
||||
}
|
||||
};
|
||||
_saveRequestId = _api.request(MTPaccount_SetContentSettings(
|
||||
MTP_flags(enabled ? Flag::f_sensitive_enabled : Flag(0))
|
||||
)).done([=] {
|
||||
_requestId = 0;
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
)).done(finish).fail(finish).send();
|
||||
_enabled = enabled;
|
||||
|
||||
_appConfigReloadTimer.callOnce(kRefreshAppConfigTimeout);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -22,7 +22,8 @@ class SensitiveContent final {
|
||||
public:
|
||||
explicit SensitiveContent(not_null<ApiWrap*> api);
|
||||
|
||||
void reload();
|
||||
void preload();
|
||||
void reload(bool force = false);
|
||||
void update(bool enabled);
|
||||
|
||||
[[nodiscard]] bool enabledCurrent() const;
|
||||
@@ -32,10 +33,14 @@ public:
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _requestId = 0;
|
||||
mtpRequestId _loadRequestId = 0;
|
||||
mtpRequestId _saveRequestId = 0;
|
||||
rpl::variable<bool> _enabled = false;
|
||||
rpl::variable<bool> _canChange = false;
|
||||
base::Timer _appConfigReloadTimer;
|
||||
bool _appConfigReloadForce = false;
|
||||
bool _loadPending = false;
|
||||
bool _loaded = false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -571,13 +571,22 @@ rpl::producer<rpl::no_value, QString> Boosts::request() {
|
||||
_boostStatus.prepaidGiveaway = ranges::views::all(
|
||||
data.vprepaid_giveaways()->v
|
||||
) | ranges::views::transform([](const MTPPrepaidGiveaway &r) {
|
||||
return Data::BoostPrepaidGiveaway{
|
||||
.months = r.data().vmonths().v,
|
||||
.id = r.data().vid().v,
|
||||
.quantity = r.data().vquantity().v,
|
||||
.date = QDateTime::fromSecsSinceEpoch(
|
||||
r.data().vdate().v),
|
||||
};
|
||||
return r.match([&](const MTPDprepaidGiveaway &data) {
|
||||
return Data::BoostPrepaidGiveaway{
|
||||
.date = base::unixtime::parse(data.vdate().v),
|
||||
.id = data.vid().v,
|
||||
.months = data.vmonths().v,
|
||||
.quantity = data.vquantity().v,
|
||||
};
|
||||
}, [&](const MTPDprepaidStarsGiveaway &data) {
|
||||
return Data::BoostPrepaidGiveaway{
|
||||
.date = base::unixtime::parse(data.vdate().v),
|
||||
.id = data.vid().v,
|
||||
.credits = data.vstars().v,
|
||||
.quantity = data.vquantity().v,
|
||||
.boosts = data.vboosts().v,
|
||||
};
|
||||
});
|
||||
}) | ranges::to_vector;
|
||||
}
|
||||
|
||||
@@ -635,19 +644,21 @@ void Boosts::requestBoosts(
|
||||
}
|
||||
: Data::GiftCodeLink();
|
||||
list.push_back({
|
||||
data.is_gift(),
|
||||
data.is_giveaway(),
|
||||
data.is_unclaimed(),
|
||||
qs(data.vid()),
|
||||
data.vuser_id().value_or_empty(),
|
||||
data.vgiveaway_msg_id()
|
||||
.id = qs(data.vid()),
|
||||
.userId = UserId(data.vuser_id().value_or_empty()),
|
||||
.giveawayMessage = data.vgiveaway_msg_id()
|
||||
? FullMsgId{ _peer->id, data.vgiveaway_msg_id()->v }
|
||||
: FullMsgId(),
|
||||
QDateTime::fromSecsSinceEpoch(data.vdate().v),
|
||||
QDateTime::fromSecsSinceEpoch(data.vexpires().v),
|
||||
(data.vexpires().v - data.vdate().v) / kMonthsDivider,
|
||||
std::move(giftCodeLink),
|
||||
data.vmultiplier().value_or_empty(),
|
||||
.date = base::unixtime::parse(data.vdate().v),
|
||||
.expiresAt = base::unixtime::parse(data.vexpires().v),
|
||||
.expiresAfterMonths = ((data.vexpires().v - data.vdate().v)
|
||||
/ kMonthsDivider),
|
||||
.giftCodeLink = std::move(giftCodeLink),
|
||||
.multiplier = data.vmultiplier().value_or_empty(),
|
||||
.credits = data.vstars().value_or_empty(),
|
||||
.isGift = data.is_gift(),
|
||||
.isGiveaway = data.is_giveaway(),
|
||||
.isUnclaimed = data.is_unclaimed(),
|
||||
});
|
||||
}
|
||||
done(Data::BoostsListSlice{
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_authorizations.h"
|
||||
#include "api/api_user_names.h"
|
||||
#include "api/api_chat_participants.h"
|
||||
#include "api/api_global_privacy.h"
|
||||
#include "api/api_ringtones.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
@@ -21,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "mtproto/mtproto_dc_options.h"
|
||||
#include "data/business/data_shortcut_messages.h"
|
||||
#include "data/components/credits.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/components/top_peers.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
@@ -2618,7 +2620,13 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
case mtpc_updateStarsBalance: {
|
||||
const auto &data = update.c_updateStarsBalance();
|
||||
_session->setCredits(data.vbalance().v);
|
||||
_session->credits().apply(data);
|
||||
} break;
|
||||
|
||||
case mtpc_updatePaidReactionPrivacy: {
|
||||
const auto &data = update.c_updatePaidReactionPrivacy();
|
||||
_session->api().globalPrivacy().updatePaidReactionAnonymous(
|
||||
mtpIsTrue(data.vprivate()));
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
@@ -214,7 +214,10 @@ struct State {
|
||||
|
||||
[[nodiscard]] QImage GenerateUserpic(Userpic &userpic, int size) {
|
||||
size *= style::DevicePixelRatio();
|
||||
auto result = userpic.peer->generateUserpicImage(userpic.view, size);
|
||||
auto result = PeerData::GenerateUserpicImage(
|
||||
userpic.peer,
|
||||
userpic.view,
|
||||
size);
|
||||
result.setDevicePixelRatio(style::DevicePixelRatio());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2585,7 +2585,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &resu
|
||||
void ApiWrap::updateStickers() {
|
||||
const auto now = crl::now();
|
||||
requestStickers(now);
|
||||
requestRecentStickers(now);
|
||||
requestRecentStickers(now, false);
|
||||
requestFavedStickers(now);
|
||||
requestFeaturedStickers(now);
|
||||
}
|
||||
@@ -2607,8 +2607,15 @@ void ApiWrap::updateCustomEmoji() {
|
||||
requestFeaturedEmoji(now);
|
||||
}
|
||||
|
||||
void ApiWrap::requestRecentStickersForce(bool attached) {
|
||||
requestRecentStickersWithHash(0, attached);
|
||||
void ApiWrap::requestSpecialStickersForce(
|
||||
bool faved,
|
||||
bool recent,
|
||||
bool attached) {
|
||||
if (faved) {
|
||||
requestFavedStickers(std::nullopt);
|
||||
} else if (recent || attached) {
|
||||
requestRecentStickers(std::nullopt, attached);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::setGroupStickerSet(
|
||||
@@ -2761,18 +2768,17 @@ void ApiWrap::requestCustomEmoji(TimeId now) {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::requestRecentStickers(TimeId now, bool attached) {
|
||||
const auto needed = attached
|
||||
? _session->data().stickers().recentAttachedUpdateNeeded(now)
|
||||
: _session->data().stickers().recentUpdateNeeded(now);
|
||||
void ApiWrap::requestRecentStickers(
|
||||
std::optional<TimeId> now,
|
||||
bool attached) {
|
||||
const auto needed = !now
|
||||
? true
|
||||
: attached
|
||||
? _session->data().stickers().recentAttachedUpdateNeeded(*now)
|
||||
: _session->data().stickers().recentUpdateNeeded(*now);
|
||||
if (!needed) {
|
||||
return;
|
||||
}
|
||||
requestRecentStickersWithHash(
|
||||
Api::CountRecentStickersHash(_session, attached), attached);
|
||||
}
|
||||
|
||||
void ApiWrap::requestRecentStickersWithHash(uint64 hash, bool attached) {
|
||||
const auto requestId = [=]() -> mtpRequestId & {
|
||||
return attached
|
||||
? _recentAttachedStickersUpdateRequest
|
||||
@@ -2795,7 +2801,7 @@ void ApiWrap::requestRecentStickersWithHash(uint64 hash, bool attached) {
|
||||
: MTPmessages_getRecentStickers::Flags(0);
|
||||
requestId() = request(MTPmessages_GetRecentStickers(
|
||||
MTP_flags(flags),
|
||||
MTP_long(hash)
|
||||
MTP_long(now ? Api::CountRecentStickersHash(_session, attached) : 0)
|
||||
)).done([=](const MTPmessages_RecentStickers &result) {
|
||||
finish();
|
||||
|
||||
@@ -2822,13 +2828,15 @@ void ApiWrap::requestRecentStickersWithHash(uint64 hash, bool attached) {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::requestFavedStickers(TimeId now) {
|
||||
if (!_session->data().stickers().favedUpdateNeeded(now)
|
||||
|| _favedStickersUpdateRequest) {
|
||||
return;
|
||||
void ApiWrap::requestFavedStickers(std::optional<TimeId> now) {
|
||||
if (now) {
|
||||
if (!_session->data().stickers().favedUpdateNeeded(*now)
|
||||
|| _favedStickersUpdateRequest) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_favedStickersUpdateRequest = request(MTPmessages_GetFavedStickers(
|
||||
MTP_long(Api::CountFavedStickersHash(_session))
|
||||
MTP_long(now ? Api::CountFavedStickersHash(_session) : 0)
|
||||
)).done([=](const MTPmessages_FavedStickers &result) {
|
||||
_session->data().stickers().setLastFavedUpdate(crl::now());
|
||||
_favedStickersUpdateRequest = 0;
|
||||
@@ -3274,9 +3282,8 @@ void ApiWrap::forwardMessages(
|
||||
if (!action.options.scheduled && !action.options.shortcutId) {
|
||||
histories.readInbox(history);
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
const auto sendAs = action.options.sendAs;
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
|
||||
using SendFlag = MTPmessages_ForwardMessages::Flag;
|
||||
auto flags = MessageFlags();
|
||||
@@ -3367,23 +3374,14 @@ void ApiWrap::forwardMessages(
|
||||
const auto newId = FullMsgId(
|
||||
peer->id,
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto self = _session->user();
|
||||
const auto messageFromId = sendAs
|
||||
? sendAs->id
|
||||
: anonymousPost
|
||||
? PeerId(0)
|
||||
: self->id;
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? self->name()
|
||||
: QString();
|
||||
history->addNewLocalMessage({
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = messageFromId,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = { .topicRootId = topMsgId },
|
||||
.date = HistoryItem::NewMessageDate(action.options),
|
||||
.date = NewMessageDate(action.options),
|
||||
.shortcutId = action.options.shortcutId,
|
||||
.postAuthor = messagePostAuthor,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
|
||||
// forwarded messages don't have effects
|
||||
//.effectId = action.options.effectId,
|
||||
@@ -3458,8 +3456,6 @@ void ApiWrap::sendSharedContact(
|
||||
const auto newId = FullMsgId(
|
||||
peer->id,
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
|
||||
auto flags = NewMessageFlags(peer);
|
||||
if (action.replyTo) {
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
@@ -3471,22 +3467,14 @@ void ApiWrap::sendSharedContact(
|
||||
if (action.options.shortcutId) {
|
||||
flags |= MessageFlag::ShortcutMessage;
|
||||
}
|
||||
const auto messageFromId = action.options.sendAs
|
||||
? action.options.sendAs->id
|
||||
: anonymousPost
|
||||
? PeerId()
|
||||
: _session->userPeerId();
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? _session->user()->name()
|
||||
: QString();
|
||||
const auto item = history->addNewLocalMessage({
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = messageFromId,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = action.replyTo,
|
||||
.date = HistoryItem::NewMessageDate(action.options),
|
||||
.date = NewMessageDate(action.options),
|
||||
.shortcutId = action.options.shortcutId,
|
||||
.postAuthor = messagePostAuthor,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
}, TextWithEntities(), MTP_messageMediaContact(
|
||||
MTP_string(phone),
|
||||
@@ -3772,7 +3760,6 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
MTP_string(fields.url),
|
||||
MTP_int(page->pendingTill)));
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if ((exactWebPage && !ignoreWebPage && message.webPage.invert)
|
||||
@@ -3800,18 +3787,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
history->startSavingCloudDraft(draftTopicRootId);
|
||||
}
|
||||
const auto sendAs = action.options.sendAs;
|
||||
const auto messageFromId = sendAs
|
||||
? sendAs->id
|
||||
: anonymousPost
|
||||
? PeerId()
|
||||
: _session->userPeerId();
|
||||
if (sendAs) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_send_as;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
}
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? _session->user()->name()
|
||||
: QString();
|
||||
if (action.options.scheduled) {
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
||||
@@ -3829,11 +3808,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
lastMessage = history->addNewLocalMessage({
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = messageFromId,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = action.replyTo,
|
||||
.date = HistoryItem::NewMessageDate(action.options),
|
||||
.date = NewMessageDate(action.options),
|
||||
.shortcutId = action.options.shortcutId,
|
||||
.postAuthor = messagePostAuthor,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
}, sending, media);
|
||||
const auto done = [=](
|
||||
@@ -3979,7 +3958,6 @@ void ApiWrap::sendInlineResult(
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= SendFlag::f_reply_to;
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
@@ -3998,30 +3976,22 @@ void ApiWrap::sendInlineResult(
|
||||
}
|
||||
|
||||
const auto sendAs = action.options.sendAs;
|
||||
const auto messageFromId = sendAs
|
||||
? sendAs->id
|
||||
: anonymousPost ? PeerId()
|
||||
: _session->userPeerId();
|
||||
if (sendAs) {
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_send_as;
|
||||
}
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? _session->user()->name()
|
||||
: QString();
|
||||
|
||||
_session->data().registerMessageRandomId(randomId, newId);
|
||||
|
||||
data->addToHistory(history, {
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = messageFromId,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = action.replyTo,
|
||||
.date = HistoryItem::NewMessageDate(action.options),
|
||||
.date = NewMessageDate(action.options),
|
||||
.shortcutId = action.options.shortcutId,
|
||||
.viaBotId = ((bot && !action.options.hideViaBot)
|
||||
? peerToUser(bot->id)
|
||||
: UserId()),
|
||||
.postAuthor = messagePostAuthor,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
});
|
||||
|
||||
history->clearCloudDraft(topicRootId);
|
||||
@@ -4190,8 +4160,10 @@ void ApiWrap::sendMediaWithRandomId(
|
||||
Data::Histories::ReplyToPlaceholder(),
|
||||
(options.price
|
||||
? MTPInputMedia(MTP_inputMediaPaidMedia(
|
||||
MTP_flags(0),
|
||||
MTP_long(options.price),
|
||||
MTP_vector<MTPInputMedia>(1, media)))
|
||||
MTP_vector<MTPInputMedia>(1, media),
|
||||
MTPstring()))
|
||||
: media),
|
||||
MTP_string(caption.text),
|
||||
MTP_long(randomId),
|
||||
@@ -4204,7 +4176,7 @@ void ApiWrap::sendMediaWithRandomId(
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (done) done(true);
|
||||
if (updateRecentStickers) {
|
||||
requestRecentStickersForce(true);
|
||||
requestRecentStickers(std::nullopt, true);
|
||||
}
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
if (done) done(false);
|
||||
@@ -4262,8 +4234,10 @@ void ApiWrap::sendMultiPaidMedia(
|
||||
peer->input,
|
||||
Data::Histories::ReplyToPlaceholder(),
|
||||
MTP_inputMediaPaidMedia(
|
||||
MTP_flags(0),
|
||||
MTP_long(options.price),
|
||||
MTP_vector<MTPInputMedia>(std::move(medias))),
|
||||
MTP_vector<MTPInputMedia>(std::move(medias)),
|
||||
MTPstring()),
|
||||
MTP_string(caption.text),
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
|
||||
@@ -244,7 +244,10 @@ public:
|
||||
void updateSavedGifs();
|
||||
void updateMasks();
|
||||
void updateCustomEmoji();
|
||||
void requestRecentStickersForce(bool attached = false);
|
||||
void requestSpecialStickersForce(
|
||||
bool faved,
|
||||
bool recent,
|
||||
bool attached);
|
||||
void setGroupStickerSet(
|
||||
not_null<ChannelData*> megagroup,
|
||||
const StickerSetIdentifier &set);
|
||||
@@ -477,9 +480,10 @@ private:
|
||||
void requestStickers(TimeId now);
|
||||
void requestMasks(TimeId now);
|
||||
void requestCustomEmoji(TimeId now);
|
||||
void requestRecentStickers(TimeId now, bool attached = false);
|
||||
void requestRecentStickersWithHash(uint64 hash, bool attached = false);
|
||||
void requestFavedStickers(TimeId now);
|
||||
void requestRecentStickers(
|
||||
std::optional<TimeId> now,
|
||||
bool attached);
|
||||
void requestFavedStickers(std::optional<TimeId> now);
|
||||
void requestFeaturedStickers(TimeId now);
|
||||
void requestFeaturedEmoji(TimeId now);
|
||||
void requestSavedGifs(TimeId now);
|
||||
|
||||
@@ -100,6 +100,8 @@ void AboutBox::showVersionHistory() {
|
||||
url += u"win/%1.zip"_q;
|
||||
} else if (Platform::IsWindows64Bit()) {
|
||||
url += u"win64/%1.zip"_q;
|
||||
} else if (Platform::IsWindowsARM64()) {
|
||||
url += u"winarm/%1.zip"_q;
|
||||
} else if (Platform::IsMac()) {
|
||||
url += u"mac/%1.zip"_q;
|
||||
} else if (Platform::IsLinux()) {
|
||||
@@ -155,6 +157,8 @@ QString currentVersionText() {
|
||||
}
|
||||
if (Platform::IsWindows64Bit()) {
|
||||
result += " x64";
|
||||
} else if (Platform::IsWindowsARM64()) {
|
||||
result += " arm64";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -217,7 +217,9 @@ void ShowAddParticipantsError(
|
||||
channel,
|
||||
user,
|
||||
ChatAdminRightsInfo(),
|
||||
QString());
|
||||
QString(),
|
||||
0,
|
||||
nullptr);
|
||||
box->setSaveCallback(saveCallback);
|
||||
*weak = box.data();
|
||||
show->showBox(std::move(box));
|
||||
@@ -898,9 +900,10 @@ void GroupInfoBox::checkInviteLink() {
|
||||
channelReady();
|
||||
} else if (_createdChannel->isFullLoaded() && !_creatingInviteLink) {
|
||||
_creatingInviteLink = true;
|
||||
_createdChannel->session().api().inviteLinks().create(
|
||||
_createdChannel->session().api().inviteLinks().create({
|
||||
_createdChannel,
|
||||
crl::guard(this, [=](auto&&) { channelReady(); }));
|
||||
crl::guard(this, [=](auto&&) { channelReady(); }),
|
||||
});
|
||||
} else {
|
||||
_createdChannel->session().changes().peerUpdates(
|
||||
_createdChannel,
|
||||
@@ -1243,7 +1246,7 @@ void SetupChannelBox::mousePressEvent(QMouseEvent *e) {
|
||||
showToast(tr::lng_create_channel_link_copied(tr::now));
|
||||
} else if (_channel->isFullLoaded() && !_creatingInviteLink) {
|
||||
_creatingInviteLink = true;
|
||||
_channel->session().api().inviteLinks().create(_channel);
|
||||
_channel->session().api().inviteLinks().create({ _channel });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -597,8 +597,6 @@ rightsHeaderLabel: FlatLabel(boxLabel) {
|
||||
}
|
||||
textFg: windowActiveTextFg;
|
||||
}
|
||||
rightsUntilMargin: margins(0px, 8px, 0px, 20px);
|
||||
rightsRankMargin: margins(0px, 7px, 0px, 20px);
|
||||
|
||||
groupStickersRemove: defaultMultiSelectSearchCancel;
|
||||
groupStickersRemovePosition: point(6px, 6px);
|
||||
@@ -756,6 +754,8 @@ createPollWarningPosition: point(16px, 6px);
|
||||
createPollCheckboxMargin: margins(22px, 10px, 22px, 10px);
|
||||
createPollFieldTitlePadding: margins(22px, 7px, 10px, 6px);
|
||||
|
||||
sendGifWithCaptionEmojiPosition: point(-30px, 23px);
|
||||
|
||||
backgroundCheckbox: Checkbox(defaultCheckbox) {
|
||||
textFg: msgServiceFg;
|
||||
textFgActive: msgServiceFg;
|
||||
@@ -785,7 +785,7 @@ backgroundConfirmPadding: margins(24px, 16px, 24px, 16px);
|
||||
backgroundConfirm: RoundButton(defaultActiveButton) {
|
||||
height: 44px;
|
||||
textTop: 12px;
|
||||
font: font(13px semibold);
|
||||
style: semiboldTextStyle;
|
||||
}
|
||||
backgroundConfirmCancel: RoundButton(backgroundConfirm) {
|
||||
textFg: mediaviewSaveMsgFg;
|
||||
@@ -797,7 +797,7 @@ backgroundConfirmCancel: RoundButton(backgroundConfirm) {
|
||||
|
||||
height: 44px;
|
||||
textTop: 12px;
|
||||
font: font(13px semibold);
|
||||
style: semiboldTextStyle;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: shadowFg;
|
||||
@@ -949,7 +949,7 @@ sponsoredUrlButton: RoundButton(defaultActiveButton) {
|
||||
textFg: historyLinkInFg;
|
||||
textFgOver: historyLinkInFg;
|
||||
textTop: 7px;
|
||||
font: normalFont;
|
||||
style: defaultTextStyle;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
@@ -1120,3 +1120,10 @@ moderateBoxDividerLabel: FlatLabel(boxDividerLabel) {
|
||||
selectLinkFg: windowActiveTextFg;
|
||||
}
|
||||
}
|
||||
|
||||
profileQrFont: font(fsize bold);
|
||||
profileQrCenterSize: 34px;
|
||||
profileQrBackgroundRadius: 12px;
|
||||
profileQrIcon: icon{{ "qr_mini", windowActiveTextFg }};
|
||||
profileQrBackgroundMargins: margins(36px, 12px, 36px, 12px);
|
||||
profileQrBackgroundPadding: margins(0px, 24px, 0px, 24px);
|
||||
|
||||
@@ -39,6 +39,7 @@ Data::ChatFilter ChangedFilter(
|
||||
filter.id(),
|
||||
filter.title(),
|
||||
filter.iconEmoji(),
|
||||
filter.colorIndex(),
|
||||
filter.flags(),
|
||||
std::move(always),
|
||||
filter.pinned(),
|
||||
@@ -58,6 +59,7 @@ Data::ChatFilter ChangedFilter(
|
||||
filter.id(),
|
||||
filter.title(),
|
||||
filter.iconEmoji(),
|
||||
filter.colorIndex(),
|
||||
filter.flags(),
|
||||
std::move(always),
|
||||
filter.pinned(),
|
||||
|
||||
@@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "boxes/abstract_box.h" // Ui::show().
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "menu/menu_send.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
#include "ui/controls/emoji_button_factory.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
@@ -37,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h" // defaultComposeFiles.
|
||||
@@ -54,100 +56,6 @@ constexpr auto kSolutionLimit = 200;
|
||||
constexpr auto kWarnSolutionLimit = 60;
|
||||
constexpr auto kErrorLimit = 99;
|
||||
|
||||
[[nodiscard]] not_null<Ui::EmojiButton*> AddEmojiToggleToField(
|
||||
not_null<Ui::InputField*> field,
|
||||
not_null<Ui::BoxContent*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<ChatHelpers::TabbedPanel*> emojiPanel,
|
||||
QPoint shift) {
|
||||
const auto emojiToggle = Ui::CreateChild<Ui::EmojiButton>(
|
||||
field->parentWidget(),
|
||||
st::defaultComposeFiles.emoji);
|
||||
const auto fade = Ui::CreateChild<Ui::FadeAnimation>(
|
||||
emojiToggle,
|
||||
emojiToggle,
|
||||
0.5);
|
||||
{
|
||||
const auto fadeTarget = Ui::CreateChild<Ui::RpWidget>(emojiToggle);
|
||||
fadeTarget->resize(emojiToggle->size());
|
||||
fadeTarget->paintRequest(
|
||||
) | rpl::start_with_next([=](const QRect &rect) {
|
||||
auto p = QPainter(fadeTarget);
|
||||
if (fade->animating()) {
|
||||
p.fillRect(fadeTarget->rect(), st::boxBg);
|
||||
}
|
||||
fade->paint(p);
|
||||
}, fadeTarget->lifetime());
|
||||
rpl::single(false) | rpl::then(
|
||||
field->focusedChanges()
|
||||
) | rpl::start_with_next([=](bool shown) {
|
||||
if (shown) {
|
||||
fade->fadeIn(st::universalDuration);
|
||||
} else {
|
||||
fade->fadeOut(st::universalDuration);
|
||||
}
|
||||
}, emojiToggle->lifetime());
|
||||
fade->fadeOut(1);
|
||||
fade->finish();
|
||||
}
|
||||
|
||||
|
||||
const auto outer = box->getDelegate()->outerContainer();
|
||||
const auto allow = [](not_null<DocumentData*>) { return true; };
|
||||
InitMessageFieldHandlers(
|
||||
controller,
|
||||
field,
|
||||
Window::GifPauseReason::Layer,
|
||||
allow);
|
||||
Ui::Emoji::SuggestionsController::Init(
|
||||
outer,
|
||||
field,
|
||||
&controller->session(),
|
||||
Ui::Emoji::SuggestionsController::Options{
|
||||
.suggestCustomEmoji = true,
|
||||
.allowCustomWithoutPremium = allow,
|
||||
});
|
||||
const auto updateEmojiPanelGeometry = [=] {
|
||||
const auto parent = emojiPanel->parentWidget();
|
||||
const auto global = emojiToggle->mapToGlobal({ 0, 0 });
|
||||
const auto local = parent->mapFromGlobal(global);
|
||||
const auto right = local.x() + emojiToggle->width() * 3;
|
||||
const auto isDropDown = local.y() < parent->height() / 2;
|
||||
emojiPanel->setDropDown(isDropDown);
|
||||
if (isDropDown) {
|
||||
emojiPanel->moveTopRight(
|
||||
local.y() + emojiToggle->height(),
|
||||
right);
|
||||
} else {
|
||||
emojiPanel->moveBottomRight(local.y(), right);
|
||||
}
|
||||
};
|
||||
rpl::combine(
|
||||
box->sizeValue(),
|
||||
field->geometryValue()
|
||||
) | rpl::start_with_next([=](QSize outer, QRect inner) {
|
||||
emojiToggle->moveToLeft(
|
||||
rect::right(inner) + shift.x(),
|
||||
inner.y() + shift.y());
|
||||
emojiToggle->update();
|
||||
}, emojiToggle->lifetime());
|
||||
|
||||
emojiToggle->installEventFilter(emojiPanel);
|
||||
emojiToggle->addClickHandler([=] {
|
||||
updateEmojiPanelGeometry();
|
||||
emojiPanel->toggleAnimated();
|
||||
});
|
||||
const auto filterCallback = [=](not_null<QEvent*> event) {
|
||||
if (event->type() == QEvent::Enter) {
|
||||
updateEmojiPanelGeometry();
|
||||
}
|
||||
return base::EventFilterResult::Continue;
|
||||
};
|
||||
base::install_event_filter(emojiToggle, filterCallback);
|
||||
|
||||
return emojiToggle;
|
||||
}
|
||||
|
||||
class Options {
|
||||
public:
|
||||
Options(
|
||||
@@ -770,7 +678,7 @@ void Options::addEmptyOption() {
|
||||
_chooseCorrectGroup));
|
||||
const auto field = _list.back()->field();
|
||||
if (const auto emojiPanel = _emojiPanel) {
|
||||
const auto emojiToggle = AddEmojiToggleToField(
|
||||
const auto emojiToggle = Ui::AddEmojiToggleToField(
|
||||
field,
|
||||
_box,
|
||||
_controller,
|
||||
@@ -972,7 +880,7 @@ not_null<Ui::InputField*> CreatePollBox::setupQuestion(
|
||||
emojiPanel->hide();
|
||||
emojiPanel->selector()->setCurrentPeer(session->user());
|
||||
|
||||
const auto emojiToggle = AddEmojiToggleToField(
|
||||
const auto emojiToggle = Ui::AddEmojiToggleToField(
|
||||
question,
|
||||
this,
|
||||
_controller,
|
||||
|
||||
@@ -25,7 +25,7 @@ DownloadPathBox::DownloadPathBox(
|
||||
, _path(Core::App().settings().downloadPath())
|
||||
, _pathBookmark(Core::App().settings().downloadPathBookmark())
|
||||
, _group(std::make_shared<Ui::RadioenumGroup<Directory>>(typeFromPath(_path)))
|
||||
, _default(Core::App().canReadDefaultDownloadPath(true)
|
||||
, _default(Core::App().canReadDefaultDownloadPath()
|
||||
? object_ptr<Ui::Radioenum<Directory>>(
|
||||
this,
|
||||
_group,
|
||||
@@ -149,7 +149,7 @@ void DownloadPathBox::setPathText(const QString &text) {
|
||||
DownloadPathBox::Directory DownloadPathBox::typeFromPath(
|
||||
const QString &path) {
|
||||
if (path.isEmpty()) {
|
||||
return Core::App().canReadDefaultDownloadPath(true)
|
||||
return Core::App().canReadDefaultDownloadPath()
|
||||
? Directory::Downloads
|
||||
: Directory::Temp;
|
||||
} else if (path == FileDialog::Tmp()) {
|
||||
|
||||
@@ -195,7 +195,7 @@ PaintRoundImageCallback PremiumsRow::generatePaintUserpicCallback(
|
||||
const auto radius = size * Ui::ForumUserpicRadiusMultiplier();
|
||||
p.drawRoundedRect(x, y, size, size, radius, radius);
|
||||
}
|
||||
st::settingsPrivacyPremium.paintInCenter(p, { x, y, size, size });
|
||||
st::settingsPrivacyPremium.paintInCenter(p, QRect(x, y, size, size));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -763,9 +763,6 @@ void EditMessagesPrivacyBox(
|
||||
lt_link,
|
||||
link,
|
||||
Ui::Text::WithEntities),
|
||||
.st = &st::defaultMultilineToast,
|
||||
.duration = Ui::Toast::kDefaultDuration * 2,
|
||||
.multiline = true,
|
||||
.filter = crl::guard(&controller->session(), [=](
|
||||
const ClickHandlerPtr &,
|
||||
Qt::MouseButton button) {
|
||||
|
||||
@@ -83,6 +83,7 @@ not_null<FilterChatsPreview*> SetupChatsPreview(
|
||||
rules.id(),
|
||||
rules.title(),
|
||||
rules.iconEmoji(),
|
||||
rules.colorIndex(),
|
||||
(rules.flags() & ~flag),
|
||||
rules.always(),
|
||||
rules.pinned(),
|
||||
@@ -104,6 +105,7 @@ not_null<FilterChatsPreview*> SetupChatsPreview(
|
||||
rules.id(),
|
||||
rules.title(),
|
||||
rules.iconEmoji(),
|
||||
rules.colorIndex(),
|
||||
rules.flags(),
|
||||
std::move(always),
|
||||
std::move(pinned),
|
||||
@@ -170,6 +172,7 @@ void EditExceptions(
|
||||
rules.id(),
|
||||
rules.title(),
|
||||
rules.iconEmoji(),
|
||||
rules.colorIndex(),
|
||||
((rules.flags() & ~options)
|
||||
| rawController->chosenOptions()),
|
||||
include ? std::move(changed) : std::move(removeFrom),
|
||||
@@ -240,6 +243,7 @@ void CreateIconSelector(
|
||||
rules.id(),
|
||||
rules.title(),
|
||||
Ui::LookupFilterIcon(icon).emoji,
|
||||
rules.colorIndex(),
|
||||
rules.flags(),
|
||||
rules.always(),
|
||||
rules.pinned(),
|
||||
|
||||
@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_info.h"
|
||||
@@ -581,6 +582,7 @@ void LinkController::addLinkBlock(not_null<Ui::VerticalLayout*> container) {
|
||||
});
|
||||
const auto getLinkQr = crl::guard(weak, [=] {
|
||||
delegate()->peerListUiShow()->showBox(InviteLinkQrBox(
|
||||
nullptr,
|
||||
link,
|
||||
tr::lng_group_invite_qr_title(),
|
||||
tr::lng_filters_link_qr_about()));
|
||||
@@ -889,6 +891,7 @@ base::unique_qptr<Ui::PopupMenu> LinksController::createRowContextMenu(
|
||||
};
|
||||
const auto getLinkQr = [=] {
|
||||
delegate()->peerListUiShow()->showBox(InviteLinkQrBox(
|
||||
nullptr,
|
||||
link,
|
||||
tr::lng_group_invite_qr_title(),
|
||||
tr::lng_filters_link_qr_about()));
|
||||
@@ -965,9 +968,9 @@ void LinksController::rowPaintIcon(
|
||||
p.setBrush(*bg);
|
||||
{
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.drawEllipse(QRect(0, 0, inner, inner));
|
||||
p.drawEllipse(Rect(Size(inner)));
|
||||
}
|
||||
st::inviteLinkIcon.paintInCenter(p, { 0, 0, inner, inner });
|
||||
st::inviteLinkIcon.paintInCenter(p, Rect(Size(inner)));
|
||||
}
|
||||
p.drawImage(x + skip, y + skip, icon);
|
||||
}
|
||||
@@ -1113,7 +1116,7 @@ QString FilterChatStatusText(not_null<PeerData*> peer) {
|
||||
? tr::lng_chat_status_subscribers
|
||||
: tr::lng_chat_status_members)(
|
||||
tr::now,
|
||||
lt_count,
|
||||
lt_count_decimal,
|
||||
channel->membersCount());
|
||||
}
|
||||
}
|
||||
|
||||
181
Telegram/SourceFiles/boxes/gift_credits_box.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
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/gift_credits_box.h"
|
||||
|
||||
#include "api/api_credits.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/session/session_show.h"
|
||||
#include "settings/settings_credits_graphics.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/effects/premium_graphics.h"
|
||||
#include "ui/effects/premium_stars_colored.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/label_with_custom_emoji.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_channel_earn.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_credits.h"
|
||||
#include "styles/style_giveaway.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_premium.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
void GiftCreditsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> gifted) {
|
||||
box->setWidth(st::boxWideWidth);
|
||||
box->setStyle(st::creditsGiftBox);
|
||||
box->setNoContentMargin(true);
|
||||
box->addButton(tr::lng_create_group_back(), [=] { box->closeBox(); });
|
||||
|
||||
const auto content = box->setPinnedToTopContent(
|
||||
object_ptr<Ui::VerticalLayout>(box));
|
||||
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
const auto &stUser = st::premiumGiftsUserpicButton;
|
||||
const auto userpicWrap = content->add(
|
||||
object_ptr<Ui::CenterWrap<>>(
|
||||
content,
|
||||
object_ptr<Ui::UserpicButton>(content, peer, stUser)));
|
||||
userpicWrap->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
|
||||
{
|
||||
const auto widget = Ui::CreateChild<Ui::RpWidget>(content);
|
||||
using ColoredMiniStars = Ui::Premium::ColoredMiniStars;
|
||||
const auto stars = widget->lifetime().make_state<ColoredMiniStars>(
|
||||
widget,
|
||||
false,
|
||||
Ui::Premium::MiniStars::Type::BiStars);
|
||||
stars->setColorOverride(Ui::Premium::CreditsIconGradientStops());
|
||||
widget->resize(
|
||||
st::boxWidth - stUser.photoSize,
|
||||
stUser.photoSize * 2);
|
||||
content->sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &size) {
|
||||
widget->moveToLeft(stUser.photoSize / 2, 0);
|
||||
const auto starsRect = Rect(widget->size());
|
||||
stars->setPosition(starsRect.topLeft());
|
||||
stars->setSize(starsRect.size());
|
||||
widget->lower();
|
||||
}, widget->lifetime());
|
||||
widget->paintRequest(
|
||||
) | rpl::start_with_next([=](const QRect &r) {
|
||||
auto p = QPainter(widget);
|
||||
p.fillRect(r, Qt::transparent);
|
||||
stars->paint(p);
|
||||
}, widget->lifetime());
|
||||
}
|
||||
{
|
||||
Ui::AddSkip(content);
|
||||
const auto arrow = Ui::Text::SingleCustomEmoji(
|
||||
peer->owner().customEmojiManager().registerInternalEmoji(
|
||||
st::topicButtonArrow,
|
||||
st::channelEarnLearnArrowMargins,
|
||||
false));
|
||||
auto link = tr::lng_credits_box_history_entry_gift_about_link(
|
||||
lt_emoji,
|
||||
rpl::single(arrow),
|
||||
Ui::Text::RichLangValue
|
||||
) | rpl::map([](TextWithEntities text) {
|
||||
return Ui::Text::Link(
|
||||
std::move(text),
|
||||
u"internal:stars_examples"_q);
|
||||
});
|
||||
content->add(
|
||||
object_ptr<Ui::CenterWrap<>>(
|
||||
content,
|
||||
Ui::CreateLabelWithCustomEmoji(
|
||||
content,
|
||||
tr::lng_credits_box_history_entry_gift_out_about(
|
||||
lt_user,
|
||||
rpl::single(TextWithEntities{ peer->shortName() }),
|
||||
lt_link,
|
||||
std::move(link),
|
||||
Ui::Text::RichLangValue),
|
||||
{ .session = &peer->session() },
|
||||
st::creditsBoxAbout)),
|
||||
st::boxRowPadding);
|
||||
}
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(box->verticalLayout());
|
||||
|
||||
Settings::FillCreditOptions(
|
||||
Main::MakeSessionShow(box->uiShow(), &peer->session()),
|
||||
box->verticalLayout(),
|
||||
peer,
|
||||
0,
|
||||
[=] { gifted(); box->uiShow()->hideLayer(); });
|
||||
|
||||
box->setPinnedToBottomContent(
|
||||
object_ptr<Ui::VerticalLayout>(box));
|
||||
}
|
||||
|
||||
void ShowGiftCreditsBox(
|
||||
not_null<Window::SessionController*> controller,
|
||||
Fn<void()> gifted) {
|
||||
|
||||
class Controller final : public ContactsBoxController {
|
||||
public:
|
||||
Controller(
|
||||
not_null<Main::Session*> session,
|
||||
Fn<void(not_null<PeerData*>)> choose)
|
||||
: ContactsBoxController(session)
|
||||
, _choose(std::move(choose)) {
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<PeerListRow> createRow(
|
||||
not_null<UserData*> user) override {
|
||||
if (user->isSelf()
|
||||
|| user->isBot()
|
||||
|| user->isServiceUser()
|
||||
|| user->isInaccessible()) {
|
||||
return nullptr;
|
||||
}
|
||||
return ContactsBoxController::createRow(user);
|
||||
}
|
||||
|
||||
void rowClicked(not_null<PeerListRow*> row) override {
|
||||
_choose(row->peer());
|
||||
}
|
||||
|
||||
private:
|
||||
const Fn<void(not_null<PeerData*>)> _choose;
|
||||
|
||||
};
|
||||
auto initBox = [=](not_null<PeerListBox*> peersBox) {
|
||||
peersBox->setTitle(tr::lng_credits_gift_title());
|
||||
peersBox->addButton(tr::lng_cancel(), [=] { peersBox->closeBox(); });
|
||||
};
|
||||
|
||||
const auto show = controller->uiShow();
|
||||
auto listController = std::make_unique<Controller>(
|
||||
&controller->session(),
|
||||
[=](not_null<PeerData*> peer) {
|
||||
show->showBox(Box(GiftCreditsBox, peer, gifted));
|
||||
});
|
||||
show->showBox(
|
||||
Box<PeerListBox>(std::move(listController), std::move(initBox)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
20
Telegram/SourceFiles/boxes/gift_credits_box.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
|
||||
void ShowGiftCreditsBox(
|
||||
not_null<Window::SessionController*> controller,
|
||||
Fn<void()> gifted);
|
||||
|
||||
} // namespace Ui
|
||||
@@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_media_types.h" // Data::GiveawayStart.
|
||||
#include "data/data_peer_values.h" // Data::PeerPremiumValue.
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_subscription_option.h"
|
||||
#include "data/data_premium_subscription_option.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "info/channel_statistics/boosts/giveaway/boost_badge.h" // InfiniteRadialAnimationWidget.
|
||||
@@ -66,8 +66,26 @@ namespace {
|
||||
|
||||
constexpr auto kUserpicsMax = size_t(3);
|
||||
|
||||
using GiftOption = Data::SubscriptionOption;
|
||||
using GiftOptions = Data::SubscriptionOptions;
|
||||
using GiftOption = Data::PremiumSubscriptionOption;
|
||||
using GiftOptions = Data::PremiumSubscriptionOptions;
|
||||
|
||||
[[nodiscard]] QString CreateMessageLink(
|
||||
not_null<Main::Session*> session,
|
||||
PeerId peerId,
|
||||
uint64 messageId) {
|
||||
if (const auto msgId = MsgId(peerId ? messageId : 0)) {
|
||||
const auto peer = session->data().peer(peerId);
|
||||
if (const auto channel = peer->asBroadcast()) {
|
||||
const auto username = channel->username();
|
||||
const auto base = username.isEmpty()
|
||||
? u"c/%1"_q.arg(peerToChannel(channel->id).bare)
|
||||
: username;
|
||||
const auto query = base + '/' + QString::number(msgId.bare);
|
||||
return session->createInternalLink(query);
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
};
|
||||
|
||||
GiftOptions GiftOptionFromTL(const MTPDuserFull &data) {
|
||||
auto result = GiftOptions();
|
||||
@@ -75,7 +93,7 @@ GiftOptions GiftOptionFromTL(const MTPDuserFull &data) {
|
||||
if (!gifts) {
|
||||
return result;
|
||||
}
|
||||
result = Api::SubscriptionOptionsFromTL(gifts->v);
|
||||
result = Api::PremiumSubscriptionOptionsFromTL(gifts->v);
|
||||
for (auto &option : result) {
|
||||
option.costPerMonth = tr::lng_premium_gift_per(
|
||||
tr::now,
|
||||
@@ -932,8 +950,8 @@ void ShowAlreadyPremiumToast(
|
||||
Ui::Text::Link(
|
||||
Ui::Text::Bold(tr::lng_gift_link_already_link(tr::now))),
|
||||
Ui::Text::WithEntities),
|
||||
.duration = 6 * crl::time(1000),
|
||||
.filter = crl::guard(navigation, shareLink),
|
||||
.duration = 6 * crl::time(1000),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1014,6 +1032,7 @@ void GiftPremiumValidator::showChoosePeerBox(const QString &ref) {
|
||||
if (users.empty()) {
|
||||
show->showToast(
|
||||
tr::lng_settings_gift_premium_choose(tr::now));
|
||||
return;
|
||||
}
|
||||
const auto giftBox = show->show(
|
||||
Box(GiftsBox, _controller, users, api, ref));
|
||||
@@ -1418,21 +1437,56 @@ void GiveawayInfoBox(
|
||||
: !start->channels.empty()
|
||||
? start->channels.front()->name()
|
||||
: u"channel"_q;
|
||||
auto text = TextWithEntities();
|
||||
|
||||
if (!info.giftCode.isEmpty()) {
|
||||
text.append("\n\n");
|
||||
text.append(Ui::Text::Bold(tr::lng_prizes_you_won(
|
||||
tr::now,
|
||||
auto resultText = (!info.giftCode.isEmpty())
|
||||
? tr::lng_prizes_you_won(
|
||||
lt_cup,
|
||||
QString::fromUtf8("\xf0\x9f\x8f\x86"))));
|
||||
text.append("\n\n");
|
||||
} else if (info.state == State::Finished) {
|
||||
text.append("\n\n");
|
||||
text.append(Ui::Text::Bold(tr::lng_prizes_you_didnt(tr::now)));
|
||||
text.append("\n\n");
|
||||
rpl::single(
|
||||
TextWithEntities{ QString::fromUtf8("\xf0\x9f\x8f\x86") }),
|
||||
Ui::Text::WithEntities)
|
||||
: (info.credits)
|
||||
? tr::lng_prizes_you_won_credits(
|
||||
lt_amount,
|
||||
tr::lng_prizes_you_won_credits_amount(
|
||||
lt_count,
|
||||
rpl::single(float64(info.credits)),
|
||||
Ui::Text::Bold),
|
||||
lt_cup,
|
||||
rpl::single(
|
||||
TextWithEntities{ QString::fromUtf8("\xf0\x9f\x8f\x86") }),
|
||||
Ui::Text::WithEntities)
|
||||
: (info.state == State::Finished)
|
||||
? tr::lng_prizes_you_didnt(Ui::Text::WithEntities)
|
||||
: (rpl::producer<TextWithEntities>)(nullptr);
|
||||
|
||||
if (resultText) {
|
||||
const auto &st = st::changePhoneDescription;
|
||||
const auto skip = st.style.font->height * 0.5;
|
||||
auto label = object_ptr<Ui::FlatLabel>(
|
||||
box.get(),
|
||||
std::move(resultText),
|
||||
st);
|
||||
if ((!info.giftCode.isEmpty()) || info.credits) {
|
||||
label->setTextColorOverride(st::windowActiveTextFg->c);
|
||||
}
|
||||
const auto result = box->addRow(
|
||||
object_ptr<Ui::PaddingWrap<Ui::CenterWrap<Ui::FlatLabel>>>(
|
||||
box.get(),
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
box.get(),
|
||||
std::move(label)),
|
||||
QMargins(0, skip, 0, skip)));
|
||||
result->paintRequest() | rpl::start_with_next([=] {
|
||||
auto p = QPainter(result);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::boxDividerBg);
|
||||
p.drawRoundedRect(result->rect(), st::boxRadius, st::boxRadius);
|
||||
}, result->lifetime());
|
||||
Ui::AddSkip(box->verticalLayout());
|
||||
}
|
||||
|
||||
auto text = TextWithEntities();
|
||||
|
||||
const auto quantity = start
|
||||
? start->quantity
|
||||
: (results->winnersCount + results->unclaimedCount);
|
||||
@@ -1441,22 +1495,39 @@ void GiveawayInfoBox(
|
||||
? results->channel->isMegagroup()
|
||||
: (!start->channels.empty()
|
||||
&& start->channels.front()->isMegagroup());
|
||||
const auto credits = start
|
||||
? start->credits
|
||||
: (results ? results->credits : 0);
|
||||
text.append((finished
|
||||
? tr::lng_prizes_end_text
|
||||
: tr::lng_prizes_how_text)(
|
||||
tr::now,
|
||||
lt_admins,
|
||||
(group
|
||||
? tr::lng_prizes_admins_group
|
||||
: tr::lng_prizes_admins)(
|
||||
tr::now,
|
||||
lt_count,
|
||||
quantity,
|
||||
lt_channel,
|
||||
Ui::Text::Bold(first),
|
||||
lt_duration,
|
||||
TextWithEntities{ GiftDuration(months) },
|
||||
Ui::Text::RichLangValue),
|
||||
credits
|
||||
? (group
|
||||
? tr::lng_prizes_credits_admins_group
|
||||
: tr::lng_prizes_credits_admins)(
|
||||
tr::now,
|
||||
lt_channel,
|
||||
Ui::Text::Bold(first),
|
||||
lt_amount,
|
||||
tr::lng_prizes_credits_admins_amount(
|
||||
tr::now,
|
||||
lt_count_decimal,
|
||||
float64(credits),
|
||||
Ui::Text::Bold),
|
||||
Ui::Text::RichLangValue)
|
||||
: (group
|
||||
? tr::lng_prizes_admins_group
|
||||
: tr::lng_prizes_admins)(
|
||||
tr::now,
|
||||
lt_count,
|
||||
quantity,
|
||||
lt_channel,
|
||||
Ui::Text::Bold(first),
|
||||
lt_duration,
|
||||
TextWithEntities{ GiftDuration(months) },
|
||||
Ui::Text::RichLangValue),
|
||||
Ui::Text::RichLangValue));
|
||||
const auto many = start
|
||||
? (start->channels.size() > 1)
|
||||
@@ -1641,26 +1712,29 @@ void AddCreditsHistoryEntryTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const Data::CreditsHistoryEntry &entry) {
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
auto table = container->add(
|
||||
object_ptr<Ui::TableLayout>(
|
||||
container,
|
||||
st::giveawayGiftCodeTable),
|
||||
st::giveawayGiftCodeTableMargin);
|
||||
const auto peerId = PeerId(entry.barePeerId);
|
||||
const auto session = &controller->session();
|
||||
if (peerId) {
|
||||
auto text = tr::lng_credits_box_history_entry_peer();
|
||||
auto text = entry.in
|
||||
? tr::lng_credits_box_history_entry_peer_in()
|
||||
: tr::lng_credits_box_history_entry_peer();
|
||||
AddTableRow(table, std::move(text), controller, peerId);
|
||||
}
|
||||
if (const auto msgId = MsgId(peerId ? entry.bareMsgId : 0)) {
|
||||
const auto session = &controller->session();
|
||||
const auto peer = session->data().peer(peerId);
|
||||
if (const auto channel = peer->asBroadcast()) {
|
||||
const auto username = channel->username();
|
||||
const auto base = username.isEmpty()
|
||||
? u"c/%1"_q.arg(peerToChannel(channel->id).bare)
|
||||
: username;
|
||||
const auto query = base + '/' + QString::number(msgId.bare);
|
||||
const auto link = session->createInternalLink(query);
|
||||
const auto link = CreateMessageLink(
|
||||
session,
|
||||
peerId,
|
||||
entry.bareMsgId);
|
||||
auto label = object_ptr<Ui::FlatLabel>(
|
||||
table,
|
||||
rpl::single(Ui::Text::Link(link)),
|
||||
@@ -1692,14 +1766,55 @@ void AddCreditsHistoryEntryTable(
|
||||
} else if (entry.peerType == Type::Fragment) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_via(),
|
||||
tr::lng_credits_box_history_entry_fragment(
|
||||
Ui::Text::RichLangValue));
|
||||
(entry.gift
|
||||
? tr::lng_credits_box_history_entry_peer_in
|
||||
: tr::lng_credits_box_history_entry_via)(),
|
||||
(entry.gift
|
||||
? tr::lng_credits_box_history_entry_anonymous
|
||||
: tr::lng_credits_box_history_entry_fragment)(
|
||||
Ui::Text::RichLangValue));
|
||||
} else if (entry.peerType == Type::Ads) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_via(),
|
||||
tr::lng_credits_box_history_entry_ads(Ui::Text::RichLangValue));
|
||||
} else if (entry.peerType == Type::PremiumBot) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_via(),
|
||||
tr::lng_credits_box_history_entry_via_premium_bot(
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
if (entry.bareGiveawayMsgId) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_to(),
|
||||
controller,
|
||||
controller->session().userId());
|
||||
}
|
||||
if (entry.bareGiveawayMsgId && entry.credits) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_gift(),
|
||||
tr::lng_gift_stars_title(
|
||||
lt_count,
|
||||
rpl::single(float64(entry.credits)),
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
{
|
||||
const auto link = CreateMessageLink(
|
||||
session,
|
||||
peerId,
|
||||
entry.bareGiveawayMsgId);
|
||||
if (!link.isEmpty()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_reason(),
|
||||
tr::lng_gift_link_reason_giveaway(
|
||||
) | rpl::map([link](const QString &text) {
|
||||
return Ui::Text::Link(text, link);
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (!entry.id.isEmpty()) {
|
||||
constexpr auto kOneLineCount = 18;
|
||||
@@ -1744,3 +1859,113 @@ void AddCreditsHistoryEntryTable(
|
||||
Ui::Text::Link(entry.successLink, entry.successLink)));
|
||||
}
|
||||
}
|
||||
|
||||
void AddSubscriptionEntryTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const Data::SubscriptionEntry &s) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
auto table = container->add(
|
||||
object_ptr<Ui::TableLayout>(
|
||||
container,
|
||||
st::giveawayGiftCodeTable),
|
||||
st::giveawayGiftCodeTableMargin);
|
||||
const auto peerId = PeerId(s.barePeerId);
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_subscription_row_to(),
|
||||
controller,
|
||||
peerId);
|
||||
if (!s.until.isNull()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
s.expired
|
||||
? tr::lng_credits_subscription_row_next_none()
|
||||
: s.cancelled
|
||||
? tr::lng_credits_subscription_row_next_off()
|
||||
: tr::lng_credits_subscription_row_next_on(),
|
||||
rpl::single(Ui::Text::WithEntities(langDateTime(s.until))));
|
||||
}
|
||||
}
|
||||
|
||||
void AddSubscriberEntryTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
not_null<PeerData*> peer,
|
||||
TimeId date) {
|
||||
auto table = container->add(
|
||||
object_ptr<Ui::TableLayout>(
|
||||
container,
|
||||
st::giveawayGiftCodeTable),
|
||||
st::giveawayGiftCodeTableMargin);
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_group_invite_joined_row_subscriber(),
|
||||
controller,
|
||||
peer->id);
|
||||
if (const auto d = base::unixtime::parse(date); !d.isNull()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_group_invite_joined_row_date(),
|
||||
rpl::single(Ui::Text::WithEntities(langDateTime(d))));
|
||||
}
|
||||
}
|
||||
|
||||
void AddCreditsBoostTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const Data::Boost &b) {
|
||||
auto table = container->add(
|
||||
object_ptr<Ui::TableLayout>(
|
||||
container,
|
||||
st::giveawayGiftCodeTable),
|
||||
st::giveawayGiftCodeTableMargin);
|
||||
const auto peerId = b.giveawayMessage.peer;
|
||||
if (!peerId) {
|
||||
return;
|
||||
}
|
||||
const auto from = controller->session().data().peer(peerId);
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_peer_in(),
|
||||
controller,
|
||||
from->id);
|
||||
if (b.credits) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_gift(),
|
||||
tr::lng_gift_stars_title(
|
||||
lt_count,
|
||||
rpl::single(float64(b.credits)),
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
{
|
||||
const auto link = CreateMessageLink(
|
||||
&controller->session(),
|
||||
peerId,
|
||||
b.giveawayMessage.msg.bare);
|
||||
if (!link.isEmpty()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_reason(),
|
||||
tr::lng_gift_link_reason_giveaway(
|
||||
) | rpl::map([link](const QString &text) {
|
||||
return Ui::Text::Link(text, link);
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (!b.date.isNull()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_date(),
|
||||
rpl::single(Ui::Text::WithEntities(langDateTime(b.date))));
|
||||
}
|
||||
if (!b.expiresAt.isNull()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_until(),
|
||||
rpl::single(Ui::Text::WithEntities(langDateTime(b.expiresAt))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@ struct GiftCode;
|
||||
} // namespace Api
|
||||
|
||||
namespace Data {
|
||||
struct Boost;
|
||||
struct CreditsHistoryEntry;
|
||||
struct GiveawayStart;
|
||||
struct GiveawayResults;
|
||||
struct SubscriptionEntry;
|
||||
} // namespace Data
|
||||
|
||||
namespace Ui {
|
||||
@@ -78,3 +80,18 @@ void AddCreditsHistoryEntryTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const Data::CreditsHistoryEntry &entry);
|
||||
|
||||
void AddSubscriptionEntryTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const Data::SubscriptionEntry &s);
|
||||
void AddSubscriberEntryTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
not_null<PeerData*> peer,
|
||||
TimeId date);
|
||||
|
||||
void AddCreditsBoostTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const Data::Boost &boost);
|
||||
|
||||
@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
|
||||
@@ -94,7 +94,7 @@ void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
|
||||
showToast(tr::lng_create_channel_link_copied(tr::now));
|
||||
} else if (_channel->isFullLoaded() && !_creatingInviteLink) {
|
||||
_creatingInviteLink = true;
|
||||
_channel->session().api().inviteLinks().create(_channel);
|
||||
_channel->session().api().inviteLinks().create({ _channel });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||