Compare commits
603 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf345da87b | ||
|
|
1e5aa2a78d | ||
|
|
8cf62c312f | ||
|
|
3b0bf7cb1e | ||
|
|
673072ea5b | ||
|
|
849deb57e2 | ||
|
|
dda587a2fc | ||
|
|
c057f28425 | ||
|
|
a16c6ca41a | ||
|
|
c5845f17ae | ||
|
|
e2f54eb3e9 | ||
|
|
5a1c8e6a0a | ||
|
|
b73390a3f6 | ||
|
|
0c713a930a | ||
|
|
a87529b8c9 | ||
|
|
0c30bbf40a | ||
|
|
f75bfb4369 | ||
|
|
0c34ba638c | ||
|
|
4af9c801ae | ||
|
|
e06bf16980 | ||
|
|
1018745b0b | ||
|
|
47b157bf32 | ||
|
|
09547bd6d5 | ||
|
|
d17f21c10d | ||
|
|
f11339361d | ||
|
|
04b9d4bdb5 | ||
|
|
1d8d2b6251 | ||
|
|
190bf8fc5f | ||
|
|
f463d3ec6d | ||
|
|
f9d10094ac | ||
|
|
9fc87c3cb8 | ||
|
|
0d9c30423f | ||
|
|
c4bc76c022 | ||
|
|
241f5e1d26 | ||
|
|
76f0abecfd | ||
|
|
ca45fb617e | ||
|
|
dfd63e66ff | ||
|
|
d85f162bff | ||
|
|
1d4fbc64e2 | ||
|
|
9fd32fc85b | ||
|
|
f7f195eb98 | ||
|
|
12c7bd8ee1 | ||
|
|
cd5ef069c0 | ||
|
|
f90fdce422 | ||
|
|
423254f7eb | ||
|
|
c9c0d74b68 | ||
|
|
8bf6013342 | ||
|
|
c1ab1acd44 | ||
|
|
90b955534a | ||
|
|
61c7bf2f5e | ||
|
|
ee5423762a | ||
|
|
6d29dc3b36 | ||
|
|
aa10934e85 | ||
|
|
9ff1fbcf47 | ||
|
|
51c1dc20e1 | ||
|
|
3a3bf84cfc | ||
|
|
037b936613 | ||
|
|
b631d09a40 | ||
|
|
fd4f384c3b | ||
|
|
428a501bac | ||
|
|
3ca57ae50d | ||
|
|
f1eddcd584 | ||
|
|
f979df3dfe | ||
|
|
eebcdb842d | ||
|
|
048658f838 | ||
|
|
8fd17e2e8f | ||
|
|
5c13214244 | ||
|
|
12a020cd09 | ||
|
|
b98e02f326 | ||
|
|
9a521c5340 | ||
|
|
5f26e92f5c | ||
|
|
3d78c637a2 | ||
|
|
2ab2eed633 | ||
|
|
bb7018424a | ||
|
|
a770b5d4cd | ||
|
|
c92a9585e1 | ||
|
|
cedb2d31af | ||
|
|
95da2dbc34 | ||
|
|
f9b2a8d6ac | ||
|
|
a773ad7b02 | ||
|
|
32287a51f9 | ||
|
|
37a4c79c81 | ||
|
|
95ee17bd54 | ||
|
|
469c6770fb | ||
|
|
e38123cc48 | ||
|
|
e3d7bf771f | ||
|
|
1cda90c3c5 | ||
|
|
9c86f0e0a5 | ||
|
|
910f16312c | ||
|
|
639b4bdd27 | ||
|
|
4951eeac98 | ||
|
|
79106e0c01 | ||
|
|
7485f0c960 | ||
|
|
03bdd80b2f | ||
|
|
dd74f57a66 | ||
|
|
534772722e | ||
|
|
6343221d7b | ||
|
|
4929de2bfb | ||
|
|
ac8f924909 | ||
|
|
95afcbb485 | ||
|
|
229bc56cc8 | ||
|
|
4b045a602c | ||
|
|
1e3b72ab74 | ||
|
|
bc63d9fe53 | ||
|
|
d7cb8b7065 | ||
|
|
30f4d870c5 | ||
|
|
ad515c6f4a | ||
|
|
056949416d | ||
|
|
ab6d9ff73c | ||
|
|
8b766dda8e | ||
|
|
ee0f66d746 | ||
|
|
7893ad0558 | ||
|
|
b0c5a75fb9 | ||
|
|
1c313da888 | ||
|
|
ee210ea701 | ||
|
|
e0c0d79be9 | ||
|
|
cb3bad31fa | ||
|
|
917696be36 | ||
|
|
253816641c | ||
|
|
ca2692473d | ||
|
|
8000dfac01 | ||
|
|
85cca51154 | ||
|
|
87ea49e094 | ||
|
|
66bf48e21e | ||
|
|
451056d2ab | ||
|
|
791ae64a90 | ||
|
|
3b4563772e | ||
|
|
16b786186b | ||
|
|
7be1c4ca2f | ||
|
|
17fba16c23 | ||
|
|
5fc4dcd172 | ||
|
|
b27a2cd34a | ||
|
|
569340c7d3 | ||
|
|
3715fa4b1e | ||
|
|
d95e54cb1a | ||
|
|
470b67f557 | ||
|
|
c46bcef9ff | ||
|
|
c31cda0587 | ||
|
|
5758f756c9 | ||
|
|
f199205592 | ||
|
|
2b656f7745 | ||
|
|
7be286751b | ||
|
|
04617e4a12 | ||
|
|
405ccb8580 | ||
|
|
131ef4f15a | ||
|
|
07f45b7eab | ||
|
|
87addd41b1 | ||
|
|
0a4f91a53d | ||
|
|
3b76a908a4 | ||
|
|
9e3bc966c8 | ||
|
|
149c69809d | ||
|
|
97a239a8b4 | ||
|
|
bd7cee2252 | ||
|
|
66d0d6e8fe | ||
|
|
117d6192fa | ||
|
|
763bdf8798 | ||
|
|
56a82600f8 | ||
|
|
a3e993253c | ||
|
|
04d5158ae3 | ||
|
|
38e4daacd4 | ||
|
|
44d156760e | ||
|
|
d66541989e | ||
|
|
56c4d164f3 | ||
|
|
e2c1c4c8de | ||
|
|
a465117689 | ||
|
|
c2117e7722 | ||
|
|
7de28fc4bd | ||
|
|
529ef64257 | ||
|
|
9cb5423d40 | ||
|
|
dd136350fb | ||
|
|
ef7087348a | ||
|
|
8eac2dcb78 | ||
|
|
f690f93f32 | ||
|
|
77ebdd3576 | ||
|
|
3e895d0e85 | ||
|
|
385a7eb00d | ||
|
|
1c9775baf9 | ||
|
|
fb96d2eef8 | ||
|
|
debeb61540 | ||
|
|
03cdddfe18 | ||
|
|
caef7dde24 | ||
|
|
0b08810d5a | ||
|
|
694f771131 | ||
|
|
956bb876f6 | ||
|
|
99037d3d46 | ||
|
|
ea0a616453 | ||
|
|
815a18be94 | ||
|
|
3814b0833d | ||
|
|
549789bfb7 | ||
|
|
a539fad3e2 | ||
|
|
ee96d78656 | ||
|
|
288c1130b9 | ||
|
|
d1083a1fb4 | ||
|
|
e1fe373504 | ||
|
|
1a06714f3a | ||
|
|
7316d24ca4 | ||
|
|
b814c6307a | ||
|
|
06fbb2edc4 | ||
|
|
0ee47bb10f | ||
|
|
9f228d8146 | ||
|
|
de270d5283 | ||
|
|
3f041545bf | ||
|
|
1139a59818 | ||
|
|
1e64ba8f29 | ||
|
|
65342559c7 | ||
|
|
e150db1d0b | ||
|
|
4548b14b45 | ||
|
|
dac1128dc9 | ||
|
|
c3944d95b4 | ||
|
|
02b65a42f7 | ||
|
|
4869ce2247 | ||
|
|
e40267f45b | ||
|
|
e9ab8df737 | ||
|
|
9276101809 | ||
|
|
0c3773486e | ||
|
|
b831766375 | ||
|
|
325989ed47 | ||
|
|
63203ecc00 | ||
|
|
93793d8bdd | ||
|
|
6710372d27 | ||
|
|
a8c94deca8 | ||
|
|
e97d014a01 | ||
|
|
7ffa348e43 | ||
|
|
b999d87388 | ||
|
|
fb00d523c3 | ||
|
|
d7f7a03eb4 | ||
|
|
bc83df9d7f | ||
|
|
61c1c10ed9 | ||
|
|
4bad642190 | ||
|
|
f48732f813 | ||
|
|
10e28913ca | ||
|
|
230dd29af5 | ||
|
|
169db40e9f | ||
|
|
116b483a88 | ||
|
|
57cdef4e6b | ||
|
|
1b1b1780db | ||
|
|
e479daca03 | ||
|
|
51d350c356 | ||
|
|
9da4bd671e | ||
|
|
d298953653 | ||
|
|
1d52ba7a42 | ||
|
|
850940116d | ||
|
|
fd59147b8a | ||
|
|
93a52bb66e | ||
|
|
7e4c9f98a6 | ||
|
|
7d2896dd42 | ||
|
|
f7f797dd78 | ||
|
|
4b7b1c35e1 | ||
|
|
708b1d7ad4 | ||
|
|
abf49e1672 | ||
|
|
052e4bc508 | ||
|
|
80fedcbbae | ||
|
|
787b5f549a | ||
|
|
e8a28a57df | ||
|
|
b05ea9fc25 | ||
|
|
8d94cfb61b | ||
|
|
d8a58991c4 | ||
|
|
03cf8b6ac2 | ||
|
|
32e8ae2b9e | ||
|
|
27d84befa8 | ||
|
|
3bf709d459 | ||
|
|
2a8b6f05c8 | ||
|
|
f29b331470 | ||
|
|
a8b74d4b6b | ||
|
|
415d817034 | ||
|
|
3f2cc01f48 | ||
|
|
f1cd70d8a8 | ||
|
|
bacaf805b5 | ||
|
|
137fa0378c | ||
|
|
ff44094ded | ||
|
|
06982fdf04 | ||
|
|
9cf4cf6dca | ||
|
|
db2018c765 | ||
|
|
020e62fb7a | ||
|
|
2ed5552279 | ||
|
|
4d92d74de0 | ||
|
|
4fd50cfb70 | ||
|
|
27f248645c | ||
|
|
3f1a2d0b58 | ||
|
|
6fe36e6534 | ||
|
|
f36e2981ca | ||
|
|
22f210ea8e | ||
|
|
b23bfe8b02 | ||
|
|
6aa930d510 | ||
|
|
4a10a88ecf | ||
|
|
f4754f210c | ||
|
|
873b77cf40 | ||
|
|
a7d9aa947b | ||
|
|
234b0ffcf0 | ||
|
|
c50ade565a | ||
|
|
0005e0a3ce | ||
|
|
04bf24288a | ||
|
|
01d0479335 | ||
|
|
055c145af5 | ||
|
|
328b090877 | ||
|
|
1d2c86839b | ||
|
|
59574532c6 | ||
|
|
4544a2e331 | ||
|
|
c0f8ab8da0 | ||
|
|
d02617867c | ||
|
|
78c99a1583 | ||
|
|
9ec797857d | ||
|
|
b310011dee | ||
|
|
633084ed9c | ||
|
|
ab8889b2fa | ||
|
|
d563e746ab | ||
|
|
7c6ede0908 | ||
|
|
c22aeb8b40 | ||
|
|
cabe06256b | ||
|
|
2fad4e9956 | ||
|
|
c5df4db621 | ||
|
|
68b1024dd4 | ||
|
|
c894ce30c4 | ||
|
|
33fce38f90 | ||
|
|
e123399f7c | ||
|
|
0805c09446 | ||
|
|
8135f4b427 | ||
|
|
2f0331b2e0 | ||
|
|
69b6b48738 | ||
|
|
3cda267787 | ||
|
|
ffba901620 | ||
|
|
2351865961 | ||
|
|
7a11d1e31f | ||
|
|
f2b3d9714f | ||
|
|
8477956117 | ||
|
|
77b8d56c03 | ||
|
|
90fb9eccd4 | ||
|
|
c3c6571835 | ||
|
|
b9d3ba621e | ||
|
|
4757ad6c97 | ||
|
|
9c909c8992 | ||
|
|
0710dde4d5 | ||
|
|
8008d8a3d4 | ||
|
|
5c5eead0f5 | ||
|
|
696c70e34a | ||
|
|
75fd2d0257 | ||
|
|
4e595d5cef | ||
|
|
8486ad368e | ||
|
|
ae075e9b90 | ||
|
|
86d7143d94 | ||
|
|
4e52da91c7 | ||
|
|
198de85ce5 | ||
|
|
72a9d61b97 | ||
|
|
96a26b44a9 | ||
|
|
f19ff1f9b2 | ||
|
|
4bd0683e91 | ||
|
|
567bf60644 | ||
|
|
3ca28c0cf9 | ||
|
|
4a12e9798a | ||
|
|
5c6515febb | ||
|
|
ca5fee6db9 | ||
|
|
4ac3aef600 | ||
|
|
1963fca7d3 | ||
|
|
5e233dab47 | ||
|
|
cf8a06302f | ||
|
|
9c9ea8c2c0 | ||
|
|
bb9e6e7b5f | ||
|
|
7c98f64cdb | ||
|
|
da6baeb1a7 | ||
|
|
26569683ca | ||
|
|
821bd3c65b | ||
|
|
2d62c9b083 | ||
|
|
9d09cee1cc | ||
|
|
0e964b06dc | ||
|
|
b1807938ad | ||
|
|
b96b801b22 | ||
|
|
58d4b763b6 | ||
|
|
f1518af8b3 | ||
|
|
d228495550 | ||
|
|
226ca6d117 | ||
|
|
556f36ba7e | ||
|
|
c8b61366d3 | ||
|
|
729da4a6b4 | ||
|
|
dd38da7737 | ||
|
|
306b87dd39 | ||
|
|
826d229c1a | ||
|
|
89fb121caf | ||
|
|
d479442a63 | ||
|
|
10ee81f466 | ||
|
|
0a63eac4f6 | ||
|
|
7034df49e9 | ||
|
|
da48a78f7c | ||
|
|
0109ee2758 | ||
|
|
ae152d28be | ||
|
|
dd1bca1769 | ||
|
|
a4fbbc06d1 | ||
|
|
0dd1b4eae6 | ||
|
|
848ea16eef | ||
|
|
76630528f7 | ||
|
|
3b645422ff | ||
|
|
db2d24ff32 | ||
|
|
a10b91fe1a | ||
|
|
ead212f31b | ||
|
|
37689affc5 | ||
|
|
5375e7958c | ||
|
|
1da5d1c64f | ||
|
|
f6bfbbb805 | ||
|
|
2c461b9df3 | ||
|
|
53a3d0038c | ||
|
|
ad1816cb7c | ||
|
|
09c9f4ef9a | ||
|
|
cbffeca8d5 | ||
|
|
4a7b5a8e01 | ||
|
|
808583c5ae | ||
|
|
5628c1eee6 | ||
|
|
0b8aa880e5 | ||
|
|
059a24bcdf | ||
|
|
df8625345b | ||
|
|
a026aec786 | ||
|
|
56e137b20f | ||
|
|
10772f4ac5 | ||
|
|
35bc2cc2a5 | ||
|
|
f20d9395d1 | ||
|
|
aa3a079853 | ||
|
|
e43fcc0e5f | ||
|
|
b10e6b3508 | ||
|
|
b36f7dfdb1 | ||
|
|
f08d913175 | ||
|
|
21dfb310f3 | ||
|
|
0d6ee3929d | ||
|
|
040cae6a9a | ||
|
|
8f3f898c47 | ||
|
|
10910588a0 | ||
|
|
adf5c8ec71 | ||
|
|
f77b11975b | ||
|
|
84aaec30a1 | ||
|
|
764490b4a9 | ||
|
|
022fb0c81b | ||
|
|
d5497c3105 | ||
|
|
09162e6f19 | ||
|
|
f46189041c | ||
|
|
7c2f114330 | ||
|
|
a04247a893 | ||
|
|
3a8a74f063 | ||
|
|
9c85d58235 | ||
|
|
e5cfa3fdc9 | ||
|
|
5c49701603 | ||
|
|
978a4ac0ad | ||
|
|
8a7980ca7b | ||
|
|
29532f8232 | ||
|
|
ee4501810c | ||
|
|
99aa1fc556 | ||
|
|
8741266819 | ||
|
|
d864ebd695 | ||
|
|
352839337d | ||
|
|
88b7387a40 | ||
|
|
d0cf39f8ed | ||
|
|
d57b8d2ec7 | ||
|
|
8de3826c9e | ||
|
|
3ea0247a3e | ||
|
|
bebf58ea8d | ||
|
|
7489f2297f | ||
|
|
c7526ae1cd | ||
|
|
07a063e19e | ||
|
|
3727c8c865 | ||
|
|
662d0d0764 | ||
|
|
dcba07b9b7 | ||
|
|
a4d83b679a | ||
|
|
dc102bd9e8 | ||
|
|
f877bf7a46 | ||
|
|
a0171cb144 | ||
|
|
7d585ab72f | ||
|
|
6537e524b8 | ||
|
|
4917ca7b32 | ||
|
|
edcd09c29f | ||
|
|
87fc066e67 | ||
|
|
d3ca6b96a1 | ||
|
|
52e40cbc6e | ||
|
|
a7c8feaecb | ||
|
|
d1d98c3bb1 | ||
|
|
8ed433cc01 | ||
|
|
7af0dd105e | ||
|
|
f35085800a | ||
|
|
366413a0a6 | ||
|
|
faa42110ac | ||
|
|
87cb0ada98 | ||
|
|
6a1abe8767 | ||
|
|
7f96a185cf | ||
|
|
91c57f2035 | ||
|
|
522e66b2db | ||
|
|
2d10e3e432 | ||
|
|
d23fd3559a | ||
|
|
3c11eda611 | ||
|
|
b9d1d8519c | ||
|
|
8f3f072b50 | ||
|
|
a68a53d768 | ||
|
|
0dddb7694f | ||
|
|
ca7c50fbcd | ||
|
|
9066acd2dd | ||
|
|
2162aa8df0 | ||
|
|
e9677779b8 | ||
|
|
aca3ec0ab8 | ||
|
|
3a34b15841 | ||
|
|
08d4715ad6 | ||
|
|
213a8d888a | ||
|
|
f49c7ba7ee | ||
|
|
984f19b1e9 | ||
|
|
5e3734d7bf | ||
|
|
30dea3a2e7 | ||
|
|
14b82698f8 | ||
|
|
37df26fc34 | ||
|
|
42798d466f | ||
|
|
9ca4f0975a | ||
|
|
26da5c5339 | ||
|
|
d0b86e1229 | ||
|
|
61c66994a2 | ||
|
|
034bee8fc3 | ||
|
|
734ecc070b | ||
|
|
ece315f3c5 | ||
|
|
484ecffb66 | ||
|
|
77a216cbca | ||
|
|
d9426413dd | ||
|
|
859cfe4cbb | ||
|
|
d4976dda6c | ||
|
|
e7c40ff2a8 | ||
|
|
90ecec1d2e | ||
|
|
d9e93fb5cc | ||
|
|
e7bdcc4155 | ||
|
|
fa3bf11a7f | ||
|
|
3013301a91 | ||
|
|
96acecc35b | ||
|
|
f8d900d7fb | ||
|
|
ce760f0534 | ||
|
|
1225c9194a | ||
|
|
abfe685697 | ||
|
|
37ff1bde31 | ||
|
|
b674003868 | ||
|
|
0868a9f7b9 | ||
|
|
1e861f79f0 | ||
|
|
ae3fae44b2 | ||
|
|
dd68c7e90d | ||
|
|
a547f80ae9 | ||
|
|
263bbf1788 | ||
|
|
94c4ea6174 | ||
|
|
bd2e1ceb02 | ||
|
|
8c67a4b991 | ||
|
|
126ffc8769 | ||
|
|
4379fa2297 | ||
|
|
b9bd937aaa | ||
|
|
351ba3a912 | ||
|
|
c2b2236e64 | ||
|
|
6f4e31c9c3 | ||
|
|
1290cda830 | ||
|
|
a27a80351a | ||
|
|
e53f4a5450 | ||
|
|
65b949d36b | ||
|
|
a8d3951116 | ||
|
|
f91e11efc9 | ||
|
|
ed7a88ca17 | ||
|
|
dcdaee3db2 | ||
|
|
c7b1683f6e | ||
|
|
961fd1dbab | ||
|
|
2f963d7f12 | ||
|
|
5be9ce0cf0 | ||
|
|
04e3b250e7 | ||
|
|
2255eb2c68 | ||
|
|
0ce5405eef | ||
|
|
46d8d9f97a | ||
|
|
274fed3cb0 | ||
|
|
021ada5e9e | ||
|
|
6f2a04e5ae | ||
|
|
eb438e35ee | ||
|
|
b2895a39ed | ||
|
|
cca906d383 | ||
|
|
8704f6efd0 | ||
|
|
e1114530ab | ||
|
|
27018d94ee | ||
|
|
1ee4dac4f3 | ||
|
|
fe15ee742d | ||
|
|
ebf2a678b1 | ||
|
|
8c0cd9b9e9 | ||
|
|
8e15e71fd5 | ||
|
|
1fb529803e | ||
|
|
3355e6da0c | ||
|
|
1331e7089e | ||
|
|
9c613fe2f7 | ||
|
|
0467401635 | ||
|
|
4fd6a85861 | ||
|
|
3d38abce97 | ||
|
|
271d929ad6 | ||
|
|
ef364e998f | ||
|
|
53ba300d7e | ||
|
|
caf1af8963 | ||
|
|
9fce11b672 | ||
|
|
f7cb38c36a | ||
|
|
d7ab7aed62 | ||
|
|
ea61211a61 | ||
|
|
c560f327cd | ||
|
|
030b298a7d | ||
|
|
b45705f39d | ||
|
|
9871184953 | ||
|
|
7f74084237 | ||
|
|
0fc1a40b42 | ||
|
|
45a6985df5 | ||
|
|
619aca04f9 | ||
|
|
a968e112e8 | ||
|
|
325323e0b3 | ||
|
|
b012847017 | ||
|
|
56d3e69399 | ||
|
|
f1c7409980 | ||
|
|
33ea5ad297 | ||
|
|
a5ea13f248 | ||
|
|
8796572704 |
@@ -25,13 +25,10 @@ GOTO:EOF
|
||||
|
||||
:getDependencies
|
||||
call:logInfo "Clone dependencies repository"
|
||||
git clone -q --depth 1 --branch=master https://github.com/telegramdesktop/dependencies_windows.git %LIB_DIR%
|
||||
git clone -q --depth 1 --branch master https://github.com/telegramdesktop/dependencies_windows.git %LIB_DIR%
|
||||
cd %LIB_DIR%
|
||||
|
||||
git clone https://github.com/ericniebler/range-v3
|
||||
cd range-v3
|
||||
git checkout 0.5.0
|
||||
cd ..
|
||||
git clone --depth 1 --branch 0.5.0 https://github.com/ericniebler/range-v3
|
||||
|
||||
if exist prepare.bat (
|
||||
call prepare.bat
|
||||
@@ -45,9 +42,9 @@ GOTO:EOF
|
||||
:setupGYP
|
||||
call:logInfo "Setup GYP/Ninja and generate VS solution"
|
||||
cd %LIB_DIR%
|
||||
git clone https://chromium.googlesource.com/external/gyp
|
||||
git clone https://github.com/telegramdesktop/gyp.git
|
||||
cd gyp
|
||||
git checkout a478c1ab51
|
||||
git checkout tdesktop
|
||||
SET PATH=%PATH%;%BUILD_DIR%\Libraries\gyp;%BUILD_DIR%\Libraries\ninja;
|
||||
cd %SRC_DIR%
|
||||
git submodule init
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report errors or unexpected behavior.
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for reporting issues of Telegram Desktop!
|
||||
|
||||
18
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea.
|
||||
title: "[Feature Request] "
|
||||
|
||||
---
|
||||
|
||||
### Is your feature request related to a problem?
|
||||
A clear and concise description of what the problem is.
|
||||
|
||||
### Describe the solution you'd like
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
### Describe alternatives you've considered
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
### Additional context
|
||||
Add any other context or screenshots about the feature request here.
|
||||
8
.github/ISSUE_TEMPLATE/QUESTION.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question.
|
||||
title: "[Question] "
|
||||
labels: 'question'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
12
.gitmodules
vendored
@@ -16,9 +16,9 @@
|
||||
[submodule "Telegram/ThirdParty/xxHash"]
|
||||
path = Telegram/ThirdParty/xxHash
|
||||
url = https://github.com/Cyan4973/xxHash.git
|
||||
[submodule "Telegram/ThirdParty/qtlottie"]
|
||||
path = Telegram/ThirdParty/qtlottie
|
||||
url = https://github.com/telegramdesktop/qtlottie.git
|
||||
[submodule "Telegram/ThirdParty/rapidjson"]
|
||||
path = Telegram/ThirdParty/rapidjson
|
||||
url = https://github.com/Tencent/rapidjson.git
|
||||
[submodule "Telegram/ThirdParty/rlottie"]
|
||||
path = Telegram/ThirdParty/rlottie
|
||||
url = https://github.com/john-preston/rlottie
|
||||
[submodule "Telegram/ThirdParty/lz4"]
|
||||
path = Telegram/ThirdParty/lz4
|
||||
url = https://github.com/lz4/lz4.git
|
||||
|
||||
@@ -28,7 +28,7 @@ GYP_CACHE_VERSION="3"
|
||||
GYP_PATCH="$UPSTREAM/Telegram/Patches/gyp.diff"
|
||||
|
||||
RANGE_PATH="$BUILD/range-v3"
|
||||
RANGE_CACHE_VERSION="3"
|
||||
RANGE_CACHE_VERSION="4"
|
||||
|
||||
VA_PATH="$BUILD/libva"
|
||||
VA_CACHE_VERSION="3"
|
||||
@@ -170,6 +170,7 @@ buildXkbCommon() {
|
||||
git clone https://github.com/xkbcommon/libxkbcommon.git
|
||||
|
||||
cd "$EXTERNAL/libxkbcommon"
|
||||
git checkout xkbcommon-0.8.4
|
||||
./autogen.sh --prefix=$XKB_PATH
|
||||
make $MAKE_ARGS
|
||||
sudo make install
|
||||
@@ -216,7 +217,7 @@ buildRange() {
|
||||
rm -rf *
|
||||
|
||||
cd "$EXTERNAL"
|
||||
git clone --depth=1 https://github.com/ericniebler/range-v3
|
||||
git clone --depth 1 --branch 0.5.0 https://github.com/ericniebler/range-v3
|
||||
|
||||
cd "$EXTERNAL/range-v3"
|
||||
cp -r * "$RANGE_PATH/"
|
||||
|
||||
@@ -92,6 +92,67 @@ index bcd29b6fe1..bcb0672f69 100644
|
||||
if (QPlatformCursor *platformCursor = q->screen()->handle()->cursor()) {
|
||||
QCursor *c = QGuiApplication::overrideCursor();
|
||||
if (!c && hasCursor)
|
||||
diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp
|
||||
index 8e0e76f787..a61bd62834 100644
|
||||
--- a/src/gui/painting/qbezier.cpp
|
||||
+++ b/src/gui/painting/qbezier.cpp
|
||||
@@ -45,6 +45,34 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
//#define QDEBUG_BEZIER
|
||||
|
||||
+// Patch: Workaround VS2019 compiler bug, see QTBUG-75280.
|
||||
+#ifdef Q_OS_WIN
|
||||
+Q_NEVER_INLINE void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const
|
||||
+{
|
||||
+ Q_ASSERT(firstHalf);
|
||||
+ Q_ASSERT(secondHalf);
|
||||
+
|
||||
+ qreal c = (x2 + x3)*.5;
|
||||
+ firstHalf->x2 = (x1 + x2)*.5;
|
||||
+ secondHalf->x3 = (x3 + x4)*.5;
|
||||
+ firstHalf->x1 = x1;
|
||||
+ secondHalf->x4 = x4;
|
||||
+ firstHalf->x3 = (firstHalf->x2 + c)*.5;
|
||||
+ secondHalf->x2 = (secondHalf->x3 + c)*.5;
|
||||
+ firstHalf->x4 = secondHalf->x1 = (firstHalf->x3 + secondHalf->x2)*.5;
|
||||
+
|
||||
+ c = (y2 + y3)/2;
|
||||
+ firstHalf->y2 = (y1 + y2)*.5;
|
||||
+ secondHalf->y3 = (y3 + y4)*.5;
|
||||
+ firstHalf->y1 = y1;
|
||||
+ secondHalf->y4 = y4;
|
||||
+ firstHalf->y3 = (firstHalf->y2 + c)*.5;
|
||||
+ secondHalf->y2 = (secondHalf->y3 + c)*.5;
|
||||
+ firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2)*.5;
|
||||
+}
|
||||
+// Patch: Workaround VS2019 compiler bug, see QTBUG-75280.
|
||||
+#endif // Q_OS_WIN
|
||||
+
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h
|
||||
index dd1cd94acf..aedc8b6a4b 100644
|
||||
--- a/src/gui/painting/qbezier_p.h
|
||||
+++ b/src/gui/painting/qbezier_p.h
|
||||
@@ -215,6 +215,8 @@ inline QPointF QBezier::secondDerivedAt(qreal t) const
|
||||
a * y1 + b * y2 + c * y3 + d * y4);
|
||||
}
|
||||
|
||||
+// Patch: Workaround VS2019 compiler bug, see QTBUG-75280.
|
||||
+#ifndef Q_OS_WIN
|
||||
inline void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const
|
||||
{
|
||||
Q_ASSERT(firstHalf);
|
||||
@@ -238,6 +240,8 @@ inline void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const
|
||||
secondHalf->y2 = (secondHalf->y3 + c)*.5;
|
||||
firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2)*.5;
|
||||
}
|
||||
+// Patch: Workaround VS2019 compiler bug, see QTBUG-75280.
|
||||
+#endif // Q_OS_WIN
|
||||
|
||||
inline void QBezier::parameterSplitLeft(qreal t, QBezier *left)
|
||||
{
|
||||
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
|
||||
index 918c98997b..4158259743 100644
|
||||
--- a/src/gui/painting/qpaintengine_p.h
|
||||
@@ -234,6 +295,40 @@ index c4cb8e65c0..45793e364f 100644
|
||||
channels[i].socket->close();
|
||||
delete channels[i].socket;
|
||||
}
|
||||
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||
index 94235a48dd..9abd2cc0a1 100644
|
||||
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||
@@ -2045,6 +2045,9 @@ void QNetworkReplyHttpImplPrivate::finished()
|
||||
{
|
||||
Q_Q(QNetworkReplyHttpImpl);
|
||||
|
||||
+ // Patch: Fix crash in Linux (by crashreports).
|
||||
+ QPointer<QNetworkReplyHttpImpl> guard = q;
|
||||
+
|
||||
if (state == Finished || state == Aborted || state == WaitingForSession)
|
||||
return;
|
||||
|
||||
@@ -2075,6 +2078,9 @@ void QNetworkReplyHttpImplPrivate::finished()
|
||||
#endif
|
||||
}
|
||||
|
||||
+ // Patch: Fix crash in Linux (by crashreports).
|
||||
+ if (!guard) return;
|
||||
+
|
||||
// if we don't know the total size of or we received everything save the cache
|
||||
if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
|
||||
completeCacheSave();
|
||||
@@ -2084,6 +2090,9 @@ void QNetworkReplyHttpImplPrivate::finished()
|
||||
if (isHttpRedirectResponse() && errorCode == QNetworkReply::NoError)
|
||||
return;
|
||||
|
||||
+ // Patch: Fix crash in Linux (by crashreports).
|
||||
+ if (!guard) return;
|
||||
+
|
||||
state = Finished;
|
||||
q->setFinished(true);
|
||||
|
||||
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
|
||||
index 41834b21ae..8cdf4ab145 100644
|
||||
--- a/src/network/socket/qnativesocketengine_win.cpp
|
||||
@@ -253,7 +348,7 @@ index 41834b21ae..8cdf4ab145 100644
|
||||
setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
|
||||
socketState = QAbstractSocket::UnconnectedState;
|
||||
diff --git a/src/platformsupport/cglconvenience/cglconvenience.mm b/src/platformsupport/cglconvenience/cglconvenience.mm
|
||||
index fb609ae485..7cca45ded4 100644
|
||||
index fb609ae485..ef1c638d91 100644
|
||||
--- a/src/platformsupport/cglconvenience/cglconvenience.mm
|
||||
+++ b/src/platformsupport/cglconvenience/cglconvenience.mm
|
||||
@@ -128,7 +128,12 @@ void *qcgl_createNSOpenGLPixelFormat(const QSurfaceFormat &format)
|
||||
@@ -264,7 +359,7 @@ index fb609ae485..7cca45ded4 100644
|
||||
+ // Patch: Fix macOS regression. On 10.14.4, it crashes on GPU switches.
|
||||
+ // See https://bugreports.qt.io/browse/QTCREATORBUG-22215
|
||||
+ static const QAppleOperatingSystemVersion version = qt_apple_os_version();
|
||||
+ if (!(version.major == 10 && version.minor == 14 && version.patch == 4))
|
||||
+ if (!(version.major == 10 && version.minor == 14 && version.patch == 4)) {
|
||||
+ attrs << NSOpenGLPFAAllowOfflineRenderers;
|
||||
+ }
|
||||
|
||||
|
||||
@@ -72,8 +72,11 @@ linkCropLimit: 360px;
|
||||
linkFont: normalFont;
|
||||
linkOverFont: font(fsize underline);
|
||||
|
||||
dateRadius: 6px;
|
||||
buttonRadius: 3px;
|
||||
roundRadiusLarge: 6px;
|
||||
roundRadiusSmall: 3px;
|
||||
|
||||
dateRadius: roundRadiusLarge;
|
||||
buttonRadius: roundRadiusSmall;
|
||||
|
||||
setLittleSkip: 9px;
|
||||
|
||||
|
||||
@@ -51,11 +51,6 @@ attentionButtonFgOver: #d14e4e; // default attention button text with mouse over
|
||||
attentionButtonBgOver: #fcdfde; // default attention button background with mouse over
|
||||
attentionButtonBgRipple: #f4c3c2; // default attention button ripple effect
|
||||
|
||||
outlineButtonBg: windowBg; // default left outlined button background (like shared media links in profiles)
|
||||
outlineButtonBgOver: lightButtonBgOver; // default left outlined button background with mouse over
|
||||
outlineButtonOutlineFg: windowBgActive; // default left outlined button left outline border
|
||||
outlineButtonBgRipple: lightButtonBgRipple; // default left outlined button ripple effect
|
||||
|
||||
menuBg: windowBg; // default popup menu background
|
||||
menuBgOver: windowBgOver; // default popup menu item background with mouse over
|
||||
menuBgRipple: windowBgRipple; // default popup menu item ripple effect
|
||||
@@ -194,6 +189,8 @@ dialogsUnreadBg: windowBgActive; // chat list unread badge background for not mu
|
||||
dialogsUnreadBgMuted: #bbbbbb; // chat list unread badge background for muted chat
|
||||
dialogsUnreadFg: windowFgActive; // chat list unread badge text
|
||||
dialogsArchiveFg: #525252 | dialogsNameFg; // chat list archive name text
|
||||
dialogsOnlineBadgeFg: #4dc920 | dialogsUnreadBg; // chat list online status
|
||||
dialogsScamFg: dialogsDraftFg; // chat list scam label
|
||||
|
||||
dialogsBgOver: windowBgOver; // chat list background with mouse over
|
||||
dialogsNameFgOver: windowBoldFgOver; // chat list name text with mouse over
|
||||
@@ -209,7 +206,8 @@ dialogsSentIconFgOver: dialogsSentIconFg; // chat list sent message tick / doubl
|
||||
dialogsUnreadBgOver: dialogsUnreadBg; // chat list unread badge background for not muted chat with mouse over
|
||||
dialogsUnreadBgMutedOver: dialogsUnreadBgMuted; // chat list unread badge background for muted chat with mouse over
|
||||
dialogsUnreadFgOver: dialogsUnreadFg; // chat list unread badge text with mouse over
|
||||
dialogsArchiveFgOver: #525252 | dialogsNameFgOver; // chat list archive name text
|
||||
dialogsArchiveFgOver: #525252 | dialogsNameFgOver; // chat list archive name text with mouse over
|
||||
dialogsScamFgOver: dialogsDraftFgOver; // chat list scam label with mouse over
|
||||
|
||||
dialogsBgActive: #419fd9; // chat list background for current (active) chat
|
||||
dialogsNameFgActive: windowFgActive; // chat list name text for current (active) chat
|
||||
@@ -225,6 +223,8 @@ dialogsSentIconFgActive: dialogsTextFgActive; // chat list sent message tick / d
|
||||
dialogsUnreadBgActive: dialogsTextFgActive; // chat list unread badge background for not muted chat for current (active) chat
|
||||
dialogsUnreadBgMutedActive: dialogsDraftFgActive; // chat list unread badge background for muted chat for current (active) chat
|
||||
dialogsUnreadFgActive: dialogsBgActive; // chat list unread badge text for current (active) chat
|
||||
dialogsOnlineBadgeFgActive: #ffffff; // chat list online status for current (active) chat
|
||||
dialogsScamFgActive: dialogsDraftFgActive; // chat list scam label for current (active) chat
|
||||
|
||||
dialogsRippleBg: windowBgRipple; // chat list background ripple effect
|
||||
dialogsRippleBgActive: activeButtonBgRipple; // chat list background ripple effect for current (active) chat
|
||||
@@ -553,3 +553,7 @@ callBarFg: dialogsNameFgActive; // phone call bar text and icons
|
||||
importantTooltipBg: toastBg;
|
||||
importantTooltipFg: toastFg;
|
||||
importantTooltipFgLink: mediaviewTextLinkFg;
|
||||
|
||||
outdatedFg: #ffffff;
|
||||
outdateSoonBg: #e08543;
|
||||
outdatedBg: #e05745;
|
||||
|
||||
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 833 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 812 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
Telegram/Resources/icons/send_control_schedule.png
Normal file
|
After Width: | Height: | Size: 743 B |
BIN
Telegram/Resources/icons/send_control_schedule@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/send_control_schedule@3x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram/Resources/icons/send_control_scheduled.png
Normal file
|
After Width: | Height: | Size: 362 B |
BIN
Telegram/Resources/icons/send_control_scheduled@2x.png
Normal file
|
After Width: | Height: | Size: 652 B |
BIN
Telegram/Resources/icons/send_control_scheduled@3x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/send_control_scheduled_dot.png
Normal file
|
After Width: | Height: | Size: 221 B |
BIN
Telegram/Resources/icons/send_control_scheduled_dot@2x.png
Normal file
|
After Width: | Height: | Size: 406 B |
BIN
Telegram/Resources/icons/send_control_scheduled_dot@3x.png
Normal file
|
After Width: | Height: | Size: 622 B |
BIN
Telegram/Resources/icons/theme_preview.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/theme_preview@2x.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
Telegram/Resources/icons/theme_preview@3x.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
@@ -76,7 +76,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_month_day_year" = "{month} {day}, {year}";
|
||||
"lng_month_year" = "{month} {year}";
|
||||
|
||||
"lng_calendar_beginning" = "Beginning";
|
||||
|
||||
"lng_box_ok" = "OK";
|
||||
"lng_box_done" = "Done";
|
||||
|
||||
"lng_cancel" = "Cancel";
|
||||
"lng_continue" = "Continue";
|
||||
@@ -118,6 +121,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_channel_status" = "channel";
|
||||
"lng_group_status" = "group";
|
||||
"lng_scam_badge" = "SCAM";
|
||||
|
||||
"lng_flood_error" = "Too many tries. Please try again later.";
|
||||
"lng_gif_error" = "An error has occurred while reading GIF animation :(";
|
||||
@@ -143,6 +147,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_sure_ban_admin" = "This user is an admin. Are you sure you want to go ahead and restrict them?";
|
||||
"lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in the Settings (Connection Type).";
|
||||
"lng_sure_enable" = "Enable";
|
||||
"lng_proxy_invalid" = "The proxy link is invalid.";
|
||||
"lng_proxy_unsupported" = "Your Telegram Desktop version doesn't support this proxy type or the proxy link is invalid. Please update Telegram Desktop to the latest version.";
|
||||
|
||||
"lng_edit_deleted" = "This message was deleted";
|
||||
"lng_edit_too_long" = "Your message text is too long";
|
||||
@@ -160,6 +166,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_edit_media_album_error" = "This file cannot be saved as a part of an album.";
|
||||
"lng_edit_media_invalid_file" = "Sorry, no way to use this file.";
|
||||
"lng_edit_caption_attach" = "Sorry, you can't attach a new media while you're editing your message.";
|
||||
|
||||
"lng_intro_about" = "Welcome to the official Telegram Desktop app.\nIt's fast and secure.";
|
||||
"lng_start_msgs" = "START MESSAGING";
|
||||
@@ -173,7 +180,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_phone_title" = "Your Phone Number";
|
||||
"lng_phone_desc" = "Please confirm your country code and\nenter your mobile phone number.";
|
||||
"lng_phone_notreg" = "If you don't have a Telegram account yet,\nplease [b]sign up[/b] with {link_start}Android / iPhone{link_end} or {signup_start}here{signup_end}";
|
||||
"lng_country_code" = "Country Code";
|
||||
"lng_bad_country_code" = "Invalid Country Code";
|
||||
"lng_country_ph" = "Search";
|
||||
@@ -182,7 +188,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_code_ph" = "Your code";
|
||||
"lng_code_desc" = "We have sent you a message with activation\ncode to your phone. Please enter it below.";
|
||||
"lng_code_telegram" = "Please enter the code you've just received\nin your previous [b]Telegram[/b] app.";
|
||||
"lng_code_from_telegram" = "Please enter the code you've just received\nin your previous **Telegram** app.";
|
||||
"lng_code_no_telegram" = "Send code via SMS";
|
||||
"lng_code_call" = "Telegram will call you in {minutes}:{seconds}";
|
||||
"lng_code_calling" = "Requesting a call from Telegram...";
|
||||
@@ -294,6 +300,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_notification_reply" = "Reply";
|
||||
"lng_notification_hide_all" = "Hide all";
|
||||
"lng_notification_sample" = "This is a sample notification";
|
||||
"lng_notification_reminder" = "Reminder";
|
||||
|
||||
"lng_settings_section_general" = "General";
|
||||
"lng_settings_change_lang" = "Change language";
|
||||
@@ -322,6 +329,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_replace_emojis" = "Replace emoji";
|
||||
"lng_settings_suggest_emoji" = "Suggest emoji replacements";
|
||||
"lng_settings_suggest_by_emoji" = "Suggest popular stickers by emoji";
|
||||
"lng_settings_loop_stickers" = "Loop animated stickers";
|
||||
"lng_settings_large_emoji" = "Large emoji";
|
||||
"lng_settings_view_emojis" = "View list";
|
||||
"lng_settings_send_enter" = "Send by Enter";
|
||||
"lng_settings_send_ctrlenter" = "Send by Ctrl+Enter";
|
||||
@@ -331,7 +340,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_bg_use_default" = "Use default color theme";
|
||||
"lng_settings_bg_from_gallery" = "Choose from gallery";
|
||||
"lng_settings_bg_from_file" = "Choose from file";
|
||||
"lng_settings_bg_edit_theme" = "Launch theme editor";
|
||||
"lng_settings_bg_theme_edit" = "Edit theme";
|
||||
"lng_settings_bg_theme_create" = "Create new theme";
|
||||
"lng_settings_bg_cloud_themes" = "Custom themes";
|
||||
"lng_settings_bg_show_all" = "Show all themes";
|
||||
"lng_settings_bg_tile" = "Tile background";
|
||||
"lng_settings_adaptive_wide" = "Adaptive layout for wide screens";
|
||||
|
||||
@@ -380,6 +392,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_stickers_emoji" = "Stickers and emoji";
|
||||
"lng_settings_messages" = "Messages";
|
||||
"lng_settings_themes" = "Themes";
|
||||
"lng_settings_theme_day" = "Day";
|
||||
"lng_settings_theme_classic" = "Classic";
|
||||
"lng_settings_theme_tinted" = "Tinted";
|
||||
"lng_settings_theme_night" = "Night";
|
||||
"lng_settings_theme_accent_title" = "Choose accent color";
|
||||
"lng_settings_data_storage" = "Data and storage";
|
||||
"lng_settings_information" = "Edit profile";
|
||||
"lng_settings_passcode_title" = "Local passcode";
|
||||
@@ -399,6 +416,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_theme_reverting#other" = "Reverting to the old theme in {count} seconds.";
|
||||
"lng_theme_keep_changes" = "Keep changes";
|
||||
"lng_theme_revert" = "Revert";
|
||||
"lng_theme_no_desktop" = "Sorry, this theme doesn't include a version for Telegram Desktop.";
|
||||
"lng_theme_share" = "Share";
|
||||
"lng_theme_edit" = "Edit";
|
||||
"lng_theme_delete" = "Delete";
|
||||
"lng_theme_delete_sure" = "Are you sure you want to delete this theme?";
|
||||
"lng_background_header" = "Background preview";
|
||||
"lng_background_text1" = "Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff!";
|
||||
"lng_background_text2" = "I can't even take you seriously right now.";
|
||||
@@ -559,6 +581,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_proxy_sponsor_warning" = "This proxy may display a sponsored channel in your chat list. This doesn't reveal any of your Telegram traffic.";
|
||||
|
||||
"lng_settings_blocked_users" = "Blocked users";
|
||||
"lng_settings_no_blocked_users" = "None";
|
||||
"lng_settings_show_sessions" = "Show all sessions";
|
||||
"lng_settings_export_data" = "Export Telegram data";
|
||||
"lng_settings_destroy_if" = "If away for...";
|
||||
@@ -591,12 +614,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_blocked_list_title" = "Blocked users";
|
||||
"lng_blocked_list_unknown_phone" = "unknown phone number";
|
||||
"lng_blocked_list_unblock" = "Unblock";
|
||||
"lng_blocked_list_restart" = "Restart";
|
||||
"lng_blocked_list_add" = "Block user";
|
||||
"lng_blocked_list_add_title" = "Select user to block";
|
||||
"lng_blocked_list_already_blocked" = "blocked already";
|
||||
"lng_blocked_list_about" = "Blocked users can't send you messages or add you to groups. They will not see your profile pictures, online and last seen status.";
|
||||
"lng_blocked_list_not_found" = "No users found.";
|
||||
"lng_blocked_list_confirm_title" = "Block {name}";
|
||||
"lng_blocked_list_confirm_text" = "Do you want to block {name} from messaging and calling you on Telegram?";
|
||||
"lng_blocked_list_confirm_clear" = "Delete this chat";
|
||||
"lng_blocked_list_confirm_ok" = "Block";
|
||||
|
||||
"lng_edit_privacy_everyone" = "Everybody";
|
||||
"lng_edit_privacy_contacts" = "My contacts";
|
||||
@@ -609,13 +635,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_edit_privacy_phone_number_title" = "Phone number privacy";
|
||||
"lng_edit_privacy_phone_number_header" = "Who can see your phone number";
|
||||
"lng_edit_privacy_phone_number_warning" = "Important: blabla.";
|
||||
"lng_edit_privacy_phone_number_warning" = "Users who already have your number saved in the contacts will also see it on Telegram.";
|
||||
"lng_edit_privacy_phone_number_always_empty" = "Always share with";
|
||||
"lng_edit_privacy_phone_number_never_empty" = "Never share with";
|
||||
"lng_edit_privacy_phone_number_exceptions" = "These settings will override the values above.";
|
||||
"lng_edit_privacy_phone_number_always_title" = "Always share with";
|
||||
"lng_edit_privacy_phone_number_never_title" = "Never share with";
|
||||
|
||||
"lng_edit_privacy_phone_number_find" = "Who can find me by my number";
|
||||
"lng_edit_privacy_phone_number_contacts" = "Users who add your number to their contacts will see it on Telegram only if they are your contacts.";
|
||||
|
||||
"lng_edit_privacy_lastseen_title" = "Last seen privacy";
|
||||
"lng_edit_privacy_lastseen_header" = "Who can see your last seen time";
|
||||
"lng_edit_privacy_lastseen_warning" = "Important: you won't be able to see Last Seen times for people with whom you don't share your Last Seen time. Approximate last seen will be shown instead (recently, within a week, within a month).";
|
||||
@@ -682,7 +711,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_self_destruct_years#other" = "{count} years";
|
||||
|
||||
"lng_change_phone_title" = "Change phone number";
|
||||
"lng_change_phone_description" = "You can change your Telegram number\nhere. Your account and all your cloud data\n— messages, media, contacts, etc. will be\nmoved to the new number.\n\n[b]Important[/b]: all your Telegram contacts will\nget your [b]new number[/b] added to their address\nbook, provided they had your old number and\nyou haven't blocked them in Telegram.";
|
||||
"lng_change_phone_about" = "You can change your Telegram number\nhere. Your account and all your cloud data\n— messages, media, contacts, etc. will be\nmoved to the new number.\n\n**Important**: all your Telegram contacts will\nget your **new number** added to their address\nbook, provided they had your old number and\nyou haven't blocked them in Telegram.";
|
||||
"lng_change_phone_warning" = "All your Telegram contacts will get your new number added to their address book, provided they had your old number and you haven't blocked them in Telegram.";
|
||||
"lng_change_phone_occupied" = "The number {phone} is already connected to a Telegram account. Please delete that account before migrating to the new number.";
|
||||
"lng_change_phone_button" = "Change number";
|
||||
@@ -773,9 +802,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_info_section" = "Info";
|
||||
"lng_info_tab_media" = "Media";
|
||||
"lng_info_mobile_label" = "Mobile";
|
||||
"lng_info_mobile_hidden" = "Hidden";
|
||||
"lng_info_username_label" = "Username";
|
||||
"lng_info_bio_label" = "Bio";
|
||||
"lng_info_link_label" = "Link";
|
||||
"lng_info_location_label" = "Location";
|
||||
"lng_info_about_label" = "About";
|
||||
"lng_info_user_title" = "User Info";
|
||||
"lng_info_bot_title" = "Bot Info";
|
||||
@@ -783,7 +814,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_info_channel_title" = "Channel Info";
|
||||
"lng_profile_enable_notifications" = "Notifications";
|
||||
"lng_profile_send_message" = "Send Message";
|
||||
"lng_info_add_as_contact" = "Add as contact";
|
||||
"lng_info_add_as_contact" = "Add to contacts";
|
||||
"lng_profile_shared_media" = "Shared media";
|
||||
"lng_media_type_photos" = "Photos";
|
||||
"lng_media_type_videos" = "Videos";
|
||||
@@ -840,6 +871,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_manage_peer_group_type" = "Group type";
|
||||
"lng_manage_peer_channel_type" = "Channel type";
|
||||
"lng_manage_peer_link_type" = "Link type";
|
||||
"lng_manage_peer_link_permanent" = "Permanent link";
|
||||
"lng_manage_peer_link_invite" = "Invite link";
|
||||
"lng_manage_private_group_title" = "Private";
|
||||
"lng_manage_public_group_title" = "Public";
|
||||
"lng_manage_private_peer_title" = "Private";
|
||||
@@ -855,12 +889,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_manage_discussion_group_unlink" = "Unlink group";
|
||||
"lng_manage_discussion_group_posted" = "Everything you post in the channel is forwarded to this group.";
|
||||
"lng_manage_discussion_group_sure" = "Do you want to make {group} the discussion board for {channel}?";
|
||||
"lng_manage_linked_channel_private" = "Any member in this group will be able to see the messages in the channel.";
|
||||
"lng_manage_linked_channel_private" = "Any member of this group will be able to see messages in the channel.";
|
||||
"lng_manage_discussion_group_private" = "Anyone from the channel will be able to see messages in this group.";
|
||||
"lng_manage_discussion_group_link" = "Link group";
|
||||
"lng_manage_discussion_group_private" = "private group";
|
||||
"lng_manage_linked_channel_private_status" = "private channel";
|
||||
"lng_manage_discussion_group_private_status" = "private group";
|
||||
"lng_manage_linked_channel_about" = "{channel} is linking the group as its discussion board.";
|
||||
"lng_manage_linked_channel_unlink" = "Unlink channel";
|
||||
"lng_manage_linked_channel_posted" = "All new messages posted in this channel are forwarded to the group.";
|
||||
"lng_manage_discussion_group_warning" = "\"Chat history for new members\" will be switched to **Visible**.";
|
||||
|
||||
"lng_manage_history_visibility_title" = "Chat history for new members";
|
||||
"lng_manage_history_visibility_shown" = "Visible";
|
||||
@@ -918,6 +955,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_create_public_group_about" = "Anyone can find the group in search and join, chat history is available to everybody";
|
||||
"lng_create_private_group_title" = "Private Group";
|
||||
"lng_create_private_group_about" = "People can only join if they were invited or have an invite link";
|
||||
"lng_create_permanent_link_title" = "Permanent link";
|
||||
"lng_create_invite_link_title" = "Invite link";
|
||||
"lng_create_invite_link_about" = "People can join if they were invited, have an invite link, or from \"Groups nearby\"";
|
||||
|
||||
"lng_create_group_skip" = "Skip";
|
||||
|
||||
"lng_create_channel_link_about" = "You can use a-z, 0-9 and underscores.\nMinimum length is 5 characters.";
|
||||
@@ -1041,6 +1082,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_channels_too_much_public_revoke_confirm_group" = "Are you sure you want to revoke the link {link}?\n\nThe group «{group}» will become private.";
|
||||
"lng_channels_too_much_public_revoke_confirm_channel" = "Are you sure you want to revoke the link {link}?\n\nThe channel «{group}» will become private.";
|
||||
"lng_channels_too_much_public_revoke" = "Revoke";
|
||||
"lng_channels_too_much_public_other" = "Sorry, the target user has too many public groups or channels already. Please ask them to make one of their existing groups or channels private first.";
|
||||
"lng_channels_too_much_located_other" = "Sorry, the target user has too many location-based groups already. Please ask them to delete or transfer one of their existing ones first.";
|
||||
|
||||
"lng_group_invite_bad_link" = "This invite link is broken or has expired.";
|
||||
"lng_group_invite_join" = "Join";
|
||||
@@ -1071,6 +1114,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edited" = "edited";
|
||||
"lng_edited_date" = "Edited: {date}";
|
||||
"lng_admin_badge" = "admin";
|
||||
"lng_owner_badge" = "owner";
|
||||
"lng_channel_badge" = "channel";
|
||||
"lng_fast_reply" = "Reply";
|
||||
"lng_cancel_edit_post_sure" = "Cancel editing?";
|
||||
@@ -1106,6 +1150,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_media_size_limit" = "Limit by size";
|
||||
"lng_media_size_up_to" = "up to {size}";
|
||||
"lng_media_chat_background" = "Chat background";
|
||||
"lng_media_color_theme" = "Color theme";
|
||||
|
||||
"lng_emoji_category1" = "People";
|
||||
"lng_emoji_category2" = "Nature";
|
||||
@@ -1186,12 +1231,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_ban_user" = "Ban User";
|
||||
"lng_delete_all_from" = "Delete all from this user";
|
||||
"lng_report_spam" = "Report Spam";
|
||||
"lng_report_spam_hide" = "Hide";
|
||||
"lng_report_spam_thanks" = "Thank you for your report!";
|
||||
"lng_report_spam_sure" = "Are you sure you want to report spam from this user?";
|
||||
"lng_report_spam_and_leave" = "Report spam and leave";
|
||||
"lng_report_spam_done" = "Thank you for your report.";
|
||||
"lng_report_spam_sure_group" = "Are you sure you want to report spam in this group?";
|
||||
"lng_report_spam_sure_channel" = "Are you sure you want to report spam in this channel?";
|
||||
"lng_report_spam_ok" = "Report";
|
||||
"lng_new_contact_block" = "Block user";
|
||||
"lng_new_contact_block_done" = "{user} is now blocked.";
|
||||
"lng_new_contact_add" = "Add contact";
|
||||
"lng_new_contact_share" = "Share my phone number";
|
||||
"lng_new_contact_share_sure" = "Are you sure you want to share your phone number {phone} with {user}?";
|
||||
"lng_new_contact_share_done" = "{user} can now see your phone number.";
|
||||
"lng_new_contact_add_name" = "Add {user} to contacts";
|
||||
"lng_new_contact_add_done" = "{user} is now in your contact list.";
|
||||
"lng_cant_send_to_not_contact" = "Sorry, you can only send messages to\nmutual contacts at the moment.\n{more_info}";
|
||||
"lng_cant_invite_not_contact" = "Sorry, you can only add mutual contacts\nto groups at the moment.\n{more_info}";
|
||||
"lng_cant_more_info" = "More info »";
|
||||
@@ -1204,6 +1256,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_cant_invite_make_admin" = "Make admin";
|
||||
|
||||
"lng_send_button" = "Send";
|
||||
"lng_send_silent_message" = "Send without sound";
|
||||
"lng_schedule_message" = "Schedule message";
|
||||
"lng_reminder_message" = "Set a reminder";
|
||||
"lng_schedule_title" = "Send this message on...";
|
||||
"lng_remind_title" = "Remind me on...";
|
||||
"lng_schedule_at" = "at";
|
||||
"lng_message_ph" = "Write a message...";
|
||||
"lng_broadcast_ph" = "Broadcast a message...";
|
||||
"lng_broadcast_silent_ph" = "Silent broadcast...";
|
||||
@@ -1223,6 +1281,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_saved_short" = "Save";
|
||||
"lng_saved_forward_here" = "Forward messages here for quick access";
|
||||
|
||||
"lng_scheduled_messages" = "Scheduled Messages";
|
||||
"lng_reminder_messages" = "Reminders";
|
||||
"lng_scheduled_send_now" = "Send message now?";
|
||||
"lng_scheduled_send_now_many#one" = "Send {count} message now?";
|
||||
"lng_scheduled_send_now_many#other" = "Send {count} messages now?";
|
||||
|
||||
"lng_archived_name" = "Archived chats";
|
||||
"lng_archived_add" = "Archive";
|
||||
"lng_archived_remove" = "Unarchive";
|
||||
@@ -1238,6 +1302,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_dialogs_text_media_wrapped" = "{media},";
|
||||
"lng_dialogs_show_all_chats" = "Show all chats";
|
||||
"lng_dialogs_hide_muted_chats" = "Hide muted chats";
|
||||
"lng_dialogs_skip_archive_in_search" = "Skip results from archive";
|
||||
"lng_dialogs_show_archive_in_search" = "With results from archive";
|
||||
|
||||
"lng_open_this_link" = "Open this link?";
|
||||
"lng_open_link" = "Open";
|
||||
@@ -1314,6 +1380,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_mark_read" = "Mark as read";
|
||||
"lng_context_archive_expand" = "Expand";
|
||||
"lng_context_archive_collapse" = "Collapse";
|
||||
"lng_context_archive_to_menu" = "Move to main menu";
|
||||
"lng_context_archive_to_list" = "Move to chats list";
|
||||
"lng_context_archive_to_menu_info" = "Archive moved to the main menu!\nYou can return it from the context menu of the archive button.";
|
||||
|
||||
"lng_context_promote_admin" = "Promote to admin";
|
||||
"lng_context_edit_permissions" = "Edit permissions";
|
||||
@@ -1345,6 +1414,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_reply_msg" = "Reply";
|
||||
"lng_context_edit_msg" = "Edit";
|
||||
"lng_context_forward_msg" = "Forward Message";
|
||||
"lng_context_send_now_msg" = "Send now";
|
||||
"lng_context_delete_msg" = "Delete Message";
|
||||
"lng_context_select_msg" = "Select Message";
|
||||
"lng_context_report_msg" = "Report Message";
|
||||
@@ -1354,6 +1424,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_copy_selected" = "Copy Selected Text";
|
||||
"lng_context_copy_selected_items" = "Copy Selected as Text";
|
||||
"lng_context_forward_selected" = "Forward Selected";
|
||||
"lng_context_send_now_selected" = "Send selected now";
|
||||
"lng_context_delete_selected" = "Delete Selected";
|
||||
"lng_context_clear_selection" = "Clear Selection";
|
||||
"lng_send_image_empty" = "Could not send an empty file: {name}";
|
||||
@@ -1401,6 +1472,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_contact_phone" = "Phone Number";
|
||||
"lng_enter_contact_data" = "New Contact";
|
||||
"lng_contact_mobile_hidden" = "Mobile hidden";
|
||||
"lng_contact_phone_after" = "Phone number will be visible once {user} adds you as a contact.";
|
||||
"lng_contact_share_phone" = "Share my phone number";
|
||||
"lng_contact_phone_will_be_shared" = "You can make your phone visible to {user}.";
|
||||
"lng_edit_contact_title" = "Edit contact name";
|
||||
"lng_edit_channel_title" = "Edit channel";
|
||||
"lng_edit_sign_messages" = "Sign messages";
|
||||
@@ -1427,6 +1502,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_selected_clear" = "Cancel";
|
||||
"lng_selected_delete" = "Delete";
|
||||
"lng_selected_forward" = "Forward";
|
||||
"lng_selected_send_now" = "Send now";
|
||||
"lng_selected_cancel_sure_this" = "Cancel uploading?";
|
||||
"lng_selected_upload_stop" = "Stop";
|
||||
"lng_selected_delete_sure_this" = "Do you want to delete this message?";
|
||||
@@ -1452,9 +1528,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_box_leave" = "Leave";
|
||||
|
||||
"lng_about_version" = "version {version}";
|
||||
"lng_about_text_1" = "Official free messaging app based on [a href=\"https://core.telegram.org/api\"]Telegram API[/a]\nfor speed and security.";
|
||||
"lng_about_text_2" = "This software is licensed under [a href=\"https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\"]GNU GPL[/a] version 3.\nSource code is available on [a href=\"https://github.com/telegramdesktop/tdesktop\"]GitHub[/a].";
|
||||
"lng_about_text_3" = "Visit {faq_open}Telegram FAQ{faq_close} for more info.";
|
||||
"lng_about_text1" = "Official free messaging app based on {api_link}\nfor speed and security.";
|
||||
"lng_about_text1_api" = "Telegram API";
|
||||
"lng_about_text2" = "This software is licensed under {gpl_link} version 3.\nSource code is available on {github_link}.";
|
||||
"lng_about_text3" = "Visit {faq_link} for more info.";
|
||||
"lng_about_text3_faq" = "Telegram FAQ";
|
||||
"lng_about_done" = "Done";
|
||||
|
||||
"lng_search_no_results" = "No messages found";
|
||||
@@ -1474,19 +1552,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_mediaview_group_photo" = "Group Photo";
|
||||
"lng_mediaview_channel_photo" = "Channel Photo";
|
||||
"lng_mediaview_profile_photo" = "Profile Photo";
|
||||
"lng_mediaview_file_n_of_count" = "{file} {n} of {count}";
|
||||
"lng_mediaview_n_of_count" = "Photo {n} of {count}";
|
||||
"lng_mediaview_file_n_of_amount" = "{file} {n} of {amount}";
|
||||
"lng_mediaview_n_of_amount" = "Photo {n} of {amount}";
|
||||
"lng_mediaview_doc_image" = "File";
|
||||
"lng_mediaview_today" = "today at {time}";
|
||||
"lng_mediaview_yesterday" = "yesterday at {time}";
|
||||
"lng_mediaview_date_time" = "{date} at {time}";
|
||||
|
||||
"lng_mediaview_saved" = "Image was saved to your [c]Downloads[/c] folder";
|
||||
"lng_mediaview_saved_to" = "Image was saved to your {downloads} folder";
|
||||
"lng_mediaview_downloads" = "Downloads";
|
||||
"lng_mediaview_video_loading" = "Loading - {percent}";
|
||||
|
||||
"lng_theme_preview_title" = "Theme Preview";
|
||||
"lng_theme_preview_generating" = "Generating color theme preview...";
|
||||
"lng_theme_preview_invalid" = "Invalid data in this theme file.";
|
||||
"lng_theme_preview_apply" = "Apply this theme";
|
||||
"lng_theme_preview_users#one" = "{count} person is using this theme";
|
||||
"lng_theme_preview_users#other" = "{count} people are using this theme";
|
||||
|
||||
"lng_new_authorization" = "{name},\nWe detected a login into your account from a new device on {day}, {date} at {time}\n\nDevice: {device}\nLocation: {location}\n\nIf this wasn't you, you can go to Settings — Show all sessions and terminate that session.\n\nIf you think that somebody logged in to your account against your will, you can enable two-step verification in Settings.\n\nSincerely,\nThe Telegram Team";
|
||||
|
||||
@@ -1497,6 +1579,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_menu_formatting" = "Formatting";
|
||||
"lng_menu_formatting_bold" = "Bold";
|
||||
"lng_menu_formatting_italic" = "Italic";
|
||||
"lng_menu_formatting_underline" = "Underline";
|
||||
"lng_menu_formatting_strike_out" = "Strike-through";
|
||||
"lng_menu_formatting_monospace" = "Monospace";
|
||||
"lng_menu_formatting_link_create" = "Create link";
|
||||
"lng_menu_formatting_link_edit" = "Edit link";
|
||||
@@ -1528,9 +1612,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_theme_editor_save_palette" = "Save palette file";
|
||||
"lng_theme_editor_choose_name" = "Save theme file";
|
||||
"lng_theme_editor_error" = "The editor encountered an error :( See 'log.txt' for details.";
|
||||
"lng_theme_editor_sure_close" = "Are you sure you want to close the editor? Your changes won't be saved.";
|
||||
"lng_theme_editor_need_auth" = "You need to log in to save your theme.";
|
||||
"lng_theme_editor_need_unlock" = "You need to unlock Telegram to save your theme.";
|
||||
"lng_theme_editor_done" = "Theme exported successfully!";
|
||||
"lng_theme_editor_title" = "Edit color palette";
|
||||
"lng_theme_editor_export_button" = "Export theme";
|
||||
"lng_theme_editor_save_button" = "Save theme";
|
||||
|
||||
"lng_theme_editor_create_title" = "Create theme";
|
||||
"lng_theme_editor_attach_title" = "Attach desktop theme";
|
||||
"lng_theme_editor_create" = "Create";
|
||||
"lng_theme_editor_name" = "Theme name";
|
||||
"lng_theme_editor_create_description" = "New theme will be based on your currently selected colors and wallpaper. Alternatively, you can import existing theme or color palette from file.";
|
||||
"lng_theme_editor_attach_description" = "You can create desktop part of your theme based on your currently selected colors and wallpaper. Alternatively, you can import existing theme or color palette from file.";
|
||||
"lng_theme_editor_import_existing" = "Import existing theme";
|
||||
"lng_theme_editor_save_title" = "Save theme";
|
||||
"lng_theme_editor_link_about" = "Your theme will be updated for all users each time you change it. Anyone can install it using this link.\n\nTheme links must be longer than 5 characters and use a-z, 0-9 and underscores.";
|
||||
|
||||
"lng_theme_editor_menu_export" = "Export theme";
|
||||
"lng_theme_editor_menu_import" = "Import theme";
|
||||
"lng_theme_editor_menu_show" = "Show palette file";
|
||||
|
||||
"lng_payments_not_supported" = "Sorry, Telegram Desktop doesn't support payments yet. Please use one of our mobile apps to do this.";
|
||||
"lng_payments_receipt_label" = "Receipt";
|
||||
@@ -1562,7 +1663,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_call_box_status_today" = "{time}";
|
||||
"lng_call_box_status_yesterday" = "Yesterday at {time}";
|
||||
"lng_call_box_status_date" = "{date} at {time}";
|
||||
"lng_call_box_status_group" = "({count}) {status}";
|
||||
"lng_call_box_status_group" = "({amount}) {status}";
|
||||
|
||||
"lng_call_outgoing" = "Outgoing call";
|
||||
"lng_call_incoming" = "Incoming call";
|
||||
@@ -1585,6 +1686,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_rights_edit_admin" = "Manage permissions";
|
||||
"lng_rights_edit_admin_header" = "What can this admin do?";
|
||||
"lng_rights_edit_admin_rank_name" = "Custom title";
|
||||
"lng_rights_edit_admin_rank_about" = "A custom title that will be shown to all members instead of '{title}'.";
|
||||
"lng_rights_about_add_admins_yes" = "This admin will be able to add new admins with the same (or more limited) permissions.";
|
||||
"lng_rights_about_add_admins_no" = "This admin will not be able to add new admins.";
|
||||
|
||||
@@ -1597,6 +1700,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_user_restrictions" = "User restrictions";
|
||||
"lng_rights_user_restrictions_header" = "What can this member do?";
|
||||
"lng_rights_default_restrictions_header" = "What can members of this group do?";
|
||||
"lng_rights_slowmode_header" = "Slow mode";
|
||||
"lng_rights_slowmode_off" = "Off";
|
||||
"lng_rights_slowmode_seconds#one" = "{count}s";
|
||||
"lng_rights_slowmode_seconds#other" = "{count}s";
|
||||
"lng_rights_slowmode_minutes#one" = "{count}m";
|
||||
"lng_rights_slowmode_minutes#other" = "{count}m";
|
||||
"lng_rights_slowmode_hours#one" = "{count}h";
|
||||
"lng_rights_slowmode_hours#other" = "{count}h";
|
||||
"lng_rights_slowmode_about" = "Members will be able to send only one message per this interval.";
|
||||
"lng_rights_slowmode_about_interval" = "Members will be able to send only one message {interval}.";
|
||||
"lng_rights_slowmode_interval_seconds#one" = "every {count} second";
|
||||
"lng_rights_slowmode_interval_seconds#other" = "every {count} seconds";
|
||||
"lng_rights_slowmode_interval_minutes#one" = "every {count} minute";
|
||||
"lng_rights_slowmode_interval_minutes#other" = "every {count} minutes";
|
||||
|
||||
"lng_slowmode_enabled"= "Slow mode is enabled. You can send your next message in {left}.";
|
||||
"lng_slowmode_no_many" = "Slow mode is enabled. You can't send more than one message at a time.";
|
||||
"lng_slowmode_too_long" = "Sorry, this text is too long to send as one message.\n\nSlow mode is enabled. You can't send more than one message at a time.";
|
||||
|
||||
"lng_rights_channel_info" = "Change channel info";
|
||||
"lng_rights_channel_post" = "Post messages";
|
||||
@@ -1625,6 +1746,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_chat_banned_custom" = "Custom";
|
||||
"lng_rights_chat_banned_custom_date" = "Until {date}";
|
||||
|
||||
"lng_rights_transfer_group" = "Transfer group ownership";
|
||||
"lng_rights_transfer_channel" = "Transfer channel ownership";
|
||||
"lng_rights_transfer_check" = "Security check";
|
||||
"lng_rights_transfer_check_about" = "You can transfer this group to {user} only if you have:";
|
||||
"lng_rights_transfer_check_password" = "• Enabled **2-Step Verification** more than **7 days** ago.";
|
||||
"lng_rights_transfer_check_session" = "• Logged in on this device more than **24 hours** ago.";
|
||||
"lng_rights_transfer_check_later" = "Please come back later.";
|
||||
"lng_rights_transfer_set_password" = "Set password";
|
||||
"lng_rights_transfer_about" = "This will transfer the full **owner rights** for {group} to {user}.";
|
||||
"lng_rights_transfer_sure" = "Change owner";
|
||||
"lng_rights_transfer_password_title" = "Two-step verification";
|
||||
"lng_rights_transfer_password_description" = "Please enter your password to complete the transfer.";
|
||||
"lng_rights_transfer_done_group" = "{user} is now the owner of the group.";
|
||||
"lng_rights_transfer_done_channel" = "{user} is now the owner of the channel.";
|
||||
|
||||
"lng_restricted_send_message" = "The admins of this group restricted you from writing here.";
|
||||
"lng_restricted_send_media" = "The admins of this group restricted you from posting media content here.";
|
||||
"lng_restricted_send_stickers" = "The admins of this group restricted you from posting stickers here.";
|
||||
@@ -1642,6 +1778,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_exceptions_list_title" = "Exceptions";
|
||||
"lng_removed_list_title" = "Removed users";
|
||||
|
||||
"lng_admin_log_slow_mode_seconds#one" = "{count} second";
|
||||
"lng_admin_log_slow_mode_seconds#other" = "{count} seconds";
|
||||
"lng_admin_log_slow_mode_minutes#one" = "{count} minute";
|
||||
"lng_admin_log_slow_mode_minutes#other" = "{count} minutes";
|
||||
|
||||
"lng_admin_log_title_all" = "All actions";
|
||||
"lng_admin_log_title_selected" = "Selected actions";
|
||||
"lng_admin_log_filter" = "Filter";
|
||||
@@ -1705,6 +1846,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_banned" = "banned {user}";
|
||||
"lng_admin_log_restricted" = "changed restrictions for {user} {until}";
|
||||
"lng_admin_log_promoted" = "changed privileges for {user}";
|
||||
"lng_admin_log_transferred" = "transferred ownership to {user}";
|
||||
"lng_admin_log_changed_default_permissions" = "changed default permissions";
|
||||
"lng_admin_log_changed_stickers_group" = "{from} changed the group's {sticker_set}";
|
||||
"lng_admin_log_changed_stickers_set" = "sticker set";
|
||||
@@ -1713,6 +1855,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_removed_linked_chat" = "{from} removed the discussion group";
|
||||
"lng_admin_log_changed_linked_channel" = "{from} changed the linked channel to «{chat}»";
|
||||
"lng_admin_log_removed_linked_channel" = "{from} removed the linked channel";
|
||||
"lng_admin_log_changed_location_chat" = "{from} changed the group location to {address}";
|
||||
"lng_admin_log_removed_location_chat" = "{from} removed the group location";
|
||||
"lng_admin_log_changed_slow_mode" = "{from} changed slow mode to {duration}";
|
||||
"lng_admin_log_removed_slow_mode" = "{from} disabled slow mode";
|
||||
"lng_admin_log_user_with_username" = "{name} ({mention})";
|
||||
"lng_admin_log_restricted_forever" = "indefinitely";
|
||||
"lng_admin_log_restricted_until" = "until {date}";
|
||||
@@ -1956,14 +2102,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_export_state_userpics" = "Profile pictures";
|
||||
"lng_export_state_chats_list" = "Processing chats...";
|
||||
"lng_export_state_chats" = "Chats";
|
||||
"lng_export_state_progress" = "{count} / {total}";
|
||||
"lng_export_state_ready_progress" = "{ready} / {total}";
|
||||
"lng_export_progress" = "You can close this window now. Please don't quit Telegram until the data export is completed.";
|
||||
"lng_export_stop" = "Stop";
|
||||
"lng_export_sure_stop" = "Are you sure you want to stop exporting your data?\n\nIf you do, you'll need to start over.";
|
||||
"lng_export_about_done" = "Your data was successfully exported.";
|
||||
"lng_export_done" = "Show my data";
|
||||
"lng_export_finished" = "Data export completed.";
|
||||
"lng_export_total_files" = "Total files: {count}.";
|
||||
"lng_export_total_amount" = "Total files: {amount}.";
|
||||
"lng_export_total_size" = "Total size: {size}.";
|
||||
"lng_export_folder" = "Choose export folder";
|
||||
"lng_export_invalid" = "Sorry, you have started a new data export, so this data export is now cancelled.";
|
||||
@@ -2017,6 +2163,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_polls_create_maximum" = "You have added the maximum number of options.";
|
||||
"lng_polls_create_button" = "Create";
|
||||
|
||||
"lng_outdated_title" = "PLEASE UPDATE YOUR OPERATING SYSTEM.";
|
||||
"lng_outdated_soon" = "Otherwise, Telegram Desktop will stop updating on {date}.";
|
||||
"lng_outdated_now" = "So that Telegram Desktop can update to newer versions.";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
||||
@@ -2068,4 +2218,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_mac_menu_new_channel" = "New Channel";
|
||||
"lng_mac_menu_show" = "Show Telegram";
|
||||
|
||||
"lng_mac_touchbar_favorite_stickers" = "Favorite stickers";
|
||||
|
||||
// Keys finished
|
||||
|
||||
7
Telegram/Resources/qrc/fonts.qrc
Normal file
@@ -0,0 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="fonts/OpenSans-Regular.ttf">../fonts/OpenSans-Regular.ttf</file>
|
||||
<file alias="fonts/OpenSans-Bold.ttf">../fonts/OpenSans-Bold.ttf</file>
|
||||
<file alias="fonts/OpenSans-Semibold.ttf">../fonts/OpenSans-Semibold.ttf</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -1,79 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/export">
|
||||
<file alias="css/style.css">../export_html/css/style.css</file>
|
||||
<file alias="images/back.png">../export_html/images/back.png</file>
|
||||
<file alias="images/back@2x.png">../export_html/images/back@2x.png</file>
|
||||
<file alias="images/media_call.png">../export_html/images/media_call.png</file>
|
||||
<file alias="images/media_call@2x.png">../export_html/images/media_call@2x.png</file>
|
||||
<file alias="images/media_contact.png">../export_html/images/media_contact.png</file>
|
||||
<file alias="images/media_contact@2x.png">../export_html/images/media_contact@2x.png</file>
|
||||
<file alias="images/media_file.png">../export_html/images/media_file.png</file>
|
||||
<file alias="images/media_file@2x.png">../export_html/images/media_file@2x.png</file>
|
||||
<file alias="images/media_game.png">../export_html/images/media_game.png</file>
|
||||
<file alias="images/media_game@2x.png">../export_html/images/media_game@2x.png</file>
|
||||
<file alias="images/media_location.png">../export_html/images/media_location.png</file>
|
||||
<file alias="images/media_location@2x.png">../export_html/images/media_location@2x.png</file>
|
||||
<file alias="images/media_music.png">../export_html/images/media_music.png</file>
|
||||
<file alias="images/media_music@2x.png">../export_html/images/media_music@2x.png</file>
|
||||
<file alias="images/media_photo.png">../export_html/images/media_photo.png</file>
|
||||
<file alias="images/media_photo@2x.png">../export_html/images/media_photo@2x.png</file>
|
||||
<file alias="images/media_shop.png">../export_html/images/media_shop.png</file>
|
||||
<file alias="images/media_shop@2x.png">../export_html/images/media_shop@2x.png</file>
|
||||
<file alias="images/media_video.png">../export_html/images/media_video.png</file>
|
||||
<file alias="images/media_video@2x.png">../export_html/images/media_video@2x.png</file>
|
||||
<file alias="images/media_voice.png">../export_html/images/media_voice.png</file>
|
||||
<file alias="images/media_voice@2x.png">../export_html/images/media_voice@2x.png</file>
|
||||
<file alias="images/section_calls.png">../export_html/images/section_calls.png</file>
|
||||
<file alias="images/section_calls@2x.png">../export_html/images/section_calls@2x.png</file>
|
||||
<file alias="images/section_chats.png">../export_html/images/section_chats.png</file>
|
||||
<file alias="images/section_chats@2x.png">../export_html/images/section_chats@2x.png</file>
|
||||
<file alias="images/section_contacts.png">../export_html/images/section_contacts.png</file>
|
||||
<file alias="images/section_contacts@2x.png">../export_html/images/section_contacts@2x.png</file>
|
||||
<file alias="images/section_frequent.png">../export_html/images/section_frequent.png</file>
|
||||
<file alias="images/section_frequent@2x.png">../export_html/images/section_frequent@2x.png</file>
|
||||
<file alias="images/section_other.png">../export_html/images/section_other.png</file>
|
||||
<file alias="images/section_other@2x.png">../export_html/images/section_other@2x.png</file>
|
||||
<file alias="images/section_photos.png">../export_html/images/section_photos.png</file>
|
||||
<file alias="images/section_photos@2x.png">../export_html/images/section_photos@2x.png</file>
|
||||
<file alias="images/section_sessions.png">../export_html/images/section_sessions.png</file>
|
||||
<file alias="images/section_sessions@2x.png">../export_html/images/section_sessions@2x.png</file>
|
||||
<file alias="images/section_web.png">../export_html/images/section_web.png</file>
|
||||
<file alias="images/section_web@2x.png">../export_html/images/section_web@2x.png</file>
|
||||
<file alias="js/script.js">../export_html/js/script.js</file>
|
||||
</qresource>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="fonts/OpenSans-Regular.ttf">../fonts/OpenSans-Regular.ttf</file>
|
||||
<file alias="fonts/OpenSans-Bold.ttf">../fonts/OpenSans-Bold.ttf</file>
|
||||
<file alias="fonts/OpenSans-Semibold.ttf">../fonts/OpenSans-Semibold.ttf</file>
|
||||
<file alias="art/bg.jpg">../art/bg.jpg</file>
|
||||
<file alias="art/bg_initial.jpg">../art/bg_initial.jpg</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/sunrise.jpg">../art/sunrise.jpg</file>
|
||||
<file alias="day-blue.tdesktop-theme">../day-blue.tdesktop-theme</file>
|
||||
<file alias="night.tdesktop-theme">../night.tdesktop-theme</file>
|
||||
<file alias="night-green.tdesktop-theme">../night-green.tdesktop-theme</file>
|
||||
</qresource>
|
||||
<qresource prefix="/sounds">
|
||||
<file alias="msg_incoming.mp3">../sounds/msg_incoming.mp3</file>
|
||||
<file alias="call_incoming.mp3">../sounds/call_incoming.mp3</file>
|
||||
<file alias="call_outgoing.mp3">../sounds/call_outgoing.mp3</file>
|
||||
<file alias="call_busy.mp3">../sounds/call_busy.mp3</file>
|
||||
<file alias="call_connect.mp3">../sounds/call_connect.mp3</file>
|
||||
<file alias="call_end.mp3">../sounds/call_end.mp3</file>
|
||||
</qresource>
|
||||
<qresource prefix="/qt-project.org">
|
||||
<file>qmime/freedesktop.org.xml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/misc">
|
||||
<file alias="default_shortcuts-custom.json">../default_shortcuts-custom.json</file>
|
||||
</qresource>
|
||||
<qresource prefix="/langs">
|
||||
<file alias="lang_it.strings">../langs/lang_it.strings</file>
|
||||
<file alias="lang_es.strings">../langs/lang_es.strings</file>
|
||||
<file alias="lang_de.strings">../langs/lang_de.strings</file>
|
||||
<file alias="lang_nl.strings">../langs/lang_nl.strings</file>
|
||||
<file alias="lang_pt_BR.strings">../langs/lang_pt_BR.strings</file>
|
||||
<file alias="lang_ko.strings">../langs/lang_ko.strings</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
10
Telegram/Resources/qrc/telegram/sounds.qrc
Normal file
@@ -0,0 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/sounds">
|
||||
<file alias="msg_incoming.mp3">../../sounds/msg_incoming.mp3</file>
|
||||
<file alias="call_busy.mp3">../../sounds/call_busy.mp3</file>
|
||||
<file alias="call_connect.mp3">../../sounds/call_connect.mp3</file>
|
||||
<file alias="call_end.mp3">../../sounds/call_end.mp3</file>
|
||||
<file alias="call_incoming.mp3">../../sounds/call_incoming.mp3</file>
|
||||
<file alias="call_outgoing.mp3">../../sounds/call_outgoing.mp3</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
60
Telegram/Resources/qrc/telegram/telegram.qrc
Normal file
@@ -0,0 +1,60 @@
|
||||
<RCC>
|
||||
<qresource prefix="/export">
|
||||
<file alias="css/style.css">../../export_html/css/style.css</file>
|
||||
<file alias="images/back.png">../../export_html/images/back.png</file>
|
||||
<file alias="images/back@2x.png">../../export_html/images/back@2x.png</file>
|
||||
<file alias="images/media_call.png">../../export_html/images/media_call.png</file>
|
||||
<file alias="images/media_call@2x.png">../../export_html/images/media_call@2x.png</file>
|
||||
<file alias="images/media_contact.png">../../export_html/images/media_contact.png</file>
|
||||
<file alias="images/media_contact@2x.png">../../export_html/images/media_contact@2x.png</file>
|
||||
<file alias="images/media_file.png">../../export_html/images/media_file.png</file>
|
||||
<file alias="images/media_file@2x.png">../../export_html/images/media_file@2x.png</file>
|
||||
<file alias="images/media_game.png">../../export_html/images/media_game.png</file>
|
||||
<file alias="images/media_game@2x.png">../../export_html/images/media_game@2x.png</file>
|
||||
<file alias="images/media_location.png">../../export_html/images/media_location.png</file>
|
||||
<file alias="images/media_location@2x.png">../../export_html/images/media_location@2x.png</file>
|
||||
<file alias="images/media_music.png">../../export_html/images/media_music.png</file>
|
||||
<file alias="images/media_music@2x.png">../../export_html/images/media_music@2x.png</file>
|
||||
<file alias="images/media_photo.png">../../export_html/images/media_photo.png</file>
|
||||
<file alias="images/media_photo@2x.png">../../export_html/images/media_photo@2x.png</file>
|
||||
<file alias="images/media_shop.png">../../export_html/images/media_shop.png</file>
|
||||
<file alias="images/media_shop@2x.png">../../export_html/images/media_shop@2x.png</file>
|
||||
<file alias="images/media_video.png">../../export_html/images/media_video.png</file>
|
||||
<file alias="images/media_video@2x.png">../../export_html/images/media_video@2x.png</file>
|
||||
<file alias="images/media_voice.png">../../export_html/images/media_voice.png</file>
|
||||
<file alias="images/media_voice@2x.png">../../export_html/images/media_voice@2x.png</file>
|
||||
<file alias="images/section_calls.png">../../export_html/images/section_calls.png</file>
|
||||
<file alias="images/section_calls@2x.png">../../export_html/images/section_calls@2x.png</file>
|
||||
<file alias="images/section_chats.png">../../export_html/images/section_chats.png</file>
|
||||
<file alias="images/section_chats@2x.png">../../export_html/images/section_chats@2x.png</file>
|
||||
<file alias="images/section_contacts.png">../../export_html/images/section_contacts.png</file>
|
||||
<file alias="images/section_contacts@2x.png">../../export_html/images/section_contacts@2x.png</file>
|
||||
<file alias="images/section_frequent.png">../../export_html/images/section_frequent.png</file>
|
||||
<file alias="images/section_frequent@2x.png">../../export_html/images/section_frequent@2x.png</file>
|
||||
<file alias="images/section_other.png">../../export_html/images/section_other.png</file>
|
||||
<file alias="images/section_other@2x.png">../../export_html/images/section_other@2x.png</file>
|
||||
<file alias="images/section_photos.png">../../export_html/images/section_photos.png</file>
|
||||
<file alias="images/section_photos@2x.png">../../export_html/images/section_photos@2x.png</file>
|
||||
<file alias="images/section_sessions.png">../../export_html/images/section_sessions.png</file>
|
||||
<file alias="images/section_sessions@2x.png">../../export_html/images/section_sessions@2x.png</file>
|
||||
<file alias="images/section_web.png">../../export_html/images/section_web.png</file>
|
||||
<file alias="images/section_web@2x.png">../../export_html/images/section_web@2x.png</file>
|
||||
<file alias="js/script.js">../../export_html/js/script.js</file>
|
||||
</qresource>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="art/bg.jpg">../../art/bg.jpg</file>
|
||||
<file alias="art/bg_initial.jpg">../../art/bg_initial.jpg</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/sunrise.jpg">../../art/sunrise.jpg</file>
|
||||
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
|
||||
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
|
||||
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
|
||||
</qresource>
|
||||
<qresource prefix="/qt-project.org">
|
||||
<file>../qmime/freedesktop.org.xml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/misc">
|
||||
<file alias="default_shortcuts-custom.json">../../default_shortcuts-custom.json</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -1,10 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/sounds">
|
||||
<file alias="msg_incoming.mp3">../sounds/msg_incoming.mp3</file>
|
||||
<file alias="call_busy.mp3">../sounds/call_busy.mp3</file>
|
||||
<file alias="call_connect.mp3">../sounds/call_connect.mp3</file>
|
||||
<file alias="call_end.mp3">../sounds/call_end.mp3</file>
|
||||
<file alias="call_incoming.mp3">../sounds/call_incoming.mp3</file>
|
||||
<file alias="call_outgoing.mp3">../sounds/call_outgoing.mp3</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -1,7 +1,3 @@
|
||||
// Core types (no need to gen)
|
||||
|
||||
//vector#1cb5c415 {t:Type} # [ t ] = Vector t;
|
||||
|
||||
///////////////////////////////
|
||||
/////////////////// Layer cons
|
||||
///////////////////////////////
|
||||
@@ -28,115 +24,10 @@
|
||||
//invokeWithLayer18#1c900537 query:!X = X;
|
||||
//invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer
|
||||
|
||||
///////////////////////////////
|
||||
/// Authorization key creation
|
||||
///////////////////////////////
|
||||
|
||||
resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;
|
||||
|
||||
p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
|
||||
p_q_inner_data_dc#a9f55f95 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int = P_Q_inner_data;
|
||||
p_q_inner_data_temp#3c6a84d4 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data;
|
||||
p_q_inner_data_temp_dc#56fddf88 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = P_Q_inner_data;
|
||||
|
||||
server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
|
||||
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;
|
||||
|
||||
server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;
|
||||
|
||||
client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data;
|
||||
|
||||
dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
|
||||
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
|
||||
dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;
|
||||
|
||||
destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes;
|
||||
destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes;
|
||||
destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes;
|
||||
|
||||
---functions---
|
||||
|
||||
req_pq#60469778 nonce:int128 = ResPQ;
|
||||
req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
|
||||
|
||||
req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params;
|
||||
|
||||
set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;
|
||||
|
||||
destroy_auth_key#d1435160 = DestroyAuthKeyRes;
|
||||
|
||||
///////////////////////////////
|
||||
////////////// System messages
|
||||
///////////////////////////////
|
||||
|
||||
---types---
|
||||
|
||||
msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;
|
||||
|
||||
bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
|
||||
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;
|
||||
|
||||
msgs_state_req#da69fb52 msg_ids:Vector<long> = MsgsStateReq;
|
||||
msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
|
||||
msgs_all_info#8cc0d131 msg_ids:Vector<long> info:string = MsgsAllInfo;
|
||||
|
||||
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
|
||||
msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
|
||||
|
||||
msg_resend_req#7d861a08 msg_ids:Vector<long> = MsgResendReq;
|
||||
|
||||
//rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually
|
||||
|
||||
rpc_error#2144ca19 error_code:int error_message:string = RpcError;
|
||||
|
||||
rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
|
||||
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
|
||||
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;
|
||||
|
||||
future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt;
|
||||
future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts;
|
||||
|
||||
pong#347773c5 msg_id:long ping_id:long = Pong;
|
||||
|
||||
destroy_session_ok#e22045fc session_id:long = DestroySessionRes;
|
||||
destroy_session_none#62d350c9 session_id:long = DestroySessionRes;
|
||||
|
||||
new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession;
|
||||
|
||||
//message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually
|
||||
//msg_container#73f1f8dc messages:vector<message> = MessageContainer; // parsed manually
|
||||
//msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container
|
||||
//gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually
|
||||
|
||||
http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
|
||||
|
||||
//ipPort ipv4:int port:int = IpPort;
|
||||
//help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple;
|
||||
|
||||
ipPort#d433ad73 ipv4:int port:int = IpPort;
|
||||
ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort;
|
||||
accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule;
|
||||
help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple;
|
||||
|
||||
---functions---
|
||||
|
||||
rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
|
||||
|
||||
get_future_salts#b921bd04 num:int = FutureSalts;
|
||||
|
||||
ping#7abe77ec ping_id:long = Pong;
|
||||
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
|
||||
|
||||
destroy_session#e7512126 session_id:long = DestroySessionRes;
|
||||
|
||||
contest.saveDeveloperInfo#9a5f6e95 vk_id:int name:string phone_number:string age:int city:string = Bool;
|
||||
|
||||
///////////////////////////////
|
||||
///////// Main application API
|
||||
///////////////////////////////
|
||||
|
||||
---types---
|
||||
|
||||
boolFalse#bc799737 = Bool;
|
||||
boolTrue#997275b5 = Bool;
|
||||
|
||||
@@ -217,7 +108,7 @@ storage.fileMp4#b3cea0e4 = storage.FileType;
|
||||
storage.fileWebp#1081464c = storage.FileType;
|
||||
|
||||
userEmpty#200250ba id:int = User;
|
||||
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
|
||||
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
|
||||
userProfilePhoto#ecd75d8c photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto;
|
||||
@@ -232,11 +123,11 @@ userStatusLastMonth#77ebc742 = UserStatus;
|
||||
chatEmpty#9ba2d800 id:int = Chat;
|
||||
chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
||||
chatForbidden#7328bdb id:int title:string = Chat;
|
||||
channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
|
||||
channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
|
||||
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
|
||||
|
||||
chatFull#1b7c9db3 flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
|
||||
channelFull#9882e516 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.13?int pts:int = ChatFull;
|
||||
chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
|
||||
channelFull#2d895c74 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true can_set_location:flags.16?true has_scheduled:flags.19?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int pts:int = ChatFull;
|
||||
|
||||
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
|
||||
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
|
||||
@@ -249,7 +140,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
|
||||
chatPhoto#475cdbd5 photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
|
||||
|
||||
messageEmpty#83e5de54 id:int = Message;
|
||||
message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
|
||||
message#452c0e65 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
|
||||
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
|
||||
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
@@ -303,11 +194,10 @@ photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
|
||||
geoPointEmpty#1117dd5f = GeoPoint;
|
||||
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
|
||||
|
||||
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
|
||||
|
||||
auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode;
|
||||
auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
|
||||
|
||||
auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization;
|
||||
auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization;
|
||||
|
||||
auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
|
||||
|
||||
@@ -320,7 +210,7 @@ inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags
|
||||
|
||||
peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings;
|
||||
|
||||
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
|
||||
peerSettings#818426cd flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true = PeerSettings;
|
||||
|
||||
wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
|
||||
|
||||
@@ -330,8 +220,9 @@ inputReportReasonPornography#2e59d922 = ReportReason;
|
||||
inputReportReasonChildAbuse#adf44ee3 = ReportReason;
|
||||
inputReportReasonOther#e1746d0a text:string = ReportReason;
|
||||
inputReportReasonCopyright#9b89f93a = ReportReason;
|
||||
inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
|
||||
|
||||
userFull#745559cc flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull;
|
||||
userFull#edf17c12 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull;
|
||||
|
||||
contact#f911c994 user_id:int mutual:Bool = Contact;
|
||||
|
||||
@@ -341,8 +232,6 @@ contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
|
||||
|
||||
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
|
||||
|
||||
contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link;
|
||||
|
||||
contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
|
||||
contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector<User> = contacts.Contacts;
|
||||
|
||||
@@ -393,7 +282,6 @@ updateChatParticipants#7761198 participants:ChatParticipants = Update;
|
||||
updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
|
||||
updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update;
|
||||
updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update;
|
||||
updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update;
|
||||
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
|
||||
updateEncryptedChatTyping#1710f156 chat_id:int = Update;
|
||||
updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update;
|
||||
@@ -454,6 +342,11 @@ updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update;
|
||||
updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update;
|
||||
updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update;
|
||||
updateFolderPeers#19360dc0 folder_peers:Vector<FolderPeer> pts:int pts_count:int = Update;
|
||||
updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update;
|
||||
updatePeerLocated#b4afcfb0 peers:Vector<PeerLocated> = Update;
|
||||
updateNewScheduledMessage#39a51dfb message:Message = Update;
|
||||
updateDeleteScheduledMessages#90866cee peer:Peer messages:Vector<int> = Update;
|
||||
updateTheme#8216fba3 theme:Theme = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@@ -484,7 +377,7 @@ config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:fla
|
||||
|
||||
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
|
||||
|
||||
help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate;
|
||||
help.appUpdate#1da7158f flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate;
|
||||
help.noAppUpdate#c45a6536 = help.AppUpdate;
|
||||
|
||||
help.inviteText#18cb9f78 message:string = help.InviteText;
|
||||
@@ -550,6 +443,7 @@ inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey;
|
||||
inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey;
|
||||
inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey;
|
||||
inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey;
|
||||
inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey;
|
||||
|
||||
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
|
||||
privacyKeyChatInvite#500e6dfa = PrivacyKey;
|
||||
@@ -558,6 +452,7 @@ privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
|
||||
privacyKeyForwards#69ec56a3 = PrivacyKey;
|
||||
privacyKeyProfilePhoto#96151fed = PrivacyKey;
|
||||
privacyKeyPhoneNumber#d19ae46d = PrivacyKey;
|
||||
privacyKeyAddedByPhone#42ffd42b = PrivacyKey;
|
||||
|
||||
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
|
||||
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
|
||||
@@ -599,13 +494,9 @@ messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllSti
|
||||
|
||||
messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages;
|
||||
|
||||
contactLinkUnknown#5f4f9247 = ContactLink;
|
||||
contactLinkNone#feedd3ad = ContactLink;
|
||||
contactLinkContact#d502c2d0 = ContactLink;
|
||||
|
||||
webPageEmpty#eb1477e8 id:long = WebPage;
|
||||
webPagePending#c586da1c id:long date:int = WebPage;
|
||||
webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage;
|
||||
webPage#fa64e172 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document documents:flags.11?Vector<Document> cached_page:flags.10?Page = WebPage;
|
||||
webPageNotModified#85849473 = WebPage;
|
||||
|
||||
authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
|
||||
@@ -631,8 +522,9 @@ chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:f
|
||||
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
|
||||
inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
|
||||
|
||||
stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
|
||||
stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
|
||||
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
|
||||
@@ -673,6 +565,9 @@ messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEnt
|
||||
inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity;
|
||||
messageEntityPhone#9b69e34b offset:int length:int = MessageEntity;
|
||||
messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity;
|
||||
messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity;
|
||||
messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity;
|
||||
messageEntityBlockquote#20df5d0 offset:int length:int = MessageEntity;
|
||||
|
||||
inputChannelEmpty#ee8c1e86 = InputChannel;
|
||||
inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
|
||||
@@ -691,8 +586,8 @@ channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:
|
||||
|
||||
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
|
||||
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
|
||||
channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant;
|
||||
channelParticipantAdmin#5daa6e23 flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights = ChannelParticipant;
|
||||
channelParticipantCreator#808d15a4 flags:# user_id:int rank:flags.0?string = ChannelParticipant;
|
||||
channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
|
||||
channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
|
||||
|
||||
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
|
||||
@@ -893,7 +788,7 @@ payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password
|
||||
payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo;
|
||||
|
||||
payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult;
|
||||
payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult;
|
||||
payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult;
|
||||
|
||||
payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt;
|
||||
|
||||
@@ -959,6 +854,8 @@ channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = Chann
|
||||
channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction;
|
||||
|
||||
channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
|
||||
|
||||
@@ -1134,7 +1031,7 @@ inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
|
||||
account.wallPapersNotModified#1c199183 = account.WallPapers;
|
||||
account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
|
||||
|
||||
codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings;
|
||||
codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings;
|
||||
|
||||
wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings;
|
||||
|
||||
@@ -1165,6 +1062,22 @@ urlAuthResultRequest#92d33a0e flags:# request_write_access:flags.0?true bot:User
|
||||
urlAuthResultAccepted#8f8c0e4e url:string = UrlAuthResult;
|
||||
urlAuthResultDefault#a9d6db1f = UrlAuthResult;
|
||||
|
||||
channelLocationEmpty#bfb5ad8b = ChannelLocation;
|
||||
channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation;
|
||||
|
||||
peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated;
|
||||
|
||||
restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason;
|
||||
|
||||
inputTheme#3c5693e9 id:long access_hash:long = InputTheme;
|
||||
inputThemeSlug#f5890df1 slug:string = InputTheme;
|
||||
|
||||
themeDocumentNotModified#483d270c = Theme;
|
||||
theme#f7d90ce0 flags:# creator:flags.0?true default:flags.1?true id:long access_hash:long slug:string title:string document:flags.2?Document installs_count:int = Theme;
|
||||
|
||||
account.themesNotModified#f41eb622 = account.Themes;
|
||||
account.themes#7f676421 hash:int themes:Vector<Theme> = account.Themes;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@@ -1176,7 +1089,7 @@ invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
|
||||
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
|
||||
|
||||
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
|
||||
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
|
||||
auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
|
||||
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
|
||||
auth.logOut#5717da40 = Bool;
|
||||
auth.resetAuthorizations#9fab0d1a = Bool;
|
||||
@@ -1191,7 +1104,7 @@ auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentC
|
||||
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
|
||||
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
|
||||
|
||||
account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool;
|
||||
account.registerDevice#68976c6f flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool;
|
||||
account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = Bool;
|
||||
account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
|
||||
account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
|
||||
@@ -1246,6 +1159,13 @@ account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSet
|
||||
account.resetWallPapers#bb3b9804 = Bool;
|
||||
account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings;
|
||||
account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool;
|
||||
account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document;
|
||||
account.createTheme#2b7ffd7f slug:string title:string document:InputDocument = Theme;
|
||||
account.updateTheme#3b8ea202 flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument = Theme;
|
||||
account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool;
|
||||
account.installTheme#7ae43737 flags:# dark:flags.0?true format:flags.1?string theme:flags.1?InputTheme = Bool;
|
||||
account.getTheme#8d9d742b format:string theme:InputTheme document_id:long = Theme;
|
||||
account.getThemes#285946f8 format:string hash:int = account.Themes;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
@@ -1255,8 +1175,7 @@ contacts.getContactIDs#2caa4a42 hash:int = Vector<int>;
|
||||
contacts.getStatuses#c4a353ee = Vector<ContactStatus>;
|
||||
contacts.getContacts#c023849f hash:int = contacts.Contacts;
|
||||
contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts;
|
||||
contacts.deleteContact#8e953744 id:InputUser = contacts.Link;
|
||||
contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool;
|
||||
contacts.deleteContacts#96a0e00 id:Vector<InputUser> = Updates;
|
||||
contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool;
|
||||
contacts.block#332b49fc id:InputUser = Bool;
|
||||
contacts.unblock#e54100bd id:InputUser = Bool;
|
||||
@@ -1268,6 +1187,9 @@ contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = B
|
||||
contacts.resetSaved#879537f1 = Bool;
|
||||
contacts.getSaved#82f1e39f = Vector<SavedContact>;
|
||||
contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
|
||||
contacts.addContact#e8f463d0 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string = Updates;
|
||||
contacts.acceptContact#f831a20f id:InputUser = Updates;
|
||||
contacts.getLocated#a356056 geo_point:InputGeoPoint = Updates;
|
||||
|
||||
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
|
||||
messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
|
||||
@@ -1278,11 +1200,10 @@ messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?t
|
||||
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
|
||||
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
||||
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
|
||||
messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
|
||||
messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
|
||||
messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
|
||||
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
|
||||
messages.reportSpam#cf1592db peer:InputPeer = Bool;
|
||||
messages.hideReportSpam#a8f1709b peer:InputPeer = Bool;
|
||||
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
|
||||
messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool;
|
||||
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
|
||||
@@ -1317,7 +1238,7 @@ messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_par
|
||||
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
|
||||
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
|
||||
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
|
||||
messages.searchGlobal#f79c611 q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
|
||||
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
|
||||
messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
|
||||
@@ -1325,9 +1246,9 @@ messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
|
||||
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
||||
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
|
||||
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
|
||||
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
|
||||
messages.sendInlineBotResult#220815b0 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string schedule_date:flags.10?int = Updates;
|
||||
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
||||
messages.editMessage#d116f31e flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
|
||||
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
|
||||
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
|
||||
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
|
||||
@@ -1361,7 +1282,7 @@ messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
|
||||
messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
|
||||
messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory;
|
||||
messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages;
|
||||
messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates;
|
||||
messages.sendMultiMedia#cc0110cb flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int = Updates;
|
||||
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
|
||||
messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
|
||||
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
|
||||
@@ -1382,6 +1303,11 @@ messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
|
||||
messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
|
||||
messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
|
||||
messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
|
||||
messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool;
|
||||
messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Messages;
|
||||
messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector<int> = messages.Messages;
|
||||
messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector<int> = Updates;
|
||||
messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector<int> = Updates;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@@ -1393,7 +1319,7 @@ photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
|
||||
photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
|
||||
|
||||
upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
|
||||
upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File;
|
||||
upload.getFile#b15a9afc flags:# precise:flags.0?true location:InputFileLocation offset:int limit:int = upload.File;
|
||||
upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
|
||||
upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile;
|
||||
upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile;
|
||||
@@ -1430,8 +1356,8 @@ channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipant
|
||||
channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
|
||||
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
|
||||
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
|
||||
channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates;
|
||||
channels.editAdmin#70f893ba channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights = Updates;
|
||||
channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates;
|
||||
channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates;
|
||||
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
|
||||
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
|
||||
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
|
||||
@@ -1442,7 +1368,7 @@ channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> =
|
||||
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
|
||||
channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
|
||||
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats;
|
||||
channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats;
|
||||
channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates;
|
||||
channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
|
||||
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
|
||||
@@ -1451,8 +1377,10 @@ channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
|
||||
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
|
||||
channels.getLeftChannels#8341ecc0 offset:int = messages.Chats;
|
||||
channels.getGroupsForDiscussion#f5dad378 = messages.Chats;
|
||||
channels.getBroadcastsForDiscussion#1a87f304 = messages.Chats;
|
||||
channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool;
|
||||
channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates;
|
||||
channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool;
|
||||
channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates;
|
||||
|
||||
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
||||
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||
@@ -1487,4 +1415,4 @@ langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLangua
|
||||
folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
|
||||
folders.deleteFolder#1c295881 folder_id:int = Updates;
|
||||
|
||||
// LAYER 100
|
||||
// LAYER 105
|
||||
114
Telegram/Resources/tl/mtproto.tl
Normal file
@@ -0,0 +1,114 @@
|
||||
// Core types (no need to gen)
|
||||
|
||||
//vector#1cb5c415 {t:Type} # [ t ] = Vector t;
|
||||
|
||||
///////////////////////////////
|
||||
/// Authorization key creation
|
||||
///////////////////////////////
|
||||
|
||||
resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;
|
||||
|
||||
p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
|
||||
p_q_inner_data_dc#a9f55f95 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int = P_Q_inner_data;
|
||||
p_q_inner_data_temp#3c6a84d4 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data;
|
||||
p_q_inner_data_temp_dc#56fddf88 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = P_Q_inner_data;
|
||||
|
||||
server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
|
||||
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;
|
||||
|
||||
server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;
|
||||
|
||||
client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data;
|
||||
|
||||
dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
|
||||
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
|
||||
dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;
|
||||
|
||||
destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes;
|
||||
destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes;
|
||||
destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes;
|
||||
|
||||
---functions---
|
||||
|
||||
req_pq#60469778 nonce:int128 = ResPQ;
|
||||
req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
|
||||
|
||||
req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params;
|
||||
|
||||
set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;
|
||||
|
||||
destroy_auth_key#d1435160 = DestroyAuthKeyRes;
|
||||
|
||||
///////////////////////////////
|
||||
////////////// System messages
|
||||
///////////////////////////////
|
||||
|
||||
---types---
|
||||
|
||||
msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;
|
||||
|
||||
bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
|
||||
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;
|
||||
|
||||
msgs_state_req#da69fb52 msg_ids:Vector<long> = MsgsStateReq;
|
||||
msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
|
||||
msgs_all_info#8cc0d131 msg_ids:Vector<long> info:string = MsgsAllInfo;
|
||||
|
||||
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
|
||||
msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
|
||||
|
||||
msg_resend_req#7d861a08 msg_ids:Vector<long> = MsgResendReq;
|
||||
|
||||
//rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually
|
||||
|
||||
rpc_error#2144ca19 error_code:int error_message:string = RpcError;
|
||||
|
||||
rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
|
||||
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
|
||||
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;
|
||||
|
||||
future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt;
|
||||
future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts;
|
||||
|
||||
pong#347773c5 msg_id:long ping_id:long = Pong;
|
||||
|
||||
destroy_session_ok#e22045fc session_id:long = DestroySessionRes;
|
||||
destroy_session_none#62d350c9 session_id:long = DestroySessionRes;
|
||||
|
||||
new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession;
|
||||
|
||||
//message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually
|
||||
//msg_container#73f1f8dc messages:vector<message> = MessageContainer; // parsed manually
|
||||
//msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container
|
||||
//gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually
|
||||
|
||||
http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
|
||||
|
||||
//ipPort ipv4:int port:int = IpPort;
|
||||
//help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple;
|
||||
|
||||
ipPort#d433ad73 ipv4:int port:int = IpPort;
|
||||
ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort;
|
||||
accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule;
|
||||
help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple;
|
||||
|
||||
tlsClientHello blocks:vector<TlsBlock> = TlsClientHello;
|
||||
|
||||
tlsBlockString data:string = TlsBlock;
|
||||
tlsBlockRandom length:int = TlsBlock;
|
||||
tlsBlockZero length:int = TlsBlock;
|
||||
tlsBlockDomain = TlsBlock;
|
||||
tlsBlockGrease seed:int = TlsBlock;
|
||||
tlsBlockPublicKey = TlsBlock;
|
||||
tlsBlockScope entries:Vector<TlsBlock> = TlsBlock;
|
||||
|
||||
---functions---
|
||||
|
||||
rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
|
||||
|
||||
get_future_salts#b921bd04 num:int = FutureSalts;
|
||||
|
||||
ping#7abe77ec ping_id:long = Pong;
|
||||
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
|
||||
|
||||
destroy_session#e7512126 session_id:long = DestroySessionRes;
|
||||
@@ -9,10 +9,10 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="1.7.1.0" />
|
||||
Version="1.8.11.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>
|
||||
<Description>Telegram Desktop official messenger</Description>
|
||||
<Logo>Assets\logo\logo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
17
Telegram/Resources/winrc/Telegram.manifest
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
@@ -1,6 +1,5 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@@ -34,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,7,1,0
|
||||
PRODUCTVERSION 1,7,1,0
|
||||
FILEVERSION 1,8,11,0
|
||||
PRODUCTVERSION 1,8,11,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -50,12 +49,12 @@ BEGIN
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "1.7.1.0"
|
||||
VALUE "FileVersion", "1.8.11.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2019"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.7.1.0"
|
||||
VALUE "ProductVersion", "1.8.11.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
@@ -66,16 +65,3 @@ END
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource1.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@@ -25,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,7,1,0
|
||||
PRODUCTVERSION 1,7,1,0
|
||||
FILEVERSION 1,8,11,0
|
||||
PRODUCTVERSION 1,8,11,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -41,12 +40,12 @@ BEGIN
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "1.7.1.0"
|
||||
VALUE "FileVersion", "1.8.11.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2019"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.7.1.0"
|
||||
VALUE "ProductVersion", "1.8.11.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
@@ -57,16 +56,3 @@ END
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by Updater.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -307,7 +307,7 @@ void updateRegistry() {
|
||||
RegSetValueEx(rkey, L"DisplayVersion", 0, REG_SZ, (const BYTE*)versionStr, ((versionLen / 2) + 1) * sizeof(WCHAR));
|
||||
wsprintf(nameStr, L"Telegram Desktop version %s", versionStr);
|
||||
RegSetValueEx(rkey, L"DisplayName", 0, REG_SZ, (const BYTE*)nameStr, (wcslen(nameStr) + 1) * sizeof(WCHAR));
|
||||
wsprintf(publisherStr, L"Telegram Messenger LLP");
|
||||
wsprintf(publisherStr, L"Telegram FZ-LLC");
|
||||
RegSetValueEx(rkey, L"Publisher", 0, REG_SZ, (const BYTE*)publisherStr, (wcslen(publisherStr) + 1) * sizeof(WCHAR));
|
||||
wsprintf(icongroupStr, L"Telegram Desktop");
|
||||
RegSetValueEx(rkey, L"Inno Setup: Icon Group", 0, REG_SZ, (const BYTE*)icongroupStr, (wcslen(icongroupStr) + 1) * sizeof(WCHAR));
|
||||
|
||||
46
Telegram/SourceFiles/api/api_common.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
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
|
||||
|
||||
class History;
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct SendOptions {
|
||||
TimeId scheduled = 0;
|
||||
bool silent = false;
|
||||
bool handleSupportSwitch = false;
|
||||
bool removeWebPageId = false;
|
||||
};
|
||||
|
||||
enum class SendType {
|
||||
Normal,
|
||||
Scheduled,
|
||||
};
|
||||
|
||||
struct SendAction {
|
||||
explicit SendAction(not_null<History*> history) : history(history) {
|
||||
}
|
||||
|
||||
not_null<History*> history;
|
||||
SendOptions options;
|
||||
MsgId replyTo = 0;
|
||||
bool clearDraft = true;
|
||||
bool generateLocal = true;
|
||||
};
|
||||
|
||||
struct MessageToSend {
|
||||
explicit MessageToSend(not_null<History*> history) : action(history) {
|
||||
}
|
||||
|
||||
SendAction action;
|
||||
TextWithTags textWithTags;
|
||||
WebPageId webPageId = 0;
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
42
Telegram/SourceFiles/api/api_hash.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Api {
|
||||
|
||||
[[nodiscard]] inline uint32 HashInit() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void HashUpdate(uint32 &already, uint32 value) {
|
||||
already = (already * 20261) + uint32(value);
|
||||
}
|
||||
|
||||
inline void HashUpdate(uint32 &already, int32 value) {
|
||||
HashUpdate(already, uint32(value));
|
||||
}
|
||||
|
||||
inline void HashUpdate(uint32 &already, uint64 value) {
|
||||
HashUpdate(already, uint32(value >> 32));
|
||||
HashUpdate(already, uint32(value & 0xFFFFFFFFULL));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline int32 HashFinalize(uint32 already) {
|
||||
return int32(already & 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
template <typename IntRange>
|
||||
[[nodiscard]] inline int32 CountHash(IntRange &&range) {
|
||||
auto result = HashInit();
|
||||
for (const auto value : range) {
|
||||
HashUpdate(result, value);
|
||||
}
|
||||
return HashFinalize(result);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
193
Telegram/SourceFiles/api/api_sending.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
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_sending.h"
|
||||
|
||||
#include "api/api_text_entities.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_channel.h" // ChannelData::addsSignature.
|
||||
#include "data/data_user.h" // UserData::name
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_message.h" // NewMessageFlags.
|
||||
#include "chat_helpers/message_field.h" // ConvertTextTagsToEntities.
|
||||
#include "ui/text/text_entity.h" // TextWithEntities.
|
||||
#include "main/main_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "apiwrap.h"
|
||||
#include "app.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
template <typename MediaData>
|
||||
void SendExistingMedia(
|
||||
Api::MessageToSend &&message,
|
||||
not_null<MediaData*> media,
|
||||
Fn<MTPInputMedia()> inputMedia,
|
||||
Data::FileOrigin origin) {
|
||||
const auto history = message.action.history;
|
||||
const auto peer = history->peer;
|
||||
const auto session = &history->session();
|
||||
const auto api = &session->api();
|
||||
|
||||
message.action.clearDraft = false;
|
||||
message.action.generateLocal = true;
|
||||
api->sendAction(message.action);
|
||||
|
||||
const auto newId = FullMsgId(
|
||||
peerToChannel(peer->id),
|
||||
session->data().nextLocalMessageId());
|
||||
const auto randomId = rand_value<uint64>();
|
||||
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (message.action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto silentPost = message.action.options.silent
|
||||
|| (channelPost && session->data().notifySilentPosts(peer));
|
||||
if (channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
}
|
||||
if (!channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_from_id;
|
||||
} else if (peer->asChannel()->addsSignature()) {
|
||||
flags |= MTPDmessage::Flag::f_post_author;
|
||||
}
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : session->userId();
|
||||
auto messagePostAuthor = channelPost ? session->user()->name : QString();
|
||||
|
||||
auto caption = TextWithEntities{
|
||||
message.textWithTags.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(message.textWithTags.tags)
|
||||
};
|
||||
TextUtilities::Trim(caption);
|
||||
auto sentEntities = EntitiesToMTP(
|
||||
caption.entities,
|
||||
ConvertOption::SkipLocal);
|
||||
if (!sentEntities.v.isEmpty()) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_entities;
|
||||
}
|
||||
const auto replyTo = message.action.replyTo;
|
||||
const auto captionText = caption.text;
|
||||
|
||||
if (message.action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
}
|
||||
|
||||
session->data().registerMessageRandomId(randomId, newId);
|
||||
|
||||
history->addNewLocalMessage(
|
||||
newId.msg,
|
||||
flags,
|
||||
clientFlags,
|
||||
0,
|
||||
replyTo,
|
||||
HistoryItem::NewMessageDate(message.action.options.scheduled),
|
||||
messageFromId,
|
||||
messagePostAuthor,
|
||||
media,
|
||||
caption,
|
||||
MTPReplyMarkup());
|
||||
|
||||
auto failHandler = std::make_shared<Fn<void(const RPCError&, QByteArray)>>();
|
||||
auto performRequest = [=] {
|
||||
const auto usedFileReference = media->fileReference();
|
||||
history->sendRequestId = api->request(MTPmessages_SendMedia(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(replyTo),
|
||||
inputMedia(),
|
||||
MTP_string(captionText),
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(message.action.options.scheduled)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
api->applyUpdates(result, randomId);
|
||||
}).fail([=](const RPCError &error) {
|
||||
(*failHandler)(error, usedFileReference);
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
};
|
||||
*failHandler = [=](const RPCError &error, QByteArray usedFileReference) {
|
||||
if (error.code() == 400
|
||||
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
|
||||
api->refreshFileReference(origin, [=](const auto &result) {
|
||||
if (media->fileReference() != usedFileReference) {
|
||||
performRequest();
|
||||
} else {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
}
|
||||
};
|
||||
performRequest();
|
||||
|
||||
if (const auto main = App::main()) {
|
||||
main->finishForwarding(message.action);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SendExistingDocument(
|
||||
Api::MessageToSend &&message,
|
||||
not_null<DocumentData*> document) {
|
||||
const auto inputMedia = [=] {
|
||||
return MTP_inputMediaDocument(
|
||||
MTP_flags(0),
|
||||
document->mtpInput(),
|
||||
MTPint());
|
||||
};
|
||||
SendExistingMedia(
|
||||
std::move(message),
|
||||
document,
|
||||
inputMedia,
|
||||
document->stickerOrGifOrigin());
|
||||
|
||||
if (document->sticker()) {
|
||||
if (const auto main = App::main()) {
|
||||
main->incrementSticker(document);
|
||||
document->session().data().notifyRecentStickersUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendExistingPhoto(
|
||||
Api::MessageToSend &&message,
|
||||
not_null<PhotoData*> photo) {
|
||||
const auto inputMedia = [=] {
|
||||
return MTP_inputMediaPhoto(
|
||||
MTP_flags(0),
|
||||
photo->mtpInput(),
|
||||
MTPint());
|
||||
};
|
||||
SendExistingMedia(
|
||||
std::move(message),
|
||||
photo,
|
||||
inputMedia,
|
||||
Data::FileOrigin());
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
25
Telegram/SourceFiles/api/api_sending.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
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
|
||||
|
||||
class History;
|
||||
class DocumentData;
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct MessageToSend;
|
||||
|
||||
void SendExistingDocument(
|
||||
Api::MessageToSend &&message,
|
||||
not_null<DocumentData*> document);
|
||||
|
||||
void SendExistingPhoto(
|
||||
Api::MessageToSend &&message,
|
||||
not_null<PhotoData*> photo);
|
||||
|
||||
} // namespace Api
|
||||
235
Telegram/SourceFiles/api/api_single_message_search.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
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_single_message_search.h"
|
||||
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_search_controller.h"
|
||||
#include "core/local_url_handlers.h"
|
||||
#include "history/history_item.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
using Key = details::SingleMessageSearchKey;
|
||||
|
||||
Key ExtractKey(const QString &query) {
|
||||
const auto trimmed = query.trimmed();
|
||||
const auto local = Core::TryConvertUrlToLocal(trimmed);
|
||||
const auto check = local.isEmpty() ? trimmed : local;
|
||||
const auto parse = [&] {
|
||||
const auto delimeter = check.indexOf('?');
|
||||
return (delimeter > 0)
|
||||
? qthelp::url_parse_params(
|
||||
check.mid(delimeter + 1),
|
||||
qthelp::UrlParamNameTransform::ToLower)
|
||||
: QMap<QString, QString>();
|
||||
};
|
||||
if (check.startsWith(qstr("tg://privatepost"), Qt::CaseInsensitive)) {
|
||||
const auto params = parse();
|
||||
const auto channel = params.value("channel");
|
||||
const auto post = params.value("post").toInt();
|
||||
return (channel.toInt() && post) ? Key{ channel, post } : Key();
|
||||
} else if (check.startsWith(qstr("tg://resolve"), Qt::CaseInsensitive)) {
|
||||
const auto params = parse();
|
||||
const auto domain = params.value("domain");
|
||||
const auto post = params.value("post").toInt();
|
||||
return (!domain.isEmpty() && post) ? Key{ domain, post } : Key();
|
||||
}
|
||||
return Key();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SingleMessageSearch::SingleMessageSearch(not_null<Main::Session*> session)
|
||||
: _session(session) {
|
||||
}
|
||||
|
||||
SingleMessageSearch::~SingleMessageSearch() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void SingleMessageSearch::clear() {
|
||||
_cache.clear();
|
||||
_requestKey = Key();
|
||||
_session->api().request(base::take(_requestId)).cancel();
|
||||
}
|
||||
|
||||
std::optional<HistoryItem*> SingleMessageSearch::lookup(
|
||||
const QString &query,
|
||||
Fn<void()> ready) {
|
||||
const auto key = ExtractKey(query);
|
||||
if (!key) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto i = _cache.find(key);
|
||||
if (i != end(_cache)) {
|
||||
return _session->data().message(i->second);
|
||||
}
|
||||
if (!(_requestKey == key)) {
|
||||
_session->api().request(base::take(_requestId)).cancel();
|
||||
_requestKey = key;
|
||||
}
|
||||
return performLookup(ready);
|
||||
}
|
||||
|
||||
std::optional<HistoryItem*> SingleMessageSearch::performLookupByChannel(
|
||||
not_null<ChannelData*> channel,
|
||||
Fn<void()> ready) {
|
||||
Expects(!_requestKey.empty());
|
||||
|
||||
const auto postId = _requestKey.postId;
|
||||
if (const auto item = _session->data().message(channel, postId)) {
|
||||
_cache.emplace(_requestKey, item->fullId());
|
||||
return item;
|
||||
} else if (!ready) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto fail = [=] {
|
||||
_cache.emplace(_requestKey, FullMsgId());
|
||||
ready();
|
||||
};
|
||||
_requestId = _session->api().request(MTPchannels_GetMessages(
|
||||
channel->inputChannel,
|
||||
MTP_vector<MTPInputMessage>(1, MTP_inputMessageID(MTP_int(postId)))
|
||||
)).done([=](const MTPmessages_Messages &result) {
|
||||
const auto received = Api::ParseSearchResult(
|
||||
channel,
|
||||
Storage::SharedMediaType::kCount,
|
||||
postId,
|
||||
Data::LoadDirection::Around,
|
||||
result);
|
||||
if (!received.messageIds.empty()
|
||||
&& received.messageIds.front() == postId) {
|
||||
_cache.emplace(
|
||||
_requestKey,
|
||||
FullMsgId(channel->bareId(), postId));
|
||||
ready();
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}).fail([=](const RPCError &error) {
|
||||
fail();
|
||||
}).send();
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<HistoryItem*> SingleMessageSearch::performLookupById(
|
||||
ChannelId channelId,
|
||||
Fn<void()> ready) {
|
||||
Expects(!_requestKey.empty());
|
||||
|
||||
if (const auto channel = _session->data().channelLoaded(channelId)) {
|
||||
return performLookupByChannel(channel, ready);
|
||||
} else if (!ready) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto fail = [=] {
|
||||
_cache.emplace(_requestKey, FullMsgId());
|
||||
ready();
|
||||
};
|
||||
_requestId = _session->api().request(MTPchannels_GetChannels(
|
||||
MTP_vector<MTPInputChannel>(
|
||||
1,
|
||||
MTP_inputChannel(MTP_int(channelId), MTP_long(0)))
|
||||
)).done([=](const MTPmessages_Chats &result) {
|
||||
result.match([&](const auto &data) {
|
||||
const auto peer = _session->data().processChats(data.vchats());
|
||||
if (peer && peer->id == peerFromChannel(channelId)) {
|
||||
if (performLookupByChannel(peer->asChannel(), ready)) {
|
||||
ready();
|
||||
}
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
fail();
|
||||
}).send();
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<HistoryItem*> SingleMessageSearch::performLookupByUsername(
|
||||
const QString &username,
|
||||
Fn<void()> ready) {
|
||||
Expects(!_requestKey.empty());
|
||||
|
||||
if (const auto peer = _session->data().peerByUsername(username)) {
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
return performLookupByChannel(channel, ready);
|
||||
}
|
||||
_cache.emplace(_requestKey, FullMsgId());
|
||||
return nullptr;
|
||||
} else if (!ready) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto fail = [=] {
|
||||
_cache.emplace(_requestKey, FullMsgId());
|
||||
ready();
|
||||
};
|
||||
_requestId = _session->api().request(MTPcontacts_ResolveUsername(
|
||||
MTP_string(username)
|
||||
)).done([=](const MTPcontacts_ResolvedPeer &result) {
|
||||
result.match([&](const MTPDcontacts_resolvedPeer &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
const auto peerId = peerFromMTP(data.vpeer());
|
||||
const auto peer = peerId
|
||||
? _session->data().peerLoaded(peerId)
|
||||
: nullptr;
|
||||
if (const auto channel = peer ? peer->asChannel() : nullptr) {
|
||||
if (performLookupByChannel(channel, ready)) {
|
||||
ready();
|
||||
}
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
fail();
|
||||
}).send();
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<HistoryItem*> SingleMessageSearch::performLookup(
|
||||
Fn<void()> ready) {
|
||||
Expects(!_requestKey.empty());
|
||||
|
||||
if (!_requestKey.domainOrId[0].isDigit()) {
|
||||
return performLookupByUsername(_requestKey.domainOrId, ready);
|
||||
}
|
||||
const auto channelId = _requestKey.domainOrId.toInt();
|
||||
return performLookupById(channelId, ready);
|
||||
}
|
||||
|
||||
QString ConvertPeerSearchQuery(const QString &query) {
|
||||
const auto trimmed = query.trimmed();
|
||||
const auto local = Core::TryConvertUrlToLocal(trimmed);
|
||||
const auto check = local.isEmpty() ? trimmed : local;
|
||||
if (!check.startsWith(qstr("tg://resolve"), Qt::CaseInsensitive)) {
|
||||
return query;
|
||||
}
|
||||
const auto delimeter = check.indexOf('?');
|
||||
const auto params = (delimeter > 0)
|
||||
? qthelp::url_parse_params(
|
||||
check.mid(delimeter + 1),
|
||||
qthelp::UrlParamNameTransform::ToLower)
|
||||
: QMap<QString, QString>();
|
||||
return params.value("domain", query);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
76
Telegram/SourceFiles/api/api_single_message_search.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
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 Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
namespace details {
|
||||
|
||||
struct SingleMessageSearchKey {
|
||||
QString domainOrId;
|
||||
MsgId postId = 0;
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return domainOrId.isEmpty() || !postId;
|
||||
}
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return !empty();
|
||||
}
|
||||
[[nodiscard]] bool operator<(const SingleMessageSearchKey &other) const {
|
||||
return std::tie(domainOrId, postId)
|
||||
< std::tie(other.domainOrId, other.postId);
|
||||
}
|
||||
[[nodiscard]] bool operator==(
|
||||
const SingleMessageSearchKey &other) const {
|
||||
return std::tie(domainOrId, postId)
|
||||
== std::tie(other.domainOrId, other.postId);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
class SingleMessageSearch {
|
||||
public:
|
||||
explicit SingleMessageSearch(not_null<Main::Session*> session);
|
||||
~SingleMessageSearch();
|
||||
|
||||
void clear();
|
||||
|
||||
// If 'ready' callback is empty, the result must not be 'nullopt'.
|
||||
[[nodiscard]] std::optional<HistoryItem*> lookup(
|
||||
const QString &query,
|
||||
Fn<void()> ready = nullptr);
|
||||
|
||||
private:
|
||||
using Key = details::SingleMessageSearchKey;
|
||||
|
||||
[[nodiscard]] std::optional<HistoryItem*> performLookup(
|
||||
Fn<void()> ready);
|
||||
[[nodiscard]] std::optional<HistoryItem*> performLookupById(
|
||||
ChannelId channelId,
|
||||
Fn<void()> ready);
|
||||
[[nodiscard]] std::optional<HistoryItem*> performLookupByUsername(
|
||||
const QString &username,
|
||||
Fn<void()> ready);
|
||||
[[nodiscard]] std::optional<HistoryItem*> performLookupByChannel(
|
||||
not_null<ChannelData*> channel,
|
||||
Fn<void()> ready);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
std::map<Key, FullMsgId> _cache;
|
||||
mtpRequestId _requestId = 0;
|
||||
Key _requestKey;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] QString ConvertPeerSearchQuery(const QString &query);
|
||||
|
||||
} // namespace Api
|
||||
129
Telegram/SourceFiles/api/api_text_entities.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
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_text_entities.h"
|
||||
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
using namespace TextUtilities;
|
||||
|
||||
} // namespace
|
||||
|
||||
EntitiesInText EntitiesFromMTP(const QVector<MTPMessageEntity> &entities) {
|
||||
auto result = EntitiesInText();
|
||||
if (!entities.isEmpty()) {
|
||||
result.reserve(entities.size());
|
||||
for_const (auto &entity, entities) {
|
||||
switch (entity.type()) {
|
||||
case mtpc_messageEntityUrl: { auto &d = entity.c_messageEntityUrl(); result.push_back({ EntityType::Url, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityTextUrl: { auto &d = entity.c_messageEntityTextUrl(); result.push_back({ EntityType::CustomUrl, d.voffset().v, d.vlength().v, Clean(qs(d.vurl())) }); } break;
|
||||
case mtpc_messageEntityEmail: { auto &d = entity.c_messageEntityEmail(); result.push_back({ EntityType::Email, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityHashtag: { auto &d = entity.c_messageEntityHashtag(); result.push_back({ EntityType::Hashtag, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityCashtag: { auto &d = entity.c_messageEntityCashtag(); result.push_back({ EntityType::Cashtag, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityPhone: break; // Skipping phones.
|
||||
case mtpc_messageEntityMention: { auto &d = entity.c_messageEntityMention(); result.push_back({ EntityType::Mention, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityMentionName: {
|
||||
auto &d = entity.c_messageEntityMentionName();
|
||||
auto data = [&d] {
|
||||
if (auto user = Auth().data().userLoaded(d.vuser_id().v)) {
|
||||
return MentionNameDataFromFields({
|
||||
d.vuser_id().v,
|
||||
user->accessHash() });
|
||||
}
|
||||
return MentionNameDataFromFields(d.vuser_id().v);
|
||||
};
|
||||
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data() });
|
||||
} break;
|
||||
case mtpc_inputMessageEntityMentionName: {
|
||||
auto &d = entity.c_inputMessageEntityMentionName();
|
||||
auto data = ([&d]() -> QString {
|
||||
if (d.vuser_id().type() == mtpc_inputUserSelf) {
|
||||
return MentionNameDataFromFields(Auth().userId());
|
||||
} else if (d.vuser_id().type() == mtpc_inputUser) {
|
||||
auto &user = d.vuser_id().c_inputUser();
|
||||
return MentionNameDataFromFields({ user.vuser_id().v, user.vaccess_hash().v });
|
||||
}
|
||||
return QString();
|
||||
})();
|
||||
if (!data.isEmpty()) {
|
||||
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
|
||||
}
|
||||
} break;
|
||||
case mtpc_messageEntityBotCommand: { auto &d = entity.c_messageEntityBotCommand(); result.push_back({ EntityType::BotCommand, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityBold: { auto &d = entity.c_messageEntityBold(); result.push_back({ EntityType::Bold, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityItalic: { auto &d = entity.c_messageEntityItalic(); result.push_back({ EntityType::Italic, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityUnderline: { auto &d = entity.c_messageEntityUnderline(); result.push_back({ EntityType::Underline, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityStrike: { auto &d = entity.c_messageEntityStrike(); result.push_back({ EntityType::StrikeOut, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset().v, d.vlength().v }); } break;
|
||||
case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset().v, d.vlength().v, Clean(qs(d.vlanguage())) }); } break;
|
||||
// #TODO entities
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MTPVector<MTPMessageEntity> EntitiesToMTP(
|
||||
const EntitiesInText &entities,
|
||||
ConvertOption option) {
|
||||
auto v = QVector<MTPMessageEntity>();
|
||||
v.reserve(entities.size());
|
||||
for_const (auto &entity, entities) {
|
||||
if (entity.length() <= 0) continue;
|
||||
if (option == ConvertOption::SkipLocal
|
||||
&& entity.type() != EntityType::Bold
|
||||
&& entity.type() != EntityType::Italic
|
||||
&& entity.type() != EntityType::Underline
|
||||
&& entity.type() != EntityType::StrikeOut
|
||||
&& entity.type() != EntityType::Code // #TODO entities
|
||||
&& entity.type() != EntityType::Pre
|
||||
&& entity.type() != EntityType::MentionName
|
||||
&& entity.type() != EntityType::CustomUrl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto offset = MTP_int(entity.offset());
|
||||
auto length = MTP_int(entity.length());
|
||||
switch (entity.type()) {
|
||||
case EntityType::Url: v.push_back(MTP_messageEntityUrl(offset, length)); break;
|
||||
case EntityType::CustomUrl: v.push_back(MTP_messageEntityTextUrl(offset, length, MTP_string(entity.data()))); break;
|
||||
case EntityType::Email: v.push_back(MTP_messageEntityEmail(offset, length)); break;
|
||||
case EntityType::Hashtag: v.push_back(MTP_messageEntityHashtag(offset, length)); break;
|
||||
case EntityType::Cashtag: v.push_back(MTP_messageEntityCashtag(offset, length)); break;
|
||||
case EntityType::Mention: v.push_back(MTP_messageEntityMention(offset, length)); break;
|
||||
case EntityType::MentionName: {
|
||||
auto inputUser = ([](const QString &data) -> MTPInputUser {
|
||||
auto fields = MentionNameDataToFields(data);
|
||||
if (fields.userId == Auth().userId()) {
|
||||
return MTP_inputUserSelf();
|
||||
} else if (fields.userId) {
|
||||
return MTP_inputUser(MTP_int(fields.userId), MTP_long(fields.accessHash));
|
||||
}
|
||||
return MTP_inputUserEmpty();
|
||||
})(entity.data());
|
||||
if (inputUser.type() != mtpc_inputUserEmpty) {
|
||||
v.push_back(MTP_inputMessageEntityMentionName(offset, length, inputUser));
|
||||
}
|
||||
} break;
|
||||
case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break;
|
||||
case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break;
|
||||
case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break;
|
||||
case EntityType::Underline: v.push_back(MTP_messageEntityUnderline(offset, length)); break;
|
||||
case EntityType::StrikeOut: v.push_back(MTP_messageEntityStrike(offset, length)); break;
|
||||
case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities
|
||||
case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break;
|
||||
}
|
||||
}
|
||||
return MTP_vector<MTPMessageEntity>(std::move(v));
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
23
Telegram/SourceFiles/api/api_text_entities.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/text/text_entity.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
EntitiesInText EntitiesFromMTP(const QVector<MTPMessageEntity> &entities);
|
||||
enum class ConvertOption {
|
||||
WithLocal,
|
||||
SkipLocal,
|
||||
};
|
||||
MTPVector<MTPMessageEntity> EntitiesToMTP(
|
||||
const EntitiesInText &entities,
|
||||
ConvertOption option = ConvertOption::WithLocal);
|
||||
|
||||
} // namespace Api
|
||||
@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <rpl/event_stream.h>
|
||||
#include "api/api_common.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/flat_map.h"
|
||||
#include "base/flat_set.h"
|
||||
@@ -16,13 +16,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_messages.h"
|
||||
|
||||
class TaskQueue;
|
||||
class AuthSession;
|
||||
struct MessageGroupId;
|
||||
struct SendingAlbum;
|
||||
enum class SendMediaType;
|
||||
struct FileLoadTo;
|
||||
class mtpFileLoader;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Data {
|
||||
struct UpdatedFileReferences;
|
||||
class WallPaper;
|
||||
@@ -46,23 +49,51 @@ struct CloudPasswordState;
|
||||
} // namespace Core
|
||||
|
||||
namespace Api {
|
||||
namespace details {
|
||||
|
||||
template <typename IntRange>
|
||||
inline int32 CountHash(IntRange &&range) {
|
||||
uint32 acc = 0;
|
||||
for (auto value : range) {
|
||||
acc += (acc * 20261) + uint32(value);
|
||||
inline QString ToString(const QString &value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
inline QString ToString(int32 value) {
|
||||
return QString::number(value);
|
||||
}
|
||||
|
||||
inline QString ToString(uint64 value) {
|
||||
return QString::number(value);
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <
|
||||
typename ...Types,
|
||||
typename = std::enable_if_t<(sizeof...(Types) > 0)>>
|
||||
QString RequestKey(Types &&...values) {
|
||||
const auto strings = { details::ToString(values)... };
|
||||
if (strings.size() == 1) {
|
||||
return *strings.begin();
|
||||
}
|
||||
return int32(acc & 0x7FFFFFFF);
|
||||
|
||||
auto result = QString();
|
||||
result.reserve(
|
||||
ranges::accumulate(strings, 0, ranges::plus(), &QString::size));
|
||||
for (const auto &string : strings) {
|
||||
result.append(string);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
class ApiWrap : public MTP::Sender, private base::Subscriber {
|
||||
public:
|
||||
using SendAction = Api::SendAction;
|
||||
using MessageToSend = Api::MessageToSend;
|
||||
|
||||
struct Privacy {
|
||||
enum class Key {
|
||||
PhoneNumber,
|
||||
AddedByPhone,
|
||||
LastSeen,
|
||||
Calls,
|
||||
Invites,
|
||||
@@ -99,9 +130,17 @@ public:
|
||||
bool operator!=(const BlockedUsersSlice &other) const;
|
||||
};
|
||||
|
||||
ApiWrap(not_null<AuthSession*> session);
|
||||
explicit ApiWrap(not_null<Main::Session*> session);
|
||||
|
||||
Main::Session &session() const;
|
||||
|
||||
void applyUpdates(
|
||||
const MTPUpdates &updates,
|
||||
uint64 sentMessageRandomId = 0);
|
||||
|
||||
void registerModifyRequest(const QString &key, mtpRequestId requestId);
|
||||
void clearModifyRequest(const QString &key);
|
||||
|
||||
void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0);
|
||||
void applyNotifySettings(
|
||||
MTPInputNotifyPeer peer,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
@@ -148,6 +187,7 @@ public:
|
||||
void requestFullPeer(not_null<PeerData*> peer);
|
||||
void requestPeer(not_null<PeerData*> peer);
|
||||
void requestPeers(const QList<PeerData*> &peers);
|
||||
void requestPeerSettings(not_null<PeerData*> peer);
|
||||
void requestLastParticipants(not_null<ChannelData*> channel);
|
||||
void requestBots(not_null<ChannelData*> channel);
|
||||
void requestAdmins(not_null<ChannelData*> channel);
|
||||
@@ -211,10 +251,6 @@ public:
|
||||
void deleteAllFromUser(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> from);
|
||||
void saveDefaultRestrictions(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPChatBannedRights &rights,
|
||||
Fn<void(bool)> callback = nullptr);
|
||||
|
||||
void requestWebPageDelayed(WebPageData *page);
|
||||
void clearWebPageRequest(WebPageData *page);
|
||||
@@ -246,7 +282,7 @@ public:
|
||||
void leaveChannel(not_null<ChannelData*> channel);
|
||||
|
||||
void blockUser(not_null<UserData*> user);
|
||||
void unblockUser(not_null<UserData*> user);
|
||||
void unblockUser(not_null<UserData*> user, Fn<void()> onDone = nullptr);
|
||||
|
||||
void exportInviteLink(not_null<PeerData*> peer);
|
||||
void requestNotifySettings(const MTPInputNotifyPeer &peer);
|
||||
@@ -328,36 +364,27 @@ public:
|
||||
const MTPchannels_ChannelParticipants &result,
|
||||
Fn<void(
|
||||
int availableCount,
|
||||
const QVector<MTPChannelParticipant> &list)> callbackList,
|
||||
const QVector<MTPChannelParticipant> &list)> callbackList = nullptr,
|
||||
Fn<void()> callbackNotModified = nullptr);
|
||||
void addChatParticipants(
|
||||
not_null<PeerData*> peer,
|
||||
const std::vector<not_null<UserData*>> &users);
|
||||
|
||||
struct SendOptions {
|
||||
SendOptions(not_null<History*> history);
|
||||
|
||||
not_null<History*> history;
|
||||
MsgId replyTo = 0;
|
||||
WebPageId webPageId = 0;
|
||||
bool clearDraft = false;
|
||||
bool generateLocal = true;
|
||||
bool handleSupportSwitch = false;
|
||||
};
|
||||
rpl::producer<SendOptions> sendActions() const {
|
||||
rpl::producer<SendAction> sendActions() const {
|
||||
return _sendActions.events();
|
||||
}
|
||||
void sendAction(const SendOptions &options);
|
||||
void sendAction(const SendAction &action);
|
||||
void forwardMessages(
|
||||
HistoryItemsList &&items,
|
||||
const SendOptions &options,
|
||||
const SendAction &action,
|
||||
FnMut<void()> &&successCallback = nullptr);
|
||||
void shareContact(
|
||||
const QString &phone,
|
||||
const QString &firstName,
|
||||
const QString &lastName,
|
||||
const SendOptions &options);
|
||||
void shareContact(not_null<UserData*> user, const SendOptions &options);
|
||||
const SendAction &action);
|
||||
void shareContact(not_null<UserData*> user, const SendAction &action);
|
||||
void readServerHistory(not_null<History*> history);
|
||||
void readServerHistoryForce(not_null<History*> history);
|
||||
//void readFeed( // #feed
|
||||
@@ -368,66 +395,54 @@ public:
|
||||
QByteArray result,
|
||||
VoiceWaveform waveform,
|
||||
int duration,
|
||||
const SendOptions &options);
|
||||
const SendAction &action);
|
||||
void sendFiles(
|
||||
Storage::PreparedList &&list,
|
||||
SendMediaType type,
|
||||
TextWithTags &&caption,
|
||||
std::shared_ptr<SendingAlbum> album,
|
||||
const SendOptions &options);
|
||||
const SendAction &action);
|
||||
void sendFile(
|
||||
const QByteArray &fileContent,
|
||||
SendMediaType type,
|
||||
const SendOptions &options);
|
||||
const SendAction &action);
|
||||
|
||||
void editMedia(
|
||||
Storage::PreparedList &&list,
|
||||
SendMediaType type,
|
||||
TextWithTags &&caption,
|
||||
const SendOptions &options,
|
||||
const SendAction &action,
|
||||
MsgId msgIdToEdit);
|
||||
|
||||
void sendUploadedPhoto(
|
||||
FullMsgId localId,
|
||||
const MTPInputFile &file,
|
||||
bool silent);
|
||||
Api::SendOptions options);
|
||||
void sendUploadedDocument(
|
||||
FullMsgId localId,
|
||||
const MTPInputFile &file,
|
||||
const std::optional<MTPInputFile> &thumb,
|
||||
bool silent);
|
||||
Api::SendOptions options);
|
||||
void editUploadedFile(
|
||||
FullMsgId localId,
|
||||
const MTPInputFile &file,
|
||||
const std::optional<MTPInputFile> &thumb,
|
||||
bool silent,
|
||||
Api::SendOptions options,
|
||||
bool isDocument);
|
||||
|
||||
void cancelLocalItem(not_null<HistoryItem*> item);
|
||||
|
||||
struct MessageToSend {
|
||||
MessageToSend(not_null<History*> history);
|
||||
|
||||
not_null<History*> history;
|
||||
TextWithTags textWithTags;
|
||||
MsgId replyTo = 0;
|
||||
WebPageId webPageId = 0;
|
||||
bool clearDraft = true;
|
||||
bool handleSupportSwitch = false;
|
||||
};
|
||||
void sendMessage(MessageToSend &&message);
|
||||
void sendBotStart(not_null<UserData*> bot, PeerData *chat = nullptr);
|
||||
void sendInlineResult(
|
||||
not_null<UserData*> bot,
|
||||
not_null<InlineBots::Result*> data,
|
||||
const SendOptions &options);
|
||||
void sendExistingDocument(
|
||||
not_null<DocumentData*> document,
|
||||
Data::FileOrigin origin,
|
||||
TextWithEntities caption,
|
||||
const SendOptions &options);
|
||||
|
||||
void requestSupportContact(FnMut<void(const MTPUser&)> callback);
|
||||
const SendAction &action);
|
||||
void sendMessageFail(
|
||||
const RPCError &error,
|
||||
not_null<PeerData*> peer,
|
||||
uint64 randomId = 0,
|
||||
FullMsgId itemId = FullMsgId());
|
||||
|
||||
void uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image);
|
||||
void clearPeerPhoto(not_null<PhotoData*> photo);
|
||||
@@ -456,7 +471,7 @@ public:
|
||||
|
||||
void createPoll(
|
||||
const PollData &data,
|
||||
const SendOptions &options,
|
||||
const SendAction &action,
|
||||
FnMut<void()> done,
|
||||
FnMut<void(const RPCError &error)> fail);
|
||||
void sendPollVotes(
|
||||
@@ -533,10 +548,6 @@ private:
|
||||
not_null<ChannelData*> channel,
|
||||
int availableCount,
|
||||
const QVector<MTPChannelParticipant> &list);
|
||||
void applyAdminsList(
|
||||
not_null<ChannelData*> channel,
|
||||
int availableCount,
|
||||
const QVector<MTPChannelParticipant> &list);
|
||||
void resolveWebPages();
|
||||
void gotWebPages(
|
||||
ChannelData *channel,
|
||||
@@ -605,7 +616,7 @@ private:
|
||||
const QString &firstName,
|
||||
const QString &lastName,
|
||||
UserId userId,
|
||||
const SendOptions &options);
|
||||
const SendAction &action);
|
||||
|
||||
void deleteHistory(
|
||||
not_null<PeerData*> peer,
|
||||
@@ -624,7 +635,6 @@ private:
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> from);
|
||||
|
||||
void sendMessageFail(const RPCError &error);
|
||||
void uploadAlbumMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MessageGroupId &groupId,
|
||||
@@ -640,13 +650,13 @@ private:
|
||||
void sendMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputMedia &media,
|
||||
bool silent);
|
||||
Api::SendOptions options);
|
||||
void sendMediaWithRandomId(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputMedia &media,
|
||||
bool silent,
|
||||
Api::SendOptions options,
|
||||
uint64 randomId);
|
||||
FileLoadTo fileLoadTaskOptions(const SendOptions &options) const;
|
||||
FileLoadTo fileLoadTaskOptions(const SendAction &action) const;
|
||||
|
||||
//void readFeeds(); // #feed
|
||||
|
||||
@@ -678,7 +688,9 @@ private:
|
||||
|
||||
void sendDialogRequests();
|
||||
|
||||
not_null<AuthSession*> _session;
|
||||
not_null<Main::Session*> _session;
|
||||
|
||||
base::flat_map<QString, int> _modifyRequests;
|
||||
|
||||
MessageDataRequests _messageDataRequests;
|
||||
QMap<ChannelData*, MessageDataRequests> _channelMessageDataRequests;
|
||||
@@ -687,6 +699,7 @@ private:
|
||||
using PeerRequests = QMap<PeerData*, mtpRequestId>;
|
||||
PeerRequests _fullPeerRequests;
|
||||
PeerRequests _peerRequests;
|
||||
base::flat_set<not_null<PeerData*>> _requestedPeerSettings;
|
||||
|
||||
PeerRequests _participantsRequests;
|
||||
PeerRequests _botsRequests;
|
||||
@@ -706,10 +719,6 @@ private:
|
||||
not_null<UserData*>>;
|
||||
base::flat_map<KickRequest, mtpRequestId> _kickRequests;
|
||||
|
||||
base::flat_map<
|
||||
not_null<PeerData*>,
|
||||
mtpRequestId> _defaultRestrictionsRequests;
|
||||
|
||||
base::flat_set<not_null<ChannelData*>> _selfParticipantRequests;
|
||||
|
||||
base::flat_map<
|
||||
@@ -790,7 +799,7 @@ private:
|
||||
not_null<Data::Folder*>,
|
||||
DialogsLoadState> _foldersLoadState;
|
||||
|
||||
rpl::event_stream<SendOptions> _sendActions;
|
||||
rpl::event_stream<SendAction> _sendActions;
|
||||
|
||||
struct ReadRequest {
|
||||
ReadRequest(mtpRequestId requestId, MsgId upTo)
|
||||
|
||||
@@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/application.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "storage/file_upload.h"
|
||||
#include "storage/localstorage.h"
|
||||
@@ -39,13 +40,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "apiwrap.h"
|
||||
#include "numbers.h"
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_overview.h"
|
||||
#include "styles/style_mediaview.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtGui/QFontDatabase>
|
||||
|
||||
#ifdef OS_MAC_OLD
|
||||
#include <libexif/exif-data.h>
|
||||
#endif // OS_MAC_OLD
|
||||
@@ -59,8 +63,6 @@ namespace {
|
||||
*pressedLinkItem = nullptr,
|
||||
*mousedItem = nullptr;
|
||||
|
||||
style::font monofont;
|
||||
|
||||
struct CornersPixmaps {
|
||||
QPixmap p[4];
|
||||
};
|
||||
@@ -101,88 +103,9 @@ namespace App {
|
||||
return result;
|
||||
}
|
||||
|
||||
MainWindow *wnd() {
|
||||
return Core::IsAppLaunched()
|
||||
? Core::App().getActiveWindow()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
MainWidget *main() {
|
||||
if (auto window = wnd()) {
|
||||
return window->mainWidget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void addSavedGif(DocumentData *doc) {
|
||||
auto &saved = Auth().data().savedGifsRef();
|
||||
int32 index = saved.indexOf(doc);
|
||||
if (index) {
|
||||
if (index > 0) saved.remove(index);
|
||||
saved.push_front(doc);
|
||||
if (saved.size() > Global::SavedGifsLimit()) saved.pop_back();
|
||||
Local::writeSavedGifs();
|
||||
|
||||
Auth().data().notifySavedGifsUpdated();
|
||||
Auth().data().setLastSavedGifsUpdate(0);
|
||||
Auth().api().updateStickers();
|
||||
}
|
||||
}
|
||||
|
||||
void checkSavedGif(HistoryItem *item) {
|
||||
if (!item->Has<HistoryMessageForwarded>() && (item->out() || item->history()->peer == Auth().user())) {
|
||||
if (const auto media = item->media()) {
|
||||
if (const auto document = media->document()) {
|
||||
if (document->isGifv()) {
|
||||
addSavedGif(document);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink) {
|
||||
if (const auto user = Auth().data().userLoaded(userId.v)) {
|
||||
const auto wasShowPhone = (user->contactStatus() == UserData::ContactStatus::CanAdd);
|
||||
switch (myLink.type()) {
|
||||
case mtpc_contactLinkContact:
|
||||
user->setContactStatus(UserData::ContactStatus::Contact);
|
||||
break;
|
||||
case mtpc_contactLinkNone:
|
||||
case mtpc_contactLinkUnknown:
|
||||
user->setContactStatus(UserData::ContactStatus::PhoneUnknown);
|
||||
break;
|
||||
}
|
||||
if (user->contactStatus() == UserData::ContactStatus::PhoneUnknown
|
||||
&& !user->phone().isEmpty()
|
||||
&& user->id != Auth().userPeerId()) {
|
||||
user->setContactStatus(UserData::ContactStatus::CanAdd);
|
||||
}
|
||||
|
||||
const auto showPhone = !user->isServiceUser()
|
||||
&& !user->isSelf()
|
||||
&& user->contactStatus() == UserData::ContactStatus::CanAdd;
|
||||
const auto showPhoneChanged = !user->isServiceUser()
|
||||
&& !user->isSelf()
|
||||
&& (showPhone != wasShowPhone);
|
||||
if (showPhoneChanged) {
|
||||
user->setName(
|
||||
TextUtilities::SingleLine(user->firstName),
|
||||
TextUtilities::SingleLine(user->lastName),
|
||||
showPhone
|
||||
? App::formatPhone(user->phone())
|
||||
: QString(),
|
||||
TextUtilities::SingleLine(user->username));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString peerName(const PeerData *peer, bool forDialogs) {
|
||||
return peer ? ((forDialogs && peer->isUser() && !peer->asUser()->nameOrPhone.isEmpty()) ? peer->asUser()->nameOrPhone : peer->name) : lang(lng_deleted);
|
||||
}
|
||||
|
||||
void prepareCorners(RoundCorners index, int32 radius, const QBrush &brush, const style::color *shadow = nullptr, QImage *cors = nullptr) {
|
||||
Expects(::corners.size() > index);
|
||||
|
||||
int32 r = radius * cIntRetinaFactor(), s = st::msgShadow * cIntRetinaFactor();
|
||||
QImage rect(r * 3, r * 3 + (shadow ? s : 0), QImage::Format_ARGB32_Premultiplied), localCors[4];
|
||||
{
|
||||
@@ -213,14 +136,6 @@ namespace App {
|
||||
}
|
||||
}
|
||||
|
||||
void tryFontFamily(QString &family, const QString &tryFamily) {
|
||||
if (family.isEmpty()) {
|
||||
if (!QFontInfo(QFont(tryFamily)).family().trimmed().compare(tryFamily, Qt::CaseInsensitive)) {
|
||||
family = tryFamily;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createMaskCorners() {
|
||||
QImage mask[4];
|
||||
prepareCorners(SmallMaskCorners, st::buttonRadius, QColor(255, 255, 255), nullptr, mask);
|
||||
@@ -279,16 +194,6 @@ namespace App {
|
||||
}
|
||||
|
||||
void initMedia() {
|
||||
if (!::monofont) {
|
||||
QString family;
|
||||
tryFontFamily(family, qsl("Consolas"));
|
||||
tryFontFamily(family, qsl("Liberation Mono"));
|
||||
tryFontFamily(family, qsl("Menlo"));
|
||||
tryFontFamily(family, qsl("Courier"));
|
||||
if (family.isEmpty()) family = QFontDatabase::systemFont(QFontDatabase::FixedFont).family();
|
||||
::monofont = style::font(st::normalFont->f.pixelSize(), 0, family);
|
||||
}
|
||||
|
||||
createCorners();
|
||||
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
@@ -368,16 +273,11 @@ namespace App {
|
||||
mousedItem(nullptr);
|
||||
}
|
||||
|
||||
const style::font &monofont() {
|
||||
return ::monofont;
|
||||
}
|
||||
|
||||
void quit() {
|
||||
if (quitting()) {
|
||||
return;
|
||||
} else if (AuthSession::Exists()
|
||||
&& Auth().data().exportInProgress()) {
|
||||
Auth().data().stopExportWithConfirmation([] { App::quit(); });
|
||||
} else if (Core::IsAppLaunched()
|
||||
&& Core::App().exportPreventsQuit()) {
|
||||
return;
|
||||
}
|
||||
setLaunchState(QuitRequested);
|
||||
@@ -527,15 +427,6 @@ namespace App {
|
||||
rectWithCorners(p, rect, st::msgInBg, MessageInCorners, corners);
|
||||
}
|
||||
|
||||
QImage *cornersMask(ImageRoundRadius radius) {
|
||||
switch (radius) {
|
||||
case ImageRoundRadius::Large: return ::cornersMaskLarge;
|
||||
case ImageRoundRadius::Small:
|
||||
default: break;
|
||||
}
|
||||
return ::cornersMaskSmall;
|
||||
}
|
||||
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, const CornersPixmaps &corner, const style::color *shadow, RectParts parts) {
|
||||
auto cornerWidth = corner.p[0].width() / cIntRetinaFactor();
|
||||
auto cornerHeight = corner.p[0].height() / cIntRetinaFactor();
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "data/data_types.h"
|
||||
#include "ui/rect_part.h"
|
||||
|
||||
enum class ImageRoundRadius;
|
||||
class MainWindow;
|
||||
@@ -18,10 +19,16 @@ namespace HistoryView {
|
||||
class Element;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace Media {
|
||||
namespace Clip {
|
||||
class Reader;
|
||||
} // namespace Clip
|
||||
} // namespace Media
|
||||
|
||||
using HistoryItemsMap = base::flat_set<not_null<HistoryItem*>>;
|
||||
using GifItems = QHash<Media::Clip::Reader*, HistoryItem*>;
|
||||
|
||||
enum RoundCorners {
|
||||
enum RoundCorners : int {
|
||||
SmallMaskCorners = 0x00, // for images
|
||||
LargeMaskCorners,
|
||||
|
||||
@@ -60,16 +67,8 @@ enum RoundCorners {
|
||||
};
|
||||
|
||||
namespace App {
|
||||
MainWindow *wnd();
|
||||
MainWidget *main();
|
||||
|
||||
QString formatPhone(QString phone);
|
||||
|
||||
void addSavedGif(DocumentData *doc);
|
||||
void checkSavedGif(HistoryItem *item);
|
||||
[[nodiscard]] QString peerName(const PeerData *peer, bool forDialogs = false);
|
||||
void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink);
|
||||
|
||||
void hoveredItem(HistoryView::Element *item);
|
||||
HistoryView::Element *hoveredItem();
|
||||
void pressedItem(HistoryView::Element *item);
|
||||
@@ -82,8 +81,6 @@ namespace App {
|
||||
HistoryView::Element *mousedItem();
|
||||
void clearMousedItems();
|
||||
|
||||
const style::font &monofont();
|
||||
|
||||
void initMedia();
|
||||
void deinitMedia();
|
||||
|
||||
@@ -107,7 +104,6 @@ namespace App {
|
||||
void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners);
|
||||
void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, RectParts corners);
|
||||
|
||||
QImage *cornersMask(ImageRoundRadius radius);
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full);
|
||||
inline void roundRect(Painter &p, const QRect &rect, style::color bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) {
|
||||
return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, index, shadow, parts);
|
||||
|
||||
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QLatin1String>
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Type>
|
||||
@@ -30,6 +32,72 @@ inline bool contains(const Container &container, const T &value) {
|
||||
return std::find(std::begin(container), end, value) != end;
|
||||
}
|
||||
|
||||
template <typename D, typename T>
|
||||
inline constexpr D up_cast(T object) {
|
||||
using DV = std::decay_t<decltype(*D())>;
|
||||
using TV = std::decay_t<decltype(*T())>;
|
||||
if constexpr (std::is_base_of_v<DV, TV>) {
|
||||
return object;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// We need a custom comparator for set<std::unique_ptr<T>>::find to work with pointers.
|
||||
// thanks to http://stackoverflow.com/questions/18939882/raw-pointer-lookup-for-sets-of-unique-ptrs
|
||||
template <typename T>
|
||||
struct pointer_comparator {
|
||||
using is_transparent = std::true_type;
|
||||
|
||||
// helper does some magic in order to reduce the number of
|
||||
// pairs of types we need to know how to compare: it turns
|
||||
// everything into a pointer, and then uses `std::less<T*>`
|
||||
// to do the comparison:
|
||||
struct helper {
|
||||
const T *ptr = nullptr;
|
||||
helper() = default;
|
||||
helper(const helper &other) = default;
|
||||
helper(const T *p) : ptr(p) {
|
||||
}
|
||||
template <typename ...Ts>
|
||||
helper(const std::shared_ptr<Ts...> &other) : ptr(other.get()) {
|
||||
}
|
||||
template <typename ...Ts>
|
||||
helper(const std::unique_ptr<Ts...> &other) : ptr(other.get()) {
|
||||
}
|
||||
bool operator<(helper other) const {
|
||||
return std::less<const T*>()(ptr, other.ptr);
|
||||
}
|
||||
};
|
||||
|
||||
// without helper, we'd need 2^n different overloads, where
|
||||
// n is the number of types we want to support (so, 8 with
|
||||
// raw pointers, unique pointers, and shared pointers). That
|
||||
// seems silly.
|
||||
// && helps enforce rvalue use only
|
||||
bool operator()(const helper &&lhs, const helper &&rhs) const {
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline QString FromUtf8Safe(const char *string, int size = -1) {
|
||||
if (!string || !size) {
|
||||
return QString();
|
||||
} else if (size < 0) {
|
||||
size = strlen(string);
|
||||
}
|
||||
const auto result = QString::fromUtf8(string, size);
|
||||
const auto back = result.toUtf8();
|
||||
return (back.size() != size || memcmp(back.constData(), string, size))
|
||||
? QString::fromLocal8Bit(string, size)
|
||||
: result;
|
||||
}
|
||||
|
||||
inline QString FromUtf8Safe(const QByteArray &string) {
|
||||
return FromUtf8Safe(string.constData(), string.size());
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -9,6 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
// Ensures/Expects.
|
||||
#include <gsl/gsl_assert>
|
||||
|
||||
namespace base {
|
||||
namespace assertion {
|
||||
|
||||
|
||||
@@ -5,17 +5,14 @@ the official desktop application for the Telegram messaging service.
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cmath>
|
||||
#include "base/basic_types.h"
|
||||
|
||||
#include <QtMath>
|
||||
#include <QDebug>
|
||||
#include <QList>
|
||||
#include <QPointF>
|
||||
#include <QSizeF>
|
||||
#include <QVector4D>
|
||||
// Methods that must be implemented outside lib_base.
|
||||
|
||||
#include "json.h"
|
||||
#include "beziereasing.h"
|
||||
namespace base {
|
||||
|
||||
void EnterFromEventLoop(FnMut<void()> &&method);
|
||||
|
||||
} // namespace
|
||||
@@ -7,3 +7,4 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "base/base_pch.h"
|
||||
|
||||
// Precompiled header helper.
|
||||
|
||||
@@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/basic_types.h"
|
||||
#include <gsl/gsl>
|
||||
#include <gsl/gsl_byte>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace bytes {
|
||||
|
||||
|
||||
61
Telegram/SourceFiles/base/crc32hash.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
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 "base/crc32hash.h"
|
||||
|
||||
namespace base {
|
||||
namespace {
|
||||
|
||||
class Crc32Table {
|
||||
public:
|
||||
Crc32Table() {
|
||||
auto poly = std::uint32_t(0x04c11db7);
|
||||
for (auto i = 0; i != 256; ++i) {
|
||||
_data[i] = reflect(i, 8) << 24;
|
||||
for (auto j = 0; j != 8; ++j) {
|
||||
_data[i] = (_data[i] << 1) ^ (_data[i] & (1 << 31) ? poly : 0);
|
||||
}
|
||||
_data[i] = reflect(_data[i], 32);
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t operator[](int index) const {
|
||||
return _data[index];
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint32_t reflect(std::uint32_t val, char ch) {
|
||||
auto result = std::uint32_t(0);
|
||||
for (int i = 1; i < (ch + 1); ++i) {
|
||||
if (val & 1) {
|
||||
result |= 1 << (ch - i);
|
||||
}
|
||||
val >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::uint32_t _data[256];
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::int32_t crc32(const void *data, int len) {
|
||||
static const auto kTable = Crc32Table();
|
||||
|
||||
const auto buffer = static_cast<const std::uint8_t*>(data);
|
||||
|
||||
auto crc = std::uint32_t(0xffffffff);
|
||||
for (auto i = 0; i != len; ++i) {
|
||||
crc = (crc >> 8) ^ kTable[(crc & 0xFF) ^ buffer[i]];
|
||||
}
|
||||
|
||||
return static_cast<std::int32_t>(crc ^ 0xffffffff);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
16
Telegram/SourceFiles/base/crc32hash.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace base {
|
||||
|
||||
std::int32_t crc32(const void *data, int len);
|
||||
|
||||
} // namespace base
|
||||
@@ -53,12 +53,19 @@ struct flat_multi_map_pair_type {
|
||||
, second(std::forward<OtherValue>(value)) {
|
||||
}
|
||||
|
||||
flat_multi_map_pair_type(const flat_multi_map_pair_type&) = default;
|
||||
flat_multi_map_pair_type(flat_multi_map_pair_type&&) = default;
|
||||
flat_multi_map_pair_type(const flat_multi_map_pair_type &pair)
|
||||
: first(pair.first)
|
||||
, second(pair.second) {
|
||||
}
|
||||
|
||||
flat_multi_map_pair_type(flat_multi_map_pair_type &&pair)
|
||||
: first(std::move(const_cast<Key&>(pair.first)))
|
||||
, second(std::move(pair.second)) {
|
||||
}
|
||||
|
||||
flat_multi_map_pair_type &operator=(const flat_multi_map_pair_type&) = delete;
|
||||
flat_multi_map_pair_type &operator=(flat_multi_map_pair_type &&other) {
|
||||
const_cast<Key&>(first) = other.first;
|
||||
const_cast<Key&>(first) = std::move(const_cast<Key&>(other.first));
|
||||
second = std::move(other.second);
|
||||
return *this;
|
||||
}
|
||||
@@ -474,6 +481,28 @@ public:
|
||||
return compare()(key, where->first) ? impl().end() : where;
|
||||
}
|
||||
|
||||
template <typename OtherKey>
|
||||
iterator findFirst(const OtherKey &key) {
|
||||
if (empty()
|
||||
|| compare()(key, front().first)
|
||||
|| compare()(back().first, key)) {
|
||||
return end();
|
||||
}
|
||||
auto where = getLowerBound(key);
|
||||
return compare()(key, where->first) ? impl().end() : where;
|
||||
}
|
||||
|
||||
template <typename OtherKey>
|
||||
const_iterator findFirst(const OtherKey &key) const {
|
||||
if (empty()
|
||||
|| compare()(key, front().first)
|
||||
|| compare()(back().first, key)) {
|
||||
return end();
|
||||
}
|
||||
auto where = getLowerBound(key);
|
||||
return compare()(key, where->first) ? impl().end() : where;
|
||||
}
|
||||
|
||||
bool contains(const Key &key) const {
|
||||
return findFirst(key) != end();
|
||||
}
|
||||
@@ -558,48 +587,54 @@ private:
|
||||
return _data.elements;
|
||||
}
|
||||
|
||||
typename impl_t::iterator getLowerBound(const Key &key) {
|
||||
template <typename OtherKey>
|
||||
typename impl_t::iterator getLowerBound(const OtherKey &key) {
|
||||
return std::lower_bound(
|
||||
std::begin(impl()),
|
||||
std::end(impl()),
|
||||
key,
|
||||
compare());
|
||||
}
|
||||
typename impl_t::const_iterator getLowerBound(const Key &key) const {
|
||||
template <typename OtherKey>
|
||||
typename impl_t::const_iterator getLowerBound(const OtherKey &key) const {
|
||||
return std::lower_bound(
|
||||
std::begin(impl()),
|
||||
std::end(impl()),
|
||||
key,
|
||||
compare());
|
||||
}
|
||||
typename impl_t::iterator getUpperBound(const Key &key) {
|
||||
template <typename OtherKey>
|
||||
typename impl_t::iterator getUpperBound(const OtherKey &key) {
|
||||
return std::upper_bound(
|
||||
std::begin(impl()),
|
||||
std::end(impl()),
|
||||
key,
|
||||
compare());
|
||||
}
|
||||
typename impl_t::const_iterator getUpperBound(const Key &key) const {
|
||||
template <typename OtherKey>
|
||||
typename impl_t::const_iterator getUpperBound(const OtherKey &key) const {
|
||||
return std::upper_bound(
|
||||
std::begin(impl()),
|
||||
std::end(impl()),
|
||||
key,
|
||||
compare());
|
||||
}
|
||||
template <typename OtherKey>
|
||||
std::pair<
|
||||
typename impl_t::iterator,
|
||||
typename impl_t::iterator
|
||||
> getEqualRange(const Key &key) {
|
||||
> getEqualRange(const OtherKey &key) {
|
||||
return std::equal_range(
|
||||
std::begin(impl()),
|
||||
std::end(impl()),
|
||||
key,
|
||||
compare());
|
||||
}
|
||||
template <typename OtherKey>
|
||||
std::pair<
|
||||
typename impl_t::const_iterator,
|
||||
typename impl_t::const_iterator
|
||||
> getEqualRange(const Key &key) const {
|
||||
> getEqualRange(const OtherKey &key) const {
|
||||
return std::equal_range(
|
||||
std::begin(impl()),
|
||||
std::end(impl()),
|
||||
@@ -720,12 +755,12 @@ public:
|
||||
where->second = std::move(value);
|
||||
return { where, false };
|
||||
}
|
||||
template <typename... Args>
|
||||
template <typename OtherKey, typename... Args>
|
||||
std::pair<iterator, bool> emplace(
|
||||
const Key &key,
|
||||
OtherKey &&key,
|
||||
Args&&... args) {
|
||||
return this->insert(value_type(
|
||||
key,
|
||||
std::forward<OtherKey>(key),
|
||||
Type(std::forward<Args>(args)...)));
|
||||
}
|
||||
template <typename... Args>
|
||||
@@ -775,6 +810,14 @@ public:
|
||||
const_iterator find(const Key &key) const {
|
||||
return this->findFirst(key);
|
||||
}
|
||||
template <typename OtherKey>
|
||||
iterator find(const OtherKey &key) {
|
||||
return this->template findFirst<OtherKey>(key);
|
||||
}
|
||||
template <typename OtherKey>
|
||||
const_iterator find(const OtherKey &key) const {
|
||||
return this->template findFirst<OtherKey>(key);
|
||||
}
|
||||
|
||||
Type &operator[](const Key &key) {
|
||||
if (this->empty() || this->compare()(key, this->front().first)) {
|
||||
|
||||
@@ -69,10 +69,10 @@ TEST_CASE("simple flat_maps tests", "[flat_map]") {
|
||||
|
||||
TEST_CASE("flat_maps custom comparator", "[flat_map]") {
|
||||
base::flat_map<int_wrap, string, int_wrap_comparator> v;
|
||||
v.emplace({ 0 }, "a");
|
||||
v.emplace({ 5 }, "b");
|
||||
v.emplace({ 4 }, "d");
|
||||
v.emplace({ 2 }, "e");
|
||||
v.emplace(int_wrap{ 0 }, "a");
|
||||
v.emplace(int_wrap{ 5 }, "b");
|
||||
v.emplace(int_wrap{ 4 }, "d");
|
||||
v.emplace(int_wrap{ 2 }, "e");
|
||||
|
||||
auto checkSorted = [&] {
|
||||
auto prev = v.begin();
|
||||
@@ -85,7 +85,7 @@ TEST_CASE("flat_maps custom comparator", "[flat_map]") {
|
||||
checkSorted();
|
||||
|
||||
SECTION("adding item puts it in the right position") {
|
||||
v.emplace({ 3 }, "c");
|
||||
v.emplace(int_wrap{ 3 }, "c");
|
||||
REQUIRE(v.size() == 5);
|
||||
REQUIRE(v.find({ 3 }) != v.end());
|
||||
checkSorted();
|
||||
|
||||
62
Telegram/SourceFiles/base/invoke_queued.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QEvent>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include "base/basic_types.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class InvokeQueuedEvent : public QEvent {
|
||||
public:
|
||||
static constexpr auto kType = QEvent::Type(60666);
|
||||
|
||||
explicit InvokeQueuedEvent(FnMut<void()> &&method)
|
||||
: QEvent(kType)
|
||||
, _method(std::move(method)) {
|
||||
}
|
||||
|
||||
void invoke() {
|
||||
_method();
|
||||
}
|
||||
|
||||
private:
|
||||
FnMut<void()> _method;
|
||||
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
template <typename Lambda>
|
||||
inline void InvokeQueued(const QObject *context, Lambda &&lambda) {
|
||||
QCoreApplication::postEvent(
|
||||
const_cast<QObject*>(context),
|
||||
new base::InvokeQueuedEvent(std::forward<Lambda>(lambda)));
|
||||
}
|
||||
|
||||
class SingleQueuedInvokation : public QObject {
|
||||
public:
|
||||
SingleQueuedInvokation(Fn<void()> callback) : _callback(callback) {
|
||||
}
|
||||
void call() {
|
||||
if (_pending.testAndSetAcquire(0, 1)) {
|
||||
InvokeQueued(this, [this] {
|
||||
if (_pending.testAndSetRelease(1, 0)) {
|
||||
_callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Fn<void()> _callback;
|
||||
QAtomicInt _pending = { 0 };
|
||||
|
||||
};
|
||||
121
Telegram/SourceFiles/base/object_ptr.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
// Smart pointer for QObject*, has move semantics, destroys object if it doesn't have a parent.
|
||||
template <typename Object>
|
||||
class object_ptr {
|
||||
public:
|
||||
object_ptr(std::nullptr_t) noexcept {
|
||||
}
|
||||
|
||||
// No default constructor, but constructors with at least
|
||||
// one argument are simply make functions.
|
||||
template <typename Parent, typename... Args>
|
||||
explicit object_ptr(Parent &&parent, Args&&... args)
|
||||
: _object(new Object(std::forward<Parent>(parent), std::forward<Args>(args)...)) {
|
||||
}
|
||||
static object_ptr<Object> fromRaw(Object *value) noexcept {
|
||||
object_ptr<Object> result = { nullptr };
|
||||
result._object = value;
|
||||
return result;
|
||||
}
|
||||
Object *release() noexcept {
|
||||
return static_cast<Object*>(base::take(_object).data());
|
||||
}
|
||||
|
||||
object_ptr(const object_ptr &other) = delete;
|
||||
object_ptr &operator=(const object_ptr &other) = delete;
|
||||
object_ptr(object_ptr &&other) noexcept : _object(base::take(other._object)) {
|
||||
}
|
||||
object_ptr &operator=(object_ptr &&other) noexcept {
|
||||
auto temp = std::move(other);
|
||||
destroy();
|
||||
std::swap(_object, temp._object);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <
|
||||
typename OtherObject,
|
||||
typename = std::enable_if_t<
|
||||
std::is_base_of_v<Object, OtherObject>>>
|
||||
object_ptr(object_ptr<OtherObject> &&other) noexcept
|
||||
: _object(base::take(other._object)) {
|
||||
}
|
||||
|
||||
template <
|
||||
typename OtherObject,
|
||||
typename = std::enable_if_t<
|
||||
std::is_base_of_v<Object, OtherObject>>>
|
||||
object_ptr &operator=(object_ptr<OtherObject> &&other) noexcept {
|
||||
_object = base::take(other._object);
|
||||
return *this;
|
||||
}
|
||||
|
||||
object_ptr &operator=(std::nullptr_t) noexcept {
|
||||
_object = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// So we can pass this pointer to methods like connect().
|
||||
Object *data() const noexcept {
|
||||
return static_cast<Object*>(_object.data());
|
||||
}
|
||||
operator Object*() const noexcept {
|
||||
return data();
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return _object != nullptr;
|
||||
}
|
||||
|
||||
Object *operator->() const noexcept {
|
||||
return data();
|
||||
}
|
||||
Object &operator*() const noexcept {
|
||||
return *data();
|
||||
}
|
||||
|
||||
// Use that instead "= new Object(parent, ...)"
|
||||
template <typename Parent, typename... Args>
|
||||
Object *create(Parent &&parent, Args&&... args) {
|
||||
destroy();
|
||||
_object = new Object(
|
||||
std::forward<Parent>(parent),
|
||||
std::forward<Args>(args)...);
|
||||
return data();
|
||||
}
|
||||
void destroy() noexcept {
|
||||
delete base::take(_object);
|
||||
}
|
||||
void destroyDelayed() {
|
||||
if (_object) {
|
||||
if (auto widget = base::up_cast<QWidget*>(data())) {
|
||||
widget->hide();
|
||||
}
|
||||
base::take(_object)->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
~object_ptr() noexcept {
|
||||
if (auto pointer = _object) {
|
||||
if (!pointer->parent()) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename OtherObject>
|
||||
friend class object_ptr;
|
||||
|
||||
QPointer<QObject> _object;
|
||||
|
||||
};
|
||||
@@ -19,6 +19,7 @@ extern "C" {
|
||||
#include <openssl/modes.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
} // extern "C"
|
||||
|
||||
#ifdef small
|
||||
@@ -56,19 +57,38 @@ private:
|
||||
|
||||
class BigNum {
|
||||
public:
|
||||
BigNum() : _data(BN_new()) {
|
||||
BigNum() = default;
|
||||
BigNum(const BigNum &other)
|
||||
: _data((other.failed() || other.isZero())
|
||||
? nullptr
|
||||
: BN_dup(other.raw()))
|
||||
, _failed(other._failed) {
|
||||
}
|
||||
BigNum(const BigNum &other) : BigNum() {
|
||||
*this = other;
|
||||
BigNum(BigNum &&other)
|
||||
: _data(std::exchange(other._data, nullptr))
|
||||
, _failed(std::exchange(other._failed, false)) {
|
||||
}
|
||||
BigNum &operator=(const BigNum &other) {
|
||||
if (other.failed() || !BN_copy(raw(), other.raw())) {
|
||||
if (other.failed()) {
|
||||
_failed = true;
|
||||
} else if (other.isZero()) {
|
||||
clear();
|
||||
_failed = false;
|
||||
} else if (!_data) {
|
||||
_data = BN_dup(other.raw());
|
||||
_failed = false;
|
||||
} else {
|
||||
_failed = !BN_copy(raw(), other.raw());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BigNum &operator=(BigNum &&other) {
|
||||
std::swap(_data, other._data);
|
||||
std::swap(_failed, other._failed);
|
||||
return *this;
|
||||
}
|
||||
~BigNum() {
|
||||
BN_clear_free(raw());
|
||||
clear();
|
||||
}
|
||||
|
||||
explicit BigNum(unsigned int word) : BigNum() {
|
||||
@@ -78,64 +98,74 @@ public:
|
||||
setBytes(bytes);
|
||||
}
|
||||
|
||||
void setWord(unsigned int word) {
|
||||
if (!BN_set_word(raw(), word)) {
|
||||
_failed = true;
|
||||
BigNum &setWord(unsigned int word) {
|
||||
if (!word) {
|
||||
clear();
|
||||
_failed = false;
|
||||
} else {
|
||||
_failed = !BN_set_word(raw(), word);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void setBytes(bytes::const_span bytes) {
|
||||
if (!BN_bin2bn(
|
||||
BigNum &setBytes(bytes::const_span bytes) {
|
||||
if (bytes.empty()) {
|
||||
clear();
|
||||
_failed = false;
|
||||
} else {
|
||||
_failed = !BN_bin2bn(
|
||||
reinterpret_cast<const unsigned char*>(bytes.data()),
|
||||
bytes.size(),
|
||||
raw())) {
|
||||
_failed = true;
|
||||
raw());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void setAdd(const BigNum &a, const BigNum &b) {
|
||||
BigNum &setAdd(const BigNum &a, const BigNum &b) {
|
||||
if (a.failed() || b.failed()) {
|
||||
_failed = true;
|
||||
} else if (!BN_add(raw(), a.raw(), b.raw())) {
|
||||
_failed = true;
|
||||
} else {
|
||||
_failed = !BN_add(raw(), a.raw(), b.raw());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void setSub(const BigNum &a, const BigNum &b) {
|
||||
BigNum &setSub(const BigNum &a, const BigNum &b) {
|
||||
if (a.failed() || b.failed()) {
|
||||
_failed = true;
|
||||
} else if (!BN_sub(raw(), a.raw(), b.raw())) {
|
||||
_failed = true;
|
||||
} else {
|
||||
_failed = !BN_sub(raw(), a.raw(), b.raw());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void setSubWord(unsigned int word) {
|
||||
if (failed()) {
|
||||
return;
|
||||
} else if (!BN_sub_word(raw(), word)) {
|
||||
_failed = true;
|
||||
}
|
||||
}
|
||||
void setMul(
|
||||
BigNum &setMul(
|
||||
const BigNum &a,
|
||||
const BigNum &b,
|
||||
const Context &context = Context()) {
|
||||
if (a.failed() || b.failed()) {
|
||||
_failed = true;
|
||||
} else if (!BN_mul(raw(), a.raw(), b.raw(), context.raw())) {
|
||||
_failed = true;
|
||||
} else {
|
||||
_failed = !BN_mul(raw(), a.raw(), b.raw(), context.raw());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BN_ULONG setDivWord(BN_ULONG word) {
|
||||
Expects(word != 0);
|
||||
if (failed()) {
|
||||
return (BN_ULONG)-1;
|
||||
}
|
||||
|
||||
auto result = BN_div_word(raw(), word);
|
||||
if (result == (BN_ULONG)-1) {
|
||||
BigNum &setModAdd(
|
||||
const BigNum &a,
|
||||
const BigNum &b,
|
||||
const BigNum &m,
|
||||
const Context &context = Context()) {
|
||||
if (a.failed() || b.failed() || m.failed()) {
|
||||
_failed = true;
|
||||
} else if (a.isNegative() || b.isNegative() || m.isNegative()) {
|
||||
_failed = true;
|
||||
} else if (!BN_mod_add(raw(), a.raw(), b.raw(), m.raw(), context.raw())) {
|
||||
_failed = true;
|
||||
} else if (isNegative()) {
|
||||
_failed = true;
|
||||
} else {
|
||||
_failed = false;
|
||||
}
|
||||
return result;
|
||||
return *this;
|
||||
}
|
||||
void setModSub(
|
||||
BigNum &setModSub(
|
||||
const BigNum &a,
|
||||
const BigNum &b,
|
||||
const BigNum &m,
|
||||
@@ -148,9 +178,12 @@ public:
|
||||
_failed = true;
|
||||
} else if (isNegative()) {
|
||||
_failed = true;
|
||||
} else {
|
||||
_failed = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void setModMul(
|
||||
BigNum &setModMul(
|
||||
const BigNum &a,
|
||||
const BigNum &b,
|
||||
const BigNum &m,
|
||||
@@ -163,9 +196,29 @@ public:
|
||||
_failed = true;
|
||||
} else if (isNegative()) {
|
||||
_failed = true;
|
||||
} else {
|
||||
_failed = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void setModExp(
|
||||
BigNum &setModInverse(
|
||||
const BigNum &a,
|
||||
const BigNum &m,
|
||||
const Context &context = Context()) {
|
||||
if (a.failed() || m.failed()) {
|
||||
_failed = true;
|
||||
} else if (a.isNegative() || m.isNegative()) {
|
||||
_failed = true;
|
||||
} else if (!BN_mod_inverse(raw(), a.raw(), m.raw(), context.raw())) {
|
||||
_failed = true;
|
||||
} else if (isNegative()) {
|
||||
_failed = true;
|
||||
} else {
|
||||
_failed = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BigNum &setModExp(
|
||||
const BigNum &base,
|
||||
const BigNum &power,
|
||||
const BigNum &m,
|
||||
@@ -178,23 +231,34 @@ public:
|
||||
_failed = true;
|
||||
} else if (isNegative()) {
|
||||
_failed = true;
|
||||
} else {
|
||||
_failed = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isNegative() const {
|
||||
return failed() ? false : BN_is_negative(raw());
|
||||
[[nodiscard]] bool isZero() const {
|
||||
return !failed() && (!_data || BN_is_zero(raw()));
|
||||
}
|
||||
|
||||
bool isPrime(const Context &context = Context()) const {
|
||||
if (failed()) {
|
||||
[[nodiscard]] bool isOne() const {
|
||||
return !failed() && _data && BN_is_one(raw());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isNegative() const {
|
||||
return !failed() && _data && BN_is_negative(raw());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isPrime(const Context &context = Context()) const {
|
||||
if (failed() || !_data) {
|
||||
return false;
|
||||
}
|
||||
constexpr auto kMillerRabinIterationCount = 30;
|
||||
auto result = BN_is_prime_ex(
|
||||
const auto result = BN_is_prime_ex(
|
||||
raw(),
|
||||
kMillerRabinIterationCount,
|
||||
context.raw(),
|
||||
NULL);
|
||||
nullptr);
|
||||
if (result == 1) {
|
||||
return true;
|
||||
} else if (result != 0) {
|
||||
@@ -203,27 +267,42 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
BN_ULONG modWord(BN_ULONG word) const {
|
||||
Expects(word != 0);
|
||||
BigNum &subWord(unsigned int word) {
|
||||
if (failed()) {
|
||||
return (BN_ULONG)-1;
|
||||
return *this;
|
||||
} else if (!BN_sub_word(raw(), word)) {
|
||||
_failed = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BigNum &divWord(BN_ULONG word, BN_ULONG *mod = nullptr) {
|
||||
Expects(word != 0);
|
||||
|
||||
auto result = BN_mod_word(raw(), word);
|
||||
const auto result = failed()
|
||||
? (BN_ULONG)-1
|
||||
: BN_div_word(raw(), word);
|
||||
if (result == (BN_ULONG)-1) {
|
||||
_failed = true;
|
||||
}
|
||||
return result;
|
||||
if (mod) {
|
||||
*mod = result;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
[[nodiscard]] BN_ULONG countModWord(BN_ULONG word) const {
|
||||
Expects(word != 0);
|
||||
|
||||
return failed() ? (BN_ULONG)-1 : BN_mod_word(raw(), word);
|
||||
}
|
||||
|
||||
int bitsSize() const {
|
||||
[[nodiscard]] int bitsSize() const {
|
||||
return failed() ? 0 : BN_num_bits(raw());
|
||||
}
|
||||
int bytesSize() const {
|
||||
[[nodiscard]] int bytesSize() const {
|
||||
return failed() ? 0 : BN_num_bytes(raw());
|
||||
}
|
||||
|
||||
bytes::vector getBytes() const {
|
||||
[[nodiscard]] bytes::vector getBytes() const {
|
||||
if (failed()) {
|
||||
return {};
|
||||
}
|
||||
@@ -236,73 +315,84 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
BIGNUM *raw() {
|
||||
[[nodiscard]] BIGNUM *raw() {
|
||||
if (!_data) _data = BN_new();
|
||||
return _data;
|
||||
}
|
||||
const BIGNUM *raw() const {
|
||||
[[nodiscard]] const BIGNUM *raw() const {
|
||||
if (!_data) _data = BN_new();
|
||||
return _data;
|
||||
}
|
||||
BIGNUM *takeRaw() {
|
||||
return base::take(_data);
|
||||
[[nodiscard]] BIGNUM *takeRaw() {
|
||||
return _failed
|
||||
? nullptr
|
||||
: _data
|
||||
? std::exchange(_data, nullptr)
|
||||
: BN_new();
|
||||
}
|
||||
|
||||
bool failed() const {
|
||||
[[nodiscard]] bool failed() const {
|
||||
return _failed;
|
||||
}
|
||||
|
||||
static BigNum Add(const BigNum &a, const BigNum &b) {
|
||||
BigNum result;
|
||||
result.setAdd(a, b);
|
||||
return result;
|
||||
[[nodiscard]] static BigNum Add(const BigNum &a, const BigNum &b) {
|
||||
return BigNum().setAdd(a, b);
|
||||
}
|
||||
static BigNum Sub(const BigNum &a, const BigNum &b) {
|
||||
BigNum result;
|
||||
result.setSub(a, b);
|
||||
return result;
|
||||
[[nodiscard]] static BigNum Sub(const BigNum &a, const BigNum &b) {
|
||||
return BigNum().setSub(a, b);
|
||||
}
|
||||
static BigNum Mul(
|
||||
[[nodiscard]] static BigNum Mul(
|
||||
const BigNum &a,
|
||||
const BigNum &b,
|
||||
const Context &context = Context()) {
|
||||
BigNum result;
|
||||
result.setMul(a, b, context);
|
||||
return result;
|
||||
return BigNum().setMul(a, b, context);
|
||||
}
|
||||
static BigNum ModSub(
|
||||
[[nodiscard]] static BigNum ModAdd(
|
||||
const BigNum &a,
|
||||
const BigNum &b,
|
||||
const BigNum &mod,
|
||||
const Context &context = Context()) {
|
||||
BigNum result;
|
||||
result.setModSub(a, b, mod, context);
|
||||
return result;
|
||||
return BigNum().setModAdd(a, b, mod, context);
|
||||
}
|
||||
static BigNum ModMul(
|
||||
[[nodiscard]] static BigNum ModSub(
|
||||
const BigNum &a,
|
||||
const BigNum &b,
|
||||
const BigNum &mod,
|
||||
const Context &context = Context()) {
|
||||
BigNum result;
|
||||
result.setModMul(a, b, mod, context);
|
||||
return result;
|
||||
return BigNum().setModSub(a, b, mod, context);
|
||||
}
|
||||
static BigNum ModExp(
|
||||
[[nodiscard]] static BigNum ModMul(
|
||||
const BigNum &a,
|
||||
const BigNum &b,
|
||||
const BigNum &mod,
|
||||
const Context &context = Context()) {
|
||||
return BigNum().setModMul(a, b, mod, context);
|
||||
}
|
||||
[[nodiscard]] static BigNum ModInverse(
|
||||
const BigNum &a,
|
||||
const BigNum &mod,
|
||||
const Context &context = Context()) {
|
||||
return BigNum().setModInverse(a, mod, context);
|
||||
}
|
||||
[[nodiscard]] static BigNum ModExp(
|
||||
const BigNum &base,
|
||||
const BigNum &power,
|
||||
const BigNum &mod,
|
||||
const Context &context = Context()) {
|
||||
BigNum result;
|
||||
result.setModExp(base, power, mod, context);
|
||||
return result;
|
||||
return BigNum().setModExp(base, power, mod, context);
|
||||
}
|
||||
static BigNum Failed() {
|
||||
BigNum result;
|
||||
[[nodiscard]] static BigNum Failed() {
|
||||
auto result = BigNum();
|
||||
result._failed = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
BIGNUM *_data = nullptr;
|
||||
void clear() {
|
||||
BN_clear_free(std::exchange(_data, nullptr));
|
||||
}
|
||||
|
||||
mutable BIGNUM *_data = nullptr;
|
||||
mutable bool _failed = false;
|
||||
|
||||
};
|
||||
@@ -434,6 +524,17 @@ inline void AddRandomSeed(bytes::const_span data) {
|
||||
RAND_seed(data.data(), data.size());
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
[[nodiscard]] inline T RandomValue() {
|
||||
unsigned char buffer[sizeof(T)];
|
||||
if (!RAND_bytes(buffer, sizeof(T))) {
|
||||
Unexpected("Could not generate random bytes!");
|
||||
}
|
||||
auto result = T();
|
||||
memcpy(&result, buffer, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bytes::vector Pbkdf2Sha512(
|
||||
bytes::const_span password,
|
||||
bytes::const_span salt,
|
||||
@@ -445,6 +546,24 @@ inline bytes::vector Pbkdf2Sha512(
|
||||
EVP_sha512());
|
||||
}
|
||||
|
||||
inline bytes::vector HmacSha256(
|
||||
bytes::const_span key,
|
||||
bytes::const_span data) {
|
||||
auto result = bytes::vector(kSha256Size);
|
||||
auto length = (unsigned int)kSha256Size;
|
||||
|
||||
HMAC(
|
||||
EVP_sha256(),
|
||||
key.data(),
|
||||
key.size(),
|
||||
reinterpret_cast<const unsigned char*>(data.data()),
|
||||
data.size(),
|
||||
reinterpret_cast<unsigned char*>(result.data()),
|
||||
&length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace openssl
|
||||
|
||||
namespace bytes {
|
||||
|
||||
49
Telegram/SourceFiles/base/qt_connection.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/algorithm.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
namespace base {
|
||||
|
||||
class qt_connection final {
|
||||
public:
|
||||
qt_connection(QMetaObject::Connection data = {}) : _data(data) {
|
||||
}
|
||||
qt_connection(qt_connection &&other) : _data(base::take(other._data)) {
|
||||
}
|
||||
qt_connection &operator=(qt_connection &&other) {
|
||||
reset(base::take(other._data));
|
||||
return *this;
|
||||
}
|
||||
~qt_connection() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
void release() {
|
||||
_data = QMetaObject::Connection();
|
||||
}
|
||||
void reset(QMetaObject::Connection data = {}) {
|
||||
disconnect();
|
||||
_data = data;
|
||||
}
|
||||
|
||||
private:
|
||||
void disconnect() {
|
||||
if (_data) {
|
||||
QObject::disconnect(base::take(_data));
|
||||
}
|
||||
}
|
||||
|
||||
QMetaObject::Connection _data;
|
||||
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
@@ -7,9 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/sandbox.h"
|
||||
#include "base/base_integration.h"
|
||||
|
||||
namespace Core {
|
||||
namespace base {
|
||||
|
||||
// This method allows to create an rpl::producer from a Qt object
|
||||
// and a signal with none or one reported value.
|
||||
@@ -20,34 +20,34 @@ namespace Core {
|
||||
// This means that all postponeCall's will be invoked right after
|
||||
// the value processing by the current consumer finishes.
|
||||
template <typename Object, typename Signal>
|
||||
auto QtSignalProducer(Object *object, Signal signal);
|
||||
auto qt_signal_producer(Object *object, Signal signal);
|
||||
|
||||
namespace details {
|
||||
|
||||
template <typename Signal>
|
||||
struct QtSignalArgument;
|
||||
struct qt_signal_argument;
|
||||
|
||||
template <typename Class, typename Return, typename Value>
|
||||
struct QtSignalArgument<Return(Class::*)(Value)> {
|
||||
struct qt_signal_argument<Return(Class::*)(Value)> {
|
||||
using type = Value;
|
||||
};
|
||||
|
||||
template <typename Class, typename Return>
|
||||
struct QtSignalArgument<Return(Class::*)()> {
|
||||
struct qt_signal_argument<Return(Class::*)()> {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename Object, typename Signal>
|
||||
auto QtSignalProducer(Object *object, Signal signal) {
|
||||
using Value = typename details::QtSignalArgument<Signal>::type;
|
||||
auto qt_signal_producer(Object *object, Signal signal) {
|
||||
using Value = typename details::qt_signal_argument<Signal>::type;
|
||||
static constexpr auto NoArgument = std::is_same_v<Value, void>;
|
||||
using Produced = std::conditional_t<
|
||||
NoArgument,
|
||||
rpl::empty_value,
|
||||
std::remove_const_t<std::decay_t<Value>>>;
|
||||
const auto guarded = make_weak(object);
|
||||
const auto guarded = QPointer<Object>(object);
|
||||
return rpl::make_producer<Produced>([=](auto consumer) {
|
||||
if (!guarded) {
|
||||
return rpl::lifetime();
|
||||
@@ -59,7 +59,7 @@ auto QtSignalProducer(Object *object, Signal signal) {
|
||||
signal,
|
||||
listener,
|
||||
std::forward<decltype(handler)>(handler));
|
||||
const auto weak = make_weak(listener);
|
||||
const auto weak = QPointer<QObject>(listener);
|
||||
return rpl::lifetime([=] {
|
||||
if (weak) {
|
||||
delete weak;
|
||||
@@ -67,7 +67,7 @@ auto QtSignalProducer(Object *object, Signal signal) {
|
||||
});
|
||||
};
|
||||
auto put = [=](const Produced &value) {
|
||||
Sandbox::Instance().customEnterFromEventLoop([&] {
|
||||
EnterFromEventLoop([&] {
|
||||
consumer.put_next_copy(value);
|
||||
});
|
||||
};
|
||||
@@ -79,4 +79,4 @@ auto QtSignalProducer(Object *object, Signal signal) {
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
} // namespace base
|
||||
@@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QRegularExpression>
|
||||
|
||||
namespace qthelp {
|
||||
|
||||
const QRegularExpression &RegExpDomain();
|
||||
|
||||
60
Telegram/SourceFiles/base/thread_safe_wrap.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename T>
|
||||
class thread_safe_wrap {
|
||||
public:
|
||||
template <typename ...Args>
|
||||
thread_safe_wrap(Args &&...args) : _value(std::forward<Args>(args)...) {
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
auto with(Callback &&callback) {
|
||||
QMutexLocker lock(&_mutex);
|
||||
return callback(_value);
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
auto with(Callback &&callback) const {
|
||||
QMutexLocker lock(&_mutex);
|
||||
return callback(_value);
|
||||
}
|
||||
|
||||
private:
|
||||
T _value;
|
||||
QMutex _mutex;
|
||||
|
||||
};
|
||||
|
||||
template <typename T, template<typename...> typename Container = std::deque>
|
||||
class thread_safe_queue {
|
||||
public:
|
||||
template <typename ...Args>
|
||||
void emplace(Args &&...args) {
|
||||
_wrap.with([&](Container<T> &value) {
|
||||
value.emplace_back(std::forward<Args>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
Container<T> take() {
|
||||
return _wrap.with([&](Container<T> &value) {
|
||||
return std::exchange(value, Container<T>());
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
thread_safe_wrap<Container<T>> _wrap;
|
||||
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
@@ -108,8 +108,8 @@ void Timer::timerEvent(QTimerEvent *e) {
|
||||
cancel();
|
||||
}
|
||||
|
||||
if (_callback) {
|
||||
_callback();
|
||||
if (const auto onstack = _callback) {
|
||||
onstack();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename T>
|
||||
|
||||
174
Telegram/SourceFiles/base/unixtime.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
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 "base/unixtime.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#elif defined Q_OS_MAC
|
||||
#include <mach/mach_time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace unixtime {
|
||||
namespace {
|
||||
|
||||
std::atomic<bool> ValueUpdated/* = false*/;
|
||||
std::atomic<TimeId> ValueShift/* = 0*/;
|
||||
std::atomic<bool> HttpValueValid/* = false*/;
|
||||
std::atomic<TimeId> HttpValueShift/* = 0*/;
|
||||
|
||||
class MsgIdManager {
|
||||
public:
|
||||
MsgIdManager();
|
||||
|
||||
void update();
|
||||
[[nodiscard]] uint64 next();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
QReadWriteLock _lock;
|
||||
uint64 _startId = 0;
|
||||
std::atomic<uint32> _incrementedPart = 0;
|
||||
uint64 _startCounter = 0;
|
||||
uint64 _randomPart = 0;
|
||||
float64 _multiplier = 0.;
|
||||
|
||||
};
|
||||
|
||||
MsgIdManager GlobalMsgIdManager;
|
||||
|
||||
[[nodiscard]] float64 GetMultiplier() {
|
||||
// 0xFFFF0000 instead of 0x100000000 to make msgId grow slightly slower,
|
||||
// than unixtime and we had time to reconfigure.
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceFrequency(&li);
|
||||
return float64(0xFFFF0000L) / float64(li.QuadPart);
|
||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
||||
mach_timebase_info_data_t tb = { 0, 0 };
|
||||
mach_timebase_info(&tb);
|
||||
const auto frequency = (float64(tb.numer) / tb.denom) / 1000000.;
|
||||
return frequency * (float64(0xFFFF0000L) / 1000.);
|
||||
#else // Q_OS_MAC || Q_OS_WIN
|
||||
return float64(0xFFFF0000L) / 1000000000.;
|
||||
#endif // Q_OS_MAC || Q_OS_WIN
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64 GetCounter() {
|
||||
#ifdef Q_OS_WIN
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceCounter(&li);
|
||||
return li.QuadPart;
|
||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
||||
return mach_absolute_time();
|
||||
#else // Q_OS_MAC || Q_OS_WIN
|
||||
timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return 1000000000 * uint64(ts.tv_sec) + uint64(ts.tv_nsec);
|
||||
#endif // Q_OS_MAC || Q_OS_WIN
|
||||
}
|
||||
|
||||
MsgIdManager::MsgIdManager() {
|
||||
auto generator = std::mt19937(std::random_device()());
|
||||
auto distribution = std::uniform_int_distribution<uint32>();
|
||||
_randomPart = distribution(generator);
|
||||
_multiplier = GetMultiplier();
|
||||
initialize();
|
||||
|
||||
srand(uint32(_startCounter & 0xFFFFFFFFUL));
|
||||
}
|
||||
|
||||
void MsgIdManager::update() {
|
||||
QWriteLocker lock(&_lock);
|
||||
initialize();
|
||||
}
|
||||
|
||||
void MsgIdManager::initialize() {
|
||||
_startCounter = GetCounter();
|
||||
_startId = ((uint64(uint32(now()))) << 32) | _randomPart;
|
||||
}
|
||||
|
||||
uint64 MsgIdManager::next() {
|
||||
const auto counter = GetCounter();
|
||||
|
||||
QReadLocker lock(&_lock);
|
||||
const auto delta = (counter - _startCounter);
|
||||
const auto result = _startId + (uint64)floor(delta * _multiplier);
|
||||
lock.unlock();
|
||||
|
||||
return (result & ~0x03L) + (_incrementedPart += 4);
|
||||
}
|
||||
|
||||
TimeId local() {
|
||||
return (TimeId)time(nullptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TimeId now() {
|
||||
return local() + ValueShift.load();
|
||||
}
|
||||
|
||||
void update(TimeId now, bool force) {
|
||||
if (force) {
|
||||
ValueUpdated = true;
|
||||
} else {
|
||||
auto expected = false;
|
||||
if (!ValueUpdated.compare_exchange_strong(expected, true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto shift = now + 1 - local();
|
||||
ValueShift = shift;
|
||||
|
||||
HttpValueShift = 0;
|
||||
HttpValueValid = false;
|
||||
|
||||
GlobalMsgIdManager.update();
|
||||
}
|
||||
|
||||
QDateTime parse(TimeId value) {
|
||||
return (value > 0)
|
||||
? QDateTime::fromTime_t(value - ValueShift)
|
||||
: QDateTime();
|
||||
}
|
||||
|
||||
TimeId serialize(const QDateTime &date) {
|
||||
return date.isNull() ? TimeId(0) : date.toTime_t() + ValueShift;
|
||||
}
|
||||
|
||||
bool http_valid() {
|
||||
return HttpValueValid;
|
||||
}
|
||||
|
||||
TimeId http_now() {
|
||||
return now() + HttpValueShift;
|
||||
}
|
||||
|
||||
void http_update(TimeId now) {
|
||||
HttpValueShift = now - base::unixtime::now();
|
||||
HttpValueValid = true;
|
||||
}
|
||||
|
||||
void http_invalidate() {
|
||||
HttpValueValid = false;
|
||||
}
|
||||
|
||||
uint64 mtproto_msg_id() {
|
||||
return GlobalMsgIdManager.next();
|
||||
}
|
||||
|
||||
} // namespace unixtime
|
||||
} // namespace base
|
||||
33
Telegram/SourceFiles/base/unixtime.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/basic_types.h"
|
||||
|
||||
class QDateTime;
|
||||
|
||||
namespace base {
|
||||
namespace unixtime {
|
||||
|
||||
// All functions are thread-safe.
|
||||
|
||||
[[nodiscard]] TimeId now();
|
||||
void update(TimeId now, bool force = false);
|
||||
|
||||
[[nodiscard]] QDateTime parse(TimeId value);
|
||||
[[nodiscard]] TimeId serialize(const QDateTime &date);
|
||||
|
||||
[[nodiscard]] bool http_valid();
|
||||
[[nodiscard]] TimeId http_now();
|
||||
void http_update(TimeId now);
|
||||
void http_invalidate();
|
||||
|
||||
[[nodiscard]] uint64 mtproto_msg_id();
|
||||
|
||||
} // namespace unixtime
|
||||
} // namespace base
|
||||
@@ -13,35 +13,64 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "platform/platform_info.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtGui/QDesktopServices>
|
||||
|
||||
namespace {
|
||||
|
||||
rpl::producer<TextWithEntities> Text1() {
|
||||
return tr::lng_about_text1(
|
||||
lt_api_link,
|
||||
tr::lng_about_text1_api(
|
||||
) | Ui::Text::ToLink("https://core.telegram.org/api"),
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
|
||||
rpl::producer<TextWithEntities> Text2() {
|
||||
return tr::lng_about_text2(
|
||||
lt_gpl_link,
|
||||
rpl::single(Ui::Text::Link(
|
||||
"GNU GPL",
|
||||
"https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE")),
|
||||
lt_github_link,
|
||||
rpl::single(Ui::Text::Link(
|
||||
"GitHub",
|
||||
"https://github.com/telegramdesktop/tdesktop")),
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
|
||||
rpl::producer<TextWithEntities> Text3() {
|
||||
return tr::lng_about_text3(
|
||||
lt_faq_link,
|
||||
tr::lng_about_text3_faq() | Ui::Text::ToLink(telegramFaqLink()),
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AboutBox::AboutBox(QWidget *parent)
|
||||
: _version(this, lng_about_version(lt_version, currentVersionText()), st::aboutVersionLink)
|
||||
, _text1(this, lang(lng_about_text_1), Ui::FlatLabel::InitType::Rich, st::aboutLabel)
|
||||
, _text2(this, lang(lng_about_text_2), Ui::FlatLabel::InitType::Rich, st::aboutLabel)
|
||||
, _text3(this, st::aboutLabel) {
|
||||
: _version(this, tr::lng_about_version(tr::now, lt_version, currentVersionText()), st::aboutVersionLink)
|
||||
, _text1(this, Text1(), st::aboutLabel)
|
||||
, _text2(this, Text2(), st::aboutLabel)
|
||||
, _text3(this, Text3(), st::aboutLabel) {
|
||||
}
|
||||
|
||||
void AboutBox::prepare() {
|
||||
setTitle([] { return qsl("Telegram Desktop"); });
|
||||
setTitle(rpl::single(qsl("Telegram Desktop")));
|
||||
|
||||
addButton(langFactory(lng_close), [this] { closeBox(); });
|
||||
addButton(tr::lng_close(), [this] { closeBox(); });
|
||||
|
||||
const auto linkFilter = [](const ClickHandlerPtr &link, auto button) {
|
||||
if (const auto url = dynamic_cast<UrlClickHandler*>(link.get())) {
|
||||
url->UrlClickHandler::onClick({ button });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
_text3->setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]")));
|
||||
_text1->setClickHandlerFilter(linkFilter);
|
||||
_text2->setClickHandlerFilter(linkFilter);
|
||||
_text3->setClickHandlerFilter(linkFilter);
|
||||
_text1->setLinksTrusted();
|
||||
_text2->setLinksTrusted();
|
||||
_text3->setLinksTrusted();
|
||||
|
||||
_version->setClickedCallback([this] { showVersionHistory(); });
|
||||
|
||||
@@ -60,16 +89,22 @@ void AboutBox::resizeEvent(QResizeEvent *e) {
|
||||
void AboutBox::showVersionHistory() {
|
||||
if (cRealAlphaVersion()) {
|
||||
auto url = qsl("https://tdesktop.com/");
|
||||
switch (cPlatform()) {
|
||||
case dbipWindows: url += qsl("win/%1.zip"); break;
|
||||
case dbipMac: url += qsl("mac/%1.zip"); break;
|
||||
case dbipMacOld: url += qsl("mac32/%1.zip"); break;
|
||||
case dbipLinux32: url += qsl("linux32/%1.tar.xz"); break;
|
||||
case dbipLinux64: url += qsl("linux/%1.tar.xz"); break;
|
||||
if (Platform::IsWindows()) {
|
||||
url += qsl("win/%1.zip");
|
||||
} else if (Platform::IsMacOldBuild()) {
|
||||
url += qsl("mac32/%1.zip");
|
||||
} else if (Platform::IsMac()) {
|
||||
url += qsl("mac/%1.zip");
|
||||
} else if (Platform::IsLinux32Bit()) {
|
||||
url += qsl("linux32/%1.tar.xz");
|
||||
} else if (Platform::IsLinux64Bit()) {
|
||||
url += qsl("linux/%1.tar.xz");
|
||||
} else {
|
||||
Unexpected("Platform value.");
|
||||
}
|
||||
url = url.arg(qsl("talpha%1_%2").arg(cRealAlphaVersion()).arg(Core::countAlphaVersionSignature(cRealAlphaVersion())));
|
||||
|
||||
QApplication::clipboard()->setText(url);
|
||||
QGuiApplication::clipboard()->setText(url);
|
||||
|
||||
Ui::show(Box<InformBox>("The link to the current private alpha version of Telegram Desktop was copied to the clipboard."));
|
||||
} else {
|
||||
|
||||
@@ -11,28 +11,52 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_profile.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/painter.h"
|
||||
#include "base/timer.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "app.h"
|
||||
|
||||
struct AbstractBox::LoadingProgress {
|
||||
LoadingProgress(
|
||||
Fn<void()> &&callback,
|
||||
const style::InfiniteRadialAnimation &st);
|
||||
|
||||
Ui::InfiniteRadialAnimation animation;
|
||||
base::Timer removeTimer;
|
||||
};
|
||||
|
||||
AbstractBox::LoadingProgress::LoadingProgress(
|
||||
Fn<void()> &&callback,
|
||||
const style::InfiniteRadialAnimation &st)
|
||||
: animation(std::move(callback), st) {
|
||||
}
|
||||
|
||||
void BoxContent::setTitle(rpl::producer<QString> title) {
|
||||
getDelegate()->setTitle(std::move(title) | Ui::Text::ToWithEntities());
|
||||
}
|
||||
|
||||
QPointer<Ui::RoundButton> BoxContent::addButton(
|
||||
Fn<QString()> textFactory,
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback) {
|
||||
return addButton(
|
||||
std::move(textFactory),
|
||||
std::move(text),
|
||||
std::move(clickCallback),
|
||||
st::defaultBoxButton);
|
||||
}
|
||||
|
||||
QPointer<Ui::RoundButton> BoxContent::addLeftButton(
|
||||
Fn<QString()> textFactory,
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback) {
|
||||
return getDelegate()->addLeftButton(
|
||||
std::move(textFactory),
|
||||
std::move(text),
|
||||
std::move(clickCallback),
|
||||
st::defaultBoxButton);
|
||||
}
|
||||
@@ -112,7 +136,7 @@ void BoxContent::onDraggingScrollDelta(int delta) {
|
||||
}
|
||||
|
||||
void BoxContent::onDraggingScrollTimer() {
|
||||
auto delta = (_draggingScrollDelta > 0) ? qMin(_draggingScrollDelta * 3 / 20 + 1, int32(MaxScrollSpeed)) : qMax(_draggingScrollDelta * 3 / 20 - 1, -int32(MaxScrollSpeed));
|
||||
auto delta = (_draggingScrollDelta > 0) ? qMin(_draggingScrollDelta * 3 / 20 + 1, int32(Ui::kMaxScrollSpeed)) : qMax(_draggingScrollDelta * 3 / 20 - 1, -int32(Ui::kMaxScrollSpeed));
|
||||
_scroll->scrollToY(_scroll->scrollTop() + delta);
|
||||
}
|
||||
|
||||
@@ -247,15 +271,24 @@ void BoxContent::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
AbstractBox::AbstractBox(not_null<Window::LayerStackWidget*> layer, object_ptr<BoxContent> content)
|
||||
AbstractBox::AbstractBox(
|
||||
not_null<Window::LayerStackWidget*> layer,
|
||||
object_ptr<BoxContent> content)
|
||||
: LayerWidget(layer)
|
||||
, _layer(layer)
|
||||
, _content(std::move(content)) {
|
||||
subscribe(Lang::Current().updated(), [this] { refreshLang(); });
|
||||
_content->setParent(this);
|
||||
_content->setDelegate(this);
|
||||
|
||||
_additionalTitle.changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateSize();
|
||||
update();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
AbstractBox::~AbstractBox() = default;
|
||||
|
||||
void AbstractBox::setLayerType(bool layerType) {
|
||||
_layerType = layerType;
|
||||
updateTitlePosition();
|
||||
@@ -266,15 +299,35 @@ int AbstractBox::titleHeight() const {
|
||||
}
|
||||
|
||||
int AbstractBox::buttonsHeight() const {
|
||||
auto padding = _layerType ? st::boxLayerButtonPadding : st::boxButtonPadding;
|
||||
const auto padding = _layerType
|
||||
? st::boxLayerButtonPadding
|
||||
: st::boxButtonPadding;
|
||||
return padding.top() + st::defaultBoxButton.height + padding.bottom();
|
||||
}
|
||||
|
||||
int AbstractBox::buttonsTop() const {
|
||||
auto padding = _layerType ? st::boxLayerButtonPadding : st::boxButtonPadding;
|
||||
const auto padding = _layerType
|
||||
? st::boxLayerButtonPadding
|
||||
: st::boxButtonPadding;
|
||||
return height() - padding.bottom() - st::defaultBoxButton.height;
|
||||
}
|
||||
|
||||
QRect AbstractBox::loadingRect() const {
|
||||
const auto padding = _layerType
|
||||
? st::boxLayerButtonPadding
|
||||
: st::boxButtonPadding;
|
||||
const auto size = st::boxLoadingSize;
|
||||
const auto skipx = _layerType
|
||||
? st::boxLayerTitlePosition.x()
|
||||
: st::boxTitlePosition.x();
|
||||
const auto skipy = (st::defaultBoxButton.height - size) / 2;
|
||||
return QRect(
|
||||
skipx,
|
||||
height() - padding.bottom() - skipy - size,
|
||||
size,
|
||||
size);
|
||||
}
|
||||
|
||||
void AbstractBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
auto clip = e->rect();
|
||||
@@ -292,15 +345,24 @@ void AbstractBox::paintEvent(QPaintEvent *e) {
|
||||
p.fillRect(rect, st::boxBg);
|
||||
}
|
||||
}
|
||||
if (!_additionalTitle.isEmpty() && clip.intersects(QRect(0, 0, width(), titleHeight()))) {
|
||||
if (!_additionalTitle.current().isEmpty()
|
||||
&& clip.intersects(QRect(0, 0, width(), titleHeight()))) {
|
||||
paintAdditionalTitle(p);
|
||||
}
|
||||
if (_loadingProgress) {
|
||||
const auto rect = loadingRect();
|
||||
_loadingProgress->animation.draw(
|
||||
p,
|
||||
rect.topLeft(),
|
||||
rect.size(),
|
||||
width());
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractBox::paintAdditionalTitle(Painter &p) {
|
||||
p.setFont(st::boxLayerTitleAdditionalFont);
|
||||
p.setPen(st::boxTitleAdditionalFg);
|
||||
p.drawTextLeft(_titleLeft + (_title ? _title->width() : 0) + st::boxLayerTitleAdditionalSkip, _titleTop + st::boxTitleFont->ascent - st::boxLayerTitleAdditionalFont->ascent, width(), _additionalTitle);
|
||||
p.drawTextLeft(_titleLeft + (_title ? _title->width() : 0) + st::boxLayerTitleAdditionalSkip, _titleTop + st::boxTitleFont->ascent - st::boxLayerTitleAdditionalFont->ascent, width(), _additionalTitle.current());
|
||||
}
|
||||
|
||||
void AbstractBox::parentResized() {
|
||||
@@ -310,18 +372,11 @@ void AbstractBox::parentResized() {
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractBox::setTitle(Fn<TextWithEntities()> titleFactory) {
|
||||
_titleFactory = std::move(titleFactory);
|
||||
refreshTitle();
|
||||
}
|
||||
|
||||
void AbstractBox::refreshTitle() {
|
||||
auto wasTitle = hasTitle();
|
||||
if (_titleFactory) {
|
||||
if (!_title) {
|
||||
_title.create(this, st::boxTitle);
|
||||
}
|
||||
_title->setMarkedText(_titleFactory());
|
||||
void AbstractBox::setTitle(rpl::producer<TextWithEntities> title) {
|
||||
const auto wasTitle = hasTitle();
|
||||
if (title) {
|
||||
_title.create(this, std::move(title), st::boxTitle);
|
||||
_title->show();
|
||||
updateTitlePosition();
|
||||
} else {
|
||||
_title.destroy();
|
||||
@@ -331,9 +386,8 @@ void AbstractBox::refreshTitle() {
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractBox::setAdditionalTitle(Fn<QString()> additionalFactory) {
|
||||
_additionalTitleFactory = std::move(additionalFactory);
|
||||
refreshAdditionalTitle();
|
||||
void AbstractBox::setAdditionalTitle(rpl::producer<QString> additional) {
|
||||
_additionalTitle = std::move(additional);
|
||||
}
|
||||
|
||||
void AbstractBox::setCloseByOutsideClick(bool close) {
|
||||
@@ -344,19 +398,8 @@ bool AbstractBox::closeByOutsideClick() const {
|
||||
return _closeByOutsideClick;
|
||||
}
|
||||
|
||||
void AbstractBox::refreshAdditionalTitle() {
|
||||
_additionalTitle = _additionalTitleFactory ? _additionalTitleFactory() : QString();
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractBox::refreshLang() {
|
||||
refreshTitle();
|
||||
refreshAdditionalTitle();
|
||||
InvokeQueued(this, [this] { updateButtonsPositions(); });
|
||||
}
|
||||
|
||||
bool AbstractBox::hasTitle() const {
|
||||
return (_title != nullptr) || !_additionalTitle.isEmpty();
|
||||
return (_title != nullptr) || !_additionalTitle.current().isEmpty();
|
||||
}
|
||||
|
||||
void AbstractBox::showBox(
|
||||
@@ -409,21 +452,33 @@ void AbstractBox::clearButtons() {
|
||||
_topButton = nullptr;
|
||||
}
|
||||
|
||||
QPointer<Ui::RoundButton> AbstractBox::addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) {
|
||||
_buttons.push_back(object_ptr<Ui::RoundButton>(this, std::move(textFactory), st));
|
||||
QPointer<Ui::RoundButton> AbstractBox::addButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback,
|
||||
const style::RoundButton &st) {
|
||||
_buttons.emplace_back(this, std::move(text), st);
|
||||
auto result = QPointer<Ui::RoundButton>(_buttons.back());
|
||||
result->setClickedCallback(std::move(clickCallback));
|
||||
result->show();
|
||||
updateButtonsPositions();
|
||||
result->widthValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateButtonsPositions();
|
||||
}, result->lifetime());
|
||||
return result;
|
||||
}
|
||||
|
||||
QPointer<Ui::RoundButton> AbstractBox::addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) {
|
||||
_leftButton = object_ptr<Ui::RoundButton>(this, std::move(textFactory), st);
|
||||
QPointer<Ui::RoundButton> AbstractBox::addLeftButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback,
|
||||
const style::RoundButton &st) {
|
||||
_leftButton = object_ptr<Ui::RoundButton>(this, std::move(text), st);
|
||||
auto result = QPointer<Ui::RoundButton>(_leftButton);
|
||||
result->setClickedCallback(std::move(clickCallback));
|
||||
result->show();
|
||||
updateButtonsPositions();
|
||||
result->widthValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateButtonsPositions();
|
||||
}, result->lifetime());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -436,6 +491,36 @@ QPointer<Ui::IconButton> AbstractBox::addTopButton(const style::IconButton &st,
|
||||
return result;
|
||||
}
|
||||
|
||||
void AbstractBox::showLoading(bool show) {
|
||||
const auto &st = st::boxLoadingAnimation;
|
||||
if (!show) {
|
||||
if (_loadingProgress && !_loadingProgress->removeTimer.isActive()) {
|
||||
_loadingProgress->removeTimer.callOnce(
|
||||
st.sineDuration + st.sinePeriod);
|
||||
_loadingProgress->animation.stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!_loadingProgress) {
|
||||
const auto callback = [=] {
|
||||
if (!anim::Disabled()) {
|
||||
const auto t = st::boxLoadingAnimation.thickness;
|
||||
update(loadingRect().marginsAdded({ t, t, t, t }));
|
||||
}
|
||||
};
|
||||
_loadingProgress = std::make_unique<LoadingProgress>(
|
||||
callback,
|
||||
st::boxLoadingAnimation);
|
||||
_loadingProgress->removeTimer.setCallback([=] {
|
||||
_loadingProgress = nullptr;
|
||||
});
|
||||
} else {
|
||||
_loadingProgress->removeTimer.cancel();
|
||||
}
|
||||
_loadingProgress->animation.start();
|
||||
}
|
||||
|
||||
|
||||
void AbstractBox::setDimensions(int newWidth, int maxHeight, bool forceCenterPosition) {
|
||||
_maxContentHeight = maxHeight;
|
||||
|
||||
@@ -514,3 +599,39 @@ void BoxContentDivider::paintEvent(QPaintEvent *e) {
|
||||
auto dividerFillBottom = myrtlrect(0, height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height());
|
||||
st::profileDividerBottom.fill(p, dividerFillBottom);
|
||||
}
|
||||
|
||||
namespace Ui {
|
||||
namespace internal {
|
||||
|
||||
void showBox(
|
||||
object_ptr<BoxContent> content,
|
||||
LayerOptions options,
|
||||
anim::type animated) {
|
||||
if (auto w = App::wnd()) {
|
||||
w->ui_showBox(std::move(content), options, animated);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
void hideLayer(anim::type animated) {
|
||||
if (auto w = App::wnd()) {
|
||||
w->ui_showBox(
|
||||
{ nullptr },
|
||||
LayerOption::CloseOther,
|
||||
animated);
|
||||
}
|
||||
}
|
||||
|
||||
void hideSettingsAndLayer(anim::type animated) {
|
||||
if (auto w = App::wnd()) {
|
||||
w->ui_hideSettingsAndLayer(animated);
|
||||
}
|
||||
}
|
||||
|
||||
bool isLayerShown() {
|
||||
if (auto w = App::wnd()) return w->ui_isLayerShown();
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
||||
@@ -9,8 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "window/layer_widget.h"
|
||||
#include "base/unique_qptr.h"
|
||||
#include "base/flags.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
class Painter;
|
||||
|
||||
namespace style {
|
||||
struct RoundButton;
|
||||
struct IconButton;
|
||||
@@ -30,14 +35,23 @@ class BoxContent;
|
||||
class BoxContentDelegate {
|
||||
public:
|
||||
virtual void setLayerType(bool layerType) = 0;
|
||||
virtual void setTitle(Fn<TextWithEntities()> titleFactory) = 0;
|
||||
virtual void setAdditionalTitle(Fn<QString()> additionalFactory) = 0;
|
||||
virtual void setTitle(rpl::producer<TextWithEntities> title) = 0;
|
||||
virtual void setAdditionalTitle(rpl::producer<QString> additional) = 0;
|
||||
virtual void setCloseByOutsideClick(bool close) = 0;
|
||||
|
||||
virtual void clearButtons() = 0;
|
||||
virtual QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) = 0;
|
||||
virtual QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) = 0;
|
||||
virtual QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback) = 0;
|
||||
virtual QPointer<Ui::RoundButton> addButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback,
|
||||
const style::RoundButton &st) = 0;
|
||||
virtual QPointer<Ui::RoundButton> addLeftButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback,
|
||||
const style::RoundButton &st) = 0;
|
||||
virtual QPointer<Ui::IconButton> addTopButton(
|
||||
const style::IconButton &st,
|
||||
Fn<void()> clickCallback) = 0;
|
||||
virtual void showLoading(bool show) = 0;
|
||||
virtual void updateButtonsPositions() = 0;
|
||||
|
||||
virtual void showBox(
|
||||
@@ -66,7 +80,7 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class BoxContent : public Ui::RpWidget, protected base::Subscriber {
|
||||
class BoxContent : public Ui::RpWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -81,17 +95,11 @@ public:
|
||||
getDelegate()->closeBox();
|
||||
}
|
||||
|
||||
void setTitle(Fn<QString()> titleFactory) {
|
||||
if (titleFactory) {
|
||||
getDelegate()->setTitle([titleFactory] { return TextWithEntities { titleFactory(), EntitiesInText() }; });
|
||||
} else {
|
||||
getDelegate()->setTitle(Fn<TextWithEntities()>());
|
||||
}
|
||||
void setTitle(rpl::producer<QString> title);
|
||||
void setTitle(rpl::producer<TextWithEntities> title) {
|
||||
getDelegate()->setTitle(std::move(title));
|
||||
}
|
||||
void setTitle(Fn<TextWithEntities()> titleFactory) {
|
||||
getDelegate()->setTitle(std::move(titleFactory));
|
||||
}
|
||||
void setAdditionalTitle(Fn<QString()> additional) {
|
||||
void setAdditionalTitle(rpl::producer<QString> additional) {
|
||||
getDelegate()->setAdditionalTitle(std::move(additional));
|
||||
}
|
||||
void setCloseByEscape(bool close) {
|
||||
@@ -106,16 +114,33 @@ public:
|
||||
void clearButtons() {
|
||||
getDelegate()->clearButtons();
|
||||
}
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback = nullptr);
|
||||
QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback = nullptr);
|
||||
QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback = nullptr) {
|
||||
QPointer<Ui::RoundButton> addButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback = nullptr);
|
||||
QPointer<Ui::RoundButton> addLeftButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback = nullptr);
|
||||
QPointer<Ui::IconButton> addTopButton(
|
||||
const style::IconButton &st,
|
||||
Fn<void()> clickCallback = nullptr) {
|
||||
return getDelegate()->addTopButton(st, std::move(clickCallback));
|
||||
}
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, const style::RoundButton &st) {
|
||||
return getDelegate()->addButton(std::move(textFactory), nullptr, st);
|
||||
QPointer<Ui::RoundButton> addButton(
|
||||
rpl::producer<QString> text,
|
||||
const style::RoundButton &st) {
|
||||
return getDelegate()->addButton(std::move(text), nullptr, st);
|
||||
}
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) {
|
||||
return getDelegate()->addButton(std::move(textFactory), std::move(clickCallback), st);
|
||||
QPointer<Ui::RoundButton> addButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback,
|
||||
const style::RoundButton &st) {
|
||||
return getDelegate()->addButton(
|
||||
std::move(text),
|
||||
std::move(clickCallback),
|
||||
st);
|
||||
}
|
||||
void showLoading(bool show) {
|
||||
getDelegate()->showLoading(show);
|
||||
}
|
||||
void updateButtonsGeometry() {
|
||||
getDelegate()->updateButtonsPositions();
|
||||
@@ -162,10 +187,13 @@ protected:
|
||||
getDelegate()->setNoContentMargin(noContentMargin);
|
||||
}
|
||||
void setDimensions(
|
||||
int newWidth,
|
||||
int maxHeight,
|
||||
bool forceCenterPosition = false) {
|
||||
getDelegate()->setDimensions(newWidth, maxHeight, forceCenterPosition);
|
||||
int newWidth,
|
||||
int maxHeight,
|
||||
bool forceCenterPosition = false) {
|
||||
getDelegate()->setDimensions(
|
||||
newWidth,
|
||||
maxHeight,
|
||||
forceCenterPosition);
|
||||
}
|
||||
void setDimensionsToContent(
|
||||
int newWidth,
|
||||
@@ -200,7 +228,8 @@ protected:
|
||||
|
||||
template <typename Widget>
|
||||
object_ptr<Widget> takeInnerWidget() {
|
||||
return static_object_cast<Widget>(doTakeInnerWidget());
|
||||
return object_ptr<Widget>::fromRaw(
|
||||
static_cast<Widget*>(doTakeInnerWidget().release()));
|
||||
}
|
||||
|
||||
void setInnerVisible(bool scrollAreaVisible);
|
||||
@@ -244,29 +273,36 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class AbstractBox
|
||||
: public Window::LayerWidget
|
||||
, public BoxContentDelegate
|
||||
, protected base::Subscriber {
|
||||
class AbstractBox : public Window::LayerWidget, public BoxContentDelegate {
|
||||
public:
|
||||
AbstractBox(
|
||||
not_null<Window::LayerStackWidget*> layer,
|
||||
object_ptr<BoxContent> content);
|
||||
~AbstractBox();
|
||||
|
||||
void parentResized() override;
|
||||
|
||||
void setLayerType(bool layerType) override;
|
||||
void setTitle(Fn<TextWithEntities()> titleFactory) override;
|
||||
void setAdditionalTitle(Fn<QString()> additionalFactory) override;
|
||||
void setTitle(rpl::producer<TextWithEntities> title) override;
|
||||
void setAdditionalTitle(rpl::producer<QString> additional) override;
|
||||
void showBox(
|
||||
object_ptr<BoxContent> box,
|
||||
LayerOptions options,
|
||||
anim::type animated) override;
|
||||
|
||||
void clearButtons() override;
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) override;
|
||||
QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) override;
|
||||
QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback) override;
|
||||
QPointer<Ui::RoundButton> addButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback,
|
||||
const style::RoundButton &st) override;
|
||||
QPointer<Ui::RoundButton> addLeftButton(
|
||||
rpl::producer<QString> text,
|
||||
Fn<void()> clickCallback,
|
||||
const style::RoundButton &st) override;
|
||||
QPointer<Ui::IconButton> addTopButton(
|
||||
const style::IconButton &st,
|
||||
Fn<void()> clickCallback) override;
|
||||
void showLoading(bool show) override;
|
||||
void updateButtonsPositions() override;
|
||||
QPointer<QWidget> outerContainer() override;
|
||||
|
||||
@@ -305,19 +341,19 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
struct LoadingProgress;
|
||||
|
||||
void paintAdditionalTitle(Painter &p);
|
||||
void updateTitlePosition();
|
||||
void refreshTitle();
|
||||
void refreshAdditionalTitle();
|
||||
void refreshLang();
|
||||
|
||||
bool hasTitle() const;
|
||||
int titleHeight() const;
|
||||
int buttonsHeight() const;
|
||||
int buttonsTop() const;
|
||||
int contentTop() const;
|
||||
int countFullHeight() const;
|
||||
int countRealHeight() const;
|
||||
[[nodiscard]] bool hasTitle() const;
|
||||
[[nodiscard]] int titleHeight() const;
|
||||
[[nodiscard]] int buttonsHeight() const;
|
||||
[[nodiscard]] int buttonsTop() const;
|
||||
[[nodiscard]] int contentTop() const;
|
||||
[[nodiscard]] int countFullHeight() const;
|
||||
[[nodiscard]] int countRealHeight() const;
|
||||
[[nodiscard]] QRect loadingRect() const;
|
||||
void updateSize();
|
||||
|
||||
not_null<Window::LayerStackWidget*> _layer;
|
||||
@@ -329,8 +365,7 @@ private:
|
||||
|
||||
object_ptr<Ui::FlatLabel> _title = { nullptr };
|
||||
Fn<TextWithEntities()> _titleFactory;
|
||||
QString _additionalTitle;
|
||||
Fn<QString()> _additionalTitleFactory;
|
||||
rpl::variable<QString> _additionalTitle;
|
||||
int _titleLeft = 0;
|
||||
int _titleTop = 0;
|
||||
bool _layerType = false;
|
||||
@@ -339,6 +374,7 @@ private:
|
||||
std::vector<object_ptr<Ui::RoundButton>> _buttons;
|
||||
object_ptr<Ui::RoundButton> _leftButton = { nullptr };
|
||||
base::unique_qptr<Ui::IconButton> _topButton = { nullptr };
|
||||
std::unique_ptr<LoadingProgress> _loadingProgress;
|
||||
|
||||
};
|
||||
|
||||
@@ -393,3 +429,30 @@ private:
|
||||
QPointer<BoxContent> _value;
|
||||
|
||||
};
|
||||
|
||||
// Legacy global method.
|
||||
namespace Ui {
|
||||
namespace internal {
|
||||
|
||||
void showBox(
|
||||
object_ptr<BoxContent> content,
|
||||
LayerOptions options,
|
||||
anim::type animated);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename BoxType>
|
||||
QPointer<BoxType> show(
|
||||
object_ptr<BoxType> content,
|
||||
LayerOptions options = LayerOption::CloseOther,
|
||||
anim::type animated = anim::type::normal) {
|
||||
auto result = QPointer<BoxType>(content.data());
|
||||
internal::showBox(std::move(content), options, animated);
|
||||
return result;
|
||||
}
|
||||
|
||||
void hideLayer(anim::type animated = anim::type::normal);
|
||||
void hideSettingsAndLayer(anim::type animated = anim::type::normal);
|
||||
bool isLayerShown();
|
||||
|
||||
} // namespace Ui
|
||||
|
||||
@@ -11,12 +11,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mtproto/sender.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
class ConfirmBox;
|
||||
class PeerListBox;
|
||||
|
||||
constexpr auto kMaxBioLength = 70;
|
||||
namespace Window {
|
||||
class SessionNavigation;
|
||||
} // namespace Window
|
||||
|
||||
style::InputField CreateBioFieldStyle();
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class FlatLabel;
|
||||
@@ -32,21 +38,31 @@ class LinkButton;
|
||||
class UserpicButton;
|
||||
} // namespace Ui
|
||||
|
||||
constexpr auto kMaxBioLength = 70;
|
||||
|
||||
enum class PeerFloodType {
|
||||
Send,
|
||||
InviteGroup,
|
||||
InviteChannel,
|
||||
};
|
||||
|
||||
style::InputField CreateBioFieldStyle();
|
||||
|
||||
QString PeerFloodErrorText(PeerFloodType type);
|
||||
void ShowAddParticipantsError(
|
||||
const QString &error,
|
||||
not_null<PeerData*> chat,
|
||||
const std::vector<not_null<UserData*>> &users);
|
||||
|
||||
class AddContactBox : public BoxContent, public RPCSender {
|
||||
class AddContactBox : public BoxContent {
|
||||
public:
|
||||
AddContactBox(QWidget*, QString fname = QString(), QString lname = QString(), QString phone = QString());
|
||||
AddContactBox(QWidget*, UserData *user);
|
||||
AddContactBox(QWidget*, not_null<Main::Session*> session);
|
||||
AddContactBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
QString fname,
|
||||
QString lname,
|
||||
QString phone);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@@ -61,12 +77,8 @@ private:
|
||||
void retry();
|
||||
void save();
|
||||
void updateButtons();
|
||||
void onImportDone(const MTPcontacts_ImportedContacts &res);
|
||||
|
||||
void onSaveUserDone(const MTPcontacts_ImportedContacts &res);
|
||||
bool onSaveUserFail(const RPCError &e);
|
||||
|
||||
UserData *_user = nullptr;
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
object_ptr<Ui::InputField> _first;
|
||||
object_ptr<Ui::InputField> _last;
|
||||
@@ -91,6 +103,7 @@ public:
|
||||
};
|
||||
GroupInfoBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
Type type,
|
||||
const QString &title = QString(),
|
||||
Fn<void(not_null<ChannelData*>)> channelDone = nullptr);
|
||||
@@ -110,6 +123,8 @@ private:
|
||||
void descriptionResized();
|
||||
void updateMaxHeight();
|
||||
|
||||
const not_null<Window::SessionNavigation*> _navigation;
|
||||
|
||||
Type _type = Type::Group;
|
||||
QString _initialTitle;
|
||||
Fn<void(not_null<ChannelData*>)> _channelDone;
|
||||
@@ -124,9 +139,16 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class SetupChannelBox : public BoxContent, public RPCSender {
|
||||
class SetupChannelBox
|
||||
: public BoxContent
|
||||
, public RPCSender
|
||||
, private base::Subscriber {
|
||||
public:
|
||||
SetupChannelBox(QWidget*, ChannelData *channel, bool existing = false);
|
||||
SetupChannelBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<ChannelData*> channel,
|
||||
bool existing = false);
|
||||
|
||||
void setInnerFocus() override;
|
||||
|
||||
@@ -162,14 +184,16 @@ private:
|
||||
|
||||
void showRevokePublicLinkBoxForEdit();
|
||||
|
||||
ChannelData *_channel = nullptr;
|
||||
const not_null<Window::SessionNavigation*> _navigation;
|
||||
const not_null<ChannelData*> _channel;
|
||||
|
||||
bool _existing = false;
|
||||
|
||||
std::shared_ptr<Ui::RadioenumGroup<Privacy>> _privacyGroup;
|
||||
object_ptr<Ui::Radioenum<Privacy>> _public;
|
||||
object_ptr<Ui::Radioenum<Privacy>> _private;
|
||||
int32 _aboutPublicWidth, _aboutPublicHeight;
|
||||
Text _aboutPublic, _aboutPrivate;
|
||||
Ui::Text::String _aboutPublic, _aboutPrivate;
|
||||
|
||||
object_ptr<Ui::UsernameInput> _link;
|
||||
|
||||
@@ -213,9 +237,15 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class RevokePublicLinkBox : public BoxContent, public RPCSender {
|
||||
class RevokePublicLinkBox
|
||||
: public BoxContent
|
||||
, public RPCSender
|
||||
, private base::Subscriber {
|
||||
public:
|
||||
RevokePublicLinkBox(QWidget*, Fn<void()> revokeCallback);
|
||||
RevokePublicLinkBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
Fn<void()> revokeCallback);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@@ -223,6 +253,8 @@ protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _aboutRevoke;
|
||||
|
||||
class Inner;
|
||||
|
||||
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/auto_download_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "auth_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "info/profile/info_profile_button.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
@@ -29,8 +29,10 @@ constexpr auto kDefaultLimit = 10 * kMegabyte;
|
||||
|
||||
AutoDownloadBox::AutoDownloadBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
Data::AutoDownload::Source source)
|
||||
: _source(source) {
|
||||
: _session(session)
|
||||
, _source(source) {
|
||||
}
|
||||
|
||||
void AutoDownloadBox::prepare() {
|
||||
@@ -43,9 +45,9 @@ void AutoDownloadBox::setupContent() {
|
||||
using namespace rpl::mappers;
|
||||
using Type = Data::AutoDownload::Type;
|
||||
|
||||
setTitle(langFactory(lng_media_auto_title));
|
||||
setTitle(tr::lng_media_auto_title());
|
||||
|
||||
const auto settings = &Auth().settings().autoDownload();
|
||||
const auto settings = &_session->settings().autoDownload();
|
||||
const auto checked = [=](Source source, Type type) {
|
||||
return (settings->bytesLimit(source, type) > 0);
|
||||
};
|
||||
@@ -63,14 +65,14 @@ void AutoDownloadBox::setupContent() {
|
||||
};
|
||||
|
||||
const auto values = Ui::CreateChild<base::flat_map<Type, int>>(content);
|
||||
const auto add = [&](Type type, LangKey label) {
|
||||
const auto add = [&](Type type, rpl::producer<QString> label) {
|
||||
if (ranges::find(kHidden, type) != end(kHidden)) {
|
||||
return;
|
||||
}
|
||||
const auto value = settings->bytesLimit(_source, type);
|
||||
AddButton(
|
||||
content,
|
||||
label,
|
||||
std::move(label),
|
||||
st::settingsButton
|
||||
)->toggleOn(
|
||||
rpl::single(value > 0)
|
||||
@@ -80,13 +82,13 @@ void AutoDownloadBox::setupContent() {
|
||||
}, content->lifetime());
|
||||
values->emplace(type, value);
|
||||
};
|
||||
add(Type::Photo, lng_media_photo_title);
|
||||
add(Type::VoiceMessage, lng_media_audio_title);
|
||||
add(Type::VideoMessage, lng_media_video_messages_title);
|
||||
add(Type::Video, lng_media_video_title);
|
||||
add(Type::File, lng_media_file_title);
|
||||
add(Type::Music, lng_media_music_title);
|
||||
add(Type::GIF, lng_media_animation_title);
|
||||
add(Type::Photo, tr::lng_media_photo_title());
|
||||
add(Type::VoiceMessage, tr::lng_media_audio_title());
|
||||
add(Type::VideoMessage, tr::lng_media_video_messages_title());
|
||||
add(Type::Video, tr::lng_media_video_title());
|
||||
add(Type::File, tr::lng_media_file_title());
|
||||
add(Type::Music, tr::lng_media_music_title());
|
||||
add(Type::GIF, tr::lng_media_animation_title());
|
||||
|
||||
const auto limits = Ui::CreateChild<rpl::event_stream<int>>(content);
|
||||
using Pair = base::flat_map<Type, int>::value_type;
|
||||
@@ -98,11 +100,12 @@ void AutoDownloadBox::setupContent() {
|
||||
const auto limit = Ui::CreateChild<int>(content, initialLimit);
|
||||
AddButtonWithLabel(
|
||||
content,
|
||||
lng_media_size_limit,
|
||||
tr::lng_media_size_limit(),
|
||||
limits->events_starting_with_copy(
|
||||
initialLimit
|
||||
) | rpl::map([](int value) {
|
||||
return lng_media_size_up_to(
|
||||
return tr::lng_media_size_up_to(
|
||||
tr::now,
|
||||
lt_size,
|
||||
QString::number(value / kMegabyte) + " MB");
|
||||
}),
|
||||
@@ -121,7 +124,7 @@ void AutoDownloadBox::setupContent() {
|
||||
limits->fire_copy(value);
|
||||
});
|
||||
|
||||
addButton(langFactory(lng_connection_save), [=] {
|
||||
addButton(tr::lng_connection_save(), [=] {
|
||||
auto allowMore = ranges::view::all(
|
||||
*values
|
||||
) | ranges::view::filter([&](Pair pair) {
|
||||
@@ -165,15 +168,15 @@ void AutoDownloadBox::setupContent() {
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
if (allowMoreTypes.contains(Type::Photo)) {
|
||||
Auth().data().photoLoadSettingsChanged();
|
||||
_session->data().photoLoadSettingsChanged();
|
||||
}
|
||||
if (ranges::find_if(allowMoreTypes, _1 != Type::Photo)
|
||||
!= allowMoreTypes.end()) {
|
||||
Auth().data().documentLoadSettingsChanged();
|
||||
_session->data().documentLoadSettingsChanged();
|
||||
}
|
||||
closeBox();
|
||||
});
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
setDimensionsToContent(st::boxWidth, content);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Data {
|
||||
namespace AutoDownload {
|
||||
enum class Source;
|
||||
@@ -17,7 +21,10 @@ enum class Source;
|
||||
|
||||
class AutoDownloadBox : public BoxContent {
|
||||
public:
|
||||
AutoDownloadBox(QWidget*, Data::AutoDownload::Source source);
|
||||
AutoDownloadBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
Data::AutoDownload::Source source);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@@ -25,6 +32,8 @@ protected:
|
||||
private:
|
||||
void setupContent();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
Data::AutoDownload::Source _source;
|
||||
|
||||
};
|
||||
|
||||
@@ -11,12 +11,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "storage/localstorage.h"
|
||||
#include "mainwindow.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "facades.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
void AutoLockBox::prepare() {
|
||||
setTitle(langFactory(lng_passcode_autolock));
|
||||
AutoLockBox::AutoLockBox(QWidget*, not_null<Main::Session*> session)
|
||||
: _session(session) {
|
||||
}
|
||||
|
||||
addButton(langFactory(lng_box_ok), [this] { closeBox(); });
|
||||
void AutoLockBox::prepare() {
|
||||
setTitle(tr::lng_passcode_autolock());
|
||||
|
||||
addButton(tr::lng_box_ok(), [this] { closeBox(); });
|
||||
|
||||
auto options = { 60, 300, 3600, 18000 };
|
||||
|
||||
@@ -25,7 +30,7 @@ void AutoLockBox::prepare() {
|
||||
auto count = int(options.size());
|
||||
_options.reserve(count);
|
||||
for (auto seconds : options) {
|
||||
_options.emplace_back(this, group, seconds, (seconds % 3600) ? lng_passcode_autolock_minutes(lt_count, seconds / 60) : lng_passcode_autolock_hours(lt_count, seconds / 3600), st::autolockButton);
|
||||
_options.emplace_back(this, group, seconds, (seconds % 3600) ? tr::lng_passcode_autolock_minutes(tr::now, lt_count, seconds / 60) : tr::lng_passcode_autolock_hours(tr::now, lt_count, seconds / 3600), st::autolockButton);
|
||||
_options.back()->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), y);
|
||||
y += _options.back()->heightNoMargins() + st::boxOptionListSkip;
|
||||
}
|
||||
@@ -39,6 +44,6 @@ void AutoLockBox::durationChanged(int seconds) {
|
||||
Local::writeUserSettings();
|
||||
Global::RefLocalPasscodeChanged().notify();
|
||||
|
||||
Auth().checkAutoLock();
|
||||
_session->checkAutoLock();
|
||||
closeBox();
|
||||
}
|
||||
|
||||