Compare commits
778 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45444253fd | ||
|
|
308ade6a7e | ||
|
|
fc67a801e3 | ||
|
|
6a3657ca87 | ||
|
|
0537c5f273 | ||
|
|
cc4a5f30b6 | ||
|
|
b0d7c3e9b1 | ||
|
|
3bf7c44fc9 | ||
|
|
4ff4e63a11 | ||
|
|
72a35ba58b | ||
|
|
b6a31979f2 | ||
|
|
7c710e22cc | ||
|
|
ab58e7a225 | ||
|
|
c9fb97cd7c | ||
|
|
789f3e1584 | ||
|
|
0fc8229be1 | ||
|
|
a1e555267e | ||
|
|
0ac88c0cb5 | ||
|
|
d43a6da62b | ||
|
|
940455f786 | ||
|
|
0f74456f30 | ||
|
|
7840fa6d90 | ||
|
|
95ccc99fee | ||
|
|
7b0a156bba | ||
|
|
0d8ae7bb37 | ||
|
|
9491cff1df | ||
|
|
51dc5d6e37 | ||
|
|
f4c739ab92 | ||
|
|
0dd8ae3d77 | ||
|
|
7d2878d81c | ||
|
|
bd70a05861 | ||
|
|
0605c7b2bc | ||
|
|
8e83a55143 | ||
|
|
4ab4eb8ef2 | ||
|
|
d1e6150874 | ||
|
|
4121c99f36 | ||
|
|
827040f487 | ||
|
|
9032489786 | ||
|
|
8ea7bd4913 | ||
|
|
97b021efaf | ||
|
|
b3f9a77ba7 | ||
|
|
63fdc1f876 | ||
|
|
17cf354c58 | ||
|
|
c6fd8bcb99 | ||
|
|
1684465e04 | ||
|
|
fe2df96953 | ||
|
|
ee9d0cfd99 | ||
|
|
7b7e18e752 | ||
|
|
928be4151b | ||
|
|
37dd648686 | ||
|
|
93a590774e | ||
|
|
22b99b6d3e | ||
|
|
101d626d4f | ||
|
|
3633c19208 | ||
|
|
e302f328f7 | ||
|
|
f74ba95e95 | ||
|
|
c38982d286 | ||
|
|
fe9bac096b | ||
|
|
5b809c4fc6 | ||
|
|
4729e51e14 | ||
|
|
960cf7a34b | ||
|
|
852ab19760 | ||
|
|
2e45d9fc6b | ||
|
|
74b71b92b6 | ||
|
|
bbc14ba74f | ||
|
|
45c7829cd8 | ||
|
|
f2aa3afbbb | ||
|
|
909b01241b | ||
|
|
abb58c58a0 | ||
|
|
700e10d32c | ||
|
|
4ac48d0e4a | ||
|
|
345b2cb835 | ||
|
|
b962309498 | ||
|
|
e99cb9bfb8 | ||
|
|
9e12e18f90 | ||
|
|
66fc9b38df | ||
|
|
5dbe429e6b | ||
|
|
b2481ea6c1 | ||
|
|
86a294ce4b | ||
|
|
a8d1eadfbf | ||
|
|
b07d3c5403 | ||
|
|
892db55ae1 | ||
|
|
93615fef65 | ||
|
|
87452706ef | ||
|
|
3569615b21 | ||
|
|
86f7d09d31 | ||
|
|
d5d1254393 | ||
|
|
4df90cfb9e | ||
|
|
ec6862d31a | ||
|
|
6f23010382 | ||
|
|
c672f105d3 | ||
|
|
e60d501e4a | ||
|
|
0d7175058b | ||
|
|
3b0bd9d1d1 | ||
|
|
bd28ac6e1f | ||
|
|
0c2d00c792 | ||
|
|
140ba653b9 | ||
|
|
f64f008f77 | ||
|
|
a6315bef05 | ||
|
|
f810d7c82a | ||
|
|
cf61dedc79 | ||
|
|
2ab9587f5f | ||
|
|
4950b52359 | ||
|
|
03af444735 | ||
|
|
7f6221b409 | ||
|
|
ef859d77e9 | ||
|
|
0fd752657a | ||
|
|
f1451a1de3 | ||
|
|
fa96f25683 | ||
|
|
9e447383df | ||
|
|
5e762be32b | ||
|
|
75de81a3ab | ||
|
|
d26b64a5bb | ||
|
|
cb8d40eaf2 | ||
|
|
ded0936bc4 | ||
|
|
16830a410c | ||
|
|
9f79dda463 | ||
|
|
15dc7c74d7 | ||
|
|
f9abef9e05 | ||
|
|
ba84499f00 | ||
|
|
79ce24222a | ||
|
|
6cb9264864 | ||
|
|
247a070405 | ||
|
|
e05bb75b8a | ||
|
|
6a415cf232 | ||
|
|
e8034189df | ||
|
|
107f329b4f | ||
|
|
999a13358e | ||
|
|
2077f51084 | ||
|
|
1e77a3df20 | ||
|
|
141a291523 | ||
|
|
cb03d5a9d3 | ||
|
|
b618d1e56a | ||
|
|
23ae638512 | ||
|
|
eda749d7cb | ||
|
|
08d0186e53 | ||
|
|
443981ba31 | ||
|
|
f3ed7c5e19 | ||
|
|
dd2378b591 | ||
|
|
b885779365 | ||
|
|
32b95f0d9a | ||
|
|
2b8eec8666 | ||
|
|
3f24627f54 | ||
|
|
0c4bca312e | ||
|
|
e36afc675e | ||
|
|
d754014321 | ||
|
|
9f73242cc5 | ||
|
|
fae9649773 | ||
|
|
4b43f4cbec | ||
|
|
b61befa210 | ||
|
|
5e2bc337bc | ||
|
|
af1608cbfa | ||
|
|
9aa80976ff | ||
|
|
c9cfe9e90f | ||
|
|
482e337762 | ||
|
|
a0821f5a01 | ||
|
|
5ebdf3ed39 | ||
|
|
86096db02d | ||
|
|
a93e01b896 | ||
|
|
0585e72c35 | ||
|
|
c82fbefcfc | ||
|
|
23542a1db1 | ||
|
|
1bf50d60d8 | ||
|
|
8596b0309e | ||
|
|
7f6e871b26 | ||
|
|
8912d4d55a | ||
|
|
7ac849ab12 | ||
|
|
4cab699b04 | ||
|
|
03aa05e4d2 | ||
|
|
428a3cf0ce | ||
|
|
1c8b165a64 | ||
|
|
1869071ef7 | ||
|
|
33ca5ee39f | ||
|
|
e46d5a86d3 | ||
|
|
2729bcac3b | ||
|
|
d60ce41fa9 | ||
|
|
958db945f3 | ||
|
|
057f906ca4 | ||
|
|
8df7a45e29 | ||
|
|
e4af1570cb | ||
|
|
049ebf9027 | ||
|
|
f2f0c7df92 | ||
|
|
bee4118513 | ||
|
|
bf48025d12 | ||
|
|
5e624605cf | ||
|
|
026490acc6 | ||
|
|
709ce3adb8 | ||
|
|
a8d23489c4 | ||
|
|
296df113e3 | ||
|
|
97c4e79e96 | ||
|
|
f89bac7781 | ||
|
|
1d8a7f8fd3 | ||
|
|
ef9f7ab27a | ||
|
|
a676138745 | ||
|
|
7442ea7a16 | ||
|
|
0089cad740 | ||
|
|
cf1fa718a8 | ||
|
|
d6ba6ac41e | ||
|
|
bbdd5feaa4 | ||
|
|
678527254b | ||
|
|
46bf7781aa | ||
|
|
99c547b625 | ||
|
|
6976e97de3 | ||
|
|
f8e3e70273 | ||
|
|
23c9f7a957 | ||
|
|
2ca763cc77 | ||
|
|
2adc811351 | ||
|
|
be18be4a86 | ||
|
|
8d7abb1b8a | ||
|
|
1cc5988c40 | ||
|
|
da426ae03b | ||
|
|
3cebd6d923 | ||
|
|
f1019c8ca4 | ||
|
|
edfb7b6b24 | ||
|
|
157a928f5a | ||
|
|
5f5a2a3ef2 | ||
|
|
8534cf3756 | ||
|
|
39b90092ff | ||
|
|
d3142ebe6d | ||
|
|
d914c6be2e | ||
|
|
05c3e968df | ||
|
|
7756cce123 | ||
|
|
8287d717f8 | ||
|
|
db9e60b4b5 | ||
|
|
28a79bfccb | ||
|
|
321490e528 | ||
|
|
6f752357d7 | ||
|
|
e1f71baed6 | ||
|
|
df377cd5bb | ||
|
|
691a0acdab | ||
|
|
5e2eda6af3 | ||
|
|
17cdc2b585 | ||
|
|
c08266f81b | ||
|
|
f90a4db569 | ||
|
|
22ec7a6d75 | ||
|
|
1b16a84810 | ||
|
|
d778276f5d | ||
|
|
e3030a168f | ||
|
|
dfd07a4f4f | ||
|
|
f9fc65d7de | ||
|
|
46cf7db242 | ||
|
|
2b94cffe7e | ||
|
|
2e74ad6fbe | ||
|
|
df7dc1583d | ||
|
|
88e80b4fae | ||
|
|
aea90f4b65 | ||
|
|
80db076f38 | ||
|
|
27bba8250a | ||
|
|
3fb0fa6892 | ||
|
|
c3195cfcbe | ||
|
|
51661a872c | ||
|
|
64706ea103 | ||
|
|
ec69d557dc | ||
|
|
addd37fb1f | ||
|
|
9dc947ecb6 | ||
|
|
7d74d3da3a | ||
|
|
aa0c56876c | ||
|
|
37c7b0c6d1 | ||
|
|
0d07d238bc | ||
|
|
fa4e74ffef | ||
|
|
c22d76e5be | ||
|
|
18850ebd83 | ||
|
|
17abef95eb | ||
|
|
d135151477 | ||
|
|
07fd9b3074 | ||
|
|
0523ae705a | ||
|
|
9db2502cd0 | ||
|
|
a174119877 | ||
|
|
569dd19932 | ||
|
|
530e2a1feb | ||
|
|
de732ba692 | ||
|
|
c6649e84a6 | ||
|
|
e3517aceab | ||
|
|
6d7abd1718 | ||
|
|
e9e493707b | ||
|
|
c25adf8b57 | ||
|
|
d2be10cd4e | ||
|
|
006ecf9a56 | ||
|
|
a53cc52241 | ||
|
|
961d283325 | ||
|
|
4e46529eb6 | ||
|
|
81001e04e9 | ||
|
|
2fd174ab9c | ||
|
|
6ff5e221ea | ||
|
|
232077b919 | ||
|
|
fecddb5203 | ||
|
|
d0132c0f7b | ||
|
|
37d32b32f8 | ||
|
|
51213b499f | ||
|
|
dcb98ce0fb | ||
|
|
428e90a844 | ||
|
|
017535cf7b | ||
|
|
409389a994 | ||
|
|
ba34d92cd3 | ||
|
|
b412ee258d | ||
|
|
f1ffe2a641 | ||
|
|
a13ca95894 | ||
|
|
0989a80a57 | ||
|
|
d72c15e9d3 | ||
|
|
7084cf9526 | ||
|
|
67cc0ef75c | ||
|
|
75714cc358 | ||
|
|
75e454f3fd | ||
|
|
97afb4e01a | ||
|
|
8fcbf43410 | ||
|
|
15a834b883 | ||
|
|
3d8396e586 | ||
|
|
3257fd364a | ||
|
|
d690af99fc | ||
|
|
1c28495162 | ||
|
|
ec82d5674f | ||
|
|
4a22e76bdb | ||
|
|
527be95618 | ||
|
|
41985c0a5f | ||
|
|
522e45ce92 | ||
|
|
48fb0f3b1e | ||
|
|
798093c58f | ||
|
|
e795dad616 | ||
|
|
c3587ff46f | ||
|
|
dc9fa9ccf2 | ||
|
|
97c259d928 | ||
|
|
afffdd5bbf | ||
|
|
199e7a1d46 | ||
|
|
a1aa315187 | ||
|
|
8c56fddc55 | ||
|
|
277d76df3e | ||
|
|
1ac33d30bd | ||
|
|
658cb438f8 | ||
|
|
2b71625ffe | ||
|
|
2b13fc9a24 | ||
|
|
9e18964e7f | ||
|
|
43dfe559a6 | ||
|
|
aab7ba264c | ||
|
|
b7162b5fad | ||
|
|
ce4a081155 | ||
|
|
5df2a048e1 | ||
|
|
1b6a7fafa8 | ||
|
|
2ab725e5e1 | ||
|
|
88a310a86e | ||
|
|
86319be256 | ||
|
|
9d68ef6421 | ||
|
|
2bb1c5d39b | ||
|
|
3aa15c979d | ||
|
|
c062ba3426 | ||
|
|
343560225c | ||
|
|
e0dd77f0c3 | ||
|
|
92ff07f723 | ||
|
|
a23dca080a | ||
|
|
6844f88567 | ||
|
|
e6060ea277 | ||
|
|
549de7fa54 | ||
|
|
ecf9faa21d | ||
|
|
a87ebd41e7 | ||
|
|
183dd40f39 | ||
|
|
c722c5c46f | ||
|
|
865200db5e | ||
|
|
c3e15de759 | ||
|
|
44bfdbdc83 | ||
|
|
5f10c1875c | ||
|
|
a7ae7a8cda | ||
|
|
706f142a98 | ||
|
|
08df3b2dff | ||
|
|
14672ff145 | ||
|
|
7fcd84d08e | ||
|
|
12f8686326 | ||
|
|
aa445adfff | ||
|
|
603aa5db5f | ||
|
|
c34289036f | ||
|
|
5b6bec775b | ||
|
|
3b0fe3043f | ||
|
|
c99165891f | ||
|
|
4938b18f9d | ||
|
|
8895b4e8a3 | ||
|
|
a7321c9beb | ||
|
|
c23b533704 | ||
|
|
de34c75788 | ||
|
|
06341efe0d | ||
|
|
c810005f86 | ||
|
|
cdedf283ac | ||
|
|
acfd92e2e6 | ||
|
|
51b81dba87 | ||
|
|
7f6dfcf52f | ||
|
|
92582d8434 | ||
|
|
e2bff474db | ||
|
|
4f702e12b7 | ||
|
|
083400d1c2 | ||
|
|
7491337bfd | ||
|
|
d6b833fbb2 | ||
|
|
2113a2b634 | ||
|
|
5df632264f | ||
|
|
42c350243a | ||
|
|
522ca3b04a | ||
|
|
2d53ec5d34 | ||
|
|
13d2f70c3a | ||
|
|
a87d19998e | ||
|
|
6ddf241293 | ||
|
|
e43ec6c4ea | ||
|
|
5f3db95cbd | ||
|
|
d874829b06 | ||
|
|
6cfbccd955 | ||
|
|
0d821c3630 | ||
|
|
b61e3b580d | ||
|
|
5c301353ec | ||
|
|
0363421862 | ||
|
|
6f18b9b691 | ||
|
|
35e40be550 | ||
|
|
c1528f532e | ||
|
|
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 |
32
.devcontainer.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "CentOS",
|
||||
"image": "tdesktop:centos_env",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"C_Cpp.intelliSenseEngine": "disabled",
|
||||
"clangd.arguments": [
|
||||
"--compile-commands-dir=${workspaceFolder}/out"
|
||||
],
|
||||
"cmake.generator": "Ninja Multi-Config",
|
||||
"cmake.buildDirectory": "${workspaceFolder}/out"
|
||||
},
|
||||
"extensions": [
|
||||
"ms-vscode.cpptools-extension-pack",
|
||||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"TheQtCompany.qt",
|
||||
"ms-python.python",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"eamodio.gitlens"
|
||||
]
|
||||
}
|
||||
},
|
||||
"capAdd": [
|
||||
"SYS_PTRACE"
|
||||
],
|
||||
"securityOpt": [
|
||||
"seccomp=unconfined"
|
||||
],
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/usr/src/tdesktop,type=bind,consistency=cached",
|
||||
"workspaceFolder": "/usr/src/tdesktop"
|
||||
}
|
||||
5
.github/workflows/linux.yml
vendored
@@ -83,6 +83,7 @@ jobs:
|
||||
fi
|
||||
|
||||
docker run --rm \
|
||||
-u $(id -u) \
|
||||
-v $PWD:/usr/src/tdesktop \
|
||||
-e CONFIG=Debug \
|
||||
tdesktop:centos_env \
|
||||
@@ -114,8 +115,8 @@ jobs:
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
run: |
|
||||
cd $REPO_NAME/out/Debug
|
||||
sudo mkdir artifact
|
||||
sudo mv {Telegram,Updater} artifact/
|
||||
mkdir artifact
|
||||
mv {Telegram,Updater} artifact/
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
name: Upload artifact.
|
||||
|
||||
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'
|
||||
|
||||
1
.gitignore
vendored
@@ -19,6 +19,7 @@ Release/
|
||||
ipch/
|
||||
.vs/
|
||||
.vscode/
|
||||
.cache/
|
||||
|
||||
/Telegram/log.txt
|
||||
/Telegram/data
|
||||
|
||||
2
LEGAL
@@ -1,7 +1,7 @@
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
Copyright (c) 2014-2024 The Telegram Desktop Authors.
|
||||
Copyright (c) 2014-2025 The Telegram Desktop Authors.
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -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
|
||||
@@ -244,6 +246,8 @@ PRIVATE
|
||||
boxes/peers/prepare_short_info_box.h
|
||||
boxes/peers/replace_boost_box.cpp
|
||||
boxes/peers/replace_boost_box.h
|
||||
boxes/peers/verify_peers_box.cpp
|
||||
boxes/peers/verify_peers_box.h
|
||||
boxes/about_box.cpp
|
||||
boxes/about_box.h
|
||||
boxes/about_sponsored_box.cpp
|
||||
@@ -292,6 +296,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 +324,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
|
||||
@@ -328,6 +332,8 @@ PRIVATE
|
||||
boxes/sticker_set_box.h
|
||||
boxes/stickers_box.cpp
|
||||
boxes/stickers_box.h
|
||||
boxes/transfer_gift_box.cpp
|
||||
boxes/transfer_gift_box.h
|
||||
boxes/translate_box.cpp
|
||||
boxes/translate_box.h
|
||||
boxes/url_auth_box.cpp
|
||||
@@ -466,6 +472,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
|
||||
@@ -623,6 +630,7 @@ PRIVATE
|
||||
data/data_shared_media.h
|
||||
data/data_sparse_ids.cpp
|
||||
data/data_sparse_ids.h
|
||||
data/data_star_gift.h
|
||||
data/data_statistics.h
|
||||
data/data_stories.cpp
|
||||
data/data_stories.h
|
||||
@@ -636,6 +644,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
|
||||
@@ -791,6 +801,8 @@ PRIVATE
|
||||
history/view/media/history_view_story_mention.h
|
||||
history/view/media/history_view_theme_document.cpp
|
||||
history/view/media/history_view_theme_document.h
|
||||
history/view/media/history_view_unique_gift.cpp
|
||||
history/view/media/history_view_unique_gift.h
|
||||
history/view/media/history_view_userpic_suggestion.cpp
|
||||
history/view/media/history_view_userpic_suggestion.h
|
||||
history/view/media/history_view_web_page.cpp
|
||||
@@ -913,6 +925,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 +953,13 @@ 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.cpp
|
||||
info/media/info_media_buttons.h
|
||||
info/media/info_media_common.cpp
|
||||
info/media/info_media_common.h
|
||||
@@ -982,12 +1007,16 @@ 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
|
||||
info/settings/info_settings_widget.h
|
||||
info/similar_channels/info_similar_channels_widget.cpp
|
||||
info/similar_channels/info_similar_channels_widget.h
|
||||
info/similar_peers/info_similar_peers_widget.cpp
|
||||
info/similar_peers/info_similar_peers_widget.h
|
||||
info/statistics/info_statistics_common.h
|
||||
info/statistics/info_statistics_inner_widget.cpp
|
||||
info/statistics/info_statistics_inner_widget.h
|
||||
@@ -1032,6 +1061,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
|
||||
@@ -1103,6 +1136,8 @@ PRIVATE
|
||||
media/audio/media_audio_loader.h
|
||||
media/audio/media_audio_loaders.cpp
|
||||
media/audio/media_audio_loaders.h
|
||||
media/audio/media_audio_local_cache.cpp
|
||||
media/audio/media_audio_local_cache.h
|
||||
media/audio/media_audio_track.cpp
|
||||
media/audio/media_audio_track.h
|
||||
media/audio/media_child_ffmpeg_loader.cpp
|
||||
@@ -1171,6 +1206,8 @@ PRIVATE
|
||||
media/streaming/media_streaming_video_track.h
|
||||
media/view/media_view_group_thumbs.cpp
|
||||
media/view/media_view_group_thumbs.h
|
||||
media/view/media_view_open_common.cpp
|
||||
media/view/media_view_open_common.h
|
||||
media/view/media_view_overlay_opengl.cpp
|
||||
media/view/media_view_overlay_opengl.h
|
||||
media/view/media_view_overlay_raster.cpp
|
||||
@@ -1189,7 +1226,6 @@ PRIVATE
|
||||
media/view/media_view_playback_controls.h
|
||||
media/view/media_view_playback_progress.cpp
|
||||
media/view/media_view_playback_progress.h
|
||||
media/view/media_view_open_common.h
|
||||
media/system_media_controls_manager.h
|
||||
media/system_media_controls_manager.cpp
|
||||
menu/menu_antispam_validator.cpp
|
||||
@@ -1377,8 +1413,6 @@ PRIVATE
|
||||
settings/business/settings_recipients_helper.h
|
||||
settings/business/settings_working_hours.cpp
|
||||
settings/business/settings_working_hours.h
|
||||
settings/cloud_password/settings_cloud_password_common.cpp
|
||||
settings/cloud_password/settings_cloud_password_common.h
|
||||
settings/cloud_password/settings_cloud_password_email.cpp
|
||||
settings/cloud_password/settings_cloud_password_email.h
|
||||
settings/cloud_password/settings_cloud_password_email_confirm.cpp
|
||||
@@ -1391,6 +1425,10 @@ 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/cloud_password/settings_cloud_password_step.cpp
|
||||
settings/cloud_password/settings_cloud_password_step.h
|
||||
settings/settings_active_sessions.cpp
|
||||
settings/settings_active_sessions.h
|
||||
settings/settings_advanced.cpp
|
||||
settings/settings_advanced.h
|
||||
settings/settings_blocked_peers.cpp
|
||||
@@ -1437,6 +1475,8 @@ PRIVATE
|
||||
settings/settings_privacy_security.h
|
||||
settings/settings_scale_preview.cpp
|
||||
settings/settings_scale_preview.h
|
||||
settings/settings_shortcuts.cpp
|
||||
settings/settings_shortcuts.h
|
||||
settings/settings_type.h
|
||||
settings/settings_websites.cpp
|
||||
settings/settings_websites.h
|
||||
@@ -1537,6 +1577,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
|
||||
@@ -1548,8 +1592,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
|
||||
|
||||
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/verified_bg.webp
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Telegram/Resources/art/verified_fg.webp
Normal file
|
After Width: | Height: | Size: 500 B |
@@ -1,6 +1,7 @@
|
||||
// This is a list of your own shortcuts for Telegram Desktop
|
||||
// You can see full list of commands in the 'shortcuts-default.json' file
|
||||
// Place a null value instead of a command string to switch the shortcut off
|
||||
// You can also edit them in Settings > Chat Settings > Keyboard Shortcuts.
|
||||
|
||||
[
|
||||
// {
|
||||
|
||||
BIN
Telegram/Resources/icons/chat/markup_webview.png
Normal file
|
After Width: | Height: | Size: 663 B |
BIN
Telegram/Resources/icons/chat/markup_webview@2x.png
Normal file
|
After Width: | Height: | Size: 761 B |
BIN
Telegram/Resources/icons/chat/markup_webview@3x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/chat/mini_info_alert.png
Normal file
|
After Width: | Height: | Size: 311 B |
BIN
Telegram/Resources/icons/chat/mini_info_alert@2x.png
Normal file
|
After Width: | Height: | Size: 578 B |
BIN
Telegram/Resources/icons/chat/mini_info_alert@3x.png
Normal file
|
After Width: | Height: | Size: 829 B |
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/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/nft_takeoff.png
Normal file
|
After Width: | Height: | Size: 730 B |
BIN
Telegram/Resources/icons/menu/nft_takeoff@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/menu/nft_takeoff@3x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Telegram/Resources/icons/menu/nft_wear.png
Normal file
|
After Width: | Height: | Size: 716 B |
BIN
Telegram/Resources/icons/menu/nft_wear@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/menu/nft_wear@3x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Telegram/Resources/icons/menu/shortcut.png
Normal file
|
After Width: | Height: | Size: 447 B |
BIN
Telegram/Resources/icons/menu/shortcut@2x.png
Normal file
|
After Width: | Height: | Size: 671 B |
BIN
Telegram/Resources/icons/menu/shortcut@3x.png
Normal file
|
After Width: | Height: | Size: 1004 B |
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/menu/tradable.png
Normal file
|
After Width: | Height: | Size: 811 B |
BIN
Telegram/Resources/icons/menu/tradable@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/menu/tradable@3x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram/Resources/icons/menu/unique.png
Normal file
|
After Width: | Height: | Size: 868 B |
BIN
Telegram/Resources/icons/menu/unique@2x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/menu/unique@3x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Telegram/Resources/icons/payments/premium_emoji.png
Normal file
|
After Width: | Height: | Size: 370 B |
BIN
Telegram/Resources/icons/payments/premium_emoji@2x.png
Normal file
|
After Width: | Height: | Size: 712 B |
BIN
Telegram/Resources/icons/payments/premium_emoji@3x.png
Normal file
|
After Width: | Height: | Size: 926 B |
|
After Width: | Height: | Size: 654 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -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,6 +4,7 @@
|
||||
<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>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="5.7.2.0" />
|
||||
Version="5.12.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,7,2,0
|
||||
PRODUCTVERSION 5,7,2,0
|
||||
FILEVERSION 5,12,2,0
|
||||
PRODUCTVERSION 5,12,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.7.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "FileVersion", "5.12.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "5.7.2.0"
|
||||
VALUE "ProductVersion", "5.12.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,7,2,0
|
||||
PRODUCTVERSION 5,7,2,0
|
||||
FILEVERSION 5,12,2,0
|
||||
PRODUCTVERSION 5,12,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.7.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "FileVersion", "5.12.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "5.7.2.0"
|
||||
VALUE "ProductVersion", "5.12.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -217,7 +217,11 @@ void Authorizations::toggleCallsDisabled(uint64 hash, bool disabled) {
|
||||
MTP_bool(disabled)
|
||||
)).done([=] {
|
||||
_toggleCallsDisabledRequests.remove(hash);
|
||||
}).fail([=] {
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
LOG(("API Error: toggle calls %1. Hash: %2. %3.")
|
||||
.arg(disabled ? u"disabled"_q : u"enabled"_q)
|
||||
.arg(hash)
|
||||
.arg(error.type()));
|
||||
_toggleCallsDisabledRequests.remove(hash);
|
||||
}).send();
|
||||
_toggleCallsDisabledRequests.emplace(hash, id);
|
||||
|
||||
@@ -7,11 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_chat_filters.h"
|
||||
|
||||
#include "api/api_text_entities.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 "core/ui_integration.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
@@ -23,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/controls/filter_link_header.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/vertical_list.h"
|
||||
@@ -47,7 +52,7 @@ public:
|
||||
ToggleChatsController(
|
||||
not_null<Window::SessionController*> window,
|
||||
ToggleAction action,
|
||||
const QString &title,
|
||||
Data::ChatFilterTitle title,
|
||||
std::vector<not_null<PeerData*>> chats,
|
||||
std::vector<not_null<PeerData*>> additional);
|
||||
|
||||
@@ -73,7 +78,6 @@ private:
|
||||
Ui::RpWidget *_addedBottomWidget = nullptr;
|
||||
|
||||
ToggleAction _action = ToggleAction::Adding;
|
||||
QString _filterTitle;
|
||||
base::flat_set<not_null<PeerData*>> _checkable;
|
||||
std::vector<not_null<PeerData*>> _chats;
|
||||
std::vector<not_null<PeerData*>> _additional;
|
||||
@@ -104,9 +108,9 @@ private:
|
||||
|
||||
[[nodiscard]] TextWithEntities AboutText(
|
||||
Ui::FilterLinkHeaderType type,
|
||||
const QString &title) {
|
||||
TextWithEntities title) {
|
||||
using Type = Ui::FilterLinkHeaderType;
|
||||
auto boldTitle = Ui::Text::Bold(title);
|
||||
auto boldTitle = Ui::Text::Wrapped(title, EntityType::Bold);
|
||||
return (type == Type::AddingFilter)
|
||||
? tr::lng_filters_by_link_sure(
|
||||
tr::now,
|
||||
@@ -136,22 +140,29 @@ void InitFilterLinkHeader(
|
||||
not_null<PeerListBox*> box,
|
||||
Fn<void(int minHeight, int maxHeight, int addedTopHeight)> adjust,
|
||||
Ui::FilterLinkHeaderType type,
|
||||
const QString &title,
|
||||
const QString &iconEmoji,
|
||||
rpl::producer<int> count) {
|
||||
Data::ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
rpl::producer<int> count,
|
||||
bool horizontalFilters) {
|
||||
const auto icon = Ui::LookupFilterIcon(
|
||||
Ui::LookupFilterIconByEmoji(
|
||||
iconEmoji
|
||||
).value_or(Ui::FilterIcon::Custom)).active;
|
||||
const auto isStatic = title.isStatic;
|
||||
auto header = Ui::MakeFilterLinkHeader(box, {
|
||||
.type = type,
|
||||
.title = TitleText(type)(tr::now),
|
||||
.about = AboutText(type, title),
|
||||
.folderTitle = title,
|
||||
.about = AboutText(type, title.text),
|
||||
.aboutContext = Core::TextContext({
|
||||
.session = &box->peerListUiShow()->session(),
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
}),
|
||||
.folderTitle = title.text,
|
||||
.folderIcon = icon,
|
||||
.badge = (type == Ui::FilterLinkHeaderType::AddingChats
|
||||
? std::move(count)
|
||||
: rpl::single(0)),
|
||||
.horizontalFilters = horizontalFilters,
|
||||
});
|
||||
const auto widget = header.widget;
|
||||
widget->resizeToWidth(st::boxWideWidth);
|
||||
@@ -244,12 +255,11 @@ void ImportInvite(
|
||||
ToggleChatsController::ToggleChatsController(
|
||||
not_null<Window::SessionController*> window,
|
||||
ToggleAction action,
|
||||
const QString &title,
|
||||
Data::ChatFilterTitle title,
|
||||
std::vector<not_null<PeerData*>> chats,
|
||||
std::vector<not_null<PeerData*>> additional)
|
||||
: _window(window)
|
||||
, _action(action)
|
||||
, _filterTitle(title)
|
||||
, _chats(std::move(chats))
|
||||
, _additional(std::move(additional)) {
|
||||
setStyleOverrides(&st::filterLinkChatsList);
|
||||
@@ -525,7 +535,7 @@ void ShowImportError(
|
||||
|
||||
void ShowImportToast(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &title,
|
||||
Data::ChatFilterTitle title,
|
||||
Ui::FilterLinkHeaderType type,
|
||||
int added) {
|
||||
const auto strong = weak.get();
|
||||
@@ -536,22 +546,51 @@ void ShowImportToast(
|
||||
const auto phrase = created
|
||||
? tr::lng_filters_added_title
|
||||
: tr::lng_filters_updated_title;
|
||||
auto text = Ui::Text::Bold(phrase(tr::now, lt_folder, title));
|
||||
auto text = Ui::Text::Wrapped(
|
||||
phrase(tr::now, lt_folder, title.text, Ui::Text::WithEntities),
|
||||
EntityType::Bold);
|
||||
if (added > 0) {
|
||||
const auto phrase = created
|
||||
? tr::lng_filters_added_also
|
||||
: tr::lng_filters_updated_also;
|
||||
text.append('\n').append(phrase(tr::now, lt_count, added));
|
||||
}
|
||||
strong->showToast(std::move(text));
|
||||
const auto isStatic = title.isStatic;
|
||||
strong->showToast({
|
||||
.text = std::move(text),
|
||||
.textContext = Core::TextContext({
|
||||
.session = &strong->session(),
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
FilterId filterId,
|
||||
const QString &title,
|
||||
const QString &iconEmoji,
|
||||
Data::ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
std::vector<not_null<PeerData*>> peers,
|
||||
std::vector<not_null<PeerData*>> already) {
|
||||
const auto strong = weak.get();
|
||||
@@ -570,6 +609,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,14 +627,19 @@ 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());
|
||||
|
||||
const auto isStatic = title.isStatic;
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
type,
|
||||
title,
|
||||
title.text,
|
||||
Core::TextContext({
|
||||
.session = &strong->session(),
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
}),
|
||||
std::move(badge));
|
||||
|
||||
const auto button = owned.data();
|
||||
@@ -608,6 +654,8 @@ void ProcessFilterInvite(
|
||||
|
||||
box->addButton(std::move(owned));
|
||||
|
||||
HandleEnterInBox(box);
|
||||
|
||||
struct State {
|
||||
bool importing = false;
|
||||
};
|
||||
@@ -692,7 +740,7 @@ void CheckFilterInvite(
|
||||
if (!strong) {
|
||||
return;
|
||||
}
|
||||
auto title = QString();
|
||||
auto title = Data::ChatFilterTitle();
|
||||
auto iconEmoji = QString();
|
||||
auto filterId = FilterId();
|
||||
auto peers = std::vector<not_null<PeerData*>>();
|
||||
@@ -711,7 +759,8 @@ void CheckFilterInvite(
|
||||
return result;
|
||||
};
|
||||
result.match([&](const MTPDchatlists_chatlistInvite &data) {
|
||||
title = qs(data.vtitle());
|
||||
title.text = ParseTextWithEntities(session, data.vtitle());
|
||||
title.isStatic = data.is_title_noanimate();
|
||||
iconEmoji = data.vemoticon().value_or_empty();
|
||||
peers = parseList(data.vpeers());
|
||||
}, [&](const MTPDchatlists_chatlistInviteAlready &data) {
|
||||
@@ -776,8 +825,8 @@ void ProcessFilterUpdate(
|
||||
|
||||
void ProcessFilterRemove(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &title,
|
||||
const QString &iconEmoji,
|
||||
Data::ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
std::vector<not_null<PeerData*>> all,
|
||||
std::vector<not_null<PeerData*>> suggest,
|
||||
Fn<void(std::vector<not_null<PeerData*>>)> done) {
|
||||
@@ -796,6 +845,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,12 +858,17 @@ 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);
|
||||
|
||||
const auto isStatic = title.isStatic;
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
type,
|
||||
title,
|
||||
title.text,
|
||||
Core::TextContext({
|
||||
.session = &strong->session(),
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
}),
|
||||
std::move(badge));
|
||||
|
||||
const auto button = owned.data();
|
||||
@@ -827,6 +883,8 @@ void ProcessFilterRemove(
|
||||
|
||||
box->addButton(std::move(owned));
|
||||
|
||||
HandleEnterInBox(box);
|
||||
|
||||
raw->selectedValue(
|
||||
) | rpl::start_with_next([=](
|
||||
base::flat_set<not_null<PeerData*>> &&peers) {
|
||||
|
||||
@@ -17,6 +17,7 @@ class SessionController;
|
||||
|
||||
namespace Data {
|
||||
class ChatFilter;
|
||||
struct ChatFilterTitle;
|
||||
} // namespace Data
|
||||
|
||||
namespace Api {
|
||||
@@ -36,8 +37,8 @@ void ProcessFilterUpdate(
|
||||
|
||||
void ProcessFilterRemove(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &title,
|
||||
const QString &iconEmoji,
|
||||
Data::ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
std::vector<not_null<PeerData*>> all,
|
||||
std::vector<not_null<PeerData*>> suggest,
|
||||
Fn<void(std::vector<not_null<PeerData*>>)> done);
|
||||
|
||||
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"
|
||||
@@ -206,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>>(
|
||||
@@ -295,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) {
|
||||
|
||||
@@ -211,11 +211,10 @@ void ApplyBotsList(
|
||||
Data::PeerUpdate::Flag::FullInfo);
|
||||
}
|
||||
|
||||
[[nodiscard]] ChatParticipants::Channels ParseSimilar(
|
||||
[[nodiscard]] ChatParticipants::Peers ParseSimilarChannels(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPmessages_Chats &chats) {
|
||||
auto result = ChatParticipants::Channels();
|
||||
std::vector<not_null<ChannelData*>>();
|
||||
auto result = ChatParticipants::Peers();
|
||||
chats.match([&](const auto &data) {
|
||||
const auto &list = data.vchats().v;
|
||||
result.list.reserve(list.size());
|
||||
@@ -234,10 +233,29 @@ void ApplyBotsList(
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] ChatParticipants::Channels ParseSimilar(
|
||||
[[nodiscard]] ChatParticipants::Peers ParseSimilarChannels(
|
||||
not_null<ChannelData*> channel,
|
||||
const MTPmessages_Chats &chats) {
|
||||
return ParseSimilar(&channel->session(), chats);
|
||||
return ParseSimilarChannels(&channel->session(), chats);
|
||||
}
|
||||
|
||||
[[nodiscard]] ChatParticipants::Peers ParseSimilarBots(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPusers_Users &users) {
|
||||
auto result = ChatParticipants::Peers();
|
||||
users.match([&](const auto &data) {
|
||||
const auto &list = data.vusers().v;
|
||||
result.list.reserve(list.size());
|
||||
for (const auto &user : list) {
|
||||
result.list.push_back(session->data().processUser(user));
|
||||
}
|
||||
if constexpr (MTPDusers_usersSlice::Is<decltype(data)>()) {
|
||||
if (session->premiumPossible()) {
|
||||
result.more = data.vcount().v - data.vusers().v.size();
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -782,52 +800,65 @@ void ChatParticipants::unblock(
|
||||
_kickRequests.emplace(kick, requestId);
|
||||
}
|
||||
|
||||
void ChatParticipants::loadSimilarChannels(not_null<ChannelData*> channel) {
|
||||
if (!channel->isBroadcast()) {
|
||||
return;
|
||||
} else if (const auto i = _similar.find(channel); i != end(_similar)) {
|
||||
void ChatParticipants::loadSimilarPeers(not_null<PeerData*> peer) {
|
||||
if (const auto i = _similar.find(peer); i != end(_similar)) {
|
||||
if (i->second.requestId
|
||||
|| !i->second.channels.more
|
||||
|| !channel->session().premium()) {
|
||||
|| !i->second.peers.more
|
||||
|| !peer->session().premium()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
using Flag = MTPchannels_GetChannelRecommendations::Flag;
|
||||
_similar[channel].requestId = _api.request(
|
||||
MTPchannels_GetChannelRecommendations(
|
||||
MTP_flags(Flag::f_channel),
|
||||
channel->inputChannel)
|
||||
).done([=](const MTPmessages_Chats &result) {
|
||||
auto &similar = _similar[channel];
|
||||
similar.requestId = 0;
|
||||
auto parsed = ParseSimilar(channel, result);
|
||||
if (similar.channels == parsed) {
|
||||
return;
|
||||
}
|
||||
similar.channels = std::move(parsed);
|
||||
if (const auto history = channel->owner().historyLoaded(channel)) {
|
||||
if (const auto item = history->joinedMessageInstance()) {
|
||||
history->owner().requestItemResize(item);
|
||||
if (const auto channel = peer->asBroadcast()) {
|
||||
using Flag = MTPchannels_GetChannelRecommendations::Flag;
|
||||
_similar[peer].requestId = _api.request(
|
||||
MTPchannels_GetChannelRecommendations(
|
||||
MTP_flags(Flag::f_channel),
|
||||
channel->inputChannel)
|
||||
).done([=](const MTPmessages_Chats &result) {
|
||||
auto &similar = _similar[channel];
|
||||
similar.requestId = 0;
|
||||
auto parsed = ParseSimilarChannels(channel, result);
|
||||
if (similar.peers == parsed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_similarLoaded.fire_copy(channel);
|
||||
}).send();
|
||||
similar.peers = std::move(parsed);
|
||||
if (const auto history = channel->owner().historyLoaded(channel)) {
|
||||
if (const auto item = history->joinedMessageInstance()) {
|
||||
history->owner().requestItemResize(item);
|
||||
}
|
||||
}
|
||||
_similarLoaded.fire_copy(channel);
|
||||
}).send();
|
||||
} else if (const auto bot = peer->asBot()) {
|
||||
_similar[peer].requestId = _api.request(
|
||||
MTPbots_GetBotRecommendations(bot->inputUser)
|
||||
).done([=](const MTPusers_Users &result) {
|
||||
auto &similar = _similar[peer];
|
||||
similar.requestId = 0;
|
||||
auto parsed = ParseSimilarBots(&peer->session(), result);
|
||||
if (similar.peers == parsed) {
|
||||
return;
|
||||
}
|
||||
similar.peers = std::move(parsed);
|
||||
_similarLoaded.fire_copy(peer);
|
||||
}).send();
|
||||
}
|
||||
}
|
||||
|
||||
auto ChatParticipants::similar(not_null<ChannelData*> channel)
|
||||
-> const Channels & {
|
||||
const auto i = channel->isBroadcast()
|
||||
? _similar.find(channel)
|
||||
auto ChatParticipants::similar(not_null<PeerData*> peer)
|
||||
-> const Peers & {
|
||||
const auto i = (peer->isBroadcast() || peer->isBot())
|
||||
? _similar.find(peer)
|
||||
: end(_similar);
|
||||
if (i != end(_similar)) {
|
||||
return i->second.channels;
|
||||
return i->second.peers;
|
||||
}
|
||||
static const auto empty = Channels();
|
||||
static const auto empty = Peers();
|
||||
return empty;
|
||||
}
|
||||
|
||||
auto ChatParticipants::similarLoaded() const
|
||||
-> rpl::producer<not_null<ChannelData*>> {
|
||||
-> rpl::producer<not_null<PeerData*>> {
|
||||
return _similarLoaded.events();
|
||||
}
|
||||
|
||||
@@ -841,15 +872,15 @@ void ChatParticipants::loadRecommendations() {
|
||||
MTP_inputChannelEmpty())
|
||||
).done([=](const MTPmessages_Chats &result) {
|
||||
_recommendations.requestId = 0;
|
||||
auto parsed = ParseSimilar(_session, result);
|
||||
_recommendations.channels = std::move(parsed);
|
||||
_recommendations.channels.more = 0;
|
||||
auto parsed = ParseSimilarChannels(_session, result);
|
||||
_recommendations.peers = std::move(parsed);
|
||||
_recommendations.peers.more = 0;
|
||||
_recommendationsLoaded = true;
|
||||
}).send();
|
||||
}
|
||||
|
||||
const ChatParticipants::Channels &ChatParticipants::recommendations() const {
|
||||
return _recommendations.channels;
|
||||
const ChatParticipants::Peers &ChatParticipants::recommendations() const {
|
||||
return _recommendations.peers;
|
||||
}
|
||||
|
||||
rpl::producer<> ChatParticipants::recommendationsLoaded() const {
|
||||
|
||||
@@ -138,27 +138,27 @@ public:
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> participant);
|
||||
|
||||
void loadSimilarChannels(not_null<ChannelData*> channel);
|
||||
void loadSimilarPeers(not_null<PeerData*> peer);
|
||||
|
||||
struct Channels {
|
||||
std::vector<not_null<ChannelData*>> list;
|
||||
struct Peers {
|
||||
std::vector<not_null<PeerData*>> list;
|
||||
int more = 0;
|
||||
|
||||
friend inline bool operator==(
|
||||
const Channels &,
|
||||
const Channels &) = default;
|
||||
const Peers &,
|
||||
const Peers &) = default;
|
||||
};
|
||||
[[nodiscard]] const Channels &similar(not_null<ChannelData*> channel);
|
||||
[[nodiscard]] const Peers &similar(not_null<PeerData*> peer);
|
||||
[[nodiscard]] auto similarLoaded() const
|
||||
-> rpl::producer<not_null<ChannelData*>>;
|
||||
-> rpl::producer<not_null<PeerData*>>;
|
||||
|
||||
void loadRecommendations();
|
||||
[[nodiscard]] const Channels &recommendations() const;
|
||||
[[nodiscard]] const Peers &recommendations() const;
|
||||
[[nodiscard]] rpl::producer<> recommendationsLoaded() const;
|
||||
|
||||
private:
|
||||
struct SimilarChannels {
|
||||
Channels channels;
|
||||
struct SimilarPeers {
|
||||
Peers peers;
|
||||
mtpRequestId requestId = 0;
|
||||
};
|
||||
|
||||
@@ -186,10 +186,10 @@ private:
|
||||
not_null<PeerData*>>;
|
||||
base::flat_map<KickRequest, mtpRequestId> _kickRequests;
|
||||
|
||||
base::flat_map<not_null<ChannelData*>, SimilarChannels> _similar;
|
||||
rpl::event_stream<not_null<ChannelData*>> _similarLoaded;
|
||||
base::flat_map<not_null<PeerData*>, SimilarPeers> _similar;
|
||||
rpl::event_stream<not_null<PeerData*>> _similarLoaded;
|
||||
|
||||
SimilarChannels _recommendations;
|
||||
SimilarPeers _recommendations;
|
||||
rpl::variable<bool> _recommendationsLoaded = false;
|
||||
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ struct SendOptions {
|
||||
TimeId scheduled = 0;
|
||||
BusinessShortcutId shortcutId = 0;
|
||||
EffectId effectId = 0;
|
||||
int starsApproved = 0;
|
||||
bool silent = false;
|
||||
bool handleSupportSwitch = false;
|
||||
bool invertCaption = false;
|
||||
@@ -74,6 +75,7 @@ struct MessageToSend {
|
||||
struct RemoteFileInfo {
|
||||
MTPInputFile file;
|
||||
std::optional<MTPInputFile> thumb;
|
||||
std::optional<MTPInputPhoto> videoCover;
|
||||
std::vector<MTPInputDocument> attachedStickers;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_credits.h"
|
||||
|
||||
#include "api/api_premium.h"
|
||||
#include "api/api_statistics_data_deserialize.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "apiwrap.h"
|
||||
@@ -73,9 +74,33 @@ constexpr auto kTransactionsLimit = 100;
|
||||
return PeerId(0);
|
||||
}).value;
|
||||
const auto stargift = tl.data().vstargift();
|
||||
const auto nonUniqueGift = stargift
|
||||
? stargift->match([&](const MTPDstarGift &data) {
|
||||
return &data;
|
||||
}, [](const auto &) { return (const MTPDstarGift*)nullptr; })
|
||||
: nullptr;
|
||||
const auto reaction = tl.data().is_reaction();
|
||||
const auto incoming = (int64(tl.data().vstars().v) >= 0);
|
||||
const auto saveActorId = (reaction || !extended.empty()) && incoming;
|
||||
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 paidMessagesCount
|
||||
= tl.data().vpaid_messages().value_or_empty();
|
||||
const auto premiumMonthsForStars
|
||||
= tl.data().vpremium_gift_months().value_or_empty();
|
||||
const auto saveActorId = (reaction
|
||||
|| !extended.empty()
|
||||
|| paidMessagesCount) && incoming;
|
||||
const auto parsedGift = stargift
|
||||
? FromTL(&peer->session(), *stargift)
|
||||
: std::optional<Data::StarGift>();
|
||||
const auto giftStickerId = parsedGift ? parsedGift->document->id : 0;
|
||||
return Data::CreditsHistoryEntry{
|
||||
.id = qs(tl.data().vid()),
|
||||
.title = qs(tl.data().vtitle().value_or_empty()),
|
||||
@@ -83,15 +108,17 @@ 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 = saveActorId ? peer->id.value : barePeerId,
|
||||
.bareGiveawayMsgId = uint64(
|
||||
tl.data().vgiveaway_post_id().value_or_empty()),
|
||||
.bareGiftStickerId = (stargift
|
||||
? owner->processDocument(stargift->data().vsticker())->id
|
||||
: 0),
|
||||
.bareGiftStickerId = giftStickerId,
|
||||
.bareActorId = saveActorId ? barePeerId : uint64(0),
|
||||
.uniqueGift = parsedGift ? parsedGift->unique : nullptr,
|
||||
.starrefAmount = paidMessagesCount ? StarsAmount() : starrefAmount,
|
||||
.starrefCommission = paidMessagesCount ? 0 : starrefCommission,
|
||||
.starrefRecipientId = paidMessagesCount ? 0 : starrefBarePeerId,
|
||||
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Peer;
|
||||
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
|
||||
@@ -117,11 +144,19 @@ constexpr auto kTransactionsLimit = 100;
|
||||
? base::unixtime::parse(tl.data().vtransaction_date()->v)
|
||||
: QDateTime(),
|
||||
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
|
||||
.convertStars = int(stargift
|
||||
? stargift->data().vconvert_stars().v
|
||||
.paidMessagesCount = paidMessagesCount,
|
||||
.paidMessagesAmount = (paidMessagesCount
|
||||
? starrefAmount
|
||||
: StarsAmount()),
|
||||
.paidMessagesCommission = paidMessagesCount ? starrefCommission : 0,
|
||||
.starsConverted = int(nonUniqueGift
|
||||
? nonUniqueGift->vconvert_stars().v
|
||||
: 0),
|
||||
.premiumMonthsForStars = premiumMonthsForStars,
|
||||
.floodSkip = int(tl.data().vfloodskip_number().value_or(0)),
|
||||
.converted = stargift && incoming,
|
||||
.stargift = stargift.has_value(),
|
||||
.giftUpgraded = tl.data().is_stargift_upgrade(),
|
||||
.reaction = tl.data().is_reaction(),
|
||||
.refunded = tl.data().is_refund(),
|
||||
.pending = tl.data().is_pending(),
|
||||
@@ -132,17 +167,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(),
|
||||
};
|
||||
@@ -165,16 +209,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()),
|
||||
@@ -257,8 +302,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));
|
||||
}
|
||||
@@ -337,7 +382,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());
|
||||
@@ -369,12 +416,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()
|
||||
@@ -461,4 +509,28 @@ 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();
|
||||
}
|
||||
|
||||
MTPInputSavedStarGift InputSavedStarGiftId(const Data::SavedStarGiftId &id) {
|
||||
return id.isUser()
|
||||
? MTP_inputSavedStarGiftUser(MTP_int(id.userMessageId().bare))
|
||||
: MTP_inputSavedStarGiftChat(
|
||||
id.chat()->input,
|
||||
MTP_long(id.chatSavedId()));
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_credits_earn.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Data {
|
||||
class SavedStarGiftId;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
@@ -109,4 +113,14 @@ 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);
|
||||
|
||||
[[nodiscard]] MTPInputSavedStarGift InputSavedStarGiftId(
|
||||
const Data::SavedStarGiftId &id);
|
||||
|
||||
} // 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;
|
||||
|
||||
@@ -276,14 +276,22 @@ mtpRequestId EditTextMessage(
|
||||
takeFileReference = [=] { return photo->fileReference(); };
|
||||
} else if (const auto document = media->document()) {
|
||||
using Flag = MTPDinputMediaDocument::Flag;
|
||||
const auto videoCover = media->videoCover();
|
||||
const auto videoTimestamp = media->videoTimestamp();
|
||||
const auto flags = Flag()
|
||||
| (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
|
||||
| (spoilered ? Flag::f_spoiler : Flag());
|
||||
| (spoilered ? Flag::f_spoiler : Flag())
|
||||
| (videoTimestamp ? Flag::f_video_timestamp : Flag())
|
||||
| (videoCover ? Flag::f_video_cover : Flag());
|
||||
takeInputMedia = [=] {
|
||||
return MTP_inputMediaDocument(
|
||||
MTP_flags(flags),
|
||||
document->mtpInput(),
|
||||
(videoCover
|
||||
? videoCover->mtpInput()
|
||||
: MTPInputPhoto()),
|
||||
MTP_int(media->ttlSeconds()),
|
||||
MTP_int(videoTimestamp),
|
||||
MTPstring()); // query
|
||||
};
|
||||
takeFileReference = [=] { return document->fileReference(); };
|
||||
|
||||
@@ -13,6 +13,32 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Api {
|
||||
|
||||
PeerId ParsePaidReactionShownPeer(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPPaidReactionPrivacy &value) {
|
||||
return value.match([&](const MTPDpaidReactionPrivacyDefault &) {
|
||||
return session->userPeerId();
|
||||
}, [](const MTPDpaidReactionPrivacyAnonymous &) {
|
||||
return PeerId();
|
||||
}, [&](const MTPDpaidReactionPrivacyPeer &data) {
|
||||
return data.vpeer().match([&](const MTPDinputPeerSelf &) {
|
||||
return session->userPeerId();
|
||||
}, [](const MTPDinputPeerUser &data) {
|
||||
return peerFromUser(data.vuser_id());
|
||||
}, [](const MTPDinputPeerChat &data) {
|
||||
return peerFromChat(data.vchat_id());
|
||||
}, [](const MTPDinputPeerChannel &data) {
|
||||
return peerFromChannel(data.vchannel_id());
|
||||
}, [](const MTPDinputPeerUserFromMessage &data) -> PeerId {
|
||||
Unexpected("From message peer in ParsePaidReactionShownPeer.");
|
||||
}, [](const MTPDinputPeerChannelFromMessage &data) -> PeerId {
|
||||
Unexpected("From message peer in ParsePaidReactionShownPeer.");
|
||||
}, [](const MTPDinputPeerEmpty &) -> PeerId {
|
||||
Unexpected("Empty peer in ParsePaidReactionShownPeer.");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
GlobalPrivacy::GlobalPrivacy(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance()) {
|
||||
@@ -88,7 +114,8 @@ void GlobalPrivacy::updateHideReadTime(bool hide) {
|
||||
archiveAndMuteCurrent(),
|
||||
unarchiveOnNewMessageCurrent(),
|
||||
hide,
|
||||
newRequirePremiumCurrent());
|
||||
newRequirePremiumCurrent(),
|
||||
newChargeStarsCurrent());
|
||||
}
|
||||
|
||||
bool GlobalPrivacy::hideReadTimeCurrent() const {
|
||||
@@ -99,14 +126,6 @@ rpl::producer<bool> GlobalPrivacy::hideReadTime() const {
|
||||
return _hideReadTime.value();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updateNewRequirePremium(bool value) {
|
||||
update(
|
||||
archiveAndMuteCurrent(),
|
||||
unarchiveOnNewMessageCurrent(),
|
||||
hideReadTimeCurrent(),
|
||||
value);
|
||||
}
|
||||
|
||||
bool GlobalPrivacy::newRequirePremiumCurrent() const {
|
||||
return _newRequirePremium.current();
|
||||
}
|
||||
@@ -115,27 +134,46 @@ rpl::producer<bool> GlobalPrivacy::newRequirePremium() const {
|
||||
return _newRequirePremium.value();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::loadPaidReactionAnonymous() {
|
||||
if (_paidReactionAnonymousLoaded) {
|
||||
int GlobalPrivacy::newChargeStarsCurrent() const {
|
||||
return _newChargeStars.current();
|
||||
}
|
||||
|
||||
rpl::producer<int> GlobalPrivacy::newChargeStars() const {
|
||||
return _newChargeStars.value();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updateMessagesPrivacy(
|
||||
bool requirePremium,
|
||||
int chargeStars) {
|
||||
update(
|
||||
archiveAndMuteCurrent(),
|
||||
unarchiveOnNewMessageCurrent(),
|
||||
hideReadTimeCurrent(),
|
||||
requirePremium,
|
||||
chargeStars);
|
||||
}
|
||||
|
||||
void GlobalPrivacy::loadPaidReactionShownPeer() {
|
||||
if (_paidReactionShownPeerLoaded) {
|
||||
return;
|
||||
}
|
||||
_paidReactionAnonymousLoaded = true;
|
||||
_paidReactionShownPeerLoaded = true;
|
||||
_api.request(MTPmessages_GetPaidReactionPrivacy(
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_session->api().applyUpdates(result);
|
||||
}).send();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updatePaidReactionAnonymous(bool value) {
|
||||
_paidReactionAnonymous = value;
|
||||
void GlobalPrivacy::updatePaidReactionShownPeer(PeerId shownPeer) {
|
||||
_paidReactionShownPeer = shownPeer;
|
||||
}
|
||||
|
||||
bool GlobalPrivacy::paidReactionAnonymousCurrent() const {
|
||||
return _paidReactionAnonymous.current();
|
||||
PeerId GlobalPrivacy::paidReactionShownPeerCurrent() const {
|
||||
return _paidReactionShownPeer.current();
|
||||
}
|
||||
|
||||
rpl::producer<bool> GlobalPrivacy::paidReactionAnonymous() const {
|
||||
return _paidReactionAnonymous.value();
|
||||
rpl::producer<PeerId> GlobalPrivacy::paidReactionShownPeer() const {
|
||||
return _paidReactionShownPeer.value();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updateArchiveAndMute(bool value) {
|
||||
@@ -143,7 +181,8 @@ void GlobalPrivacy::updateArchiveAndMute(bool value) {
|
||||
value,
|
||||
unarchiveOnNewMessageCurrent(),
|
||||
hideReadTimeCurrent(),
|
||||
newRequirePremiumCurrent());
|
||||
newRequirePremiumCurrent(),
|
||||
newChargeStarsCurrent());
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updateUnarchiveOnNewMessage(
|
||||
@@ -152,14 +191,16 @@ void GlobalPrivacy::updateUnarchiveOnNewMessage(
|
||||
archiveAndMuteCurrent(),
|
||||
value,
|
||||
hideReadTimeCurrent(),
|
||||
newRequirePremiumCurrent());
|
||||
newRequirePremiumCurrent(),
|
||||
newChargeStarsCurrent());
|
||||
}
|
||||
|
||||
void GlobalPrivacy::update(
|
||||
bool archiveAndMute,
|
||||
UnarchiveOnNewMessage unarchiveOnNewMessage,
|
||||
bool hideReadTime,
|
||||
bool newRequirePremium) {
|
||||
bool newRequirePremium,
|
||||
int newChargeStars) {
|
||||
using Flag = MTPDglobalPrivacySettings::Flag;
|
||||
|
||||
_api.request(_requestId).cancel();
|
||||
@@ -178,35 +219,44 @@ void GlobalPrivacy::update(
|
||||
| (hideReadTime ? Flag::f_hide_read_marks : Flag())
|
||||
| ((newRequirePremium && newRequirePremiumAllowed)
|
||||
? Flag::f_new_noncontact_peers_require_premium
|
||||
: Flag());
|
||||
: Flag())
|
||||
| Flag::f_noncontact_peers_paid_stars;
|
||||
_requestId = _api.request(MTPaccount_SetGlobalPrivacySettings(
|
||||
MTP_globalPrivacySettings(MTP_flags(flags))
|
||||
MTP_globalPrivacySettings(
|
||||
MTP_flags(flags),
|
||||
MTP_long(newChargeStars))
|
||||
)).done([=](const MTPGlobalPrivacySettings &result) {
|
||||
_requestId = 0;
|
||||
apply(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
if (error.type() == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
|
||||
update(archiveAndMute, unarchiveOnNewMessage, hideReadTime, {});
|
||||
update(
|
||||
archiveAndMute,
|
||||
unarchiveOnNewMessage,
|
||||
hideReadTime,
|
||||
false,
|
||||
0);
|
||||
}
|
||||
}).send();
|
||||
_archiveAndMute = archiveAndMute;
|
||||
_unarchiveOnNewMessage = unarchiveOnNewMessage;
|
||||
_hideReadTime = hideReadTime;
|
||||
_newRequirePremium = newRequirePremium;
|
||||
_newChargeStars = newChargeStars;
|
||||
}
|
||||
|
||||
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
|
||||
data.match([&](const MTPDglobalPrivacySettings &data) {
|
||||
_archiveAndMute = data.is_archive_and_mute_new_noncontact_peers();
|
||||
_unarchiveOnNewMessage = data.is_keep_archived_unmuted()
|
||||
? UnarchiveOnNewMessage::None
|
||||
: data.is_keep_archived_folders()
|
||||
? UnarchiveOnNewMessage::NotInFoldersUnmuted
|
||||
: UnarchiveOnNewMessage::AnyUnmuted;
|
||||
_hideReadTime = data.is_hide_read_marks();
|
||||
_newRequirePremium = data.is_new_noncontact_peers_require_premium();
|
||||
});
|
||||
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &settings) {
|
||||
const auto &data = settings.data();
|
||||
_archiveAndMute = data.is_archive_and_mute_new_noncontact_peers();
|
||||
_unarchiveOnNewMessage = data.is_keep_archived_unmuted()
|
||||
? UnarchiveOnNewMessage::None
|
||||
: data.is_keep_archived_folders()
|
||||
? UnarchiveOnNewMessage::NotInFoldersUnmuted
|
||||
: UnarchiveOnNewMessage::AnyUnmuted;
|
||||
_hideReadTime = data.is_hide_read_marks();
|
||||
_newRequirePremium = data.is_new_noncontact_peers_require_premium();
|
||||
_newChargeStars = data.vnoncontact_peers_paid_stars().value_or_empty();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -23,6 +23,10 @@ enum class UnarchiveOnNewMessage {
|
||||
AnyUnmuted,
|
||||
};
|
||||
|
||||
[[nodiscard]] PeerId ParsePaidReactionShownPeer(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPPaidReactionPrivacy &value);
|
||||
|
||||
class GlobalPrivacy final {
|
||||
public:
|
||||
explicit GlobalPrivacy(not_null<ApiWrap*> api);
|
||||
@@ -45,23 +49,28 @@ public:
|
||||
[[nodiscard]] bool hideReadTimeCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> hideReadTime() const;
|
||||
|
||||
void updateNewRequirePremium(bool value);
|
||||
[[nodiscard]] bool newRequirePremiumCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> newRequirePremium() const;
|
||||
|
||||
void loadPaidReactionAnonymous();
|
||||
void updatePaidReactionAnonymous(bool value);
|
||||
[[nodiscard]] bool paidReactionAnonymousCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> paidReactionAnonymous() const;
|
||||
[[nodiscard]] int newChargeStarsCurrent() const;
|
||||
[[nodiscard]] rpl::producer<int> newChargeStars() const;
|
||||
|
||||
void updateMessagesPrivacy(bool requirePremium, int chargeStars);
|
||||
|
||||
void loadPaidReactionShownPeer();
|
||||
void updatePaidReactionShownPeer(PeerId shownPeer);
|
||||
[[nodiscard]] PeerId paidReactionShownPeerCurrent() const;
|
||||
[[nodiscard]] rpl::producer<PeerId> paidReactionShownPeer() const;
|
||||
|
||||
private:
|
||||
void apply(const MTPGlobalPrivacySettings &data);
|
||||
void apply(const MTPGlobalPrivacySettings &settings);
|
||||
|
||||
void update(
|
||||
bool archiveAndMute,
|
||||
UnarchiveOnNewMessage unarchiveOnNewMessage,
|
||||
bool hideReadTime,
|
||||
bool newRequirePremium);
|
||||
bool newRequirePremium,
|
||||
int newChargeStars);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
@@ -72,9 +81,10 @@ private:
|
||||
rpl::variable<bool> _showArchiveAndMute = false;
|
||||
rpl::variable<bool> _hideReadTime = false;
|
||||
rpl::variable<bool> _newRequirePremium = false;
|
||||
rpl::variable<bool> _paidReactionAnonymous = false;
|
||||
rpl::variable<int> _newChargeStars = 0;
|
||||
rpl::variable<PeerId> _paidReactionShownPeer = false;
|
||||
std::vector<Fn<void()>> _callbacks;
|
||||
bool _paidReactionAnonymousLoaded = false;
|
||||
bool _paidReactionShownPeerLoaded = false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -111,7 +111,8 @@ MTPInputMedia PrepareUploadedDocument(
|
||||
| (info.thumb ? Flag::f_thumb : Flag())
|
||||
| (item->groupId() ? Flag::f_nosound_video : Flag())
|
||||
| (info.attachedStickers.empty() ? Flag::f_stickers : Flag())
|
||||
| (ttlSeconds ? Flag::f_ttl_seconds : Flag());
|
||||
| (ttlSeconds ? Flag::f_ttl_seconds : Flag())
|
||||
| (info.videoCover ? Flag::f_video_cover : Flag());
|
||||
const auto document = item->media()->document();
|
||||
return MTP_inputMediaUploadedDocument(
|
||||
MTP_flags(flags),
|
||||
@@ -121,6 +122,8 @@ MTPInputMedia PrepareUploadedDocument(
|
||||
ComposeSendingDocumentAttributes(document),
|
||||
MTP_vector<MTPInputDocument>(
|
||||
ranges::to<QVector<MTPInputDocument>>(info.attachedStickers)),
|
||||
info.videoCover.value_or(MTPInputPhoto()),
|
||||
MTP_int(0), // video_timestamp
|
||||
MTP_int(ttlSeconds));
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ void MessagesSearch::searchRequest() {
|
||||
_requestId = _history->session().api().request(MTPmessages_Search(
|
||||
MTP_flags((fromPeer ? Flag::f_from_id : Flag())
|
||||
| (savedPeer ? Flag::f_saved_peer_id : Flag())
|
||||
| (_request.topMsgId ? Flag::f_top_msg_id : Flag())
|
||||
| (_request.tags.empty() ? Flag() : Flag::f_saved_reaction)),
|
||||
_history->peer->input,
|
||||
MTP_string(_request.query),
|
||||
@@ -111,7 +112,7 @@ void MessagesSearch::searchRequest() {
|
||||
MTP_vector_from_range(_request.tags | ranges::views::transform(
|
||||
Data::ReactionToMTP
|
||||
)),
|
||||
MTPint(), // top_msg_id
|
||||
MTP_int(_request.topMsgId), // top_msg_id
|
||||
MTP_inputMessagesFilterEmpty(),
|
||||
MTP_int(0), // min_date
|
||||
MTP_int(0), // max_date
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
QString query;
|
||||
PeerData *from = nullptr;
|
||||
std::vector<Data::ReactionId> tags;
|
||||
MsgId topMsgId;
|
||||
|
||||
friend inline bool operator==(
|
||||
const Request &,
|
||||
|
||||
@@ -64,6 +64,10 @@ MessagesSearchMerged::MessagesSearchMerged(not_null<History*> history)
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesSearchMerged::disableMigrated() {
|
||||
_migratedSearch = std::nullopt;
|
||||
}
|
||||
|
||||
void MessagesSearchMerged::addFound(const FoundMessages &data) {
|
||||
for (const auto &message : data.messages) {
|
||||
_concatedFound.messages.push_back(message);
|
||||
@@ -74,12 +78,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);
|
||||
|
||||
@@ -29,8 +29,10 @@ public:
|
||||
void clear();
|
||||
void search(const Request &search);
|
||||
void searchMore();
|
||||
void disableMigrated();
|
||||
|
||||
[[nodiscard]] const FoundMessages &messages() const;
|
||||
[[nodiscard]] const Request &request() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<> newFounds() const;
|
||||
[[nodiscard]] rpl::producer<> nextFounds() const;
|
||||
@@ -39,6 +41,7 @@ private:
|
||||
void addFound(const FoundMessages &data);
|
||||
|
||||
MessagesSearch _apiSearch;
|
||||
Request _request;
|
||||
|
||||
std::optional<MessagesSearch> _migratedSearch;
|
||||
FoundMessages _migratedFirstFound;
|
||||
|
||||
@@ -37,7 +37,7 @@ Polls::Polls(not_null<ApiWrap*> api)
|
||||
|
||||
void Polls::create(
|
||||
const PollData &data,
|
||||
const SendAction &action,
|
||||
SendAction action,
|
||||
Fn<void()> done,
|
||||
Fn<void()> fail) {
|
||||
_session->api().sendAction(action);
|
||||
@@ -59,6 +59,9 @@ void Polls::create(
|
||||
history->startSavingCloudDraft(topicRootId);
|
||||
}
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
const auto starsPaid = std::min(
|
||||
peer->starsPerMessageChecked(),
|
||||
action.options.starsApproved);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
@@ -71,6 +74,10 @@ void Polls::create(
|
||||
if (action.options.effectId) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
}
|
||||
if (starsPaid) {
|
||||
action.options.starsApproved -= starsPaid;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
|
||||
}
|
||||
const auto sendAs = action.options.sendAs;
|
||||
if (sendAs) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
@@ -93,7 +100,8 @@ void Polls::create(
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(_session, action.options.shortcutId),
|
||||
MTP_long(action.options.effectId)
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
|
||||
void create(
|
||||
const PollData &data,
|
||||
const SendAction &action,
|
||||
SendAction action,
|
||||
Fn<void()> done,
|
||||
Fn<void()> fail);
|
||||
void sendVotes(
|
||||
|
||||
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_text_entities.h"
|
||||
#include "apiwrap.h"
|
||||
#include "base/random.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_values.h"
|
||||
@@ -377,15 +378,15 @@ const Data::PremiumSubscriptionOptions &Premium::subscriptionOptions() const {
|
||||
return _subscriptionOptions;
|
||||
}
|
||||
|
||||
rpl::producer<> Premium::somePremiumRequiredResolved() const {
|
||||
return _somePremiumRequiredResolved.events();
|
||||
rpl::producer<> Premium::someMessageMoneyRestrictionsResolved() const {
|
||||
return _someMessageMoneyRestrictionsResolved.events();
|
||||
}
|
||||
|
||||
void Premium::resolvePremiumRequired(not_null<UserData*> user) {
|
||||
_resolvePremiumRequiredUsers.emplace(user);
|
||||
if (!_premiumRequiredRequestScheduled
|
||||
&& _resolvePremiumRequestedUsers.empty()) {
|
||||
_premiumRequiredRequestScheduled = true;
|
||||
void Premium::resolveMessageMoneyRestrictions(not_null<UserData*> user) {
|
||||
_resolveMessageMoneyRequiredUsers.emplace(user);
|
||||
if (!_messageMoneyRequestScheduled
|
||||
&& _resolveMessageMoneyRequestedUsers.empty()) {
|
||||
_messageMoneyRequestScheduled = true;
|
||||
crl::on_main(_session, [=] {
|
||||
requestPremiumRequiredSlice();
|
||||
});
|
||||
@@ -393,50 +394,65 @@ void Premium::resolvePremiumRequired(not_null<UserData*> user) {
|
||||
}
|
||||
|
||||
void Premium::requestPremiumRequiredSlice() {
|
||||
_premiumRequiredRequestScheduled = false;
|
||||
if (!_resolvePremiumRequestedUsers.empty()
|
||||
|| _resolvePremiumRequiredUsers.empty()) {
|
||||
_messageMoneyRequestScheduled = false;
|
||||
if (!_resolveMessageMoneyRequestedUsers.empty()
|
||||
|| _resolveMessageMoneyRequiredUsers.empty()) {
|
||||
return;
|
||||
}
|
||||
constexpr auto kPerRequest = 100;
|
||||
auto users = MTP_vector_from_range(_resolvePremiumRequiredUsers
|
||||
auto users = MTP_vector_from_range(_resolveMessageMoneyRequiredUsers
|
||||
| ranges::views::transform(&UserData::inputUser));
|
||||
if (users.v.size() > kPerRequest) {
|
||||
auto shortened = users.v;
|
||||
shortened.resize(kPerRequest);
|
||||
users = MTP_vector<MTPInputUser>(std::move(shortened));
|
||||
const auto from = begin(_resolvePremiumRequiredUsers);
|
||||
_resolvePremiumRequestedUsers = { from, from + kPerRequest };
|
||||
_resolvePremiumRequiredUsers.erase(from, from + kPerRequest);
|
||||
const auto from = begin(_resolveMessageMoneyRequiredUsers);
|
||||
_resolveMessageMoneyRequestedUsers = { from, from + kPerRequest };
|
||||
_resolveMessageMoneyRequiredUsers.erase(from, from + kPerRequest);
|
||||
} else {
|
||||
_resolvePremiumRequestedUsers
|
||||
= base::take(_resolvePremiumRequiredUsers);
|
||||
_resolveMessageMoneyRequestedUsers
|
||||
= base::take(_resolveMessageMoneyRequiredUsers);
|
||||
}
|
||||
const auto finish = [=](const QVector<MTPBool> &list) {
|
||||
constexpr auto me = UserDataFlag::MeRequiresPremiumToWrite;
|
||||
constexpr auto known = UserDataFlag::RequirePremiumToWriteKnown;
|
||||
constexpr auto mask = me | known;
|
||||
const auto finish = [=](const QVector<MTPRequirementToContact> &list) {
|
||||
|
||||
auto index = 0;
|
||||
for (const auto &user : base::take(_resolvePremiumRequestedUsers)) {
|
||||
const auto require = (index < list.size())
|
||||
&& mtpIsTrue(list[index++]);
|
||||
user->setFlags((user->flags() & ~mask)
|
||||
| known
|
||||
| (require ? me : UserDataFlag()));
|
||||
for (const auto &user : base::take(_resolveMessageMoneyRequestedUsers)) {
|
||||
const auto set = [&](bool requirePremium, int stars) {
|
||||
using Flag = UserDataFlag;
|
||||
constexpr auto me = Flag::RequiresPremiumToWrite;
|
||||
constexpr auto known = Flag::MessageMoneyRestrictionsKnown;
|
||||
constexpr auto hasPrem = Flag::HasRequirePremiumToWrite;
|
||||
constexpr auto hasStars = Flag::HasStarsPerMessage;
|
||||
user->setStarsPerMessage(stars);
|
||||
user->setFlags((user->flags() & ~(me | hasPrem | hasStars))
|
||||
| known
|
||||
| (requirePremium ? (me | hasPrem) : Flag())
|
||||
| (stars ? hasStars : Flag()));
|
||||
};
|
||||
if (index >= list.size()) {
|
||||
set(false, 0);
|
||||
continue;
|
||||
}
|
||||
list[index++].match([&](const MTPDrequirementToContactEmpty &) {
|
||||
set(false, 0);
|
||||
}, [&](const MTPDrequirementToContactPremium &) {
|
||||
set(true, 0);
|
||||
}, [&](const MTPDrequirementToContactPaidMessages &data) {
|
||||
set(false, data.vstars_amount().v);
|
||||
});
|
||||
}
|
||||
if (!_premiumRequiredRequestScheduled
|
||||
&& !_resolvePremiumRequiredUsers.empty()) {
|
||||
_premiumRequiredRequestScheduled = true;
|
||||
if (!_messageMoneyRequestScheduled
|
||||
&& !_resolveMessageMoneyRequiredUsers.empty()) {
|
||||
_messageMoneyRequestScheduled = true;
|
||||
crl::on_main(_session, [=] {
|
||||
requestPremiumRequiredSlice();
|
||||
});
|
||||
}
|
||||
_somePremiumRequiredResolved.fire({});
|
||||
_someMessageMoneyRestrictionsResolved.fire({});
|
||||
};
|
||||
_session->api().request(
|
||||
MTPusers_GetIsPremiumRequiredToContact(std::move(users))
|
||||
).done([=](const MTPVector<MTPBool> &result) {
|
||||
MTPusers_GetRequirementsToContact(std::move(users))
|
||||
).done([=](const MTPVector<MTPRequirementToContact> &result) {
|
||||
finish(result.v);
|
||||
}).fail([=] {
|
||||
finish({});
|
||||
@@ -463,10 +479,14 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::request() {
|
||||
for (const auto &tlOption : result.v) {
|
||||
const auto &data = tlOption.data();
|
||||
tlMapOptions[data.vusers().v].push_back(tlOption);
|
||||
if (qs(data.vcurrency()) == Ui::kCreditsCurrency) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto token = Token{ data.vusers().v, data.vmonths().v };
|
||||
_stores[token] = Store{
|
||||
.amount = data.vamount().v,
|
||||
.currency = qs(data.vcurrency()),
|
||||
.product = qs(data.vstore_product().value_or_empty()),
|
||||
.quantity = data.vstore_quantity().value_or_empty(),
|
||||
};
|
||||
@@ -475,14 +495,14 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::request() {
|
||||
}
|
||||
}
|
||||
for (const auto &[amount, tlOptions] : tlMapOptions) {
|
||||
if (amount == 1 && _optionsForOnePerson.currency.isEmpty()) {
|
||||
_optionsForOnePerson.currency = qs(
|
||||
tlOptions.front().data().vcurrency());
|
||||
if (amount == 1 && _optionsForOnePerson.currencies.empty()) {
|
||||
for (const auto &option : tlOptions) {
|
||||
_optionsForOnePerson.months.push_back(
|
||||
option.data().vmonths().v);
|
||||
_optionsForOnePerson.totalCosts.push_back(
|
||||
option.data().vamount().v);
|
||||
_optionsForOnePerson.currencies.push_back(
|
||||
qs(option.data().vcurrency()));
|
||||
}
|
||||
}
|
||||
_subscriptionOptions[amount] = GiftCodesFromTL(tlOptions);
|
||||
@@ -509,7 +529,7 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::applyPrepaid(
|
||||
_api.request(MTPpayments_LaunchPrepaidGiveaway(
|
||||
_peer->input,
|
||||
MTP_long(prepaidId),
|
||||
invoice.creditsAmount
|
||||
invoice.giveawayCredits
|
||||
? Payments::InvoiceCreditsGiveawayToTL(invoice)
|
||||
: Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
@@ -540,7 +560,7 @@ Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
|
||||
const auto token = Token{ users, months };
|
||||
const auto &store = _stores[token];
|
||||
return Payments::InvoicePremiumGiftCode{
|
||||
.currency = _optionsForOnePerson.currency,
|
||||
.currency = store.currency,
|
||||
.storeProduct = store.product,
|
||||
.randomId = randomId,
|
||||
.amount = store.amount,
|
||||
@@ -553,14 +573,15 @@ Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
|
||||
std::vector<GiftOptionData> PremiumGiftCodeOptions::optionsForPeer() const {
|
||||
auto result = std::vector<GiftOptionData>();
|
||||
|
||||
if (!_optionsForOnePerson.currency.isEmpty()) {
|
||||
if (!_optionsForOnePerson.currencies.empty()) {
|
||||
const auto count = int(_optionsForOnePerson.months.size());
|
||||
result.reserve(count);
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
Assert(i < _optionsForOnePerson.totalCosts.size());
|
||||
Assert(i < _optionsForOnePerson.currencies.size());
|
||||
result.push_back({
|
||||
.cost = _optionsForOnePerson.totalCosts[i],
|
||||
.currency = _optionsForOnePerson.currency,
|
||||
.currency = _optionsForOnePerson.currencies[i],
|
||||
.months = _optionsForOnePerson.months[i],
|
||||
});
|
||||
}
|
||||
@@ -581,7 +602,7 @@ Data::PremiumSubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
|
||||
MTP_int(_optionsForOnePerson.months[i]),
|
||||
MTPstring(),
|
||||
MTPint(),
|
||||
MTP_string(_optionsForOnePerson.currency),
|
||||
MTP_string(_optionsForOnePerson.currencies[i]),
|
||||
MTP_long(_optionsForOnePerson.totalCosts[i] * amount)));
|
||||
}
|
||||
_subscriptionOptions[amount] = GiftCodesFromTL(tlOptions);
|
||||
@@ -601,7 +622,7 @@ auto PremiumGiftCodeOptions::requestStarGifts()
|
||||
_giftsHash = data.vhash().v;
|
||||
const auto &list = data.vgifts().v;
|
||||
const auto session = &_peer->session();
|
||||
auto gifts = std::vector<StarGift>();
|
||||
auto gifts = std::vector<Data::StarGift>();
|
||||
gifts.reserve(list.size());
|
||||
for (const auto &gift : list) {
|
||||
if (auto parsed = FromTL(session, gift)) {
|
||||
@@ -620,7 +641,8 @@ auto PremiumGiftCodeOptions::requestStarGifts()
|
||||
};
|
||||
}
|
||||
|
||||
const std::vector<StarGift> &PremiumGiftCodeOptions::starGifts() const {
|
||||
auto PremiumGiftCodeOptions::starGifts() const
|
||||
-> const std::vector<Data::StarGift> & {
|
||||
return _gifts;
|
||||
}
|
||||
|
||||
@@ -693,28 +715,38 @@ rpl::producer<rpl::no_value, QString> SponsoredToggle::setToggled(bool v) {
|
||||
};
|
||||
}
|
||||
|
||||
RequirePremiumState ResolveRequiresPremiumToWrite(
|
||||
MessageMoneyRestriction ResolveMessageMoneyRestrictions(
|
||||
not_null<PeerData*> peer,
|
||||
History *maybeHistory) {
|
||||
const auto user = peer->asUser();
|
||||
if (!user
|
||||
|| !user->someRequirePremiumToWrite()
|
||||
|| user->session().premium()) {
|
||||
return RequirePremiumState::No;
|
||||
} else if (user->requirePremiumToWriteKnown()) {
|
||||
return user->meRequiresPremiumToWrite()
|
||||
? RequirePremiumState::Yes
|
||||
: RequirePremiumState::No;
|
||||
} else if (user->flags() & UserDataFlag::MutualContact) {
|
||||
return RequirePremiumState::No;
|
||||
} else if (!maybeHistory) {
|
||||
return RequirePremiumState::Unknown;
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
return {
|
||||
.starsPerMessage = channel->starsPerMessageChecked(),
|
||||
.known = true,
|
||||
};
|
||||
}
|
||||
const auto user = peer->asUser();
|
||||
if (!user) {
|
||||
return { .known = true };
|
||||
} else if (user->messageMoneyRestrictionsKnown()) {
|
||||
return {
|
||||
.starsPerMessage = user->starsPerMessageChecked(),
|
||||
.premiumRequired = (user->requiresPremiumToWrite()
|
||||
&& !user->session().premium()),
|
||||
.known = true,
|
||||
};
|
||||
} else if (user->hasStarsPerMessage()) {
|
||||
return {};
|
||||
} else if (!user->hasRequirePremiumToWrite()) {
|
||||
return { .known = true };
|
||||
} else if (user->flags() & UserDataFlag::MutualContact) {
|
||||
return { .known = true };
|
||||
} else if (!maybeHistory) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto update = [&](bool require) {
|
||||
using Flag = UserDataFlag;
|
||||
constexpr auto known = Flag::RequirePremiumToWriteKnown;
|
||||
constexpr auto me = Flag::MeRequiresPremiumToWrite;
|
||||
constexpr auto known = Flag::MessageMoneyRestrictionsKnown;
|
||||
constexpr auto me = Flag::RequiresPremiumToWrite;
|
||||
user->setFlags((user->flags() & ~me)
|
||||
| known
|
||||
| (require ? me : Flag()));
|
||||
@@ -726,16 +758,19 @@ RequirePremiumState ResolveRequiresPremiumToWrite(
|
||||
const auto item = view->data();
|
||||
if (!item->out() && !item->isService()) {
|
||||
update(false);
|
||||
return RequirePremiumState::No;
|
||||
return { .known = true };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (user->isContact() // Here we know, that we're not in his contacts.
|
||||
&& maybeHistory->loadedAtTop() // And no incoming messages.
|
||||
&& maybeHistory->loadedAtBottom()) {
|
||||
update(true);
|
||||
return {
|
||||
.premiumRequired = !user->session().premium(),
|
||||
.known = true,
|
||||
};
|
||||
}
|
||||
return RequirePremiumState::Unknown;
|
||||
return {};
|
||||
}
|
||||
|
||||
rpl::producer<DocumentData*> RandomHelloStickerValue(
|
||||
@@ -758,40 +793,100 @@ rpl::producer<DocumentData*> RandomHelloStickerValue(
|
||||
}) | rpl::take(1) | rpl::map(random));
|
||||
}
|
||||
|
||||
std::optional<StarGift> FromTL(
|
||||
std::optional<Data::StarGift> FromTL(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPstarGift &gift) {
|
||||
const auto &data = gift.data();
|
||||
const auto document = session->data().processDocument(
|
||||
data.vsticker());
|
||||
const auto remaining = data.vavailability_remains();
|
||||
const auto total = data.vavailability_total();
|
||||
if (!document->sticker()) {
|
||||
return {};
|
||||
}
|
||||
return StarGift{
|
||||
.id = uint64(data.vid().v),
|
||||
.stars = int64(data.vstars().v),
|
||||
.convertStars = int64(data.vconvert_stars().v),
|
||||
.document = document,
|
||||
.limitedLeft = remaining.value_or_empty(),
|
||||
.limitedCount = total.value_or_empty(),
|
||||
.firstSaleDate = data.vfirst_sale_date().value_or_empty(),
|
||||
.lastSaleDate = data.vlast_sale_date().value_or_empty(),
|
||||
};
|
||||
return gift.match([&](const MTPDstarGift &data) {
|
||||
const auto document = session->data().processDocument(
|
||||
data.vsticker());
|
||||
const auto remaining = data.vavailability_remains();
|
||||
const auto total = data.vavailability_total();
|
||||
if (!document->sticker()) {
|
||||
return std::optional<Data::StarGift>();
|
||||
}
|
||||
return std::optional<Data::StarGift>(Data::StarGift{
|
||||
.id = uint64(data.vid().v),
|
||||
.stars = int64(data.vstars().v),
|
||||
.starsConverted = int64(data.vconvert_stars().v),
|
||||
.starsToUpgrade = int64(data.vupgrade_stars().value_or_empty()),
|
||||
.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(),
|
||||
.upgradable = data.vupgrade_stars().has_value(),
|
||||
.birthday = data.is_birthday(),
|
||||
});
|
||||
}, [&](const MTPDstarGiftUnique &data) {
|
||||
const auto total = data.vavailability_total().v;
|
||||
auto model = std::optional<Data::UniqueGiftModel>();
|
||||
auto pattern = std::optional<Data::UniqueGiftPattern>();
|
||||
for (const auto &attribute : data.vattributes().v) {
|
||||
attribute.match([&](const MTPDstarGiftAttributeModel &data) {
|
||||
model = FromTL(session, data);
|
||||
}, [&](const MTPDstarGiftAttributePattern &data) {
|
||||
pattern = FromTL(session, data);
|
||||
}, [&](const MTPDstarGiftAttributeBackdrop &data) {
|
||||
}, [&](const MTPDstarGiftAttributeOriginalDetails &data) {
|
||||
});
|
||||
}
|
||||
if (!model
|
||||
|| !model->document->sticker()
|
||||
|| !pattern
|
||||
|| !pattern->document->sticker()) {
|
||||
return std::optional<Data::StarGift>();
|
||||
}
|
||||
auto result = Data::StarGift{
|
||||
.id = uint64(data.vid().v),
|
||||
.unique = std::make_shared<Data::UniqueGift>(Data::UniqueGift{
|
||||
.id = data.vid().v,
|
||||
.slug = qs(data.vslug()),
|
||||
.title = qs(data.vtitle()),
|
||||
.ownerAddress = qs(data.vowner_address().value_or_empty()),
|
||||
.ownerName = qs(data.vowner_name().value_or_empty()),
|
||||
.ownerId = (data.vowner_id()
|
||||
? peerFromMTP(*data.vowner_id())
|
||||
: PeerId()),
|
||||
.number = data.vnum().v,
|
||||
.model = *model,
|
||||
.pattern = *pattern,
|
||||
}),
|
||||
.document = model->document,
|
||||
.limitedLeft = (total - data.vavailability_issued().v),
|
||||
.limitedCount = total,
|
||||
};
|
||||
const auto unique = result.unique.get();
|
||||
for (const auto &attribute : data.vattributes().v) {
|
||||
attribute.match([&](const MTPDstarGiftAttributeModel &data) {
|
||||
}, [&](const MTPDstarGiftAttributePattern &data) {
|
||||
}, [&](const MTPDstarGiftAttributeBackdrop &data) {
|
||||
unique->backdrop = FromTL(data);
|
||||
}, [&](const MTPDstarGiftAttributeOriginalDetails &data) {
|
||||
unique->originalDetails = FromTL(session, data);
|
||||
});
|
||||
}
|
||||
return std::make_optional(result);
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<UserStarGift> FromTL(
|
||||
not_null<UserData*> to,
|
||||
const MTPuserStarGift &gift) {
|
||||
std::optional<Data::SavedStarGift> FromTL(
|
||||
not_null<PeerData*> to,
|
||||
const MTPsavedStarGift &gift) {
|
||||
const auto session = &to->session();
|
||||
const auto &data = gift.data();
|
||||
auto parsed = FromTL(session, data.vgift());
|
||||
if (!parsed) {
|
||||
return {};
|
||||
} else if (const auto unique = parsed->unique.get()) {
|
||||
unique->starsForTransfer = data.vtransfer_stars().value_or(-1);
|
||||
unique->exportAt = data.vcan_export_at().value_or_empty();
|
||||
}
|
||||
return UserStarGift{
|
||||
using Id = Data::SavedStarGiftId;
|
||||
return Data::SavedStarGift{
|
||||
.info = std::move(*parsed),
|
||||
.manageId = (to->isUser()
|
||||
? Id::User(data.vmsg_id().value_or_empty())
|
||||
: Id::Chat(to, data.vsaved_id().value_or_empty())),
|
||||
.message = (data.vmessage()
|
||||
? TextWithEntities{
|
||||
.text = qs(data.vmessage()->data().vtext()),
|
||||
@@ -800,16 +895,72 @@ 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()),
|
||||
.starsUpgradedBySender = int64(
|
||||
data.vupgrade_stars().value_or_empty()),
|
||||
.fromId = (data.vfrom_id()
|
||||
? peerFromUser(data.vfrom_id()->v)
|
||||
? peerFromMTP(*data.vfrom_id())
|
||||
: PeerId()),
|
||||
.messageId = data.vmsg_id().value_or_empty(),
|
||||
.date = data.vdate().v,
|
||||
.upgradable = data.is_can_upgrade(),
|
||||
.anonymous = data.is_name_hidden(),
|
||||
.pinned = data.is_pinned_to_top(),
|
||||
.hidden = data.is_unsaved(),
|
||||
.mine = to->isSelf(),
|
||||
};
|
||||
}
|
||||
|
||||
Data::UniqueGiftModel FromTL(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDstarGiftAttributeModel &data) {
|
||||
auto result = Data::UniqueGiftModel{
|
||||
.document = session->data().processDocument(data.vdocument()),
|
||||
};
|
||||
result.name = qs(data.vname());
|
||||
result.rarityPermille = data.vrarity_permille().v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Data::UniqueGiftPattern FromTL(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDstarGiftAttributePattern &data) {
|
||||
auto result = Data::UniqueGiftPattern{
|
||||
.document = session->data().processDocument(data.vdocument()),
|
||||
};
|
||||
result.document->overrideEmojiUsesTextColor(true);
|
||||
result.name = qs(data.vname());
|
||||
result.rarityPermille = data.vrarity_permille().v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Data::UniqueGiftBackdrop FromTL(const MTPDstarGiftAttributeBackdrop &data) {
|
||||
auto result = Data::UniqueGiftBackdrop();
|
||||
result.name = qs(data.vname());
|
||||
result.rarityPermille = data.vrarity_permille().v;
|
||||
result.centerColor = Ui::ColorFromSerialized(
|
||||
data.vcenter_color());
|
||||
result.edgeColor = Ui::ColorFromSerialized(
|
||||
data.vedge_color());
|
||||
result.patternColor = Ui::ColorFromSerialized(
|
||||
data.vpattern_color());
|
||||
result.textColor = Ui::ColorFromSerialized(
|
||||
data.vtext_color());
|
||||
return result;
|
||||
}
|
||||
|
||||
Data::UniqueGiftOriginalDetails FromTL(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDstarGiftAttributeOriginalDetails &data) {
|
||||
auto result = Data::UniqueGiftOriginalDetails();
|
||||
result.date = data.vdate().v;
|
||||
result.senderId = data.vsender_id()
|
||||
? peerFromMTP(*data.vsender_id())
|
||||
: PeerId();
|
||||
result.recipientId = peerFromMTP(data.vrecipient_id());
|
||||
result.message = data.vmessage()
|
||||
? ParseTextWithEntities(session, *data.vmessage())
|
||||
: TextWithEntities();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||