Compare commits
560 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4505a2bf2d | ||
|
|
a314380b08 | ||
|
|
0c07a015c6 | ||
|
|
a0c7697280 | ||
|
|
04023da723 | ||
|
|
13ea045055 | ||
|
|
f03351d112 | ||
|
|
48d9f10f5b | ||
|
|
2b53df98cd | ||
|
|
99a7a13218 | ||
|
|
2d2d4ac002 | ||
|
|
d12e8023e3 | ||
|
|
17181cee8f | ||
|
|
a74ee911b3 | ||
|
|
b0b37172ce | ||
|
|
cccf048e3f | ||
|
|
82e890746b | ||
|
|
188d65d700 | ||
|
|
4569f93e70 | ||
|
|
bcd1d8461f | ||
|
|
183a9139f9 | ||
|
|
80a1e6ecf3 | ||
|
|
aa1f8cfb8f | ||
|
|
8060691f3d | ||
|
|
bf26de495a | ||
|
|
73b3f7e298 | ||
|
|
22191649aa | ||
|
|
0557907310 | ||
|
|
0f283c484d | ||
|
|
e33ca9d316 | ||
|
|
f93f4c72f7 | ||
|
|
f0b9bc10c2 | ||
|
|
f583879aee | ||
|
|
7ea6c6c84b | ||
|
|
2532a0ff59 | ||
|
|
c3f354826d | ||
|
|
6d1e421ad7 | ||
|
|
29b0055e39 | ||
|
|
2cb20fe342 | ||
|
|
fc97fa4415 | ||
|
|
876a50f759 | ||
|
|
eb0d2868f5 | ||
|
|
e215d5bc64 | ||
|
|
3f0d687656 | ||
|
|
d59eb8e731 | ||
|
|
04e9eed88d | ||
|
|
5072e95f16 | ||
|
|
a2b8366477 | ||
|
|
e9a6bee046 | ||
|
|
080a8d7ee5 | ||
|
|
f94fd3118b | ||
|
|
8ddb13d6e2 | ||
|
|
c6cf8be8d4 | ||
|
|
e92270a9ab | ||
|
|
65d6636a41 | ||
|
|
4701badb2a | ||
|
|
3565215c81 | ||
|
|
3957fea5e4 | ||
|
|
10f1ae152d | ||
|
|
eb29b6bffe | ||
|
|
d157eb0b6e | ||
|
|
0045eb4598 | ||
|
|
b61c66c385 | ||
|
|
56d6c4eb30 | ||
|
|
a6030d708d | ||
|
|
683c3c4f36 | ||
|
|
bd084f9181 | ||
|
|
fef133bf0a | ||
|
|
15c226e6cf | ||
|
|
84f111d641 | ||
|
|
18c1e7ac60 | ||
|
|
ee6dbdced6 | ||
|
|
cb443d797d | ||
|
|
5a6497ec70 | ||
|
|
893ca8bcbd | ||
|
|
f91e4c8b69 | ||
|
|
f7c777d07d | ||
|
|
12a8e8616c | ||
|
|
2fbf7e8504 | ||
|
|
6864e6d5bf | ||
|
|
09b4e0e21b | ||
|
|
f381005184 | ||
|
|
42a2de4bf0 | ||
|
|
1fd1e34844 | ||
|
|
64dbbd7d09 | ||
|
|
c137e577dc | ||
|
|
f592a9202f | ||
|
|
cdc24d2e57 | ||
|
|
b8bf3f6520 | ||
|
|
82cec83d87 | ||
|
|
1e14667006 | ||
|
|
6539d14852 | ||
|
|
400df0f980 | ||
|
|
4cafb3f966 | ||
|
|
d8892c4eb4 | ||
|
|
1ebd25e76e | ||
|
|
ca89aa8377 | ||
|
|
ad6272bfe5 | ||
|
|
b401c37c39 | ||
|
|
552dd318cd | ||
|
|
a97880132a | ||
|
|
89058c63c8 | ||
|
|
747e417809 | ||
|
|
fd26e1618c | ||
|
|
86ea760011 | ||
|
|
824237deb3 | ||
|
|
ca8c70cc95 | ||
|
|
46fcc695a5 | ||
|
|
0e866a0266 | ||
|
|
63c36f5907 | ||
|
|
5299500d78 | ||
|
|
3b3d1aa9cc | ||
|
|
62d2346471 | ||
|
|
1e15764bb9 | ||
|
|
a6bfd35f1a | ||
|
|
3296efe46b | ||
|
|
51ddfbc340 | ||
|
|
42142d819a | ||
|
|
bbf9d523a6 | ||
|
|
721877e10a | ||
|
|
a9e95a128f | ||
|
|
2b920eaa87 | ||
|
|
a3ec759e62 | ||
|
|
3661442acd | ||
|
|
f232d329c5 | ||
|
|
ac5cf3bd80 | ||
|
|
ac13ac7a2c | ||
|
|
0bccb35cb0 | ||
|
|
18d9484ab1 | ||
|
|
fe7c06bc84 | ||
|
|
b6fb3bbf1d | ||
|
|
927d7a3aeb | ||
|
|
979973745b | ||
|
|
afab863f11 | ||
|
|
168162c174 | ||
|
|
2b122087c4 | ||
|
|
043d97cfdf | ||
|
|
794818953d | ||
|
|
783570fe9f | ||
|
|
b1e2a4243e | ||
|
|
b347308137 | ||
|
|
b3c8a79946 | ||
|
|
9822c56f1a | ||
|
|
cdd7ff5c6d | ||
|
|
5aba2f25cc | ||
|
|
96398daa78 | ||
|
|
61ceb66415 | ||
|
|
b4f173cdb3 | ||
|
|
03e4592082 | ||
|
|
cf2dbe50a1 | ||
|
|
e5bb5b75fe | ||
|
|
cffce47eb1 | ||
|
|
ca0adba6cf | ||
|
|
8502b90c25 | ||
|
|
cef43e7f06 | ||
|
|
18aaf3cc93 | ||
|
|
f13740cb7f | ||
|
|
bddac79b40 | ||
|
|
e52baf555f | ||
|
|
475dec3014 | ||
|
|
f2ed649694 | ||
|
|
e82506e0c4 | ||
|
|
3071daa6f3 | ||
|
|
5d71286000 | ||
|
|
339d7be9c1 | ||
|
|
7f85494b1d | ||
|
|
a405794a03 | ||
|
|
4e8e096fdb | ||
|
|
eb821c1f36 | ||
|
|
bf07b832f0 | ||
|
|
5934614edb | ||
|
|
96b5c1d3d3 | ||
|
|
cb2972b145 | ||
|
|
cd5a1980c9 | ||
|
|
0e35107e17 | ||
|
|
10b026dfe0 | ||
|
|
743c3c54a7 | ||
|
|
489c86dad8 | ||
|
|
a9824fde91 | ||
|
|
6c62bbe6fb | ||
|
|
8a3aa660cb | ||
|
|
14cc7789d9 | ||
|
|
728d9a0993 | ||
|
|
aa8d543ed8 | ||
|
|
b335981621 | ||
|
|
9d5ca1252a | ||
|
|
d5dbbd566f | ||
|
|
5362d54ab6 | ||
|
|
1f162aa2a0 | ||
|
|
4a19f193ce | ||
|
|
cfc40ee966 | ||
|
|
6baba5a7b2 | ||
|
|
ba082081b3 | ||
|
|
e314c68a56 | ||
|
|
889fcb3939 | ||
|
|
632abd2225 | ||
|
|
e3465da979 | ||
|
|
f4523b2dba | ||
|
|
0d58b32914 | ||
|
|
aea2d34080 | ||
|
|
d5dbde0a24 | ||
|
|
f888008dc1 | ||
|
|
021a5881c2 | ||
|
|
3e49b45418 | ||
|
|
23e22650f9 | ||
|
|
85267a921e | ||
|
|
2c7089d47f | ||
|
|
edc6cfe210 | ||
|
|
03b6e2df17 | ||
|
|
5309138980 | ||
|
|
a5e927ea4f | ||
|
|
ec83f4ae72 | ||
|
|
71efd95136 | ||
|
|
0c21eba1f8 | ||
|
|
2ae4e15f87 | ||
|
|
d69905feae | ||
|
|
f795d56b2a | ||
|
|
4608ffcab4 | ||
|
|
9824df5f2a | ||
|
|
27a5ba4681 | ||
|
|
73936dca73 | ||
|
|
213274e96c | ||
|
|
7518361266 | ||
|
|
f7aaece2f7 | ||
|
|
fbce06cb26 | ||
|
|
ccc0bf57a1 | ||
|
|
ee29deee47 | ||
|
|
17e54104a9 | ||
|
|
479e369d29 | ||
|
|
3042fb7299 | ||
|
|
36fa455aad | ||
|
|
1c64e90537 | ||
|
|
09643aef82 | ||
|
|
03d9fb4115 | ||
|
|
81bea04db0 | ||
|
|
9211e338e7 | ||
|
|
23464ac55f | ||
|
|
af78e4ea29 | ||
|
|
e3d9216b10 | ||
|
|
9532a2e3da | ||
|
|
e70f50d837 | ||
|
|
2dfa58aae2 | ||
|
|
c04f68f25c | ||
|
|
e4902efefc | ||
|
|
1267bcd255 | ||
|
|
0659ccc3f0 | ||
|
|
bd2ae03ab4 | ||
|
|
244696ae24 | ||
|
|
1438046dd4 | ||
|
|
5c62ba0835 | ||
|
|
20fadfef7f | ||
|
|
eed9541f9f | ||
|
|
1594afa389 | ||
|
|
9d74d93ed7 | ||
|
|
e4e2f47f8e | ||
|
|
be53bec9b7 | ||
|
|
bb32c546d4 | ||
|
|
ecb4ceec7b | ||
|
|
c080bd4c4d | ||
|
|
39780f49bf | ||
|
|
73349c3c89 | ||
|
|
42a70ff7d0 | ||
|
|
fa8262cbe9 | ||
|
|
7552328cdd | ||
|
|
60f4587d95 | ||
|
|
572c074c42 | ||
|
|
3cfbd6a93b | ||
|
|
d0911b6a45 | ||
|
|
06b85442f8 | ||
|
|
762592daff | ||
|
|
338122793c | ||
|
|
ef521624a0 | ||
|
|
341ab781b2 | ||
|
|
2fed657940 | ||
|
|
7bf78b3317 | ||
|
|
2d1fb0562d | ||
|
|
3d77bff0c9 | ||
|
|
4198203a7f | ||
|
|
21487641c1 | ||
|
|
c987872be8 | ||
|
|
07e367e1a0 | ||
|
|
db2e45c56e | ||
|
|
67bbdbfc70 | ||
|
|
83df3cba66 | ||
|
|
f4e2b4bcbd | ||
|
|
6c64c22f83 | ||
|
|
702aa944dd | ||
|
|
df45edd816 | ||
|
|
3f3143514e | ||
|
|
3e89910749 | ||
|
|
721a642a2f | ||
|
|
d16ccc9dc5 | ||
|
|
77e7796b3f | ||
|
|
983c949e8c | ||
|
|
e3f4f60e2d | ||
|
|
33aa904cb7 | ||
|
|
0248be5543 | ||
|
|
f7ca8212aa | ||
|
|
5eb59a1a43 | ||
|
|
7dd1e9bfbe | ||
|
|
067fd25a34 | ||
|
|
7cb26ba104 | ||
|
|
a4212cc865 | ||
|
|
0445f7d6e8 | ||
|
|
efe99b3f62 | ||
|
|
7f2c98f17a | ||
|
|
8f1d215851 | ||
|
|
013b58f6f6 | ||
|
|
9d3b3476c2 | ||
|
|
715874a98f | ||
|
|
d2109dd2cb | ||
|
|
ddaf11ed6a | ||
|
|
2b5f68003d | ||
|
|
1a759cc4e7 | ||
|
|
9e83562bf4 | ||
|
|
c03c19d26f | ||
|
|
ad9ebdf8e6 | ||
|
|
9c1701c62a | ||
|
|
edf6c42e9d | ||
|
|
f0f2a71a87 | ||
|
|
cf270bd9ce | ||
|
|
49223a4688 | ||
|
|
074bb1e66e | ||
|
|
7e2e510d8a | ||
|
|
1ed34c6fa0 | ||
|
|
78a0fa55b5 | ||
|
|
d37c040b36 | ||
|
|
e56bbf557d | ||
|
|
5abecec478 | ||
|
|
ccb41f778e | ||
|
|
059a4cf0d8 | ||
|
|
7a535a4554 | ||
|
|
f89167ef94 | ||
|
|
a77777f509 | ||
|
|
4a327ba584 | ||
|
|
a41e9bf67e | ||
|
|
6716973ce0 | ||
|
|
7cc81393d6 | ||
|
|
3e413a036f | ||
|
|
63a8fe7ee8 | ||
|
|
146409844d | ||
|
|
ba0da9f59e | ||
|
|
81aef519d4 | ||
|
|
bcd84518d1 | ||
|
|
f205952ff2 | ||
|
|
1d7622e0b5 | ||
|
|
4d9112283d | ||
|
|
dc49c788a8 | ||
|
|
36741ab780 | ||
|
|
53dffc5e88 | ||
|
|
607c7e7777 | ||
|
|
6f09e1699f | ||
|
|
8c35de48f3 | ||
|
|
b83d943841 | ||
|
|
b11b5caeb3 | ||
|
|
36924da59a | ||
|
|
f0a2c47613 | ||
|
|
5a4449f1a2 | ||
|
|
de3d7a7774 | ||
|
|
b06dbd1c00 | ||
|
|
1fa5e424e9 | ||
|
|
d81c7abf1a | ||
|
|
932215c91d | ||
|
|
7aa1141ba5 | ||
|
|
3699439506 | ||
|
|
76b1288f77 | ||
|
|
8fd9ae4e59 | ||
|
|
53abd2fe38 | ||
|
|
da8a4ba8ab | ||
|
|
9c3990c0c1 | ||
|
|
1eeb46d5fc | ||
|
|
02c01e258c | ||
|
|
b2f912868d | ||
|
|
ecf0eba0a5 | ||
|
|
8e5fec2fa8 | ||
|
|
89c35e8512 | ||
|
|
3fa88fad79 | ||
|
|
5f037462ed | ||
|
|
93c01e5f1e | ||
|
|
52953626a7 | ||
|
|
f77fdc799d | ||
|
|
7bf1f9bd71 | ||
|
|
363ffc1c04 | ||
|
|
4001899bdf | ||
|
|
fabdd89c4a | ||
|
|
70f1675085 | ||
|
|
07e1e2d9d6 | ||
|
|
ebff6c6370 | ||
|
|
233eb6d916 | ||
|
|
d568cab2fc | ||
|
|
8447b95c50 | ||
|
|
e959d1e1b0 | ||
|
|
ead5dbe368 | ||
|
|
f091f2b344 | ||
|
|
267a51e800 | ||
|
|
939f6095ba | ||
|
|
a333615e53 | ||
|
|
e1b33fbc40 | ||
|
|
99c5d994b5 | ||
|
|
0971485367 | ||
|
|
3cfa963f69 | ||
|
|
7096a4231f | ||
|
|
07f0c182e6 | ||
|
|
535b223333 | ||
|
|
ffa8c2be79 | ||
|
|
2873e64ca2 | ||
|
|
8bd28bce69 | ||
|
|
b97ce43fca | ||
|
|
d34c4cc2f2 | ||
|
|
1ca1f0fa7d | ||
|
|
8c3c8f888d | ||
|
|
a75d7f0381 | ||
|
|
7684466acf | ||
|
|
0067245739 | ||
|
|
4a5d8aa217 | ||
|
|
2d786aa02c | ||
|
|
b0933b96ef | ||
|
|
20fb73b626 | ||
|
|
ae7bd7112b | ||
|
|
2365363dcc | ||
|
|
e0e4a7bec6 | ||
|
|
ebd0c3696a | ||
|
|
e0a0d9c039 | ||
|
|
dae9f2ab2b | ||
|
|
7168a00ee4 | ||
|
|
1e2d0ced20 | ||
|
|
d6ac883efa | ||
|
|
a386d70ae4 | ||
|
|
bc8bf672b4 | ||
|
|
e38998214f | ||
|
|
472a2fe802 | ||
|
|
2d6d89b1cf | ||
|
|
66be2ac6ca | ||
|
|
3137c9f3f7 | ||
|
|
b9ebb02e72 | ||
|
|
1e02c475d6 | ||
|
|
4d2cda0692 | ||
|
|
cbd2b8f428 | ||
|
|
93605db690 | ||
|
|
2567096de0 | ||
|
|
6ed25d012f | ||
|
|
c2afef2bde | ||
|
|
0991e7d8a4 | ||
|
|
cf52f2a743 | ||
|
|
37dddda1a0 | ||
|
|
3f2f3ebd51 | ||
|
|
7ba78540ac | ||
|
|
19afb49fce | ||
|
|
46ab553fa5 | ||
|
|
68cc42047e | ||
|
|
e25cf27ba5 | ||
|
|
3895e6d958 | ||
|
|
24cf3984c8 | ||
|
|
6237675744 | ||
|
|
30dae049ff | ||
|
|
1dc30caee9 | ||
|
|
b2d340cbfb | ||
|
|
7d52787e54 | ||
|
|
ae3f16ccbd | ||
|
|
057222757b | ||
|
|
119f109904 | ||
|
|
23a77b1ba4 | ||
|
|
c076daa91f | ||
|
|
b7ef5325ac | ||
|
|
8b535c58fa | ||
|
|
6bc8daaeda | ||
|
|
7a2562e5bb | ||
|
|
9e0c731b32 | ||
|
|
2e0e4006a1 | ||
|
|
187139473d | ||
|
|
dbb0a5ad28 | ||
|
|
24aaed44b9 | ||
|
|
32b8d83c04 | ||
|
|
bf55c325ce | ||
|
|
3af288c74e | ||
|
|
e306d9ba35 | ||
|
|
b23a877d7e | ||
|
|
08fda055fc | ||
|
|
84055ed74e | ||
|
|
2db30690ce | ||
|
|
304bcfd343 | ||
|
|
8a1cf2bb3a | ||
|
|
c857c24a64 | ||
|
|
bbdcb047d0 | ||
|
|
78f2e70956 | ||
|
|
75a75626ce | ||
|
|
cec9688d58 | ||
|
|
81492b7d3a | ||
|
|
9166acbbb9 | ||
|
|
36de2b6ca6 | ||
|
|
21f909dd4b | ||
|
|
f2a92c9122 | ||
|
|
7ee2e3d8bc | ||
|
|
f89aeb6ad4 | ||
|
|
0397006894 | ||
|
|
d6863074b2 | ||
|
|
9c185a30e0 | ||
|
|
a8f492a027 | ||
|
|
0a92b1dc68 | ||
|
|
e6d661f8ee | ||
|
|
f48dfb5d81 | ||
|
|
cd041e8366 | ||
|
|
6787ea883e | ||
|
|
78937d716f | ||
|
|
9713abc002 | ||
|
|
b44b45cca0 | ||
|
|
9e2cf0ed73 | ||
|
|
b01d7ea5b9 | ||
|
|
ae89b65a98 | ||
|
|
9b9c3d788d | ||
|
|
ccc6c6daa5 | ||
|
|
9ce6636c6a | ||
|
|
6287d306c2 | ||
|
|
6cfa053328 | ||
|
|
9514b6eecd | ||
|
|
c8d4818d22 | ||
|
|
4142ada729 | ||
|
|
d7ffdbd78d | ||
|
|
e8d87d37bb | ||
|
|
343ffc23eb | ||
|
|
95e0086eed | ||
|
|
c010ecfe38 | ||
|
|
302e9371c8 | ||
|
|
7060c0e6d7 | ||
|
|
20a4c7f9f4 | ||
|
|
e59e4afd3e | ||
|
|
f74dd3ca1e | ||
|
|
511cfc524f | ||
|
|
4cf6173d25 | ||
|
|
17996757fd | ||
|
|
6bc1049858 | ||
|
|
ff44f626ba | ||
|
|
552343fa37 | ||
|
|
4dc7fd8cd1 | ||
|
|
285c96fd2e | ||
|
|
e6af33367e | ||
|
|
7092fe2242 | ||
|
|
a32ff46579 | ||
|
|
7f20cf59d1 | ||
|
|
a8a1b08127 | ||
|
|
1a1e777b87 | ||
|
|
9e76e64064 | ||
|
|
975ae17ef9 | ||
|
|
ed9dcef66f | ||
|
|
b1e537e54e | ||
|
|
e5886862c3 | ||
|
|
d85b668d4f | ||
|
|
b363d8bfb5 | ||
|
|
754d467440 | ||
|
|
598f08d6c7 | ||
|
|
224fdc1864 | ||
|
|
e646b4dc9a | ||
|
|
9077db2e97 | ||
|
|
7e14277ead | ||
|
|
d351a7d697 | ||
|
|
70ed43b811 | ||
|
|
913083ebc6 | ||
|
|
588a95a7ae | ||
|
|
c0a0ad4ec5 | ||
|
|
5eafe96525 |
2
.github/workflows/mac_packaged.yml
vendored
@@ -69,7 +69,7 @@ jobs:
|
||||
run: |
|
||||
brew update
|
||||
brew upgrade || true
|
||||
brew install ada-url autoconf automake boost cmake ffmpeg@6 libtool openal-soft openh264 openssl opus ninja pkg-config python qt yasm xz
|
||||
brew install ada-url autoconf automake boost cmake ffmpeg libtool 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
|
||||
|
||||
6
.github/workflows/snap.yml
vendored
@@ -57,14 +57,14 @@ jobs:
|
||||
sudo iptables -P FORWARD ACCEPT
|
||||
sudo snap install --classic snapcraft
|
||||
sudo usermod -aG lxd $USER
|
||||
sudo snap run lxd init --auto
|
||||
sudo snap run lxd waitready
|
||||
sudo lxd init --auto
|
||||
sudo lxd waitready
|
||||
|
||||
- name: Free up some disk space.
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||
|
||||
- name: Telegram Desktop snap build.
|
||||
run: sg lxd -c 'snap run snapcraft --verbosity=debug'
|
||||
run: sudo -u $USER snap run snapcraft --verbosity=debug
|
||||
|
||||
- name: Move artifact.
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
|
||||
2
.gitmodules
vendored
@@ -3,7 +3,7 @@
|
||||
url = https://github.com/telegramdesktop/libtgvoip
|
||||
[submodule "Telegram/ThirdParty/GSL"]
|
||||
path = Telegram/ThirdParty/GSL
|
||||
url = https://github.com/desktop-app/GSL.git
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
[submodule "Telegram/ThirdParty/xxHash"]
|
||||
path = Telegram/ThirdParty/xxHash
|
||||
url = https://github.com/Cyan4973/xxHash.git
|
||||
|
||||
@@ -58,7 +58,7 @@ Version **1.8.15** was the last that supports older systems
|
||||
* Guideline Support Library ([MIT License](https://github.com/Microsoft/GSL/blob/master/LICENSE))
|
||||
* Range-v3 ([Boost License](https://github.com/ericniebler/range-v3/blob/master/LICENSE.txt))
|
||||
* Open Sans font ([Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html))
|
||||
* Vazir font ([SIL Open Font License 1.1](https://github.com/rastikerdar/vazir-font/blob/master/OFL.txt))
|
||||
* Vazirmatn font ([SIL Open Font License 1.1](https://github.com/rastikerdar/vazirmatn/blob/master/OFL.txt))
|
||||
* Emoji alpha codes ([MIT License](https://github.com/emojione/emojione/blob/master/extras/alpha-codes/LICENSE.md))
|
||||
* xxHash ([BSD License](https://github.com/Cyan4973/xxHash/blob/dev/LICENSE))
|
||||
* QR Code generator ([MIT License](https://github.com/nayuki/QR-Code-generator#license))
|
||||
|
||||
@@ -112,6 +112,8 @@ PRIVATE
|
||||
api/api_bot.h
|
||||
api/api_chat_filters.cpp
|
||||
api/api_chat_filters.h
|
||||
api/api_chat_filters_remove_manager.cpp
|
||||
api/api_chat_filters_remove_manager.h
|
||||
api/api_chat_invite.cpp
|
||||
api/api_chat_invite.h
|
||||
api/api_chat_links.cpp
|
||||
@@ -292,6 +294,8 @@ PRIVATE
|
||||
boxes/peer_list_box.h
|
||||
boxes/peer_list_controllers.cpp
|
||||
boxes/peer_list_controllers.h
|
||||
boxes/peer_list_widgets.cpp
|
||||
boxes/peer_list_widgets.h
|
||||
boxes/peer_lists_box.cpp
|
||||
boxes/peer_lists_box.h
|
||||
boxes/passcode_box.cpp
|
||||
@@ -318,8 +322,6 @@ PRIVATE
|
||||
boxes/send_gif_with_caption_box.h
|
||||
boxes/send_files_box.cpp
|
||||
boxes/send_files_box.h
|
||||
boxes/sessions_box.cpp
|
||||
boxes/sessions_box.h
|
||||
boxes/share_box.cpp
|
||||
boxes/share_box.h
|
||||
boxes/star_gift_box.cpp
|
||||
@@ -466,6 +468,7 @@ PRIVATE
|
||||
core/sandbox.h
|
||||
core/shortcuts.cpp
|
||||
core/shortcuts.h
|
||||
core/stars_amount.h
|
||||
core/ui_integration.cpp
|
||||
core/ui_integration.h
|
||||
core/update_checker.cpp
|
||||
@@ -636,6 +639,8 @@ PRIVATE
|
||||
data/data_thread.h
|
||||
data/data_types.cpp
|
||||
data/data_types.h
|
||||
data/data_unread_value.cpp
|
||||
data/data_unread_value.h
|
||||
data/data_user.cpp
|
||||
data/data_user.h
|
||||
data/data_user_photos.cpp
|
||||
@@ -913,6 +918,12 @@ PRIVATE
|
||||
info/bot/earn/info_bot_earn_list.h
|
||||
info/bot/earn/info_bot_earn_widget.cpp
|
||||
info/bot/earn/info_bot_earn_widget.h
|
||||
info/bot/starref/info_bot_starref_common.cpp
|
||||
info/bot/starref/info_bot_starref_common.h
|
||||
info/bot/starref/info_bot_starref_join_widget.cpp
|
||||
info/bot/starref/info_bot_starref_join_widget.h
|
||||
info/bot/starref/info_bot_starref_setup_widget.cpp
|
||||
info/bot/starref/info_bot_starref_setup_widget.h
|
||||
info/channel_statistics/boosts/create_giveaway_box.cpp
|
||||
info/channel_statistics/boosts/create_giveaway_box.h
|
||||
info/channel_statistics/boosts/giveaway/giveaway_list_controllers.cpp
|
||||
@@ -935,6 +946,12 @@ PRIVATE
|
||||
info/downloads/info_downloads_provider.h
|
||||
info/downloads/info_downloads_widget.cpp
|
||||
info/downloads/info_downloads_widget.h
|
||||
info/global_media/info_global_media_widget.cpp
|
||||
info/global_media/info_global_media_widget.h
|
||||
info/global_media/info_global_media_inner_widget.cpp
|
||||
info/global_media/info_global_media_inner_widget.h
|
||||
info/global_media/info_global_media_provider.cpp
|
||||
info/global_media/info_global_media_provider.h
|
||||
info/media/info_media_buttons.h
|
||||
info/media/info_media_common.cpp
|
||||
info/media/info_media_common.h
|
||||
@@ -982,6 +999,10 @@ PRIVATE
|
||||
info/profile/info_profile_values.h
|
||||
info/profile/info_profile_widget.cpp
|
||||
info/profile/info_profile_widget.h
|
||||
info/reactions_list/info_reactions_list_widget.cpp
|
||||
info/reactions_list/info_reactions_list_widget.h
|
||||
info/requests_list/info_requests_list_widget.cpp
|
||||
info/requests_list/info_requests_list_widget.h
|
||||
info/saved/info_saved_sublists_widget.cpp
|
||||
info/saved/info_saved_sublists_widget.h
|
||||
info/settings/info_settings_widget.cpp
|
||||
@@ -995,6 +1016,7 @@ PRIVATE
|
||||
info/statistics/info_statistics_list_controllers.h
|
||||
info/statistics/info_statistics_recent_message.cpp
|
||||
info/statistics/info_statistics_recent_message.h
|
||||
info/statistics/info_statistics_tag.h
|
||||
info/statistics/info_statistics_widget.cpp
|
||||
info/statistics/info_statistics_widget.h
|
||||
info/stories/info_stories_inner_widget.cpp
|
||||
@@ -1031,6 +1053,10 @@ PRIVATE
|
||||
info/info_wrap_widget.h
|
||||
inline_bots/bot_attach_web_view.cpp
|
||||
inline_bots/bot_attach_web_view.h
|
||||
inline_bots/inline_bot_confirm_prepared.cpp
|
||||
inline_bots/inline_bot_confirm_prepared.h
|
||||
inline_bots/inline_bot_downloads.cpp
|
||||
inline_bots/inline_bot_downloads.h
|
||||
inline_bots/inline_bot_layout_internal.cpp
|
||||
inline_bots/inline_bot_layout_internal.h
|
||||
inline_bots/inline_bot_layout_item.cpp
|
||||
@@ -1162,6 +1188,8 @@ PRIVATE
|
||||
media/streaming/media_streaming_player.h
|
||||
media/streaming/media_streaming_reader.cpp
|
||||
media/streaming/media_streaming_reader.h
|
||||
media/streaming/media_streaming_round_preview.cpp
|
||||
media/streaming/media_streaming_round_preview.h
|
||||
media/streaming/media_streaming_utility.cpp
|
||||
media/streaming/media_streaming_utility.h
|
||||
media/streaming/media_streaming_video_track.cpp
|
||||
@@ -1388,6 +1416,8 @@ PRIVATE
|
||||
settings/cloud_password/settings_cloud_password_manage.h
|
||||
settings/cloud_password/settings_cloud_password_start.cpp
|
||||
settings/cloud_password/settings_cloud_password_start.h
|
||||
settings/settings_active_sessions.cpp
|
||||
settings/settings_active_sessions.h
|
||||
settings/settings_advanced.cpp
|
||||
settings/settings_advanced.h
|
||||
settings/settings_blocked_peers.cpp
|
||||
@@ -1501,6 +1531,8 @@ PRIVATE
|
||||
ui/chat/choose_send_as.h
|
||||
ui/chat/choose_theme_controller.cpp
|
||||
ui/chat/choose_theme_controller.h
|
||||
ui/chat/sponsored_message_bar.cpp
|
||||
ui/chat/sponsored_message_bar.h
|
||||
ui/controls/emoji_button_factory.cpp
|
||||
ui/controls/emoji_button_factory.h
|
||||
ui/controls/location_picker.cpp
|
||||
@@ -1532,6 +1564,10 @@ PRIVATE
|
||||
ui/widgets/expandable_peer_list.h
|
||||
ui/widgets/label_with_custom_emoji.cpp
|
||||
ui/widgets/label_with_custom_emoji.h
|
||||
ui/widgets/chat_filters_tabs_strip.cpp
|
||||
ui/widgets/chat_filters_tabs_strip.h
|
||||
ui/widgets/peer_bubble.cpp
|
||||
ui/widgets/peer_bubble.h
|
||||
ui/countryinput.cpp
|
||||
ui/countryinput.h
|
||||
ui/dynamic_thumbnails.cpp
|
||||
@@ -1543,8 +1579,6 @@ PRIVATE
|
||||
ui/item_text_options.cpp
|
||||
ui/item_text_options.h
|
||||
ui/resize_area.h
|
||||
ui/search_field_controller.cpp
|
||||
ui/search_field_controller.h
|
||||
ui/unread_badge.cpp
|
||||
ui/unread_badge.h
|
||||
window/main_window.cpp
|
||||
@@ -1849,7 +1883,7 @@ endif()
|
||||
|
||||
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
|
||||
|
||||
if (WIN32 AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
if (MSVC)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
delayimp
|
||||
@@ -1946,7 +1980,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_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
if (MSVC)
|
||||
target_link_libraries(Updater
|
||||
PRIVATE
|
||||
delayimp
|
||||
|
||||
BIN
Telegram/Resources/animations/hello_status.tgs
Normal file
BIN
Telegram/Resources/animations/starref_link.tgs
Normal file
BIN
Telegram/Resources/art/affiliate_logo.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
Telegram/Resources/art/round_placeholder.jpg
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
Telegram/Resources/icons/chat/input_video.png
Normal file
|
After Width: | Height: | Size: 621 B |
BIN
Telegram/Resources/icons/chat/input_video@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/chat/input_video@3x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Telegram/Resources/icons/menu/affiliate_simple.png
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
Telegram/Resources/icons/menu/affiliate_simple@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/menu/affiliate_simple@3x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/menu/affiliate_transparent.png
Normal file
|
After Width: | Height: | Size: 820 B |
BIN
Telegram/Resources/icons/menu/affiliate_transparent@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/menu/affiliate_transparent@3x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram/Resources/icons/menu/bot.png
Normal file
|
After Width: | Height: | Size: 586 B |
BIN
Telegram/Resources/icons/menu/bot@2x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Telegram/Resources/icons/menu/bot@3x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/menu/bot_add.png
Normal file
|
After Width: | Height: | Size: 699 B |
BIN
Telegram/Resources/icons/menu/bot_add@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/menu/bot_add@3x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/menu/caption_hide.png
Normal file
|
After Width: | Height: | Size: 718 B |
BIN
Telegram/Resources/icons/menu/caption_hide@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/menu/caption_hide@3x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/menu/caption_show.png
Normal file
|
After Width: | Height: | Size: 505 B |
BIN
Telegram/Resources/icons/menu/caption_show@2x.png
Normal file
|
After Width: | Height: | Size: 763 B |
BIN
Telegram/Resources/icons/menu/caption_show@3x.png
Normal file
|
After Width: | Height: | Size: 963 B |
BIN
Telegram/Resources/icons/menu/edited_status.png
Normal file
|
After Width: | Height: | Size: 586 B |
BIN
Telegram/Resources/icons/menu/edited_status@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/menu/edited_status@3x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/menu/forwarded_status.png
Normal file
|
After Width: | Height: | Size: 691 B |
BIN
Telegram/Resources/icons/menu/forwarded_status@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/menu/forwarded_status@3x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Telegram/Resources/icons/menu/name_hide.png
Normal file
|
After Width: | Height: | Size: 615 B |
BIN
Telegram/Resources/icons/menu/name_hide@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/menu/name_hide@3x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/menu/name_show.png
Normal file
|
After Width: | Height: | Size: 517 B |
BIN
Telegram/Resources/icons/menu/name_show@2x.png
Normal file
|
After Width: | Height: | Size: 959 B |
BIN
Telegram/Resources/icons/menu/name_show@3x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/menu/stars_share.png
Normal file
|
After Width: | Height: | Size: 791 B |
BIN
Telegram/Resources/icons/menu/stars_share@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/menu/stars_share@3x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Telegram/Resources/icons/player/player_settings.png
Normal file
|
After Width: | Height: | Size: 997 B |
BIN
Telegram/Resources/icons/player/player_settings@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/player/player_settings@3x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 654 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/voice_lock/input_round_s.png
Normal file
|
After Width: | Height: | Size: 498 B |
BIN
Telegram/Resources/icons/voice_lock/input_round_s@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/voice_lock/input_round_s@3x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
@@ -12,6 +12,7 @@ body {
|
||||
margin: 0;
|
||||
background-color: var(--td-window-bg);
|
||||
color: var(--td-window-fg);
|
||||
zoom: var(--td-zoom-percentage);
|
||||
}
|
||||
|
||||
html.custom_scroll ::-webkit-scrollbar {
|
||||
|
||||
@@ -72,6 +72,9 @@ var IV = {
|
||||
}
|
||||
},
|
||||
frameKeyDown: function (e) {
|
||||
const key0 = (e.key === '0')
|
||||
|| (e.code === 'Key0')
|
||||
|| (e.keyCode === 48);
|
||||
const keyW = (e.key === 'w')
|
||||
|| (e.code === 'KeyW')
|
||||
|| (e.keyCode === 87);
|
||||
@@ -81,12 +84,12 @@ var IV = {
|
||||
const keyM = (e.key === 'm')
|
||||
|| (e.code === 'KeyM')
|
||||
|| (e.keyCode === 77);
|
||||
if ((e.metaKey || e.ctrlKey) && (keyW || keyQ || keyM)) {
|
||||
if ((e.metaKey || e.ctrlKey) && (keyW || keyQ || keyM || key0)) {
|
||||
e.preventDefault();
|
||||
IV.notify({
|
||||
event: 'keydown',
|
||||
modifier: e.ctrlKey ? 'ctrl' : 'cmd',
|
||||
key: keyW ? 'w' : keyQ ? 'q' : 'm',
|
||||
key: key0 ? '0' : keyW ? 'w' : keyQ ? 'q' : 'm',
|
||||
});
|
||||
} else if (e.key === 'Escape' || e.keyCode === 27) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_menu_activate" = "Use this account";
|
||||
"lng_menu_set_status" = "Set Emoji Status";
|
||||
"lng_menu_change_status" = "Change Emoji Status";
|
||||
"lng_menu_my_profile" = "My Profile";
|
||||
"lng_menu_my_stories" = "My Stories";
|
||||
"lng_menu_my_groups" = "My Groups";
|
||||
"lng_menu_my_channels" = "My Channels";
|
||||
@@ -288,8 +289,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_error_cant_add_member" = "Sorry, you can't add the bot to this group. Ask a group admin to do it.";
|
||||
"lng_error_cant_add_bot" = "Sorry, this bot can't be added to groups.";
|
||||
"lng_error_cant_add_admin_invite" = "You can't add this user as an admin because they are not a member of this group and you are not allowed to add them.";
|
||||
"lng_error_you_blocked_user" = "Sorry, you can't add this user or bot to groups because you've blocked them. Please unblock to proceed.";
|
||||
"lng_error_add_admin_not_member" = "You can't add this user as an admin because they are not a member of this group and you are not allowed to add them.";
|
||||
"lng_error_user_admin_invalid" = "You can't ban this user because they are an admin in this group and you are not allowed to demote them.";
|
||||
"lng_error_channel_bots_too_much" = "Sorry, this channel has too many bots.";
|
||||
"lng_error_group_bots_too_much" = "There are too many bots in this group. Please remove some of the bots you're not using first.";
|
||||
"lng_error_cant_add_admin_unban" = "Sorry, you can't add this user as an admin because they are in the Removed Users list and you can't unban them.";
|
||||
"lng_error_cant_ban_admin" = "You can't ban this user because they are an admin in this group and you are not allowed to demote them.";
|
||||
"lng_error_cant_reply_other" = "This message can't be replied in another chat.";
|
||||
"lng_error_admin_limit" = "Sorry, you've reached the maximum number of admins for this group.";
|
||||
"lng_error_admin_limit_channel" = "Sorry, you've reached the maximum number of admins for this channel.";
|
||||
"lng_error_post_link_invalid" = "Unfortunately, you can't access this message. You aren't a member of the chat where it was posted.";
|
||||
@@ -298,6 +305,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_error_nocopy_group" = "Sorry, copying from this group is disabled by admins.";
|
||||
"lng_error_nocopy_channel" = "Sorry, copying from this channel is disabled by admins.";
|
||||
"lng_error_nocopy_story" = "Sorry, the creator of this story disabled copying.";
|
||||
"lng_error_schedule_limit" = "Sorry, you can't schedule more than 100 messages.";
|
||||
"lng_sure_add_admin_invite" = "This user is not a member of this group. Add them to the group and promote them to admin?";
|
||||
"lng_sure_add_admin_invite_channel" = "This user is not a subscriber of this channel. Add them to the channel and promote them to admin?";
|
||||
"lng_sure_add_admin_unremove" = "This user is currently restricted or removed. Are you sure you want to promote them?";
|
||||
@@ -499,8 +507,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_notify_global" = "Global settings";
|
||||
"lng_settings_notify_title" = "Notifications for chats";
|
||||
"lng_settings_desktop_notify" = "Desktop notifications";
|
||||
"lng_settings_native_title" = "Native notifications";
|
||||
"lng_settings_native_title" = "System integration";
|
||||
"lng_settings_use_windows" = "Use Windows notifications";
|
||||
"lng_settings_skip_in_focus" = "Respect system Focus mode";
|
||||
"lng_settings_use_native_notifications" = "Use native notifications";
|
||||
"lng_settings_notifications_position" = "Location on the screen";
|
||||
"lng_settings_notifications_count" = "Notifications count";
|
||||
@@ -681,6 +690,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_messages_privacy" = "Messages";
|
||||
"lng_settings_voices_privacy" = "Voice messages";
|
||||
"lng_settings_bio_privacy" = "Bio";
|
||||
"lng_settings_gifts_privacy" = "Gifts";
|
||||
"lng_settings_birthday_privacy" = "Date of Birth";
|
||||
"lng_settings_privacy_premium" = "Only subscribers of {link} can restrict receiving voice messages.";
|
||||
"lng_settings_privacy_premium_link" = "Telegram Premium";
|
||||
@@ -1161,19 +1171,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_blocked_list_subtitle#other" = "{count} blocked users";
|
||||
|
||||
"lng_edit_privacy_everyone" = "Everybody";
|
||||
"lng_edit_privacy_no_miniapps" = "Not Mini Apps";
|
||||
"lng_edit_privacy_contacts" = "My contacts";
|
||||
"lng_edit_privacy_close_friends" = "Close friends";
|
||||
"lng_edit_privacy_contacts_and_premium" = "Contacts & Premium";
|
||||
"lng_edit_privacy_contacts_and_miniapps" = "Contacts & Mini Apps";
|
||||
"lng_edit_privacy_nobody" = "Nobody";
|
||||
"lng_edit_privacy_premium" = "Premium users";
|
||||
"lng_edit_privacy_miniapps" = "Mini Apps";
|
||||
"lng_edit_privacy_exceptions" = "Add exceptions";
|
||||
"lng_edit_privacy_user_types" = "User types";
|
||||
"lng_edit_privacy_users_and_groups" = "Users and groups";
|
||||
"lng_edit_privacy_premium_status" = "all Telegram Premium subscribers";
|
||||
"lng_edit_privacy_miniapps_status" = "web mini apps that you use";
|
||||
|
||||
"lng_edit_privacy_exceptions_count#one" = "{count} user";
|
||||
"lng_edit_privacy_exceptions_count#other" = "{count} users";
|
||||
"lng_edit_privacy_exceptions_premium_and" = "Premium & {users}";
|
||||
"lng_edit_privacy_exceptions_miniapps_and" = "Mini Apps & {users}";
|
||||
"lng_edit_privacy_exceptions_add" = "Add users";
|
||||
|
||||
"lng_edit_privacy_phone_number_title" = "Phone number privacy";
|
||||
@@ -1227,6 +1242,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_privacy_birthday_yet" = "You haven't entered your date of birth yet.\n{link}";
|
||||
"lng_edit_privacy_birthday_yet_link" = "Add my birthday >";
|
||||
|
||||
"lng_edit_privacy_gifts_title" = "Gifts";
|
||||
"lng_edit_privacy_gifts_header" = "Who can display gifts on my profile";
|
||||
"lng_edit_privacy_gifts_always_empty" = "Always allow";
|
||||
"lng_edit_privacy_gifts_never_empty" = "Never allow";
|
||||
"lng_edit_privacy_gifts_exceptions" = "Choose whether gifts from specific senders need your approval before they're visible to others on your profile.";
|
||||
"lng_edit_privacy_gifts_always_title" = "Always allow";
|
||||
"lng_edit_privacy_gifts_never_title" = "Never allow";
|
||||
|
||||
"lng_edit_privacy_calls_title" = "Calls";
|
||||
"lng_edit_privacy_calls_header" = "Who can call me";
|
||||
"lng_edit_privacy_calls_always_empty" = "Always allow";
|
||||
@@ -1458,13 +1481,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_enable_notifications" = "Notifications";
|
||||
"lng_profile_send_message" = "Send Message";
|
||||
"lng_profile_open_app" = "Open App";
|
||||
"lng_profile_open_app_short" = "Open";
|
||||
"lng_profile_open_app_about" = "By launching this mini app, you agree to the {terms}.";
|
||||
"lng_profile_open_app_terms" = "Terms of Service for Mini Apps";
|
||||
"lng_profile_bot_permissions_title" = "Allow access to";
|
||||
"lng_profile_bot_emoji_status_access" = "Emoji Status";
|
||||
"lng_info_add_as_contact" = "Add to contacts";
|
||||
"lng_profile_shared_media" = "Shared media";
|
||||
"lng_profile_suggest_photo" = "Suggest Profile Photo";
|
||||
"lng_profile_suggest_photo_from_clipboard" = "Suggest From Clipboard";
|
||||
"lng_profile_set_photo_for" = "Set Profile Photo";
|
||||
"lng_profile_set_photo_for_from_clipboard" = "Set From Clipboard";
|
||||
"lng_profile_photo_reset" = "Reset to Original";
|
||||
"lng_profile_photo_from_clipboard" = "From clipboard";
|
||||
"lng_profile_suggest_sure" = "You can suggest {user} to set this photo for their Telegram profile.";
|
||||
"lng_profile_suggest_button" = "Suggest";
|
||||
"lng_profile_set_personal_sure" = "Only you will see this photo and it will replace any photo {user} sets for themselves.";
|
||||
@@ -1522,6 +1551,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_manage_channel_title" = "Manage Channel";
|
||||
"lng_manage_bot_title" = "Manage Bot";
|
||||
"lng_manage_peer_recent_actions" = "Recent actions";
|
||||
"lng_manage_peer_star_ref" = "Affiliate programs";
|
||||
"lng_manage_peer_members" = "Members";
|
||||
"lng_manage_peer_subscribers" = "Subscribers";
|
||||
"lng_manage_peer_administrators" = "Administrators";
|
||||
@@ -1593,11 +1623,101 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_manage_peer_bot_public_link" = "Public Link";
|
||||
"lng_manage_peer_bot_public_links" = "Public Links";
|
||||
"lng_manage_peer_bot_balance" = "Balance";
|
||||
"lng_manage_peer_bot_balance_currency" = "Toncoin";
|
||||
"lng_manage_peer_bot_balance_credits" = "Stars";
|
||||
"lng_manage_peer_bot_star_ref" = "Affiliate Program";
|
||||
"lng_manage_peer_bot_star_ref_off" = "Off";
|
||||
"lng_manage_peer_bot_star_ref_about" = "Share a link to {bot} with your friends and earn {amount} of their spending there.";
|
||||
"lng_manage_peer_bot_edit_intro" = "Edit Intro";
|
||||
"lng_manage_peer_bot_edit_commands" = "Edit Commands";
|
||||
"lng_manage_peer_bot_edit_settings" = "Change Bot Settings";
|
||||
"lng_manage_peer_bot_about" = "Use {bot} to manage this bot.";
|
||||
|
||||
"lng_star_ref_title" = "Affiliate Program";
|
||||
"lng_star_ref_about" = "Reward those who help grow your user base.";
|
||||
"lng_star_ref_share_title" = "Share revenue with affiliates";
|
||||
"lng_star_ref_share_about" = "Set the commission for revenue generated by users referred to you.";
|
||||
"lng_star_ref_launch_title" = "Launch your affiliate program";
|
||||
"lng_star_ref_launch_about" = "Telegram will feature your program for millions of potential affiliates.";
|
||||
"lng_star_ref_let_title" = "Let affiliate promote you";
|
||||
"lng_star_ref_let_about" = "Affiliates will share your referral link with their audience.";
|
||||
"lng_star_ref_commission_title" = "Commission";
|
||||
"lng_star_ref_commission_about" = "Define the percentage of star revenue your affiliates earn for referring users to your bot.";
|
||||
"lng_star_ref_duration_title" = "Duration";
|
||||
"lng_star_ref_duration_about" = "Set the duration for which affiliates will earn commissions from referred users.";
|
||||
"lng_star_ref_existing_title" = "View existing programs";
|
||||
"lng_star_ref_existing_about" = "Explore what other mini apps offer.";
|
||||
"lng_star_ref_add_bot" = "Add {bot}";
|
||||
"lng_star_ref_end" = "End Affiliate Program";
|
||||
"lng_star_ref_start" = "Start Affiliate Program";
|
||||
"lng_star_ref_start_disabled" = "Available in {time}";
|
||||
"lng_star_ref_start_info" = "By creating an affiliate program, you agree to the {terms} of Affiliate Programs.";
|
||||
"lng_star_ref_update" = "Update Affiliate Program";
|
||||
"lng_star_ref_update_info" = "By updating an affiliate program, you agree to the {terms} of Affiliate Programs.";
|
||||
"lng_star_ref_button_link" = "terms and conditions";
|
||||
"lng_star_ref_tos_url" = "https://telegram.org/tos/mini-apps";
|
||||
"lng_star_ref_warning_title" = "Warning";
|
||||
"lng_star_ref_warning_text" = "Once you start the affiliate program, you won't be able to decrease its commission or duration. You can only increase these parameters or end the program, which will disable all previously distributed referral links.";
|
||||
"lng_star_ref_warning_change" = "This change is irreversible. You won't be able to reduce commission or duration. You can only increase these parameters or end the program, which will disable all previously shared referral links.";
|
||||
"lng_star_ref_warning_start" = "Start";
|
||||
"lng_star_ref_warning_update" = "Update";
|
||||
"lng_star_ref_warning_if_end" = "If you end your affiliate program:";
|
||||
"lng_star_ref_warning_if_end1" = "Any referral links already shared will be disabled in **24** hours.";
|
||||
"lng_star_ref_warning_if_end2" = "All participating affiliates will be notified.";
|
||||
"lng_star_ref_warning_if_end3" = "You will be able to start a new affiliate program only in **24** hours.";
|
||||
"lng_star_ref_warning_end" = "End Anyway";
|
||||
"lng_star_ref_created_title" = "Affiliate program started";
|
||||
"lng_star_ref_created_text" = "Any Telegram user, channel owner or mini app developer can now join your program.";
|
||||
"lng_star_ref_updated_title" = "Affiliate program updated";
|
||||
"lng_star_ref_updated_text" = "Any Telegram user, channel owner or mini app developer can join your program.";
|
||||
"lng_star_ref_ended_title" = "Affiliate program ended";
|
||||
"lng_star_ref_ended_text" = "Participating affiliates have been notified. All referral links will be disabled in **24** hours.";
|
||||
"lng_star_ref_list_title" = "Affiliate Programs";
|
||||
"lng_star_ref_list_about_channel" = "Promote mini apps to your subscribers and earn a share of their revenue in Stars.";
|
||||
"lng_star_ref_list_text" = "Earn a commission each time a user who first accessed a mini app through your referral link spends **Stars** within it.";
|
||||
"lng_star_ref_list_my" = "My Programs";
|
||||
"lng_star_ref_list_my_open" = "Open App";
|
||||
"lng_star_ref_list_my_copy" = "Copy Link";
|
||||
"lng_star_ref_list_my_leave" = "Leave";
|
||||
"lng_star_ref_list_subtitle" = "Programs";
|
||||
"lng_star_ref_sort_text" = "Sort by {sort}";
|
||||
"lng_star_ref_sort_profitability" = "Profitability";
|
||||
"lng_star_ref_sort_date" = "Date";
|
||||
"lng_star_ref_sort_revenue" = "Revenue";
|
||||
"lng_star_ref_reliable_title" = "Reliable";
|
||||
"lng_star_ref_reliable_about" = "Receive guaranteed commissions for spending by users you refer.";
|
||||
"lng_star_ref_transparent_title" = "Transparent";
|
||||
"lng_star_ref_transparent_about" = "Track your commissions from referred users in real time.";
|
||||
"lng_star_ref_simple_title" = "Simple";
|
||||
"lng_star_ref_simple_about" = "Choose a mini app below, get your referral link, and start earning Stars.";
|
||||
"lng_star_ref_duration_forever" = "Forever";
|
||||
"lng_star_ref_one_about" = "{app} will share {amount} of the revenue from each user you refer to it {duration}.";
|
||||
"lng_star_ref_one_about_for_forever" = "for **lifetime**";
|
||||
"lng_star_ref_one_about_for_months#one" = "for **{count} month**";
|
||||
"lng_star_ref_one_about_for_months#other" = "for **{count} months**";
|
||||
"lng_star_ref_one_about_for_years#one" = "for **{count} year**";
|
||||
"lng_star_ref_one_about_for_years#other" = "for **{count} years**";
|
||||
"lng_star_ref_one_daily_revenue" = "Daily revenue per user: {amount}";
|
||||
"lng_star_ref_one_join" = "Join Program";
|
||||
"lng_star_ref_one_join_text" = "By joining this program, you agree to the {terms} of Affiliate Programs.";
|
||||
"lng_star_ref_joined_title" = "Program joined";
|
||||
"lng_star_ref_joined_text" = "You can now copy the referral link.";
|
||||
"lng_star_ref_link_title" = "Referral Link";
|
||||
"lng_star_ref_link_about_channel" = "Share this link with your subscribers to earn a {amount} commission on their spending in {app} {duration}.";
|
||||
"lng_star_ref_link_about_user" = "Share this link with your friends to earn a {amount} commission on their spending in {app} {duration}.";
|
||||
"lng_star_ref_link_about_bot" = "Share this link with your users to earn a {amount} commission on their spending in {app} {duration}.";
|
||||
"lng_star_ref_link_recipient" = "Commissions will be sent to:";
|
||||
"lng_star_ref_link_copy" = "Copy Link";
|
||||
"lng_star_ref_link_copy_none" = "No one have opened {app} through this link.";
|
||||
"lng_star_ref_link_copy_users#one" = "{count} user have opened {app} through this link.";
|
||||
"lng_star_ref_link_copy_users#other" = "{count} users have opened {app} through this link.";
|
||||
"lng_star_ref_link_copied_title" = "Link copied to clipboard";
|
||||
"lng_star_ref_link_copied_text" = "Share this link and earn {amount} of what people who use it spend in {app}!";
|
||||
"lng_star_ref_stopped" = "This affiliate link is no longer active.";
|
||||
"lng_star_ref_revoke_title" = "Revoke Link";
|
||||
"lng_star_ref_revoke_text" = "Are you sure you want to revoke the link of {bot}?";
|
||||
"lng_star_ref_revoked_title" = "Link removed";
|
||||
"lng_star_ref_revoked_text" = "It will no longer work.";
|
||||
|
||||
"lng_manage_discussion_group" = "Discussion";
|
||||
"lng_manage_discussion_group_add" = "Add a group";
|
||||
@@ -1839,6 +1959,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_payment_init_recurring_for" = "You successfully transferred {amount} to {user} for {invoice} and allowed future recurring payments";
|
||||
"lng_action_payment_init_recurring" = "You successfully transferred {amount} to {user} and allowed future recurring payments";
|
||||
"lng_action_payment_used_recurring" = "You were charged {amount} via recurring payment";
|
||||
"lng_action_payment_bot_done" = "Bot connected to this account received {amount}";
|
||||
"lng_action_payment_bot_recurring" = "Bot connected to this account received {amount} via recurring payment";
|
||||
"lng_action_took_screenshot" = "{from} took a screenshot!";
|
||||
"lng_action_you_took_screenshot" = "You took a screenshot!";
|
||||
"lng_action_bot_allowed_from_domain" = "You allowed this bot to message you when you logged in on {domain}.";
|
||||
@@ -1870,6 +1992,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_gift_got_subtitle" = "Gift from {user}";
|
||||
"lng_action_gift_got_stars_text#one" = "Display this gift on your page or convert it to **{count}** Star.";
|
||||
"lng_action_gift_got_stars_text#other" = "Display this gift on your page or convert it to **{count}** Stars.";
|
||||
"lng_action_gift_got_gift_text" = "You can keep this gift on your page.";
|
||||
"lng_action_gift_can_remove_text" = "You can remove this gift from your page.";
|
||||
"lng_action_gift_sent_subtitle" = "Gift for {user}";
|
||||
"lng_action_gift_sent_text#one" = "{user} can display this gift on their page or convert it to {count} Star.";
|
||||
"lng_action_gift_sent_text#other" = "{user} can display this gift on their page or convert it to {count} Stars.";
|
||||
@@ -2097,6 +2221,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_channel_public_link_copied" = "Link copied to clipboard.";
|
||||
"lng_context_about_private_link" = "This link will only work for members of this chat.";
|
||||
"lng_public_post_private_hint_ctrl" = "Use Ctrl+Click to copy a non-public link.";
|
||||
"lng_public_post_private_hint_cmd" = "Use Cmd+Click to copy a non-public link.";
|
||||
|
||||
"lng_forwarded" = "Forwarded from {user}";
|
||||
"lng_forwarded_story" = "Story from {user}";
|
||||
@@ -2115,8 +2241,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_recommended_message_title" = "Recommended";
|
||||
"lng_edited" = "edited";
|
||||
"lng_commented" = "commented";
|
||||
"lng_approximate" = "appx.";
|
||||
"lng_edited_date" = "Edited: {date}";
|
||||
"lng_sent_date" = "Sent: {date}";
|
||||
"lng_approximate_about" = "Estimated date of video publishing.";
|
||||
"lng_views_tooltip#one" = "Views: {count}";
|
||||
"lng_views_tooltip#other" = "Views: {count}";
|
||||
"lng_forwards_tooltip#one" = "Shares: {count}";
|
||||
@@ -2151,6 +2279,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_media_cancel" = "Cancel";
|
||||
"lng_media_video" = "Video";
|
||||
"lng_media_audio" = "Voice message";
|
||||
"lng_media_round" = "Video message";
|
||||
|
||||
"lng_media_auto_settings" = "Automatic media download";
|
||||
"lng_media_auto_in_private" = "In private chats";
|
||||
@@ -2267,6 +2396,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_premium_summary_about_business" = "Upgrade your account with business features such as location, opening hours and quick replies.";
|
||||
"lng_premium_summary_subtitle_effects" = "Message Effects";
|
||||
"lng_premium_summary_about_effects" = "Add over 500 animated effects to private messages.";
|
||||
"lng_premium_summary_subtitle_filter_tags" = "Tag Your Chats";
|
||||
"lng_premium_summary_about_filter_tags" = "Display folder names for each chat in the chat list.";
|
||||
"lng_premium_summary_bottom_subtitle" = "About Telegram Premium";
|
||||
"lng_premium_summary_bottom_about" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";
|
||||
"lng_premium_summary_button" = "Subscribe for {cost} per month";
|
||||
@@ -2399,11 +2530,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_credits_summary_options_about" = "By proceeding and purchasing Stars, you agree with the {link}.";
|
||||
"lng_credits_summary_options_about_link" = "Terms and Conditions";
|
||||
"lng_credits_summary_options_about_url" = "https://telegram.org/tos/stars";
|
||||
"lng_credits_summary_earn_title" = "Earn Stars";
|
||||
"lng_credits_summary_earn_about" = "Distribute links to mini apps and earn a share of their revenue in Stars.";
|
||||
"lng_credits_summary_history_tab_full" = "All Transactions";
|
||||
"lng_credits_summary_history_tab_in" = "Incoming";
|
||||
"lng_credits_summary_history_tab_out" = "Outgoing";
|
||||
"lng_credits_summary_history_entry_inner_in" = "In-App Purchase";
|
||||
"lng_credits_summary_balance" = "Balance";
|
||||
"lng_credits_commission" = "{amount} commission";
|
||||
"lng_credits_more_options" = "More Options";
|
||||
"lng_credits_balance_me" = "your balance";
|
||||
"lng_credits_buy_button" = "Buy More Stars";
|
||||
"lng_credits_gift_button" = "Gift Stars to Friends";
|
||||
"lng_credits_box_out_title" = "Confirm Your Purchase";
|
||||
"lng_credits_box_out_sure#one" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Star**?";
|
||||
@@ -2412,6 +2549,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_credits_box_out_media#other" = "Do you want to unlock {media} in {chat} for **{count} Stars**?";
|
||||
"lng_credits_box_out_media_user#one" = "Do you want to unlock {media} from {user} for **{count} Star**?";
|
||||
"lng_credits_box_out_media_user#other" = "Do you want to unlock {media} from {user} for **{count} Stars**?";
|
||||
"lng_credits_box_out_subscription_bot#one" = "Do you want to subscribe to **{title}** in **{recipient}** for **{count}** star per month?";
|
||||
"lng_credits_box_out_subscription_bot#other" = "Do you want to subscribe to **{title}** in **{recipient}** for **{count}** stars per month?";
|
||||
"lng_credits_box_out_subscription_business#one" = "Do you want to subscribe to **{title}** from **{recipient}** for **{count}** star per month?";
|
||||
"lng_credits_box_out_subscription_business#other" = "Do you want to subscribe to **{title}** from **{recipient}** for **{count}** stars per month?";
|
||||
"lng_credits_box_out_subscription_confirm#one" = "Subscribe for {emoji} {count} / month";
|
||||
"lng_credits_box_out_subscription_confirm#other" = "Subscribe for {emoji} {count} / month";
|
||||
"lng_credits_box_out_photo" = "a photo";
|
||||
"lng_credits_box_out_photos#one" = "{count} photo";
|
||||
"lng_credits_box_out_photos#other" = "{count} photos";
|
||||
@@ -2442,18 +2585,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_credits_box_history_entry_giveaway_name" = "Received Prize";
|
||||
"lng_credits_box_history_entry_gift_sent" = "Sent Gift";
|
||||
"lng_credits_box_history_entry_gift_converted" = "Converted Gift";
|
||||
"lng_credits_box_history_entry_gift_unavailable" = "Unavailable";
|
||||
"lng_credits_box_history_entry_gift_sold_out" = "This gift has sold out";
|
||||
"lng_credits_box_history_entry_gift_out_about" = "With Stars, **{user}** will be able to unlock content and services on Telegram.\n{link}";
|
||||
"lng_credits_box_history_entry_gift_in_about" = "Use Stars to unlock content and services on Telegram. {link}";
|
||||
"lng_credits_box_history_entry_gift_about_link" = "See Examples {emoji}";
|
||||
"lng_credits_box_history_entry_gift_examples" = "Examples";
|
||||
"lng_credits_box_history_entry_ads" = "Ads Platform";
|
||||
"lng_credits_box_history_entry_premium_bot" = "Stars Top-Up";
|
||||
"lng_credits_box_history_entry_api" = "Paid Broadcast";
|
||||
"lng_credits_box_history_entry_floodskip_about#one" = "{count} Message";
|
||||
"lng_credits_box_history_entry_floodskip_about#other" = "{count} Messages";
|
||||
"lng_credits_box_history_entry_floodskip_row" = "Messages";
|
||||
"lng_credits_box_history_entry_via_premium_bot" = "Premium Bot";
|
||||
"lng_credits_box_history_entry_id" = "Transaction ID";
|
||||
"lng_credits_box_history_entry_id_copied" = "Transaction ID copied to clipboard.";
|
||||
"lng_credits_box_history_entry_reason_star_ref" = "Affiliate Program";
|
||||
"lng_credits_box_history_entry_affiliate" = "Affiliate";
|
||||
"lng_credits_box_history_entry_miniapp" = "Mini App";
|
||||
"lng_credits_box_history_entry_referred" = "Referred User";
|
||||
"lng_credits_box_history_entry_success_date" = "Transaction date";
|
||||
"lng_credits_box_history_entry_success_url" = "Transaction link";
|
||||
"lng_credits_box_history_entry_media" = "Media";
|
||||
"lng_credits_box_history_entry_message" = "Message";
|
||||
"lng_credits_box_history_entry_about" = "You can dispute this transaction {link}.";
|
||||
"lng_credits_box_history_entry_about_link" = "here";
|
||||
"lng_credits_box_history_entry_reaction_name" = "Star Reaction";
|
||||
@@ -2465,6 +2619,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_credits_subscriber_subtitle" = "appx. {total} per month";
|
||||
|
||||
"lng_credits_subscription_row_to" = "Subscription";
|
||||
"lng_credits_subscription_row_to_bot" = "Bot";
|
||||
"lng_credits_subscription_row_to_business" = "Business";
|
||||
"lng_credits_subscription_row_from" = "Subscribed";
|
||||
|
||||
"lng_credits_subscription_row_next_on" = "Renews";
|
||||
@@ -2475,13 +2631,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_credits_subscription_on_about" = "If you cancel now, you will still be able to access your subscription until {date}.";
|
||||
|
||||
"lng_credits_subscription_off_button" = "Renew Subscription";
|
||||
"lng_credits_subscription_off_rejoin_button" = "Subscribe again";
|
||||
"lng_credits_subscription_off_about" = "You have canceled your subscription.";
|
||||
"lng_credits_subscription_off_by_bot_about" = "{bot} has canceled your subscription.";
|
||||
|
||||
"lng_credits_subscription_status_on" = "renews on {date}";
|
||||
"lng_credits_subscription_status_off" = "expires on {date}";
|
||||
"lng_credits_subscription_status_none" = "expired on {date}";
|
||||
"lng_credits_subscription_status_off_right" = "canceled";
|
||||
"lng_credits_subscription_status_none_right" = "expired";
|
||||
"lng_credits_subscription_status_off_by_bot_right" = "canceled\nby bot";
|
||||
|
||||
"lng_credits_small_balance_title#one" = "{count} Star Needed";
|
||||
"lng_credits_small_balance_title#other" = "{count} Stars Needed";
|
||||
@@ -2988,6 +3147,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_link_reason_unclaimed" = "Incomplete Giveaway";
|
||||
"lng_gift_link_reason_chosen" = "You were selected by the channel";
|
||||
"lng_gift_link_label_date" = "Date";
|
||||
"lng_gift_link_label_first_sale" = "First Sale";
|
||||
"lng_gift_link_label_last_sale" = "Last Sale";
|
||||
"lng_gift_link_label_value" = "Value";
|
||||
"lng_gift_link_also_send" = "You can also {link} to a friend as a gift.";
|
||||
"lng_gift_link_also_send_link" = "send this link";
|
||||
"lng_gift_link_use" = "Use Link";
|
||||
@@ -3020,6 +3182,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_stars_sold_out" = "sold out";
|
||||
"lng_gift_stars_tabs_all" = "All Gifts";
|
||||
"lng_gift_stars_tabs_limited" = "Limited";
|
||||
"lng_gift_stars_tabs_in_stock" = "In Stock";
|
||||
"lng_gift_send_title" = "Send a Gift";
|
||||
"lng_gift_send_message" = "Enter Message";
|
||||
"lng_gift_send_anonymous" = "Hide My Name";
|
||||
@@ -3036,16 +3199,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_visible_hint" = "This gift is visible to visitors of your page.";
|
||||
"lng_gift_availability" = "Availability";
|
||||
"lng_gift_from_hidden" = "Hidden User";
|
||||
"lng_gift_visibility" = "Visibility";
|
||||
"lng_gift_visibility_shown" = "Visible on your page";
|
||||
"lng_gift_visibility_hidden" = "Not visible on your page";
|
||||
"lng_gift_visibility_show" = "show";
|
||||
"lng_gift_visibility_hide" = "hide";
|
||||
"lng_gift_availability_left#one" = "{count} of {amount} left";
|
||||
"lng_gift_availability_left#other" = "{count} of {amount} left";
|
||||
"lng_gift_availability_none" = "None of {amount} left";
|
||||
"lng_gift_display_on_page" = "Display on my Page";
|
||||
"lng_gift_display_on_page_hide" = "Hide from my Page";
|
||||
"lng_gift_convert_to_stars#one" = "Convert to {count} Star";
|
||||
"lng_gift_convert_to_stars#other" = "Convert to {count} Stars";
|
||||
"lng_gift_convert_sure_title" = "Convert Gift to Stars";
|
||||
"lng_gift_convert_sure_text#one" = "Do you want to convert this gift from {user} to **{count} Star**?\n\nThis action cannot be undone.";
|
||||
"lng_gift_convert_sure_text#other" = "Do you want to convert this gift from {user} to **{count} Stars**?\n\nThis action cannot be undone.";
|
||||
"lng_gift_convert_sure_confirm#one" = "Do you want to convert this gift from {user} to **{count} Star**?";
|
||||
"lng_gift_convert_sure_confirm#other" = "Do you want to convert this gift from {user} to **{count} Stars**?";
|
||||
"lng_gift_convert_sure_limit#one" = "Conversion is available for the next **{count} day**.";
|
||||
"lng_gift_convert_sure_limit#other" = "Conversion is available for the next **{count} days**.";
|
||||
"lng_gift_convert_sure_caution" = "This action cannot be undone. This will permanently destroy the gift.";
|
||||
"lng_gift_convert_sure" = "Convert";
|
||||
"lng_gift_display_done" = "The gift is now shown on your profile page.";
|
||||
"lng_gift_display_done_hide" = "The gift is now hidden from your profile page.";
|
||||
@@ -3054,6 +3223,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_sold_out_title" = "Sold Out!";
|
||||
"lng_gift_sold_out_text#one" = "All {count} gift was already sold.";
|
||||
"lng_gift_sold_out_text#other" = "All {count} gifts were already sold.";
|
||||
"lng_gift_send_small" = "send a gift";
|
||||
"lng_gift_sell_small#one" = "sell for {count} Star";
|
||||
"lng_gift_sell_small#other" = "sell for {count} Stars";
|
||||
|
||||
"lng_accounts_limit_title" = "Limit Reached";
|
||||
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected account.";
|
||||
@@ -3243,11 +3415,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_record_cancel" = "Release outside this field to cancel";
|
||||
"lng_record_cancel_stories" = "Release outside to cancel";
|
||||
"lng_record_lock_cancel_sure" = "Do you want to stop recording and discard your voice message?";
|
||||
"lng_record_lock_cancel_sure_round" = "Do you want to stop recording and discard your video message?";
|
||||
"lng_record_listen_cancel_sure" = "Do you want to discard your recorded voice message?";
|
||||
"lng_record_listen_cancel_sure_round" = "Do you want to discard your recorded video message?";
|
||||
"lng_record_lock_discard" = "Discard";
|
||||
"lng_record_hold_tip" = "Please hold the mouse button pressed to record a voice message.";
|
||||
"lng_record_voice_tip" = "Hold to record audio. Click to switch to video.";
|
||||
"lng_record_video_tip" = "Hold to record video. Click to switch to audio.";
|
||||
"lng_record_audio_problem" = "Could not start audio recording. Please check your microphone.";
|
||||
"lng_record_video_problem" = "Could not start video recording. Please check your camera.";
|
||||
"lng_record_once_first_tooltip" = "Click to set this message to **Play Once**.";
|
||||
"lng_record_once_active_tooltip" = "The recipient will be able to listen only once.";
|
||||
"lng_record_once_active_video" = "The recipient will be able to watch only once.";
|
||||
"lng_will_be_notified" = "Subscribers will be notified when you post.";
|
||||
"lng_wont_be_notified" = "Subscribers will receive a silent notification.";
|
||||
"lng_willbe_history" = "Select a chat to start messaging";
|
||||
@@ -3276,6 +3455,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_scheduled_send_now" = "Send message now?";
|
||||
"lng_scheduled_send_now_many#one" = "Send {count} message now?";
|
||||
"lng_scheduled_send_now_many#other" = "Send {count} messages now?";
|
||||
"lng_scheduled_video_tip_title" = "Improving video...";
|
||||
"lng_scheduled_video_tip_text" = "The video will be published after it's optimized for the best viewing experience.";
|
||||
"lng_scheduled_video_tip" = "Processing video may take a few minutes.";
|
||||
"lng_scheduled_video_published" = "Video Published.";
|
||||
"lng_scheduled_video_view" = "View";
|
||||
|
||||
"lng_replies_view#one" = "View {count} Reply";
|
||||
"lng_replies_view#other" = "View {count} Replies";
|
||||
@@ -3298,6 +3482,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_replies_no_comments" = "No comments here yet...";
|
||||
|
||||
"lng_verification_codes" = "Verification Codes";
|
||||
"lng_verification_codes_about" = "Third-party services, like websites and stores, can send verification codes to your phone number via Telegram instead of SMS. Such codes will appear in this chat.\n\nIf you didn't request any codes — don't worry! Most likely, someone made a mistake when entering their number.";
|
||||
|
||||
"lng_archived_name" = "Archived chats";
|
||||
"lng_archived_add" = "Archive";
|
||||
@@ -3359,6 +3544,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_bot_settings" = "Settings";
|
||||
"lng_bot_open" = "Open Bot";
|
||||
"lng_bot_terms" = "Terms of Use";
|
||||
"lng_bot_privacy" = "Privacy Policy";
|
||||
"lng_bot_reload_page" = "Reload Page";
|
||||
"lng_bot_add_to_menu" = "{bot} asks your permission to be added as an option to your attachment menu so you can access it from any chat.";
|
||||
"lng_bot_add_to_menu_done" = "Bot added to the menu.";
|
||||
@@ -3374,6 +3560,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_bot_add_to_side_menu_done" = "Bot added to the main menu.";
|
||||
"lng_bot_no_scan_qr" = "QR Codes for bots are not supported on Desktop. Please use one of Telegram's mobile apps.";
|
||||
"lng_bot_no_share_story" = "Sharing to Stories is not supported on Desktop. Please use one of Telegram's mobile apps.";
|
||||
"lng_bot_emoji_status_confirm" = "Confirm";
|
||||
"lng_bot_emoji_status_title" = "Set Emoji Status";
|
||||
"lng_bot_emoji_status_text" = "Do you want to set this emoji status suggested by {bot}?";
|
||||
"lng_bot_emoji_status_access_text" = "{bot} requests access to set your **emoji status**. You will be able to revoke this access in the profile page of {name}.";
|
||||
"lng_bot_emoji_status_access_allow" = "Allow";
|
||||
"lng_bot_share_prepared_title" = "Share Message";
|
||||
"lng_bot_share_prepared_about" = "{bot} mini app suggests you to send this message to a chat you select.";
|
||||
"lng_bot_share_prepared_button" = "Share With...";
|
||||
"lng_bot_download_file" = "Download File";
|
||||
"lng_bot_download_file_sure" = "{bot} suggests you download the following file:";
|
||||
"lng_bot_download_file_button" = "Download";
|
||||
"lng_bot_download_starting" = "Starting...";
|
||||
"lng_bot_download_failed" = "Failed. {retry}";
|
||||
"lng_bot_download_retry" = "Retry";
|
||||
|
||||
"lng_bot_status_users#one" = "{count} monthly user";
|
||||
"lng_bot_status_users#other" = "{count} monthly users";
|
||||
@@ -3457,6 +3657,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_mark_read_sure" = "Are you sure you want to mark all chats from this folder as read?";
|
||||
"lng_context_mark_read_all" = "Mark all chats as read";
|
||||
"lng_context_mark_read_all_sure" = "Are you sure you want to mark all chats as read?";
|
||||
"lng_context_mark_read_all_sure_2" = "**This action cannot be undone.**";
|
||||
"lng_context_mark_read_mentions_all" = "Mark all mentions as read";
|
||||
"lng_context_mark_read_reactions_all" = "Read all reactions";
|
||||
"lng_context_archive_expand" = "Expand";
|
||||
@@ -3576,11 +3777,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_animated_reactions_many#one" = "Reactions contain emoji from **{count} pack**.";
|
||||
"lng_context_animated_reactions_many#other" = "Reactions contain emoji from **{count} packs**.";
|
||||
|
||||
"lng_context_noforwards_info_channel" = "Copying and forwarding is not allowed in this channel.";
|
||||
"lng_context_noforwards_info_group" = "Copying and forwarding is not allowed in this group.";
|
||||
"lng_context_noforwards_info_bot" = "Copying and forwarding is not allowed from this bot.";
|
||||
|
||||
"lng_context_spoiler_effect" = "Hide with Spoiler";
|
||||
"lng_context_disable_spoiler" = "Remove Spoiler";
|
||||
"lng_context_make_paid" = "Make This Content Paid";
|
||||
"lng_context_change_price" = "Change Price";
|
||||
|
||||
"lng_context_mention" = "Mention";
|
||||
"lng_context_search_from" = "Search messages";
|
||||
|
||||
"lng_factcheck_title" = "Fact Check";
|
||||
"lng_factcheck_placeholder" = "Add Facts or Context";
|
||||
"lng_factcheck_whats_this" = "what's this?";
|
||||
@@ -3609,6 +3817,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_paid_react_agree_link" = "Terms of Service";
|
||||
"lng_paid_react_toast#one" = "Star Sent!";
|
||||
"lng_paid_react_toast#other" = "Stars Sent!";
|
||||
"lng_paid_react_toast_anonymous#one" = "Star sent anonymously!";
|
||||
"lng_paid_react_toast_anonymous#other" = "Stars sent anonymously!";
|
||||
"lng_paid_react_toast_text#one" = "You reacted with **{count} Star**.";
|
||||
"lng_paid_react_toast_text#other" = "You reacted with **{count} Stars**.";
|
||||
"lng_paid_react_undo" = "Undo";
|
||||
@@ -3678,6 +3888,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_reply_in_another_title" = "Reply in...";
|
||||
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
||||
"lng_reply_in_author" = "Message author";
|
||||
"lng_reply_in_chats_list" = "Your chats";
|
||||
"lng_reply_show_in_chat" = "Show in Chat";
|
||||
"lng_reply_remove" = "Do Not Reply";
|
||||
"lng_reply_about_quote" = "You can select a specific part to quote.";
|
||||
@@ -3865,6 +4077,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_mediaview_downloads" = "Downloads";
|
||||
"lng_mediaview_playback_speed" = "Playback speed: {speed}";
|
||||
"lng_mediaview_rotate_video" = "Rotate video";
|
||||
"lng_mediaview_quality_auto" = "Auto";
|
||||
|
||||
"lng_theme_preview_title" = "Theme Preview";
|
||||
"lng_theme_preview_generating" = "Generating color theme preview...";
|
||||
@@ -3946,7 +4159,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_payments_webview_no_use" = "Unfortunately, you can't use payments with current system configuration.";
|
||||
"lng_payments_webview_install_edge" = "Please install {link}.";
|
||||
"lng_payments_webview_install_webkit" = "Please install WebKitGTK (webkitgtk-6.0/webkit2gtk-4.1/webkit2gtk-4.0) using your package manager.";
|
||||
"lng_payments_webview_install_webkit" = "Please install WebKitGTK (webkit2gtk-4.1/webkit2gtk-4.0) using your package manager.";
|
||||
"lng_payments_webview_enable_opengl" = "Please enable OpenGL in application settings.";
|
||||
"lng_payments_webview_switch_x11" = "Unsupported display server. Please switch to X11.";
|
||||
"lng_payments_webview_update_windows" = "Please update your system to Windows 8.1 or later.";
|
||||
"lng_payments_sure_close" = "Are you sure you want to close this payment form? The changes you made will be lost.";
|
||||
"lng_payments_receipt_label" = "Receipt";
|
||||
@@ -4306,7 +4521,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_edit_admin_rank_about" = "A title that members will see instead of '{title}'.";
|
||||
"lng_rights_about_add_admins_yes" = "This admin will be able to add new admins with equal or fewer rights.";
|
||||
"lng_rights_about_add_admins_no" = "This admin will not be able to add new admins.";
|
||||
"lng_rights_about_by" = "This admin promoted by {user} at {date}.";
|
||||
"lng_rights_about_by" = "This admin promoted by {user} on {date}.";
|
||||
|
||||
"lng_rights_about_admin_cant_edit" = "You can't edit the rights of this admin.";
|
||||
"lng_rights_about_restriction_cant_edit" = "You cannot change the restrictions for this user.";
|
||||
@@ -4385,8 +4600,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_chat_files" = "Files";
|
||||
"lng_rights_chat_voice_messages" = "Voice messages";
|
||||
"lng_rights_chat_video_messages" = "Video messages";
|
||||
"lng_rights_chat_restricted_by" = "Restricted by {user} at {date}.";
|
||||
"lng_rights_chat_banned_by" = "Banned by {user} at {date}.";
|
||||
"lng_rights_chat_restricted_by" = "Restricted by {user} on {date}.";
|
||||
"lng_rights_chat_banned_by" = "Banned by {user} on {date}.";
|
||||
"lng_rights_chat_banned_until_header" = "Restricted until";
|
||||
"lng_rights_chat_banned_forever" = "Forever";
|
||||
"lng_rights_chat_banned_day#one" = "For {count} day";
|
||||
@@ -4710,6 +4925,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_forward_show_captions" = "Show captions";
|
||||
"lng_forward_change_recipient" = "Change recipient";
|
||||
"lng_forward_sender_names_removed" = "Sender names removed";
|
||||
"lng_forward_header_short" = "Forward";
|
||||
"lng_forward_action_show_sender" = "Show Sender Name";
|
||||
"lng_forward_action_show_senders" = "Show Sender Names";
|
||||
"lng_forward_action_hide_sender" = "Hide Sender Name";
|
||||
"lng_forward_action_hide_senders" = "Hide Sender Names";
|
||||
"lng_forward_action_show_caption" = "Show Caption";
|
||||
"lng_forward_action_show_captions" = "Show Captions";
|
||||
"lng_forward_action_hide_caption" = "Hide Caption";
|
||||
"lng_forward_action_hide_captions" = "Hide Captions";
|
||||
"lng_forward_action_change_recipient" = "Change Recipient";
|
||||
"lng_forward_action_remove" = "Do Not Forward";
|
||||
|
||||
"lng_passport_title" = "Telegram Passport";
|
||||
"lng_passport_request1" = "{bot} requests access to your personal data";
|
||||
@@ -4995,6 +5221,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_outdated_now" = "So Telegram Desktop can update to newer versions.";
|
||||
|
||||
"lng_filters_all" = "All chats";
|
||||
"lng_filters_all_short" = "All";
|
||||
"lng_filters_setup" = "Edit";
|
||||
"lng_filters_title" = "Folders";
|
||||
"lng_filters_subtitle" = "My folders";
|
||||
@@ -5049,11 +5276,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_filters_toast_add" = "{chat} added to {folder} folder";
|
||||
"lng_filters_toast_remove" = "{chat} removed from {folder} folder";
|
||||
"lng_filters_shareable_status" = "shareable folder";
|
||||
"lng_filters_view_subtitle" = "Tabs view";
|
||||
"lng_filters_vertical" = "Tabs on the left";
|
||||
"lng_filters_horizontal" = "Tabs at the top";
|
||||
"lng_filters_enable_tags" = "Show Folder Tags";
|
||||
"lng_filters_enable_tags_about" = "Display folder names for each chat in the chat list.";
|
||||
"lng_filters_enable_tags_about_premium" = "Subscribe to **{link}** to display folder names for each chat in the chat list.";
|
||||
"lng_filters_tag_color_subtitle" = "Folder color in chat list";
|
||||
"lng_filters_tag_color_about" = "Choose a color for the tag of this folder.";
|
||||
"lng_filters_tag_color_no" = "No Tag";
|
||||
|
||||
"lng_filters_delete_sure" = "Are you sure you want to delete this folder? This will also deactivate all the invite links created to share this folder.";
|
||||
"lng_filters_link" = "Share Folder";
|
||||
"lng_filters_link_has" = "Invite links";
|
||||
|
||||
"lng_filters_checkbox_remove_bot" = "Remove bot from all folders";
|
||||
"lng_filters_checkbox_remove_group" = "Remove group from all folders";
|
||||
"lng_filters_checkbox_remove_channel" = "Remove channel from all folders";
|
||||
|
||||
"lng_filters_link_create" = "Create an Invite Link";
|
||||
"lng_filters_link_cant" = "You can’t share folders which include or exclude specific chat types like 'Groups', 'Contacts', etc.";
|
||||
"lng_filters_link_about" = "Share access to some of this folder's groups and channels with others.";
|
||||
@@ -5168,13 +5408,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_sponsored_revenued_subtitle" = "Telegram Ads are very different from ads on other platforms. Ads such as this one:";
|
||||
"lng_sponsored_revenued_info1_title" = "Respect Your Privacy";
|
||||
"lng_sponsored_revenued_info1_description" = "Ads on Telegram do not use your personal information and are based on the channel in which you see them.";
|
||||
"lng_sponsored_revenued_info1_bot_description" = "Ads on Telegram do not use your personal information and are based on the mini app in which you see them.";
|
||||
"lng_sponsored_revenued_info2_title" = "Help the Channel Creator";
|
||||
"lng_sponsored_revenued_info2_bot_title" = "Help the Bot Developer";
|
||||
"lng_sponsored_revenued_info2_description" = "50% of the revenue from Telegram Ads goes to the owner of the channel where they are displayed.";
|
||||
"lng_sponsored_revenued_info2_bot_description" = "50% of the revenue from Telegram Ads goes to the developer of the mini app where they are displayed.";
|
||||
"lng_sponsored_revenued_info3_title" = "Can Be Removed";
|
||||
"lng_sponsored_revenued_info3_description#one" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers.";
|
||||
"lng_sponsored_revenued_info3_description#other" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers.";
|
||||
"lng_sponsored_revenued_info3_bot_description" = "You can turn off ads in mini apps by subscribing to {link}.";
|
||||
"lng_sponsored_revenued_footer_title" = "Can I Launch an Ad?";
|
||||
"lng_sponsored_revenued_footer_description" = "Anyone can create an ad to display in this channel — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}";
|
||||
"lng_sponsored_revenued_footer_bot_description" = "Anyone can create an ad to display in this bot — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}";
|
||||
"lng_sponsored_top_bar_hide" = "remove";
|
||||
|
||||
"lng_telegram_features_url" = "https://t.me/TelegramTips";
|
||||
|
||||
@@ -5478,6 +5724,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_channel_earn_title" = "Monetization";
|
||||
"lng_channel_earn_about" = "Telegram shares 50% of the revenue from ads displayed in your channel as rewards. {link}";
|
||||
"lng_channel_earn_about_bot" = "Telegram shares 50% of the revenue from ads displayed in your bot. {link}";
|
||||
"lng_channel_earn_about_link" = "Learn more {emoji}";
|
||||
"lng_channel_earn_overview_title" = "Rewards overview";
|
||||
"lng_channel_earn_available" = "Rewards available for collection";
|
||||
@@ -5510,8 +5757,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_channel_earn_cpm#one" = "{emoji} {count} CPM";
|
||||
"lng_channel_earn_cpm#other" = "{emoji} {count} CPM";
|
||||
"lng_channel_earn_learn_title" = "Earn From Your Channel";
|
||||
"lng_channel_earn_bot_learn_title" = "Earn From Your Bot";
|
||||
"lng_channel_earn_learn_in_subtitle" = "Telegram Ads";
|
||||
"lng_channel_earn_learn_in_about" = "Telegram can display ads in your channel.";
|
||||
"lng_channel_earn_learn_bot_in_about" = "Telegram can display ads in your bot.";
|
||||
"lng_channel_earn_learn_split_subtitle" = "50:50 revenue split";
|
||||
"lng_channel_earn_learn_split_about" = "You can receive 50% of the ad revenue as rewards in TON.";
|
||||
"lng_channel_earn_learn_out_subtitle" = "Flexible withdrawals";
|
||||
@@ -5548,6 +5797,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_bot_earn_credits_out_minimal" = "You cannot withdraw less than {link}.";
|
||||
"lng_bot_earn_credits_out_minimal_link#one" = "{count} star";
|
||||
"lng_bot_earn_credits_out_minimal_link#other" = "{count} stars";
|
||||
"lng_bot_copy_text_tooltip" = "Copy to Clipboard: {text}";
|
||||
|
||||
"lng_contact_add" = "Add";
|
||||
"lng_contact_send_message" = "Message";
|
||||
@@ -5558,6 +5808,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_iv_window_title" = "Instant View";
|
||||
"lng_iv_wrong_layout" = "Wrong layout?";
|
||||
"lng_iv_not_supported" = "This link appears to be invalid.";
|
||||
"lng_iv_zoom_tooltip_ctrl" = "Hold Ctrl to zoom by 5%.\nHold Alt to zoom by 1%.";
|
||||
"lng_iv_zoom_tooltip_cmd" = "Hold Cmd to zoom by 5%.\nHold Alt to zoom by 1%.";
|
||||
|
||||
"lng_limit_download_title" = "Download speed limited";
|
||||
"lng_limit_download_subscribe" = "Subscribe to {link} to increase download speed {increase}.";
|
||||
@@ -5587,6 +5839,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_recent_chats" = "Chats";
|
||||
"lng_recent_channels" = "Channels";
|
||||
"lng_recent_apps" = "Apps";
|
||||
"lng_all_photos" = "Photos";
|
||||
"lng_all_videos" = "Videos";
|
||||
"lng_all_downloads" = "Downloads";
|
||||
"lng_all_links" = "Links";
|
||||
"lng_all_files" = "Files";
|
||||
"lng_all_music" = "Music";
|
||||
"lng_all_voice" = "Voice";
|
||||
"lng_channels_none_title" = "No channels yet...";
|
||||
"lng_channels_none_about" = "You are not currently subscribed to any channels.";
|
||||
"lng_channels_your_title" = "Channels you joined";
|
||||
@@ -5595,6 +5854,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_channels_recommended" = "Similar channels";
|
||||
"lng_bot_apps_your" = "Apps you use";
|
||||
"lng_bot_apps_popular" = "Grossing apps";
|
||||
"lng_bot_apps_which" = "Which apps are included here? {link}";
|
||||
"lng_bot_apps_which_link" = "Learn >";
|
||||
|
||||
"lng_popular_apps_info_title" = "Top Mini Apps";
|
||||
"lng_popular_apps_info_text" = "This catalogue ranks mini apps based on their daily revenue, measured in Stars. To be listed, developers must set their main mini apps in {bot} (as described {link}), have over **1,000** daily users, and earn a daily revenue above **1,000** Stars, based on the weekly average.";
|
||||
"lng_popular_apps_info_bot" = "@botfather";
|
||||
"lng_popular_apps_info_here" = "here";
|
||||
"lng_popular_apps_info_url" = "https://core.telegram.org/bots/webapps#launching-the-main-mini-app";
|
||||
"lng_popular_apps_info_confirm" = "Understood";
|
||||
|
||||
"lng_font_box_title" = "Choose font family";
|
||||
"lng_font_default" = "Default";
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
<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="hello_status.tgs">../../animations/hello_status.tgs</file>
|
||||
<file alias="starref_link.tgs">../../animations/starref_link.tgs</file>
|
||||
|
||||
<file alias="dice_idle.tgs">../../animations/dice/dice_idle.tgs</file>
|
||||
<file alias="dart_idle.tgs">../../animations/dice/dart_idle.tgs</file>
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
<file alias="art/bg_thumbnail.png">../../art/bg_thumbnail.png</file>
|
||||
<file alias="art/bg_initial.jpg">../../art/bg_initial.jpg</file>
|
||||
<file alias="art/business_logo.png">../../art/business_logo.png</file>
|
||||
<file alias="art/affiliate_logo.png">../../art/affiliate_logo.png</file>
|
||||
<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/round_placeholder.jpg">../../art/round_placeholder.jpg</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>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="5.6.2.0" />
|
||||
Version="5.9.2.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,6,2,0
|
||||
PRODUCTVERSION 5,6,2,0
|
||||
FILEVERSION 5,9,2,0
|
||||
PRODUCTVERSION 5,9,2,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.6.2.0"
|
||||
VALUE "FileVersion", "5.9.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "5.6.2.0"
|
||||
VALUE "ProductVersion", "5.9.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,6,2,0
|
||||
PRODUCTVERSION 5,6,2,0
|
||||
FILEVERSION 5,9,2,0
|
||||
PRODUCTVERSION 5,9,2,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.6.2.0"
|
||||
VALUE "FileVersion", "5.9.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "5.6.2.0"
|
||||
VALUE "ProductVersion", "5.9.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -8,10 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_chat_filters.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/filters/edit_filter_links.h" // FilterChatStatusText
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
@@ -138,7 +140,8 @@ void InitFilterLinkHeader(
|
||||
Ui::FilterLinkHeaderType type,
|
||||
const QString &title,
|
||||
const QString &iconEmoji,
|
||||
rpl::producer<int> count) {
|
||||
rpl::producer<int> count,
|
||||
bool horizontalFilters) {
|
||||
const auto icon = Ui::LookupFilterIcon(
|
||||
Ui::LookupFilterIconByEmoji(
|
||||
iconEmoji
|
||||
@@ -152,6 +155,7 @@ void InitFilterLinkHeader(
|
||||
.badge = (type == Ui::FilterLinkHeaderType::AddingChats
|
||||
? std::move(count)
|
||||
: rpl::single(0)),
|
||||
.horizontalFilters = horizontalFilters,
|
||||
});
|
||||
const auto widget = header.widget;
|
||||
widget->resizeToWidth(st::boxWideWidth);
|
||||
@@ -546,6 +550,26 @@ void ShowImportToast(
|
||||
strong->showToast(std::move(text));
|
||||
}
|
||||
|
||||
void HandleEnterInBox(not_null<Ui::BoxContent*> box) {
|
||||
const auto isEnter = [=](not_null<QEvent*> event) {
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
if (const auto k = static_cast<QKeyEvent*>(event.get())) {
|
||||
return (k->key() == Qt::Key_Enter)
|
||||
|| (k->key() == Qt::Key_Return);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
base::install_event_filter(box, [=](not_null<QEvent*> event) {
|
||||
if (isEnter(event)) {
|
||||
box->triggerButton(0);
|
||||
return base::EventFilterResult::Cancel;
|
||||
}
|
||||
return base::EventFilterResult::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
void ProcessFilterInvite(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &slug,
|
||||
@@ -570,6 +594,8 @@ void ProcessFilterInvite(
|
||||
title,
|
||||
std::move(peers),
|
||||
std::move(already));
|
||||
const auto horizontalFilters = !strong->enoughSpaceForFilters()
|
||||
|| Core::App().settings().chatFiltersHorizontal();
|
||||
const auto raw = controller.get();
|
||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->setStyle(st::filterInviteBox);
|
||||
@@ -586,7 +612,7 @@ void ProcessFilterInvite(
|
||||
});
|
||||
InitFilterLinkHeader(box, [=](int min, int max, int addedTop) {
|
||||
raw->adjust(min, max, addedTop);
|
||||
}, type, title, iconEmoji, rpl::duplicate(badge));
|
||||
}, type, title, iconEmoji, rpl::duplicate(badge), horizontalFilters);
|
||||
|
||||
raw->setRealContentHeight(box->heightValue());
|
||||
|
||||
@@ -608,6 +634,8 @@ void ProcessFilterInvite(
|
||||
|
||||
box->addButton(std::move(owned));
|
||||
|
||||
HandleEnterInBox(box);
|
||||
|
||||
struct State {
|
||||
bool importing = false;
|
||||
};
|
||||
@@ -796,6 +824,8 @@ void ProcessFilterRemove(
|
||||
title,
|
||||
std::move(suggest),
|
||||
std::move(all));
|
||||
const auto horizontalFilters = !strong->enoughSpaceForFilters()
|
||||
|| Core::App().settings().chatFiltersHorizontal();
|
||||
const auto raw = controller.get();
|
||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->setStyle(st::filterInviteBox);
|
||||
@@ -807,7 +837,7 @@ void ProcessFilterRemove(
|
||||
});
|
||||
InitFilterLinkHeader(box, [=](int min, int max, int addedTop) {
|
||||
raw->adjust(min, max, addedTop);
|
||||
}, type, title, iconEmoji, rpl::single(0));
|
||||
}, type, title, iconEmoji, rpl::single(0), horizontalFilters);
|
||||
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
@@ -827,6 +857,8 @@ void ProcessFilterRemove(
|
||||
|
||||
box->addButton(std::move(owned));
|
||||
|
||||
HandleEnterInBox(box);
|
||||
|
||||
raw->selectedValue(
|
||||
) | rpl::start_with_next([=](
|
||||
base::flat_set<not_null<PeerData*>> &&peers) {
|
||||
|
||||
128
Telegram/SourceFiles/api/api_chat_filters_remove_manager.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_chat_filters_remove_manager.h"
|
||||
|
||||
#include "api/api_chat_filters.h"
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
void RemoveChatFilter(
|
||||
not_null<Main::Session*> session,
|
||||
FilterId filterId,
|
||||
std::vector<not_null<PeerData*>> leave) {
|
||||
const auto api = &session->api();
|
||||
session->data().chatsFilters().apply(MTP_updateDialogFilter(
|
||||
MTP_flags(MTPDupdateDialogFilter::Flag(0)),
|
||||
MTP_int(filterId),
|
||||
MTPDialogFilter()));
|
||||
if (leave.empty()) {
|
||||
api->request(MTPmessages_UpdateDialogFilter(
|
||||
MTP_flags(MTPmessages_UpdateDialogFilter::Flag(0)),
|
||||
MTP_int(filterId),
|
||||
MTPDialogFilter()
|
||||
)).send();
|
||||
} else {
|
||||
api->request(MTPchatlists_LeaveChatlist(
|
||||
MTP_inputChatlistDialogFilter(MTP_int(filterId)),
|
||||
MTP_vector<MTPInputPeer>(ranges::views::all(
|
||||
leave
|
||||
) | ranges::views::transform([](not_null<PeerData*> peer) {
|
||||
return MTPInputPeer(peer->input);
|
||||
}) | ranges::to<QVector<MTPInputPeer>>())
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
api->applyUpdates(result);
|
||||
}).send();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RemoveComplexChatFilter::RemoveComplexChatFilter() = default;
|
||||
|
||||
void RemoveComplexChatFilter::request(
|
||||
QPointer<Ui::RpWidget> widget,
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
FilterId id) {
|
||||
const auto session = &weak->session();
|
||||
const auto &list = session->data().chatsFilters().list();
|
||||
const auto i = ranges::find(list, id, &Data::ChatFilter::id);
|
||||
const auto filter = (i != end(list)) ? *i : Data::ChatFilter();
|
||||
const auto has = filter.hasMyLinks();
|
||||
const auto confirm = [=](Fn<void()> action, bool onlyWhenHas = false) {
|
||||
if (!has && onlyWhenHas) {
|
||||
action();
|
||||
return;
|
||||
}
|
||||
weak->window().show(Ui::MakeConfirmBox({
|
||||
.text = (has
|
||||
? tr::lng_filters_delete_sure()
|
||||
: tr::lng_filters_remove_sure()),
|
||||
.confirmed = [=](Fn<void()> &&close) { close(); action(); },
|
||||
.confirmText = (has
|
||||
? tr::lng_box_delete()
|
||||
: tr::lng_filters_remove_yes()),
|
||||
.confirmStyle = &st::attentionBoxButton,
|
||||
}));
|
||||
};
|
||||
const auto simple = [=] {
|
||||
confirm([=] { RemoveChatFilter(session, id, {}); });
|
||||
};
|
||||
const auto suggestRemoving = Api::ExtractSuggestRemoving(filter);
|
||||
if (suggestRemoving.empty()) {
|
||||
simple();
|
||||
return;
|
||||
} else if (_removingRequestId) {
|
||||
if (_removingId == id) {
|
||||
return;
|
||||
}
|
||||
session->api().request(_removingRequestId).cancel();
|
||||
}
|
||||
_removingId = id;
|
||||
_removingRequestId = session->api().request(
|
||||
MTPchatlists_GetLeaveChatlistSuggestions(
|
||||
MTP_inputChatlistDialogFilter(
|
||||
MTP_int(id)))
|
||||
).done(crl::guard(widget, [=, this](const MTPVector<MTPPeer> &result) {
|
||||
_removingRequestId = 0;
|
||||
const auto suggestRemovePeers = ranges::views::all(
|
||||
result.v
|
||||
) | ranges::views::transform([=](const MTPPeer &peer) {
|
||||
return session->data().peer(peerFromMTP(peer));
|
||||
}) | ranges::to_vector;
|
||||
const auto chosen = crl::guard(widget, [=](
|
||||
std::vector<not_null<PeerData*>> peers) {
|
||||
RemoveChatFilter(session, id, std::move(peers));
|
||||
});
|
||||
confirm(crl::guard(widget, [=] {
|
||||
Api::ProcessFilterRemove(
|
||||
weak,
|
||||
filter.title(),
|
||||
filter.iconEmoji(),
|
||||
suggestRemoving,
|
||||
suggestRemovePeers,
|
||||
chosen);
|
||||
}), true);
|
||||
})).fail(crl::guard(widget, [=, this] {
|
||||
_removingRequestId = 0;
|
||||
simple();
|
||||
})).send();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
35
Telegram/SourceFiles/api/api_chat_filters_remove_manager.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Api {
|
||||
|
||||
class RemoveComplexChatFilter final {
|
||||
public:
|
||||
RemoveComplexChatFilter();
|
||||
|
||||
void request(
|
||||
QPointer<Ui::RpWidget> widget,
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
FilterId id);
|
||||
|
||||
private:
|
||||
FilterId _removingId = 0;
|
||||
mtpRequestId _removingRequestId = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_chat_invite.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_credits.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "core/application.h"
|
||||
#include "data/components/credits.h"
|
||||
@@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "settings/settings_credits_graphics.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/effects/credits_graphics.h"
|
||||
#include "ui/effects/premium_graphics.h"
|
||||
#include "ui/effects/premium_stars_colored.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
@@ -129,6 +131,7 @@ void ConfirmSubscriptionBox(
|
||||
struct State final {
|
||||
std::shared_ptr<Data::PhotoMedia> photoMedia;
|
||||
std::unique_ptr<Ui::EmptyUserpic> photoEmpty;
|
||||
QImage frame;
|
||||
|
||||
std::optional<MTP::Sender> api;
|
||||
Ui::RpWidget* saveButton = nullptr;
|
||||
@@ -146,25 +149,45 @@ void ConfirmSubscriptionBox(
|
||||
const auto userpic = userpicWrap->entity();
|
||||
const auto photoSize = st::confirmInvitePhotoSize;
|
||||
userpic->resize(Size(photoSize));
|
||||
const auto creditsIconSize = photoSize / 3;
|
||||
const auto creditsIconCallback =
|
||||
Ui::PaintOutlinedColoredCreditsIconCallback(
|
||||
creditsIconSize,
|
||||
1.5);
|
||||
state->frame = QImage(
|
||||
Size(photoSize * style::DevicePixelRatio()),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
state->frame.setDevicePixelRatio(style::DevicePixelRatio());
|
||||
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(
|
||||
state->frame.fill(Qt::transparent);
|
||||
{
|
||||
auto p = QPainter(&state->frame);
|
||||
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,
|
||||
image->pix(Size(photoSize), { .options = options }));
|
||||
userpic->width(),
|
||||
photoSize);
|
||||
}
|
||||
if (creditsIconCallback) {
|
||||
p.translate(
|
||||
photoSize - creditsIconSize,
|
||||
photoSize - creditsIconSize);
|
||||
creditsIconCallback(p);
|
||||
}
|
||||
} else if (state->photoEmpty) {
|
||||
state->photoEmpty->paintCircle(
|
||||
p,
|
||||
0,
|
||||
0,
|
||||
userpic->width(),
|
||||
photoSize);
|
||||
}
|
||||
auto p = QPainter(userpic);
|
||||
p.drawImage(0, 0, state->frame);
|
||||
}, userpicWrap->lifetime());
|
||||
userpicWrap->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
if (photo) {
|
||||
@@ -184,32 +207,12 @@ void ConfirmSubscriptionBox(
|
||||
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());
|
||||
}
|
||||
Settings::AddMiniStars(
|
||||
content,
|
||||
Ui::CreateChild<Ui::RpWidget>(content),
|
||||
photoSize,
|
||||
box->width(),
|
||||
2.);
|
||||
|
||||
box->addRow(
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
@@ -273,20 +276,39 @@ void ConfirmSubscriptionBox(
|
||||
const auto buttonWidth = state->saveButton
|
||||
? state->saveButton->width()
|
||||
: 0;
|
||||
const auto finish = [=] {
|
||||
state->api = std::nullopt;
|
||||
state->loading.force_assign(false);
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
state->api->request(
|
||||
MTPpayments_SendStarsForm(
|
||||
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();
|
||||
const auto refill = session->data().activeCreditsSubsRebuilder();
|
||||
const auto strong = weak.data();
|
||||
if (!strong) {
|
||||
return;
|
||||
}
|
||||
if (!refill) {
|
||||
return finish();
|
||||
}
|
||||
const auto api
|
||||
= strong->lifetime().make_state<Api::CreditsHistory>(
|
||||
session->user(),
|
||||
true,
|
||||
true);
|
||||
api->requestSubscriptions({}, [=](Data::CreditsStatusSlice d) {
|
||||
refill->fire(std::move(d));
|
||||
finish();
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
const auto id = error.type();
|
||||
if (weak) {
|
||||
|
||||
@@ -39,8 +39,8 @@ constexpr auto kTransactionsLimit = 100;
|
||||
if (const auto list = tl.data().vextended_media()) {
|
||||
extended.reserve(list->v.size());
|
||||
for (const auto &media : list->v) {
|
||||
media.match([&](const MTPDmessageMediaPhoto &photo) {
|
||||
if (const auto inner = photo.vphoto()) {
|
||||
media.match([&](const MTPDmessageMediaPhoto &data) {
|
||||
if (const auto inner = data.vphoto()) {
|
||||
const auto photo = owner->processPhoto(*inner);
|
||||
if (!photo->isNull()) {
|
||||
extended.push_back(CreditsHistoryMedia{
|
||||
@@ -49,9 +49,11 @@ constexpr auto kTransactionsLimit = 100;
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDmessageMediaDocument &document) {
|
||||
if (const auto inner = document.vdocument()) {
|
||||
const auto document = owner->processDocument(*inner);
|
||||
}, [&](const MTPDmessageMediaDocument &data) {
|
||||
if (const auto inner = data.vdocument()) {
|
||||
const auto document = owner->processDocument(
|
||||
*inner,
|
||||
data.valt_documents());
|
||||
if (document->isAnimation()
|
||||
|| document->isVideoFile()
|
||||
|| document->isGifv()) {
|
||||
@@ -71,7 +73,18 @@ constexpr auto kTransactionsLimit = 100;
|
||||
return PeerId(0);
|
||||
}).value;
|
||||
const auto stargift = tl.data().vstargift();
|
||||
const auto incoming = (int64(tl.data().vstars().v) >= 0);
|
||||
const auto reaction = tl.data().is_reaction();
|
||||
const auto amount = Data::FromTL(tl.data().vstars());
|
||||
const auto starrefAmount = tl.data().vstarref_amount()
|
||||
? Data::FromTL(*tl.data().vstarref_amount())
|
||||
: StarsAmount();
|
||||
const auto starrefCommission
|
||||
= tl.data().vstarref_commission_permille().value_or_empty();
|
||||
const auto starrefBarePeerId = tl.data().vstarref_peer()
|
||||
? peerFromMTP(*tl.data().vstarref_peer()).value
|
||||
: 0;
|
||||
const auto incoming = (amount >= StarsAmount());
|
||||
const auto saveActorId = (reaction || !extended.empty()) && incoming;
|
||||
return Data::CreditsHistoryEntry{
|
||||
.id = qs(tl.data().vid()),
|
||||
.title = qs(tl.data().vtitle().value_or_empty()),
|
||||
@@ -79,14 +92,18 @@ constexpr auto kTransactionsLimit = 100;
|
||||
.date = base::unixtime::parse(tl.data().vdate().v),
|
||||
.photoId = photo ? photo->id : 0,
|
||||
.extended = std::move(extended),
|
||||
.credits = tl.data().vstars().v,
|
||||
.credits = Data::FromTL(tl.data().vstars()),
|
||||
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
|
||||
.barePeerId = barePeerId,
|
||||
.barePeerId = saveActorId ? peer->id.value : barePeerId,
|
||||
.bareGiveawayMsgId = uint64(
|
||||
tl.data().vgiveaway_post_id().value_or_empty()),
|
||||
.bareGiftStickerId = (stargift
|
||||
? owner->processDocument(stargift->data().vsticker())->id
|
||||
: 0),
|
||||
.bareActorId = saveActorId ? barePeerId : uint64(0),
|
||||
.starrefAmount = starrefAmount,
|
||||
.starrefCommission = starrefCommission,
|
||||
.starrefRecipientId = starrefBarePeerId,
|
||||
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Peer;
|
||||
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
|
||||
@@ -101,6 +118,8 @@ constexpr auto kTransactionsLimit = 100;
|
||||
return Data::CreditsHistoryEntry::PeerType::PremiumBot;
|
||||
}, [](const MTPDstarsTransactionPeerAds &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Ads;
|
||||
}, [](const MTPDstarsTransactionPeerAPI &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::API;
|
||||
}),
|
||||
.subscriptionUntil = tl.data().vsubscription_period()
|
||||
? base::unixtime::parse(base::unixtime::now()
|
||||
@@ -110,10 +129,12 @@ constexpr auto kTransactionsLimit = 100;
|
||||
? base::unixtime::parse(tl.data().vtransaction_date()->v)
|
||||
: QDateTime(),
|
||||
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
|
||||
.convertStars = int(stargift
|
||||
.starsConverted = int(stargift
|
||||
? stargift->data().vconvert_stars().v
|
||||
: 0),
|
||||
.floodSkip = int(tl.data().vfloodskip_number().value_or(0)),
|
||||
.converted = stargift && incoming,
|
||||
.stargift = stargift.has_value(),
|
||||
.reaction = tl.data().is_reaction(),
|
||||
.refunded = tl.data().is_refund(),
|
||||
.pending = tl.data().is_pending(),
|
||||
@@ -124,17 +145,26 @@ constexpr auto kTransactionsLimit = 100;
|
||||
}
|
||||
|
||||
[[nodiscard]] Data::SubscriptionEntry SubscriptionFromTL(
|
||||
const MTPStarsSubscription &tl) {
|
||||
const MTPStarsSubscription &tl,
|
||||
not_null<PeerData*> peer) {
|
||||
return Data::SubscriptionEntry{
|
||||
.id = qs(tl.data().vid()),
|
||||
.inviteHash = qs(tl.data().vchat_invite_hash().value_or_empty()),
|
||||
.title = qs(tl.data().vtitle().value_or_empty()),
|
||||
.slug = qs(tl.data().vinvoice_slug().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,
|
||||
.photoId = (tl.data().vphoto()
|
||||
? peer->owner().photoFromWeb(
|
||||
*tl.data().vphoto(),
|
||||
ImageLocation())->id
|
||||
: 0),
|
||||
.cancelled = tl.data().is_canceled(),
|
||||
.cancelledByBot = tl.data().is_bot_canceled(),
|
||||
.expired = (base::unixtime::now() > tl.data().vuntil_date().v),
|
||||
.canRefulfill = tl.data().is_can_refulfill(),
|
||||
};
|
||||
@@ -157,16 +187,17 @@ constexpr auto kTransactionsLimit = 100;
|
||||
if (const auto history = data.vsubscriptions()) {
|
||||
subscriptions.reserve(history->v.size());
|
||||
for (const auto &tl : history->v) {
|
||||
subscriptions.push_back(SubscriptionFromTL(tl));
|
||||
subscriptions.push_back(SubscriptionFromTL(tl, peer));
|
||||
}
|
||||
}
|
||||
return Data::CreditsStatusSlice{
|
||||
.list = std::move(entries),
|
||||
.subscriptions = std::move(subscriptions),
|
||||
.balance = status.data().vbalance().v,
|
||||
.balance = Data::FromTL(status.data().vbalance()),
|
||||
.subscriptionsMissingBalance
|
||||
= status.data().vsubscriptions_missing_balance().value_or_empty(),
|
||||
.allLoaded = !status.data().vnext_offset().has_value(),
|
||||
.allLoaded = !status.data().vnext_offset().has_value()
|
||||
&& !status.data().vsubscriptions_next_offset().has_value(),
|
||||
.token = qs(status.data().vnext_offset().value_or_empty()),
|
||||
.tokenSubscriptions = qs(
|
||||
status.data().vsubscriptions_next_offset().value_or_empty()),
|
||||
@@ -249,8 +280,8 @@ void CreditsStatus::request(
|
||||
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input
|
||||
)).done([=](const TLResult &result) {
|
||||
_requestId = 0;
|
||||
const auto balance = result.data().vbalance().v;
|
||||
_peer->session().credits().apply(_peer->id, balance);
|
||||
const auto &balance = result.data().vbalance();
|
||||
_peer->session().credits().apply(_peer->id, Data::FromTL(balance));
|
||||
if (const auto onstack = done) {
|
||||
onstack(StatusFromTL(result, _peer));
|
||||
}
|
||||
@@ -329,7 +360,9 @@ rpl::producer<not_null<PeerData*>> PremiumPeerBot(
|
||||
const auto api = lifetime.make_state<MTP::Sender>(&session->mtp());
|
||||
|
||||
api->request(MTPcontacts_ResolveUsername(
|
||||
MTP_string(username)
|
||||
MTP_flags(0),
|
||||
MTP_string(username),
|
||||
MTP_string()
|
||||
)).done([=](const MTPcontacts_ResolvedPeer &result) {
|
||||
session->data().processUsers(result.data().vusers());
|
||||
session->data().processChats(result.data().vchats());
|
||||
@@ -361,12 +394,13 @@ rpl::producer<rpl::no_value, QString> CreditsEarnStatistics::request() {
|
||||
)).done([=](const MTPpayments_StarsRevenueStats &result) {
|
||||
const auto &data = result.data();
|
||||
const auto &status = data.vstatus().data();
|
||||
using Data::FromTL;
|
||||
_data = Data::CreditsEarnStatistics{
|
||||
.revenueGraph = StatisticalGraphFromTL(
|
||||
data.vrevenue_graph()),
|
||||
.currentBalance = status.vcurrent_balance().v,
|
||||
.availableBalance = status.vavailable_balance().v,
|
||||
.overallRevenue = status.voverall_revenue().v,
|
||||
.currentBalance = FromTL(status.vcurrent_balance()),
|
||||
.availableBalance = FromTL(status.vavailable_balance()),
|
||||
.overallRevenue = FromTL(status.voverall_revenue()),
|
||||
.usdRate = data.vusd_rate().v,
|
||||
.isWithdrawalEnabled = status.is_withdrawal_enabled(),
|
||||
.nextWithdrawalAt = status.vnext_withdrawal_at()
|
||||
@@ -453,4 +487,20 @@ Data::CreditsGiveawayOptions CreditsGiveawayOptions::options() const {
|
||||
return _options;
|
||||
}
|
||||
|
||||
void EditCreditsSubscription(
|
||||
not_null<Main::Session*> session,
|
||||
const QString &id,
|
||||
bool cancel,
|
||||
Fn<void()> done,
|
||||
Fn<void(QString)> fail) {
|
||||
using Flag = MTPpayments_ChangeStarsSubscription::Flag;
|
||||
session->api().request(
|
||||
MTPpayments_ChangeStarsSubscription(
|
||||
MTP_flags(Flag::f_canceled),
|
||||
MTP_inputPeerSelf(),
|
||||
MTP_string(id),
|
||||
MTP_bool(cancel)
|
||||
)).done(done).fail([=](const MTP::Error &e) { fail(e.type()); }).send();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -99,8 +99,8 @@ public:
|
||||
[[nodiscard]] Data::CreditsEarnStatistics data() const;
|
||||
|
||||
private:
|
||||
const bool _isUser = false;
|
||||
Data::CreditsEarnStatistics _data;
|
||||
bool _isUser = false;
|
||||
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
@@ -109,4 +109,11 @@ private:
|
||||
[[nodiscard]] rpl::producer<not_null<PeerData*>> PremiumPeerBot(
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
void EditCreditsSubscription(
|
||||
not_null<Main::Session*> session,
|
||||
const QString &id,
|
||||
bool cancel,
|
||||
Fn<void()> done,
|
||||
Fn<void(QString)> fail);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -40,6 +40,7 @@ void HandleWithdrawalButton(
|
||||
std::shared_ptr<Ui::Show> show) {
|
||||
Expects(receiver.currencyReceiver
|
||||
|| (receiver.creditsReceiver && receiver.creditsAmount));
|
||||
|
||||
struct State {
|
||||
rpl::lifetime lifetime;
|
||||
bool loading = false;
|
||||
@@ -58,8 +59,7 @@ void HandleWithdrawalButton(
|
||||
const auto processOut = [=] {
|
||||
if (state->loading) {
|
||||
return;
|
||||
}
|
||||
if (peer && !receiver.creditsAmount()) {
|
||||
} else if (peer && !receiver.creditsAmount()) {
|
||||
return;
|
||||
}
|
||||
state->loading = true;
|
||||
@@ -89,12 +89,15 @@ void HandleWithdrawalButton(
|
||||
}
|
||||
};
|
||||
const auto fail = [=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
const auto message = error.type();
|
||||
if (box && !box->handleCustomCheckError(message)) {
|
||||
show->showToast(message);
|
||||
}
|
||||
};
|
||||
if (channel) {
|
||||
session->api().request(
|
||||
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
||||
channel->inputChannel,
|
||||
channel->input,
|
||||
result.result
|
||||
)).done([=](const ChannelOutUrl &r) {
|
||||
done(qs(r.data().vurl()));
|
||||
@@ -134,7 +137,7 @@ void HandleWithdrawalButton(
|
||||
if (channel) {
|
||||
session->api().request(
|
||||
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
||||
channel->inputChannel,
|
||||
channel->input,
|
||||
MTP_inputCheckPasswordEmpty()
|
||||
)).fail(fail).send();
|
||||
} else if (peer) {
|
||||
|
||||
@@ -74,12 +74,17 @@ const FoundMessages &MessagesSearchMerged::messages() const {
|
||||
return _concatedFound;
|
||||
}
|
||||
|
||||
const MessagesSearch::Request &MessagesSearchMerged::request() const {
|
||||
return _request;
|
||||
}
|
||||
|
||||
void MessagesSearchMerged::clear() {
|
||||
_concatedFound = {};
|
||||
_migratedFirstFound = {};
|
||||
}
|
||||
|
||||
void MessagesSearchMerged::search(const Request &search) {
|
||||
_request = search;
|
||||
if (_migratedSearch) {
|
||||
_waitingForTotal = true;
|
||||
_migratedSearch->searchMessages(search);
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
void searchMore();
|
||||
|
||||
[[nodiscard]] const FoundMessages &messages() const;
|
||||
[[nodiscard]] const Request &request() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<> newFounds() const;
|
||||
[[nodiscard]] rpl::producer<> nextFounds() const;
|
||||
@@ -39,6 +40,7 @@ private:
|
||||
void addFound(const FoundMessages &data);
|
||||
|
||||
MessagesSearch _apiSearch;
|
||||
Request _request;
|
||||
|
||||
std::optional<MessagesSearch> _migratedSearch;
|
||||
FoundMessages _migratedFirstFound;
|
||||
|
||||
@@ -772,10 +772,13 @@ std::optional<StarGift> FromTL(
|
||||
return StarGift{
|
||||
.id = uint64(data.vid().v),
|
||||
.stars = int64(data.vstars().v),
|
||||
.convertStars = int64(data.vconvert_stars().v),
|
||||
.starsConverted = int64(data.vconvert_stars().v),
|
||||
.document = document,
|
||||
.limitedLeft = remaining.value_or_empty(),
|
||||
.limitedCount = total.value_or_empty(),
|
||||
.firstSaleDate = data.vfirst_sale_date().value_or_empty(),
|
||||
.lastSaleDate = data.vlast_sale_date().value_or_empty(),
|
||||
.birthday = data.is_birthday(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -789,7 +792,7 @@ std::optional<UserStarGift> FromTL(
|
||||
return {};
|
||||
}
|
||||
return UserStarGift{
|
||||
.gift = std::move(*parsed),
|
||||
.info = std::move(*parsed),
|
||||
.message = (data.vmessage()
|
||||
? TextWithEntities{
|
||||
.text = qs(data.vmessage()->data().vtext()),
|
||||
@@ -798,7 +801,7 @@ std::optional<UserStarGift> FromTL(
|
||||
data.vmessage()->data().ventities().v),
|
||||
}
|
||||
: TextWithEntities()),
|
||||
.convertStars = int64(data.vconvert_stars().value_or_empty()),
|
||||
.starsConverted = int64(data.vconvert_stars().value_or_empty()),
|
||||
.fromId = (data.vfrom_id()
|
||||
? peerFromUser(data.vfrom_id()->v)
|
||||
: PeerId()),
|
||||
|
||||
@@ -76,16 +76,23 @@ struct GiftOptionData {
|
||||
struct StarGift {
|
||||
uint64 id = 0;
|
||||
int64 stars = 0;
|
||||
int64 convertStars = 0;
|
||||
int64 starsConverted = 0;
|
||||
not_null<DocumentData*> document;
|
||||
int limitedLeft = 0;
|
||||
int limitedCount = 0;
|
||||
TimeId firstSaleDate = 0;
|
||||
TimeId lastSaleDate = 0;
|
||||
bool birthday = false;
|
||||
|
||||
friend inline bool operator==(
|
||||
const StarGift &,
|
||||
const StarGift &) = default;
|
||||
};
|
||||
|
||||
struct UserStarGift {
|
||||
StarGift gift;
|
||||
StarGift info;
|
||||
TextWithEntities message;
|
||||
int64 convertStars = 0;
|
||||
int64 starsConverted = 0;
|
||||
PeerId fromId = 0;
|
||||
MsgId messageId = 0;
|
||||
TimeId date = 0;
|
||||
|
||||
@@ -40,29 +40,20 @@ MTPreportReason ReasonToTL(const Ui::ReportReason &reason) {
|
||||
|
||||
} // namespace
|
||||
|
||||
void SendReport(
|
||||
void SendPhotoReport(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
Ui::ReportReason reason,
|
||||
const QString &comment,
|
||||
std::variant<v::null_t, not_null<PhotoData*>> data) {
|
||||
auto done = [=] {
|
||||
not_null<PhotoData*> photo) {
|
||||
peer->session().api().request(MTPaccount_ReportProfilePhoto(
|
||||
peer->input,
|
||||
photo->mtpInput(),
|
||||
ReasonToTL(reason),
|
||||
MTP_string(comment)
|
||||
)).done([=] {
|
||||
show->showToast(tr::lng_report_thanks(tr::now));
|
||||
};
|
||||
v::match(data, [&](v::null_t) {
|
||||
peer->session().api().request(MTPaccount_ReportPeer(
|
||||
peer->input,
|
||||
ReasonToTL(reason),
|
||||
MTP_string(comment)
|
||||
)).done(std::move(done)).send();
|
||||
}, [&](not_null<PhotoData*> photo) {
|
||||
peer->session().api().request(MTPaccount_ReportProfilePhoto(
|
||||
peer->input,
|
||||
photo->mtpInput(),
|
||||
ReasonToTL(reason),
|
||||
MTP_string(comment)
|
||||
)).done(std::move(done)).send();
|
||||
});
|
||||
}).send();
|
||||
}
|
||||
|
||||
auto CreateReportMessagesOrStoriesCallback(
|
||||
|
||||
@@ -41,12 +41,12 @@ struct ReportResult final {
|
||||
bool successful = false;
|
||||
};
|
||||
|
||||
void SendReport(
|
||||
void SendPhotoReport(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
Ui::ReportReason reason,
|
||||
const QString &comment,
|
||||
std::variant<v::null_t, not_null<PhotoData*>> data);
|
||||
not_null<PhotoData*> photo);
|
||||
|
||||
[[nodiscard]] auto CreateReportMessagesOrStoriesCallback(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
|
||||
@@ -456,6 +456,7 @@ void SendConfirmedFile(
|
||||
not_null<Main::Session*> session,
|
||||
const std::shared_ptr<FilePrepareResult> &file) {
|
||||
const auto isEditing = (file->type != SendMediaType::Audio)
|
||||
&& (file->type != SendMediaType::Round)
|
||||
&& (file->to.replaceMediaOf != 0);
|
||||
const auto newId = FullMsgId(
|
||||
file->to.peer,
|
||||
@@ -525,7 +526,8 @@ void SendConfirmedFile(
|
||||
// Shortcut messages have no 'edited' badge.
|
||||
flags |= MessageFlag::HideEdited;
|
||||
}
|
||||
if (file->type == SendMediaType::Audio) {
|
||||
if (file->type == SendMediaType::Audio
|
||||
|| file->type == SendMediaType::Round) {
|
||||
if (!peer->isChannel() || peer->isMegagroup()) {
|
||||
flags |= MessageFlag::MediaIsUnread;
|
||||
}
|
||||
@@ -551,29 +553,25 @@ void SendConfirmedFile(
|
||||
MTPint());
|
||||
} else if (file->type == SendMediaType::Audio) {
|
||||
const auto ttlSeconds = file->to.options.ttlSeconds;
|
||||
const auto isVoice = [&] {
|
||||
return file->document.match([](const MTPDdocumentEmpty &d) {
|
||||
return false;
|
||||
}, [](const MTPDdocument &d) {
|
||||
return ranges::any_of(d.vattributes().v, [&](
|
||||
const MTPDocumentAttribute &attribute) {
|
||||
using Att = MTPDdocumentAttributeAudio;
|
||||
return attribute.match([](const Att &data) -> bool {
|
||||
return data.vflags().v & Att::Flag::f_voice;
|
||||
}, [](const auto &) {
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}();
|
||||
using Flag = MTPDmessageMediaDocument::Flag;
|
||||
return MTP_messageMediaDocument(
|
||||
MTP_flags(Flag::f_document
|
||||
| (isVoice ? Flag::f_voice : Flag())
|
||||
| Flag::f_voice
|
||||
| (ttlSeconds ? Flag::f_ttl_seconds : Flag())),
|
||||
file->document,
|
||||
MTPVector<MTPDocument>(), // alt_documents
|
||||
MTP_int(ttlSeconds));
|
||||
} else if (file->type == SendMediaType::Round) {
|
||||
using Flag = MTPDmessageMediaDocument::Flag;
|
||||
const auto ttlSeconds = file->to.options.ttlSeconds;
|
||||
return MTP_messageMediaDocument(
|
||||
MTP_flags(Flag::f_document
|
||||
| Flag::f_round
|
||||
| (ttlSeconds ? Flag::f_ttl_seconds : Flag())
|
||||
| (file->spoiler ? Flag::f_spoiler : Flag())),
|
||||
file->document,
|
||||
MTPVector<MTPDocument>(), // alt_documents
|
||||
MTP_int(ttlSeconds));
|
||||
} else {
|
||||
Unexpected("Type in sendFilesConfirmed.");
|
||||
}
|
||||
|
||||
@@ -181,7 +181,9 @@ std::optional<HistoryItem*> SingleMessageSearch::performLookupByUsername(
|
||||
ready();
|
||||
};
|
||||
_requestId = _session->api().request(MTPcontacts_ResolveUsername(
|
||||
MTP_string(username)
|
||||
MTP_flags(0),
|
||||
MTP_string(username),
|
||||
MTP_string()
|
||||
)).done([=](const MTPcontacts_ResolvedPeer &result) {
|
||||
result.match([&](const MTPDcontacts_resolvedPeer &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
|
||||
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_story.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
@@ -341,6 +342,10 @@ void PublicForwards::request(
|
||||
.token = nextToken,
|
||||
});
|
||||
};
|
||||
const auto processFail = [=] {
|
||||
_requestId = 0;
|
||||
done({});
|
||||
};
|
||||
|
||||
constexpr auto kLimit = tl::make_int(100);
|
||||
if (_fullId.messageId) {
|
||||
@@ -349,14 +354,14 @@ void PublicForwards::request(
|
||||
MTP_int(_fullId.messageId.msg),
|
||||
MTP_string(token),
|
||||
kLimit
|
||||
)).done(processResult).fail([=] { _requestId = 0; }).send();
|
||||
)).done(processResult).fail(processFail).send();
|
||||
} else if (_fullId.storyId) {
|
||||
_requestId = makeRequest(MTPstats_GetStoryPublicForwards(
|
||||
channel->input,
|
||||
MTP_int(_fullId.storyId.story),
|
||||
MTP_string(token),
|
||||
kLimit
|
||||
)).done(processResult).fail([=] { _requestId = 0; }).send();
|
||||
)).done(processResult).fail(processFail).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +386,7 @@ Data::PublicForwardsSlice MessageStatistics::firstSlice() const {
|
||||
}
|
||||
|
||||
void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
||||
if (channel()->isMegagroup()) {
|
||||
if (channel()->isMegagroup() && !_storyId) {
|
||||
return;
|
||||
}
|
||||
const auto requestFirstPublicForwards = [=](
|
||||
@@ -681,17 +686,18 @@ Data::BoostStatus Boosts::boostStatus() const {
|
||||
return _boostStatus;
|
||||
}
|
||||
|
||||
ChannelEarnStatistics::ChannelEarnStatistics(not_null<ChannelData*> channel)
|
||||
: StatisticsRequestSender(channel) {
|
||||
EarnStatistics::EarnStatistics(not_null<PeerData*> peer)
|
||||
: StatisticsRequestSender(peer)
|
||||
, _isUser(peer->isUser()) {
|
||||
}
|
||||
|
||||
rpl::producer<rpl::no_value, QString> ChannelEarnStatistics::request() {
|
||||
rpl::producer<rpl::no_value, QString> EarnStatistics::request() {
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
|
||||
makeRequest(MTPstats_GetBroadcastRevenueStats(
|
||||
MTP_flags(0),
|
||||
channel()->inputChannel
|
||||
(_isUser ? user()->input : channel()->input)
|
||||
)).done([=](const MTPstats_BroadcastRevenueStats &result) {
|
||||
const auto &data = result.data();
|
||||
const auto &balances = data.vbalances().data();
|
||||
@@ -708,18 +714,22 @@ rpl::producer<rpl::no_value, QString> ChannelEarnStatistics::request() {
|
||||
requestHistory({}, [=](Data::EarnHistorySlice &&slice) {
|
||||
_data.firstHistorySlice = std::move(slice);
|
||||
|
||||
api().request(
|
||||
MTPchannels_GetFullChannel(channel()->inputChannel)
|
||||
).done([=](const MTPmessages_ChatFull &result) {
|
||||
result.data().vfull_chat().match([&](
|
||||
const MTPDchannelFull &d) {
|
||||
_data.switchedOff = d.is_restricted_sponsored();
|
||||
}, [](const auto &) {
|
||||
});
|
||||
if (!_isUser) {
|
||||
api().request(
|
||||
MTPchannels_GetFullChannel(channel()->inputChannel)
|
||||
).done([=](const MTPmessages_ChatFull &result) {
|
||||
result.data().vfull_chat().match([&](
|
||||
const MTPDchannelFull &d) {
|
||||
_data.switchedOff = d.is_restricted_sponsored();
|
||||
}, [](const auto &) {
|
||||
});
|
||||
consumer.put_done();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
consumer.put_error_copy(error.type());
|
||||
}).send();
|
||||
} else {
|
||||
consumer.put_done();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
consumer.put_error_copy(error.type());
|
||||
}).send();
|
||||
}
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
consumer.put_error_copy(error.type());
|
||||
@@ -729,7 +739,7 @@ rpl::producer<rpl::no_value, QString> ChannelEarnStatistics::request() {
|
||||
};
|
||||
}
|
||||
|
||||
void ChannelEarnStatistics::requestHistory(
|
||||
void EarnStatistics::requestHistory(
|
||||
const Data::EarnHistorySlice::OffsetToken &token,
|
||||
Fn<void(Data::EarnHistorySlice)> done) {
|
||||
if (_requestId) {
|
||||
@@ -738,7 +748,7 @@ void ChannelEarnStatistics::requestHistory(
|
||||
constexpr auto kTlFirstSlice = tl::make_int(kFirstSlice);
|
||||
constexpr auto kTlLimit = tl::make_int(kLimit);
|
||||
_requestId = api().request(MTPstats_GetBroadcastRevenueTransactions(
|
||||
channel()->inputChannel,
|
||||
(_isUser ? user()->input : channel()->input),
|
||||
MTP_int(token),
|
||||
(!token) ? kTlFirstSlice : kTlLimit
|
||||
)).done([=](const MTPstats_BroadcastRevenueTransactions &result) {
|
||||
@@ -799,7 +809,7 @@ void ChannelEarnStatistics::requestHistory(
|
||||
}).send();
|
||||
}
|
||||
|
||||
Data::EarnStatistics ChannelEarnStatistics::data() const {
|
||||
Data::EarnStatistics EarnStatistics::data() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,9 +79,9 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class ChannelEarnStatistics final : public StatisticsRequestSender {
|
||||
class EarnStatistics final : public StatisticsRequestSender {
|
||||
public:
|
||||
explicit ChannelEarnStatistics(not_null<ChannelData*> channel);
|
||||
explicit EarnStatistics(not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
|
||||
void requestHistory(
|
||||
@@ -94,6 +94,7 @@ public:
|
||||
static constexpr auto kLimit = int(10);
|
||||
|
||||
private:
|
||||
const bool _isUser = false;
|
||||
Data::EarnStatistics _data;
|
||||
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
@@ -316,6 +316,9 @@ void Updates::feedUpdateVector(
|
||||
} else if (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants) {
|
||||
return;
|
||||
}
|
||||
if (policy == SkipUpdatePolicy::SkipNone) {
|
||||
applyConvertToScheduledOnSend(updates);
|
||||
}
|
||||
for (const auto &entry : std::as_const(list)) {
|
||||
const auto type = entry.type();
|
||||
if ((policy == SkipUpdatePolicy::SkipMessageIds
|
||||
@@ -329,6 +332,15 @@ void Updates::feedUpdateVector(
|
||||
session().data().sendHistoryChangeNotifications();
|
||||
}
|
||||
|
||||
void Updates::checkForSentToScheduled(const MTPUpdates &updates) {
|
||||
updates.match([&](const MTPDupdates &data) {
|
||||
applyConvertToScheduledOnSend(data.vupdates(), true);
|
||||
}, [&](const MTPDupdatesCombined &data) {
|
||||
applyConvertToScheduledOnSend(data.vupdates(), true);
|
||||
}, [](const auto &) {
|
||||
});
|
||||
}
|
||||
|
||||
void Updates::feedMessageIds(const MTPVector<MTPUpdate> &updates) {
|
||||
for (const auto &update : updates.v) {
|
||||
if (update.type() == mtpc_updateMessageID) {
|
||||
@@ -432,6 +444,7 @@ void Updates::feedChannelDifference(
|
||||
session().data().processChats(data.vchats());
|
||||
|
||||
_handlingChannelDifference = true;
|
||||
applyConvertToScheduledOnSend(data.vother_updates());
|
||||
feedMessageIds(data.vother_updates());
|
||||
session().data().processMessages(
|
||||
data.vnew_messages(),
|
||||
@@ -596,6 +609,7 @@ void Updates::feedDifference(
|
||||
Core::App().checkAutoLock();
|
||||
session().data().processUsers(users);
|
||||
session().data().processChats(chats);
|
||||
applyConvertToScheduledOnSend(other);
|
||||
feedMessageIds(other);
|
||||
session().data().processMessages(msgs, NewMessageType::Unread);
|
||||
feedUpdateVector(other, SkipUpdatePolicy::SkipMessageIds);
|
||||
@@ -881,6 +895,51 @@ void Updates::mtpUpdateReceived(const MTPUpdates &updates) {
|
||||
}
|
||||
}
|
||||
|
||||
void Updates::applyConvertToScheduledOnSend(
|
||||
const MTPVector<MTPUpdate> &other,
|
||||
bool skipScheduledCheck) {
|
||||
for (const auto &update : other.v) {
|
||||
update.match([&](const MTPDupdateNewScheduledMessage &data) {
|
||||
const auto &message = data.vmessage();
|
||||
const auto id = IdFromMessage(message);
|
||||
const auto scheduledMessages = &_session->scheduledMessages();
|
||||
const auto scheduledId = scheduledMessages->localMessageId(id);
|
||||
for (const auto &updateId : other.v) {
|
||||
updateId.match([&](const MTPDupdateMessageID &dataId) {
|
||||
if (dataId.vid().v == id) {
|
||||
auto &owner = session().data();
|
||||
if (skipScheduledCheck) {
|
||||
const auto peerId = PeerFromMessage(message);
|
||||
const auto history = owner.historyLoaded(peerId);
|
||||
if (history) {
|
||||
_session->data().sentToScheduled({
|
||||
.history = history,
|
||||
.scheduledId = scheduledId,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto rand = dataId.vrandom_id().v;
|
||||
const auto localId = owner.messageIdByRandomId(rand);
|
||||
if (const auto local = owner.message(localId)) {
|
||||
if (!local->isScheduled()) {
|
||||
_session->data().sentToScheduled({
|
||||
.history = local->history(),
|
||||
.scheduledId = scheduledId,
|
||||
});
|
||||
|
||||
// We've sent a non-scheduled message,
|
||||
// but it was converted to a scheduled.
|
||||
local->destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [](const auto &) {});
|
||||
}
|
||||
}, [](const auto &) {});
|
||||
}
|
||||
}
|
||||
|
||||
void Updates::applyGroupCallParticipantUpdates(const MTPUpdates &updates) {
|
||||
updates.match([&](const MTPDupdates &data) {
|
||||
session().data().processUsers(data.vusers());
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
void applyUpdatesNoPtsCheck(const MTPUpdates &updates);
|
||||
void applyUpdateNoPtsCheck(const MTPUpdate &update);
|
||||
|
||||
void checkForSentToScheduled(const MTPUpdates &updates);
|
||||
|
||||
[[nodiscard]] int32 pts() const;
|
||||
|
||||
void updateOnline(crl::time lastNonIdleTime = 0);
|
||||
@@ -131,6 +133,9 @@ private:
|
||||
// Doesn't call sendHistoryChangeNotifications itself.
|
||||
void feedUpdate(const MTPUpdate &update);
|
||||
|
||||
void applyConvertToScheduledOnSend(
|
||||
const MTPVector<MTPUpdate> &other,
|
||||
bool skipScheduledCheck = false);
|
||||
void applyGroupCallParticipantUpdates(const MTPUpdates &updates);
|
||||
|
||||
bool whenGetDiffChanged(
|
||||
|
||||
@@ -69,6 +69,9 @@ TLInputRules RulesToTL(const UserPrivacy::Rule &rule) {
|
||||
if (rule.always.premiums && (rule.option != Option::Everyone)) {
|
||||
result.push_back(MTP_inputPrivacyValueAllowPremium());
|
||||
}
|
||||
if (rule.always.miniapps && (rule.option != Option::Everyone)) {
|
||||
result.push_back(MTP_inputPrivacyValueAllowBots());
|
||||
}
|
||||
}
|
||||
if (!rule.ignoreNever) {
|
||||
const auto users = collectInputUsers(rule.never);
|
||||
@@ -83,6 +86,9 @@ TLInputRules RulesToTL(const UserPrivacy::Rule &rule) {
|
||||
MTP_inputPrivacyValueDisallowChatParticipants(
|
||||
MTP_vector<MTPlong>(chats)));
|
||||
}
|
||||
if (rule.never.miniapps && (rule.option != Option::Nobody)) {
|
||||
result.push_back(MTP_inputPrivacyValueDisallowBots());
|
||||
}
|
||||
}
|
||||
result.push_back([&] {
|
||||
switch (rule.option) {
|
||||
@@ -124,6 +130,10 @@ UserPrivacy::Rule TLToRules(const TLRules &rules, Data::Session &owner) {
|
||||
setOption(Option::CloseFriends);
|
||||
}, [&](const MTPDprivacyValueAllowPremium &) {
|
||||
result.always.premiums = true;
|
||||
}, [&](const MTPDprivacyValueAllowBots &) {
|
||||
result.always.miniapps = true;
|
||||
}, [&](const MTPDprivacyValueDisallowBots &) {
|
||||
result.never.miniapps = true;
|
||||
}, [&](const MTPDprivacyValueAllowUsers &data) {
|
||||
const auto &users = data.vusers().v;
|
||||
always.reserve(always.size() + users.size());
|
||||
@@ -199,6 +209,7 @@ MTPInputPrivacyKey KeyToTL(UserPrivacy::Key key) {
|
||||
case Key::Voices: return MTP_inputPrivacyKeyVoiceMessages();
|
||||
case Key::About: return MTP_inputPrivacyKeyAbout();
|
||||
case Key::Birthday: return MTP_inputPrivacyKeyBirthday();
|
||||
case Key::GiftsAutoSave: return MTP_inputPrivacyKeyStarGiftsAutoSave();
|
||||
}
|
||||
Unexpected("Key in Api::UserPrivacy::KetToTL.");
|
||||
}
|
||||
@@ -228,6 +239,8 @@ std::optional<UserPrivacy::Key> TLToKey(mtpTypeId type) {
|
||||
case mtpc_inputPrivacyKeyAbout: return Key::About;
|
||||
case mtpc_privacyKeyBirthday:
|
||||
case mtpc_inputPrivacyKeyBirthday: return Key::Birthday;
|
||||
case mtpc_privacyKeyStarGiftsAutoSave:
|
||||
case mtpc_inputPrivacyKeyStarGiftsAutoSave: return Key::GiftsAutoSave;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
Voices,
|
||||
About,
|
||||
Birthday,
|
||||
GiftsAutoSave,
|
||||
};
|
||||
enum class Option {
|
||||
Everyone,
|
||||
@@ -41,6 +42,7 @@ public:
|
||||
struct Exceptions {
|
||||
std::vector<not_null<PeerData*>> peers;
|
||||
bool premiums = false;
|
||||
bool miniapps = false;
|
||||
};
|
||||
struct Rule {
|
||||
Option option = Option::Everyone;
|
||||
|
||||
@@ -757,4 +757,31 @@ rpl::producer<Ui::WhoReadContent> WhoReacted(
|
||||
return WhoReacted(item, reaction, context, st, nullptr);
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<Ui::WhoReadContent> WhenDate(
|
||||
not_null<PeerData*> author,
|
||||
TimeId date,
|
||||
Ui::WhoReadType type) {
|
||||
return rpl::single(Ui::WhoReadContent{
|
||||
.participants = { Ui::WhoReadParticipant{
|
||||
.name = author->name(),
|
||||
.date = FormatReadDate(date, QDateTime::currentDateTime()),
|
||||
.id = author->id.value,
|
||||
} },
|
||||
.type = type,
|
||||
.fullReadCount = 1,
|
||||
});
|
||||
}
|
||||
|
||||
rpl::producer<Ui::WhoReadContent> WhenEdited(
|
||||
not_null<PeerData*> author,
|
||||
TimeId date) {
|
||||
return WhenDate(author, date, Ui::WhoReadType::Edited);
|
||||
}
|
||||
|
||||
rpl::producer<Ui::WhoReadContent> WhenOriginal(
|
||||
not_null<PeerData*> author,
|
||||
TimeId date) {
|
||||
return WhenDate(author, date, Ui::WhoReadType::Original);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -61,5 +61,11 @@ struct WhoReadList {
|
||||
const Data::ReactionId &reaction,
|
||||
not_null<QWidget*> context, // Cache results for this lifetime.
|
||||
const style::WhoRead &st);
|
||||
[[nodiscard]] rpl::producer<Ui::WhoReadContent> WhenEdited(
|
||||
not_null<PeerData*> author,
|
||||
TimeId date);
|
||||
[[nodiscard]] rpl::producer<Ui::WhoReadContent> WhenOriginal(
|
||||
not_null<PeerData*> author,
|
||||
TimeId date);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -559,6 +559,14 @@ void ApiWrap::sendMessageFail(
|
||||
: tr::lng_error_noforwards_group(tr::now), kJoinErrorDuration);
|
||||
} else if (error == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
|
||||
Settings::ShowPremium(&session(), "premium_stickers");
|
||||
} else if (error == u"SCHEDULE_TOO_MUCH"_q) {
|
||||
auto &scheduled = _session->scheduledMessages();
|
||||
if (const auto item = scheduled.lookupItem(peer->id, itemId.msg)) {
|
||||
scheduled.removeSending(item);
|
||||
}
|
||||
if (show) {
|
||||
show->showToast(tr::lng_error_schedule_limit(tr::now));
|
||||
}
|
||||
}
|
||||
if (const auto item = _session->data().message(itemId)) {
|
||||
Assert(randomId != 0);
|
||||
@@ -708,7 +716,8 @@ void ApiWrap::finalizeMessageDataRequest(
|
||||
|
||||
QString ApiWrap::exportDirectMessageLink(
|
||||
not_null<HistoryItem*> item,
|
||||
bool inRepliesContext) {
|
||||
bool inRepliesContext,
|
||||
bool forceNonPublicLink) {
|
||||
Expects(item->history()->peer->isChannel());
|
||||
|
||||
const auto itemId = item->fullId();
|
||||
@@ -731,7 +740,7 @@ QString ApiWrap::exportDirectMessageLink(
|
||||
const auto sender = root
|
||||
? root->discussionPostOriginalSender()
|
||||
: nullptr;
|
||||
if (sender && sender->hasUsername()) {
|
||||
if (sender && sender->hasUsername() && !forceNonPublicLink) {
|
||||
// Comment to a public channel.
|
||||
const auto forwarded = root->Get<HistoryMessageForwarded>();
|
||||
linkItemId = forwarded->savedFromMsgId;
|
||||
@@ -747,7 +756,7 @@ QString ApiWrap::exportDirectMessageLink(
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto base = linkChannel->hasUsername()
|
||||
const auto base = (linkChannel->hasUsername() && !forceNonPublicLink)
|
||||
? linkChannel->username()
|
||||
: "c/" + QString::number(peerToChannel(linkChannel->id).bare);
|
||||
const auto post = QString::number(linkItemId.bare);
|
||||
@@ -761,6 +770,7 @@ QString ApiWrap::exportDirectMessageLink(
|
||||
? (QString::number(linkThreadId.bare) + '/' + post)
|
||||
: post);
|
||||
if (linkChannel->hasUsername()
|
||||
&& !forceNonPublicLink
|
||||
&& !linkChannel->isMegagroup()
|
||||
&& !linkCommentId
|
||||
&& !linkThreadId) {
|
||||
@@ -774,6 +784,9 @@ QString ApiWrap::exportDirectMessageLink(
|
||||
}
|
||||
return session().createInternalLinkFull(query);
|
||||
};
|
||||
if (forceNonPublicLink) {
|
||||
return fallback();
|
||||
}
|
||||
const auto i = _unlikelyMessageLinks.find(itemId);
|
||||
const auto current = (i != end(_unlikelyMessageLinks))
|
||||
? i->second
|
||||
@@ -3206,6 +3219,31 @@ void ApiWrap::sharedMediaDone(
|
||||
}
|
||||
}
|
||||
|
||||
mtpRequestId ApiWrap::requestGlobalMedia(
|
||||
Storage::SharedMediaType type,
|
||||
const QString &query,
|
||||
int32 offsetRate,
|
||||
Data::MessagePosition offsetPosition,
|
||||
Fn<void(Api::GlobalMediaResult)> done) {
|
||||
auto prepared = Api::PrepareGlobalMediaRequest(
|
||||
_session,
|
||||
offsetRate,
|
||||
offsetPosition,
|
||||
type,
|
||||
query);
|
||||
if (!prepared) {
|
||||
done({});
|
||||
return 0;
|
||||
}
|
||||
return request(
|
||||
std::move(*prepared)
|
||||
).done([=](const Api::SearchRequestResult &result) {
|
||||
done(Api::ParseGlobalMediaResult(_session, result));
|
||||
}).fail([=] {
|
||||
done({});
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::sendAction(const SendAction &action) {
|
||||
if (!action.options.scheduled
|
||||
&& !action.options.shortcutId
|
||||
@@ -3329,6 +3367,7 @@ void ApiWrap::forwardMessages(
|
||||
}
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
const auto idsCopy = localIds;
|
||||
const auto scheduled = action.options.scheduled;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_ForwardMessages(
|
||||
MTP_flags(sendFlags),
|
||||
@@ -3341,6 +3380,9 @@ void ApiWrap::forwardMessages(
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(_session, action.options.shortcutId)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
if (!scheduled) {
|
||||
this->updates().checkForSentToScheduled(result);
|
||||
}
|
||||
applyUpdates(result);
|
||||
if (shared && !--shared->requestsLeft) {
|
||||
shared->callback();
|
||||
@@ -3502,6 +3544,7 @@ void ApiWrap::sendVoiceMessage(
|
||||
QByteArray result,
|
||||
VoiceWaveform waveform,
|
||||
crl::time duration,
|
||||
bool video,
|
||||
const SendAction &action) {
|
||||
const auto caption = TextWithTags();
|
||||
const auto to = FileLoadTaskOptions(action);
|
||||
@@ -3510,6 +3553,7 @@ void ApiWrap::sendVoiceMessage(
|
||||
result,
|
||||
duration,
|
||||
waveform,
|
||||
video,
|
||||
to,
|
||||
caption));
|
||||
}
|
||||
@@ -3936,7 +3980,8 @@ void ApiWrap::sendInlineResult(
|
||||
not_null<UserData*> bot,
|
||||
not_null<InlineBots::Result*> data,
|
||||
const SendAction &action,
|
||||
std::optional<MsgId> localMessageId) {
|
||||
std::optional<MsgId> localMessageId,
|
||||
Fn<void(bool)> done) {
|
||||
sendAction(action);
|
||||
|
||||
const auto history = action.history;
|
||||
@@ -4016,11 +4061,17 @@ void ApiWrap::sendInlineResult(
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
if (done) {
|
||||
done(true);
|
||||
}
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
sendMessageFail(error, peer, randomId, newId);
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
if (done) {
|
||||
done(false);
|
||||
}
|
||||
});
|
||||
finishForwarding(action);
|
||||
}
|
||||
@@ -4225,6 +4276,7 @@ void ApiWrap::sendMultiPaidMedia(
|
||||
auto &histories = history->owner().histories();
|
||||
const auto peer = history->peer;
|
||||
const auto itemId = item->fullId();
|
||||
album->sent = true;
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
@@ -4296,6 +4348,9 @@ void ApiWrap::sendAlbumWithCancelled(
|
||||
}
|
||||
|
||||
void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||
if (album->sent) {
|
||||
return;
|
||||
}
|
||||
const auto groupId = album->groupId;
|
||||
if (album->items.empty()) {
|
||||
_sendingAlbums.remove(groupId);
|
||||
@@ -4320,6 +4375,7 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||
return;
|
||||
} else if (medias.size() < 2) {
|
||||
const auto &single = medias.front().data();
|
||||
album->sent = true;
|
||||
sendMediaWithRandomId(
|
||||
sample,
|
||||
single.vmedia(),
|
||||
@@ -4346,6 +4402,7 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||
| (album->options.invertCaption ? Flag::f_invert_media : Flag(0));
|
||||
auto &histories = history->owner().histories();
|
||||
const auto peer = history->peer;
|
||||
album->sent = true;
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
|
||||
@@ -59,6 +59,7 @@ class Show;
|
||||
namespace Api {
|
||||
|
||||
struct SearchResult;
|
||||
struct GlobalMediaResult;
|
||||
|
||||
class Updates;
|
||||
class Authorizations;
|
||||
@@ -164,7 +165,8 @@ public:
|
||||
void requestMessageData(PeerData *peer, MsgId msgId, Fn<void()> done);
|
||||
QString exportDirectMessageLink(
|
||||
not_null<HistoryItem*> item,
|
||||
bool inRepliesContext);
|
||||
bool inRepliesContext,
|
||||
bool forceNonPublicLink = false);
|
||||
QString exportDirectStoryLink(not_null<Data::Story*> item);
|
||||
|
||||
void requestContacts();
|
||||
@@ -287,6 +289,12 @@ public:
|
||||
Storage::SharedMediaType type,
|
||||
MsgId messageId,
|
||||
SliceType slice);
|
||||
mtpRequestId requestGlobalMedia(
|
||||
Storage::SharedMediaType type,
|
||||
const QString &query,
|
||||
int32 offsetRate,
|
||||
Data::MessagePosition offsetPosition,
|
||||
Fn<void(Api::GlobalMediaResult)> done);
|
||||
|
||||
void readFeaturedSetDelayed(uint64 setId);
|
||||
|
||||
@@ -317,6 +325,7 @@ public:
|
||||
QByteArray result,
|
||||
VoiceWaveform waveform,
|
||||
crl::time duration,
|
||||
bool video,
|
||||
const SendAction &action);
|
||||
void sendFiles(
|
||||
Ui::PreparedList &&list,
|
||||
@@ -359,7 +368,8 @@ public:
|
||||
not_null<UserData*> bot,
|
||||
not_null<InlineBots::Result*> data,
|
||||
const SendAction &action,
|
||||
std::optional<MsgId> localMessageId);
|
||||
std::optional<MsgId> localMessageId,
|
||||
Fn<void(bool)> done = nullptr);
|
||||
void sendMessageFail(
|
||||
const MTP::Error &error,
|
||||
not_null<PeerData*> peer,
|
||||
@@ -506,6 +516,10 @@ private:
|
||||
MsgId topicRootId,
|
||||
SharedMediaType type,
|
||||
Api::SearchResult &&parsed);
|
||||
void globalMediaDone(
|
||||
SharedMediaType type,
|
||||
FullMsgId messageId,
|
||||
Api::GlobalMediaResult &&parsed);
|
||||
|
||||
void sendSharedContact(
|
||||
const QString &phone,
|
||||
@@ -669,6 +683,17 @@ private:
|
||||
};
|
||||
base::flat_set<HistoryRequest> _historyRequests;
|
||||
|
||||
struct GlobalMediaRequest {
|
||||
SharedMediaType mediaType = {};
|
||||
FullMsgId aroundId;
|
||||
SliceType sliceType = {};
|
||||
|
||||
friend inline auto operator<=>(
|
||||
const GlobalMediaRequest&,
|
||||
const GlobalMediaRequest&) = default;
|
||||
};
|
||||
base::flat_set<GlobalMediaRequest> _globalMediaRequests;
|
||||
|
||||
std::unique_ptr<DialogsLoadState> _dialogsLoadState;
|
||||
TimeId _dialogsLoadTill = 0;
|
||||
rpl::variable<bool> _dialogsLoadMayBlockByDate = false;
|
||||
|
||||
@@ -262,10 +262,16 @@ void ShowAddParticipantsError(
|
||||
return tr::lng_bot_already_in_group(tr::now);
|
||||
} else if (error == u"BOT_GROUPS_BLOCKED"_q) {
|
||||
return tr::lng_error_cant_add_bot(tr::now);
|
||||
} else if (error == u"ADMINS_TOO_MUCH"_q) {
|
||||
return ((chat->isChat() || chat->isMegagroup())
|
||||
? tr::lng_error_admin_limit
|
||||
: tr::lng_error_admin_limit_channel)(tr::now);
|
||||
} else if (error == u"YOU_BLOCKED_USER"_q) {
|
||||
return tr::lng_error_you_blocked_user(tr::now);
|
||||
} else if (error == u"CHAT_ADMIN_INVITE_REQUIRED"_q) {
|
||||
return tr::lng_error_add_admin_not_member(tr::now);
|
||||
} else if (error == u"USER_ADMIN_INVALID"_q) {
|
||||
return tr::lng_error_user_admin_invalid(tr::now);
|
||||
} else if (error == u"BOTS_TOO_MUCH"_q) {
|
||||
return (chat->isChannel()
|
||||
? tr::lng_error_channel_bots_too_much
|
||||
: tr::lng_error_group_bots_too_much)(tr::now);
|
||||
}
|
||||
return tr::lng_failed_add_participant(tr::now);
|
||||
}();
|
||||
|
||||
@@ -154,9 +154,7 @@ contactsSortButton: IconButton(defaultIconButton) {
|
||||
iconPosition: point(10px, -1px);
|
||||
rippleAreaPosition: point(1px, 6px);
|
||||
rippleAreaSize: 42px;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
ripple: defaultRippleAnimationBgOver;
|
||||
}
|
||||
contactsSortOnlineIcon: icon{{ "contacts_online", boxTitleCloseFg }};
|
||||
contactsSortOnlineIconOver: icon{{ "contacts_online", boxTitleCloseFgOver }};
|
||||
@@ -416,9 +414,7 @@ calendarPrevious: IconButton {
|
||||
|
||||
rippleAreaPosition: point(2px, 2px);
|
||||
rippleAreaSize: 44px;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
ripple: defaultRippleAnimationBgOver;
|
||||
}
|
||||
calendarPreviousDisabled: icon {{ "calendar_down-flip_vertical", menuIconFg }};
|
||||
calendarNext: IconButton(calendarPrevious) {
|
||||
@@ -616,9 +612,7 @@ proxyTryIPv6Padding: margins(22px, 8px, 22px, 5px);
|
||||
proxyRowPadding: margins(22px, 8px, 8px, 8px);
|
||||
proxyRowIconSkip: 32px;
|
||||
proxyRowSkip: 2px;
|
||||
proxyRowRipple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
proxyRowRipple: defaultRippleAnimationBgOver;
|
||||
proxyRowTitleFg: windowFg;
|
||||
proxyRowTitlePalette: TextPalette(defaultTextPalette) {
|
||||
linkFg: windowSubTextFg;
|
||||
@@ -683,9 +677,7 @@ themesMenuToggle: IconButton(defaultIconButton) {
|
||||
|
||||
rippleAreaPosition: point(4px, 4px);
|
||||
rippleAreaSize: 36px;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
ripple: defaultRippleAnimationBgOver;
|
||||
}
|
||||
themesMenuPosition: point(-2px, 25px);
|
||||
|
||||
@@ -738,9 +730,7 @@ createPollOptionRemove: CrossButton {
|
||||
|
||||
duration: 150;
|
||||
loadingPeriod: 1000;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
ripple: defaultRippleAnimationBgOver;
|
||||
}
|
||||
createPollOptionRemovePosition: point(11px, 9px);
|
||||
createPollOptionEmojiPositionSkip: 4px;
|
||||
@@ -888,6 +878,13 @@ peerListWithInviteViaLink: PeerList(peerListBox) {
|
||||
peerListSingleRow: PeerList(peerListBox) {
|
||||
padding: margins(0px, 0px, 0px, 0px);
|
||||
}
|
||||
peerListSmallSkips: PeerList(peerListBox) {
|
||||
padding: margins(
|
||||
0px,
|
||||
defaultVerticalListSkip,
|
||||
0px,
|
||||
defaultVerticalListSkip);
|
||||
}
|
||||
|
||||
scheduleHeight: 95px;
|
||||
scheduleDateTop: 38px;
|
||||
@@ -951,9 +948,7 @@ sponsoredUrlButton: RoundButton(defaultActiveButton) {
|
||||
textTop: 7px;
|
||||
style: defaultTextStyle;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
ripple: defaultRippleAnimationBgOver;
|
||||
}
|
||||
|
||||
requestPeerRestriction: FlatLabel(defaultFlatLabel) {
|
||||
|
||||
@@ -8,22 +8,106 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/choose_filter_box.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "boxes/filters/edit_filter_box.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "core/application.h" // primaryWindow
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::Bold
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/menu/menu_action.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_media_player.h" // mediaPlayerMenuCheck
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] QImage Icon(const Data::ChatFilter &f) {
|
||||
constexpr auto kScale = 0.75;
|
||||
const auto icon = Ui::LookupFilterIcon(Ui::ComputeFilterIcon(f)).normal;
|
||||
const auto originalWidth = icon->width();
|
||||
const auto originalHeight = icon->height();
|
||||
|
||||
const auto scaledWidth = int(originalWidth * kScale);
|
||||
const auto scaledHeight = int(originalHeight * kScale);
|
||||
|
||||
auto image = QImage(
|
||||
scaledWidth * style::DevicePixelRatio(),
|
||||
scaledHeight * style::DevicePixelRatio(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
image.setDevicePixelRatio(style::DevicePixelRatio());
|
||||
image.fill(Qt::transparent);
|
||||
|
||||
{
|
||||
auto p = QPainter(&image);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
|
||||
const auto x = int((scaledWidth - originalWidth * kScale) / 2);
|
||||
const auto y = int((scaledHeight - originalHeight * kScale) / 2);
|
||||
|
||||
p.scale(kScale, kScale);
|
||||
icon->paint(p, x, y, scaledWidth, st::dialogsUnreadBgMuted->c);
|
||||
if (const auto color = f.colorIndex()) {
|
||||
p.resetTransform();
|
||||
const auto circleSize = scaledWidth / 3.;
|
||||
const auto r = QRectF(
|
||||
x + scaledWidth - circleSize,
|
||||
y + scaledHeight - circleSize - circleSize / 3.,
|
||||
circleSize,
|
||||
circleSize);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Clear);
|
||||
p.setBrush(Qt::transparent);
|
||||
p.drawEllipse(r + Margins(st::lineWidth * 1.5));
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
p.setBrush(Ui::EmptyUserpic::UserpicColor(*color).color2);
|
||||
p.drawEllipse(r);
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
class FilterAction : public Ui::Menu::Action {
|
||||
public:
|
||||
using Ui::Menu::Action::Action;
|
||||
|
||||
void setIcon(QImage &&image) {
|
||||
_icon = std::move(image);
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override {
|
||||
Ui::Menu::Action::paintEvent(event);
|
||||
if (!_icon.isNull()) {
|
||||
const auto size = _icon.size() / style::DevicePixelRatio();
|
||||
auto p = QPainter(this);
|
||||
p.drawImage(
|
||||
width()
|
||||
- size.width()
|
||||
- st::menuWithIcons.itemPadding.right(),
|
||||
(height() - size.height()) / 2,
|
||||
_icon);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QImage _icon;
|
||||
|
||||
};
|
||||
|
||||
Data::ChatFilter ChangedFilter(
|
||||
const Data::ChatFilter &filter,
|
||||
not_null<History*> history,
|
||||
@@ -96,6 +180,9 @@ void ChangeFilterById(
|
||||
Ui::Text::WithEntities));
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
LOG(("API Error: failed to %1 a dialog to a folder. %2")
|
||||
.arg(add ? u"add"_q : u"remove"_q)
|
||||
.arg(error.type()));
|
||||
// Revert filter on fail.
|
||||
history->owner().chatsFilters().set(was);
|
||||
}).send();
|
||||
@@ -123,9 +210,7 @@ bool ChooseFilterValidator::canRemove(FilterId filterId) const {
|
||||
const auto list = _history->owner().chatsFilters().list();
|
||||
const auto i = ranges::find(list, filterId, &Data::ChatFilter::id);
|
||||
if (i != end(list)) {
|
||||
const auto &filter = *i;
|
||||
return filter.contains(_history)
|
||||
&& ((filter.always().size() > 1) || filter.flags());
|
||||
return Data::CanRemoveFromChatFilter(*i, _history);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -161,14 +246,15 @@ void FillChooseFilterMenu(
|
||||
not_null<History*> history) {
|
||||
const auto weak = base::make_weak(controller);
|
||||
const auto validator = ChooseFilterValidator(history);
|
||||
for (const auto &filter : history->owner().chatsFilters().list()) {
|
||||
const auto &list = history->owner().chatsFilters().list();
|
||||
const auto showColors = history->owner().chatsFilters().tagsEnabled();
|
||||
for (const auto &filter : list) {
|
||||
const auto id = filter.id();
|
||||
if (!id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto contains = filter.contains(history);
|
||||
const auto action = menu->addAction(filter.title(), [=] {
|
||||
auto callback = [=] {
|
||||
const auto toAdd = !filter.contains(history);
|
||||
const auto r = validator.limitReached(id, toAdd);
|
||||
if (r.reached) {
|
||||
@@ -185,11 +271,58 @@ void FillChooseFilterMenu(
|
||||
validator.remove(id);
|
||||
}
|
||||
}
|
||||
}, contains ? &st::mediaPlayerMenuCheck : nullptr);
|
||||
};
|
||||
|
||||
const auto contains = filter.contains(history);
|
||||
auto item = base::make_unique_q<FilterAction>(
|
||||
menu.get(),
|
||||
menu->st().menu,
|
||||
Ui::Menu::CreateAction(
|
||||
menu.get(),
|
||||
Ui::Text::FixAmpersandInAction(filter.title()),
|
||||
std::move(callback)),
|
||||
contains ? &st::mediaPlayerMenuCheck : nullptr,
|
||||
contains ? &st::mediaPlayerMenuCheck : nullptr);
|
||||
|
||||
item->setIcon(Icon(showColors ? filter : filter.withColorIndex({})));
|
||||
const auto &p = st::menuWithIcons.itemPadding;
|
||||
item->setMinWidth(item->minWidth() + p.left() - p.right() - p.top());
|
||||
const auto action = menu->addAction(std::move(item));
|
||||
action->setEnabled(contains
|
||||
? validator.canRemove(id)
|
||||
: validator.canAdd());
|
||||
}
|
||||
|
||||
const auto limit = [session = &controller->session()] {
|
||||
return Data::PremiumLimits(session).dialogFiltersCurrent();
|
||||
};
|
||||
if ((list.size() - 1) < limit()) {
|
||||
menu->addAction(tr::lng_filters_create(tr::now), [=] {
|
||||
const auto strong = weak.get();
|
||||
if (!strong) {
|
||||
return;
|
||||
}
|
||||
const auto session = &strong->session();
|
||||
const auto count = session->data().chatsFilters().list().size();
|
||||
if ((count - 1) >= limit()) {
|
||||
return;
|
||||
}
|
||||
auto filter =
|
||||
Data::ChatFilter({}, {}, {}, {}, {}, { history }, {}, {});
|
||||
const auto send = [=](const Data::ChatFilter &filter) {
|
||||
session->api().request(MTPmessages_UpdateDialogFilter(
|
||||
MTP_flags(MTPmessages_UpdateDialogFilter::Flag::f_filter),
|
||||
MTP_int(count),
|
||||
filter.tl()
|
||||
)).done([=] {
|
||||
session->data().chatsFilters().reload();
|
||||
}).send();
|
||||
};
|
||||
strong->uiShow()->show(
|
||||
Box(EditFilterBox, strong, std::move(filter), send, nullptr));
|
||||
}, &st::menuIconShowInFolder);
|
||||
}
|
||||
|
||||
history->owner().chatsFilters().changed(
|
||||
) | rpl::start_with_next([=] {
|
||||
menu->hideMenu();
|
||||
|
||||
@@ -238,7 +238,7 @@ EditCaptionBox::EditCaptionBox(
|
||||
Fn<void()> saved)
|
||||
: _controller(controller)
|
||||
, _historyItem(item)
|
||||
, _isAllowedEditMedia(item->media() && item->media()->allowsEditMedia())
|
||||
, _isAllowedEditMedia(item->allowsEditMedia())
|
||||
, _albumType(ComputeAlbumType(item))
|
||||
, _controls(base::make_unique_q<Ui::VerticalLayout>(this))
|
||||
, _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll))
|
||||
@@ -253,8 +253,8 @@ EditCaptionBox::EditCaptionBox(
|
||||
, _initialText(std::move(text))
|
||||
, _initialList(std::move(list))
|
||||
, _saved(std::move(saved)) {
|
||||
Expects(item->media() != nullptr);
|
||||
Expects(item->media()->allowsEditCaption());
|
||||
Expects(!_initialList.files.empty());
|
||||
Expects(item->allowsEditMedia());
|
||||
|
||||
_mediaEditManager.start(item, spoilered, invertCaption);
|
||||
|
||||
@@ -422,7 +422,8 @@ void EditCaptionBox::prepare() {
|
||||
setInitialText();
|
||||
|
||||
if (!setPreparedList(std::move(_initialList))) {
|
||||
rebuildPreview();
|
||||
crl::on_main(this, [=] { closeBox(); });
|
||||
return;
|
||||
}
|
||||
setupEditEventHandler();
|
||||
SetupShadowsToScrollContent(this, _scroll, _contentHeight.events());
|
||||
|
||||
@@ -36,13 +36,63 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_window.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kPremiumsRowId = PeerId(FakeChatId(BareId(1))).value;
|
||||
constexpr auto kMiniAppsRowId = PeerId(FakeChatId(BareId(2))).value;
|
||||
|
||||
using Exceptions = Api::UserPrivacy::Exceptions;
|
||||
|
||||
enum class SpecialRowType {
|
||||
Premiums,
|
||||
MiniApps,
|
||||
};
|
||||
|
||||
[[nodiscard]] PaintRoundImageCallback GeneratePremiumsUserpicCallback(
|
||||
bool forceRound) {
|
||||
return [=](QPainter &p, int x, int y, int outerWidth, int size) {
|
||||
auto gradient = QLinearGradient(
|
||||
QPointF(x, y),
|
||||
QPointF(x + size, y + size));
|
||||
gradient.setStops(Ui::Premium::ButtonGradientStops());
|
||||
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(gradient);
|
||||
if (forceRound) {
|
||||
p.drawEllipse(x, y, size, size);
|
||||
} else {
|
||||
const auto radius = size * Ui::ForumUserpicRadiusMultiplier();
|
||||
p.drawRoundedRect(x, y, size, size, radius, radius);
|
||||
}
|
||||
st::settingsPrivacyPremium.paintInCenter(p, QRect(x, y, size, size));
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] PaintRoundImageCallback GenerateMiniAppsUserpicCallback(
|
||||
bool forceRound) {
|
||||
return [=](QPainter &p, int x, int y, int outerWidth, int size) {
|
||||
const auto &color1 = st::historyPeer6UserpicBg;
|
||||
const auto &color2 = st::historyPeer6UserpicBg2;
|
||||
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
auto gradient = QLinearGradient(x, y, x, y + size);
|
||||
gradient.setStops({ { 0., color1->c }, { 1., color2->c } });
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(gradient);
|
||||
if (forceRound) {
|
||||
p.drawEllipse(x, y, size, size);
|
||||
} else {
|
||||
const auto radius = size * Ui::ForumUserpicRadiusMultiplier();
|
||||
p.drawRoundedRect(x, y, size, size, radius, radius);
|
||||
}
|
||||
st::windowFilterTypeBots.paintInCenter(p, QRect(x, y, size, size));
|
||||
};
|
||||
}
|
||||
|
||||
void CreateRadiobuttonLock(
|
||||
not_null<Ui::RpWidget*> widget,
|
||||
const style::Checkbox &st) {
|
||||
@@ -102,7 +152,7 @@ public:
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<QString> title,
|
||||
const Exceptions &selected,
|
||||
bool allowChoosePremiums);
|
||||
std::optional<SpecialRowType> allowChooseSpecial);
|
||||
|
||||
Main::Session &session() const override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
@@ -110,18 +160,20 @@ public:
|
||||
bool handleDeselectForeignRow(PeerListRowId itemId) override;
|
||||
|
||||
[[nodiscard]] bool premiumsSelected() const;
|
||||
[[nodiscard]] bool miniAppsSelected() const;
|
||||
|
||||
protected:
|
||||
void prepareViewHook() override;
|
||||
std::unique_ptr<Row> createRow(not_null<History*> history) override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> preparePremiumsRowList();
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> prepareSpecialRowList(
|
||||
SpecialRowType type);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
rpl::producer<QString> _title;
|
||||
Exceptions _selected;
|
||||
bool _allowChoosePremiums = false;
|
||||
std::optional<SpecialRowType> _allowChooseSpecial;
|
||||
|
||||
PeerListContentDelegate *_typesDelegate = nullptr;
|
||||
Fn<void(PeerListRowId)> _deselectOption;
|
||||
@@ -133,9 +185,9 @@ struct RowSelectionChange {
|
||||
bool checked = false;
|
||||
};
|
||||
|
||||
class PremiumsRow final : public PeerListRow {
|
||||
class SpecialRow final : public PeerListRow {
|
||||
public:
|
||||
PremiumsRow();
|
||||
explicit SpecialRow(SpecialRowType type);
|
||||
|
||||
QString generateName() override;
|
||||
QString generateShortName() override;
|
||||
@@ -147,66 +199,61 @@ public:
|
||||
|
||||
class TypesController final : public PeerListController {
|
||||
public:
|
||||
TypesController(not_null<Main::Session*> session, bool premiums);
|
||||
TypesController(not_null<Main::Session*> session, SpecialRowType type);
|
||||
|
||||
Main::Session &session() const override;
|
||||
void prepare() override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
|
||||
[[nodiscard]] bool premiumsSelected() const;
|
||||
[[nodiscard]] rpl::producer<bool> premiumsChanges() const;
|
||||
[[nodiscard]] bool specialSelected() const;
|
||||
[[nodiscard]] rpl::producer<bool> specialChanges() const;
|
||||
[[nodiscard]] auto rowSelectionChanges() const
|
||||
-> rpl::producer<RowSelectionChange>;
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
const SpecialRowType _type;
|
||||
|
||||
rpl::event_stream<> _selectionChanged;
|
||||
rpl::event_stream<RowSelectionChange> _rowSelectionChanges;
|
||||
|
||||
};
|
||||
|
||||
PremiumsRow::PremiumsRow() : PeerListRow(kPremiumsRowId) {
|
||||
setCustomStatus(tr::lng_edit_privacy_premium_status(tr::now));
|
||||
SpecialRow::SpecialRow(SpecialRowType type)
|
||||
: PeerListRow((type == SpecialRowType::Premiums)
|
||||
? kPremiumsRowId
|
||||
: kMiniAppsRowId) {
|
||||
setCustomStatus((id() == kPremiumsRowId)
|
||||
? tr::lng_edit_privacy_premium_status(tr::now)
|
||||
: tr::lng_edit_privacy_miniapps_status(tr::now));
|
||||
}
|
||||
|
||||
QString PremiumsRow::generateName() {
|
||||
return tr::lng_edit_privacy_premium(tr::now);
|
||||
QString SpecialRow::generateName() {
|
||||
return (id() == kPremiumsRowId)
|
||||
? tr::lng_edit_privacy_premium(tr::now)
|
||||
: tr::lng_edit_privacy_miniapps(tr::now);
|
||||
}
|
||||
|
||||
QString PremiumsRow::generateShortName() {
|
||||
QString SpecialRow::generateShortName() {
|
||||
return generateName();
|
||||
}
|
||||
|
||||
PaintRoundImageCallback PremiumsRow::generatePaintUserpicCallback(
|
||||
PaintRoundImageCallback SpecialRow::generatePaintUserpicCallback(
|
||||
bool forceRound) {
|
||||
return [=](QPainter &p, int x, int y, int outerWidth, int size) {
|
||||
auto gradient = QLinearGradient(
|
||||
QPointF(x, y),
|
||||
QPointF(x + size, y + size));
|
||||
gradient.setStops(Ui::Premium::ButtonGradientStops());
|
||||
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(gradient);
|
||||
if (forceRound) {
|
||||
p.drawEllipse(x, y, size, size);
|
||||
} else {
|
||||
const auto radius = size * Ui::ForumUserpicRadiusMultiplier();
|
||||
p.drawRoundedRect(x, y, size, size, radius, radius);
|
||||
}
|
||||
st::settingsPrivacyPremium.paintInCenter(p, QRect(x, y, size, size));
|
||||
};
|
||||
return (id() == kPremiumsRowId)
|
||||
? GeneratePremiumsUserpicCallback(forceRound)
|
||||
: GenerateMiniAppsUserpicCallback(forceRound);
|
||||
}
|
||||
|
||||
bool PremiumsRow::useForumLikeUserpic() const {
|
||||
bool SpecialRow::useForumLikeUserpic() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
TypesController::TypesController(
|
||||
not_null<Main::Session*> session,
|
||||
bool premiums)
|
||||
: _session(session) {
|
||||
SpecialRowType type)
|
||||
: _session(session)
|
||||
, _type(type) {
|
||||
}
|
||||
|
||||
Main::Session &TypesController::session() const {
|
||||
@@ -214,12 +261,15 @@ Main::Session &TypesController::session() const {
|
||||
}
|
||||
|
||||
void TypesController::prepare() {
|
||||
delegate()->peerListAppendRow(std::make_unique<PremiumsRow>());
|
||||
delegate()->peerListAppendRow(std::make_unique<SpecialRow>(_type));
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
|
||||
bool TypesController::premiumsSelected() const {
|
||||
const auto row = delegate()->peerListFindRow(kPremiumsRowId);
|
||||
bool TypesController::specialSelected() const {
|
||||
const auto premiums = (_type == SpecialRowType::Premiums);
|
||||
const auto row = delegate()->peerListFindRow(premiums
|
||||
? kPremiumsRowId
|
||||
: kMiniAppsRowId);
|
||||
Assert(row != nullptr);
|
||||
|
||||
return row->checked();
|
||||
@@ -231,10 +281,10 @@ void TypesController::rowClicked(not_null<PeerListRow*> row) {
|
||||
_rowSelectionChanges.fire({ row, checked });
|
||||
}
|
||||
|
||||
rpl::producer<bool> TypesController::premiumsChanges() const {
|
||||
rpl::producer<bool> TypesController::specialChanges() const {
|
||||
return _rowSelectionChanges.events(
|
||||
) | rpl::map([=] {
|
||||
return premiumsSelected();
|
||||
return specialSelected();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -247,12 +297,12 @@ PrivacyExceptionsBoxController::PrivacyExceptionsBoxController(
|
||||
not_null<Main::Session*> session,
|
||||
rpl::producer<QString> title,
|
||||
const Exceptions &selected,
|
||||
bool allowChoosePremiums)
|
||||
std::optional<SpecialRowType> allowChooseSpecial)
|
||||
: ChatsListBoxController(session)
|
||||
, _session(session)
|
||||
, _title(std::move(title))
|
||||
, _selected(selected)
|
||||
, _allowChoosePremiums(allowChoosePremiums) {
|
||||
, _allowChooseSpecial(allowChooseSpecial) {
|
||||
}
|
||||
|
||||
Main::Session &PrivacyExceptionsBoxController::session() const {
|
||||
@@ -261,14 +311,18 @@ Main::Session &PrivacyExceptionsBoxController::session() const {
|
||||
|
||||
void PrivacyExceptionsBoxController::prepareViewHook() {
|
||||
delegate()->peerListSetTitle(std::move(_title));
|
||||
if (_allowChoosePremiums || _selected.premiums) {
|
||||
delegate()->peerListSetAboveWidget(preparePremiumsRowList());
|
||||
if (_allowChooseSpecial || _selected.premiums || _selected.miniapps) {
|
||||
delegate()->peerListSetAboveWidget(prepareSpecialRowList(
|
||||
_allowChooseSpecial.value_or(_selected.premiums
|
||||
? SpecialRowType::Premiums
|
||||
: SpecialRowType::MiniApps)));
|
||||
}
|
||||
delegate()->peerListAddSelectedPeers(_selected.peers);
|
||||
}
|
||||
|
||||
bool PrivacyExceptionsBoxController::isForeignRow(PeerListRowId itemId) {
|
||||
return (itemId == kPremiumsRowId);
|
||||
return (itemId == kPremiumsRowId)
|
||||
|| (itemId == kMiniAppsRowId);
|
||||
}
|
||||
|
||||
bool PrivacyExceptionsBoxController::handleDeselectForeignRow(
|
||||
@@ -280,7 +334,8 @@ bool PrivacyExceptionsBoxController::handleDeselectForeignRow(
|
||||
return false;
|
||||
}
|
||||
|
||||
auto PrivacyExceptionsBoxController::preparePremiumsRowList()
|
||||
auto PrivacyExceptionsBoxController::prepareSpecialRowList(
|
||||
SpecialRowType type)
|
||||
-> object_ptr<Ui::RpWidget> {
|
||||
auto result = object_ptr<Ui::VerticalLayout>((QWidget*)nullptr);
|
||||
const auto container = result.data();
|
||||
@@ -291,30 +346,39 @@ auto PrivacyExceptionsBoxController::preparePremiumsRowList()
|
||||
_typesDelegate = lifetime.make_state<PeerListContentDelegateSimple>();
|
||||
const auto controller = lifetime.make_state<TypesController>(
|
||||
&session(),
|
||||
_selected.premiums);
|
||||
type);
|
||||
const auto content = result->add(object_ptr<PeerListContent>(
|
||||
container,
|
||||
controller));
|
||||
_typesDelegate->setContent(content);
|
||||
controller->setDelegate(_typesDelegate);
|
||||
|
||||
const auto selectType = [&](PeerListRowId id) {
|
||||
const auto row = _typesDelegate->peerListFindRow(id);
|
||||
if (row) {
|
||||
content->changeCheckState(row, true, anim::type::instant);
|
||||
this->delegate()->peerListSetForeignRowChecked(
|
||||
row,
|
||||
true,
|
||||
anim::type::instant);
|
||||
}
|
||||
};
|
||||
if (_selected.premiums) {
|
||||
const auto row = _typesDelegate->peerListFindRow(kPremiumsRowId);
|
||||
Assert(row != nullptr);
|
||||
|
||||
content->changeCheckState(row, true, anim::type::instant);
|
||||
this->delegate()->peerListSetForeignRowChecked(
|
||||
row,
|
||||
true,
|
||||
anim::type::instant);
|
||||
selectType(kPremiumsRowId);
|
||||
} else if (_selected.miniapps) {
|
||||
selectType(kMiniAppsRowId);
|
||||
}
|
||||
container->add(CreatePeerListSectionSubtitle(
|
||||
container,
|
||||
tr::lng_edit_privacy_users_and_groups()));
|
||||
|
||||
controller->premiumsChanges(
|
||||
) | rpl::start_with_next([=](bool premiums) {
|
||||
_selected.premiums = premiums;
|
||||
controller->specialChanges(
|
||||
) | rpl::start_with_next([=](bool chosen) {
|
||||
if (type == SpecialRowType::Premiums) {
|
||||
_selected.premiums = chosen;
|
||||
} else {
|
||||
_selected.miniapps = chosen;
|
||||
}
|
||||
}, lifetime);
|
||||
|
||||
controller->rowSelectionChanges(
|
||||
@@ -329,6 +393,8 @@ auto PrivacyExceptionsBoxController::preparePremiumsRowList()
|
||||
if (const auto row = _typesDelegate->peerListFindRow(itemId)) {
|
||||
if (itemId == kPremiumsRowId) {
|
||||
_selected.premiums = false;
|
||||
} else if (itemId == kMiniAppsRowId) {
|
||||
_selected.miniapps = false;
|
||||
}
|
||||
_typesDelegate->peerListSetRowChecked(row, false);
|
||||
}
|
||||
@@ -337,10 +403,14 @@ auto PrivacyExceptionsBoxController::preparePremiumsRowList()
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool PrivacyExceptionsBoxController::premiumsSelected() const {
|
||||
bool PrivacyExceptionsBoxController::premiumsSelected() const {
|
||||
return _selected.premiums;
|
||||
}
|
||||
|
||||
bool PrivacyExceptionsBoxController::miniAppsSelected() const {
|
||||
return _selected.miniapps;
|
||||
}
|
||||
|
||||
void PrivacyExceptionsBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
const auto peer = row->peer();
|
||||
|
||||
@@ -412,6 +482,11 @@ EditPrivacyBox::EditPrivacyBox(
|
||||
// If we switch from Everyone to Contacts or Nobody suggest Premiums.
|
||||
_value.always.premiums = true;
|
||||
}
|
||||
if (_controller->allowMiniAppsToggle(Exception::Always)
|
||||
&& _value.option == Option::Everyone) {
|
||||
// If we switch from Everyone to Contacts or Nobody suggest MiniApps.
|
||||
_value.always.miniapps = true;
|
||||
}
|
||||
}
|
||||
|
||||
void EditPrivacyBox::prepare() {
|
||||
@@ -427,12 +502,18 @@ void EditPrivacyBox::editExceptions(
|
||||
&_window->session(),
|
||||
_controller->exceptionBoxTitle(exception),
|
||||
exceptions(exception),
|
||||
_controller->allowPremiumsToggle(exception));
|
||||
(_controller->allowPremiumsToggle(exception)
|
||||
? SpecialRowType::Premiums
|
||||
: _controller->allowMiniAppsToggle(exception)
|
||||
? SpecialRowType::MiniApps
|
||||
: std::optional<SpecialRowType>()));
|
||||
auto initBox = [=, controller = controller.get()](
|
||||
not_null<PeerListBox*> box) {
|
||||
box->addButton(tr::lng_settings_save(), crl::guard(this, [=] {
|
||||
exceptions(exception).peers = box->collectSelectedRows();
|
||||
exceptions(exception).premiums = controller->premiumsSelected();
|
||||
auto &setTo = exceptions(exception);
|
||||
setTo.peers = box->collectSelectedRows();
|
||||
setTo.premiums = controller->premiumsSelected();
|
||||
setTo.miniapps = controller->miniAppsSelected();
|
||||
const auto type = [&] {
|
||||
switch (exception) {
|
||||
case Exception::Always: return Exception::Never;
|
||||
@@ -440,11 +521,17 @@ void EditPrivacyBox::editExceptions(
|
||||
}
|
||||
Unexpected("Invalid exception value.");
|
||||
}();
|
||||
auto &removeFrom = exceptions(type).peers;
|
||||
auto &removeFrom = exceptions(type);
|
||||
for (const auto peer : exceptions(exception).peers) {
|
||||
removeFrom.erase(
|
||||
ranges::remove(removeFrom, peer),
|
||||
end(removeFrom));
|
||||
removeFrom.peers.erase(
|
||||
ranges::remove(removeFrom.peers, peer),
|
||||
end(removeFrom.peers));
|
||||
}
|
||||
if (setTo.premiums) {
|
||||
removeFrom.premiums = false;
|
||||
}
|
||||
if (setTo.miniapps) {
|
||||
removeFrom.miniapps = false;
|
||||
}
|
||||
done();
|
||||
box->closeBox();
|
||||
@@ -566,14 +653,21 @@ void EditPrivacyBox::setupContent() {
|
||||
lt_count,
|
||||
count)
|
||||
: tr::lng_edit_privacy_exceptions_add(tr::now);
|
||||
return !value.premiums
|
||||
? users
|
||||
: !count
|
||||
? tr::lng_edit_privacy_premium(tr::now)
|
||||
: tr::lng_edit_privacy_exceptions_premium_and(
|
||||
tr::now,
|
||||
lt_users,
|
||||
users);
|
||||
return value.premiums
|
||||
? (!count
|
||||
? tr::lng_edit_privacy_premium(tr::now)
|
||||
: tr::lng_edit_privacy_exceptions_premium_and(
|
||||
tr::now,
|
||||
lt_users,
|
||||
users))
|
||||
: value.miniapps
|
||||
? (!count
|
||||
? tr::lng_edit_privacy_miniapps(tr::now)
|
||||
: tr::lng_edit_privacy_exceptions_miniapps_and(
|
||||
tr::now,
|
||||
lt_users,
|
||||
users))
|
||||
: users;
|
||||
});
|
||||
_controller->handleExceptionsChange(
|
||||
exception,
|
||||
|
||||
@@ -61,6 +61,10 @@ public:
|
||||
Exception exception) const {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] virtual bool allowMiniAppsToggle(
|
||||
Exception exception) const {
|
||||
return false;
|
||||
}
|
||||
virtual void handleExceptionsChange(
|
||||
Exception exception,
|
||||
rpl::producer<int> value) {
|
||||
|
||||
@@ -7,22 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/filters/edit_filter_box.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "boxes/filters/edit_filter_chats_list.h"
|
||||
#include "boxes/filters/edit_filter_chats_preview.h"
|
||||
#include "boxes/filters/edit_filter_links.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/effects/panel_animation.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/filter_icon_panel.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_peer.h"
|
||||
@@ -30,22 +24,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "history/history.h"
|
||||
#include "info/userpic/info_userpic_color_circle_button.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/chat/chats_filter_tag.h"
|
||||
#include "ui/effects/animation_value_f.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/panel_animation.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "ui/filter_icon_panel.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "apiwrap.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_info_userpic_builder.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -336,6 +341,8 @@ void EditFilterBox(
|
||||
const Data::ChatFilter &data,
|
||||
Fn<void(Data::ChatFilter)> next)> saveAnd) {
|
||||
using namespace rpl::mappers;
|
||||
constexpr auto kColorsCount = 8;
|
||||
constexpr auto kNoTag = kColorsCount - 1;
|
||||
|
||||
struct State {
|
||||
rpl::variable<Data::ChatFilter> rules;
|
||||
@@ -343,6 +350,7 @@ void EditFilterBox(
|
||||
rpl::variable<bool> hasLinks;
|
||||
rpl::variable<bool> chatlist;
|
||||
rpl::variable<bool> creating;
|
||||
rpl::variable<int> colorIndex;
|
||||
};
|
||||
const auto owner = &window->session().data();
|
||||
const auto state = box->lifetime().make_state<State>(State{
|
||||
@@ -350,6 +358,7 @@ void EditFilterBox(
|
||||
.chatlist = filter.chatlist(),
|
||||
.creating = filter.title().isEmpty(),
|
||||
});
|
||||
state->colorIndex = filter.colorIndex().value_or(kNoTag);
|
||||
state->links = owner->chatsFilters().chatlistLinks(filter.id()),
|
||||
state->hasLinks = state->links.value() | rpl::map([=](const auto &v) {
|
||||
return !v.empty();
|
||||
@@ -504,6 +513,164 @@ void EditFilterBox(
|
||||
Ui::AddDividerText(excludeInner, tr::lng_filters_exclude_about());
|
||||
Ui::AddSkip(excludeInner);
|
||||
|
||||
{
|
||||
const auto wrap = content->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
content,
|
||||
object_ptr<Ui::VerticalLayout>(content)));
|
||||
const auto colors = wrap->entity();
|
||||
const auto session = &window->session();
|
||||
|
||||
wrap->toggleOn(
|
||||
rpl::combine(
|
||||
session->premiumPossibleValue(),
|
||||
session->data().chatsFilters().tagsEnabledValue(),
|
||||
Data::AmPremiumValue(session)
|
||||
) | rpl::map([=] (bool possible, bool tagsEnabled, bool premium) {
|
||||
return possible && (tagsEnabled || !premium);
|
||||
}),
|
||||
anim::type::instant);
|
||||
|
||||
const auto isPremium = session->premium();
|
||||
const auto title = Ui::AddSubsectionTitle(
|
||||
colors,
|
||||
tr::lng_filters_tag_color_subtitle());
|
||||
const auto preview = Ui::CreateChild<Ui::RpWidget>(colors);
|
||||
title->geometryValue(
|
||||
) | rpl::start_with_next([=](const QRect &r) {
|
||||
const auto h = st::normalFont->height;
|
||||
preview->setGeometry(
|
||||
colors->x(),
|
||||
r.y() + (r.height() - h) / 2 + st::lineWidth,
|
||||
colors->width(),
|
||||
h);
|
||||
}, preview->lifetime());
|
||||
const auto previewTag = preview->lifetime().make_state<QImage>();
|
||||
const auto previewAlpha = preview->lifetime().make_state<float64>(1);
|
||||
preview->paintRequest() | rpl::start_with_next([=] {
|
||||
auto p = QPainter(preview);
|
||||
p.setOpacity(*previewAlpha);
|
||||
const auto size = previewTag->size() / style::DevicePixelRatio();
|
||||
const auto rect = QRect(
|
||||
preview->width() - size.width() - st::boxRowPadding.right(),
|
||||
(st::normalFont->height - size.height()) / 2,
|
||||
size.width(),
|
||||
size.height());
|
||||
p.drawImage(rect.topLeft(), *previewTag);
|
||||
if (p.opacity() < 1) {
|
||||
p.setOpacity(1. - p.opacity());
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(st::windowSubTextFg);
|
||||
p.drawText(
|
||||
preview->rect() - st::boxRowPadding,
|
||||
tr::lng_filters_tag_color_no(tr::now),
|
||||
style::al_right);
|
||||
}
|
||||
}, preview->lifetime());
|
||||
|
||||
const auto side = st::userpicBuilderEmojiAccentColorSize;
|
||||
const auto line = colors->add(
|
||||
Ui::CreateSkipWidget(colors, side),
|
||||
st::boxRowPadding);
|
||||
auto buttons = std::vector<not_null<UserpicBuilder::CircleButton*>>();
|
||||
const auto animation
|
||||
= line->lifetime().make_state<Ui::Animations::Simple>();
|
||||
const auto palette = [](int i) {
|
||||
return Ui::EmptyUserpic::UserpicColor(i).color2;
|
||||
};
|
||||
name->changes() | rpl::start_with_next([=] {
|
||||
*previewTag = Ui::ChatsFilterTag(
|
||||
name->getLastText().toUpper(),
|
||||
palette(state->colorIndex.current())->c,
|
||||
false);
|
||||
preview->update();
|
||||
}, preview->lifetime());
|
||||
for (auto i = 0; i < kColorsCount; ++i) {
|
||||
const auto button = Ui::CreateChild<UserpicBuilder::CircleButton>(
|
||||
line);
|
||||
button->resize(side, side);
|
||||
const auto progress = isPremium
|
||||
? (state->colorIndex.current() == i)
|
||||
: (i == kNoTag);
|
||||
button->setSelectedProgress(progress);
|
||||
const auto color = palette(i);
|
||||
button->setBrush(color);
|
||||
if (progress == 1) {
|
||||
*previewTag = Ui::ChatsFilterTag(
|
||||
name->getLastText().toUpper(),
|
||||
color->c,
|
||||
false);
|
||||
if (i == kNoTag) {
|
||||
*previewAlpha = 0.;
|
||||
}
|
||||
}
|
||||
buttons.push_back(button);
|
||||
}
|
||||
for (auto i = 0; i < kColorsCount; ++i) {
|
||||
const auto &button = buttons[i];
|
||||
button->setClickedCallback([=] {
|
||||
const auto was = state->colorIndex.current();
|
||||
const auto now = i;
|
||||
if (was != now) {
|
||||
const auto c1 = palette(was);
|
||||
const auto c2 = palette(now);
|
||||
const auto a1 = (was == kNoTag) ? 0. : 1.;
|
||||
const auto a2 = (now == kNoTag) ? 0. : 1.;
|
||||
animation->stop();
|
||||
animation->start([=](float64 progress) {
|
||||
if (was >= 0) {
|
||||
buttons[was]->setSelectedProgress(1. - progress);
|
||||
}
|
||||
buttons[now]->setSelectedProgress(progress);
|
||||
*previewTag = Ui::ChatsFilterTag(
|
||||
name->getLastText().toUpper(),
|
||||
anim::color(c1, c2, progress),
|
||||
false);
|
||||
*previewAlpha = anim::interpolateF(a1, a2, progress);
|
||||
preview->update();
|
||||
}, 0., 1., st::universalDuration);
|
||||
}
|
||||
state->colorIndex = now;
|
||||
});
|
||||
if (!session->premium()) {
|
||||
button->setClickedCallback([w = window] {
|
||||
ShowPremiumPreviewToBuy(w, PremiumFeature::FilterTags);
|
||||
});
|
||||
}
|
||||
}
|
||||
line->sizeValue() | rpl::start_with_next([=](const QSize &size) {
|
||||
const auto totalWidth = buttons.size() * side;
|
||||
const auto spacing = (size.width() - totalWidth)
|
||||
/ (buttons.size() - 1);
|
||||
for (auto i = 0; i < kColorsCount; ++i) {
|
||||
const auto &button = buttons[i];
|
||||
button->moveToLeft(i * (side + spacing), 0);
|
||||
}
|
||||
}, line->lifetime());
|
||||
|
||||
{
|
||||
const auto last = buttons.back();
|
||||
const auto icon = Ui::CreateChild<Ui::RpWidget>(last);
|
||||
icon->resize(side, side);
|
||||
icon->paintRequest() | rpl::start_with_next([=] {
|
||||
auto p = QPainter(icon);
|
||||
(session->premium()
|
||||
? st::windowFilterSmallRemove.icon
|
||||
: st::historySendDisabledIcon).paintInCenter(
|
||||
p,
|
||||
QRectF(icon->rect()),
|
||||
st::historyPeerUserpicFg->c);
|
||||
}, icon->lifetime());
|
||||
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
last->setBrush(st::historyPeerArchiveUserpicBg);
|
||||
}
|
||||
|
||||
Ui::AddSkip(colors);
|
||||
Ui::AddSkip(colors);
|
||||
Ui::AddDividerText(colors, tr::lng_filters_tag_color_about());
|
||||
Ui::AddSkip(colors);
|
||||
}
|
||||
|
||||
const auto collect = [=]() -> std::optional<Data::ChatFilter> {
|
||||
const auto title = name->getLastText().trimmed();
|
||||
const auto rules = data->current();
|
||||
@@ -520,7 +687,11 @@ void EditFilterBox(
|
||||
window->window().showToast(tr::lng_filters_default(tr::now));
|
||||
return {};
|
||||
}
|
||||
return rules.withTitle(title);
|
||||
const auto rawColorIndex = state->colorIndex.current();
|
||||
const auto colorIndex = (rawColorIndex >= kNoTag
|
||||
? std::nullopt
|
||||
: std::make_optional(rawColorIndex));
|
||||
return rules.withTitle(title).withColorIndex(colorIndex);
|
||||
};
|
||||
|
||||
Ui::AddSubsectionTitle(
|
||||
|
||||
@@ -7,12 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
class GenericBox;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Data {
|
||||
class ChatFilter;
|
||||
} // namespace Data
|
||||
|
||||
@@ -7,7 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/filters/edit_filter_chats_list.h"
|
||||
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@@ -125,7 +127,15 @@ Flag TypeRow::flag() const {
|
||||
}
|
||||
|
||||
ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
|
||||
if (peer()->isSelf()) {
|
||||
auto filters = QStringList();
|
||||
for (const auto &filter : history->owner().chatsFilters().list()) {
|
||||
if (filter.contains(history) && filter.id()) {
|
||||
filters << filter.title();
|
||||
}
|
||||
}
|
||||
if (!filters.isEmpty()) {
|
||||
setCustomStatus(filters.join(", "));
|
||||
} else if (peer()->isSelf()) {
|
||||
setCustomStatus(tr::lng_saved_forward_here(tr::now));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ void GiftCreditsBox(
|
||||
const auto content = box->setPinnedToTopContent(
|
||||
object_ptr<Ui::VerticalLayout>(box));
|
||||
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
const auto &stUser = st::premiumGiftsUserpicButton;
|
||||
@@ -58,39 +59,19 @@ void GiftCreditsBox(
|
||||
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());
|
||||
}
|
||||
Settings::AddMiniStars(
|
||||
content,
|
||||
Ui::CreateChild<Ui::RpWidget>(content),
|
||||
stUser.photoSize,
|
||||
box->width(),
|
||||
2.);
|
||||
{
|
||||
Ui::AddSkip(content);
|
||||
const auto arrow = Ui::Text::SingleCustomEmoji(
|
||||
peer->owner().customEmojiManager().registerInternalEmoji(
|
||||
st::topicButtonArrow,
|
||||
st::channelEarnLearnArrowMargins,
|
||||
false));
|
||||
true));
|
||||
auto link = tr::lng_credits_box_history_entry_gift_about_link(
|
||||
lt_emoji,
|
||||
rpl::single(arrow),
|
||||
@@ -122,8 +103,10 @@ void GiftCreditsBox(
|
||||
Main::MakeSessionShow(box->uiShow(), &peer->session()),
|
||||
box->verticalLayout(),
|
||||
peer,
|
||||
0,
|
||||
[=] { gifted(); box->uiShow()->hideLayer(); });
|
||||
StarsAmount(),
|
||||
[=] { gifted(); box->uiShow()->hideLayer(); },
|
||||
tr::lng_credits_summary_options_subtitle(),
|
||||
{});
|
||||
|
||||
box->setPinnedToBottomContent(
|
||||
object_ptr<Ui::VerticalLayout>(box));
|
||||
|
||||
@@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/peers/prepare_short_info_box.h"
|
||||
#include "boxes/peers/replace_boost_box.h" // BoostsForGift.
|
||||
#include "boxes/premium_preview_box.h" // ShowPremiumPreviewBox.
|
||||
#include "boxes/star_gift_box.h" // ShowStarGiftBox.
|
||||
#include "data/data_boosts.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
@@ -123,7 +124,8 @@ namespace {
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> MakePeerTableValue(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
PeerId id) {
|
||||
PeerId id,
|
||||
bool withSendGiftButton = false) {
|
||||
auto result = object_ptr<Ui::AbstractButton>(parent);
|
||||
const auto raw = result.data();
|
||||
|
||||
@@ -134,15 +136,40 @@ namespace {
|
||||
const auto userpic = Ui::CreateChild<Ui::UserpicButton>(raw, peer, st);
|
||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||
raw,
|
||||
peer->name(),
|
||||
withSendGiftButton ? peer->shortName() : peer->name(),
|
||||
st::giveawayGiftCodeValue);
|
||||
raw->widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
const auto send = withSendGiftButton
|
||||
? Ui::CreateChild<Ui::RoundButton>(
|
||||
raw,
|
||||
tr::lng_gift_send_small(),
|
||||
st::starGiftSmallButton)
|
||||
: nullptr;
|
||||
if (send) {
|
||||
send->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||
send->setClickedCallback([=] {
|
||||
Ui::ShowStarGiftBox(controller->parentController(), peer);
|
||||
});
|
||||
}
|
||||
rpl::combine(
|
||||
raw->widthValue(),
|
||||
send ? send->widthValue() : rpl::single(0)
|
||||
) | rpl::start_with_next([=](int width, int sendWidth) {
|
||||
const auto position = st::giveawayGiftCodeNamePosition;
|
||||
label->resizeToNaturalWidth(width - position.x());
|
||||
const auto sendSkip = sendWidth
|
||||
? (st::normalFont->spacew + sendWidth)
|
||||
: 0;
|
||||
label->resizeToNaturalWidth(width - position.x() - sendSkip);
|
||||
label->moveToLeft(position.x(), position.y(), width);
|
||||
const auto top = (raw->height() - userpic->height()) / 2;
|
||||
userpic->moveToLeft(0, top, width);
|
||||
if (send) {
|
||||
send->moveToLeft(
|
||||
position.x() + label->width() + st::normalFont->spacew,
|
||||
(position.y()
|
||||
+ st::giveawayGiftCodeValue.style.font->ascent
|
||||
- st::starGiftSmallButton.style.font->ascent),
|
||||
width);
|
||||
}
|
||||
}, label->lifetime());
|
||||
|
||||
userpic->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
@@ -210,14 +237,138 @@ void AddTableRow(
|
||||
valueMargins);
|
||||
}
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> MakeStarGiftStarsValue(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
const Data::CreditsHistoryEntry &entry,
|
||||
Fn<void()> convertToStars) {
|
||||
auto result = object_ptr<Ui::RpWidget>(parent);
|
||||
const auto raw = result.data();
|
||||
|
||||
const auto session = &controller->session();
|
||||
const auto makeContext = [session](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = session,
|
||||
.customEmojiRepaint = std::move(update),
|
||||
};
|
||||
};
|
||||
auto star = session->data().customEmojiManager().creditsEmoji();
|
||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||
raw,
|
||||
rpl::single(star.append(
|
||||
' ' + Lang::FormatStarsAmountDecimal(entry.credits))),
|
||||
st::giveawayGiftCodeValue,
|
||||
st::defaultPopupMenu,
|
||||
std::move(makeContext));
|
||||
|
||||
const auto convert = convertToStars
|
||||
? Ui::CreateChild<Ui::RoundButton>(
|
||||
raw,
|
||||
tr::lng_gift_sell_small(
|
||||
lt_count_decimal,
|
||||
rpl::single(entry.starsConverted * 1.)),
|
||||
st::starGiftSmallButton)
|
||||
: nullptr;
|
||||
if (convert) {
|
||||
convert->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||
convert->setClickedCallback(std::move(convertToStars));
|
||||
}
|
||||
rpl::combine(
|
||||
raw->widthValue(),
|
||||
convert ? convert->widthValue() : rpl::single(0)
|
||||
) | rpl::start_with_next([=](int width, int convertWidth) {
|
||||
const auto convertSkip = convertWidth
|
||||
? (st::normalFont->spacew + convertWidth)
|
||||
: 0;
|
||||
label->resizeToNaturalWidth(width - convertSkip);
|
||||
label->moveToLeft(0, 0, width);
|
||||
if (convert) {
|
||||
convert->moveToLeft(
|
||||
label->width() + st::normalFont->spacew,
|
||||
(st::giveawayGiftCodeValue.style.font->ascent
|
||||
- st::starGiftSmallButton.style.font->ascent),
|
||||
width);
|
||||
}
|
||||
}, label->lifetime());
|
||||
|
||||
label->heightValue() | rpl::start_with_next([=](int height) {
|
||||
raw->resize(
|
||||
raw->width(),
|
||||
height + st::giveawayGiftCodeValueMargin.bottom());
|
||||
}, raw->lifetime());
|
||||
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> MakeVisibilityTableValue(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
bool savedToProfile,
|
||||
Fn<void(bool)> toggleVisibility) {
|
||||
auto result = object_ptr<Ui::RpWidget>(parent);
|
||||
const auto raw = result.data();
|
||||
|
||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||
raw,
|
||||
(savedToProfile
|
||||
? tr::lng_gift_visibility_shown()
|
||||
: tr::lng_gift_visibility_hidden()),
|
||||
st::giveawayGiftCodeValue,
|
||||
st::defaultPopupMenu);
|
||||
|
||||
const auto toggle = Ui::CreateChild<Ui::RoundButton>(
|
||||
raw,
|
||||
(savedToProfile
|
||||
? tr::lng_gift_visibility_hide()
|
||||
: tr::lng_gift_visibility_show()),
|
||||
st::starGiftSmallButton);
|
||||
toggle->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||
toggle->setClickedCallback([=] {
|
||||
toggleVisibility(!savedToProfile);
|
||||
});
|
||||
|
||||
rpl::combine(
|
||||
raw->widthValue(),
|
||||
toggle->widthValue()
|
||||
) | rpl::start_with_next([=](int width, int toggleWidth) {
|
||||
const auto toggleSkip = toggleWidth
|
||||
? (st::normalFont->spacew + toggleWidth)
|
||||
: 0;
|
||||
label->resizeToNaturalWidth(width - toggleSkip);
|
||||
label->moveToLeft(0, 0, width);
|
||||
if (toggle) {
|
||||
toggle->moveToLeft(
|
||||
label->width() + st::normalFont->spacew,
|
||||
(st::giveawayGiftCodeValue.style.font->ascent
|
||||
- st::starGiftSmallButton.style.font->ascent),
|
||||
width);
|
||||
}
|
||||
}, label->lifetime());
|
||||
|
||||
label->heightValue() | rpl::start_with_next([=](int height) {
|
||||
raw->resize(
|
||||
raw->width(),
|
||||
height + st::giveawayGiftCodeValueMargin.bottom());
|
||||
}, raw->lifetime());
|
||||
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
not_null<Ui::FlatLabel*> AddTableRow(
|
||||
not_null<Ui::TableLayout*> table,
|
||||
rpl::producer<QString> label,
|
||||
rpl::producer<TextWithEntities> value) {
|
||||
rpl::producer<TextWithEntities> value,
|
||||
const Fn<std::any(Fn<void()>)> &makeContext = nullptr) {
|
||||
auto widget = object_ptr<Ui::FlatLabel>(
|
||||
table,
|
||||
std::move(value),
|
||||
st::giveawayGiftCodeValue);
|
||||
st::giveawayGiftCodeValue,
|
||||
st::defaultPopupMenu,
|
||||
std::move(makeContext));
|
||||
const auto result = widget.data();
|
||||
AddTableRow(
|
||||
table,
|
||||
@@ -939,42 +1090,85 @@ void ResolveGiveawayInfo(
|
||||
void AddStarGiftTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const Data::CreditsHistoryEntry &entry) {
|
||||
const Data::CreditsHistoryEntry &entry,
|
||||
Fn<void(bool)> toggleVisibility,
|
||||
Fn<void()> convertToStars) {
|
||||
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) {
|
||||
const auto user = session->data().peer(peerId)->asUser();
|
||||
const auto withSendButton = entry.in && user && !user->isBot();
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_peer_in(),
|
||||
controller,
|
||||
peerId);
|
||||
} else {
|
||||
MakePeerTableValue(table, controller, peerId, withSendButton),
|
||||
st::giveawayGiftCodePeerMargin);
|
||||
} else if (!entry.soldOutInfo) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_peer_in(),
|
||||
MakeHiddenPeerTableValue(table, controller),
|
||||
st::giveawayGiftCodePeerMargin);
|
||||
}
|
||||
if (!entry.firstSaleDate.isNull()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_first_sale(),
|
||||
rpl::single(Ui::Text::WithEntities(
|
||||
langDateTime(entry.firstSaleDate))));
|
||||
}
|
||||
if (!entry.lastSaleDate.isNull()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_last_sale(),
|
||||
rpl::single(Ui::Text::WithEntities(
|
||||
langDateTime(entry.lastSaleDate))));
|
||||
}
|
||||
if (!entry.date.isNull()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_date(),
|
||||
rpl::single(Ui::Text::WithEntities(langDateTime(entry.date))));
|
||||
}
|
||||
const auto marginWithButton = st::giveawayGiftCodeValueMargin
|
||||
- QMargins(0, 0, 0, st::giveawayGiftCodeValueMargin.bottom());
|
||||
{
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_value(),
|
||||
MakeStarGiftStarsValue(
|
||||
table,
|
||||
controller,
|
||||
entry,
|
||||
std::move(convertToStars)),
|
||||
marginWithButton);
|
||||
}
|
||||
if (toggleVisibility) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_visibility(),
|
||||
MakeVisibilityTableValue(
|
||||
table,
|
||||
controller,
|
||||
entry.savedToProfile,
|
||||
std::move(toggleVisibility)),
|
||||
marginWithButton);
|
||||
}
|
||||
if (entry.limitedCount > 0) {
|
||||
auto amount = rpl::single(TextWithEntities{
|
||||
QString::number(entry.limitedCount)
|
||||
Lang::FormatCountDecimal(entry.limitedCount)
|
||||
});
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_availability(),
|
||||
((entry.limitedLeft > 0)
|
||||
? tr::lng_gift_availability_left(
|
||||
lt_count,
|
||||
lt_count_decimal,
|
||||
rpl::single(entry.limitedLeft * 1.),
|
||||
lt_amount,
|
||||
std::move(amount),
|
||||
@@ -985,7 +1179,6 @@ void AddStarGiftTable(
|
||||
Ui::Text::WithEntities)));
|
||||
}
|
||||
if (!entry.description.empty()) {
|
||||
const auto session = &controller->session();
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = session,
|
||||
@@ -1020,12 +1213,51 @@ void AddCreditsHistoryEntryTable(
|
||||
st::giveawayGiftCodeTable),
|
||||
st::giveawayGiftCodeTableMargin);
|
||||
const auto peerId = PeerId(entry.barePeerId);
|
||||
const auto actorId = PeerId(entry.bareActorId);
|
||||
const auto starrefRecipientId = PeerId(entry.starrefRecipientId);
|
||||
const auto session = &controller->session();
|
||||
if (peerId) {
|
||||
auto text = entry.in
|
||||
if (entry.starrefCommission) {
|
||||
if (entry.starrefAmount) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_star_ref_commission_title(),
|
||||
rpl::single(TextWithEntities{
|
||||
QString::number(entry.starrefCommission / 10.) + '%' }));
|
||||
} else {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_reason(),
|
||||
tr::lng_credits_box_history_entry_reason_star_ref(
|
||||
Ui::Text::WithEntities));
|
||||
}
|
||||
}
|
||||
if (starrefRecipientId && entry.starrefAmount) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_affiliate(),
|
||||
controller,
|
||||
starrefRecipientId);
|
||||
}
|
||||
if (peerId && entry.starrefCommission) {
|
||||
AddTableRow(
|
||||
table,
|
||||
(entry.starrefAmount
|
||||
? tr::lng_credits_box_history_entry_referred
|
||||
: tr::lng_credits_box_history_entry_miniapp)(),
|
||||
controller,
|
||||
peerId);
|
||||
}
|
||||
if (actorId || (!entry.starrefCommission && peerId)) {
|
||||
auto text = entry.starrefCommission
|
||||
? tr::lng_credits_box_history_entry_referred()
|
||||
: entry.in
|
||||
? tr::lng_credits_box_history_entry_peer_in()
|
||||
: tr::lng_credits_box_history_entry_peer();
|
||||
AddTableRow(table, std::move(text), controller, peerId);
|
||||
AddTableRow(
|
||||
table,
|
||||
std::move(text),
|
||||
controller,
|
||||
actorId ? actorId : peerId);
|
||||
}
|
||||
if (const auto msgId = MsgId(peerId ? entry.bareMsgId : 0)) {
|
||||
const auto peer = session->data().peer(peerId);
|
||||
@@ -1044,7 +1276,9 @@ void AddCreditsHistoryEntryTable(
|
||||
});
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_media(),
|
||||
(entry.reaction
|
||||
? tr::lng_credits_box_history_entry_message
|
||||
: tr::lng_credits_box_history_entry_media)(),
|
||||
std::move(label),
|
||||
st::giveawayGiftCodeValueMargin);
|
||||
}
|
||||
@@ -1097,7 +1331,7 @@ void AddCreditsHistoryEntryTable(
|
||||
tr::lng_gift_link_label_gift(),
|
||||
tr::lng_gift_stars_title(
|
||||
lt_count,
|
||||
rpl::single(float64(entry.credits)),
|
||||
rpl::single(entry.credits.value()),
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
{
|
||||
@@ -1115,8 +1349,15 @@ void AddCreditsHistoryEntryTable(
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (!entry.subscriptionUntil.isNull() && !entry.title.isEmpty()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_gift_link_label_reason(),
|
||||
tr::lng_credits_box_history_entry_subscription(
|
||||
Ui::Text::WithEntities));
|
||||
}
|
||||
if (!entry.id.isEmpty()) {
|
||||
constexpr auto kOneLineCount = 18;
|
||||
constexpr auto kOneLineCount = 24;
|
||||
const auto oneLine = entry.id.length() <= kOneLineCount;
|
||||
auto label = object_ptr<Ui::FlatLabel>(
|
||||
table,
|
||||
@@ -1138,6 +1379,14 @@ void AddCreditsHistoryEntryTable(
|
||||
std::move(label),
|
||||
st::giveawayGiftCodeValueMargin);
|
||||
}
|
||||
if (entry.floodSkip) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_box_history_entry_floodskip_row(),
|
||||
rpl::single(
|
||||
Ui::Text::WithEntities(
|
||||
Lang::FormatCountDecimal(entry.floodSkip))));
|
||||
}
|
||||
if (!entry.date.isNull()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
@@ -1172,12 +1421,35 @@ void AddSubscriptionEntryTable(
|
||||
st::giveawayGiftCodeTable),
|
||||
st::giveawayGiftCodeTableMargin);
|
||||
const auto peerId = PeerId(s.barePeerId);
|
||||
const auto user = peerIsUser(peerId)
|
||||
? controller->session().data().peer(peerId)->asUser()
|
||||
: nullptr;
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_subscription_row_to(),
|
||||
(!s.title.isEmpty() && user && user->botInfo)
|
||||
? tr::lng_credits_subscription_row_to_bot()
|
||||
: (!s.title.isEmpty() && user && !user->botInfo)
|
||||
? tr::lng_credits_subscription_row_to_business()
|
||||
: tr::lng_credits_subscription_row_to(),
|
||||
controller,
|
||||
peerId);
|
||||
if (!s.title.isEmpty()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_credits_subscription_row_to(),
|
||||
rpl::single(Ui::Text::WithEntities(s.title)));
|
||||
}
|
||||
if (!s.until.isNull()) {
|
||||
if (s.subscription.period > 0) {
|
||||
const auto subscribed = s.until.addSecs(-s.subscription.period);
|
||||
if (subscribed.isValid()) {
|
||||
AddTableRow(
|
||||
table,
|
||||
tr::lng_group_invite_joined_row_date(),
|
||||
rpl::single(
|
||||
Ui::Text::WithEntities(langDateTime(subscribed))));
|
||||
}
|
||||
}
|
||||
AddTableRow(
|
||||
table,
|
||||
s.expired
|
||||
|
||||
@@ -57,7 +57,9 @@ void ResolveGiveawayInfo(
|
||||
void AddStarGiftTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const Data::CreditsHistoryEntry &entry);
|
||||
const Data::CreditsHistoryEntry &entry,
|
||||
Fn<void(bool)> toggleVisibility,
|
||||
Fn<void()> convertToStars);
|
||||
void AddCreditsHistoryEntryTable(
|
||||
not_null<Window::SessionNavigation*> controller,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
|
||||
@@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/local_storage_box.h"
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
@@ -21,8 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "storage/cache/storage_cache_database.h"
|
||||
#include "data/data_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwindow.h"
|
||||
#include "main/main_session.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
@@ -240,7 +239,8 @@ int LocalStorageBox::Row::resizeGetHeight(int newWidth) {
|
||||
}
|
||||
|
||||
void LocalStorageBox::Row::paintEvent(QPaintEvent *e) {
|
||||
if (!_progress || true) {
|
||||
#if 0 // not used
|
||||
if (!_progress) {
|
||||
return;
|
||||
}
|
||||
auto p = QPainter(this);
|
||||
@@ -254,6 +254,7 @@ void LocalStorageBox::Row::paintEvent(QPaintEvent *e) {
|
||||
st::proxyCheckingPosition.y() + bottom
|
||||
},
|
||||
width());
|
||||
#endif
|
||||
}
|
||||
|
||||
QString LocalStorageBox::Row::titleText(const Database::TaggedSummary &data) const {
|
||||
@@ -280,19 +281,19 @@ LocalStorageBox::LocalStorageBox(
|
||||
_timeLimit = settings.totalTimeLimit;
|
||||
}
|
||||
|
||||
void LocalStorageBox::Show(not_null<::Main::Session*> session) {
|
||||
void LocalStorageBox::Show(not_null<Window::SessionController*> controller) {
|
||||
auto shared = std::make_shared<object_ptr<LocalStorageBox>>(
|
||||
Box<LocalStorageBox>(session, CreateTag()));
|
||||
Box<LocalStorageBox>(&controller->session(), CreateTag()));
|
||||
const auto weak = shared->data();
|
||||
rpl::combine(
|
||||
session->data().cache().statsOnMain(),
|
||||
session->data().cacheBigFile().statsOnMain()
|
||||
controller->session().data().cache().statsOnMain(),
|
||||
controller->session().data().cacheBigFile().statsOnMain()
|
||||
) | rpl::start_with_next([=](
|
||||
Database::Stats &&stats,
|
||||
Database::Stats &&statsBig) {
|
||||
weak->update(std::move(stats), std::move(statsBig));
|
||||
if (auto &strong = *shared) {
|
||||
Ui::show(std::move(strong));
|
||||
controller->uiShow()->show(std::move(strong));
|
||||
}
|
||||
}, weak->lifetime());
|
||||
}
|
||||
|
||||