Compare commits
603 commits
Author | SHA1 | Date | |
---|---|---|---|
|
3be793032f | ||
|
0fab18e8e8 | ||
|
c91f41e988 | ||
|
3c7f3e8740 | ||
|
3a9899529a | ||
|
5a015888d4 | ||
|
be378eaacb | ||
|
631f5a1043 | ||
|
353e9adec1 | ||
|
e572da4927 | ||
|
d22afa36c3 | ||
|
a7296f15ac | ||
|
b20caee548 | ||
|
519832edd7 | ||
|
a2cea1e5bc | ||
|
b3c198f0d2 | ||
|
b45a696b5d | ||
|
a2b3fe6411 | ||
|
13d4f37726 | ||
|
71f34f4e31 | ||
|
018f147de6 | ||
|
da012cbf8b | ||
|
3907a103fc | ||
|
efb566bcc7 | ||
|
53e8df3542 | ||
|
a00d262773 | ||
|
b64db54793 | ||
|
97c0e3d4a9 | ||
|
ba31bbace8 | ||
|
606dfd29d3 | ||
|
9411d0781b | ||
|
7aea200860 | ||
|
5d8ac95d07 | ||
|
cd0ebb41aa | ||
|
eb028b0dad | ||
|
61803f7516 | ||
|
50bfed79be | ||
|
1c77ae818e | ||
|
66ede6037d | ||
|
01452b7309 | ||
|
b5f2470b79 | ||
|
49403e9fee | ||
|
66d512f26f | ||
|
2ba0ebf3e8 | ||
|
bbcd27d3c2 | ||
|
837a3528cd | ||
|
f39662588f | ||
|
4b12f52029 | ||
|
f2920ddefb | ||
|
ce010653d5 | ||
|
ce764c862f | ||
|
60d821ae3e | ||
|
8f7f8fc0b5 | ||
|
ec45041a66 | ||
|
67a666b282 | ||
|
d9404fc566 | ||
|
bcd899c641 | ||
|
ec61ac29ea | ||
|
180e663a43 | ||
|
ae1711a685 | ||
|
9c3b62574d | ||
|
a3637c12d6 | ||
|
cae192682b | ||
|
6c68bacaef | ||
|
ee7a2b564b | ||
|
fb25d90b48 | ||
|
9075a521f0 | ||
|
00a0e595ff | ||
|
694ff32b01 | ||
|
a74635ff56 | ||
|
8c6f3d66b5 | ||
|
a49cb06d77 | ||
|
f96f478470 | ||
|
1d2f713673 | ||
|
57d24d0fbf | ||
|
584e55a89c | ||
|
4560a83441 | ||
|
f4658728e8 | ||
|
54825dc66f | ||
|
d4056ac10a | ||
|
8f409a8fe2 | ||
|
d369d988b0 | ||
|
2a74736761 | ||
|
6bd0bf6e69 | ||
|
53cee177e8 | ||
|
a8afc62db7 | ||
|
14328eb601 | ||
|
2184755fdf | ||
|
3a3cd1f856 | ||
|
24a3a41cd6 | ||
|
197f6b05ae | ||
|
c2e887a86e | ||
|
12b16577ef | ||
|
409165dec6 | ||
|
4870d59a43 | ||
|
70c3bb3288 | ||
|
36156997ee | ||
|
2c2728448c | ||
|
d1781a7c47 | ||
|
dc1459438c | ||
|
00e6da9d64 | ||
|
68b3d75705 | ||
|
3e538b732a | ||
|
833341dea7 | ||
|
bc3efe2f4c | ||
|
10e4c59f2e | ||
|
d9016b7979 | ||
|
d975610ecd | ||
|
5d1251f6d8 | ||
|
bdf802e64a | ||
|
f2b888f9ae | ||
|
9583007769 | ||
|
eb81c33308 | ||
|
8d734f5cc4 | ||
|
3375ff6152 | ||
|
80fc58f83e | ||
|
17c0124747 | ||
|
c220d4dd17 | ||
|
15146725e3 | ||
|
ddfab824c3 | ||
|
8b5a00ca27 | ||
|
04a7f14c0e | ||
|
18f14b828c | ||
|
0a92e12a62 | ||
|
5b71281ec4 | ||
|
08fdc4f1fc | ||
|
c726bef740 | ||
|
94e0ac3f54 | ||
|
284f7fc4f7 | ||
|
e629460942 | ||
|
904e531113 | ||
|
ca2f2adc90 | ||
|
78a3e329f5 | ||
|
5938e0f821 | ||
|
4a6ae3b46c | ||
|
2327d661b9 | ||
|
9790e37154 | ||
|
f97d751343 | ||
|
81c1f6bd8e | ||
|
e3a5a4239b | ||
|
fcec85881f | ||
|
cfefb8b2e0 | ||
|
e81a2a5011 | ||
|
d62b488459 | ||
|
932bd92b95 | ||
|
9fd1f95ab8 | ||
|
cf414cb9cb | ||
|
f676d32f96 | ||
|
939c9afeb4 | ||
|
7d88c48c39 | ||
|
26337a6bd4 | ||
|
1263a5bfc0 | ||
|
fe21ca5b95 | ||
|
0fe9dad515 | ||
|
75b33c906d | ||
|
835fa77964 | ||
|
3e13186560 | ||
|
01f191289d | ||
|
6586791655 | ||
|
b4f6774ca8 | ||
|
75d346fe69 | ||
|
27780c7327 | ||
|
100a8882f1 | ||
|
983bd1a57b | ||
|
810f7949f4 | ||
|
28c502bd85 | ||
|
b8c313965f | ||
|
8a2dcbbcff | ||
|
263b9fa611 | ||
|
793e15f80c | ||
|
23d1394fb2 | ||
|
f97bb23c9d | ||
|
d557739a28 | ||
|
8d06243b57 | ||
|
9a4b73b942 | ||
|
d73e0dd13c | ||
|
2f3818fe4b | ||
|
d3d773079c | ||
|
0b2acec50c | ||
|
3501e4f44d | ||
|
384c540197 | ||
|
1b78ffc018 | ||
|
79f4f0adbf | ||
|
98d71308a8 | ||
|
4f0fa66575 | ||
|
ecac3a0f16 | ||
|
d1898b9a0b | ||
|
868c7b170e | ||
|
b1c5c53687 | ||
|
6704886c6e | ||
|
7e45283ba2 | ||
|
ff67d876b2 | ||
|
4975a0a8d8 | ||
|
e34a4338a1 | ||
|
0b4986b47a | ||
|
937eab5f27 | ||
|
70378bfac8 | ||
|
29d87f692a | ||
|
b1b2798be1 | ||
|
2b74ad8b5f | ||
|
3098fa6855 | ||
|
53883a7f1f | ||
|
2c048376d4 | ||
|
b583240d58 | ||
|
844be11d43 | ||
|
53b739139b | ||
|
d09d1d72e6 | ||
|
01d927aceb | ||
|
59abfcbd6d | ||
|
4c2ec15f70 | ||
|
2b6dfbf4eb | ||
|
eb8372eb91 | ||
|
c6b2967da0 | ||
|
042f51e58f | ||
|
c72cf46db7 | ||
|
2a7aac76d9 | ||
|
a569495f5d | ||
|
59e56600bc | ||
|
915dec7ba5 | ||
|
909bd3dd2d | ||
|
d50fad615f | ||
|
b036bedbc3 | ||
|
55c05d1a6e | ||
|
344c0f6427 | ||
|
8ab1a7268b | ||
|
e5f31dbe8e | ||
|
783c5c12e9 | ||
|
c972485555 | ||
|
c507382d19 | ||
|
fbbcbc8753 | ||
|
a5fa595627 | ||
|
502045f1fa | ||
|
e9280777fd | ||
|
c36f402b88 | ||
|
3a68dd50ce | ||
|
eb06c0da08 | ||
|
6528567746 | ||
|
09229812f4 | ||
|
aaa37a3e0d | ||
|
c5531b1bd8 | ||
|
021115b463 | ||
|
698d9c208f | ||
|
01a6b432f3 | ||
|
a5f44b3ed6 | ||
|
a3ba99c682 | ||
|
7c709fddba | ||
|
8f313b4603 | ||
|
41c0a5ee3b | ||
|
346f7aadd6 | ||
|
be611c1920 | ||
|
e33a866a63 | ||
|
c846eeed9d | ||
|
d052eac019 | ||
|
9dbd134601 | ||
|
6451e1cfe2 | ||
|
9f3f715527 | ||
|
0d8e5b139b | ||
|
5d5dda548a | ||
|
1d32e5267c | ||
|
a300a25419 | ||
|
4eaf03b922 | ||
|
4401ea388c | ||
|
dfe6ad3a32 | ||
|
e3ef870b29 | ||
|
7deb5bfdf2 | ||
|
0e46a4402a | ||
|
33a15e69bb | ||
|
ebe11fdb1e | ||
|
f9a7c46868 | ||
|
c80c23e8e8 | ||
|
5e6c81a98e | ||
|
214cc83d4a | ||
|
8e643fbf87 | ||
|
6008d9e12b | ||
|
81da453ec4 | ||
|
f34835463d | ||
|
eb3419f3fc | ||
|
5886a07300 | ||
|
69e7c27fd0 | ||
|
165cf6809f | ||
|
9b2b8b6796 | ||
|
3ed6d1dec1 | ||
|
9ad1d1c25d | ||
|
667e614bf3 | ||
|
d49da1fdd0 | ||
|
85b0733169 | ||
|
7f2bba7c4a | ||
|
664ec62396 | ||
|
b4a9e45214 | ||
|
2eab7044ba | ||
|
8d449f91c6 | ||
|
be8a836528 | ||
|
423782fd2b | ||
|
dc1dc8dffa | ||
|
16a77e2975 | ||
|
df69a70dd7 | ||
|
0638c86211 | ||
|
8c0de22c14 | ||
|
f83568c6c9 | ||
|
10d472728c | ||
|
2c3cb3f5ce | ||
|
fbfe3fd5ed | ||
|
b280a26317 | ||
|
640db8af7d | ||
|
98d9357208 | ||
|
f3b6c7c09b | ||
|
3a622f111a | ||
|
e0b1ed87e8 | ||
|
63578affa4 | ||
|
74b188fa46 | ||
|
fadaf852b7 | ||
|
ac6124951a | ||
|
89e42af149 | ||
|
cf5987b2b4 | ||
|
069d8d376c | ||
|
fe3d8ea2be | ||
|
3ac03b43e1 | ||
|
eaf1a532f4 | ||
|
f2b0116c1e | ||
|
155b5fa831 | ||
|
130c77a305 | ||
|
2e168d152f | ||
|
e0890541ea | ||
|
1447b62999 | ||
|
518ae8044d | ||
|
314a90995a | ||
|
8f29e32577 | ||
|
b6e25a353d | ||
|
635ed02198 | ||
|
cd81a54062 | ||
|
1035d787ab | ||
|
29567df407 | ||
|
79cb4668f1 | ||
|
9bdc19e2fd | ||
|
25cd6106f5 | ||
|
13fbe59164 | ||
|
c261c3367a | ||
|
8b92ab25c7 | ||
|
0aa1031270 | ||
|
dec8bdb39d | ||
|
f318aeb67c | ||
|
8b791e77d6 | ||
|
260b72fec1 | ||
|
7d0beafce0 | ||
|
3c2f8b65ce | ||
|
5f73e8b3bf | ||
|
74afeeb85f | ||
|
f8920e5fef | ||
|
dd76313084 | ||
|
627ff6f26e | ||
|
705db0b9cf | ||
|
47a958d81d | ||
|
906fc9cc1d | ||
|
44d9525476 | ||
|
8b2a549fab | ||
|
7312e34f46 | ||
|
696be858f6 | ||
|
e1f4fd0c7b | ||
|
f51320d1bc | ||
|
a0764190f2 | ||
|
33c5b35444 | ||
|
04e10f81b5 | ||
|
7f2545a9ef | ||
|
a2a16f3f23 | ||
|
ab2a947992 | ||
|
7d0a73a6b0 | ||
|
e3c3a68566 | ||
|
4fc026b13c | ||
|
c0fed4d2c3 | ||
|
b656e14453 | ||
|
fbab3964e6 | ||
|
d9b270b477 | ||
|
7f53a19647 | ||
|
9f1e90d007 | ||
|
9a439e1941 | ||
|
4e4c69993c | ||
|
0d085d500f | ||
|
f734c0475b | ||
|
a30951dc91 | ||
|
c4b37950a9 | ||
|
7cf832a2f4 | ||
|
1f07e7978d | ||
|
5adab2739b | ||
|
2be76760de | ||
|
28c125a3ec | ||
|
bdf8a37a8f | ||
|
838711e2ac | ||
|
c085691c54 | ||
|
47506d70ed | ||
|
efc7cc4980 | ||
|
f2016a8aa5 | ||
|
d6bbc375c4 | ||
|
885996c5cf | ||
|
4e4604e00a | ||
|
b057d4fcb7 | ||
|
cdf27296e4 | ||
|
889f111300 | ||
|
520b4f92ab | ||
|
feb1d4ebcc | ||
|
c11a7589e2 | ||
|
c332b7cb40 | ||
|
418dcedc4e | ||
|
a21eb9d59e | ||
|
25ed8fe044 | ||
|
b079c79390 | ||
|
d7a89ef122 | ||
|
b95035e7a2 | ||
|
e28d29f276 | ||
|
c29d78ac0d | ||
|
ad9106b815 | ||
|
f3ea24f9f9 | ||
|
96fdece478 | ||
|
c30a5782df | ||
|
c924fcb91f | ||
|
46e7b6d6df | ||
|
bb8ecf2f84 | ||
|
7123a6d647 | ||
|
eb4ef8b3d7 | ||
|
0d346610a2 | ||
|
fe0c1acd79 | ||
|
b3552d8c2c | ||
|
206a15191f | ||
|
22de3980d1 | ||
|
af35beefc2 | ||
|
532258bea8 | ||
|
5b257293eb | ||
|
8e6d23ddd6 | ||
|
6d5d61c842 | ||
|
9d2e2a1739 | ||
|
19e2642ec1 | ||
|
f9df522b41 | ||
|
b3e5c4a4aa | ||
|
06ed6c81a7 | ||
|
d1e4dbb603 | ||
|
abe8079296 | ||
|
033cb2790c | ||
|
188edce258 | ||
|
34858b36c1 | ||
|
044ef3447c | ||
|
2660439160 | ||
|
9502120ee3 | ||
|
7f1a3320dd | ||
|
8a4fd7f182 | ||
|
b0a4d15d64 | ||
|
3f6f96cfb4 | ||
|
99a1c98ae0 | ||
|
fd718dfd5c | ||
|
31cb2f1999 | ||
|
a6a8e32be7 | ||
|
594bb8a76b | ||
|
228bbc1e8e | ||
|
b14c2878b3 | ||
|
57f10040e1 | ||
|
0fb67c78a9 | ||
|
ff0f7f49da | ||
|
9682e37547 | ||
|
7197d9480b | ||
|
3315c9c7f4 | ||
|
f57eff4195 | ||
|
f0c8e48403 | ||
|
de87bed375 | ||
|
5cdfaab2db | ||
|
acb0b029b9 | ||
|
4c74cbbbe9 | ||
|
ad64e068db | ||
|
6bed3f3f09 | ||
|
d02e55da06 | ||
|
d662a8f2b9 | ||
|
13a93102a5 | ||
|
0d6a1e6610 | ||
|
05cd9eebb8 | ||
|
d93d8ab1cc | ||
|
540fa0e669 | ||
|
17a10cf6bb | ||
|
11d0f9db03 | ||
|
f024ceecdd | ||
|
08c07a0785 | ||
|
b843f91b3c | ||
|
4b2c5b3321 | ||
|
2b43f2682a | ||
|
7da0124286 | ||
|
feaeef6482 | ||
|
15bcfeec1d | ||
|
5fb002ab4c | ||
|
f56ddbb1e0 | ||
|
6bd2a7c962 | ||
|
9d591ae806 | ||
|
7d30e3913c | ||
|
19d7dd7aa3 | ||
|
45444253fd | ||
|
308ade6a7e | ||
|
66d54ccd54 | ||
|
ccf8d91f01 | ||
|
7c940a0480 | ||
|
277a2edb57 | ||
|
bd742689e9 | ||
|
9ca0c3c41d | ||
|
ce8650b4de | ||
|
4bce9d440e | ||
|
adc691f516 | ||
|
fc67a801e3 | ||
|
6a3657ca87 | ||
|
0537c5f273 | ||
|
cc4a5f30b6 | ||
|
b0d7c3e9b1 | ||
|
3bf7c44fc9 | ||
|
4ff4e63a11 | ||
|
72a35ba58b | ||
|
b6a31979f2 | ||
|
7c710e22cc | ||
|
ab58e7a225 | ||
|
c9fb97cd7c | ||
|
789f3e1584 | ||
|
0fc8229be1 | ||
|
a1e555267e | ||
|
0ac88c0cb5 | ||
|
d43a6da62b | ||
|
940455f786 | ||
|
0f74456f30 | ||
|
7840fa6d90 | ||
|
95ccc99fee | ||
|
7b0a156bba | ||
|
0d8ae7bb37 | ||
|
9491cff1df | ||
|
51dc5d6e37 | ||
|
f4c739ab92 | ||
|
0dd8ae3d77 | ||
|
7d2878d81c | ||
|
bd70a05861 | ||
|
0605c7b2bc | ||
|
8e83a55143 | ||
|
4ab4eb8ef2 | ||
|
d1e6150874 | ||
|
4121c99f36 | ||
|
827040f487 | ||
|
9032489786 | ||
|
8ea7bd4913 | ||
|
97b021efaf | ||
|
b3f9a77ba7 | ||
|
63fdc1f876 | ||
|
17cf354c58 | ||
|
c6fd8bcb99 | ||
|
1684465e04 | ||
|
fe2df96953 | ||
|
ee9d0cfd99 | ||
|
7b7e18e752 | ||
|
928be4151b | ||
|
37dd648686 | ||
|
93a590774e | ||
|
22b99b6d3e | ||
|
101d626d4f | ||
|
3633c19208 | ||
|
e302f328f7 | ||
|
f74ba95e95 | ||
|
c38982d286 | ||
|
fe9bac096b | ||
|
5b809c4fc6 | ||
|
4729e51e14 | ||
|
960cf7a34b | ||
|
852ab19760 | ||
|
2e45d9fc6b | ||
|
74b71b92b6 | ||
|
bbc14ba74f | ||
|
45c7829cd8 | ||
|
f2aa3afbbb | ||
|
909b01241b | ||
|
abb58c58a0 | ||
|
700e10d32c | ||
|
4ac48d0e4a | ||
|
345b2cb835 | ||
|
b962309498 | ||
|
e99cb9bfb8 | ||
|
9e12e18f90 | ||
|
66fc9b38df | ||
|
5dbe429e6b | ||
|
b2481ea6c1 | ||
|
86a294ce4b | ||
|
a8d1eadfbf | ||
|
b07d3c5403 | ||
|
892db55ae1 | ||
|
93615fef65 | ||
|
87452706ef | ||
|
3569615b21 | ||
|
86f7d09d31 | ||
|
d5d1254393 | ||
|
4df90cfb9e | ||
|
ec6862d31a | ||
|
6f23010382 | ||
|
c672f105d3 | ||
|
e60d501e4a | ||
|
0d7175058b | ||
|
3b0bd9d1d1 | ||
|
bd28ac6e1f | ||
|
0c2d00c792 | ||
|
140ba653b9 | ||
|
f64f008f77 | ||
|
a6315bef05 | ||
|
f810d7c82a | ||
|
cf61dedc79 | ||
|
2ab9587f5f | ||
|
4950b52359 | ||
|
03af444735 | ||
|
7f6221b409 |
105
.cursor/rules/api_usage.mdc
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
---
|
||||||
|
description: For tasks requiring sending Telegram server API requests or working with generated API types.
|
||||||
|
globs:
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
# Telegram Desktop API Usage
|
||||||
|
|
||||||
|
## API Schema
|
||||||
|
|
||||||
|
The API definitions are described using [TL Language]\(https:/core.telegram.org/mtproto/TL) in two main schema files:
|
||||||
|
|
||||||
|
1. **`Telegram/SourceFiles/mtproto/scheme/mtproto.tl`**
|
||||||
|
* Defines the core MTProto protocol types and methods used for basic communication, encryption, authorization, service messages, etc.
|
||||||
|
* Some fundamental types and methods from this schema (like basic types, RPC calls, containers) are often implemented directly in the C++ MTProto core (`SourceFiles/mtproto/`) and may be skipped during the C++ code generation phase.
|
||||||
|
* Other parts of `mtproto.tl` might still be processed by the code generator.
|
||||||
|
|
||||||
|
2. **`Telegram/SourceFiles/mtproto/scheme/api.tl`**
|
||||||
|
* Defines the higher-level Telegram API layer, including all the methods and types related to chat functionality, user profiles, messages, channels, stickers, etc.
|
||||||
|
* This is the primary schema used when making functional API requests within the application.
|
||||||
|
|
||||||
|
Both files use the same TL syntax to describe API methods (functions) and types (constructors).
|
||||||
|
|
||||||
|
## Code Generation
|
||||||
|
|
||||||
|
A custom code generation tool processes `api.tl` (and parts of `mtproto.tl`) to create corresponding C++ classes and types. These generated headers are typically included via the Precompiled Header (PCH) for the main `Telegram` project.
|
||||||
|
|
||||||
|
Generated types often follow the pattern `MTP[Type]` (e.g., `MTPUser`, `MTPMessage`) and methods correspond to functions within the `MTP` namespace or related classes (e.g., `MTPmessages_SendMessage`).
|
||||||
|
|
||||||
|
## Making API Requests
|
||||||
|
|
||||||
|
API requests are made using a standard pattern involving the `api()` object (providing access to the `MTP::Instance`), the generated `MTP...` request object, callback handlers for success (`.done()`) and failure (`.fail()`), and the `.send()` method.
|
||||||
|
|
||||||
|
Here's the general structure:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Include necessary headers if not already in PCH
|
||||||
|
|
||||||
|
// Obtain the API instance (usually via api() or MTP::Instance::Get())
|
||||||
|
api().request(MTPnamespace_MethodName(
|
||||||
|
// Constructor arguments based on the api.tl definition for the method
|
||||||
|
MTP_flags(flags_value), // Use MTP_flags if the method has flags
|
||||||
|
MTP_inputPeer(peer), // Use MTP_... types for parameters
|
||||||
|
MTP_string(messageText),
|
||||||
|
MTP_long(randomId),
|
||||||
|
// ... other arguments matching the TL definition
|
||||||
|
MTP_vector<MTPMessageEntity>() // Example for a vector argument
|
||||||
|
)).done([=]\(const MTPResponseType &result) {
|
||||||
|
// Handle the successful response (result).
|
||||||
|
// 'result' will be of the C++ type corresponding to the TL type
|
||||||
|
// specified after the '=' in the api.tl method definition.
|
||||||
|
// How to access data depends on whether the TL type has one or multiple constructors:
|
||||||
|
|
||||||
|
// 1. Multiple Constructors (e.g., User = User | UserEmpty):
|
||||||
|
// Use .match() with lambdas for each constructor:
|
||||||
|
result.match([&]\(const MTPDuser &data) {
|
||||||
|
/* use data.vfirst_name().v, etc. */
|
||||||
|
}, [&]\(const MTPDuserEmpty &data) {
|
||||||
|
/* handle empty user */
|
||||||
|
});
|
||||||
|
|
||||||
|
// Alternatively, check the type explicitly and use the constructor getter:
|
||||||
|
if (result.type() == mtpc_user) {
|
||||||
|
const auto &data = result.c_user(); // Asserts if type is not mtpc_user!
|
||||||
|
// use data.vfirst_name().v
|
||||||
|
} else if (result.type() == mtpc_userEmpty) {
|
||||||
|
const auto &data = result.c_userEmpty();
|
||||||
|
// handle empty user
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Single Constructor (e.g., Messages = messages { msgs: vector<Message> }):
|
||||||
|
// Use .match() with a single lambda:
|
||||||
|
result.match([&]\(const MTPDmessages &data) { /* use data.vmessages().v */ });
|
||||||
|
|
||||||
|
// Or check the type explicitly and use the constructor getter:
|
||||||
|
if (result.type() == mtpc_messages) {
|
||||||
|
const auto &data = result.c_messages(); // Asserts if type is not mtpc_messages!
|
||||||
|
// use data.vmessages().v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or use the shortcut .data() for single-constructor types:
|
||||||
|
const auto &data = result.data(); // Only works for single-constructor types!
|
||||||
|
// use data.vmessages().v
|
||||||
|
|
||||||
|
}).fail([=]\(const MTP::Error &error) {
|
||||||
|
// Handle the API error (error).
|
||||||
|
// 'error' is an MTP::Error object containing the error code (error.type())
|
||||||
|
// and description (error.description()). Check for specific error strings.
|
||||||
|
if (error.type() == u"FLOOD_WAIT_X"_q) {
|
||||||
|
// Handle flood wait
|
||||||
|
} else {
|
||||||
|
Ui::show(Box<InformBox>(Lang::Hard::ServerError())); // Example generic error handling
|
||||||
|
}
|
||||||
|
}).handleFloodErrors().send(); // handleFloodErrors() is common, then send()
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Points:**
|
||||||
|
|
||||||
|
* Always refer to `Telegram/SourceFiles/mtproto/scheme/api.tl` for the correct method names, parameters (names and types), and response types.
|
||||||
|
* Use the generated `MTP...` types/classes for request parameters (e.g., `MTP_int`, `MTP_string`, `MTP_bool`, `MTP_vector`, `MTPInputUser`, etc.) and response handling.
|
||||||
|
* The `.done()` lambda receives the specific C++ `MTP...` type corresponding to the TL return type.
|
||||||
|
* For types with **multiple constructors** (e.g., `User = User | UserEmpty`), use `result.match([&]\(const MTPDuser &d){ ... }, [&]\(const MTPDuserEmpty &d){ ... })` to handle each case, or check `result.type() == mtpc_user` / `mtpc_userEmpty` and call the specific `result.c_user()` / `result.c_userEmpty()` getter (which asserts on type mismatch).
|
||||||
|
* For types with a **single constructor** (e.g., `Messages = messages{...}`), you can use `result.match([&]\(const MTPDmessages &d){ ... })` with one lambda, or check `type()` and call `c_messages()`, or use the shortcut `result.data()` to access the fields directly.
|
||||||
|
* The `.fail()` lambda receives an `MTP::Error` object. Check `error.type()` against known error strings (often defined as constants or using `u"..."_q` literals).
|
||||||
|
* Directly construct the `MTPnamespace_MethodName(...)` object inside `request()`.
|
||||||
|
* Include `.handleFloodErrors()` before `.send()` for standard flood wait handling.
|
164
.cursor/rules/localization.mdc
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
---
|
||||||
|
description: For tasks requiring changing or adding user facing phrases and text parts.
|
||||||
|
globs:
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
# Telegram Desktop Localization
|
||||||
|
|
||||||
|
## Coding Style Note
|
||||||
|
|
||||||
|
**Use `auto`:** In the actual codebase, variable types are almost always deduced using `auto` (or `const auto`, `const auto &`) rather than being written out explicitly. Examples in this guide may use explicit types for clarity, but prefer `auto` in practice.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Prefer this:
|
||||||
|
auto currentTitle = tr::lng_settings_title(tr::now);
|
||||||
|
auto nameProducer = GetNameProducer(); // Returns rpl::producer<...>
|
||||||
|
|
||||||
|
// Instead of this:
|
||||||
|
QString currentTitle = tr::lng_settings_title(tr::now);
|
||||||
|
rpl::producer<QString> nameProducer = GetNameProducer();
|
||||||
|
```
|
||||||
|
|
||||||
|
## String Resource File
|
||||||
|
|
||||||
|
Base user-facing English strings are defined in the `lang.strings` file:
|
||||||
|
|
||||||
|
`Telegram/Resources/langs/lang.strings`
|
||||||
|
|
||||||
|
This file uses a key-value format with named placeholders:
|
||||||
|
|
||||||
|
```
|
||||||
|
"lng_settings_title" = "Settings";
|
||||||
|
"lng_confirm_delete_item" = "Are you sure you want to delete {item_name}?";
|
||||||
|
"lng_files_selected" = "{count} files selected"; // Simple count example (see Pluralization)
|
||||||
|
```
|
||||||
|
|
||||||
|
Placeholders are enclosed in curly braces, e.g., `{name}`, `{user}`. A special placeholder `{count}` is used for pluralization rules.
|
||||||
|
|
||||||
|
### Pluralization
|
||||||
|
|
||||||
|
For keys that depend on a number (using the `{count}` placeholder), English typically requires two forms: singular and plural. These are defined in `lang.strings` using `#one` and `#other` suffixes:
|
||||||
|
|
||||||
|
```
|
||||||
|
"lng_files_selected#one" = "{count} file selected";
|
||||||
|
"lng_files_selected#other" = "{count} files selected";
|
||||||
|
```
|
||||||
|
|
||||||
|
While only `#one` and `#other` are defined in the base `lang.strings`, the code generation process creates C++ accessors for all six CLDR plural categories (`#zero`, `#one`, `#two`, `#few`, `#many`, `#other`) to support languages with more complex pluralization rules.
|
||||||
|
|
||||||
|
## Translation Process
|
||||||
|
|
||||||
|
While `lang.strings` provides the base English text and the keys, the actual translations are managed via Telegram's translations platform (translations.telegram.org) and loaded dynamically at runtime from the API. The keys from `lang.strings` (including the `#one`/`#other` variants) are used on the platform.
|
||||||
|
|
||||||
|
## Code Generation
|
||||||
|
|
||||||
|
A code generation tool processes `lang.strings` to create C++ structures and accessors within the `tr` namespace. These allow type-safe access to strings and handling of placeholders and pluralization. Generated keys typically follow the pattern `tr::lng_key_name`.
|
||||||
|
|
||||||
|
## String Usage in Code
|
||||||
|
|
||||||
|
Strings are accessed in C++ code using the generated objects within the `tr::` namespace. There are two main ways to use them: reactively (returning an `rpl::producer`) or immediately (returning the current value).
|
||||||
|
|
||||||
|
### 1. Reactive Usage (rpl::producer)
|
||||||
|
|
||||||
|
Calling a generated string function directly returns a reactive producer, typically `rpl::producer<QString>`. This producer automatically updates its value whenever the application language changes.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Key: "settings_title" = "Settings";
|
||||||
|
auto titleProducer = tr::lng_settings_title(); // Type: rpl::producer<QString>
|
||||||
|
|
||||||
|
// Key: "confirm_delete_item" = "Are you sure you want to delete {item_name}?";
|
||||||
|
auto itemNameProducer = /* ... */; // Type: rpl::producer<QString>
|
||||||
|
auto confirmationProducer = tr::lng_confirm_delete_item( // Type: rpl::producer<QString>
|
||||||
|
tr::now, // NOTE: tr::now is NOT passed here for reactive result
|
||||||
|
lt_item_name,
|
||||||
|
std::move(itemNameProducer)); // Placeholder producers should be moved
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Immediate Usage (Current Value)
|
||||||
|
|
||||||
|
Passing `tr::now` as the first argument retrieves the string's current value in the active language (typically as a `QString`).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Key: "settings_title" = "Settings";
|
||||||
|
auto currentTitle = tr::lng_settings_title(tr::now); // Type: QString
|
||||||
|
|
||||||
|
// Key: "confirm_delete_item" = "Are you sure you want to delete {item_name}?";
|
||||||
|
const auto currentItemName = QString("My Document"); // Type: QString
|
||||||
|
auto currentConfirmation = tr::lng_confirm_delete_item( // Type: QString
|
||||||
|
tr::now, // Pass tr::now for immediate value
|
||||||
|
lt_item_name, currentItemName); // Placeholder value is a direct QString (or convertible)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Placeholders (`{tag}`)
|
||||||
|
|
||||||
|
Placeholders like `{item_name}` are replaced by providing arguments after `tr::now` (for immediate) or as the initial arguments (for reactive). A corresponding `lt_tag_name` constant is passed before the value.
|
||||||
|
|
||||||
|
* **Immediate:** Pass the direct value (e.g., `QString`, `int`).
|
||||||
|
* **Reactive:** Pass an `rpl::producer` of the corresponding type (e.g., `rpl::producer<QString>`). Remember to `std::move` the producer or use `rpl::duplicate` if you need to reuse the original producer afterwards.
|
||||||
|
|
||||||
|
### 4. Pluralization (`{count}`)
|
||||||
|
|
||||||
|
Keys using `{count}` require a numeric value for the `lt_count` placeholder. The correct plural form (`#zero`, `#one`, ..., `#other`) is automatically selected based on this value and the current language rules.
|
||||||
|
|
||||||
|
* **Immediate (`tr::now`):** Pass a `float64` or `int` (which is auto-converted to `float64`).
|
||||||
|
```cpp
|
||||||
|
int count = 1;
|
||||||
|
auto filesText = tr::lng_files_selected(tr::now, lt_count, count); // Type: QString
|
||||||
|
count = 5;
|
||||||
|
filesText = tr::lng_files_selected(tr::now, lt_count, count); // Uses "files_selected#other"
|
||||||
|
```
|
||||||
|
|
||||||
|
* **Reactive:** Pass an `rpl::producer<float64>`. Use the `tr::to_count()` helper to convert an `rpl::producer<int>` or wrap a single value.
|
||||||
|
```cpp
|
||||||
|
// From an existing int producer:
|
||||||
|
auto countProducer = /* ... */; // Type: rpl::producer<int>
|
||||||
|
auto filesTextProducer = tr::lng_files_selected( // Type: rpl::producer<QString>
|
||||||
|
lt_count,
|
||||||
|
countProducer | tr::to_count()); // Use tr::to_count() for conversion
|
||||||
|
|
||||||
|
// From a single int value wrapped reactively:
|
||||||
|
int currentCount = 5;
|
||||||
|
auto filesTextProducerSingle = tr::lng_files_selected( // Type: rpl::producer<QString>
|
||||||
|
lt_count,
|
||||||
|
rpl::single(currentCount) | tr::to_count());
|
||||||
|
// Alternative for single values (less common): rpl::single(currentCount * 1.)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Custom Projectors
|
||||||
|
|
||||||
|
An optional final argument can be a projector function (like `Ui::Text::Upper` or `Ui::Text::WithEntities`) to transform the output.
|
||||||
|
|
||||||
|
* If the projector returns `OutputType`, the string function returns `OutputType` (immediate) or `rpl::producer<OutputType>` (reactive).
|
||||||
|
* Placeholder values must match the projector's *input* requirements. For `Ui::Text::WithEntities`, placeholders expect `TextWithEntities` (immediate) or `rpl::producer<TextWithEntities>` (reactive).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Immediate with Ui::Text::WithEntities projector
|
||||||
|
// Key: "user_posted_photo" = "{user} posted a photo";
|
||||||
|
const auto userName = TextWithEntities{ /* ... */ }; // Type: TextWithEntities
|
||||||
|
auto message = tr::lng_user_posted_photo( // Type: TextWithEntities
|
||||||
|
tr::now,
|
||||||
|
lt_user,
|
||||||
|
userName, // Must be TextWithEntities
|
||||||
|
Ui::Text::WithEntities); // Projector
|
||||||
|
|
||||||
|
// Reactive with Ui::Text::WithEntities projector
|
||||||
|
auto userNameProducer = /* ... */; // Type: rpl::producer<TextWithEntities>
|
||||||
|
auto messageProducer = tr::lng_user_posted_photo( // Type: rpl::producer<TextWithEntities>
|
||||||
|
lt_user,
|
||||||
|
std::move(userNameProducer), // Move placeholder producers
|
||||||
|
Ui::Text::WithEntities); // Projector
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Summary
|
||||||
|
|
||||||
|
* Keys are defined in `Resources/langs/lang.strings` using `{tag}` placeholders.
|
||||||
|
* Plural keys use `{count}` and have `#one`/`#other` variants in `lang.strings`.
|
||||||
|
* Access keys via `tr::lng_key_name(...)` in C++.
|
||||||
|
* Call with `tr::now` as the first argument for the immediate `QString` (or projected type).
|
||||||
|
* Call without `tr::now` for the reactive `rpl::producer<QString>` (or projected type).
|
||||||
|
* Provide placeholder values (`lt_tag_name, value`) matching the usage (direct value for immediate, `rpl::producer` for reactive). Producers should typically be moved via `std::move`.
|
||||||
|
* For `{count}`:
|
||||||
|
* Immediate: Pass `int` or `float64`.
|
||||||
|
* Reactive: Pass `rpl::producer<float64>`, typically by converting an `int` producer using `| tr::to_count()`.
|
||||||
|
* Optional projector function as the last argument modifies the output type and required placeholder types.
|
||||||
|
* Actual translations are loaded at runtime from the API.
|
216
.cursor/rules/rpl_guide.mdc
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
---
|
||||||
|
description:
|
||||||
|
globs:
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
# RPL (Reactive Programming Library) Guide
|
||||||
|
|
||||||
|
## Coding Style Note
|
||||||
|
|
||||||
|
**Use `auto`:** In the actual codebase, variable types are almost always deduced using `auto` (or `const auto`, `const auto &`) rather than being written out explicitly. Examples in this guide may use explicit types for clarity, but prefer `auto` in practice.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Prefer this:
|
||||||
|
auto intProducer = rpl::single(123);
|
||||||
|
const auto &lifetime = existingLifetime;
|
||||||
|
|
||||||
|
// Instead of this:
|
||||||
|
rpl::producer<int> intProducer = rpl::single(123);
|
||||||
|
const rpl::lifetime &lifetime = existingLifetime;
|
||||||
|
|
||||||
|
// Sometimes needed if deduction is ambiguous or needs help:
|
||||||
|
auto user = std::make_shared<UserData>();
|
||||||
|
auto data = QByteArray::fromHex("...");
|
||||||
|
```
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
RPL is the reactive programming library used in this project, residing in the `rpl::` namespace. It allows handling asynchronous streams of data over time.
|
||||||
|
|
||||||
|
The core concept is the `rpl::producer`, which represents a stream of values that can be generated over a certain lifetime.
|
||||||
|
|
||||||
|
## Producers: `rpl::producer<Type, Error = no_error>`
|
||||||
|
|
||||||
|
The fundamental building block is `rpl::producer<Type, Error>`. It produces values of `Type` and can optionally signal an error of type `Error`. By default, `Error` is `rpl::no_error`, indicating that the producer does not explicitly handle error signaling through this mechanism.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// A producer that emits integers.
|
||||||
|
auto intProducer = /* ... */; // Type: rpl::producer<int>
|
||||||
|
|
||||||
|
// A producer that emits strings and can potentially emit a CustomError.
|
||||||
|
auto stringProducerWithError = /* ... */; // Type: rpl::producer<QString, CustomError>
|
||||||
|
```
|
||||||
|
|
||||||
|
Producers are typically lazy; they don't start emitting values until someone subscribes to them.
|
||||||
|
|
||||||
|
## Lifetime Management: `rpl::lifetime`
|
||||||
|
|
||||||
|
Reactive pipelines have a limited duration, managed by `rpl::lifetime`. An `rpl::lifetime` object essentially holds a collection of cleanup callbacks. When the lifetime ends (either explicitly destroyed or goes out of scope), these callbacks are executed, tearing down the associated pipeline and freeing resources.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
rpl::lifetime myLifetime;
|
||||||
|
// ... later ...
|
||||||
|
// myLifetime is destroyed, cleanup happens.
|
||||||
|
|
||||||
|
// Or, pass a lifetime instance to manage a pipeline's duration.
|
||||||
|
rpl::lifetime &parentLifetime = /* ... get lifetime from context ... */;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Starting a Pipeline: `rpl::start_...`
|
||||||
|
|
||||||
|
To consume values from a producer, you start a pipeline using one of the `rpl::start_...` methods. These methods subscribe to the producer and execute callbacks for the events they handle.
|
||||||
|
|
||||||
|
The most common method is `rpl::start_with_next`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto counter = /* ... */; // Type: rpl::producer<int>
|
||||||
|
rpl::lifetime lifetime;
|
||||||
|
|
||||||
|
// Counter is consumed here, use std::move if it's an l-value.
|
||||||
|
std::move(
|
||||||
|
counter
|
||||||
|
) | rpl::start_with_next([=]\(int nextValue) {
|
||||||
|
// Process the next integer value emitted by the producer.
|
||||||
|
qDebug() << "Received: " << nextValue;
|
||||||
|
}, lifetime); // Pass the lifetime to manage the subscription.
|
||||||
|
// Note: `counter` is now in a moved-from state and likely invalid.
|
||||||
|
|
||||||
|
// If you need to start the same producer multiple times, duplicate it:
|
||||||
|
// rpl::duplicate(counter) | rpl::start_with_next(...);
|
||||||
|
|
||||||
|
// If you DON'T pass a lifetime to a start_... method:
|
||||||
|
auto counter2 = /* ... */; // Type: rpl::producer<int>
|
||||||
|
rpl::lifetime subscriptionLifetime = std::move(
|
||||||
|
counter2
|
||||||
|
) | rpl::start_with_next([=]\(int nextValue) { /* ... */ });
|
||||||
|
// The returned lifetime MUST be stored. If it's discarded immediately,
|
||||||
|
// the subscription stops instantly.
|
||||||
|
// `counter2` is also moved-from here.
|
||||||
|
```
|
||||||
|
|
||||||
|
Other variants allow handling errors (`_error`) and completion (`_done`):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto dataStream = /* ... */; // Type: rpl::producer<QString, Error>
|
||||||
|
rpl::lifetime lifetime;
|
||||||
|
|
||||||
|
// Assuming dataStream might be used again, we duplicate it for the first start.
|
||||||
|
// If it's the only use, std::move(dataStream) would be preferred.
|
||||||
|
rpl::duplicate(
|
||||||
|
dataStream
|
||||||
|
) | rpl::start_with_error([=]\(Error &&error) {
|
||||||
|
// Handle the error signaled by the producer.
|
||||||
|
qDebug() << "Error: " << error.text();
|
||||||
|
}, lifetime);
|
||||||
|
|
||||||
|
// Using dataStream again, perhaps duplicated again or moved if last use.
|
||||||
|
rpl::duplicate(
|
||||||
|
dataStream
|
||||||
|
) | rpl::start_with_done([=] {
|
||||||
|
// Execute when the producer signals it's finished emitting values.
|
||||||
|
qDebug() << "Stream finished.";
|
||||||
|
}, lifetime);
|
||||||
|
|
||||||
|
// Last use of dataStream, so we move it.
|
||||||
|
std::move(
|
||||||
|
dataStream
|
||||||
|
) | rpl::start_with_next_error_done(
|
||||||
|
[=]\(QString &&value) { /* handle next value */ },
|
||||||
|
[=]\(Error &&error) { /* handle error */ },
|
||||||
|
[=] { /* handle done */ },
|
||||||
|
lifetime);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Transforming Producers
|
||||||
|
|
||||||
|
RPL provides functions to create new producers by transforming existing ones:
|
||||||
|
|
||||||
|
* `rpl::map`: Transforms each value emitted by a producer.
|
||||||
|
```cpp
|
||||||
|
auto ints = /* ... */; // Type: rpl::producer<int>
|
||||||
|
// The pipe operator often handles the move implicitly for chained transformations.
|
||||||
|
auto strings = std::move(
|
||||||
|
ints // Explicit move is safer
|
||||||
|
) | rpl::map([](int value) {
|
||||||
|
return QString::number(value * 2);
|
||||||
|
}); // Emits strings like "0", "2", "4", ...
|
||||||
|
```
|
||||||
|
|
||||||
|
* `rpl::filter`: Emits only the values from a producer that satisfy a condition.
|
||||||
|
```cpp
|
||||||
|
auto ints = /* ... */; // Type: rpl::producer<int>
|
||||||
|
auto evenInts = std::move(
|
||||||
|
ints // Explicit move is safer
|
||||||
|
) | rpl::filter([](int value) {
|
||||||
|
return (value % 2 == 0);
|
||||||
|
}); // Emits only even numbers.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Combining Producers
|
||||||
|
|
||||||
|
You can combine multiple producers into one:
|
||||||
|
|
||||||
|
* `rpl::combine`: Combines the latest values from multiple producers whenever *any* of them emits a new value. Requires all producers to have emitted at least one value initially.
|
||||||
|
While it produces a `std::tuple`, subsequent operators like `map`, `filter`, and `start_with_next` can automatically unpack this tuple into separate lambda arguments.
|
||||||
|
```cpp
|
||||||
|
auto countProducer = rpl::single(1); // Type: rpl::producer<int>
|
||||||
|
auto textProducer = rpl::single(u"hello"_q); // Type: rpl::producer<QString>
|
||||||
|
rpl::lifetime lifetime;
|
||||||
|
|
||||||
|
// rpl::combine takes producers by const-ref internally and duplicates,
|
||||||
|
// so move/duplicate is usually not strictly needed here unless you
|
||||||
|
// want to signal intent or manage the lifetime of p1/p2 explicitly.
|
||||||
|
auto combined = rpl::combine(
|
||||||
|
countProducer, // or rpl::duplicate(countProducer)
|
||||||
|
textProducer // or rpl::duplicate(textProducer)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Starting the combined producer consumes it.
|
||||||
|
// The lambda receives unpacked arguments, not the tuple itself.
|
||||||
|
std::move(
|
||||||
|
combined
|
||||||
|
) | rpl::start_with_next([=]\(int count, const QString &text) {
|
||||||
|
// No need for std::get<0>(latest), etc.
|
||||||
|
qDebug() << "Combined: Count=" << count << ", Text=" << text;
|
||||||
|
}, lifetime);
|
||||||
|
|
||||||
|
// This also works with map, filter, etc.
|
||||||
|
std::move(
|
||||||
|
combined
|
||||||
|
) | rpl::filter([=]\(int count, const QString &text) {
|
||||||
|
return count > 0 && !text.isEmpty();
|
||||||
|
}) | rpl::map([=]\(int count, const QString &text) {
|
||||||
|
return text.repeated(count);
|
||||||
|
}) | rpl::start_with_next([=]\(const QString &result) {
|
||||||
|
qDebug() << "Mapped & Filtered: " << result;
|
||||||
|
}, lifetime);
|
||||||
|
```
|
||||||
|
|
||||||
|
* `rpl::merge`: Merges the output of multiple producers of the *same type* into a single producer. It emits a value whenever *any* of the source producers emits a value.
|
||||||
|
```cpp
|
||||||
|
auto sourceA = /* ... */; // Type: rpl::producer<QString>
|
||||||
|
auto sourceB = /* ... */; // Type: rpl::producer<QString>
|
||||||
|
|
||||||
|
// rpl::merge also duplicates internally.
|
||||||
|
auto merged = rpl::merge(sourceA, sourceB);
|
||||||
|
|
||||||
|
// Starting the merged producer consumes it.
|
||||||
|
std::move(
|
||||||
|
merged
|
||||||
|
) | rpl::start_with_next([=]\(QString &&value) {
|
||||||
|
// Receives values from either sourceA or sourceB as they arrive.
|
||||||
|
qDebug() << "Merged value: " << value;
|
||||||
|
}, lifetime);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Concepts Summary
|
||||||
|
|
||||||
|
* Use `rpl::producer<Type, Error>` to represent streams of values.
|
||||||
|
* Manage subscription duration using `rpl::lifetime`.
|
||||||
|
* Pass `rpl::lifetime` to `rpl::start_...` methods.
|
||||||
|
* If `rpl::lifetime` is not passed, **store the returned lifetime** to keep the subscription active.
|
||||||
|
* Use operators like `| rpl::map`, `| rpl::filter` to transform streams.
|
||||||
|
* Use `rpl::combine` or `rpl::merge` to combine streams.
|
||||||
|
* When starting a chain (`std::move(producer) | rpl::map(...)`), explicitly move the initial producer.
|
||||||
|
* These functions typically duplicate their input producers internally.
|
||||||
|
* Starting a pipeline consumes the producer; use `
|
154
.cursor/rules/styling.mdc
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
---
|
||||||
|
description: For tasks requiring working with user facing UI components.
|
||||||
|
globs:
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
# Telegram Desktop UI Styling
|
||||||
|
|
||||||
|
## Style Definition Files
|
||||||
|
|
||||||
|
UI element styles (colors, fonts, paddings, margins, icons, etc.) are defined in `.style` files using a custom syntax. These files are located alongside the C++ source files they correspond to within specific UI component directories (e.g., `Telegram/SourceFiles/ui/chat/chat.style`).
|
||||||
|
|
||||||
|
Definitions from other `.style` files can be included using the `using` directive at the top of the file:
|
||||||
|
```style
|
||||||
|
using "ui/basic.style";
|
||||||
|
using "ui/widgets/widgets.style";
|
||||||
|
```
|
||||||
|
|
||||||
|
The central definition of named colors happens in `Telegram/SourceFiles/ui/colors.palette`. This file allows for theme generation and loading colors from various sources.
|
||||||
|
|
||||||
|
### Syntax Overview
|
||||||
|
|
||||||
|
1. **Built-in Types:** The syntax recognizes several base types inferred from the value assigned:
|
||||||
|
* `int`: Integer numbers (e.g., `lineHeight: 20;`)
|
||||||
|
* `bool`: Boolean values (e.g., `useShadow: true;`)
|
||||||
|
* `pixels`: Pixel values, ending with `px` (e.g., `borderWidth: 1px;`). Generated as `int` in C++.
|
||||||
|
* `color`: Named colors defined in `colors.palette` (e.g., `background: windowBg;`)
|
||||||
|
* `icon`: Defined inline using a specific syntax (see below). Generates `style::icon`.
|
||||||
|
* `margins`: Four pixel values for margins or padding. Requires `margins(top, right, bottom, left)` syntax (e.g., `margin: margins(10px, 5px, 10px, 5px);` or `padding: margins(8px, 8px, 8px, 8px);`). Generates `style::margins` (an alias for `QMargins`).
|
||||||
|
* `size`: Two pixel values for width and height (e.g., `iconSize: size(16px, 16px);`). Generates `style::size`.
|
||||||
|
* `point`: Two pixel values for x and y coordinates (e.g., `textPos: point(5px, 2px);`). Generates `style::point`.
|
||||||
|
* `align`: Alignment keywords (e.g., `textAlign: align(center);` or `iconAlign: align(left);`). Generates `style::align`.
|
||||||
|
* `font`: Font definitions (e.g., `font: font(14px semibold);`). Generates `style::font`.
|
||||||
|
* `double`: Floating point numbers (e.g., `disabledOpacity: 0.5;`)
|
||||||
|
|
||||||
|
*Note on Borders:* Borders are typically defined using multiple fields like `border: pixels;` (for width) and `borderFg: color;` (for color), rather than a single CSS-like property.
|
||||||
|
|
||||||
|
2. **Structure Definition:** You can define complex data structures directly within the `.style` file:
|
||||||
|
```style
|
||||||
|
MyButtonStyle { // Defines a structure named 'MyButtonStyle'
|
||||||
|
textPadding: margins; // Field 'textPadding' expects margins type
|
||||||
|
icon: icon; // Field 'icon' of type icon
|
||||||
|
height: pixels; // Field 'height' of type pixels
|
||||||
|
}
|
||||||
|
```
|
||||||
|
This generates a `struct MyButtonStyle { ... };` inside the `namespace style`. Fields will have corresponding C++ types (`style::margins`, `style::icon`, `int`).
|
||||||
|
|
||||||
|
3. **Variable Definition & Inheritance:** Variables are defined using `name: value;` or `groupName { ... }`. They can be of built-in types or custom structures. Structures can be initialized inline or inherit from existing variables.
|
||||||
|
|
||||||
|
**Icon Definition Syntax:** Icons are defined inline using the `icon{...}` syntax. The generator probes for `.svg` files or `.png` files (including `@2x`, `@3x` variants) based on the provided path stem.
|
||||||
|
```style
|
||||||
|
// Single-part icon definition:
|
||||||
|
myIconSearch: icon{{ "gui/icons/search", iconColor }};
|
||||||
|
// Multi-part icon definition (layers drawn bottom-up):
|
||||||
|
myComplexIcon: icon{
|
||||||
|
{ "gui/icons/background", iconBgColor },
|
||||||
|
{ "gui/icons/foreground", iconFgColor }
|
||||||
|
};
|
||||||
|
// Icon with path modifiers (PNG only for flips, SVG only for size):
|
||||||
|
myFlippedIcon: icon{{ "gui/icons/arrow-flip_horizontal", arrowColor }};
|
||||||
|
myResizedIcon: icon{{ "gui/icons/logo-128x128", logoColor }}; // Forces 128x128 for SVG
|
||||||
|
```
|
||||||
|
|
||||||
|
**Other Variable Examples:**
|
||||||
|
```style
|
||||||
|
// Simple variables
|
||||||
|
buttonHeight: 30px;
|
||||||
|
activeButtonColor: buttonBgActive; // Named color from colors.palette
|
||||||
|
|
||||||
|
// Variable of a custom structure type, initialized inline
|
||||||
|
defaultButton: MyButtonStyle {
|
||||||
|
textPadding: margins(10px, 15px, 10px, 15px); // Use margins(...) syntax
|
||||||
|
icon: myIconSearch; // Assign the previously defined icon variable
|
||||||
|
height: buttonHeight; // Reference another variable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Another variable inheriting from 'defaultButton' and overriding/adding fields
|
||||||
|
primaryButton: MyButtonStyle(defaultButton) {
|
||||||
|
icon: myComplexIcon; // Override icon with the multi-part one
|
||||||
|
backgroundColor: activeButtonColor; // Add a field not in MyButtonStyle definition
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style group (often used for specific UI elements)
|
||||||
|
chatInput { // Example using separate border properties and explicit padding
|
||||||
|
border: 1px; // Border width
|
||||||
|
borderFg: defaultInputFieldBorder; // Border color (named color)
|
||||||
|
padding: margins(5px, 10px, 5px, 10px); // Use margins(...) syntax for padding field
|
||||||
|
backgroundColor: defaultChatBg; // Background color
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Generation
|
||||||
|
|
||||||
|
A code generation tool processes these `.style` files and `colors.palette` to create C++ objects.
|
||||||
|
- The `using` directives resolve dependencies between `.style` files.
|
||||||
|
- Custom structure definitions (like `MyButtonStyle`) generate corresponding `struct MyButtonStyle { ... };` within the `namespace style`.
|
||||||
|
- Style variables/groups (like `defaultButton`, `primaryButton`, `chatInput`) are generated as objects/structs within the `st` namespace (e.g., `st::defaultButton`, `st::primaryButton`, `st::chatInput`). These generated structs contain members corresponding to the fields defined in the `.style` file.
|
||||||
|
- Color objects are generated into the `st` namespace as well, based on their names in `colors.palette` (e.g., `st::windowBg`, `st::buttonBgActive`).
|
||||||
|
- The generated header files for styles are placed in the `Telegram/SourceFiles/styles/` directory with a `style_` prefix (e.g., `styles/style_widgets.h` for `ui/widgets/widgets.style`). You include them like `#include "styles/style_widgets.h"`.
|
||||||
|
|
||||||
|
Generated C++ types correspond to the `.style` types: `style::color`, `style::font`, `style::margins` (used for both `margin:` and `padding:` fields), `style::icon`, `style::size`, `style::point`, `style::align`, and `int` or `bool` for simple types.
|
||||||
|
|
||||||
|
## Style Usage in Code
|
||||||
|
|
||||||
|
Styles are applied in C++ code by referencing the generated `st::...` objects and their members.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Example: Including the generated style header
|
||||||
|
#include "styles/style_widgets.h" // For styles defined in ui/widgets/widgets.style
|
||||||
|
|
||||||
|
// ... inside some UI class code ...
|
||||||
|
|
||||||
|
// Accessing members of a generated style struct
|
||||||
|
int height = st::primaryButton.height; // Accessing the 'height' field (pixels -> int)
|
||||||
|
const style::icon &icon = st::primaryButton.icon; // Accessing the 'icon' field (st::myComplexIcon)
|
||||||
|
style::margins padding = st::primaryButton.textPadding; // Accessing 'textPadding'
|
||||||
|
style::color bgColor = st::primaryButton.backgroundColor; // Accessing the color (st::activeButtonColor)
|
||||||
|
|
||||||
|
// Applying styles (conceptual examples)
|
||||||
|
myButton->setIcon(st::primaryButton.icon);
|
||||||
|
myButton->setHeight(st::primaryButton.height);
|
||||||
|
myButton->setPadding(st::primaryButton.textPadding);
|
||||||
|
myButton->setBackgroundColor(st::primaryButton.backgroundColor);
|
||||||
|
|
||||||
|
// Using styles directly in painting
|
||||||
|
void MyWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
p.fillRect(rect(), st::chatInput.backgroundColor); // Use color from chatInput style
|
||||||
|
|
||||||
|
// Border painting requires width and color
|
||||||
|
int borderWidth = st::chatInput.border; // Access border width (pixels -> int)
|
||||||
|
style::color borderColor = st::chatInput.borderFg; // Access border color
|
||||||
|
if (borderWidth > 0) {
|
||||||
|
p.setPen(QPen(borderColor, borderWidth));
|
||||||
|
// Adjust rect for pen width if needed before drawing
|
||||||
|
p.drawRect(rect().adjusted(borderWidth / 2, borderWidth / 2, -borderWidth / 2, -borderWidth / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access padding (style::margins)
|
||||||
|
style::margins inputPadding = st::chatInput.padding;
|
||||||
|
// ... use inputPadding.top(), inputPadding.left() etc. for content layout ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Points:**
|
||||||
|
|
||||||
|
* Styles are defined in `.style` files next to their corresponding C++ source files.
|
||||||
|
* `using "path/to/other.style";` includes definitions from other style files.
|
||||||
|
* Named colors are defined centrally in `ui/colors.palette`.
|
||||||
|
* `.style` syntax supports built-in types (like `pixels`, `color`, `margins`, `point`, `size`, `align`, `font`, `double`), custom structure definitions (`Name { field: type; ... }`), variable definitions (`name: value;`), and inheritance (`child: Name(parent) { ... }`).
|
||||||
|
* Values must match the expected type (e.g., fields declared as `margins` type, like `margin:` or `padding:`, require `margins(...)` syntax). Borders are typically set via separate `border: pixels;` and `borderFg: color;` fields.
|
||||||
|
* Icons are defined inline using `name: icon{{ "path_stem", color }};` or `name: icon{ { "path1", c1 }, ... };` syntax, with optional path modifiers.
|
||||||
|
* Code generation creates `struct` definitions in the `style` namespace for custom types and objects/structs in the `st` namespace for defined variables/groups.
|
||||||
|
* Generated headers are in `styles/` with a `style_` prefix and must be included.
|
||||||
|
* Access style properties via the generated `st::` objects (e.g., `st::primaryButton.height`, `st::chatInput.backgroundColor`).
|
2
.cursorignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)
|
||||||
|
Telegram/ThirdParty/
|
|
@ -5,14 +5,9 @@
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"settings": {
|
"settings": {
|
||||||
"C_Cpp.intelliSenseEngine": "disabled",
|
"C_Cpp.intelliSenseEngine": "disabled",
|
||||||
"clangd.arguments": [
|
|
||||||
"--compile-commands-dir=${workspaceFolder}/out"
|
|
||||||
],
|
|
||||||
"cmake.generator": "Ninja Multi-Config",
|
"cmake.generator": "Ninja Multi-Config",
|
||||||
"cmake.buildDirectory": "${workspaceFolder}/out",
|
"cmake.buildDirectory": "${workspaceFolder}/out",
|
||||||
"cmake.configureSettings": {
|
"cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json"
|
||||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ms-vscode.cpptools-extension-pack",
|
"ms-vscode.cpptools-extension-pack",
|
||||||
|
|
19
.github/ISSUE_TEMPLATE/BUG_REPORT.yml
vendored
|
@ -5,7 +5,7 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thanks for reporting issues of Telegram Desktop!
|
Thanks for reporting issues of AyuGram Desktop!
|
||||||
|
|
||||||
To make it easier for us to help you please enter detailed information below.
|
To make it easier for us to help you please enter detailed information below.
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
@ -39,12 +39,9 @@ body:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Version of Telegram Desktop
|
label: Version of AyuGram Desktop
|
||||||
description: >
|
description: >
|
||||||
Please note we don't support versions from Linux distro repositories.
|
**Don't use 'latest'**, specify actual version.
|
||||||
If you need support for these versions, **please contact your distro maintainer**
|
|
||||||
or your distro bugtracker.
|
|
||||||
**Don't use 'latest'**, specify actual version, **that's a reason to close your issue**.
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
@ -52,11 +49,7 @@ body:
|
||||||
label: Installation source
|
label: Installation source
|
||||||
multiple: false
|
multiple: false
|
||||||
options:
|
options:
|
||||||
- Static binary from official website
|
- Binary from GitHub / official Telegram source
|
||||||
- Microsoft Store
|
|
||||||
- Mac App Store
|
|
||||||
- Flatpak
|
|
||||||
- Snap
|
|
||||||
- Other (unofficial) source
|
- Other (unofficial) source
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
@ -65,9 +58,7 @@ body:
|
||||||
label: Crash ID
|
label: Crash ID
|
||||||
description: >
|
description: >
|
||||||
If you're reporting a crash, please enter the crash ID from the crash reporter
|
If you're reporting a crash, please enter the crash ID from the crash reporter
|
||||||
opening on the next launch after crash. **You have to enable beta versions
|
opening on the next launch after crash.
|
||||||
installation in Settings -> Advanced for the reporter to appear.**
|
|
||||||
You don't have to wait for a beta version to arrive.
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Logs
|
label: Logs
|
||||||
|
|
125
.github/workflows/linux.yml
vendored
|
@ -1,125 +0,0 @@
|
||||||
name: Linux.
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths-ignore:
|
|
||||||
- 'docs/**'
|
|
||||||
- '**.md'
|
|
||||||
- 'changelog.txt'
|
|
||||||
- 'LEGAL'
|
|
||||||
- 'LICENSE'
|
|
||||||
- '.github/**'
|
|
||||||
- '!.github/workflows/linux.yml'
|
|
||||||
- 'snap/**'
|
|
||||||
- 'Telegram/build/**'
|
|
||||||
- 'Telegram/Resources/uwp/**'
|
|
||||||
- 'Telegram/Resources/winrc/**'
|
|
||||||
- 'Telegram/SourceFiles/platform/win/**'
|
|
||||||
- 'Telegram/SourceFiles/platform/mac/**'
|
|
||||||
- 'Telegram/Telegram/**'
|
|
||||||
- 'Telegram/configure.bat'
|
|
||||||
- 'Telegram/Telegram.plist'
|
|
||||||
pull_request:
|
|
||||||
paths-ignore:
|
|
||||||
- 'docs/**'
|
|
||||||
- '**.md'
|
|
||||||
- 'changelog.txt'
|
|
||||||
- 'LEGAL'
|
|
||||||
- 'LICENSE'
|
|
||||||
- '.github/**'
|
|
||||||
- '!.github/workflows/linux.yml'
|
|
||||||
- 'snap/**'
|
|
||||||
- 'Telegram/build/**'
|
|
||||||
- 'Telegram/Resources/uwp/**'
|
|
||||||
- 'Telegram/Resources/winrc/**'
|
|
||||||
- 'Telegram/SourceFiles/platform/win/**'
|
|
||||||
- 'Telegram/SourceFiles/platform/mac/**'
|
|
||||||
- 'Telegram/Telegram/**'
|
|
||||||
- 'Telegram/configure.bat'
|
|
||||||
- 'Telegram/Telegram.plist'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
linux:
|
|
||||||
name: Rocky Linux 8
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
defines:
|
|
||||||
- ""
|
|
||||||
- "DESKTOP_APP_DISABLE_X11_INTEGRATION"
|
|
||||||
|
|
||||||
env:
|
|
||||||
UPLOAD_ARTIFACT: "true"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Get repository name.
|
|
||||||
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Clone.
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
path: ${{ env.REPO_NAME }}
|
|
||||||
|
|
||||||
- name: First set up.
|
|
||||||
run: |
|
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
|
|
||||||
docker pull ghcr.io/$GITHUB_REPOSITORY/centos_env
|
|
||||||
docker tag ghcr.io/$GITHUB_REPOSITORY/centos_env tdesktop:centos_env
|
|
||||||
|
|
||||||
- name: Telegram Desktop build.
|
|
||||||
run: |
|
|
||||||
cd $REPO_NAME
|
|
||||||
|
|
||||||
DEFINE=""
|
|
||||||
if [ -n "${{ matrix.defines }}" ]; then
|
|
||||||
DEFINE="-D ${{ matrix.defines }}=ON"
|
|
||||||
echo Define from matrix: $DEFINE
|
|
||||||
echo "ARTIFACT_NAME=Telegram_${{ matrix.defines }}" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "ARTIFACT_NAME=Telegram" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker run --rm \
|
|
||||||
-u $(id -u) \
|
|
||||||
-v $PWD:/usr/src/tdesktop \
|
|
||||||
-e CONFIG=Debug \
|
|
||||||
tdesktop:centos_env \
|
|
||||||
/usr/src/tdesktop/Telegram/build/docker/centos_env/build.sh \
|
|
||||||
-D CMAKE_C_FLAGS_DEBUG="" \
|
|
||||||
-D CMAKE_CXX_FLAGS_DEBUG="" \
|
|
||||||
-D CMAKE_C_FLAGS="-Werror" \
|
|
||||||
-D CMAKE_CXX_FLAGS="-Werror" \
|
|
||||||
-D CMAKE_EXE_LINKER_FLAGS="-s" \
|
|
||||||
-D TDESKTOP_API_TEST=ON \
|
|
||||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF \
|
|
||||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF \
|
|
||||||
$DEFINE
|
|
||||||
|
|
||||||
- name: Check.
|
|
||||||
run: |
|
|
||||||
filePath="$REPO_NAME/out/Debug/Telegram"
|
|
||||||
if test -f "$filePath"; then
|
|
||||||
echo "Build successfully done! :)"
|
|
||||||
|
|
||||||
size=$(stat -c %s "$filePath")
|
|
||||||
echo "File size of ${filePath}: ${size} Bytes."
|
|
||||||
else
|
|
||||||
echo "Build error, output file does not exist."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Move artifact.
|
|
||||||
if: env.UPLOAD_ARTIFACT == 'true'
|
|
||||||
run: |
|
|
||||||
cd $REPO_NAME/out/Debug
|
|
||||||
mkdir artifact
|
|
||||||
mv {Telegram,Updater} artifact/
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
if: env.UPLOAD_ARTIFACT == 'true'
|
|
||||||
name: Upload artifact.
|
|
||||||
with:
|
|
||||||
name: ${{ env.ARTIFACT_NAME }}
|
|
||||||
path: ${{ env.REPO_NAME }}/out/Debug/artifact/
|
|
201
.github/workflows/win.yml
vendored
|
@ -1,201 +0,0 @@
|
||||||
name: Windows.
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths-ignore:
|
|
||||||
- 'docs/**'
|
|
||||||
- '**.md'
|
|
||||||
- 'changelog.txt'
|
|
||||||
- 'LEGAL'
|
|
||||||
- 'LICENSE'
|
|
||||||
- '.github/**'
|
|
||||||
- '!.github/workflows/win.yml'
|
|
||||||
- 'lib/xdg/**'
|
|
||||||
- 'snap/**'
|
|
||||||
- 'Telegram/build/docker/**'
|
|
||||||
- 'Telegram/Resources/uwp/**'
|
|
||||||
- 'Telegram/SourceFiles/platform/linux/**'
|
|
||||||
- 'Telegram/SourceFiles/platform/mac/**'
|
|
||||||
- 'Telegram/Telegram/**'
|
|
||||||
- 'Telegram/configure.sh'
|
|
||||||
- 'Telegram/Telegram.plist'
|
|
||||||
pull_request:
|
|
||||||
paths-ignore:
|
|
||||||
- 'docs/**'
|
|
||||||
- '**.md'
|
|
||||||
- 'changelog.txt'
|
|
||||||
- 'LEGAL'
|
|
||||||
- 'LICENSE'
|
|
||||||
- '.github/**'
|
|
||||||
- '!.github/workflows/win.yml'
|
|
||||||
- 'lib/xdg/**'
|
|
||||||
- 'snap/**'
|
|
||||||
- 'Telegram/build/docker/**'
|
|
||||||
- 'Telegram/Resources/uwp/**'
|
|
||||||
- 'Telegram/SourceFiles/platform/linux/**'
|
|
||||||
- 'Telegram/SourceFiles/platform/mac/**'
|
|
||||||
- 'Telegram/Telegram/**'
|
|
||||||
- 'Telegram/configure.sh'
|
|
||||||
- 'Telegram/Telegram.plist'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
windows:
|
|
||||||
name: Windows
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
arch: [Win32, x64]
|
|
||||||
generator: ["", "Ninja Multi-Config"]
|
|
||||||
|
|
||||||
env:
|
|
||||||
UPLOAD_ARTIFACT: "true"
|
|
||||||
ONLY_CACHE: "false"
|
|
||||||
PREPARE_PATH: "Telegram/build/prepare/prepare.py"
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: cmd
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Prepare directories.
|
|
||||||
run: |
|
|
||||||
mkdir %userprofile%\TBuild\Libraries
|
|
||||||
mklink /d %GITHUB_WORKSPACE%\TBuild %userprofile%\TBuild
|
|
||||||
echo TBUILD=%GITHUB_WORKSPACE%\TBuild>>%GITHUB_ENV%
|
|
||||||
|
|
||||||
- name: Get repository name.
|
|
||||||
shell: bash
|
|
||||||
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- uses: ilammy/msvc-dev-cmd@v1.13.0
|
|
||||||
name: Native Tools Command Prompt.
|
|
||||||
with:
|
|
||||||
arch: ${{ matrix.arch }}
|
|
||||||
|
|
||||||
- name: Clone.
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
path: ${{ env.TBUILD }}\${{ env.REPO_NAME }}
|
|
||||||
|
|
||||||
- name: Set up environment paths.
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "CACHE_KEY=$(sha256sum $TBUILD/$REPO_NAME/$PREPARE_PATH | awk '{ print $1 }')" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
echo "Configurate git for cherry-picks."
|
|
||||||
git config --global user.email "you@example.com"
|
|
||||||
git config --global user.name "Sample"
|
|
||||||
|
|
||||||
- name: NuGet sources.
|
|
||||||
run: |
|
|
||||||
nuget sources Disable -Name "Microsoft Visual Studio Offline Packages"
|
|
||||||
nuget sources Add -Source https://api.nuget.org/v3/index.json & exit 0
|
|
||||||
|
|
||||||
- name: ThirdParty cache.
|
|
||||||
id: cache-third-party
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ${{ env.TBUILD }}\ThirdParty
|
|
||||||
key: ${{ runner.OS }}-${{ matrix.arch }}-third-party-${{ env.CACHE_KEY }}
|
|
||||||
restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-third-party-
|
|
||||||
|
|
||||||
- name: Libraries cache.
|
|
||||||
id: cache-libs
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ${{ env.TBUILD }}\Libraries
|
|
||||||
key: ${{ runner.OS }}-${{ matrix.arch }}-libs-${{ env.CACHE_KEY }}
|
|
||||||
restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-libs-
|
|
||||||
|
|
||||||
- name: Libraries.
|
|
||||||
env:
|
|
||||||
GYP_MSVS_OVERRIDE_PATH: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\'
|
|
||||||
GYP_MSVS_VERSION: 2022
|
|
||||||
run: |
|
|
||||||
cd %TBUILD%
|
|
||||||
%REPO_NAME%\Telegram\build\prepare\win.bat skip-release silent
|
|
||||||
|
|
||||||
- name: Read configuration matrix.
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
ARTIFACT_NAME="Telegram"
|
|
||||||
|
|
||||||
ARCH=""
|
|
||||||
if [ -n "${{ matrix.arch }}" ]; then
|
|
||||||
case "${{ matrix.arch }}" in
|
|
||||||
Win32) ARCH="x86";;
|
|
||||||
*) ARCH="${{ matrix.arch }}";;
|
|
||||||
esac
|
|
||||||
echo "Architecture from matrix: $ARCH"
|
|
||||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.arch }}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
GENERATOR=""
|
|
||||||
if [ -n "${{ matrix.generator }}" ]; then
|
|
||||||
GENERATOR="-G \"${{ matrix.generator }}\""
|
|
||||||
echo "Generator from matrix: $GENERATOR"
|
|
||||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.generator }}"
|
|
||||||
fi
|
|
||||||
echo "TDESKTOP_BUILD_GENERATOR=$GENERATOR" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
[ -n "$GENERATOR" ] && ARCH=""
|
|
||||||
echo "TDESKTOP_BUILD_ARCH=$ARCH" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
DEFINE=""
|
|
||||||
if [ -n "${{ matrix.defines }}" ]; then
|
|
||||||
DEFINE="-D ${{ matrix.defines }}=ON"
|
|
||||||
echo "Define from matrix: $DEFINE"
|
|
||||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.defines }}"
|
|
||||||
fi
|
|
||||||
echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
API="-D TDESKTOP_API_TEST=ON"
|
|
||||||
if [ $GITHUB_REF == 'refs/heads/nightly' ]; then
|
|
||||||
echo "Use the open credentials."
|
|
||||||
API="-D TDESKTOP_API_ID=611335 -D TDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c"
|
|
||||||
fi
|
|
||||||
echo "TDESKTOP_BUILD_API=$API" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Free up some disk space.
|
|
||||||
run: |
|
|
||||||
cd %TBUILD%
|
|
||||||
del /S Libraries\*.pdb
|
|
||||||
del /S Libraries\*.pch
|
|
||||||
del /S Libraries\*.obj
|
|
||||||
|
|
||||||
- name: Telegram Desktop build.
|
|
||||||
if: env.ONLY_CACHE == 'false'
|
|
||||||
run: |
|
|
||||||
cd %TBUILD%\%REPO_NAME%\Telegram
|
|
||||||
|
|
||||||
call configure.bat ^
|
|
||||||
%TDESKTOP_BUILD_GENERATOR% ^
|
|
||||||
%TDESKTOP_BUILD_ARCH% ^
|
|
||||||
%TDESKTOP_BUILD_API% ^
|
|
||||||
-D CMAKE_C_FLAGS="/WX" ^
|
|
||||||
-D CMAKE_CXX_FLAGS="/WX" ^
|
|
||||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF ^
|
|
||||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF ^
|
|
||||||
-D DESKTOP_APP_NO_PDB=ON ^
|
|
||||||
%TDESKTOP_BUILD_DEFINE%
|
|
||||||
|
|
||||||
cmake --build ..\out --config Debug --parallel
|
|
||||||
|
|
||||||
- name: Move artifact.
|
|
||||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
|
||||||
run: |
|
|
||||||
set OUT=%TBUILD%\%REPO_NAME%\out\Debug
|
|
||||||
mkdir artifact
|
|
||||||
move %OUT%\Telegram.exe artifact/
|
|
||||||
move %OUT%\Updater.exe artifact/
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
name: Upload artifact.
|
|
||||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
|
||||||
with:
|
|
||||||
name: ${{ env.ARTIFACT_NAME }}
|
|
||||||
path: artifact\
|
|
1
.gitignore
vendored
|
@ -20,6 +20,7 @@ ipch/
|
||||||
.vs/
|
.vs/
|
||||||
.vscode/
|
.vscode/
|
||||||
.cache/
|
.cache/
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
/Telegram/log.txt
|
/Telegram/log.txt
|
||||||
/Telegram/data
|
/Telegram/data
|
||||||
|
|
|
@ -4,15 +4,7 @@
|
||||||
# For license and copyright information please follow this link:
|
# For license and copyright information please follow this link:
|
||||||
# https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
# https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
if (APPLE)
|
cmake_minimum_required(VERSION 3.25...3.31)
|
||||||
# target_precompile_headers with COMPILE_LANGUAGE restriction.
|
|
||||||
cmake_minimum_required(VERSION 3.23)
|
|
||||||
else()
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
|
||||||
endif()
|
|
||||||
if (POLICY CMP0149)
|
|
||||||
cmake_policy(SET CMP0149 NEW)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
|
|
17
README-RU.md
|
@ -30,10 +30,10 @@
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
#### Официальный вариант
|
#### Официальная версия
|
||||||
|
|
||||||
Вы можете скачать готовый бинарный файл со вкладки [Releases](https://github.com/AyuGram/AyuGramDesktop/releases) или из
|
Вы можете скачать готовый бинарный файл со вкладки [Releases](https://github.com/AyuGram/AyuGramDesktop/releases) или из
|
||||||
[Телеграм чата](https://t.me/ayugramchat/12788).
|
[Телеграм канала](https://t.me/AyuGramReleases).
|
||||||
|
|
||||||
#### Winget
|
#### Winget
|
||||||
|
|
||||||
|
@ -55,8 +55,16 @@ scoop install ayugram
|
||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
|
#### Официальная версия
|
||||||
|
|
||||||
Вы можете скачать подписанный пакет со вкладки [Releases](https://github.com/AyuGram/AyuGramDesktop/releases).
|
Вы можете скачать подписанный пакет со вкладки [Releases](https://github.com/AyuGram/AyuGramDesktop/releases).
|
||||||
|
|
||||||
|
#### Homebrew
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install --cask ayugram
|
||||||
|
```
|
||||||
|
|
||||||
### Arch Linux
|
### Arch Linux
|
||||||
|
|
||||||
Вы можете установить `ayugram-desktop` из [AUR](https://aur.archlinux.org/packages?O=0&K=ayugram).
|
Вы можете установить `ayugram-desktop` из [AUR](https://aur.archlinux.org/packages?O=0&K=ayugram).
|
||||||
|
@ -101,3 +109,8 @@ scoop install ayugram
|
||||||
### Иконки
|
### Иконки
|
||||||
|
|
||||||
- [Solar Icon Set](https://www.figma.com/community/file/1166831539721848736)
|
- [Solar Icon Set](https://www.figma.com/community/file/1166831539721848736)
|
||||||
|
|
||||||
|
### Боты
|
||||||
|
|
||||||
|
- [TelegramDB](https://t.me/tgdatabase) для получения юзернейма по ID (до закрытия бесплатной версии 25 мая 2025)
|
||||||
|
- [usinfobot](https://t.me/usinfobot) для получения юзернейма по ID
|
||||||
|
|
15
README.md
|
@ -34,7 +34,7 @@ And many more. Check out our [Documentation](https://docs.ayugram.one/desktop/).
|
||||||
#### Official
|
#### Official
|
||||||
|
|
||||||
You can download prebuilt Windows binary from [Releases tab](https://github.com/AyuGram/AyuGramDesktop/releases) or from
|
You can download prebuilt Windows binary from [Releases tab](https://github.com/AyuGram/AyuGramDesktop/releases) or from
|
||||||
the [Telegram topic](https://t.me/ayugramchat/12788).
|
the [Telegram channel](https://t.me/AyuGramReleases).
|
||||||
|
|
||||||
#### Winget
|
#### Winget
|
||||||
|
|
||||||
|
@ -56,8 +56,16 @@ build by yourself.
|
||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
|
#### Official
|
||||||
|
|
||||||
You can download prebuilt macOS package from [Releases tab](https://github.com/AyuGram/AyuGramDesktop/releases).
|
You can download prebuilt macOS package from [Releases tab](https://github.com/AyuGram/AyuGramDesktop/releases).
|
||||||
|
|
||||||
|
#### Homebrew
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install --cask ayugram
|
||||||
|
```
|
||||||
|
|
||||||
### Arch Linux
|
### Arch Linux
|
||||||
|
|
||||||
You can install `ayugram-desktop` from [AUR](https://aur.archlinux.org/packages?O=0&K=ayugram).
|
You can install `ayugram-desktop` from [AUR](https://aur.archlinux.org/packages?O=0&K=ayugram).
|
||||||
|
@ -102,3 +110,8 @@ Enjoy using **AyuGram**? Consider sending us a tip!
|
||||||
### Icons
|
### Icons
|
||||||
|
|
||||||
- [Solar Icon Set](https://www.figma.com/community/file/1166831539721848736)
|
- [Solar Icon Set](https://www.figma.com/community/file/1166831539721848736)
|
||||||
|
|
||||||
|
### Bots
|
||||||
|
|
||||||
|
- [TelegramDB](https://t.me/tgdatabase) for username lookup by ID (until closing free inline mode at 25 May 2025)
|
||||||
|
- [usinfobot](https://t.me/usinfobot) for username lookup by ID
|
||||||
|
|
|
@ -26,7 +26,6 @@ get_filename_component(res_loc Resources REALPATH)
|
||||||
include(cmake/telegram_options.cmake)
|
include(cmake/telegram_options.cmake)
|
||||||
include(cmake/lib_ffmpeg.cmake)
|
include(cmake/lib_ffmpeg.cmake)
|
||||||
include(cmake/lib_stripe.cmake)
|
include(cmake/lib_stripe.cmake)
|
||||||
include(cmake/lib_tgvoip.cmake)
|
|
||||||
include(cmake/lib_tgcalls.cmake)
|
include(cmake/lib_tgcalls.cmake)
|
||||||
include(cmake/lib_prisma.cmake)
|
include(cmake/lib_prisma.cmake)
|
||||||
include(cmake/td_export.cmake)
|
include(cmake/td_export.cmake)
|
||||||
|
@ -34,6 +33,7 @@ include(cmake/td_iv.cmake)
|
||||||
include(cmake/td_lang.cmake)
|
include(cmake/td_lang.cmake)
|
||||||
include(cmake/td_mtproto.cmake)
|
include(cmake/td_mtproto.cmake)
|
||||||
include(cmake/td_scheme.cmake)
|
include(cmake/td_scheme.cmake)
|
||||||
|
include(cmake/td_tde2e.cmake)
|
||||||
include(cmake/td_ui.cmake)
|
include(cmake/td_ui.cmake)
|
||||||
include(cmake/generate_appdata_changelog.cmake)
|
include(cmake/generate_appdata_changelog.cmake)
|
||||||
|
|
||||||
|
@ -47,17 +47,15 @@ if (WIN32)
|
||||||
platform/win/windows_quiethours.idl
|
platform/win/windows_quiethours.idl
|
||||||
platform/win/windows_toastactivator.idl
|
platform/win/windows_toastactivator.idl
|
||||||
)
|
)
|
||||||
|
|
||||||
nuget_add_winrt(Telegram)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_target_properties(Telegram PROPERTIES AUTOMOC ON)
|
set_target_properties(Telegram PROPERTIES AUTOMOC ON)
|
||||||
|
|
||||||
target_link_libraries(Telegram
|
target_link_libraries(Telegram
|
||||||
PRIVATE
|
PRIVATE
|
||||||
tdesktop::lib_tgcalls_legacy
|
# tdesktop::lib_tgcalls_legacy
|
||||||
tdesktop::lib_tgcalls
|
tdesktop::lib_tgcalls
|
||||||
tdesktop::lib_tgvoip
|
# tdesktop::lib_tgvoip
|
||||||
|
|
||||||
# Order in this list defines the order of include paths in command line.
|
# Order in this list defines the order of include paths in command line.
|
||||||
# We need to place desktop-app::external_minizip this early to have its
|
# We need to place desktop-app::external_minizip this early to have its
|
||||||
|
@ -71,6 +69,7 @@ PRIVATE
|
||||||
tdesktop::td_lang
|
tdesktop::td_lang
|
||||||
tdesktop::td_mtproto
|
tdesktop::td_mtproto
|
||||||
tdesktop::td_scheme
|
tdesktop::td_scheme
|
||||||
|
tdesktop::td_tde2e
|
||||||
tdesktop::td_ui
|
tdesktop::td_ui
|
||||||
desktop-app::lib_webrtc
|
desktop-app::lib_webrtc
|
||||||
desktop-app::lib_base
|
desktop-app::lib_base
|
||||||
|
@ -231,6 +230,8 @@ PRIVATE
|
||||||
api/api_peer_colors.h
|
api/api_peer_colors.h
|
||||||
api/api_peer_photo.cpp
|
api/api_peer_photo.cpp
|
||||||
api/api_peer_photo.h
|
api/api_peer_photo.h
|
||||||
|
api/api_peer_search.cpp
|
||||||
|
api/api_peer_search.h
|
||||||
api/api_polls.cpp
|
api/api_polls.cpp
|
||||||
api/api_polls.h
|
api/api_polls.h
|
||||||
api/api_premium.cpp
|
api/api_premium.cpp
|
||||||
|
@ -295,8 +296,8 @@ PRIVATE
|
||||||
boxes/peers/edit_contact_box.h
|
boxes/peers/edit_contact_box.h
|
||||||
boxes/peers/edit_forum_topic_box.cpp
|
boxes/peers/edit_forum_topic_box.cpp
|
||||||
boxes/peers/edit_forum_topic_box.h
|
boxes/peers/edit_forum_topic_box.h
|
||||||
boxes/peers/edit_linked_chat_box.cpp
|
boxes/peers/edit_discussion_link_box.cpp
|
||||||
boxes/peers/edit_linked_chat_box.h
|
boxes/peers/edit_discussion_link_box.h
|
||||||
boxes/peers/edit_members_visible.cpp
|
boxes/peers/edit_members_visible.cpp
|
||||||
boxes/peers/edit_members_visible.h
|
boxes/peers/edit_members_visible.h
|
||||||
boxes/peers/edit_participant_box.cpp
|
boxes/peers/edit_participant_box.cpp
|
||||||
|
@ -476,6 +477,8 @@ PRIVATE
|
||||||
calls/calls_video_bubble.h
|
calls/calls_video_bubble.h
|
||||||
calls/calls_video_incoming.cpp
|
calls/calls_video_incoming.cpp
|
||||||
calls/calls_video_incoming.h
|
calls/calls_video_incoming.h
|
||||||
|
calls/calls_window.cpp
|
||||||
|
calls/calls_window.h
|
||||||
chat_helpers/compose/compose_features.h
|
chat_helpers/compose/compose_features.h
|
||||||
chat_helpers/compose/compose_show.cpp
|
chat_helpers/compose/compose_show.cpp
|
||||||
chat_helpers/compose/compose_show.h
|
chat_helpers/compose/compose_show.h
|
||||||
|
@ -525,6 +528,8 @@ PRIVATE
|
||||||
chat_helpers/ttl_media_layer_widget.h
|
chat_helpers/ttl_media_layer_widget.h
|
||||||
core/application.cpp
|
core/application.cpp
|
||||||
core/application.h
|
core/application.h
|
||||||
|
core/bank_card_click_handler.cpp
|
||||||
|
core/bank_card_click_handler.h
|
||||||
core/base_integration.cpp
|
core/base_integration.cpp
|
||||||
core/base_integration.h
|
core/base_integration.h
|
||||||
core/changelogs.cpp
|
core/changelogs.cpp
|
||||||
|
@ -578,6 +583,8 @@ PRIVATE
|
||||||
data/components/factchecks.h
|
data/components/factchecks.h
|
||||||
data/components/location_pickers.cpp
|
data/components/location_pickers.cpp
|
||||||
data/components/location_pickers.h
|
data/components/location_pickers.h
|
||||||
|
data/components/promo_suggestions.cpp
|
||||||
|
data/components/promo_suggestions.h
|
||||||
data/components/recent_peers.cpp
|
data/components/recent_peers.cpp
|
||||||
data/components/recent_peers.h
|
data/components/recent_peers.h
|
||||||
data/components/scheduled_messages.cpp
|
data/components/scheduled_messages.cpp
|
||||||
|
@ -764,12 +771,16 @@ PRIVATE
|
||||||
dialogs/dialogs_main_list.h
|
dialogs/dialogs_main_list.h
|
||||||
dialogs/dialogs_pinned_list.cpp
|
dialogs/dialogs_pinned_list.cpp
|
||||||
dialogs/dialogs_pinned_list.h
|
dialogs/dialogs_pinned_list.h
|
||||||
|
dialogs/dialogs_quick_action.cpp
|
||||||
|
dialogs/dialogs_quick_action.h
|
||||||
dialogs/dialogs_row.cpp
|
dialogs/dialogs_row.cpp
|
||||||
dialogs/dialogs_row.h
|
dialogs/dialogs_row.h
|
||||||
dialogs/dialogs_search_from_controllers.cpp
|
dialogs/dialogs_search_from_controllers.cpp
|
||||||
dialogs/dialogs_search_from_controllers.h
|
dialogs/dialogs_search_from_controllers.h
|
||||||
dialogs/dialogs_search_tags.cpp
|
dialogs/dialogs_search_tags.cpp
|
||||||
dialogs/dialogs_search_tags.h
|
dialogs/dialogs_search_tags.h
|
||||||
|
dialogs/dialogs_top_bar_suggestion.cpp
|
||||||
|
dialogs/dialogs_top_bar_suggestion.h
|
||||||
dialogs/dialogs_widget.cpp
|
dialogs/dialogs_widget.cpp
|
||||||
dialogs/dialogs_widget.h
|
dialogs/dialogs_widget.h
|
||||||
editor/color_picker.cpp
|
editor/color_picker.cpp
|
||||||
|
@ -1001,6 +1012,8 @@ PRIVATE
|
||||||
history/history_unread_things.h
|
history/history_unread_things.h
|
||||||
history/history_view_highlight_manager.cpp
|
history/history_view_highlight_manager.cpp
|
||||||
history/history_view_highlight_manager.h
|
history/history_view_highlight_manager.h
|
||||||
|
history/history_view_swipe_back_session.cpp
|
||||||
|
history/history_view_swipe_back_session.h
|
||||||
history/history_widget.cpp
|
history/history_widget.cpp
|
||||||
history/history_widget.h
|
history/history_widget.h
|
||||||
info/bot/earn/info_bot_earn_list.cpp
|
info/bot/earn/info_bot_earn_list.cpp
|
||||||
|
@ -1155,6 +1168,8 @@ PRIVATE
|
||||||
inline_bots/inline_bot_result.h
|
inline_bots/inline_bot_result.h
|
||||||
inline_bots/inline_bot_send_data.cpp
|
inline_bots/inline_bot_send_data.cpp
|
||||||
inline_bots/inline_bot_send_data.h
|
inline_bots/inline_bot_send_data.h
|
||||||
|
inline_bots/inline_bot_storage.cpp
|
||||||
|
inline_bots/inline_bot_storage.h
|
||||||
inline_bots/inline_results_inner.cpp
|
inline_bots/inline_results_inner.cpp
|
||||||
inline_bots/inline_results_inner.h
|
inline_bots/inline_results_inner.h
|
||||||
inline_bots/inline_results_widget.cpp
|
inline_bots/inline_results_widget.cpp
|
||||||
|
@ -1501,6 +1516,10 @@ PRIVATE
|
||||||
settings/cloud_password/settings_cloud_password_hint.h
|
settings/cloud_password/settings_cloud_password_hint.h
|
||||||
settings/cloud_password/settings_cloud_password_input.cpp
|
settings/cloud_password/settings_cloud_password_input.cpp
|
||||||
settings/cloud_password/settings_cloud_password_input.h
|
settings/cloud_password/settings_cloud_password_input.h
|
||||||
|
settings/cloud_password/settings_cloud_password_login_email.cpp
|
||||||
|
settings/cloud_password/settings_cloud_password_login_email.h
|
||||||
|
settings/cloud_password/settings_cloud_password_login_email_confirm.cpp
|
||||||
|
settings/cloud_password/settings_cloud_password_login_email_confirm.h
|
||||||
settings/cloud_password/settings_cloud_password_manage.cpp
|
settings/cloud_password/settings_cloud_password_manage.cpp
|
||||||
settings/cloud_password/settings_cloud_password_manage.h
|
settings/cloud_password/settings_cloud_password_manage.h
|
||||||
settings/cloud_password/settings_cloud_password_start.cpp
|
settings/cloud_password/settings_cloud_password_start.cpp
|
||||||
|
@ -1612,6 +1631,8 @@ PRIVATE
|
||||||
support/support_preload.h
|
support/support_preload.h
|
||||||
support/support_templates.cpp
|
support/support_templates.cpp
|
||||||
support/support_templates.h
|
support/support_templates.h
|
||||||
|
tde2e/tde2e_integration.cpp
|
||||||
|
tde2e/tde2e_integration.h
|
||||||
ui/boxes/edit_invite_link_session.cpp
|
ui/boxes/edit_invite_link_session.cpp
|
||||||
ui/boxes/edit_invite_link_session.h
|
ui/boxes/edit_invite_link_session.h
|
||||||
ui/boxes/peer_qr_box.cpp
|
ui/boxes/peer_qr_box.cpp
|
||||||
|
@ -1808,6 +1829,10 @@ if (WIN32)
|
||||||
# COMMENT
|
# COMMENT
|
||||||
# $<IF:${release},"Appending compatibility manifest.","Finalizing build.">
|
# $<IF:${release},"Appending compatibility manifest.","Finalizing build.">
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
if (QT_VERSION LESS 6)
|
||||||
|
target_link_libraries(Telegram PRIVATE desktop-app::win_directx_helper)
|
||||||
|
endif()
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
if (NOT DESKTOP_APP_USE_PACKAGED)
|
if (NOT DESKTOP_APP_USE_PACKAGED)
|
||||||
target_link_libraries(Telegram PRIVATE desktop-app::external_iconv)
|
target_link_libraries(Telegram PRIVATE desktop-app::external_iconv)
|
||||||
|
@ -1985,66 +2010,8 @@ if (MSVC)
|
||||||
)
|
)
|
||||||
target_link_options(Telegram
|
target_link_options(Telegram
|
||||||
PRIVATE
|
PRIVATE
|
||||||
/DELAYLOAD:secur32.dll
|
|
||||||
/DELAYLOAD:winmm.dll
|
|
||||||
/DELAYLOAD:ws2_32.dll
|
|
||||||
/DELAYLOAD:user32.dll
|
|
||||||
/DELAYLOAD:gdi32.dll
|
|
||||||
/DELAYLOAD:advapi32.dll
|
/DELAYLOAD:advapi32.dll
|
||||||
/DELAYLOAD:shell32.dll
|
|
||||||
/DELAYLOAD:ole32.dll
|
|
||||||
/DELAYLOAD:oleaut32.dll
|
|
||||||
/DELAYLOAD:shlwapi.dll
|
|
||||||
/DELAYLOAD:iphlpapi.dll
|
|
||||||
/DELAYLOAD:gdiplus.dll
|
|
||||||
/DELAYLOAD:version.dll
|
|
||||||
/DELAYLOAD:dwmapi.dll
|
|
||||||
/DELAYLOAD:uxtheme.dll
|
|
||||||
/DELAYLOAD:crypt32.dll
|
|
||||||
/DELAYLOAD:bcrypt.dll
|
|
||||||
/DELAYLOAD:netapi32.dll
|
|
||||||
/DELAYLOAD:imm32.dll
|
|
||||||
/DELAYLOAD:userenv.dll
|
|
||||||
/DELAYLOAD:wtsapi32.dll
|
|
||||||
/DELAYLOAD:propsys.dll
|
|
||||||
)
|
)
|
||||||
if (QT_VERSION GREATER 6)
|
|
||||||
if (NOT build_winarm)
|
|
||||||
target_link_options(Telegram PRIVATE
|
|
||||||
/DELAYLOAD:API-MS-Win-EventLog-Legacy-l1-1-0.dll
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_options(Telegram
|
|
||||||
PRIVATE
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-Console-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-Fibers-l2-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-Fibers-l2-1-1.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-File-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-LibraryLoader-l1-2-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-Localization-l1-2-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-Memory-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-Memory-l1-1-1.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-ProcessThreads-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-Synch-l1-2-0.dll # Synchronization.lib
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-SysInfo-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-Timezone-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-WinRT-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-WinRT-Error-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Core-WinRT-String-l1-1-0.dll
|
|
||||||
/DELAYLOAD:API-MS-Win-Security-CryptoAPI-l1-1-0.dll
|
|
||||||
# /DELAYLOAD:API-MS-Win-Shcore-Scaling-l1-1-1.dll # We shadowed GetDpiForMonitor
|
|
||||||
/DELAYLOAD:authz.dll # Authz.lib
|
|
||||||
/DELAYLOAD:comdlg32.dll
|
|
||||||
/DELAYLOAD:dwrite.dll # DWrite.lib
|
|
||||||
/DELAYLOAD:dxgi.dll # DXGI.lib
|
|
||||||
/DELAYLOAD:d3d9.dll # D3D9.lib
|
|
||||||
/DELAYLOAD:d3d11.dll # D3D11.lib
|
|
||||||
/DELAYLOAD:d3d12.dll # D3D12.lib
|
|
||||||
/DELAYLOAD:setupapi.dll # SetupAPI.lib
|
|
||||||
/DELAYLOAD:winhttp.dll
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_prepare_qrc(Telegram)
|
target_prepare_qrc(Telegram)
|
||||||
|
@ -2075,22 +2042,6 @@ if (NOT DESKTOP_APP_DISABLE_AUTOUPDATE AND NOT build_macstore AND NOT build_wins
|
||||||
base/platform/win/base_windows_safe_library.h
|
base/platform/win/base_windows_safe_library.h
|
||||||
)
|
)
|
||||||
target_include_directories(Updater PRIVATE ${lib_base_loc})
|
target_include_directories(Updater PRIVATE ${lib_base_loc})
|
||||||
if (MSVC)
|
|
||||||
target_link_libraries(Updater
|
|
||||||
PRIVATE
|
|
||||||
delayimp
|
|
||||||
)
|
|
||||||
target_link_options(Updater
|
|
||||||
PRIVATE
|
|
||||||
/DELAYLOAD:user32.dll
|
|
||||||
/DELAYLOAD:advapi32.dll
|
|
||||||
/DELAYLOAD:shell32.dll
|
|
||||||
/DELAYLOAD:ole32.dll
|
|
||||||
/DELAYLOAD:shlwapi.dll
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
target_link_options(Updater PRIVATE -municode)
|
|
||||||
endif()
|
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
add_custom_command(TARGET Updater
|
add_custom_command(TARGET Updater
|
||||||
PRE_LINK
|
PRE_LINK
|
||||||
|
@ -2143,14 +2094,16 @@ if (LINUX AND DESKTOP_APP_USE_PACKAGED)
|
||||||
configure_file("../lib/xdg/com.ayugram.desktop.metainfo.xml" "${CMAKE_CURRENT_BINARY_DIR}/com.ayugram.desktop.metainfo.xml" @ONLY)
|
configure_file("../lib/xdg/com.ayugram.desktop.metainfo.xml" "${CMAKE_CURRENT_BINARY_DIR}/com.ayugram.desktop.metainfo.xml" @ONLY)
|
||||||
generate_appdata_changelog(Telegram "${CMAKE_SOURCE_DIR}/changelog.txt" "${CMAKE_CURRENT_BINARY_DIR}/com.ayugram.desktop.metainfo.xml")
|
generate_appdata_changelog(Telegram "${CMAKE_SOURCE_DIR}/changelog.txt" "${CMAKE_CURRENT_BINARY_DIR}/com.ayugram.desktop.metainfo.xml")
|
||||||
install(TARGETS Telegram RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
install(TARGETS Telegram RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||||
install(FILES "Resources/art/icon16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "ayugram.png")
|
install(FILES "Resources/art/icon16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "com.ayugram.desktop.png")
|
||||||
install(FILES "Resources/art/icon32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "ayugram.png")
|
install(FILES "Resources/art/icon32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "com.ayugram.desktop.png")
|
||||||
install(FILES "Resources/art/icon48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "ayugram.png")
|
install(FILES "Resources/art/icon48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "com.ayugram.desktop.png")
|
||||||
install(FILES "Resources/art/icon64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "ayugram.png")
|
install(FILES "Resources/art/icon64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "com.ayugram.desktop.png")
|
||||||
install(FILES "Resources/art/icon128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "ayugram.png")
|
install(FILES "Resources/art/icon128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "com.ayugram.desktop.png")
|
||||||
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "ayugram.png")
|
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "com.ayugram.desktop.png")
|
||||||
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "ayugram.png")
|
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "com.ayugram.desktop.png")
|
||||||
install(FILES "Resources/icons/tray_monochrome.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/symbolic/apps" RENAME "ayugram-symbolic.svg")
|
install(FILES "Resources/icons/tray_monochrome.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/symbolic/apps" RENAME "com.ayugram.desktop-symbolic.svg")
|
||||||
|
install(FILES "Resources/icons/tray_monochrome_attention.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/symbolic/apps" RENAME "com.ayugram.desktop-attention-symbolic.svg")
|
||||||
|
install(FILES "Resources/icons/tray_monochrome_mute.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/symbolic/apps" RENAME "com.ayugram.desktop-mute-symbolic.svg")
|
||||||
install(FILES "../lib/xdg/com.ayugram.desktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
|
install(FILES "../lib/xdg/com.ayugram.desktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.ayugram.desktop.service" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/dbus-1/services")
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.ayugram.desktop.service" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/dbus-1/services")
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.ayugram.desktop.metainfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.ayugram.desktop.metainfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
|
||||||
|
|
1
Telegram/Resources/animations/media_forbidden.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/archive.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/delete.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/disabled.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/mute.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/pin.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/read.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/unarchive.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/unmute.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/unpin.tgs
Normal file
BIN
Telegram/Resources/animations/swipe_action/unread.tgs
Normal file
BIN
Telegram/Resources/icons/calls/call_group.png
Normal file
After Width: | Height: | Size: 721 B |
BIN
Telegram/Resources/icons/calls/call_group@2x.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/calls/call_group@3x.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
Telegram/Resources/icons/calls/calls_add_people.png
Normal file
After Width: | Height: | Size: 529 B |
BIN
Telegram/Resources/icons/calls/calls_add_people@2x.png
Normal file
After Width: | Height: | Size: 956 B |
BIN
Telegram/Resources/icons/calls/calls_add_people@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/calls/group_call_logo.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/calls/group_call_logo@2x.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
Telegram/Resources/icons/calls/group_call_logo@3x.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
Telegram/Resources/icons/chat/input_gift.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
Telegram/Resources/icons/chat/input_gift@2x.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/chat/input_gift@3x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/chat/mini_info_alert.png
Normal file
After Width: | Height: | Size: 311 B |
BIN
Telegram/Resources/icons/chat/mini_info_alert@2x.png
Normal file
After Width: | Height: | Size: 578 B |
BIN
Telegram/Resources/icons/chat/mini_info_alert@3x.png
Normal file
After Width: | Height: | Size: 829 B |
BIN
Telegram/Resources/icons/menu/hourglass.png
Normal file
After Width: | Height: | Size: 630 B |
BIN
Telegram/Resources/icons/menu/hourglass@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/menu/hourglass@3x.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/menu/order_date.png
Normal file
After Width: | Height: | Size: 585 B |
BIN
Telegram/Resources/icons/menu/order_date@2x.png
Normal file
After Width: | Height: | Size: 1,015 B |
BIN
Telegram/Resources/icons/menu/order_date@3x.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/menu/order_number.png
Normal file
After Width: | Height: | Size: 680 B |
BIN
Telegram/Resources/icons/menu/order_number@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/menu/order_number@3x.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/menu/order_price.png
Normal file
After Width: | Height: | Size: 813 B |
BIN
Telegram/Resources/icons/menu/order_price@2x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/menu/order_price@3x.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram/Resources/icons/menu/tag_sell.png
Normal file
After Width: | Height: | Size: 377 B |
BIN
Telegram/Resources/icons/menu/tag_sell@2x.png
Normal file
After Width: | Height: | Size: 675 B |
BIN
Telegram/Resources/icons/menu/tag_sell@3x.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
Telegram/Resources/icons/payments/premium_emoji.png
Normal file
After Width: | Height: | Size: 370 B |
BIN
Telegram/Resources/icons/payments/premium_emoji@2x.png
Normal file
After Width: | Height: | Size: 712 B |
BIN
Telegram/Resources/icons/payments/premium_emoji@3x.png
Normal file
After Width: | Height: | Size: 926 B |
BIN
Telegram/Resources/icons/settings/mini_gift.png
Normal file
After Width: | Height: | Size: 472 B |
BIN
Telegram/Resources/icons/settings/mini_gift@2x.png
Normal file
After Width: | Height: | Size: 748 B |
BIN
Telegram/Resources/icons/settings/mini_gift@3x.png
Normal file
After Width: | Height: | Size: 1 KiB |
12
Telegram/Resources/icons/settings/mini_gift_order_date.svg
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>Mini / mini_gift_sorting2</title>
|
||||||
|
<g id="Mini-/-mini_gift_sorting2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M39.7913043,28.3413043 C40.9234881,28.3413043 41.8413043,29.2591206 41.8413043,30.3913043 L41.8413043,45 C41.8413043,46.1321837 40.9234881,47.05 39.7913043,47.05 C38.6591206,47.05 37.7413043,46.1321837 37.7413043,45 L37.7413043,30.3913043 C37.7413043,29.2591206 38.6591206,28.3413043 39.7913043,28.3413043 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M32.1330398,38.0495689 C32.9336146,38.8501437 34.2316028,38.8501437 35.0321776,38.0495689 L39.7906087,33.291 L44.5504311,38.0495689 C45.3088704,38.8080082 46.5137416,38.847926 47.3191738,38.1693225 L47.4495689,38.0495689 C48.2501437,37.2489941 48.2501437,35.9510059 47.4495689,35.1504311 L41.7573686,29.4582308 C40.6715413,28.3724035 38.9110674,28.3724035 37.8252401,29.4582308 L32.1330398,35.1504311 C31.332465,35.9510059 31.332465,37.2489941 32.1330398,38.0495689 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M36.5217391,5.3326087 C40.4153466,5.3326087 43.5717391,8.48900121 43.5717391,12.3826087 L43.5717391,21.7217391 C43.5717391,22.8539229 42.6539229,23.7717391 41.5217391,23.7717391 C40.3895554,23.7717391 39.4717391,22.8539229 39.4717391,21.7217391 L39.4717391,12.3826087 C39.4717391,10.7533687 38.1509791,9.4326087 36.5217391,9.4326087 L10,9.4326087 C8.37075999,9.4326087 7.05,10.7533687 7.05,12.3826087 L7.05,35.9826087 C7.05,37.6118487 8.37075999,38.9326087 10,38.9326087 L27.373913,38.9326087 C28.5060968,38.9326087 29.423913,39.850425 29.423913,40.9826087 C29.423913,42.1147924 28.5060968,43.0326087 27.373913,43.0326087 L10,43.0326087 C6.10639251,43.0326087 2.95,39.8762162 2.95,35.9826087 L2.95,12.3826087 C2.95,8.48900121 6.10639251,5.3326087 10,5.3326087 L36.5217391,5.3326087 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<polygon id="Path" fill="#FFFFFF" fill-rule="nonzero" points="6.09565217 20.3891304 40.426087 20.3891304 40.426087 16.2891304 6.09565217 16.2891304"></polygon>
|
||||||
|
<path d="M11.8434783,0.95 C12.975662,0.95 13.8934783,1.86781626 13.8934783,3 L13.8934783,6.65217391 C13.8934783,7.78435765 12.975662,8.70217391 11.8434783,8.70217391 C10.7112945,8.70217391 9.79347826,7.78435765 9.79347826,6.65217391 L9.79347826,3 C9.79347826,1.86781626 10.7112945,0.95 11.8434783,0.95 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M34.6782609,0.95 C35.8104446,0.95 36.7282609,1.86781626 36.7282609,3 L36.7282609,6.65217391 C36.7282609,7.78435765 35.8104446,8.70217391 34.6782609,8.70217391 C33.5460771,8.70217391 32.6282609,7.78435765 32.6282609,6.65217391 L32.6282609,3 C32.6282609,1.86781626 33.5460771,0.95 34.6782609,0.95 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3 KiB |
12
Telegram/Resources/icons/settings/mini_gift_order_number.svg
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>Mini / mini_gift_sorting3</title>
|
||||||
|
<g id="Mini-/-mini_gift_sorting3" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M34.4778761,13.749192 C35.6376741,13.749192 36.5778761,14.689394 36.5778761,15.849192 C36.5778761,17.00899 35.6376741,17.949192 34.4778761,17.949192 L7.57258674,17.949192 C6.41278876,17.949192 5.47258674,17.00899 5.47258674,15.849192 C5.47258674,14.689394 6.41278876,13.749192 7.57258674,13.749192 L34.4778761,13.749192 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M30.923367,27.509546 C32.083165,27.509546 33.023367,28.4497481 33.023367,29.609546 C33.023367,30.769344 32.083165,31.709546 30.923367,31.709546 L4,31.709546 C2.84020203,31.709546 1.9,30.769344 1.9,29.609546 C1.9,28.4497481 2.84020203,27.509546 4,27.509546 L30.923367,27.509546 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M14.7584617,4.53380965 C15.0159315,3.40295129 16.1413939,2.69492999 17.2722522,2.9523998 C18.4031106,3.20986962 19.1111319,4.33533198 18.8536621,5.46619035 L10.9056841,40.3752813 C10.6482143,41.5061396 9.52275197,42.2141609 8.39189361,41.9566911 C7.26103524,41.6992213 6.55301394,40.5737589 6.81048375,39.4429006 L14.7584617,4.53380965 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M28.1811642,4.55038432 C28.4294801,3.41748072 29.5491797,2.70038069 30.6820833,2.94869657 C31.8149869,3.19701246 32.532087,4.31671208 32.2837711,5.44961568 L24.6322095,40.3587066 C24.3838936,41.4916102 23.264194,42.2087102 22.1312904,41.9603943 C20.9983868,41.7120785 20.2812868,40.5923788 20.5296027,39.4594752 L28.1811642,4.55038432 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M39.7913043,28.3413043 C40.9234881,28.3413043 41.8413043,29.2591206 41.8413043,30.3913043 L41.8413043,45 C41.8413043,46.1321837 40.9234881,47.05 39.7913043,47.05 C38.6591206,47.05 37.7413043,46.1321837 37.7413043,45 L37.7413043,30.3913043 C37.7413043,29.2591206 38.6591206,28.3413043 39.7913043,28.3413043 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M32.1330398,38.0495689 C32.9336146,38.8501437 34.2316028,38.8501437 35.0321776,38.0495689 L39.7906087,33.291 L44.5504311,38.0495689 C45.3088704,38.8080082 46.5137416,38.847926 47.3191738,38.1693225 L47.4495689,38.0495689 C48.2501437,37.2489941 48.2501437,35.9510059 47.4495689,35.1504311 L41.7573686,29.4582308 C40.6715413,28.3724035 38.9110674,28.3724035 37.8252401,29.4582308 L32.1330398,35.1504311 C31.332465,35.9510059 31.332465,37.2489941 32.1330398,38.0495689 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
10
Telegram/Resources/icons/settings/mini_gift_order_price.svg
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>Mini / mini_gift_sorting1</title>
|
||||||
|
<g id="Mini-/-mini_gift_sorting1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M23.4380165,1.95 C35.3025073,1.95 44.9260331,11.510317 44.9260331,23.3103448 C44.9260331,23.5919731 44.9205389,23.8730129 44.9095753,24.1533571 C44.8653322,25.2846761 43.9123508,26.1659251 42.7810319,26.121682 C41.6497129,26.0774389 40.7684638,25.1244576 40.812707,23.9931386 C40.8215831,23.7661706 40.8260331,23.5385471 40.8260331,23.3103448 C40.8260331,13.7807547 33.0441659,6.05 23.4380165,6.05 C13.8318671,6.05 6.05,13.7807547 6.05,23.3103448 C6.05,32.839935 13.8318671,40.5706897 23.4380165,40.5706897 C25.2657432,40.5706897 27.0529516,40.2914087 28.7555206,39.7492213 C29.8343232,39.4056738 30.9873658,40.0017158 31.3309133,41.0805185 C31.6744608,42.1593211 31.0784187,43.3123637 29.9996161,43.6559112 C27.8959061,44.3258431 25.6891219,44.6706897 23.4380165,44.6706897 C11.5735257,44.6706897 1.95,35.1103726 1.95,23.3103448 C1.95,11.510317 11.5735257,1.95 23.4380165,1.95 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M39.7913043,28.3413043 C40.9234881,28.3413043 41.8413043,29.2591206 41.8413043,30.3913043 L41.8413043,45 C41.8413043,46.1321837 40.9234881,47.05 39.7913043,47.05 C38.6591206,47.05 37.7413043,46.1321837 37.7413043,45 L37.7413043,30.3913043 C37.7413043,29.2591206 38.6591206,28.3413043 39.7913043,28.3413043 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M32.1330398,38.0495689 C32.9336146,38.8501437 34.2316028,38.8501437 35.0321776,38.0495689 L39.7906087,33.291 L44.5504311,38.0495689 C45.3088704,38.8080082 46.5137416,38.847926 47.3191738,38.1693225 L47.4495689,38.0495689 C48.2501437,37.2489941 48.2501437,35.9510059 47.4495689,35.1504311 L41.7573686,29.4582308 C40.6715413,28.3724035 38.9110674,28.3724035 37.8252401,29.4582308 L32.1330398,35.1504311 C31.332465,35.9510059 31.332465,37.2489941 32.1330398,38.0495689 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
<path d="M23.8366211,35.9195313 C24.4958008,35.9195313 25.281738,35.5533203 25.281738,34.6744141 L25.281738,33.5025391 C29.2221677,33.0777344 31.4831055,30.7632813 31.4831055,27.3941406 C31.4831055,24.49375 29.7399414,22.7359375 26.1217773,21.9449219 L23.1481445,21.2710938 C21.287793,20.8609375 20.3795898,20.0113281 20.3795898,18.7662109 C20.3795898,17.2720703 21.6686523,16.1880859 23.6901367,16.1880859 C25.3307617,16.1880859 26.4733398,16.7447266 27.7477539,18.165625 C28.3922852,18.8394531 28.890332,19.0884766 29.5641602,19.0884766 C30.3844727,19.0884766 31.0143555,18.5171875 31.0143555,17.6675781 C31.0143555,16.8472656 30.530957,15.9537109 29.7106445,15.1480469 C28.6266602,14.1226563 27.2006837,13.4488281 25.369629,13.2144531 L25.369629,11.9986328 C25.369629,11.134375 24.5836914,10.7681641 23.9098633,10.7681641 C23.2506836,10.7681641 22.464746,11.1197266 22.464746,11.9986328 L22.464746,13.1705078 C18.6708007,13.5220703 16.4538086,15.7925781 16.4538086,19.0445313 C16.4538086,21.8863281 18.1969727,23.7759766 21.5368164,24.5230469 L24.5104492,25.2115234 C26.678418,25.7242188 27.5719727,26.4859375 27.5719727,27.775 C27.5719727,29.4449219 26.2682617,30.4996094 23.9391602,30.4996094 C22.1959961,30.4996094 20.7458008,29.8404297 19.4274414,28.4195313 C18.6803711,27.6724609 18.2702148,27.5113281 17.7135742,27.5113281 C16.8200195,27.5113281 16.1461914,28.0826172 16.1461914,29.0640625 C16.1461914,29.9283203 16.6442383,30.821875 17.537793,31.5982422 C18.709668,32.6675781 20.3407222,33.3267578 22.376855,33.5171875 L22.376855,34.6744141 C22.376855,35.5533203 23.162793,35.9195313 23.8366211,35.9195313 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
7
Telegram/Resources/icons/tray_monochrome_attention.svg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="plane" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M1.3311718,6.36592184 C5.3576954,4.67244493 8.04267511,3.5560013 9.38611094,3.01659096 C13.2218932,1.47646481 14.0189359,1.2089284 14.5384372,1.2 C14.6526967,1.19815119 14.9081723,1.22548649 15.0736587,1.35511219 C15.2133922,1.4645656 15.2518384,1.61242159 15.2702362,1.71619544 C15.288634,1.81996929 15.3115436,2.05636876 15.2933322,2.24108442 C15.0854698,4.34939964 14.1860526,9.46572464 13.7284802,11.8270738 C13.5348641,12.8262491 13.1536281,13.1612675 12.7845475,13.1940535 C11.9824498,13.265305 11.3733733,12.6823476 10.5965026,12.190753 C9.3808532,11.4215044 8.69408865,10.9426448 7.51409044,10.1920004 C6.15039834,9.32450079 7.03442319,8.84770795 7.81158733,8.06849502 C8.01497489,7.86457129 11.5490353,4.7615061 11.6174372,4.48000946 C11.625992,4.44480359 11.6339313,4.31357282 11.5531696,4.24427815 C11.472408,4.17498349 11.3532107,4.19867957 11.2671947,4.21752527 C11.1452695,4.24423848 9.20325394,5.48334063 5.44114787,7.93483171 C4.88991321,8.30022994 4.39062196,8.47826423 3.94327414,8.46893456 C3.45010907,8.45864936 2.50145729,8.19975808 1.79623221,7.97846422 C0.931244952,7.70703829 0.243770289,7.56353344 0.303633888,7.10256824 C0.334814555,6.86246904 0.677327192,6.61692024 1.3311718,6.36592184 Z" id="Path-3" fill="#FFFFFF"></path>
|
||||||
|
</g>
|
||||||
|
<circle class="error" fill="#f23c34" cx="3.9" cy="12.7" r="2.2"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
7
Telegram/Resources/icons/tray_monochrome_mute.svg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="plane" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M1.3311718,6.36592184 C5.3576954,4.67244493 8.04267511,3.5560013 9.38611094,3.01659096 C13.2218932,1.47646481 14.0189359,1.2089284 14.5384372,1.2 C14.6526967,1.19815119 14.9081723,1.22548649 15.0736587,1.35511219 C15.2133922,1.4645656 15.2518384,1.61242159 15.2702362,1.71619544 C15.288634,1.81996929 15.3115436,2.05636876 15.2933322,2.24108442 C15.0854698,4.34939964 14.1860526,9.46572464 13.7284802,11.8270738 C13.5348641,12.8262491 13.1536281,13.1612675 12.7845475,13.1940535 C11.9824498,13.265305 11.3733733,12.6823476 10.5965026,12.190753 C9.3808532,11.4215044 8.69408865,10.9426448 7.51409044,10.1920004 C6.15039834,9.32450079 7.03442319,8.84770795 7.81158733,8.06849502 C8.01497489,7.86457129 11.5490353,4.7615061 11.6174372,4.48000946 C11.625992,4.44480359 11.6339313,4.31357282 11.5531696,4.24427815 C11.472408,4.17498349 11.3532107,4.19867957 11.2671947,4.21752527 C11.1452695,4.24423848 9.20325394,5.48334063 5.44114787,7.93483171 C4.88991321,8.30022994 4.39062196,8.47826423 3.94327414,8.46893456 C3.45010907,8.45864936 2.50145729,8.19975808 1.79623221,7.97846422 C0.931244952,7.70703829 0.243770289,7.56353344 0.303633888,7.10256824 C0.334814555,6.86246904 0.677327192,6.61692024 1.3311718,6.36592184 Z" id="Path-3" fill="#FFFFFF"></path>
|
||||||
|
</g>
|
||||||
|
<circle fill="#888888" cx="3.9" cy="12.7" r="2.2"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"cloud_lng_passport_in_ar" = "Arabic";
|
"cloud_lng_passport_in_ar" = "Arabic";
|
||||||
"cloud_lng_passport_in_az" = "Azerbaijani";
|
"cloud_lng_passport_in_az" = "Azerbaijani";
|
||||||
"cloud_lng_passport_in_bg" = "Bulgarian";
|
"cloud_lng_passport_in_bg" = "Bulgarian";
|
||||||
"cloud_lng_passport_in_bn" = "Bangla";
|
"cloud_lng_passport_in_bn" = "Bengali";
|
||||||
"cloud_lng_passport_in_cs" = "Czech";
|
"cloud_lng_passport_in_cs" = "Czech";
|
||||||
"cloud_lng_passport_in_da" = "Danish";
|
"cloud_lng_passport_in_da" = "Danish";
|
||||||
"cloud_lng_passport_in_de" = "German";
|
"cloud_lng_passport_in_de" = "German";
|
||||||
|
@ -64,7 +64,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"cloud_lng_translate_to_ar" = "Arabic";
|
"cloud_lng_translate_to_ar" = "Arabic";
|
||||||
"cloud_lng_translate_to_az" = "Azerbaijani";
|
"cloud_lng_translate_to_az" = "Azerbaijani";
|
||||||
"cloud_lng_translate_to_bg" = "Bulgarian";
|
"cloud_lng_translate_to_bg" = "Bulgarian";
|
||||||
// "cloud_lng_translate_to_bn" = "Bangla";
|
// "cloud_lng_translate_to_bn" = "Bengali";
|
||||||
"cloud_lng_translate_to_cs" = "Czech";
|
"cloud_lng_translate_to_cs" = "Czech";
|
||||||
"cloud_lng_translate_to_da" = "Danish";
|
"cloud_lng_translate_to_da" = "Danish";
|
||||||
"cloud_lng_translate_to_de" = "German";
|
"cloud_lng_translate_to_de" = "German";
|
||||||
|
@ -109,50 +109,116 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"cloud_lng_translate_to_uz" = "Uzbek";
|
"cloud_lng_translate_to_uz" = "Uzbek";
|
||||||
"cloud_lng_translate_to_vi" = "Vietnamese";
|
"cloud_lng_translate_to_vi" = "Vietnamese";
|
||||||
|
|
||||||
|
"cloud_lng_language_af" = "Afrikaans";
|
||||||
|
"cloud_lng_language_am" = "Amharic";
|
||||||
"cloud_lng_language_ar" = "Arabic";
|
"cloud_lng_language_ar" = "Arabic";
|
||||||
"cloud_lng_language_az" = "Azerbaijani";
|
"cloud_lng_language_az" = "Azerbaijani";
|
||||||
|
"cloud_lng_language_be" = "Belarusian";
|
||||||
"cloud_lng_language_bg" = "Bulgarian";
|
"cloud_lng_language_bg" = "Bulgarian";
|
||||||
// "cloud_lng_language_bn" = "Bangla";
|
"cloud_lng_language_bn" = "Bengali";
|
||||||
|
"cloud_lng_language_bs" = "Bosnian";
|
||||||
|
"cloud_lng_language_ca" = "Catalan";
|
||||||
|
// "cloud_lng_language_ceb" = "Cebuano";
|
||||||
|
"cloud_lng_language_co" = "Corsican";
|
||||||
"cloud_lng_language_cs" = "Czech";
|
"cloud_lng_language_cs" = "Czech";
|
||||||
|
"cloud_lng_language_cy" = "Welsh";
|
||||||
"cloud_lng_language_da" = "Danish";
|
"cloud_lng_language_da" = "Danish";
|
||||||
"cloud_lng_language_de" = "German";
|
"cloud_lng_language_de" = "German";
|
||||||
// "cloud_lng_language_dv" = "Divehi";
|
"cloud_lng_language_dv" = "Divehi";
|
||||||
// "cloud_lng_language_dz" = "Dzongkha";
|
"cloud_lng_language_dz" = "Dzongkha";
|
||||||
"cloud_lng_language_el" = "Greek";
|
"cloud_lng_language_el" = "Greek";
|
||||||
"cloud_lng_language_en" = "English";
|
"cloud_lng_language_en" = "English";
|
||||||
|
"cloud_lng_language_eo" = "Esperanto";
|
||||||
"cloud_lng_language_es" = "Spanish";
|
"cloud_lng_language_es" = "Spanish";
|
||||||
"cloud_lng_language_et" = "Estonian";
|
"cloud_lng_language_et" = "Estonian";
|
||||||
|
"cloud_lng_language_eu" = "Basque";
|
||||||
"cloud_lng_language_fa" = "Persian";
|
"cloud_lng_language_fa" = "Persian";
|
||||||
|
"cloud_lng_language_fi" = "Finnish";
|
||||||
"cloud_lng_language_fr" = "French";
|
"cloud_lng_language_fr" = "French";
|
||||||
|
"cloud_lng_language_fy" = "Frisian";
|
||||||
|
"cloud_lng_language_ga" = "Irish";
|
||||||
|
"cloud_lng_language_gd" = "Scots Gaelic";
|
||||||
|
"cloud_lng_language_gl" = "Galician";
|
||||||
|
"cloud_lng_language_gu" = "Gujarati";
|
||||||
|
"cloud_lng_language_ha" = "Hausa";
|
||||||
|
"cloud_lng_language_haw" = "Hawaiian";
|
||||||
"cloud_lng_language_he" = "Hebrew";
|
"cloud_lng_language_he" = "Hebrew";
|
||||||
|
"cloud_lng_language_hi" = "Hindi";
|
||||||
|
// "cloud_lng_language_hmn" = "Hmong";
|
||||||
"cloud_lng_language_hr" = "Croatian";
|
"cloud_lng_language_hr" = "Croatian";
|
||||||
|
"cloud_lng_language_ht" = "Haitian Creole";
|
||||||
"cloud_lng_language_hu" = "Hungarian";
|
"cloud_lng_language_hu" = "Hungarian";
|
||||||
"cloud_lng_language_hy" = "Armenian";
|
"cloud_lng_language_hy" = "Armenian";
|
||||||
"cloud_lng_language_id" = "Indonesian";
|
"cloud_lng_language_id" = "Indonesian";
|
||||||
|
"cloud_lng_language_ig" = "Igbo";
|
||||||
"cloud_lng_language_is" = "Icelandic";
|
"cloud_lng_language_is" = "Icelandic";
|
||||||
"cloud_lng_language_it" = "Italian";
|
"cloud_lng_language_it" = "Italian";
|
||||||
|
"cloud_lng_language_iw" = "Hebrew (Obsolete code)";
|
||||||
"cloud_lng_language_ja" = "Japanese";
|
"cloud_lng_language_ja" = "Japanese";
|
||||||
|
"cloud_lng_language_jv" = "Javanese";
|
||||||
"cloud_lng_language_ka" = "Georgian";
|
"cloud_lng_language_ka" = "Georgian";
|
||||||
// "cloud_lng_language_km" = "Khmer";
|
"cloud_lng_language_kk" = "Kazakh";
|
||||||
|
"cloud_lng_language_km" = "Khmer";
|
||||||
|
"cloud_lng_language_kn" = "Kannada";
|
||||||
"cloud_lng_language_ko" = "Korean";
|
"cloud_lng_language_ko" = "Korean";
|
||||||
|
"cloud_lng_language_ku" = "Kurdish";
|
||||||
|
"cloud_lng_language_ky" = "Kyrgyz";
|
||||||
|
"cloud_lng_language_la" = "Latin";
|
||||||
|
"cloud_lng_language_lb" = "Luxembourgish";
|
||||||
"cloud_lng_language_lo" = "Lao";
|
"cloud_lng_language_lo" = "Lao";
|
||||||
"cloud_lng_language_lt" = "Lithuanian";
|
"cloud_lng_language_lt" = "Lithuanian";
|
||||||
"cloud_lng_language_lv" = "Latvian";
|
"cloud_lng_language_lv" = "Latvian";
|
||||||
|
"cloud_lng_language_mg" = "Malagasy";
|
||||||
|
"cloud_lng_language_mi" = "Maori";
|
||||||
"cloud_lng_language_mk" = "Macedonian";
|
"cloud_lng_language_mk" = "Macedonian";
|
||||||
|
"cloud_lng_language_ml" = "Malayalam";
|
||||||
"cloud_lng_language_mn" = "Mongolian";
|
"cloud_lng_language_mn" = "Mongolian";
|
||||||
|
"cloud_lng_language_mr" = "Marathi";
|
||||||
"cloud_lng_language_ms" = "Malay";
|
"cloud_lng_language_ms" = "Malay";
|
||||||
|
"cloud_lng_language_mt" = "Maltese";
|
||||||
"cloud_lng_language_my" = "Burmese";
|
"cloud_lng_language_my" = "Burmese";
|
||||||
"cloud_lng_language_ne" = "Nepali";
|
"cloud_lng_language_ne" = "Nepali";
|
||||||
"cloud_lng_language_nl" = "Dutch";
|
"cloud_lng_language_nl" = "Dutch";
|
||||||
|
"cloud_lng_language_no" = "Norwegian";
|
||||||
|
"cloud_lng_language_ny" = "Nyanja";
|
||||||
|
"cloud_lng_language_or" = "Odia (Oriya)";
|
||||||
|
"cloud_lng_language_pa" = "Punjabi";
|
||||||
"cloud_lng_language_pl" = "Polish";
|
"cloud_lng_language_pl" = "Polish";
|
||||||
|
"cloud_lng_language_ps" = "Pashto";
|
||||||
"cloud_lng_language_pt" = "Portuguese";
|
"cloud_lng_language_pt" = "Portuguese";
|
||||||
"cloud_lng_language_ro" = "Romanian";
|
"cloud_lng_language_ro" = "Romanian";
|
||||||
"cloud_lng_language_ru" = "Russian";
|
"cloud_lng_language_ru" = "Russian";
|
||||||
|
"cloud_lng_language_rw" = "Kinyarwanda";
|
||||||
|
"cloud_lng_language_sd" = "Sindhi";
|
||||||
|
"cloud_lng_language_si" = "Sinhala";
|
||||||
"cloud_lng_language_sk" = "Slovak";
|
"cloud_lng_language_sk" = "Slovak";
|
||||||
"cloud_lng_language_sl" = "Slovenian";
|
"cloud_lng_language_sl" = "Slovenian";
|
||||||
|
"cloud_lng_language_sm" = "Samoan";
|
||||||
|
"cloud_lng_language_sn" = "Shona";
|
||||||
|
"cloud_lng_language_so" = "Somali";
|
||||||
|
"cloud_lng_language_sq" = "Albanian";
|
||||||
|
"cloud_lng_language_sr" = "Serbian";
|
||||||
|
"cloud_lng_language_st" = "Sesotho";
|
||||||
|
"cloud_lng_language_su" = "Sundanese";
|
||||||
|
"cloud_lng_language_sv" = "Swedish";
|
||||||
|
"cloud_lng_language_sw" = "Swahili";
|
||||||
|
"cloud_lng_language_ta" = "Tamil";
|
||||||
|
"cloud_lng_language_te" = "Telugu";
|
||||||
|
"cloud_lng_language_tg" = "Tajik";
|
||||||
"cloud_lng_language_th" = "Thai";
|
"cloud_lng_language_th" = "Thai";
|
||||||
"cloud_lng_language_tk" = "Turkmen";
|
"cloud_lng_language_tk" = "Turkmen";
|
||||||
|
"cloud_lng_language_tl" = "Tagalog";
|
||||||
"cloud_lng_language_tr" = "Turkish";
|
"cloud_lng_language_tr" = "Turkish";
|
||||||
|
"cloud_lng_language_tt" = "Tatar";
|
||||||
|
"cloud_lng_language_ug" = "Uyghur";
|
||||||
"cloud_lng_language_uk" = "Ukrainian";
|
"cloud_lng_language_uk" = "Ukrainian";
|
||||||
|
"cloud_lng_language_ur" = "Urdu";
|
||||||
"cloud_lng_language_uz" = "Uzbek";
|
"cloud_lng_language_uz" = "Uzbek";
|
||||||
"cloud_lng_language_vi" = "Vietnamese";
|
"cloud_lng_language_vi" = "Vietnamese";
|
||||||
|
"cloud_lng_language_xh" = "Xhosa";
|
||||||
|
"cloud_lng_language_yi" = "Yiddish";
|
||||||
|
"cloud_lng_language_yo" = "Yoruba";
|
||||||
|
"cloud_lng_language_zh" = "Chinese";
|
||||||
|
// "cloud_lng_language_zh-CN" = "Chinese (Simplified)";
|
||||||
|
// "cloud_lng_language_zh-TW" = "Chinese (Traditional)";
|
||||||
|
"cloud_lng_language_zu" = "Zulu";
|
||||||
|
|
|
@ -681,6 +681,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_shortcuts_archive_chat" = "Archive chat";
|
"lng_shortcuts_archive_chat" = "Archive chat";
|
||||||
"lng_shortcuts_media_fullscreen" = "Toggle video fullscreen";
|
"lng_shortcuts_media_fullscreen" = "Toggle video fullscreen";
|
||||||
"lng_shortcuts_show_chat_menu" = "Show chat menu";
|
"lng_shortcuts_show_chat_menu" = "Show chat menu";
|
||||||
|
"lng_shortcuts_show_chat_preview" = "Show chat preview";
|
||||||
|
|
||||||
"lng_settings_chat_reactions_title" = "Quick Reaction";
|
"lng_settings_chat_reactions_title" = "Quick Reaction";
|
||||||
"lng_settings_chat_reactions_subtitle" = "Choose your favorite reaction";
|
"lng_settings_chat_reactions_subtitle" = "Choose your favorite reaction";
|
||||||
|
@ -835,6 +836,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_settings_disconnect" = "Disconnect";
|
"lng_settings_disconnect" = "Disconnect";
|
||||||
"lng_settings_connected_title" = "Connected websites";
|
"lng_settings_connected_title" = "Connected websites";
|
||||||
|
|
||||||
|
"lng_settings_suggestion_phone_number_title" = "Is {phone} still your number?";
|
||||||
|
"lng_settings_suggestion_phone_number_about" = "Keep your number up to date to ensure you can always log into Telegram. {link}";
|
||||||
|
"lng_settings_suggestion_phone_number_about_link" = "https://telegram.org/faq#q-i-have-a-new-phone-number-what-do-i-do";
|
||||||
|
"lng_settings_suggestion_phone_number_change" = "Please change your phone number in the official Telegram app on your phone as soon as possible. {emoji}";
|
||||||
|
|
||||||
"lng_settings_power_menu" = "Battery and Animations";
|
"lng_settings_power_menu" = "Battery and Animations";
|
||||||
"lng_settings_power_title" = "Power Usage";
|
"lng_settings_power_title" = "Power Usage";
|
||||||
"lng_settings_power_subtitle" = "Power saving options";
|
"lng_settings_power_subtitle" = "Power saving options";
|
||||||
|
@ -881,6 +887,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_settings_cloud_password_email_confirm" = "Confirm and Finish";
|
"lng_settings_cloud_password_email_confirm" = "Confirm and Finish";
|
||||||
"lng_settings_cloud_password_reset_in" = "You can reset your password in {duration}.";
|
"lng_settings_cloud_password_reset_in" = "You can reset your password in {duration}.";
|
||||||
|
|
||||||
|
"lng_settings_cloud_login_email_section_title" = "Login Email";
|
||||||
|
"lng_settings_cloud_login_email_box_about" = "This email address will be used every time you log in to your Telegram account from a new device.";
|
||||||
|
"lng_settings_cloud_login_email_box_ok" = "Change email";
|
||||||
|
"lng_settings_cloud_login_email_title" = "Enter New Email";
|
||||||
|
"lng_settings_cloud_login_email_placeholder" = "Enter Login Email";
|
||||||
|
"lng_settings_cloud_login_email_about" = "You will receive Telegram login codes via email and not SMS. Please enter an email address to which you have access.";
|
||||||
|
"lng_settings_cloud_login_email_confirm" = "Confirm";
|
||||||
|
"lng_settings_cloud_login_email_code_title" = "Check Your New Email";
|
||||||
|
"lng_settings_cloud_login_email_code_about" = "Please enter the code we have sent to your new email {email}";
|
||||||
|
"lng_settings_cloud_login_email_success" = "Your email has been changed.";
|
||||||
|
"lng_settings_error_email_not_alowed" = "Sorry, this email is not allowed";
|
||||||
|
|
||||||
"lng_settings_ttl_title" = "Auto-Delete Messages";
|
"lng_settings_ttl_title" = "Auto-Delete Messages";
|
||||||
"lng_settings_ttl_about" = "Automatically delete messages for everyone after a period of time in all new chats you start.";
|
"lng_settings_ttl_about" = "Automatically delete messages for everyone after a period of time in all new chats you start.";
|
||||||
"lng_settings_ttl_after" = "After {after_duration}";
|
"lng_settings_ttl_after" = "After {after_duration}";
|
||||||
|
@ -1179,6 +1197,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_settings_restart_now" = "Restart";
|
"lng_settings_restart_now" = "Restart";
|
||||||
"lng_settings_restart_later" = "Later";
|
"lng_settings_restart_later" = "Later";
|
||||||
|
|
||||||
|
"lng_settings_quick_dialog_action_title" = "Chat list quick action";
|
||||||
|
"lng_settings_quick_dialog_action_about" = "Choose the action you want to perform when you middle-click or swipe left in the chat list.";
|
||||||
|
"lng_settings_quick_dialog_action_both" = "Swipe left and Middle-click";
|
||||||
|
"lng_settings_quick_dialog_action_swipe" = "Swipe left";
|
||||||
|
"lng_settings_quick_dialog_action_mute" = "Mute";
|
||||||
|
"lng_settings_quick_dialog_action_unmute" = "Unmute";
|
||||||
|
"lng_settings_quick_dialog_action_pin" = "Pin";
|
||||||
|
"lng_settings_quick_dialog_action_unpin" = "Unpin";
|
||||||
|
"lng_settings_quick_dialog_action_read" = "Read";
|
||||||
|
"lng_settings_quick_dialog_action_unread" = "Unread";
|
||||||
|
"lng_settings_quick_dialog_action_archive" = "Archive";
|
||||||
|
"lng_settings_quick_dialog_action_unarchive" = "Unarchive";
|
||||||
|
"lng_settings_quick_dialog_action_delete" = "Delete";
|
||||||
|
"lng_settings_quick_dialog_action_disabled" = "Change folder";
|
||||||
|
|
||||||
|
"lng_quick_dialog_action_toast_mute_success" = "Notifications for this chat have been muted.";
|
||||||
|
"lng_quick_dialog_action_toast_unmute_success" = "Notifications enabled for this chat.";
|
||||||
|
"lng_quick_dialog_action_toast_pin_success" = "The chat has been pinned.";
|
||||||
|
"lng_quick_dialog_action_toast_unpin_success" = "The chat has been unpinned.";
|
||||||
|
"lng_quick_dialog_action_toast_read_success" = "The chat has been marked as read.";
|
||||||
|
"lng_quick_dialog_action_toast_unread_success" = "The chat has been marked as unread.";
|
||||||
|
"lng_quick_dialog_action_toast_archive_success" = "The chat has been archived.";
|
||||||
|
"lng_quick_dialog_action_toast_unarchive_success" = "The chat has been unarchived.";
|
||||||
|
|
||||||
|
"lng_settings_generic_subscribe" = "Subscribe to {link} to use this setting.";
|
||||||
|
"lng_settings_generic_subscribe_link" = "Telegram Premium";
|
||||||
|
|
||||||
"lng_sessions_header" = "This device";
|
"lng_sessions_header" = "This device";
|
||||||
"lng_sessions_other_header" = "Active Devices";
|
"lng_sessions_other_header" = "Active Devices";
|
||||||
"lng_sessions_other_desc" = "You can log in to Telegram from other mobile, tablet and desktop devices, using the same phone number. All your data will be instantly synchronized.";
|
"lng_sessions_other_desc" = "You can log in to Telegram from other mobile, tablet and desktop devices, using the same phone number. All your data will be instantly synchronized.";
|
||||||
|
@ -1218,6 +1263,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_edit_privacy_contacts" = "My contacts";
|
"lng_edit_privacy_contacts" = "My contacts";
|
||||||
"lng_edit_privacy_close_friends" = "Close friends";
|
"lng_edit_privacy_close_friends" = "Close friends";
|
||||||
"lng_edit_privacy_contacts_and_premium" = "Contacts & Premium";
|
"lng_edit_privacy_contacts_and_premium" = "Contacts & Premium";
|
||||||
|
"lng_edit_privacy_paid" = "Paid";
|
||||||
"lng_edit_privacy_contacts_and_miniapps" = "Contacts & Mini Apps";
|
"lng_edit_privacy_contacts_and_miniapps" = "Contacts & Mini Apps";
|
||||||
"lng_edit_privacy_nobody" = "Nobody";
|
"lng_edit_privacy_nobody" = "Nobody";
|
||||||
"lng_edit_privacy_premium" = "Premium users";
|
"lng_edit_privacy_premium" = "Premium users";
|
||||||
|
@ -1293,6 +1339,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_edit_privacy_gifts_always_title" = "Always allow";
|
"lng_edit_privacy_gifts_always_title" = "Always allow";
|
||||||
"lng_edit_privacy_gifts_never_title" = "Never allow";
|
"lng_edit_privacy_gifts_never_title" = "Never allow";
|
||||||
|
|
||||||
|
"lng_edit_privacy_gifts_types" = "Accepted Gift Types";
|
||||||
|
"lng_edit_privacy_gifts_premium" = "Premium Subscriptions";
|
||||||
|
"lng_edit_privacy_gifts_unlimited" = "Unlimited";
|
||||||
|
"lng_edit_privacy_gifts_limited" = "Limited-Edition";
|
||||||
|
"lng_edit_privacy_gifts_unique" = "Unique";
|
||||||
|
"lng_edit_privacy_gifts_types_about" = "Choose the types of gifts that you accept.";
|
||||||
|
"lng_edit_privacy_gifts_show_icon" = "Show Gift Icon in Chats";
|
||||||
|
"lng_edit_privacy_gifts_show_icon_about" = "Display the {emoji}Gift icon in the message input field for both participants in all chats.";
|
||||||
|
"lng_edit_privacy_gifts_restricted" = "This user doesn't accept gifts.";
|
||||||
|
|
||||||
"lng_edit_privacy_calls_title" = "Calls";
|
"lng_edit_privacy_calls_title" = "Calls";
|
||||||
"lng_edit_privacy_calls_header" = "Who can call me";
|
"lng_edit_privacy_calls_header" = "Who can call me";
|
||||||
"lng_edit_privacy_calls_always_empty" = "Always allow";
|
"lng_edit_privacy_calls_always_empty" = "Always allow";
|
||||||
|
@ -1356,6 +1412,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_messages_privacy_premium_about" = "Subscribe now to change this setting and get access to other exclusive features of Telegram Premium.";
|
"lng_messages_privacy_premium_about" = "Subscribe now to change this setting and get access to other exclusive features of Telegram Premium.";
|
||||||
"lng_messages_privacy_premium" = "Only subscribers of {link} can select this option.";
|
"lng_messages_privacy_premium" = "Only subscribers of {link} can select this option.";
|
||||||
"lng_messages_privacy_premium_link" = "Telegram Premium";
|
"lng_messages_privacy_premium_link" = "Telegram Premium";
|
||||||
|
"lng_messages_privacy_charge" = "Charge for messages";
|
||||||
|
"lng_messages_privacy_charge_about" = "Charge a fee for messages from people outside your contacts or those you haven't messaged first.";
|
||||||
|
"lng_messages_privacy_price" = "Set your price per message";
|
||||||
|
"lng_messages_privacy_price_about" = "You will receive {percent} of the selected fee ({amount}) for each incoming message.";
|
||||||
|
"lng_messages_privacy_exceptions" = "Exceptions";
|
||||||
|
"lng_messages_privacy_remove_fee" = "Remove Fee";
|
||||||
|
"lng_messages_privacy_remove_about" = "Add users or entire groups who won't be charged for sending messages to you.";
|
||||||
|
|
||||||
"lng_self_destruct_title" = "Account self-destruction";
|
"lng_self_destruct_title" = "Account self-destruction";
|
||||||
"lng_self_destruct_description" = "If you don't come online at least once within this period, your account will be deleted along with all groups, messages and contacts.";
|
"lng_self_destruct_description" = "If you don't come online at least once within this period, your account will be deleted along with all groups, messages and contacts.";
|
||||||
|
@ -2158,6 +2221,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_action_boost_apply#other" = "{from} boosted the group {count} times";
|
"lng_action_boost_apply#other" = "{from} boosted the group {count} times";
|
||||||
"lng_action_set_chat_intro" = "{from} added the message below for all empty chats. How?";
|
"lng_action_set_chat_intro" = "{from} added the message below for all empty chats. How?";
|
||||||
"lng_action_payment_refunded" = "{peer} refunded {amount}";
|
"lng_action_payment_refunded" = "{peer} refunded {amount}";
|
||||||
|
"lng_action_paid_message_sent#one" = "You paid {count} Star to {action}";
|
||||||
|
"lng_action_paid_message_sent#other" = "You paid {count} Stars to {action}";
|
||||||
|
"lng_action_paid_message_one" = "send a message";
|
||||||
|
"lng_action_paid_message_some#one" = "send {count} message";
|
||||||
|
"lng_action_paid_message_some#other" = "send {count} messages";
|
||||||
|
"lng_action_paid_message_got#one" = "You received {count} Star from {name}";
|
||||||
|
"lng_action_paid_message_got#other" = "You received {count} Stars from {name}";
|
||||||
|
"lng_action_paid_message_refund#one" = "{from} refunded {count} Star to you";
|
||||||
|
"lng_action_paid_message_refund#other" = "{from} refunded {count} Stars to you";
|
||||||
|
"lng_action_paid_message_refund_self#one" = "You refunded {count} Star to {name}";
|
||||||
|
"lng_action_paid_message_refund_self#other" = "You refunded {count} Stars to {name}";
|
||||||
|
"lng_action_message_price_free" = "Messages are now free in this group.";
|
||||||
|
"lng_action_message_price_paid#one" = "Messages now cost {count} Star each in this group.";
|
||||||
|
"lng_action_message_price_paid#other" = "Messages now cost {count} Stars each in this group.";
|
||||||
|
"lng_you_paid_stars#one" = "You paid {count} Star.";
|
||||||
|
"lng_you_paid_stars#other" = "You paid {count} Stars.";
|
||||||
|
|
||||||
|
"lng_you_joined_group" = "You joined this group";
|
||||||
|
|
||||||
"lng_similar_channels_title" = "Similar channels";
|
"lng_similar_channels_title" = "Similar channels";
|
||||||
"lng_similar_channels_view_all" = "View all";
|
"lng_similar_channels_view_all" = "View all";
|
||||||
|
@ -2175,6 +2256,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_peer_gifts_title" = "Gifts";
|
"lng_peer_gifts_title" = "Gifts";
|
||||||
"lng_peer_gifts_about" = "These gifts were sent to {user} by other users.";
|
"lng_peer_gifts_about" = "These gifts were sent to {user} by other users.";
|
||||||
"lng_peer_gifts_about_mine" = "These gifts were sent to you by other users. Click on a gift to convert it to Stars or change its privacy settings.";
|
"lng_peer_gifts_about_mine" = "These gifts were sent to you by other users. Click on a gift to convert it to Stars or change its privacy settings.";
|
||||||
|
"lng_peer_gifts_empty_search" = "No matching gifts";
|
||||||
|
"lng_peer_gifts_view_all" = "View All Gifts";
|
||||||
"lng_peer_gifts_notify" = "Notify About New Gifts";
|
"lng_peer_gifts_notify" = "Notify About New Gifts";
|
||||||
"lng_peer_gifts_notify_enabled" = "You will receive a message from Telegram when your channel receives a gift.";
|
"lng_peer_gifts_notify_enabled" = "You will receive a message from Telegram when your channel receives a gift.";
|
||||||
"lng_peer_gifts_filter_by_value" = "Sort by Value";
|
"lng_peer_gifts_filter_by_value" = "Sort by Value";
|
||||||
|
@ -2664,6 +2747,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_credits_summary_history_entry_inner_in" = "In-App Purchase";
|
"lng_credits_summary_history_entry_inner_in" = "In-App Purchase";
|
||||||
"lng_credits_summary_balance" = "Balance";
|
"lng_credits_summary_balance" = "Balance";
|
||||||
"lng_credits_commission" = "{amount} commission";
|
"lng_credits_commission" = "{amount} commission";
|
||||||
|
"lng_credits_paid_messages_fee#one" = "Fee for {count} Message";
|
||||||
|
"lng_credits_paid_messages_fee#other" = "Fee for {count} Messages";
|
||||||
|
"lng_credits_paid_messages_fee_about" = "You receive {percent} of the price that you charge for each incoming message. {link}";
|
||||||
|
"lng_credits_paid_messages_fee_about_link" = "Change Fee {emoji}";
|
||||||
|
"lng_credits_paid_messages_full" = "Full Price";
|
||||||
|
"lng_credits_premium_gift_duration" = "Duration";
|
||||||
"lng_credits_more_options" = "More Options";
|
"lng_credits_more_options" = "More Options";
|
||||||
"lng_credits_balance_me" = "your balance";
|
"lng_credits_balance_me" = "your balance";
|
||||||
"lng_credits_buy_button" = "Buy More Stars";
|
"lng_credits_buy_button" = "Buy More Stars";
|
||||||
|
@ -2741,6 +2830,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_credits_box_history_entry_reaction_name" = "Star Reaction";
|
"lng_credits_box_history_entry_reaction_name" = "Star Reaction";
|
||||||
"lng_credits_box_history_entry_subscription" = "Monthly subscription fee";
|
"lng_credits_box_history_entry_subscription" = "Monthly subscription fee";
|
||||||
"lng_credits_box_history_entry_gift_upgrade" = "Collectible Upgrade";
|
"lng_credits_box_history_entry_gift_upgrade" = "Collectible Upgrade";
|
||||||
|
"lng_credits_box_history_entry_gift_sold" = "Gift Sale";
|
||||||
|
"lng_credits_box_history_entry_gift_bought" = "Gift Purchase";
|
||||||
|
"lng_credits_box_history_entry_gift_sold_to" = "To";
|
||||||
|
"lng_credits_box_history_entry_gift_full_price" = "Full Price";
|
||||||
|
"lng_credits_box_history_entry_gift_bought_from" = "From";
|
||||||
|
|
||||||
"lng_credits_subscription_section" = "My subscriptions";
|
"lng_credits_subscription_section" = "My subscriptions";
|
||||||
"lng_credits_box_subscription_title" = "Subscription";
|
"lng_credits_box_subscription_title" = "Subscription";
|
||||||
|
@ -2777,6 +2871,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_credits_small_balance_reaction" = "Buy **Stars** and send them to {channel} to support their posts.";
|
"lng_credits_small_balance_reaction" = "Buy **Stars** and send them to {channel} to support their posts.";
|
||||||
"lng_credits_small_balance_subscribe" = "Buy **Stars** and subscribe to **{channel}** and other channels.";
|
"lng_credits_small_balance_subscribe" = "Buy **Stars** and subscribe to **{channel}** and other channels.";
|
||||||
"lng_credits_small_balance_star_gift" = "Buy **Stars** to send gifts to {user} and other contacts.";
|
"lng_credits_small_balance_star_gift" = "Buy **Stars** to send gifts to {user} and other contacts.";
|
||||||
|
"lng_credits_small_balance_for_message" = "Buy **Stars** to send messages to {user}.";
|
||||||
|
"lng_credits_small_balance_for_messages" = "Buy **Stars** to send messages.";
|
||||||
"lng_credits_small_balance_fallback" = "Buy **Stars** to unlock content and services on Telegram.";
|
"lng_credits_small_balance_fallback" = "Buy **Stars** to unlock content and services on Telegram.";
|
||||||
"lng_credits_purchase_blocked" = "Sorry, you can't purchase this item with Telegram Stars.";
|
"lng_credits_purchase_blocked" = "Sorry, you can't purchase this item with Telegram Stars.";
|
||||||
"lng_credits_enough" = "You have enough stars at the moment. {link}";
|
"lng_credits_enough" = "You have enough stars at the moment. {link}";
|
||||||
|
@ -2881,8 +2977,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_chatbots_include_button" = "Select Chats";
|
"lng_chatbots_include_button" = "Select Chats";
|
||||||
"lng_chatbots_exclude_about" = "Select chats or entire chat categories which the bot will not have access to.";
|
"lng_chatbots_exclude_about" = "Select chats or entire chat categories which the bot will not have access to.";
|
||||||
"lng_chatbots_permissions_title" = "Bot permissions";
|
"lng_chatbots_permissions_title" = "Bot permissions";
|
||||||
|
"lng_chatbots_warning_title" = "Warning";
|
||||||
|
"lng_chatbots_warning_both_text" = "The bot {bot} will be able to **manage your gifts and stars**, including giving them away to other users.";
|
||||||
|
"lng_chatbots_warning_gifts_text" = "The bot {bot} will be able to **manage your gifts**, including giving them away to other users.";
|
||||||
|
"lng_chatbots_warning_stars_text" = "The bot {bot} will be able to **transfer your stars**.";
|
||||||
|
"lng_chatbots_warning_username_text" = "The bot {bot} will be able to **set and remove usernames** for your account, which may result in the loss of your current username.";
|
||||||
|
|
||||||
|
"lng_chatbots_manage_messages" = "Manage Messages";
|
||||||
|
"lng_chatbots_read" = "Read Messages";
|
||||||
"lng_chatbots_reply" = "Reply to Messages";
|
"lng_chatbots_reply" = "Reply to Messages";
|
||||||
"lng_chatbots_reply_about" = "The bot can only reply on your behalf in chats that were active during the last 24h.";
|
"lng_chatbots_mark_as_read" = "Mark Messages as Read";
|
||||||
|
"lng_chatbots_delete_sent" = "Delete Sent Messages";
|
||||||
|
"lng_chatbots_delete_received" = "Delete Received Messages";
|
||||||
|
|
||||||
|
"lng_chatbots_manage_profile" = "Manage Profile";
|
||||||
|
"lng_chatbots_edit_name" = "Edit Name";
|
||||||
|
"lng_chatbots_edit_bio" = "Edit Bio";
|
||||||
|
"lng_chatbots_edit_userpic" = "Edit Profile Picture";
|
||||||
|
"lng_chatbots_edit_username" = "Edit Username";
|
||||||
|
|
||||||
|
"lng_chatbots_manage_gifts" = "Manage Gifts and Stars";
|
||||||
|
"lng_chatbots_view_gifts" = "View Gifts";
|
||||||
|
"lng_chatbots_sell_gifts" = "Sell Gifts";
|
||||||
|
"lng_chatbots_gift_settings" = "Change Gift Settings";
|
||||||
|
"lng_chatbots_transfer_gifts" = "Transfer and Upgrade Gifts";
|
||||||
|
"lng_chatbots_transfer_stars" = "Transfer Stars";
|
||||||
|
|
||||||
|
"lng_chatbots_manage_stories" = "Manage Stories";
|
||||||
|
|
||||||
"lng_chatbots_remove" = "Remove Bot";
|
"lng_chatbots_remove" = "Remove Bot";
|
||||||
"lng_chatbots_not_found" = "Chatbot not found.";
|
"lng_chatbots_not_found" = "Chatbot not found.";
|
||||||
"lng_chatbots_not_supported" = "This bot doesn't support Telegram Business yet.";
|
"lng_chatbots_not_supported" = "This bot doesn't support Telegram Business yet.";
|
||||||
|
@ -3050,6 +3172,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_boost_group_ask" = "Ask your **Premium** members to boost your group with this link:";
|
"lng_boost_group_ask" = "Ask your **Premium** members to boost your group with this link:";
|
||||||
//"lng_boost_group_gifting" = "Boost your group by gifting your members Telegram Premium. {link}";
|
//"lng_boost_group_gifting" = "Boost your group by gifting your members Telegram Premium. {link}";
|
||||||
|
|
||||||
|
"lng_boost_channel_title_autotranslate" = "Autotranslation of Messages";
|
||||||
|
"lng_boost_channel_needs_level_autotranslate#one" = "Your channel needs to reach **Level {count}** to enable autotranslation of messages.";
|
||||||
|
"lng_boost_channel_needs_level_autotranslate#other" = "Your channel needs to reach **Level {count}** to enable autotranslation of messages.";
|
||||||
|
|
||||||
"lng_feature_stories#one" = "**{count}** Story Per Day";
|
"lng_feature_stories#one" = "**{count}** Story Per Day";
|
||||||
"lng_feature_stories#other" = "**{count}** Stories Per Day";
|
"lng_feature_stories#other" = "**{count}** Stories Per Day";
|
||||||
"lng_feature_reactions#one" = "**{count}** Custom Reaction";
|
"lng_feature_reactions#one" = "**{count}** Custom Reaction";
|
||||||
|
@ -3068,6 +3194,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_feature_custom_background_group" = "Custom Group Background";
|
"lng_feature_custom_background_group" = "Custom Group Background";
|
||||||
"lng_feature_custom_emoji_pack" = "Custom Emoji Pack";
|
"lng_feature_custom_emoji_pack" = "Custom Emoji Pack";
|
||||||
"lng_feature_transcribe" = "Voice-to-Text Conversion";
|
"lng_feature_transcribe" = "Voice-to-Text Conversion";
|
||||||
|
"lng_feature_autotranslate" = "Autotranslation of Messages";
|
||||||
|
|
||||||
"lng_giveaway_new_title" = "Boosts via Gifts";
|
"lng_giveaway_new_title" = "Boosts via Gifts";
|
||||||
"lng_giveaway_new_about" = "Get more boosts for your channel by gifting Premium to your subscribers.";
|
"lng_giveaway_new_about" = "Get more boosts for your channel by gifting Premium to your subscribers.";
|
||||||
|
@ -3310,19 +3437,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_premium_about" = "Give {name} access to exclusive features with Telegram Premium. {features}";
|
"lng_gift_premium_about" = "Give {name} access to exclusive features with Telegram Premium. {features}";
|
||||||
"lng_gift_premium_features" = "See Features >";
|
"lng_gift_premium_features" = "See Features >";
|
||||||
"lng_gift_premium_label" = "Premium";
|
"lng_gift_premium_label" = "Premium";
|
||||||
|
"lng_gift_premium_by_stars" = "or {amount}";
|
||||||
"lng_gift_stars_subtitle" = "Gift Stars";
|
"lng_gift_stars_subtitle" = "Gift Stars";
|
||||||
"lng_gift_stars_about" = "Give {name} gifts that can be kept on your profile or converted to Stars. {link}";
|
"lng_gift_stars_about" = "Give {name} gifts that can be kept on your profile or converted to Stars. {link}";
|
||||||
"lng_gift_stars_link" = "What are Stars >";
|
"lng_gift_stars_link" = "What are Stars >";
|
||||||
"lng_gift_stars_limited" = "limited";
|
"lng_gift_stars_limited" = "limited";
|
||||||
"lng_gift_stars_sold_out" = "sold out";
|
"lng_gift_stars_sold_out" = "sold out";
|
||||||
|
"lng_gift_stars_resale" = "resale";
|
||||||
|
"lng_gift_stars_on_sale" = "on sale";
|
||||||
"lng_gift_stars_tabs_all" = "All Gifts";
|
"lng_gift_stars_tabs_all" = "All Gifts";
|
||||||
|
"lng_gift_stars_tabs_my" = "My Gifts";
|
||||||
"lng_gift_stars_tabs_limited" = "Limited";
|
"lng_gift_stars_tabs_limited" = "Limited";
|
||||||
"lng_gift_stars_tabs_in_stock" = "In Stock";
|
"lng_gift_stars_tabs_in_stock" = "In Stock";
|
||||||
|
"lng_gift_stars_tabs_resale" = "Resale";
|
||||||
"lng_gift_send_title" = "Send a Gift";
|
"lng_gift_send_title" = "Send a Gift";
|
||||||
"lng_gift_send_message" = "Enter Message";
|
"lng_gift_send_message" = "Enter Message";
|
||||||
"lng_gift_send_anonymous" = "Hide My Name";
|
"lng_gift_send_anonymous" = "Hide My Name";
|
||||||
|
"lng_gift_send_pay_with_stars" = "Pay with {amount}";
|
||||||
|
"lng_gift_send_stars_balance" = "Your balance is {amount}. {link}";
|
||||||
|
"lng_gift_send_stars_balance_link" = "Get More Stars >";
|
||||||
"lng_gift_send_anonymous_self" = "Hide my name and message from visitors to my profile.";
|
"lng_gift_send_anonymous_self" = "Hide my name and message from visitors to my profile.";
|
||||||
"lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message.";
|
"lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message.";
|
||||||
|
"lng_gift_send_anonymous_about_paid" = "You can hide your name from visitors to {user}'s profile. {recipient} will still see your name.";
|
||||||
"lng_gift_send_anonymous_about_channel" = "You can hide your name and message from all visitors of this channel except its admins.";
|
"lng_gift_send_anonymous_about_channel" = "You can hide your name and message from all visitors of this channel except its admins.";
|
||||||
"lng_gift_send_unique" = "Make Unique for {price}";
|
"lng_gift_send_unique" = "Make Unique for {price}";
|
||||||
"lng_gift_send_unique_about" = "Enable this to let {user} turn your gift into a unique collectible. {link}";
|
"lng_gift_send_unique_about" = "Enable this to let {user} turn your gift into a unique collectible. {link}";
|
||||||
|
@ -3335,13 +3471,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_send_limited_left#other" = "{count} left";
|
"lng_gift_send_limited_left#other" = "{count} left";
|
||||||
"lng_gift_send_button" = "Send a Gift for {cost}";
|
"lng_gift_send_button" = "Send a Gift for {cost}";
|
||||||
"lng_gift_send_button_self" = "Buy a Gift for {cost}";
|
"lng_gift_send_button_self" = "Buy a Gift for {cost}";
|
||||||
|
"lng_gift_buy_resale_title" = "Buy {name}";
|
||||||
|
"lng_gift_buy_resale_button" = "Buy for {cost}";
|
||||||
|
"lng_gift_buy_resale_confirm" = "Do you want to buy {name} for {price} and gift it to {user}?";
|
||||||
|
"lng_gift_buy_resale_confirm_self" = "Do you want to buy {name} for {price}?";
|
||||||
|
"lng_gift_buy_price_change_title" = "Price change!";
|
||||||
|
"lng_gift_buy_price_change_text" = "This gift price was changed and now is {price}. Do you still want to buy?";
|
||||||
"lng_gift_sent_title" = "Gift Sent!";
|
"lng_gift_sent_title" = "Gift Sent!";
|
||||||
|
"lng_gift_sent_resale_done" = "{user} has been notified about your gift.";
|
||||||
|
"lng_gift_sent_resale_done_self" = "{gift} is now yours.";
|
||||||
"lng_gift_sent_about#one" = "You spent **{count}** Star from your balance.";
|
"lng_gift_sent_about#one" = "You spent **{count}** Star from your balance.";
|
||||||
"lng_gift_sent_about#other" = "You spent **{count}** Stars from your balance.";
|
"lng_gift_sent_about#other" = "You spent **{count}** Stars from your balance.";
|
||||||
"lng_gift_limited_of_one" = "unique";
|
"lng_gift_limited_of_one" = "unique";
|
||||||
"lng_gift_limited_of_count" = "1 of {amount}";
|
"lng_gift_limited_of_count" = "1 of {amount}";
|
||||||
"lng_gift_collectible_tag" = "gift";
|
"lng_gift_collectible_tag" = "gift";
|
||||||
"lng_gift_price_unique" = "Unique";
|
|
||||||
"lng_gift_view_unpack" = "Unpack";
|
"lng_gift_view_unpack" = "Unpack";
|
||||||
"lng_gift_anonymous_hint" = "Only you can see the sender's name.";
|
"lng_gift_anonymous_hint" = "Only you can see the sender's name.";
|
||||||
"lng_gift_anonymous_hint_channel" = "Only admins of this channel can see the sender's name.";
|
"lng_gift_anonymous_hint_channel" = "Only admins of this channel can see the sender's name.";
|
||||||
|
@ -3357,6 +3500,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_show_on_channel" = "Display in channel's Gifts";
|
"lng_gift_show_on_channel" = "Display in channel's Gifts";
|
||||||
"lng_gift_availability" = "Availability";
|
"lng_gift_availability" = "Availability";
|
||||||
"lng_gift_from_hidden" = "Hidden User";
|
"lng_gift_from_hidden" = "Hidden User";
|
||||||
|
"lng_gift_subtitle_birthdays" = "Birthdays";
|
||||||
|
"lng_gift_list_birthday_status_today" = "{emoji} Birthday today";
|
||||||
|
"lng_gift_list_birthday_status_yesterday" = "Birthday yesterday";
|
||||||
|
"lng_gift_list_birthday_status_tomorrow" = "Birthday tomorrow";
|
||||||
"lng_gift_self_status" = "buy yourself a gift";
|
"lng_gift_self_status" = "buy yourself a gift";
|
||||||
"lng_gift_self_title" = "Buy a Gift";
|
"lng_gift_self_title" = "Buy a Gift";
|
||||||
"lng_gift_self_about" = "Buy yourself a gift to display on your page or reserve for later.\n\nLimited-edition gifts upgraded to collectibles can be gifted to others later.";
|
"lng_gift_self_about" = "Buy yourself a gift to display on your page or reserve for later.\n\nLimited-edition gifts upgraded to collectibles can be gifted to others later.";
|
||||||
|
@ -3398,6 +3545,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_display_done_channel" = "The gift is now shown in channel's Gifts.";
|
"lng_gift_display_done_channel" = "The gift is now shown in channel's Gifts.";
|
||||||
"lng_gift_display_done_hide" = "The gift is now hidden from your profile page.";
|
"lng_gift_display_done_hide" = "The gift is now hidden from your profile page.";
|
||||||
"lng_gift_display_done_hide_channel" = "The gift is now hidden from channel's Gifts.";
|
"lng_gift_display_done_hide_channel" = "The gift is now hidden from channel's Gifts.";
|
||||||
|
"lng_gift_pinned_done_title" = "{gift} pinned";
|
||||||
|
"lng_gift_pinned_done" = "The gift will always be shown on top.";
|
||||||
|
"lng_gift_pinned_done_replaced" = "replacing {gift}";
|
||||||
"lng_gift_got_stars#one" = "You got **{count} Star** for this gift.";
|
"lng_gift_got_stars#one" = "You got **{count} Star** for this gift.";
|
||||||
"lng_gift_got_stars#other" = "You got **{count} Stars** for this gift.";
|
"lng_gift_got_stars#other" = "You got **{count} Stars** for this gift.";
|
||||||
"lng_gift_channel_got#one" = "Channel got **{count} Star** for this gift.";
|
"lng_gift_channel_got#one" = "Channel got **{count} Star** for this gift.";
|
||||||
|
@ -3456,6 +3606,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_transfer_button_for" = "Transfer for {price}";
|
"lng_gift_transfer_button_for" = "Transfer for {price}";
|
||||||
"lng_gift_transfer_wear" = "Wear";
|
"lng_gift_transfer_wear" = "Wear";
|
||||||
"lng_gift_transfer_take_off" = "Take Off";
|
"lng_gift_transfer_take_off" = "Take Off";
|
||||||
|
"lng_gift_transfer_sell" = "Sell";
|
||||||
|
"lng_gift_transfer_update" = "Change Price";
|
||||||
|
"lng_gift_transfer_unlist" = "Unlist";
|
||||||
|
"lng_gift_sell_unlist_title" = "Unlist {name}";
|
||||||
|
"lng_gift_sell_unlist_sure" = "Are you sure you want to unlist your gift?";
|
||||||
|
"lng_gift_sell_title" = "Price in Stars";
|
||||||
|
"lng_gift_sell_placeholder" = "Enter price in Stars";
|
||||||
|
"lng_gift_sell_about" = "You will receive {percent} of the selected amount.";
|
||||||
|
"lng_gift_sell_amount#one" = "You will receive **{count}** Star.";
|
||||||
|
"lng_gift_sell_amount#other" = "You will receive **{count}** Stars.";
|
||||||
|
"lng_gift_sell_min_price#one" = "Minimum price is {count} Star.";
|
||||||
|
"lng_gift_sell_min_price#other" = "Minimum price is {count} Stars.";
|
||||||
|
"lng_gift_sell_put" = "Put for Sale";
|
||||||
|
"lng_gift_sell_update" = "Update the Price";
|
||||||
|
"lng_gift_sell_toast" = "{name} is now for sale!";
|
||||||
|
"lng_gift_sell_updated" = "Sale price for {name} was updated.";
|
||||||
|
"lng_gift_sell_removed" = "{name} is removed from sale.";
|
||||||
|
"lng_gift_menu_show" = "Show";
|
||||||
|
"lng_gift_menu_hide" = "Hide";
|
||||||
"lng_gift_wear_title" = "Wear {name}";
|
"lng_gift_wear_title" = "Wear {name}";
|
||||||
"lng_gift_wear_about" = "and get these benefits:";
|
"lng_gift_wear_about" = "and get these benefits:";
|
||||||
"lng_gift_wear_badge_title" = "Radiant Badge";
|
"lng_gift_wear_badge_title" = "Radiant Badge";
|
||||||
|
@ -3468,6 +3637,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_wear_subscribe" = "Subscribe to {link} to wear collectibles.";
|
"lng_gift_wear_subscribe" = "Subscribe to {link} to wear collectibles.";
|
||||||
"lng_gift_wear_start_toast" = "You put on {name}";
|
"lng_gift_wear_start_toast" = "You put on {name}";
|
||||||
"lng_gift_wear_end_toast" = "You took off {name}";
|
"lng_gift_wear_end_toast" = "You took off {name}";
|
||||||
|
"lng_gift_many_pinned_title" = "Too Many Pinned Gifts";
|
||||||
|
"lng_gift_many_pinned_choose" = "Select a gift to unpin below";
|
||||||
|
"lng_gift_resale_price" = "Price";
|
||||||
|
"lng_gift_resale_number" = "Number";
|
||||||
|
"lng_gift_resale_date" = "Date";
|
||||||
|
"lng_gift_resale_count#one" = "{count} gift in resale";
|
||||||
|
"lng_gift_resale_count#other" = "{count} gifts in resale";
|
||||||
|
"lng_gift_resale_sort_price" = "Sort by Price";
|
||||||
|
"lng_gift_resale_sort_date" = "Sort by Date";
|
||||||
|
"lng_gift_resale_sort_number" = "Sort by Number";
|
||||||
|
"lng_gift_resale_filter_all" = "Select All";
|
||||||
|
"lng_gift_resale_model" = "Model";
|
||||||
|
"lng_gift_resale_models#one" = "{count} Model";
|
||||||
|
"lng_gift_resale_models#other" = "{count} Models";
|
||||||
|
"lng_gift_resale_backdrop" = "Backdrop";
|
||||||
|
"lng_gift_resale_backdrops#one" = "{count} Backdrop";
|
||||||
|
"lng_gift_resale_backdrops#other" = "{count} Backdrops";
|
||||||
|
"lng_gift_resale_symbol" = "Symbol";
|
||||||
|
"lng_gift_resale_symbols#one" = "{count} Symbol";
|
||||||
|
"lng_gift_resale_symbols#other" = "{count} Symbols";
|
||||||
|
"lng_gift_resale_early" = "You will be able to resell this gift in {duration}.";
|
||||||
|
"lng_gift_transfer_early" = "You will be able to transfer this gift in {duration}.";
|
||||||
|
"lng_gift_resale_transfer_early_title" = "Try Later";
|
||||||
|
|
||||||
"lng_accounts_limit_title" = "Limit Reached";
|
"lng_accounts_limit_title" = "Limit Reached";
|
||||||
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected account.";
|
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected account.";
|
||||||
|
@ -3583,6 +3775,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_restrict_users" = "Restrict users";
|
"lng_restrict_users" = "Restrict users";
|
||||||
"lng_delete_all_from_user" = "Delete all from {user}";
|
"lng_delete_all_from_user" = "Delete all from {user}";
|
||||||
"lng_delete_all_from_users" = "Delete all from users";
|
"lng_delete_all_from_users" = "Delete all from users";
|
||||||
|
"lng_restrict_user#one" = "Restrict user";
|
||||||
|
"lng_restrict_user#other" = "Restrict users";
|
||||||
"lng_restrict_user_part" = "Partially restrict this user {emoji}";
|
"lng_restrict_user_part" = "Partially restrict this user {emoji}";
|
||||||
"lng_restrict_users_part" = "Partially restrict users {emoji}";
|
"lng_restrict_users_part" = "Partially restrict users {emoji}";
|
||||||
"lng_restrict_user_full" = "Fully ban this user {emoji}";
|
"lng_restrict_user_full" = "Fully ban this user {emoji}";
|
||||||
|
@ -3609,6 +3803,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_new_contact_from_request_group" = "{user} is an admin of {name}, a group you requested to join.";
|
"lng_new_contact_from_request_group" = "{user} is an admin of {name}, a group you requested to join.";
|
||||||
"lng_new_contact_about_status" = "This account uses {emoji} as a custom status next to its\nname. Such emoji statuses are available to all\nsubscribers of {link}.";
|
"lng_new_contact_about_status" = "This account uses {emoji} as a custom status next to its\nname. Such emoji statuses are available to all\nsubscribers of {link}.";
|
||||||
"lng_new_contact_about_status_link" = "Telegram Premium";
|
"lng_new_contact_about_status_link" = "Telegram Premium";
|
||||||
|
"lng_new_contact_not_contact" = "Not a contact";
|
||||||
|
"lng_new_contact_phone_number" = "Phone number";
|
||||||
|
"lng_new_contact_registration" = "Registration";
|
||||||
|
"lng_new_contact_common_groups" = "Common groups";
|
||||||
|
"lng_new_contact_groups#one" = "{count} group {emoji} {arrow}";
|
||||||
|
"lng_new_contact_groups#other" = "{count} groups {emoji} {arrow}";
|
||||||
|
"lng_new_contact_not_official" = "Not an official account";
|
||||||
|
"lng_new_contact_updated_name" = "User updated name {when}";
|
||||||
|
"lng_new_contact_updated_photo" = "User updated photo {when}";
|
||||||
|
"lng_new_contact_updated_now" = "less than an hour ago";
|
||||||
|
"lng_new_contact_updated_hours#one" = "{count} hour ago";
|
||||||
|
"lng_new_contact_updated_hours#other" = "{count} hours ago";
|
||||||
|
"lng_new_contact_updated_days#one" = "{count} day ago";
|
||||||
|
"lng_new_contact_updated_days#other" = "{count} days ago";
|
||||||
|
"lng_new_contact_updated_months#one" = "{count} month ago";
|
||||||
|
"lng_new_contact_updated_months#other" = "{count} months ago";
|
||||||
"lng_from_request_title_channel" = "Response to your join request";
|
"lng_from_request_title_channel" = "Response to your join request";
|
||||||
"lng_from_request_title_group" = "Response to your join request";
|
"lng_from_request_title_group" = "Response to your join request";
|
||||||
"lng_from_request_body" = "You received this message because you requested to join {name} on {date}.";
|
"lng_from_request_body" = "You received this message because you requested to join {name} on {date}.";
|
||||||
|
@ -3637,6 +3847,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_send_anonymous_ph" = "Send anonymously...";
|
"lng_send_anonymous_ph" = "Send anonymously...";
|
||||||
"lng_story_reply_ph" = "Reply privately...";
|
"lng_story_reply_ph" = "Reply privately...";
|
||||||
"lng_story_comment_ph" = "Comment story...";
|
"lng_story_comment_ph" = "Comment story...";
|
||||||
|
"lng_message_paid_ph" = "Message for {amount}";
|
||||||
"lng_send_text_no" = "Text not allowed.";
|
"lng_send_text_no" = "Text not allowed.";
|
||||||
"lng_send_text_no_about" = "The admins of this group only allow sending {types}.";
|
"lng_send_text_no_about" = "The admins of this group only allow sending {types}.";
|
||||||
"lng_send_text_type_and_last" = "{types} and {last}";
|
"lng_send_text_type_and_last" = "{types} and {last}";
|
||||||
|
@ -3743,6 +3954,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_dialogs_skip_archive_in_search" = "Skip results from archive";
|
"lng_dialogs_skip_archive_in_search" = "Skip results from archive";
|
||||||
"lng_dialogs_show_archive_in_search" = "With results from archive";
|
"lng_dialogs_show_archive_in_search" = "With results from archive";
|
||||||
|
|
||||||
|
"lng_dialogs_suggestions_birthday_title" = "Add your birthday! 🎂";
|
||||||
|
"lng_dialogs_suggestions_birthday_about" = "Let your contacts know when you’re celebrating.";
|
||||||
|
"lng_dialogs_suggestions_birthday_contact_title" = "It’s {text}'s **birthday** today! 🎂";
|
||||||
|
"lng_dialogs_suggestions_birthday_contact_about" = "Send them a Gift.";
|
||||||
|
"lng_dialogs_suggestions_birthday_contacts_title#one" = "{count} contact have **birthdays** today! 🎂";
|
||||||
|
"lng_dialogs_suggestions_birthday_contacts_title#other" = "{count} contacts have **birthdays** today! 🎂";
|
||||||
|
"lng_dialogs_suggestions_birthday_contacts_about" = "Send them a Gift.";
|
||||||
|
"lng_dialogs_suggestions_birthday_contact_dismiss" = "You can send a Gift later in Settings";
|
||||||
|
"lng_dialogs_suggestions_premium_annual_title" = "Telegram Premium with a {text} discount";
|
||||||
|
"lng_dialogs_suggestions_premium_annual_about" = "Sign up for the annual payment plan for Telegram Premium now to get the discount.";
|
||||||
|
"lng_dialogs_suggestions_premium_upgrade_title" = "Telegram Premium with a {text} discount";
|
||||||
|
"lng_dialogs_suggestions_premium_upgrade_about" = "Upgrade to the annual payment plan for Telegram Premium now to get the discount.";
|
||||||
|
"lng_dialogs_suggestions_premium_restore_title" = "Get Premium back with up to {text} off";
|
||||||
|
"lng_dialogs_suggestions_premium_restore_about" = "Your Telegram Premium has recently expired. Tap here to extend it.";
|
||||||
|
"lng_dialogs_suggestions_premium_grace_title" = "⚠️ Your Premium subscription is expiring!";
|
||||||
|
"lng_dialogs_suggestions_premium_grace_about" = "Don’t lose access to exclusive features.";
|
||||||
|
"lng_dialogs_suggestions_userpics_title" = "Add your photo! 📸";
|
||||||
|
"lng_dialogs_suggestions_userpics_about" = "Help your friends spot you easily.";
|
||||||
|
"lng_dialogs_suggestions_credits_sub_low_title#one" = "{emoji} {count} Star needed for {channels}";
|
||||||
|
"lng_dialogs_suggestions_credits_sub_low_title#other" = "{emoji} {count} Stars needed for {channels}";
|
||||||
|
"lng_dialogs_suggestions_credits_sub_low_about" = "Insufficient funds to cover your subscription.";
|
||||||
|
|
||||||
"lng_about_random" = "Send a {emoji} emoji to any chat to try your luck.";
|
"lng_about_random" = "Send a {emoji} emoji to any chat to try your luck.";
|
||||||
"lng_about_random_send" = "Send";
|
"lng_about_random_send" = "Send";
|
||||||
|
|
||||||
|
@ -4080,6 +4313,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_sensitive_toast" = "You can update the visibility of sensitive media in **Settings > Chat Settings > Sensitive content**";
|
"lng_sensitive_toast" = "You can update the visibility of sensitive media in **Settings > Chat Settings > Sensitive content**";
|
||||||
|
|
||||||
"lng_translate_show_original" = "Show Original";
|
"lng_translate_show_original" = "Show Original";
|
||||||
|
"lng_translate_return_original" = "View Original ({language})";
|
||||||
"lng_translate_bar_to" = "Translate to {name}";
|
"lng_translate_bar_to" = "Translate to {name}";
|
||||||
"lng_translate_bar_to_other" = "Translate to {name}";
|
"lng_translate_bar_to_other" = "Translate to {name}";
|
||||||
"lng_translate_menu_to" = "Translate To";
|
"lng_translate_menu_to" = "Translate To";
|
||||||
|
@ -4187,6 +4421,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_edit_contact_title" = "Edit contact";
|
"lng_edit_contact_title" = "Edit contact";
|
||||||
"lng_edit_channel_title" = "Edit channel";
|
"lng_edit_channel_title" = "Edit channel";
|
||||||
"lng_edit_bot_title" = "Edit bot";
|
"lng_edit_bot_title" = "Edit bot";
|
||||||
|
"lng_edit_autotranslate" = "Auto-translate messages";
|
||||||
"lng_edit_sign_messages" = "Sign messages";
|
"lng_edit_sign_messages" = "Sign messages";
|
||||||
"lng_edit_sign_messages_about" = "Add names of admins to the messages they post.";
|
"lng_edit_sign_messages_about" = "Add names of admins to the messages they post.";
|
||||||
"lng_edit_sign_profiles" = "Show authors' profiles";
|
"lng_edit_sign_profiles" = "Show authors' profiles";
|
||||||
|
@ -4281,6 +4516,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_search_filter_private" = "Private chats";
|
"lng_search_filter_private" = "Private chats";
|
||||||
"lng_search_filter_group" = "Group chats";
|
"lng_search_filter_group" = "Group chats";
|
||||||
"lng_search_filter_channel" = "Channels";
|
"lng_search_filter_channel" = "Channels";
|
||||||
|
"lng_search_sponsored_button" = "Ad ⋮";
|
||||||
|
|
||||||
"lng_media_save_progress" = "{ready} of {total} {mb}";
|
"lng_media_save_progress" = "{ready} of {total} {mb}";
|
||||||
"lng_mediaview_save_as" = "Save As...";
|
"lng_mediaview_save_as" = "Save As...";
|
||||||
|
@ -4494,6 +4730,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_call_status_failed" = "failed to connect";
|
"lng_call_status_failed" = "failed to connect";
|
||||||
"lng_call_status_ringing" = "ringing...";
|
"lng_call_status_ringing" = "ringing...";
|
||||||
"lng_call_status_busy" = "line busy";
|
"lng_call_status_busy" = "line busy";
|
||||||
|
"lng_call_status_group_invite" = "Telegram Group Call";
|
||||||
"lng_call_status_sure" = "Click on the Camera icon if you want to start a video call.";
|
"lng_call_status_sure" = "Click on the Camera icon if you want to start a video call.";
|
||||||
"lng_call_fingerprint_tooltip" = "If the emoji on {user}'s screen are the same, this call is 100% secure";
|
"lng_call_fingerprint_tooltip" = "If the emoji on {user}'s screen are the same, this call is 100% secure";
|
||||||
|
|
||||||
|
@ -4503,6 +4740,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_call_error_camera_not_started" = "You can switch to video call once you're connected.";
|
"lng_call_error_camera_not_started" = "You can switch to video call once you're connected.";
|
||||||
"lng_call_error_camera_outdated" = "{user}'s app does not support video calls. They need to update their app before you can call them.";
|
"lng_call_error_camera_outdated" = "{user}'s app does not support video calls. They need to update their app before you can call them.";
|
||||||
"lng_call_error_audio_io" = "There seems to be a problem with your sound card. Please make sure that your computer's speakers and microphone are working and try again.";
|
"lng_call_error_audio_io" = "There seems to be a problem with your sound card. Please make sure that your computer's speakers and microphone are working and try again.";
|
||||||
|
"lng_call_error_add_not_started" = "You can add more people once you're connected.";
|
||||||
|
|
||||||
"lng_call_bar_hangup" = "End call";
|
"lng_call_bar_hangup" = "End call";
|
||||||
"lng_call_leave_to_other_sure" = "End your active call and join this video chat?";
|
"lng_call_leave_to_other_sure" = "End your active call and join this video chat?";
|
||||||
|
@ -4521,16 +4759,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
"lng_call_outgoing" = "Outgoing call";
|
"lng_call_outgoing" = "Outgoing call";
|
||||||
"lng_call_video_outgoing" = "Outgoing video call";
|
"lng_call_video_outgoing" = "Outgoing video call";
|
||||||
|
"lng_call_group_outgoing" = "Outgoing group call";
|
||||||
"lng_call_incoming" = "Incoming call";
|
"lng_call_incoming" = "Incoming call";
|
||||||
"lng_call_video_incoming" = "Incoming video call";
|
"lng_call_video_incoming" = "Incoming video call";
|
||||||
|
"lng_call_group_incoming" = "Incoming group call";
|
||||||
"lng_call_missed" = "Missed call";
|
"lng_call_missed" = "Missed call";
|
||||||
"lng_call_video_missed" = "Missed video call";
|
"lng_call_video_missed" = "Missed video call";
|
||||||
|
"lng_call_group_missed" = "Missed group call";
|
||||||
"lng_call_cancelled" = "Canceled call";
|
"lng_call_cancelled" = "Canceled call";
|
||||||
"lng_call_video_cancelled" = "Canceled video call";
|
"lng_call_video_cancelled" = "Canceled video call";
|
||||||
"lng_call_declined" = "Declined call";
|
"lng_call_declined" = "Declined call";
|
||||||
"lng_call_video_declined" = "Declined video call";
|
"lng_call_video_declined" = "Declined video call";
|
||||||
|
"lng_call_group_declined" = "Declined group call";
|
||||||
"lng_call_duration_info" = "{time}, {duration}";
|
"lng_call_duration_info" = "{time}, {duration}";
|
||||||
"lng_call_type_and_duration" = "{type} ({duration})";
|
"lng_call_type_and_duration" = "{type} ({duration})";
|
||||||
|
"lng_call_invitation" = "Group call invitation";
|
||||||
|
"lng_call_ongoing" = "Ongoing group call";
|
||||||
|
|
||||||
"lng_call_rate_label" = "Please rate the quality of your call";
|
"lng_call_rate_label" = "Please rate the quality of your call";
|
||||||
"lng_call_rate_comment" = "Comment (optional)";
|
"lng_call_rate_comment" = "Comment (optional)";
|
||||||
|
@ -4539,6 +4783,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_call_start_video" = "Start Video";
|
"lng_call_start_video" = "Start Video";
|
||||||
"lng_call_stop_video" = "Stop Video";
|
"lng_call_stop_video" = "Stop Video";
|
||||||
"lng_call_screencast" = "Screencast";
|
"lng_call_screencast" = "Screencast";
|
||||||
|
"lng_call_add_people" = "Add People";
|
||||||
"lng_call_end_call" = "End Call";
|
"lng_call_end_call" = "End Call";
|
||||||
"lng_call_mute_audio" = "Mute";
|
"lng_call_mute_audio" = "Mute";
|
||||||
"lng_call_unmute_audio" = "Unmute";
|
"lng_call_unmute_audio" = "Unmute";
|
||||||
|
@ -4570,8 +4815,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_group_call_connecting" = "Connecting...";
|
"lng_group_call_connecting" = "Connecting...";
|
||||||
"lng_group_call_leave" = "Leave";
|
"lng_group_call_leave" = "Leave";
|
||||||
"lng_group_call_leave_title" = "Leave video chat";
|
"lng_group_call_leave_title" = "Leave video chat";
|
||||||
|
"lng_group_call_leave_title_call" = "Leave group call";
|
||||||
"lng_group_call_leave_title_channel" = "Leave live stream";
|
"lng_group_call_leave_title_channel" = "Leave live stream";
|
||||||
"lng_group_call_leave_sure" = "Do you want to leave this video chat?";
|
"lng_group_call_leave_sure" = "Do you want to leave this video chat?";
|
||||||
|
"lng_group_call_leave_sure_call" = "Do you want to leave this group call?";
|
||||||
"lng_group_call_leave_sure_channel" = "Are you sure you want to leave this live stream?";
|
"lng_group_call_leave_sure_channel" = "Are you sure you want to leave this live stream?";
|
||||||
"lng_group_call_close" = "Close";
|
"lng_group_call_close" = "Close";
|
||||||
"lng_group_call_close_sure" = "Video chat is scheduled. You can abort it or just close this panel.";
|
"lng_group_call_close_sure" = "Video chat is scheduled. You can abort it or just close this panel.";
|
||||||
|
@ -4601,15 +4848,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_group_call_also_end_channel" = "End live stream";
|
"lng_group_call_also_end_channel" = "End live stream";
|
||||||
"lng_group_call_settings_title" = "Settings";
|
"lng_group_call_settings_title" = "Settings";
|
||||||
"lng_group_call_invite" = "Invite Members";
|
"lng_group_call_invite" = "Invite Members";
|
||||||
|
"lng_group_call_invite_conf" = "Add People";
|
||||||
"lng_group_call_invited_status" = "invited";
|
"lng_group_call_invited_status" = "invited";
|
||||||
|
"lng_group_call_calling_status" = "calling...";
|
||||||
|
"lng_group_call_blockchain_only_status" = "listening";
|
||||||
"lng_group_call_muted_by_me_status" = "muted for you";
|
"lng_group_call_muted_by_me_status" = "muted for you";
|
||||||
"lng_group_call_invite_title" = "Invite members";
|
"lng_group_call_invite_title" = "Invite members";
|
||||||
"lng_group_call_invite_button" = "Invite";
|
"lng_group_call_invite_button" = "Invite";
|
||||||
|
"lng_group_call_confcall_add" = "Call";
|
||||||
"lng_group_call_add_to_group_one" = "{user} isn't a member of «{group}». Add them to the group?";
|
"lng_group_call_add_to_group_one" = "{user} isn't a member of «{group}». Add them to the group?";
|
||||||
"lng_group_call_add_to_group_some" = "Some of those users aren't members of «{group}». Add them to the group?";
|
"lng_group_call_add_to_group_some" = "Some of those users aren't members of «{group}». Add them to the group?";
|
||||||
"lng_group_call_add_to_group_all" = "Those users aren't members of «{group}». Add them to the group?";
|
"lng_group_call_add_to_group_all" = "Those users aren't members of «{group}». Add them to the group?";
|
||||||
"lng_group_call_invite_members" = "Group members";
|
"lng_group_call_invite_members" = "Group members";
|
||||||
"lng_group_call_invite_search_results" = "Search results";
|
"lng_group_call_invite_search_results" = "Search results";
|
||||||
|
"lng_group_call_invite_limit" = "This is currently the maximum allowed number of participants.";
|
||||||
"lng_group_call_new_muted" = "Mute new participants";
|
"lng_group_call_new_muted" = "Mute new participants";
|
||||||
"lng_group_call_speakers" = "Speakers";
|
"lng_group_call_speakers" = "Speakers";
|
||||||
"lng_group_call_microphone" = "Microphone";
|
"lng_group_call_microphone" = "Microphone";
|
||||||
|
@ -4648,6 +4900,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_group_call_context_pin_screen" = "Pin screencast";
|
"lng_group_call_context_pin_screen" = "Pin screencast";
|
||||||
"lng_group_call_context_unpin_screen" = "Unpin screencast";
|
"lng_group_call_context_unpin_screen" = "Unpin screencast";
|
||||||
"lng_group_call_context_remove" = "Remove";
|
"lng_group_call_context_remove" = "Remove";
|
||||||
|
"lng_group_call_context_cancel_invite" = "Discard invite";
|
||||||
|
"lng_group_call_context_stop_ringing" = "Stop calling";
|
||||||
|
"lng_group_call_context_ban_from_call" = "Ban from call";
|
||||||
"lng_group_call_remove_channel" = "Remove {channel} from the video chat and ban them?";
|
"lng_group_call_remove_channel" = "Remove {channel} from the video chat and ban them?";
|
||||||
"lng_group_call_remove_channel_from_channel" = "Remove {channel} from the live stream?";
|
"lng_group_call_remove_channel_from_channel" = "Remove {channel} from the live stream?";
|
||||||
"lng_group_call_mac_access" = "Telegram Desktop does not have access to system wide keyboard input required for Push to Talk.";
|
"lng_group_call_mac_access" = "Telegram Desktop does not have access to system wide keyboard input required for Push to Talk.";
|
||||||
|
@ -4756,6 +5011,54 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_group_call_rtmp_viewers#one" = "{count} viewer";
|
"lng_group_call_rtmp_viewers#one" = "{count} viewer";
|
||||||
"lng_group_call_rtmp_viewers#other" = "{count} viewers";
|
"lng_group_call_rtmp_viewers#other" = "{count} viewers";
|
||||||
|
|
||||||
|
"lng_confcall_join_title" = "Group Call";
|
||||||
|
"lng_confcall_join_text" = "You are invited to join a Telegram Call.";
|
||||||
|
"lng_confcall_join_text_inviter" = "{user} is inviting you to join a Telegram Call.";
|
||||||
|
"lng_confcall_already_joined_one" = "{user} already joined this call.";
|
||||||
|
"lng_confcall_already_joined_two" = "{user} and {other} already joined this call.";
|
||||||
|
"lng_confcall_already_joined_three" = "{user}, {other} and {third} already joined this call.";
|
||||||
|
"lng_confcall_already_joined_many#one" = "{user}, {other} and **{count}** other person already joined this call.";
|
||||||
|
"lng_confcall_already_joined_many#other" = "{user}, {other} and **{count}** other people already joined this call.";
|
||||||
|
"lng_confcall_join_button" = "Join Group Call";
|
||||||
|
"lng_confcall_create_call" = "Start New Call";
|
||||||
|
"lng_confcall_create_call_description#one" = "You can add up to {count} participant to a call.";
|
||||||
|
"lng_confcall_create_call_description#other" = "You can add up to {count} participants to a call.";
|
||||||
|
"lng_confcall_create_title" = "New Call";
|
||||||
|
"lng_confcall_create_link" = "Create Call Link";
|
||||||
|
"lng_confcall_create_link_description" = "You can create a link that will allow your friends on Telegram to join the call.";
|
||||||
|
"lng_confcall_link_revoke" = "Revoke link";
|
||||||
|
"lng_confcall_link_revoked_title" = "Link Revoked";
|
||||||
|
"lng_confcall_link_inactive" = "This link is no longer active.";
|
||||||
|
"lng_confcall_link_revoked_text" = "A new link has been generated.";
|
||||||
|
"lng_confcall_link_title" = "Call Link";
|
||||||
|
"lng_confcall_link_about" = "Anyone on Telegram can join your call by following the link below.";
|
||||||
|
"lng_confcall_link_or" = "or";
|
||||||
|
"lng_confcall_link_join" = "Be the first to join the call and add people from there. {link}";
|
||||||
|
"lng_confcall_link_join_link" = "Open call {arrow}";
|
||||||
|
"lng_confcall_inactive_title" = "Start Group Call";
|
||||||
|
"lng_confcall_inactive_about" = "This call is no longer active.\nYou can start a new one.";
|
||||||
|
"lng_confcall_invite_done_user" = "You're calling {user} to join.";
|
||||||
|
"lng_confcall_invite_done_many#one" = "You're calling **{count} person** to join.";
|
||||||
|
"lng_confcall_invite_done_many#other" = "You're calling **{count} people** to join.";
|
||||||
|
"lng_confcall_invite_already_user" = "{user} is already in the call.";
|
||||||
|
"lng_confcall_invite_already_many#one" = "**{count} person** is already in the call.";
|
||||||
|
"lng_confcall_invite_already_many#other" = "**{count} people** are already in the call.";
|
||||||
|
"lng_confcall_invite_privacy_user" = "You cannot call {user} because of their privacy settings.";
|
||||||
|
"lng_confcall_invite_privacy_many#one" = "You cannot call **{count} person** because of their privacy settings.";
|
||||||
|
"lng_confcall_invite_privacy_many#other" = "You cannot call **{count} people** because of their privacy settings.";
|
||||||
|
"lng_confcall_invite_fail_user" = "Couldn't call {user} to join.";
|
||||||
|
"lng_confcall_invite_fail_many#one" = "Couldn't call **{count} person** to join.";
|
||||||
|
"lng_confcall_invite_fail_many#other" = "Couldn't call **{count} people** to join.";
|
||||||
|
"lng_confcall_invite_kicked_user" = "{user} was banned from the call.";
|
||||||
|
"lng_confcall_invite_kicked_many#one" = "**{count} person** was removed from the call.";
|
||||||
|
"lng_confcall_invite_kicked_many#other" = "**{count} people** were removed from the call.";
|
||||||
|
"lng_confcall_not_accessible" = "This call is no longer accessible.";
|
||||||
|
"lng_confcall_participants_limit" = "This call reached the participants limit.";
|
||||||
|
"lng_confcall_sure_remove" = "Remove {user} from the call?";
|
||||||
|
"lng_confcall_e2e_badge" = "End-to-End Encrypted";
|
||||||
|
"lng_confcall_e2e_badge_small" = "E2E Encrypted";
|
||||||
|
"lng_confcall_e2e_about" = "These four emoji represent the call's encryption key. They must match for all participants and change when someone joins or leaves.";
|
||||||
|
|
||||||
"lng_no_mic_permission" = "Telegram needs microphone access so that you can make calls and record voice messages.";
|
"lng_no_mic_permission" = "Telegram needs microphone access so that you can make calls and record voice messages.";
|
||||||
|
|
||||||
"lng_player_message_today" = "today at {time}";
|
"lng_player_message_today" = "today at {time}";
|
||||||
|
@ -4798,6 +5101,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_rights_boosts_no_restrict" = "Do not restrict boosters";
|
"lng_rights_boosts_no_restrict" = "Do not restrict boosters";
|
||||||
"lng_rights_boosts_about" = "Turn this on to always allow users who boosted your group to send messages and media.";
|
"lng_rights_boosts_about" = "Turn this on to always allow users who boosted your group to send messages and media.";
|
||||||
"lng_rights_boosts_about_on" = "Choose how many boosts a user must give to the group to bypass restrictions on sending messages.";
|
"lng_rights_boosts_about_on" = "Choose how many boosts a user must give to the group to bypass restrictions on sending messages.";
|
||||||
|
"lng_rights_charge_stars" = "Charge Stars for Messages";
|
||||||
|
"lng_rights_charge_stars_about" = "If you turn this on, regular members of the group will have to pay Stars to send messages.";
|
||||||
|
"lng_rights_charge_price" = "Set price per message";
|
||||||
|
"lng_rights_charge_price_about" = "Your group will receive {percent} of the selected fee ({amount}) for each incoming message.";
|
||||||
|
|
||||||
"lng_slowmode_enabled" = "Slow Mode is active.\nYou can send your next message in {left}.";
|
"lng_slowmode_enabled" = "Slow Mode is active.\nYou 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_no_many" = "Slow mode is enabled. You can't send more than one message at a time.";
|
||||||
|
@ -4805,6 +5112,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_slowmode_seconds#one" = "{count} second";
|
"lng_slowmode_seconds#one" = "{count} second";
|
||||||
"lng_slowmode_seconds#other" = "{count} seconds";
|
"lng_slowmode_seconds#other" = "{count} seconds";
|
||||||
|
|
||||||
|
"lng_payment_confirm_title" = "Confirm payment";
|
||||||
|
"lng_payment_confirm_text#one" = "{name} charges **{count}** Star per message.";
|
||||||
|
"lng_payment_confirm_text#other" = "{name} charges **{count}** Stars per message.";
|
||||||
|
"lng_payment_confirm_amount#one" = "**{count}** Star";
|
||||||
|
"lng_payment_confirm_amount#other" = "**{count}** Stars";
|
||||||
|
"lng_payment_confirm_users#one" = "You selected **{count}** user who charge Stars for messages.";
|
||||||
|
"lng_payment_confirm_users#other" = "You selected **{count}** users who charge Stars for messages.";
|
||||||
|
"lng_payment_confirm_chats#one" = "You selected **{count}** chat where you pay Stars for messages.";
|
||||||
|
"lng_payment_confirm_chats#other" = "You selected **{count}** chats where you pay Stars for messages.";
|
||||||
|
"lng_payment_confirm_sure#one" = "Would you like to pay {amount} to send **{count}** message?";
|
||||||
|
"lng_payment_confirm_sure#other" = "Would you like to pay {amount} to send **{count}** messages?";
|
||||||
|
"lng_payment_confirm_dont_ask" = "Don't ask me again";
|
||||||
|
"lng_payment_confirm_button#one" = "Pay for {count} Message";
|
||||||
|
"lng_payment_confirm_button#other" = "Pay for {count} Messages";
|
||||||
|
"lng_payment_bar_text" = "{name} must pay {cost} for each message to you.";
|
||||||
|
"lng_payment_bar_button" = "Remove Fee";
|
||||||
|
"lng_payment_refund_title" = "Remove Fee";
|
||||||
|
"lng_payment_refund_text" = "Are you sure you want to allow {name} to message you for free?";
|
||||||
|
"lng_payment_refund_also#one" = "Refund already paid {count} Star";
|
||||||
|
"lng_payment_refund_also#other" = "Refund already paid {count} Stars";
|
||||||
|
"lng_payment_refund_confirm" = "Confirm";
|
||||||
|
|
||||||
"lng_rights_gigagroup_title" = "Broadcast group";
|
"lng_rights_gigagroup_title" = "Broadcast group";
|
||||||
"lng_rights_gigagroup_convert" = "Convert to Broadcast Group";
|
"lng_rights_gigagroup_convert" = "Convert to Broadcast Group";
|
||||||
"lng_rights_gigagroup_about" = "Broadcast groups can have over 200,000 members, but only admins can send messages in them.";
|
"lng_rights_gigagroup_about" = "Broadcast groups can have over 200,000 members, but only admins can send messages in them.";
|
||||||
|
@ -4936,6 +5265,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_send_non_premium_message_toast" = "**{user}** only accepts messages from contacts and {link} subscribers.";
|
"lng_send_non_premium_message_toast" = "**{user}** only accepts messages from contacts and {link} subscribers.";
|
||||||
"lng_send_non_premium_message_toast_link" = "Telegram Premium";
|
"lng_send_non_premium_message_toast_link" = "Telegram Premium";
|
||||||
|
|
||||||
|
"lng_send_charges_stars_text" = "{user} charges {amount} for each message.";
|
||||||
|
"lng_send_charges_stars_go" = "Buy Stars";
|
||||||
|
|
||||||
"lng_exceptions_list_title" = "Exceptions";
|
"lng_exceptions_list_title" = "Exceptions";
|
||||||
"lng_removed_list_title" = "Removed users";
|
"lng_removed_list_title" = "Removed users";
|
||||||
|
|
||||||
|
@ -4946,10 +5278,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_admin_log_filter_all_actions" = "All actions";
|
"lng_admin_log_filter_all_actions" = "All actions";
|
||||||
"lng_admin_log_filter_actions_type_subtitle" = "Filter actions by type";
|
"lng_admin_log_filter_actions_type_subtitle" = "Filter actions by type";
|
||||||
"lng_admin_log_filter_actions_member_section" = "Members And Admins";
|
"lng_admin_log_filter_actions_member_section" = "Members And Admins";
|
||||||
|
"lng_admin_log_filter_actions_subscriber_section" = "Subscribers And Admins";
|
||||||
"lng_admin_log_filter_restrictions" = "New restrictions";
|
"lng_admin_log_filter_restrictions" = "New restrictions";
|
||||||
"lng_admin_log_filter_admins_new" = "Admin rights";
|
"lng_admin_log_filter_admins_new" = "Admin rights";
|
||||||
"lng_admin_log_filter_members_new" = "New members";
|
"lng_admin_log_filter_members_new" = "New members";
|
||||||
|
"lng_admin_log_filter_subscribers_new" = "New subscribers";
|
||||||
"lng_admin_log_filter_actions_settings_section" = "Group Settings";
|
"lng_admin_log_filter_actions_settings_section" = "Group Settings";
|
||||||
|
"lng_admin_log_filter_actions_channel_settings_section" = "Channel Settings";
|
||||||
"lng_admin_log_filter_info_group" = "Group info";
|
"lng_admin_log_filter_info_group" = "Group info";
|
||||||
"lng_admin_log_filter_info_channel" = "Channel info";
|
"lng_admin_log_filter_info_channel" = "Channel info";
|
||||||
"lng_admin_log_filter_actions_messages_section" = "Messages";
|
"lng_admin_log_filter_actions_messages_section" = "Messages";
|
||||||
|
@ -4960,6 +5295,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_admin_log_filter_voice_chats_channel" = "Live stream";
|
"lng_admin_log_filter_voice_chats_channel" = "Live stream";
|
||||||
"lng_admin_log_filter_invite_links" = "Invite links";
|
"lng_admin_log_filter_invite_links" = "Invite links";
|
||||||
"lng_admin_log_filter_members_removed" = "Members leaving";
|
"lng_admin_log_filter_members_removed" = "Members leaving";
|
||||||
|
"lng_admin_log_filter_subscribers_removed" = "Subscribers leaving";
|
||||||
"lng_admin_log_filter_topics" = "Topics";
|
"lng_admin_log_filter_topics" = "Topics";
|
||||||
"lng_admin_log_filter_sub_extend" = "Subscription Renewals";
|
"lng_admin_log_filter_sub_extend" = "Subscription Renewals";
|
||||||
"lng_admin_log_filter_all_admins" = "All users and admins";
|
"lng_admin_log_filter_all_admins" = "All users and admins";
|
||||||
|
@ -5070,6 +5406,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_admin_log_participant_volume_channel" = "{from} changed live stream volume for {user} to {percent}";
|
"lng_admin_log_participant_volume_channel" = "{from} changed live stream volume for {user} to {percent}";
|
||||||
"lng_admin_log_antispam_enabled" = "{from} enabled aggressive anti-spam";
|
"lng_admin_log_antispam_enabled" = "{from} enabled aggressive anti-spam";
|
||||||
"lng_admin_log_antispam_disabled" = "{from} disabled aggressive anti-spam";
|
"lng_admin_log_antispam_disabled" = "{from} disabled aggressive anti-spam";
|
||||||
|
"lng_admin_log_autotranslate_enabled" = "{from} enabled automatic translation";
|
||||||
|
"lng_admin_log_autotranslate_disabled" = "{from} disabled automatic translation";
|
||||||
"lng_admin_log_change_color" = "{from} changed channel color from {previous} to {color}";
|
"lng_admin_log_change_color" = "{from} changed channel color from {previous} to {color}";
|
||||||
"lng_admin_log_set_background_emoji" = "{from} set channel background emoji to {emoji}";
|
"lng_admin_log_set_background_emoji" = "{from} set channel background emoji to {emoji}";
|
||||||
"lng_admin_log_change_background_emoji" = "{from} changed channel background emoji from {previous} to {emoji}";
|
"lng_admin_log_change_background_emoji" = "{from} changed channel background emoji from {previous} to {emoji}";
|
||||||
|
@ -5653,6 +5991,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_view_button_stickerset" = "View stickers";
|
"lng_view_button_stickerset" = "View stickers";
|
||||||
"lng_view_button_emojipack" = "View emoji";
|
"lng_view_button_emojipack" = "View emoji";
|
||||||
"lng_view_button_collectible" = "View collectible";
|
"lng_view_button_collectible" = "View collectible";
|
||||||
|
"lng_view_button_call" = "Join call";
|
||||||
|
|
||||||
"lng_sponsored_hide_ads" = "Hide";
|
"lng_sponsored_hide_ads" = "Hide";
|
||||||
"lng_sponsored_title" = "What are sponsored messages?";
|
"lng_sponsored_title" = "What are sponsored messages?";
|
||||||
|
@ -5666,6 +6005,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_sponsored_revenued_info1_title" = "Respect Your Privacy";
|
"lng_sponsored_revenued_info1_title" = "Respect Your Privacy";
|
||||||
"lng_sponsored_revenued_info1_description" = "Ads on Telegram do not use your personal information and are based on the channel in which you see them.";
|
"lng_sponsored_revenued_info1_description" = "Ads on Telegram do not use your personal information and are based on the channel in which you see them.";
|
||||||
"lng_sponsored_revenued_info1_bot_description" = "Ads on Telegram do not use your personal information and are based on the mini app in which you see them.";
|
"lng_sponsored_revenued_info1_bot_description" = "Ads on Telegram do not use your personal information and are based on the mini app in which you see them.";
|
||||||
|
"lng_sponsored_revenued_info1_search_description" = "Ads on Telegram do not use your personal information and are based on the search query you entered.";
|
||||||
"lng_sponsored_revenued_info2_title" = "Help the Channel Creator";
|
"lng_sponsored_revenued_info2_title" = "Help the Channel Creator";
|
||||||
"lng_sponsored_revenued_info2_bot_title" = "Help the Bot Developer";
|
"lng_sponsored_revenued_info2_bot_title" = "Help the Bot Developer";
|
||||||
"lng_sponsored_revenued_info2_description" = "50% of the revenue from Telegram Ads goes to the owner of the channel where they are displayed.";
|
"lng_sponsored_revenued_info2_description" = "50% of the revenue from Telegram Ads goes to the owner of the channel where they are displayed.";
|
||||||
|
@ -5674,9 +6014,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_sponsored_revenued_info3_description#one" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers.";
|
"lng_sponsored_revenued_info3_description#one" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers.";
|
||||||
"lng_sponsored_revenued_info3_description#other" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers.";
|
"lng_sponsored_revenued_info3_description#other" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers.";
|
||||||
"lng_sponsored_revenued_info3_bot_description" = "You can turn off ads in mini apps by subscribing to {link}.";
|
"lng_sponsored_revenued_info3_bot_description" = "You can turn off ads in mini apps by subscribing to {link}.";
|
||||||
|
"lng_sponsored_revenued_info3_search_description" = "You can turn off ads by subscribing to Telegram Premium. {link}";
|
||||||
|
"lng_sponsored_revenued_info3_search_link" = "Subscribe {arrow}";
|
||||||
"lng_sponsored_revenued_footer_title" = "Can I Launch an Ad?";
|
"lng_sponsored_revenued_footer_title" = "Can I Launch an Ad?";
|
||||||
"lng_sponsored_revenued_footer_description" = "Anyone can create an ad to display in this channel — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}";
|
"lng_sponsored_revenued_footer_description" = "Anyone can create an ad to display in this channel — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}";
|
||||||
"lng_sponsored_revenued_footer_bot_description" = "Anyone can create an ad to display in this bot — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}";
|
"lng_sponsored_revenued_footer_bot_description" = "Anyone can create an ad to display in this bot — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}";
|
||||||
|
"lng_sponsored_revenued_footer_search_description" = "Anyone can create an ad to display in search results for any query. Check out the **Telegram Ad Platform** for details. {link}";
|
||||||
"lng_sponsored_top_bar_hide" = "remove";
|
"lng_sponsored_top_bar_hide" = "remove";
|
||||||
|
|
||||||
"lng_telegram_features_url" = "https://t.me/TelegramTips";
|
"lng_telegram_features_url" = "https://t.me/TelegramTips";
|
||||||
|
@ -6040,6 +6383,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_bot_earn_chart_revenue" = "Revenue";
|
"lng_bot_earn_chart_revenue" = "Revenue";
|
||||||
"lng_bot_earn_overview_title" = "Proceeds overview";
|
"lng_bot_earn_overview_title" = "Proceeds overview";
|
||||||
"lng_bot_earn_available" = "Available balance";
|
"lng_bot_earn_available" = "Available balance";
|
||||||
|
"lng_bot_earn_reward" = "Total balance";
|
||||||
"lng_bot_earn_total" = "Total lifetime proceeds";
|
"lng_bot_earn_total" = "Total lifetime proceeds";
|
||||||
"lng_bot_earn_balance_title" = "Available balance";
|
"lng_bot_earn_balance_title" = "Available balance";
|
||||||
"lng_bot_earn_balance_about" = "Stars from your total balance can be used for ads or withdrawn as rewards 21 days after they are earned.";
|
"lng_bot_earn_balance_about" = "Stars from your total balance can be used for ads or withdrawn as rewards 21 days after they are earned.";
|
||||||
|
@ -6162,6 +6506,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_qr_box_transparent_background" = "Transparent Background";
|
"lng_qr_box_transparent_background" = "Transparent Background";
|
||||||
"lng_qr_box_font_size" = "Font size";
|
"lng_qr_box_font_size" = "Font size";
|
||||||
|
|
||||||
|
"lng_frozen_bar_title" = "Your account is frozen!";
|
||||||
|
"lng_frozen_bar_text" = "Click to view details {arrow}";
|
||||||
|
"lng_frozen_restrict_title" = "Your account is frozen";
|
||||||
|
"lng_frozen_restrict_text" = "Click to view details";
|
||||||
|
"lng_frozen_title" = "Your Account is Frozen";
|
||||||
|
"lng_frozen_subtitle1" = "Violation of Terms";
|
||||||
|
"lng_frozen_text1" = "Your account was frozen for breaking Telegram's Terms and Conditions.";
|
||||||
|
"lng_frozen_subtitle2" = "Read-Only Mode";
|
||||||
|
"lng_frozen_text2" = "You can access your account but can't send messages or take actions.";
|
||||||
|
"lng_frozen_subtitle3" = "Appeal Before Deactivation";
|
||||||
|
"lng_frozen_text3" = "Appeal via {link} before {date}, or your account will be deleted.";
|
||||||
|
"lng_frozen_appeal_button" = "Submit an Appeal";
|
||||||
|
|
||||||
|
"lng_context_bank_card_copy" = "Copy Card Number";
|
||||||
|
"lng_context_bank_card_copied" = "Card number copied to clipboard.";
|
||||||
|
|
||||||
// Wnd specific
|
// Wnd specific
|
||||||
|
|
||||||
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
||||||
|
@ -6243,38 +6603,41 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"ayu_DontSendOnlinePackets" = "Don't Send Online";
|
"ayu_DontSendOnlinePackets" = "Don't Send Online";
|
||||||
"ayu_DontSendUploadProgress" = "Don't Send Typing";
|
"ayu_DontSendUploadProgress" = "Don't Send Typing";
|
||||||
"ayu_SendOfflinePacketAfterOnline" = "Go Offline Automatically";
|
"ayu_SendOfflinePacketAfterOnline" = "Go Offline Automatically";
|
||||||
"ayu_GhostModeOptionLongTapDescription" = "Long tap on any option to prevent it from changing on toggling Ghost Mode.";
|
"ayu_GhostModeOptionLongTapDescription" = "Long-press any option to prevent it from changing when toggling Ghost Mode.";
|
||||||
"ayu_MarkReadAfterAction" = "Read on Interact";
|
"ayu_MarkReadAfterAction" = "Read on Interact";
|
||||||
"ayu_MarkReadAfterActionDescription" = "Automatically reads message when you send a new one or tap a reaction.";
|
"ayu_MarkReadAfterActionDescription" = "Automatically marks a message as read when you send a new one or tap a reaction.";
|
||||||
"ayu_MarkReadAfterSend" = "Send";
|
"ayu_MarkReadAfterSend" = "Send";
|
||||||
"ayu_MarkReadAfterReaction" = "Reaction";
|
"ayu_MarkReadAfterReaction" = "Reaction";
|
||||||
"ayu_MarkReadAfterPoll" = "Poll";
|
"ayu_MarkReadAfterPoll" = "Poll";
|
||||||
"ayu_UseScheduledMessages" = "Schedule Messages";
|
"ayu_UseScheduledMessages" = "Schedule Messages";
|
||||||
"ayu_UseScheduledMessagesDescription" = "Automatically schedules outgoing messages for ~12 seconds, and more for media. Sending messages this way, you won't appear online.\nDon't use on bad networks.";
|
"ayu_UseScheduledMessagesDescription" = "Automatically schedules outgoing messages to send after ~12 seconds (longer for media). Using this feature, you won't appear online.\nAvoid using on unreliable networks.";
|
||||||
"ayu_SendWithoutSoundByDefault" = "Send without Sound";
|
"ayu_SendWithoutSoundByDefault" = "Send without Sound";
|
||||||
"ayu_SendWithoutSoundByDefaultDescription" = "Automatically sends outgoing messages without sound.";
|
"ayu_SendWithoutSoundByDefaultDescription" = "Sends outgoing messages without sound by default.";
|
||||||
"ayu_SuggestGhostModeBeforeViewingStory" = "Story Ghost Mode Alert";
|
"ayu_SuggestGhostModeBeforeViewingStory" = "Story Ghost Mode Alert";
|
||||||
"ayu_SuggestGhostModeBeforeViewingStoryDescription" = "Shows an alert before opening the story, suggesting to turn on Ghost Mode.";
|
"ayu_SuggestGhostModeBeforeViewingStoryDescription" = "Displays an alert before opening a story, suggesting you enable Ghost Mode.";
|
||||||
"ayu_SpyEssentialsHeader" = "Spy essentials";
|
"ayu_SpyEssentialsHeader" = "Spy essentials";
|
||||||
"ayu_SaveDeletedMessages" = "Save Deleted Messages";
|
"ayu_SaveDeletedMessages" = "Save Deleted Messages";
|
||||||
"ayu_SaveMessagesHistory" = "Save Edits History";
|
"ayu_SaveMessagesHistory" = "Save Edits History";
|
||||||
"ayu_MessageSavingActionBarHeader" = "Message Saving Preferences";
|
"ayu_MessageSavingSaveMedia" = "Save Attachments";
|
||||||
"ayu_MessageSavingSaveMedia" = "Save Media";
|
"ayu_MessageSavingSaveMediaHint" = "Configure chats & limits";
|
||||||
"ayu_MessageSavingSaveMediaHint" = "Click for More";
|
"ayu_MessageSavingSaveMediaInPrivateChats" = "Private Chats";
|
||||||
"ayu_MessageSavingSaveMediaInPrivateChats" = "…in private chats";
|
"ayu_MessageSavingSaveMediaInPublicChannels" = "Public Channels";
|
||||||
"ayu_MessageSavingSaveMediaInPublicChannels" = "…in public channels";
|
"ayu_MessageSavingSaveMediaInPrivateChannels" = "Private Channels";
|
||||||
"ayu_MessageSavingSaveMediaInPrivateChannels" = "…in private channels";
|
"ayu_MessageSavingSaveMediaInPublicGroups" = "Public Groups";
|
||||||
"ayu_MessageSavingSaveMediaInPublicGroups" = "…in public groups";
|
"ayu_MessageSavingSaveMediaInPrivateGroups" = "Private Groups";
|
||||||
"ayu_MessageSavingSaveMediaInPrivateGroups" = "…in private groups";
|
"ayu_MessageSavingSaveMediaHintPopup" = "Make sure it's configured to your needs.";
|
||||||
"ayu_MaximumMediaSizeCellular" = "Media size limit (cellular data)";
|
"ayu_MaximumMediaSizeCellular" = "Media size limit (cellular data)";
|
||||||
"ayu_MaximumMediaSizeWiFi" = "Media size limit (WiFi)";
|
"ayu_MaximumMediaSizeWiFi" = "Media size limit (WiFi)";
|
||||||
"ayu_MessageSavingOtherHeader" = "Other";
|
"ayu_MessageSavingOtherHeader" = "Other";
|
||||||
"ayu_MessageSavingSaveReactions" = "Save reactions";
|
|
||||||
"ayu_MessageSavingSaveForBots" = "Save in Bot Dialogs";
|
"ayu_MessageSavingSaveForBots" = "Save in Bot Dialogs";
|
||||||
"ayu_MessageSavingSavePath" = "Attachments Folder";
|
"ayu_MessageSavingSavePath" = "Attachments Folder";
|
||||||
"ayu_MessageSavingSavePathTitle" = "Choose folder";
|
"ayu_MessageSavingSavePathTitle" = "Choose folder";
|
||||||
"ayu_SpySaveReadMarks" = "Save Read Date";
|
"ayu_SpySaveReadMarks" = "Save Read Date";
|
||||||
"ayu_SpySaveReadMarksDescription" = "Locally saves data about reading messages. This will be shown if Telegram does not provide read date.";
|
"ayu_SpySaveReadMarksDescription" = "Locally saves data about reading messages. This will be shown if Telegram does not provide a read date.";
|
||||||
|
"ayu_SpySaveLocalOnline" = "Save Last Seen Date";
|
||||||
|
"ayu_SpySaveLocalOnlineDescription" = "Saves the last online date for users with hidden online status based on their actions. You'll be able to see **very approximately** when they were last online.";
|
||||||
|
"ayu_ExportDatabaseButton" = "Export Database";
|
||||||
|
"ayu_ImportDatabaseButton" = "Import Database";
|
||||||
"ayu_QoLTogglesHeader" = "Useful features";
|
"ayu_QoLTogglesHeader" = "Useful features";
|
||||||
"ayu_KeepAliveService" = "AyuGram Push Service";
|
"ayu_KeepAliveService" = "AyuGram Push Service";
|
||||||
"ayu_DisableAds" = "Disable Ads";
|
"ayu_DisableAds" = "Disable Ads";
|
||||||
|
@ -6304,7 +6667,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"ayu_SettingsShowID_Hide" = "Hide";
|
"ayu_SettingsShowID_Hide" = "Hide";
|
||||||
"ayu_SettingsShowMessageShot" = "Show Message Shot";
|
"ayu_SettingsShowMessageShot" = "Show Message Shot";
|
||||||
"ayu_SettingsRecentStickersCount" = "Recent Stickers Count";
|
"ayu_SettingsRecentStickersCount" = "Recent Stickers Count";
|
||||||
"ayu_SettingsCustomizationHint" = "After making changes to the \"Customization\" section, you must restart the application.";
|
"ayu_SettingsCustomizationHint" = "You must restart the application after making changes in the \"Customization\" section.";
|
||||||
"ayu_SettingsContextMenuTitle" = "Choose when to show the item";
|
"ayu_SettingsContextMenuTitle" = "Choose when to show the item";
|
||||||
"ayu_SettingsContextMenuDescription" = "Extended menu items will be displayed if you hold CTRL or SHIFT while right-clicking on the message.";
|
"ayu_SettingsContextMenuDescription" = "Extended menu items will be displayed if you hold CTRL or SHIFT while right-clicking on the message.";
|
||||||
"ayu_SettingsContextMenuItemHidden" = "Hidden";
|
"ayu_SettingsContextMenuItemHidden" = "Hidden";
|
||||||
|
@ -6328,7 +6691,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"ayu_SettingsIncreaseWebviewHeight" = "Increase Content Height";
|
"ayu_SettingsIncreaseWebviewHeight" = "Increase Content Height";
|
||||||
"ayu_SettingsIncreaseWebviewWidth" = "Increase Content Width";
|
"ayu_SettingsIncreaseWebviewWidth" = "Increase Content Width";
|
||||||
"ayu_ExportDataTitle" = "Export AyuGram Database?";
|
"ayu_ExportDataTitle" = "Export AyuGram Database?";
|
||||||
"ayu_ExportDataDescription" = "It will be exported to the public folder, to Saved Attachments.";
|
"ayu_ExportDataDescription" = "It will be exported to the public folder under Saved Attachments.";
|
||||||
"ayu_ExportDataConfirm" = "Yes, export";
|
"ayu_ExportDataConfirm" = "Yes, export";
|
||||||
"ayu_ExportDataCancel" = "No, close window";
|
"ayu_ExportDataCancel" = "No, close window";
|
||||||
"ayu_ExportDataSuccess" = "Database exported successfully.";
|
"ayu_ExportDataSuccess" = "Database exported successfully.";
|
||||||
|
@ -6406,11 +6769,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"ayu_IconYaPlus" = "Yandex Plus";
|
"ayu_IconYaPlus" = "Yandex Plus";
|
||||||
"ayu_WALMode" = "Enable WAL mode";
|
"ayu_WALMode" = "Enable WAL mode";
|
||||||
"ayu_PushNotificationCount" = "FCM notifications received";
|
"ayu_PushNotificationCount" = "FCM notifications received";
|
||||||
"ayu_ClearAyuDatabase" = "Clear Messages Database";
|
"ayu_AyuAttachments" = "AyuGram Attachments Folder";
|
||||||
"ayu_ClearAyuAttachmentsNotification" = "AyuGram attachments folder cleared";
|
"ayu_AyuDatabase" = "AyuGram Messages Database";
|
||||||
"ayu_ClearTelegramDatabase" = "Clear Telegram Database";
|
"ayu_TelegramCacheDatabase" = "Telegram Messages Database";
|
||||||
"ayu_ClearAyuDatabaseNotification" = "AyuGram database cleared";
|
|
||||||
"ayu_ClearAyuAttachments" = "Clear Attachments Folder";
|
|
||||||
"ayu_ConfirmationsTitle" = "Confirmations";
|
"ayu_ConfirmationsTitle" = "Confirmations";
|
||||||
"ayu_StickerConfirmation" = "For Stickers";
|
"ayu_StickerConfirmation" = "For Stickers";
|
||||||
"ayu_GIFConfirmation" = "For GIFs";
|
"ayu_GIFConfirmation" = "For GIFs";
|
||||||
|
@ -6478,13 +6839,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"ayu_SuggestGhostModeStoryText" = "Do you want to enable **Ghost Mode** before viewing the story?";
|
"ayu_SuggestGhostModeStoryText" = "Do you want to enable **Ghost Mode** before viewing the story?";
|
||||||
"ayu_SuggestGhostModeStoryActionTextYes" = "Yes";
|
"ayu_SuggestGhostModeStoryActionTextYes" = "Yes";
|
||||||
"ayu_SuggestGhostModeStoryActionTextNo" = "No";
|
"ayu_SuggestGhostModeStoryActionTextNo" = "No";
|
||||||
"ayu_ClearAttachmentsFolderWarning" = "Are you sure you want to clear the **attachments folder**? This action cannot be undone.";
|
|
||||||
"ayu_ClearMessagesDatabaseWarning" = "Are you sure you want to clear **all deleted & edited messages**? This action cannot be undone.";
|
|
||||||
"ayu_ClearTelegramDatabaseWarning" = "Are you sure you want to clear the **Telegram internal database**? This action cannot be undone.";
|
|
||||||
"ayu_FirstLaunchAlert" = "AyuGram is **free** software and should only be obtained from our **official sources**. You assume **full responsibility** for using this application with your account.";
|
"ayu_FirstLaunchAlert" = "AyuGram is **free** software and should only be obtained from our **official sources**. You assume **full responsibility** for using this application with your account.";
|
||||||
"ayu_LocalPremiumAlert" = "With local Telegram Premium you won't have increased limits and won't be able to send animated emojis. Other users won't see your premium emoji and quote color.";
|
"ayu_LocalPremiumAlert" = "With local Telegram Premium, you won't get increased limits or be able to send animated emojis. Other users won't see your premium emoji and quote color.";
|
||||||
"ayu_ExteraChatsAlert" = "Don't ask questions related to **AyuGram** in **exteraGram** chats. If you need help, ask in the official **AyuGram** chat.";
|
"ayu_ExteraChatsAlert" = "Don't ask questions related to **AyuGram** in **exteraGram** chats. If you need help, ask in the official **AyuGram** chat.";
|
||||||
"ayu_HideNextViewsDescriptionAyu" = "Hide my views forever, until Ghost Mode disabled.";
|
"ayu_HideNextViewsDescriptionAyu" = "Hide my views forever, until Ghost Mode is disabled.";
|
||||||
"ayu_EnableGhostModeStories" = "Enable Ghost Mode";
|
"ayu_EnableGhostModeStories" = "Enable Ghost Mode";
|
||||||
"ayu_GhostModeIsActive" = "Ghost Mode is Active";
|
"ayu_GhostModeIsActive" = "Ghost Mode is Active";
|
||||||
"ayu_SimpleQuotesAndReplies" = "Disable Colorful Replies";
|
"ayu_SimpleQuotesAndReplies" = "Disable Colorful Replies";
|
||||||
|
@ -6510,6 +6868,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"ayu_MessageShotShowReactions" = "Show reactions";
|
"ayu_MessageShotShowReactions" = "Show reactions";
|
||||||
"ayu_MessageShotShowColorfulReplies" = "Show colorful replies";
|
"ayu_MessageShotShowColorfulReplies" = "Show colorful replies";
|
||||||
"ayu_SendAsSticker" = "Send as Sticker";
|
"ayu_SendAsSticker" = "Send as Sticker";
|
||||||
|
"ayu_SendWithSound" = "Send With Sound";
|
||||||
"ayu_AyuForwardStatusPreparing" = "Forwarding messages";
|
"ayu_AyuForwardStatusPreparing" = "Forwarding messages";
|
||||||
"ayu_AyuForwardStatusLoadingMedia" = "Loading media";
|
"ayu_AyuForwardStatusLoadingMedia" = "Loading media";
|
||||||
"ayu_AyuForwardStatusForwarding" = "Forwarding messages";
|
"ayu_AyuForwardStatusForwarding" = "Forwarding messages";
|
||||||
|
@ -6528,19 +6887,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"ayu_LikelyOfflineStatus" = "offline ?";
|
"ayu_LikelyOfflineStatus" = "offline ?";
|
||||||
"ayu_GhostModeShortcut" = "Enter with Ghost";
|
"ayu_GhostModeShortcut" = "Enter with Ghost";
|
||||||
"ayu_SettingsShowMessageSeconds" = "Show Message Seconds";
|
"ayu_SettingsShowMessageSeconds" = "Show Message Seconds";
|
||||||
|
"ayu_ShowOnlyAddedEmojisAndStickers" = "Show Only Added Emojis & Stickers";
|
||||||
"ayu_ContextCopyID" = "Copy ID";
|
"ayu_ContextCopyID" = "Copy ID";
|
||||||
"ayu_IDCopiedToast" = "ID copied to clipboard.";
|
"ayu_IDCopiedToast" = "ID copied to clipboard.";
|
||||||
"ayu_ContextHideMessage" = "Hide";
|
"ayu_ContextHideMessage" = "Hide";
|
||||||
"ayu_ContextCopyCallbackData" = "Copy Callback Data";
|
"ayu_ContextCopyCallbackData" = "Copy Callback Data";
|
||||||
"ayu_RegisterURLScheme" = "Register URL Scheme";
|
"ayu_RegisterURLScheme" = "Register URL Scheme";
|
||||||
|
"ayu_SessionTerminated" = "Session **{item}** was terminated. You may still browse cached messages.";
|
||||||
"ayu_LocalPremiumNotice" = "You're using **local** Telegram Premium.\nIt **won't** give you any benefits.\n**Enjoy the star near your nickname!**";
|
"ayu_LocalPremiumNotice" = "You're using **local** Telegram Premium.\nIt **won't** give you any benefits.\n**Enjoy the star near your nickname!**";
|
||||||
"ayu_DeveloperPopup" = "**{item}** is a member of the **exteraGram** development team.";
|
"ayu_DeveloperPopup" = "**{item}** is a member of the **exteraGram** development team.";
|
||||||
"ayu_SupporterPopup" = "**{item}** supported the development of **exteraGram** or **AyuGram** and received an exclusive badge.";
|
"ayu_SupporterPopup" = "**{item}** supported the development of **exteraGram** or **AyuGram** and received an exclusive badge.";
|
||||||
"ayu_SettingsWatermark" = "AyuGram developed and maintained by Radolyn Labs.";
|
"ayu_SettingsWatermark" = "AyuGram is developed and maintained by Radolyn Labs.";
|
||||||
"ayu_ConfirmationSticker" = "Do you want to send this sticker?";
|
"ayu_ConfirmationSticker" = "Do you want to send this sticker?";
|
||||||
"ayu_ConfirmationGIF" = "Do you want to send this GIF?";
|
"ayu_ConfirmationGIF" = "Do you want to send this GIF?";
|
||||||
"ayu_ConfirmationVoice" = "Do you want to send this voice message?";
|
"ayu_ConfirmationVoice" = "Do you want to send this voice message?";
|
||||||
"ayu_IntroAbout" = "Welcome to the AyuGram Desktop.\nMake Telegram your own.";
|
"ayu_IntroAbout" = "Welcome to the AyuGram Desktop.\nMake Telegram your own.";
|
||||||
"ayu_AboutText1" = "ToS breaking Telegram client based on {api_link}.";
|
"ayu_AboutText1" = "ToS breaking Telegram client based on {api_link}.";
|
||||||
"ayu_UpdateAyuGram" = "Update AyuGram";
|
"ayu_UpdateAyuGram" = "Update AyuGram";
|
||||||
"ayu_UtilityRestartRequired" = "App will close in 5 seconds.";
|
"ayu_UtilityRestartRequired" = "The app will close in 5 seconds.";
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/animations">
|
<qresource prefix="/animations">
|
||||||
<file alias="blocked_peers_empty.tgs">../../animations/blocked_peers_empty.tgs</file>
|
<file alias="blocked_peers_empty.tgs">../../animations/blocked_peers_empty.tgs</file>
|
||||||
|
<file alias="change_number.tgs">../../animations/change_number.tgs</file>
|
||||||
<file alias="filters.tgs">../../animations/filters.tgs</file>
|
<file alias="filters.tgs">../../animations/filters.tgs</file>
|
||||||
<file alias="cloud_filters.tgs">../../animations/cloud_filters.tgs</file>
|
<file alias="cloud_filters.tgs">../../animations/cloud_filters.tgs</file>
|
||||||
<file alias="local_passcode_enter.tgs">../../animations/local_passcode_enter.tgs</file>
|
<file alias="local_passcode_enter.tgs">../../animations/local_passcode_enter.tgs</file>
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
<file alias="noresults.tgs">../../animations/noresults.tgs</file>
|
<file alias="noresults.tgs">../../animations/noresults.tgs</file>
|
||||||
<file alias="hello_status.tgs">../../animations/hello_status.tgs</file>
|
<file alias="hello_status.tgs">../../animations/hello_status.tgs</file>
|
||||||
<file alias="starref_link.tgs">../../animations/starref_link.tgs</file>
|
<file alias="starref_link.tgs">../../animations/starref_link.tgs</file>
|
||||||
|
<file alias="media_forbidden.tgs">../../animations/media_forbidden.tgs</file>
|
||||||
|
|
||||||
<file alias="dice_idle.tgs">../../animations/dice/dice_idle.tgs</file>
|
<file alias="dice_idle.tgs">../../animations/dice/dice_idle.tgs</file>
|
||||||
<file alias="dart_idle.tgs">../../animations/dice/dart_idle.tgs</file>
|
<file alias="dart_idle.tgs">../../animations/dice/dart_idle.tgs</file>
|
||||||
|
@ -49,5 +51,16 @@
|
||||||
<file alias="star_reaction_effect1.tgs">../../animations/star_reaction/effect1.tgs</file>
|
<file alias="star_reaction_effect1.tgs">../../animations/star_reaction/effect1.tgs</file>
|
||||||
<file alias="star_reaction_effect2.tgs">../../animations/star_reaction/effect2.tgs</file>
|
<file alias="star_reaction_effect2.tgs">../../animations/star_reaction/effect2.tgs</file>
|
||||||
<file alias="star_reaction_effect3.tgs">../../animations/star_reaction/effect3.tgs</file>
|
<file alias="star_reaction_effect3.tgs">../../animations/star_reaction/effect3.tgs</file>
|
||||||
|
|
||||||
|
<file alias="swipe_archive.tgs">../../animations/swipe_action/archive.tgs</file>
|
||||||
|
<file alias="swipe_unarchive.tgs">../../animations/swipe_action/unarchive.tgs</file>
|
||||||
|
<file alias="swipe_delete.tgs">../../animations/swipe_action/delete.tgs</file>
|
||||||
|
<file alias="swipe_disabled.tgs">../../animations/swipe_action/disabled.tgs</file>
|
||||||
|
<file alias="swipe_mute.tgs">../../animations/swipe_action/mute.tgs</file>
|
||||||
|
<file alias="swipe_unmute.tgs">../../animations/swipe_action/unmute.tgs</file>
|
||||||
|
<file alias="swipe_pin.tgs">../../animations/swipe_action/pin.tgs</file>
|
||||||
|
<file alias="swipe_unpin.tgs">../../animations/swipe_action/unpin.tgs</file>
|
||||||
|
<file alias="swipe_read.tgs">../../animations/swipe_action/read.tgs</file>
|
||||||
|
<file alias="swipe_unread.tgs">../../animations/swipe_action/unread.tgs</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
<file alias="icons/settings/star.svg">../../icons/settings/star.svg</file>
|
<file alias="icons/settings/star.svg">../../icons/settings/star.svg</file>
|
||||||
<file alias="icons/settings/starmini.svg">../../icons/settings/starmini.svg</file>
|
<file alias="icons/settings/starmini.svg">../../icons/settings/starmini.svg</file>
|
||||||
<file alias="icons/tray/monochrome.svg">../../icons/tray_monochrome.svg</file>
|
<file alias="icons/tray/monochrome.svg">../../icons/tray_monochrome.svg</file>
|
||||||
|
<file alias="icons/tray/monochrome_attention.svg">../../icons/tray_monochrome_attention.svg</file>
|
||||||
|
<file alias="icons/tray/monochrome_mute.svg">../../icons/tray_monochrome_mute.svg</file>
|
||||||
<file alias="topic_icons/blue.svg">../../art/topic_icons/blue.svg</file>
|
<file alias="topic_icons/blue.svg">../../art/topic_icons/blue.svg</file>
|
||||||
<file alias="topic_icons/yellow.svg">../../art/topic_icons/yellow.svg</file>
|
<file alias="topic_icons/yellow.svg">../../art/topic_icons/yellow.svg</file>
|
||||||
<file alias="topic_icons/violet.svg">../../art/topic_icons/violet.svg</file>
|
<file alias="topic_icons/violet.svg">../../art/topic_icons/violet.svg</file>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||||
ProcessorArchitecture="ARCHITECTURE"
|
ProcessorArchitecture="ARCHITECTURE"
|
||||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||||
Version="5.11.1.0" />
|
Version="5.14.3.0" />
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>Telegram Desktop</DisplayName>
|
<DisplayName>Telegram Desktop</DisplayName>
|
||||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||||
|
|
|
@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 5,11,1,0
|
FILEVERSION 5,14,3,0
|
||||||
PRODUCTVERSION 5,11,1,0
|
PRODUCTVERSION 5,14,3,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -62,10 +62,10 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Radolyn Labs"
|
VALUE "CompanyName", "Radolyn Labs"
|
||||||
VALUE "FileDescription", "AyuGram Desktop"
|
VALUE "FileDescription", "AyuGram Desktop"
|
||||||
VALUE "FileVersion", "5.11.1.0"
|
VALUE "FileVersion", "5.14.3.0"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||||
VALUE "ProductName", "AyuGram Desktop"
|
VALUE "ProductName", "AyuGram Desktop"
|
||||||
VALUE "ProductVersion", "5.11.1.0"
|
VALUE "ProductVersion", "5.14.3.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 5,11,1,0
|
FILEVERSION 5,14,3,0
|
||||||
PRODUCTVERSION 5,11,1,0
|
PRODUCTVERSION 5,14,3,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -53,10 +53,10 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Radolyn Labs"
|
VALUE "CompanyName", "Radolyn Labs"
|
||||||
VALUE "FileDescription", "AyuGram Desktop Updater"
|
VALUE "FileDescription", "AyuGram Desktop Updater"
|
||||||
VALUE "FileVersion", "5.11.1.0"
|
VALUE "FileVersion", "5.14.3.0"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||||
VALUE "ProductName", "AyuGram Desktop"
|
VALUE "ProductName", "AyuGram Desktop"
|
||||||
VALUE "ProductVersion", "5.11.1.0"
|
VALUE "ProductVersion", "5.14.3.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -149,18 +149,14 @@ void InitFilterLinkHeader(
|
||||||
iconEmoji
|
iconEmoji
|
||||||
).value_or(Ui::FilterIcon::Custom)).active;
|
).value_or(Ui::FilterIcon::Custom)).active;
|
||||||
const auto isStatic = title.isStatic;
|
const auto isStatic = title.isStatic;
|
||||||
const auto makeContext = [=](Fn<void()> repaint) {
|
|
||||||
return Core::MarkedTextContext{
|
|
||||||
.session = &box->peerListUiShow()->session(),
|
|
||||||
.customEmojiRepaint = std::move(repaint),
|
|
||||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
auto header = Ui::MakeFilterLinkHeader(box, {
|
auto header = Ui::MakeFilterLinkHeader(box, {
|
||||||
.type = type,
|
.type = type,
|
||||||
.title = TitleText(type)(tr::now),
|
.title = TitleText(type)(tr::now),
|
||||||
.about = AboutText(type, title.text),
|
.about = AboutText(type, title.text),
|
||||||
.makeAboutContext = makeContext,
|
.aboutContext = Core::TextContext({
|
||||||
|
.session = &box->peerListUiShow()->session(),
|
||||||
|
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||||
|
}),
|
||||||
.folderTitle = title.text,
|
.folderTitle = title.text,
|
||||||
.folderIcon = icon,
|
.folderIcon = icon,
|
||||||
.badge = (type == Ui::FilterLinkHeaderType::AddingChats
|
.badge = (type == Ui::FilterLinkHeaderType::AddingChats
|
||||||
|
@ -560,16 +556,12 @@ void ShowImportToast(
|
||||||
text.append('\n').append(phrase(tr::now, lt_count, added));
|
text.append('\n').append(phrase(tr::now, lt_count, added));
|
||||||
}
|
}
|
||||||
const auto isStatic = title.isStatic;
|
const auto isStatic = title.isStatic;
|
||||||
const auto makeContext = [=](not_null<QWidget*> widget) {
|
|
||||||
return Core::MarkedTextContext{
|
|
||||||
.session = &strong->session(),
|
|
||||||
.customEmojiRepaint = [=] { widget->update(); },
|
|
||||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
strong->showToast({
|
strong->showToast({
|
||||||
.text = std::move(text),
|
.text = std::move(text),
|
||||||
.textContext = makeContext,
|
.textContext = Core::TextContext({
|
||||||
|
.session = &strong->session(),
|
||||||
|
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,18 +632,14 @@ void ProcessFilterInvite(
|
||||||
raw->setRealContentHeight(box->heightValue());
|
raw->setRealContentHeight(box->heightValue());
|
||||||
|
|
||||||
const auto isStatic = title.isStatic;
|
const auto isStatic = title.isStatic;
|
||||||
const auto makeContext = [=](Fn<void()> update) {
|
|
||||||
return Core::MarkedTextContext{
|
|
||||||
.session = &strong->session(),
|
|
||||||
.customEmojiRepaint = update,
|
|
||||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
auto owned = Ui::FilterLinkProcessButton(
|
auto owned = Ui::FilterLinkProcessButton(
|
||||||
box,
|
box,
|
||||||
type,
|
type,
|
||||||
title.text,
|
title.text,
|
||||||
makeContext,
|
Core::TextContext({
|
||||||
|
.session = &strong->session(),
|
||||||
|
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||||
|
}),
|
||||||
std::move(badge));
|
std::move(badge));
|
||||||
|
|
||||||
const auto button = owned.data();
|
const auto button = owned.data();
|
||||||
|
@ -873,18 +861,14 @@ void ProcessFilterRemove(
|
||||||
}, type, title, iconEmoji, rpl::single(0), horizontalFilters);
|
}, type, title, iconEmoji, rpl::single(0), horizontalFilters);
|
||||||
|
|
||||||
const auto isStatic = title.isStatic;
|
const auto isStatic = title.isStatic;
|
||||||
const auto makeContext = [=](Fn<void()> update) {
|
|
||||||
return Core::MarkedTextContext{
|
|
||||||
.session = &strong->session(),
|
|
||||||
.customEmojiRepaint = update,
|
|
||||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
auto owned = Ui::FilterLinkProcessButton(
|
auto owned = Ui::FilterLinkProcessButton(
|
||||||
box,
|
box,
|
||||||
type,
|
type,
|
||||||
title.text,
|
title.text,
|
||||||
makeContext,
|
Core::TextContext({
|
||||||
|
.session = &strong->session(),
|
||||||
|
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||||
|
}),
|
||||||
std::move(badge));
|
std::move(badge));
|
||||||
|
|
||||||
const auto button = owned.data();
|
const auto button = owned.data();
|
||||||
|
|
|
@ -544,4 +544,38 @@ auto CloudPassword::checkRecoveryEmailAddressCode(const QString &code)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RequestLoginEmailCode(
|
||||||
|
MTP::Sender &api,
|
||||||
|
const QString &sendToEmail,
|
||||||
|
Fn<void(int length, const QString &pattern)> done,
|
||||||
|
Fn<void(const QString &error)> fail) {
|
||||||
|
api.request(MTPaccount_SendVerifyEmailCode(
|
||||||
|
MTP_emailVerifyPurposeLoginChange(),
|
||||||
|
MTP_string(sendToEmail)
|
||||||
|
)).done([=](const MTPaccount_SentEmailCode &result) {
|
||||||
|
done(result.data().vlength().v, qs(result.data().vemail_pattern()));
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
fail(error.type());
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerifyLoginEmail(
|
||||||
|
MTP::Sender &api,
|
||||||
|
const QString &code,
|
||||||
|
Fn<void()> done,
|
||||||
|
Fn<void(const QString &error)> fail) {
|
||||||
|
api.request(MTPaccount_VerifyEmail(
|
||||||
|
MTP_emailVerifyPurposeLoginChange(),
|
||||||
|
MTP_emailVerificationCode(MTP_string(code))
|
||||||
|
)).done([=](const MTPaccount_EmailVerified &result) {
|
||||||
|
result.match([=](const MTPDaccount_emailVerified &data) {
|
||||||
|
done();
|
||||||
|
}, [=](const MTPDaccount_emailVerifiedLogin &data) {
|
||||||
|
fail(QString());
|
||||||
|
});
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
fail(error.type());
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -70,4 +70,15 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void RequestLoginEmailCode(
|
||||||
|
MTP::Sender &api,
|
||||||
|
const QString &sendToEmail,
|
||||||
|
Fn<void(int length, const QString &pattern)> done,
|
||||||
|
Fn<void(const QString &error)> fail);
|
||||||
|
void VerifyLoginEmail(
|
||||||
|
MTP::Sender &api,
|
||||||
|
const QString &code,
|
||||||
|
Fn<void()> done,
|
||||||
|
Fn<void(const QString &error)> fail);
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct SendOptions {
|
||||||
TimeId scheduled = 0;
|
TimeId scheduled = 0;
|
||||||
BusinessShortcutId shortcutId = 0;
|
BusinessShortcutId shortcutId = 0;
|
||||||
EffectId effectId = 0;
|
EffectId effectId = 0;
|
||||||
|
int starsApproved = 0;
|
||||||
bool silent = false;
|
bool silent = false;
|
||||||
bool handleSupportSwitch = false;
|
bool handleSupportSwitch = false;
|
||||||
bool invertCaption = false;
|
bool invertCaption = false;
|
||||||
|
|
|
@ -150,6 +150,9 @@ void ConfirmPhone::resolve(
|
||||||
}, [](const MTPDauth_sentCodeSuccess &) {
|
}, [](const MTPDauth_sentCodeSuccess &) {
|
||||||
LOG(("API Error: Unexpected auth.sentCodeSuccess "
|
LOG(("API Error: Unexpected auth.sentCodeSuccess "
|
||||||
"(Api::ConfirmPhone)."));
|
"(Api::ConfirmPhone)."));
|
||||||
|
}, [](const MTPDauth_sentCodePaymentRequired &) {
|
||||||
|
LOG(("API Error: Unexpected auth.sentCodePaymentRequired "
|
||||||
|
"(Api::ConfirmPhone)."));
|
||||||
});
|
});
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
_sendRequestId = 0;
|
_sendRequestId = 0;
|
||||||
|
|
|
@ -90,7 +90,13 @@ constexpr auto kTransactionsLimit = 100;
|
||||||
? peerFromMTP(*tl.data().vstarref_peer()).value
|
? peerFromMTP(*tl.data().vstarref_peer()).value
|
||||||
: 0;
|
: 0;
|
||||||
const auto incoming = (amount >= StarsAmount());
|
const auto incoming = (amount >= StarsAmount());
|
||||||
const auto saveActorId = (reaction || !extended.empty()) && incoming;
|
const auto paidMessagesCount
|
||||||
|
= tl.data().vpaid_messages().value_or_empty();
|
||||||
|
const auto premiumMonthsForStars
|
||||||
|
= tl.data().vpremium_gift_months().value_or_empty();
|
||||||
|
const auto saveActorId = (reaction
|
||||||
|
|| !extended.empty()
|
||||||
|
|| paidMessagesCount) && incoming;
|
||||||
const auto parsedGift = stargift
|
const auto parsedGift = stargift
|
||||||
? FromTL(&peer->session(), *stargift)
|
? FromTL(&peer->session(), *stargift)
|
||||||
: std::optional<Data::StarGift>();
|
: std::optional<Data::StarGift>();
|
||||||
|
@ -110,9 +116,9 @@ constexpr auto kTransactionsLimit = 100;
|
||||||
.bareGiftStickerId = giftStickerId,
|
.bareGiftStickerId = giftStickerId,
|
||||||
.bareActorId = saveActorId ? barePeerId : uint64(0),
|
.bareActorId = saveActorId ? barePeerId : uint64(0),
|
||||||
.uniqueGift = parsedGift ? parsedGift->unique : nullptr,
|
.uniqueGift = parsedGift ? parsedGift->unique : nullptr,
|
||||||
.starrefAmount = starrefAmount,
|
.starrefAmount = paidMessagesCount ? StarsAmount() : starrefAmount,
|
||||||
.starrefCommission = starrefCommission,
|
.starrefCommission = paidMessagesCount ? 0 : starrefCommission,
|
||||||
.starrefRecipientId = starrefBarePeerId,
|
.starrefRecipientId = paidMessagesCount ? 0 : starrefBarePeerId,
|
||||||
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
|
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
|
||||||
return Data::CreditsHistoryEntry::PeerType::Peer;
|
return Data::CreditsHistoryEntry::PeerType::Peer;
|
||||||
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
|
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
|
||||||
|
@ -138,13 +144,20 @@ constexpr auto kTransactionsLimit = 100;
|
||||||
? base::unixtime::parse(tl.data().vtransaction_date()->v)
|
? base::unixtime::parse(tl.data().vtransaction_date()->v)
|
||||||
: QDateTime(),
|
: QDateTime(),
|
||||||
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
|
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
|
||||||
|
.paidMessagesCount = paidMessagesCount,
|
||||||
|
.paidMessagesAmount = (paidMessagesCount
|
||||||
|
? starrefAmount
|
||||||
|
: StarsAmount()),
|
||||||
|
.paidMessagesCommission = paidMessagesCount ? starrefCommission : 0,
|
||||||
.starsConverted = int(nonUniqueGift
|
.starsConverted = int(nonUniqueGift
|
||||||
? nonUniqueGift->vconvert_stars().v
|
? nonUniqueGift->vconvert_stars().v
|
||||||
: 0),
|
: 0),
|
||||||
|
.premiumMonthsForStars = premiumMonthsForStars,
|
||||||
.floodSkip = int(tl.data().vfloodskip_number().value_or(0)),
|
.floodSkip = int(tl.data().vfloodskip_number().value_or(0)),
|
||||||
.converted = stargift && incoming,
|
.converted = stargift && incoming,
|
||||||
.stargift = stargift.has_value(),
|
.stargift = stargift.has_value(),
|
||||||
.giftUpgraded = tl.data().is_stargift_upgrade(),
|
.giftUpgraded = tl.data().is_stargift_upgrade(),
|
||||||
|
.giftResale = tl.data().is_stargift_resale(),
|
||||||
.reaction = tl.data().is_reaction(),
|
.reaction = tl.data().is_reaction(),
|
||||||
.refunded = tl.data().is_refund(),
|
.refunded = tl.data().is_refund(),
|
||||||
.pending = tl.data().is_pending(),
|
.pending = tl.data().is_pending(),
|
||||||
|
@ -336,12 +349,15 @@ void CreditsHistory::request(
|
||||||
|
|
||||||
void CreditsHistory::requestSubscriptions(
|
void CreditsHistory::requestSubscriptions(
|
||||||
const Data::CreditsStatusSlice::OffsetToken &token,
|
const Data::CreditsStatusSlice::OffsetToken &token,
|
||||||
Fn<void(Data::CreditsStatusSlice)> done) {
|
Fn<void(Data::CreditsStatusSlice)> done,
|
||||||
|
bool missingBalance) {
|
||||||
if (_requestId) {
|
if (_requestId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_requestId = _api.request(MTPpayments_GetStarsSubscriptions(
|
_requestId = _api.request(MTPpayments_GetStarsSubscriptions(
|
||||||
MTP_flags(0),
|
MTP_flags(missingBalance
|
||||||
|
? MTPpayments_getStarsSubscriptions::Flag::f_missing_balance
|
||||||
|
: MTPpayments_getStarsSubscriptions::Flags(0)),
|
||||||
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input,
|
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input,
|
||||||
MTP_string(token)
|
MTP_string(token)
|
||||||
)).done([=](const MTPpayments_StarsStatus &result) {
|
)).done([=](const MTPpayments_StarsStatus &result) {
|
||||||
|
@ -513,8 +529,12 @@ void EditCreditsSubscription(
|
||||||
)).done(done).fail([=](const MTP::Error &e) { fail(e.type()); }).send();
|
)).done(done).fail([=](const MTP::Error &e) { fail(e.type()); }).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPInputSavedStarGift InputSavedStarGiftId(const Data::SavedStarGiftId &id) {
|
MTPInputSavedStarGift InputSavedStarGiftId(
|
||||||
return id.isUser()
|
const Data::SavedStarGiftId &id,
|
||||||
|
const std::shared_ptr<Data::UniqueGift> &unique) {
|
||||||
|
return (!id && unique)
|
||||||
|
? MTP_inputSavedStarGiftSlug(MTP_string(unique->slug))
|
||||||
|
: id.isUser()
|
||||||
? MTP_inputSavedStarGiftUser(MTP_int(id.userMessageId().bare))
|
? MTP_inputSavedStarGiftUser(MTP_int(id.userMessageId().bare))
|
||||||
: MTP_inputSavedStarGiftChat(
|
: MTP_inputSavedStarGiftChat(
|
||||||
id.chat()->input,
|
id.chat()->input,
|
||||||
|
|
|
@ -82,7 +82,8 @@ public:
|
||||||
Fn<void(Data::CreditsStatusSlice)> done);
|
Fn<void(Data::CreditsStatusSlice)> done);
|
||||||
void requestSubscriptions(
|
void requestSubscriptions(
|
||||||
const Data::CreditsStatusSlice::OffsetToken &token,
|
const Data::CreditsStatusSlice::OffsetToken &token,
|
||||||
Fn<void(Data::CreditsStatusSlice)> done);
|
Fn<void(Data::CreditsStatusSlice)> done,
|
||||||
|
bool missingBalance = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using HistoryTL = MTPpayments_GetStarsTransactions;
|
using HistoryTL = MTPpayments_GetStarsTransactions;
|
||||||
|
@ -121,6 +122,7 @@ void EditCreditsSubscription(
|
||||||
Fn<void(QString)> fail);
|
Fn<void(QString)> fail);
|
||||||
|
|
||||||
[[nodiscard]] MTPInputSavedStarGift InputSavedStarGiftId(
|
[[nodiscard]] MTPInputSavedStarGift InputSavedStarGiftId(
|
||||||
const Data::SavedStarGiftId &id);
|
const Data::SavedStarGiftId &id,
|
||||||
|
const std::shared_ptr<Data::UniqueGift> &unique = nullptr);
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -46,11 +46,15 @@ void HandleWithdrawalButton(
|
||||||
bool loading = false;
|
bool loading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto channel = receiver.currencyReceiver;
|
const auto currencyReceiver = receiver.currencyReceiver;
|
||||||
const auto peer = receiver.creditsReceiver;
|
const auto creditsReceiver = receiver.creditsReceiver;
|
||||||
|
const auto isChannel = receiver.currencyReceiver
|
||||||
|
&& receiver.currencyReceiver->isChannel();
|
||||||
|
|
||||||
const auto state = button->lifetime().make_state<State>();
|
const auto state = button->lifetime().make_state<State>();
|
||||||
const auto session = (channel ? &channel->session() : &peer->session());
|
const auto session = (currencyReceiver
|
||||||
|
? ¤cyReceiver->session()
|
||||||
|
: &creditsReceiver->session());
|
||||||
|
|
||||||
using ChannelOutUrl = MTPstats_BroadcastRevenueWithdrawalUrl;
|
using ChannelOutUrl = MTPstats_BroadcastRevenueWithdrawalUrl;
|
||||||
using CreditsOutUrl = MTPpayments_StarsRevenueWithdrawalUrl;
|
using CreditsOutUrl = MTPpayments_StarsRevenueWithdrawalUrl;
|
||||||
|
@ -59,7 +63,7 @@ void HandleWithdrawalButton(
|
||||||
const auto processOut = [=] {
|
const auto processOut = [=] {
|
||||||
if (state->loading) {
|
if (state->loading) {
|
||||||
return;
|
return;
|
||||||
} else if (peer && !receiver.creditsAmount()) {
|
} else if (creditsReceiver && !receiver.creditsAmount()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state->loading = true;
|
state->loading = true;
|
||||||
|
@ -70,10 +74,10 @@ void HandleWithdrawalButton(
|
||||||
state->loading = false;
|
state->loading = false;
|
||||||
|
|
||||||
auto fields = PasscodeBox::CloudFields::From(pass);
|
auto fields = PasscodeBox::CloudFields::From(pass);
|
||||||
fields.customTitle = channel
|
fields.customTitle = isChannel
|
||||||
? tr::lng_channel_earn_balance_password_title()
|
? tr::lng_channel_earn_balance_password_title()
|
||||||
: tr::lng_bot_earn_balance_password_title();
|
: tr::lng_bot_earn_balance_password_title();
|
||||||
fields.customDescription = channel
|
fields.customDescription = isChannel
|
||||||
? tr::lng_channel_earn_balance_password_description(tr::now)
|
? tr::lng_channel_earn_balance_password_description(tr::now)
|
||||||
: tr::lng_bot_earn_balance_password_description(tr::now);
|
: tr::lng_bot_earn_balance_password_description(tr::now);
|
||||||
fields.customSubmitButton = tr::lng_passcode_submit();
|
fields.customSubmitButton = tr::lng_passcode_submit();
|
||||||
|
@ -94,18 +98,18 @@ void HandleWithdrawalButton(
|
||||||
show->showToast(message);
|
show->showToast(message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (channel) {
|
if (currencyReceiver) {
|
||||||
session->api().request(
|
session->api().request(
|
||||||
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
||||||
channel->input,
|
currencyReceiver->input,
|
||||||
result.result
|
result.result
|
||||||
)).done([=](const ChannelOutUrl &r) {
|
)).done([=](const ChannelOutUrl &r) {
|
||||||
done(qs(r.data().vurl()));
|
done(qs(r.data().vurl()));
|
||||||
}).fail(fail).send();
|
}).fail(fail).send();
|
||||||
} else if (peer) {
|
} else if (creditsReceiver) {
|
||||||
session->api().request(
|
session->api().request(
|
||||||
MTPpayments_GetStarsRevenueWithdrawalUrl(
|
MTPpayments_GetStarsRevenueWithdrawalUrl(
|
||||||
peer->input,
|
creditsReceiver->input,
|
||||||
MTP_long(receiver.creditsAmount()),
|
MTP_long(receiver.creditsAmount()),
|
||||||
result.result
|
result.result
|
||||||
)).done([=](const CreditsOutUrl &r) {
|
)).done([=](const CreditsOutUrl &r) {
|
||||||
|
@ -134,17 +138,17 @@ void HandleWithdrawalButton(
|
||||||
processOut();
|
processOut();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (channel) {
|
if (currencyReceiver) {
|
||||||
session->api().request(
|
session->api().request(
|
||||||
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
||||||
channel->input,
|
currencyReceiver->input,
|
||||||
MTP_inputCheckPasswordEmpty()
|
MTP_inputCheckPasswordEmpty()
|
||||||
)).fail(fail).send();
|
)).fail(fail).send();
|
||||||
} else if (peer) {
|
} else if (creditsReceiver) {
|
||||||
session->api().request(
|
session->api().request(
|
||||||
MTPpayments_GetStarsRevenueWithdrawalUrl(
|
MTPpayments_GetStarsRevenueWithdrawalUrl(
|
||||||
peer->input,
|
creditsReceiver->input,
|
||||||
MTP_long(std::numeric_limits<int64_t>::max()),
|
MTP_long(receiver.creditsAmount()),
|
||||||
MTP_inputCheckPasswordEmpty()
|
MTP_inputCheckPasswordEmpty()
|
||||||
)).fail(fail).send();
|
)).fail(fail).send();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ void RestrictSponsored(
|
||||||
Fn<void(QString)> failed);
|
Fn<void(QString)> failed);
|
||||||
|
|
||||||
struct RewardReceiver final {
|
struct RewardReceiver final {
|
||||||
ChannelData *currencyReceiver = nullptr;
|
PeerData *currencyReceiver = nullptr;
|
||||||
PeerData *creditsReceiver = nullptr;
|
PeerData *creditsReceiver = nullptr;
|
||||||
Fn<uint64()> creditsAmount;
|
Fn<uint64()> creditsAmount;
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_global_privacy.h"
|
#include "api/api_global_privacy.h"
|
||||||
|
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
#include "data/components/promo_suggestions.h"
|
||||||
|
#include "data/data_user.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_app_config.h"
|
#include "main/main_app_config.h"
|
||||||
|
|
||||||
|
@ -100,13 +102,11 @@ rpl::producer<bool> GlobalPrivacy::showArchiveAndMute() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<> GlobalPrivacy::suggestArchiveAndMute() const {
|
rpl::producer<> GlobalPrivacy::suggestArchiveAndMute() const {
|
||||||
return _session->appConfig().suggestionRequested(
|
return _session->promoSuggestions().requested(u"AUTOARCHIVE_POPULAR"_q);
|
||||||
u"AUTOARCHIVE_POPULAR"_q);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalPrivacy::dismissArchiveAndMuteSuggestion() {
|
void GlobalPrivacy::dismissArchiveAndMuteSuggestion() {
|
||||||
_session->appConfig().dismissSuggestion(
|
_session->promoSuggestions().dismiss(u"AUTOARCHIVE_POPULAR"_q);
|
||||||
u"AUTOARCHIVE_POPULAR"_q);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalPrivacy::updateHideReadTime(bool hide) {
|
void GlobalPrivacy::updateHideReadTime(bool hide) {
|
||||||
|
@ -114,7 +114,9 @@ void GlobalPrivacy::updateHideReadTime(bool hide) {
|
||||||
archiveAndMuteCurrent(),
|
archiveAndMuteCurrent(),
|
||||||
unarchiveOnNewMessageCurrent(),
|
unarchiveOnNewMessageCurrent(),
|
||||||
hide,
|
hide,
|
||||||
newRequirePremiumCurrent());
|
newRequirePremiumCurrent(),
|
||||||
|
newChargeStarsCurrent(),
|
||||||
|
disallowedGiftTypesCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GlobalPrivacy::hideReadTimeCurrent() const {
|
bool GlobalPrivacy::hideReadTimeCurrent() const {
|
||||||
|
@ -125,14 +127,6 @@ rpl::producer<bool> GlobalPrivacy::hideReadTime() const {
|
||||||
return _hideReadTime.value();
|
return _hideReadTime.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalPrivacy::updateNewRequirePremium(bool value) {
|
|
||||||
update(
|
|
||||||
archiveAndMuteCurrent(),
|
|
||||||
unarchiveOnNewMessageCurrent(),
|
|
||||||
hideReadTimeCurrent(),
|
|
||||||
value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GlobalPrivacy::newRequirePremiumCurrent() const {
|
bool GlobalPrivacy::newRequirePremiumCurrent() const {
|
||||||
return _newRequirePremium.current();
|
return _newRequirePremium.current();
|
||||||
}
|
}
|
||||||
|
@ -141,6 +135,45 @@ rpl::producer<bool> GlobalPrivacy::newRequirePremium() const {
|
||||||
return _newRequirePremium.value();
|
return _newRequirePremium.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GlobalPrivacy::newChargeStarsCurrent() const {
|
||||||
|
return _newChargeStars.current();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> GlobalPrivacy::newChargeStars() const {
|
||||||
|
return _newChargeStars.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalPrivacy::updateMessagesPrivacy(
|
||||||
|
bool requirePremium,
|
||||||
|
int chargeStars) {
|
||||||
|
update(
|
||||||
|
archiveAndMuteCurrent(),
|
||||||
|
unarchiveOnNewMessageCurrent(),
|
||||||
|
hideReadTimeCurrent(),
|
||||||
|
requirePremium,
|
||||||
|
chargeStars,
|
||||||
|
disallowedGiftTypesCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
|
DisallowedGiftTypes GlobalPrivacy::disallowedGiftTypesCurrent() const {
|
||||||
|
return _disallowedGiftTypes.current();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GlobalPrivacy::disallowedGiftTypes() const
|
||||||
|
-> rpl::producer<DisallowedGiftTypes> {
|
||||||
|
return _disallowedGiftTypes.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalPrivacy::updateDisallowedGiftTypes(DisallowedGiftTypes types) {
|
||||||
|
update(
|
||||||
|
archiveAndMuteCurrent(),
|
||||||
|
unarchiveOnNewMessageCurrent(),
|
||||||
|
hideReadTimeCurrent(),
|
||||||
|
newRequirePremiumCurrent(),
|
||||||
|
newChargeStarsCurrent(),
|
||||||
|
types);
|
||||||
|
}
|
||||||
|
|
||||||
void GlobalPrivacy::loadPaidReactionShownPeer() {
|
void GlobalPrivacy::loadPaidReactionShownPeer() {
|
||||||
if (_paidReactionShownPeerLoaded) {
|
if (_paidReactionShownPeerLoaded) {
|
||||||
return;
|
return;
|
||||||
|
@ -169,7 +202,9 @@ void GlobalPrivacy::updateArchiveAndMute(bool value) {
|
||||||
value,
|
value,
|
||||||
unarchiveOnNewMessageCurrent(),
|
unarchiveOnNewMessageCurrent(),
|
||||||
hideReadTimeCurrent(),
|
hideReadTimeCurrent(),
|
||||||
newRequirePremiumCurrent());
|
newRequirePremiumCurrent(),
|
||||||
|
newChargeStarsCurrent(),
|
||||||
|
disallowedGiftTypesCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalPrivacy::updateUnarchiveOnNewMessage(
|
void GlobalPrivacy::updateUnarchiveOnNewMessage(
|
||||||
|
@ -178,19 +213,26 @@ void GlobalPrivacy::updateUnarchiveOnNewMessage(
|
||||||
archiveAndMuteCurrent(),
|
archiveAndMuteCurrent(),
|
||||||
value,
|
value,
|
||||||
hideReadTimeCurrent(),
|
hideReadTimeCurrent(),
|
||||||
newRequirePremiumCurrent());
|
newRequirePremiumCurrent(),
|
||||||
|
newChargeStarsCurrent(),
|
||||||
|
disallowedGiftTypesCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalPrivacy::update(
|
void GlobalPrivacy::update(
|
||||||
bool archiveAndMute,
|
bool archiveAndMute,
|
||||||
UnarchiveOnNewMessage unarchiveOnNewMessage,
|
UnarchiveOnNewMessage unarchiveOnNewMessage,
|
||||||
bool hideReadTime,
|
bool hideReadTime,
|
||||||
bool newRequirePremium) {
|
bool newRequirePremium,
|
||||||
|
int newChargeStars,
|
||||||
|
DisallowedGiftTypes disallowedGiftTypes) {
|
||||||
using Flag = MTPDglobalPrivacySettings::Flag;
|
using Flag = MTPDglobalPrivacySettings::Flag;
|
||||||
|
using DisallowedFlag = MTPDdisallowedGiftsSettings::Flag;
|
||||||
|
|
||||||
_api.request(_requestId).cancel();
|
_api.request(_requestId).cancel();
|
||||||
const auto newRequirePremiumAllowed = _session->premium()
|
const auto newRequirePremiumAllowed = _session->premium()
|
||||||
|| _session->appConfig().newRequirePremiumFree();
|
|| _session->appConfig().newRequirePremiumFree();
|
||||||
|
const auto showGiftIcon
|
||||||
|
= (disallowedGiftTypes & DisallowedGiftType::SendHide);
|
||||||
const auto flags = Flag()
|
const auto flags = Flag()
|
||||||
| (archiveAndMute
|
| (archiveAndMute
|
||||||
? Flag::f_archive_and_mute_new_noncontact_peers
|
? Flag::f_archive_and_mute_new_noncontact_peers
|
||||||
|
@ -204,26 +246,58 @@ void GlobalPrivacy::update(
|
||||||
| (hideReadTime ? Flag::f_hide_read_marks : Flag())
|
| (hideReadTime ? Flag::f_hide_read_marks : Flag())
|
||||||
| ((newRequirePremium && newRequirePremiumAllowed)
|
| ((newRequirePremium && newRequirePremiumAllowed)
|
||||||
? Flag::f_new_noncontact_peers_require_premium
|
? Flag::f_new_noncontact_peers_require_premium
|
||||||
: Flag());
|
: Flag())
|
||||||
|
| Flag::f_noncontact_peers_paid_stars
|
||||||
|
| (showGiftIcon ? Flag::f_display_gifts_button : Flag())
|
||||||
|
| Flag::f_disallowed_gifts;
|
||||||
|
const auto disallowedFlags = DisallowedFlag()
|
||||||
|
| ((disallowedGiftTypes & DisallowedGiftType::Premium)
|
||||||
|
? DisallowedFlag::f_disallow_premium_gifts
|
||||||
|
: DisallowedFlag())
|
||||||
|
| ((disallowedGiftTypes & DisallowedGiftType::Unlimited)
|
||||||
|
? DisallowedFlag::f_disallow_unlimited_stargifts
|
||||||
|
: DisallowedFlag())
|
||||||
|
| ((disallowedGiftTypes & DisallowedGiftType::Limited)
|
||||||
|
? DisallowedFlag::f_disallow_limited_stargifts
|
||||||
|
: DisallowedFlag())
|
||||||
|
| ((disallowedGiftTypes & DisallowedGiftType::Unique)
|
||||||
|
? DisallowedFlag::f_disallow_unique_stargifts
|
||||||
|
: DisallowedFlag());
|
||||||
|
const auto typesWas = _disallowedGiftTypes.current();
|
||||||
|
const auto typesChanged = (typesWas != disallowedGiftTypes);
|
||||||
_requestId = _api.request(MTPaccount_SetGlobalPrivacySettings(
|
_requestId = _api.request(MTPaccount_SetGlobalPrivacySettings(
|
||||||
MTP_globalPrivacySettings(MTP_flags(flags))
|
MTP_globalPrivacySettings(
|
||||||
|
MTP_flags(flags),
|
||||||
|
MTP_long(newChargeStars),
|
||||||
|
MTP_disallowedGiftsSettings(MTP_flags(disallowedFlags)))
|
||||||
)).done([=](const MTPGlobalPrivacySettings &result) {
|
)).done([=](const MTPGlobalPrivacySettings &result) {
|
||||||
_requestId = 0;
|
_requestId = 0;
|
||||||
apply(result);
|
apply(result);
|
||||||
|
if (typesChanged) {
|
||||||
|
_session->user()->updateFullForced();
|
||||||
|
}
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
_requestId = 0;
|
_requestId = 0;
|
||||||
if (error.type() == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
|
if (error.type() == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
|
||||||
update(archiveAndMute, unarchiveOnNewMessage, hideReadTime, {});
|
update(
|
||||||
|
archiveAndMute,
|
||||||
|
unarchiveOnNewMessage,
|
||||||
|
hideReadTime,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
DisallowedGiftTypes());
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
_archiveAndMute = archiveAndMute;
|
_archiveAndMute = archiveAndMute;
|
||||||
_unarchiveOnNewMessage = unarchiveOnNewMessage;
|
_unarchiveOnNewMessage = unarchiveOnNewMessage;
|
||||||
_hideReadTime = hideReadTime;
|
_hideReadTime = hideReadTime;
|
||||||
_newRequirePremium = newRequirePremium;
|
_newRequirePremium = newRequirePremium;
|
||||||
|
_newChargeStars = newChargeStars;
|
||||||
|
_disallowedGiftTypes = disallowedGiftTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
|
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &settings) {
|
||||||
data.match([&](const MTPDglobalPrivacySettings &data) {
|
const auto &data = settings.data();
|
||||||
_archiveAndMute = data.is_archive_and_mute_new_noncontact_peers();
|
_archiveAndMute = data.is_archive_and_mute_new_noncontact_peers();
|
||||||
_unarchiveOnNewMessage = data.is_keep_archived_unmuted()
|
_unarchiveOnNewMessage = data.is_keep_archived_unmuted()
|
||||||
? UnarchiveOnNewMessage::None
|
? UnarchiveOnNewMessage::None
|
||||||
|
@ -232,7 +306,30 @@ void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
|
||||||
: UnarchiveOnNewMessage::AnyUnmuted;
|
: UnarchiveOnNewMessage::AnyUnmuted;
|
||||||
_hideReadTime = data.is_hide_read_marks();
|
_hideReadTime = data.is_hide_read_marks();
|
||||||
_newRequirePremium = data.is_new_noncontact_peers_require_premium();
|
_newRequirePremium = data.is_new_noncontact_peers_require_premium();
|
||||||
});
|
_newChargeStars = data.vnoncontact_peers_paid_stars().value_or_empty();
|
||||||
|
if (const auto gifts = data.vdisallowed_gifts()) {
|
||||||
|
const auto &disallow = gifts->data();
|
||||||
|
_disallowedGiftTypes = DisallowedGiftType()
|
||||||
|
| (disallow.is_disallow_unlimited_stargifts()
|
||||||
|
? DisallowedGiftType::Unlimited
|
||||||
|
: DisallowedGiftType())
|
||||||
|
| (disallow.is_disallow_limited_stargifts()
|
||||||
|
? DisallowedGiftType::Limited
|
||||||
|
: DisallowedGiftType())
|
||||||
|
| (disallow.is_disallow_unique_stargifts()
|
||||||
|
? DisallowedGiftType::Unique
|
||||||
|
: DisallowedGiftType())
|
||||||
|
| (disallow.is_disallow_premium_gifts()
|
||||||
|
? DisallowedGiftType::Premium
|
||||||
|
: DisallowedGiftType())
|
||||||
|
| (data.is_display_gifts_button()
|
||||||
|
? DisallowedGiftType::SendHide
|
||||||
|
: DisallowedGiftType());
|
||||||
|
} else {
|
||||||
|
_disallowedGiftTypes = data.is_display_gifts_button()
|
||||||
|
? DisallowedGiftType::SendHide
|
||||||
|
: DisallowedGiftType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/flags.h"
|
||||||
#include "mtproto/sender.h"
|
#include "mtproto/sender.h"
|
||||||
|
|
||||||
class ApiWrap;
|
class ApiWrap;
|
||||||
|
@ -23,6 +24,17 @@ enum class UnarchiveOnNewMessage {
|
||||||
AnyUnmuted,
|
AnyUnmuted,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class DisallowedGiftType : uchar {
|
||||||
|
Limited = 0x01,
|
||||||
|
Unlimited = 0x02,
|
||||||
|
Unique = 0x04,
|
||||||
|
Premium = 0x08,
|
||||||
|
SendHide = 0x10,
|
||||||
|
};
|
||||||
|
inline constexpr bool is_flag_type(DisallowedGiftType) { return true; }
|
||||||
|
|
||||||
|
using DisallowedGiftTypes = base::flags<DisallowedGiftType>;
|
||||||
|
|
||||||
[[nodiscard]] PeerId ParsePaidReactionShownPeer(
|
[[nodiscard]] PeerId ParsePaidReactionShownPeer(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPPaidReactionPrivacy &value);
|
const MTPPaidReactionPrivacy &value);
|
||||||
|
@ -49,23 +61,34 @@ public:
|
||||||
[[nodiscard]] bool hideReadTimeCurrent() const;
|
[[nodiscard]] bool hideReadTimeCurrent() const;
|
||||||
[[nodiscard]] rpl::producer<bool> hideReadTime() const;
|
[[nodiscard]] rpl::producer<bool> hideReadTime() const;
|
||||||
|
|
||||||
void updateNewRequirePremium(bool value);
|
|
||||||
[[nodiscard]] bool newRequirePremiumCurrent() const;
|
[[nodiscard]] bool newRequirePremiumCurrent() const;
|
||||||
[[nodiscard]] rpl::producer<bool> newRequirePremium() const;
|
[[nodiscard]] rpl::producer<bool> newRequirePremium() const;
|
||||||
|
|
||||||
|
[[nodiscard]] int newChargeStarsCurrent() const;
|
||||||
|
[[nodiscard]] rpl::producer<int> newChargeStars() const;
|
||||||
|
|
||||||
|
void updateMessagesPrivacy(bool requirePremium, int chargeStars);
|
||||||
|
|
||||||
|
[[nodiscard]] DisallowedGiftTypes disallowedGiftTypesCurrent() const;
|
||||||
|
[[nodiscard]] auto disallowedGiftTypes() const
|
||||||
|
-> rpl::producer<DisallowedGiftTypes>;
|
||||||
|
void updateDisallowedGiftTypes(DisallowedGiftTypes types);
|
||||||
|
|
||||||
void loadPaidReactionShownPeer();
|
void loadPaidReactionShownPeer();
|
||||||
void updatePaidReactionShownPeer(PeerId shownPeer);
|
void updatePaidReactionShownPeer(PeerId shownPeer);
|
||||||
[[nodiscard]] PeerId paidReactionShownPeerCurrent() const;
|
[[nodiscard]] PeerId paidReactionShownPeerCurrent() const;
|
||||||
[[nodiscard]] rpl::producer<PeerId> paidReactionShownPeer() const;
|
[[nodiscard]] rpl::producer<PeerId> paidReactionShownPeer() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void apply(const MTPGlobalPrivacySettings &data);
|
void apply(const MTPGlobalPrivacySettings &settings);
|
||||||
|
|
||||||
void update(
|
void update(
|
||||||
bool archiveAndMute,
|
bool archiveAndMute,
|
||||||
UnarchiveOnNewMessage unarchiveOnNewMessage,
|
UnarchiveOnNewMessage unarchiveOnNewMessage,
|
||||||
bool hideReadTime,
|
bool hideReadTime,
|
||||||
bool newRequirePremium);
|
bool newRequirePremium,
|
||||||
|
int newChargeStars,
|
||||||
|
DisallowedGiftTypes disallowedGiftTypes);
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
|
@ -76,6 +99,8 @@ private:
|
||||||
rpl::variable<bool> _showArchiveAndMute = false;
|
rpl::variable<bool> _showArchiveAndMute = false;
|
||||||
rpl::variable<bool> _hideReadTime = false;
|
rpl::variable<bool> _hideReadTime = false;
|
||||||
rpl::variable<bool> _newRequirePremium = false;
|
rpl::variable<bool> _newRequirePremium = false;
|
||||||
|
rpl::variable<int> _newChargeStars = 0;
|
||||||
|
rpl::variable<DisallowedGiftTypes> _disallowedGiftTypes;
|
||||||
rpl::variable<PeerId> _paidReactionShownPeer = false;
|
rpl::variable<PeerId> _paidReactionShownPeer = false;
|
||||||
std::vector<Fn<void()>> _callbacks;
|
std::vector<Fn<void()>> _callbacks;
|
||||||
bool _paidReactionShownPeerLoaded = false;
|
bool _paidReactionShownPeerLoaded = false;
|
||||||
|
|
|
@ -28,8 +28,8 @@ constexpr auto kSearchPerPage = 50;
|
||||||
auto result = MessageIdsList();
|
auto result = MessageIdsList();
|
||||||
for (const auto &message : messages) {
|
for (const auto &message : messages) {
|
||||||
const auto peerId = PeerFromMessage(message);
|
const auto peerId = PeerFromMessage(message);
|
||||||
if (const auto peer = data->peerLoaded(peerId)) {
|
if (data->peerLoaded(peerId)) {
|
||||||
if (const auto lastDate = DateFromMessage(message)) {
|
if (DateFromMessage(message)) {
|
||||||
const auto item = data->addNewMessage(
|
const auto item = data->addNewMessage(
|
||||||
message,
|
message,
|
||||||
MessageFlags(),
|
MessageFlags(),
|
||||||
|
|
170
Telegram/SourceFiles/api/api_peer_search.cpp
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
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_peer_search.h"
|
||||||
|
|
||||||
|
#include "api/api_single_message_search.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "dialogs/ui/chat_search_in.h" // IsHashOrCashtagSearchQuery
|
||||||
|
#include "main/main_session.h"
|
||||||
|
|
||||||
|
namespace Api {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kMinSponsoredQueryLength = 4;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
PeerSearch::PeerSearch(not_null<Main::Session*> session, Type type)
|
||||||
|
: _session(session)
|
||||||
|
, _type(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerSearch::~PeerSearch() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerSearch::request(
|
||||||
|
const QString &query,
|
||||||
|
Fn<void(PeerSearchResult)> callback,
|
||||||
|
RequestType type) {
|
||||||
|
using namespace Dialogs;
|
||||||
|
_query = Api::ConvertPeerSearchQuery(query);
|
||||||
|
_callback = callback;
|
||||||
|
if (_query.isEmpty()
|
||||||
|
|| IsHashOrCashtagSearchQuery(_query) != HashOrCashtag::None) {
|
||||||
|
finish(PeerSearchResult{});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &cache = _cache[_query];
|
||||||
|
if (cache.peersReady && cache.sponsoredReady) {
|
||||||
|
finish(cache.result);
|
||||||
|
return;
|
||||||
|
} else if (type == RequestType::CacheOnly) {
|
||||||
|
_callback = nullptr;
|
||||||
|
return;
|
||||||
|
} else if (cache.requested) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cache.requested = true;
|
||||||
|
cache.result.query = _query;
|
||||||
|
if (_query.size() < kMinSponsoredQueryLength) {
|
||||||
|
cache.sponsoredReady = true;
|
||||||
|
} else if (_type == Type::WithSponsored) {
|
||||||
|
requestSponsored();
|
||||||
|
}
|
||||||
|
requestPeers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerSearch::requestPeers() {
|
||||||
|
const auto requestId = _session->api().request(MTPcontacts_Search(
|
||||||
|
MTP_string(_query),
|
||||||
|
MTP_int(SearchPeopleLimit)
|
||||||
|
)).done([=](const MTPcontacts_Found &result, mtpRequestId requestId) {
|
||||||
|
const auto &data = result.data();
|
||||||
|
_session->data().processUsers(data.vusers());
|
||||||
|
_session->data().processChats(data.vchats());
|
||||||
|
auto parsed = PeerSearchResult();
|
||||||
|
parsed.my.reserve(data.vmy_results().v.size());
|
||||||
|
for (const auto &id : data.vmy_results().v) {
|
||||||
|
const auto peerId = peerFromMTP(id);
|
||||||
|
parsed.my.push_back(_session->data().peer(peerId));
|
||||||
|
}
|
||||||
|
parsed.peers.reserve(data.vresults().v.size());
|
||||||
|
for (const auto &id : data.vresults().v) {
|
||||||
|
const auto peerId = peerFromMTP(id);
|
||||||
|
parsed.peers.push_back(_session->data().peer(peerId));
|
||||||
|
}
|
||||||
|
finishPeers(requestId, std::move(parsed));
|
||||||
|
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||||
|
finishPeers(requestId, PeerSearchResult{});
|
||||||
|
}).send();
|
||||||
|
_peerRequests.emplace(requestId, _query);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerSearch::requestSponsored() {
|
||||||
|
const auto requestId = _session->api().request(
|
||||||
|
MTPcontacts_GetSponsoredPeers(MTP_string(_query))
|
||||||
|
).done([=](
|
||||||
|
const MTPcontacts_SponsoredPeers &result,
|
||||||
|
mtpRequestId requestId) {
|
||||||
|
result.match([&](const MTPDcontacts_sponsoredPeersEmpty &) {
|
||||||
|
finishSponsored(requestId, PeerSearchResult{});
|
||||||
|
}, [&](const MTPDcontacts_sponsoredPeers &data) {
|
||||||
|
_session->data().processUsers(data.vusers());
|
||||||
|
_session->data().processChats(data.vchats());
|
||||||
|
auto parsed = PeerSearchResult();
|
||||||
|
parsed.sponsored.reserve(data.vpeers().v.size());
|
||||||
|
for (const auto &peer : data.vpeers().v) {
|
||||||
|
const auto &data = peer.data();
|
||||||
|
const auto peerId = peerFromMTP(data.vpeer());
|
||||||
|
parsed.sponsored.push_back({
|
||||||
|
.peer = _session->data().peer(peerId),
|
||||||
|
.randomId = data.vrandom_id().v,
|
||||||
|
.sponsorInfo = TextWithEntities::Simple(
|
||||||
|
qs(data.vsponsor_info().value_or_empty())),
|
||||||
|
.additionalInfo = TextWithEntities::Simple(
|
||||||
|
qs(data.vadditional_info().value_or_empty())),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
finishSponsored(requestId, std::move(parsed));
|
||||||
|
});
|
||||||
|
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||||
|
finishSponsored(requestId, PeerSearchResult{});
|
||||||
|
}).send();
|
||||||
|
_sponsoredRequests.emplace(requestId, _query);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerSearch::finishPeers(
|
||||||
|
mtpRequestId requestId,
|
||||||
|
PeerSearchResult result) {
|
||||||
|
const auto query = _peerRequests.take(requestId);
|
||||||
|
Assert(query.has_value());
|
||||||
|
|
||||||
|
auto &cache = _cache[*query];
|
||||||
|
cache.peersReady = true;
|
||||||
|
cache.result.my = std::move(result.my);
|
||||||
|
cache.result.peers = std::move(result.peers);
|
||||||
|
if (cache.sponsoredReady && _query == *query) {
|
||||||
|
finish(cache.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerSearch::finishSponsored(
|
||||||
|
mtpRequestId requestId,
|
||||||
|
PeerSearchResult result) {
|
||||||
|
const auto query = _sponsoredRequests.take(requestId);
|
||||||
|
Assert(query.has_value());
|
||||||
|
|
||||||
|
auto &cache = _cache[*query];
|
||||||
|
cache.sponsoredReady = true;
|
||||||
|
cache.result.sponsored = std::move(result.sponsored);
|
||||||
|
if (cache.peersReady && _query == *query) {
|
||||||
|
finish(cache.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerSearch::finish(PeerSearchResult result) {
|
||||||
|
if (const auto onstack = base::take(_callback)) {
|
||||||
|
onstack(std::move(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerSearch::clear() {
|
||||||
|
_query = QString();
|
||||||
|
_callback = nullptr;
|
||||||
|
_cache.clear();
|
||||||
|
for (const auto &[requestId, query] : base::take(_peerRequests)) {
|
||||||
|
_session->api().request(requestId).cancel();
|
||||||
|
}
|
||||||
|
for (const auto &[requestId, query] : base::take(_sponsoredRequests)) {
|
||||||
|
_session->api().request(requestId).cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Api
|
76
Telegram/SourceFiles/api/api_peer_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 {
|
||||||
|
|
||||||
|
struct SponsoredSearchResult {
|
||||||
|
not_null<PeerData*> peer;
|
||||||
|
QByteArray randomId;
|
||||||
|
TextWithEntities sponsorInfo;
|
||||||
|
TextWithEntities additionalInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PeerSearchResult {
|
||||||
|
QString query;
|
||||||
|
std::vector<not_null<PeerData*>> my;
|
||||||
|
std::vector<not_null<PeerData*>> peers;
|
||||||
|
std::vector<SponsoredSearchResult> sponsored;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PeerSearch final {
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
WithSponsored,
|
||||||
|
JustPeers,
|
||||||
|
};
|
||||||
|
PeerSearch(not_null<Main::Session*> session, Type type);
|
||||||
|
~PeerSearch();
|
||||||
|
|
||||||
|
enum class RequestType {
|
||||||
|
CacheOnly,
|
||||||
|
CacheOrRemote,
|
||||||
|
};
|
||||||
|
void request(
|
||||||
|
const QString &query,
|
||||||
|
Fn<void(PeerSearchResult)> callback,
|
||||||
|
RequestType type = RequestType::CacheOrRemote);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CacheEntry {
|
||||||
|
PeerSearchResult result;
|
||||||
|
bool requested = false;
|
||||||
|
bool peersReady = false;
|
||||||
|
bool sponsoredReady = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void requestPeers();
|
||||||
|
void requestSponsored();
|
||||||
|
|
||||||
|
void finish(PeerSearchResult result);
|
||||||
|
void finishPeers(mtpRequestId requestId, PeerSearchResult result);
|
||||||
|
void finishSponsored(mtpRequestId requestId, PeerSearchResult result);
|
||||||
|
|
||||||
|
const not_null<Main::Session*> _session;
|
||||||
|
const Type _type;
|
||||||
|
|
||||||
|
QString _query;
|
||||||
|
Fn<void(PeerSearchResult)> _callback;
|
||||||
|
|
||||||
|
base::flat_map<QString, CacheEntry> _cache;
|
||||||
|
base::flat_map<mtpRequestId, QString> _peerRequests;
|
||||||
|
base::flat_map<mtpRequestId, QString> _sponsoredRequests;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Api
|
|
@ -42,7 +42,7 @@ Polls::Polls(not_null<ApiWrap*> api)
|
||||||
|
|
||||||
void Polls::create(
|
void Polls::create(
|
||||||
const PollData &data,
|
const PollData &data,
|
||||||
const SendAction &action,
|
SendAction action,
|
||||||
Fn<void()> done,
|
Fn<void()> done,
|
||||||
Fn<void()> fail) {
|
Fn<void()> fail) {
|
||||||
_session->api().sendAction(action);
|
_session->api().sendAction(action);
|
||||||
|
@ -64,6 +64,9 @@ void Polls::create(
|
||||||
history->startSavingCloudDraft(topicRootId);
|
history->startSavingCloudDraft(topicRootId);
|
||||||
}
|
}
|
||||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||||
|
const auto starsPaid = std::min(
|
||||||
|
peer->starsPerMessageChecked(),
|
||||||
|
action.options.starsApproved);
|
||||||
if (silentPost) {
|
if (silentPost) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +79,10 @@ void Polls::create(
|
||||||
if (action.options.effectId) {
|
if (action.options.effectId) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||||
}
|
}
|
||||||
|
if (starsPaid) {
|
||||||
|
action.options.starsApproved -= starsPaid;
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
|
||||||
|
}
|
||||||
const auto sendAs = action.options.sendAs;
|
const auto sendAs = action.options.sendAs;
|
||||||
if (sendAs) {
|
if (sendAs) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||||
|
@ -98,7 +105,8 @@ void Polls::create(
|
||||||
MTP_int(action.options.scheduled),
|
MTP_int(action.options.scheduled),
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||||
Data::ShortcutIdToMTP(_session, action.options.shortcutId),
|
Data::ShortcutIdToMTP(_session, action.options.shortcutId),
|
||||||
MTP_long(action.options.effectId)
|
MTP_long(action.options.effectId),
|
||||||
|
MTP_long(starsPaid)
|
||||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
|
@ -163,8 +171,8 @@ void Polls::sendVotes(
|
||||||
hideSending();
|
hideSending();
|
||||||
_session->updates().applyUpdates(result);
|
_session->updates().applyUpdates(result);
|
||||||
|
|
||||||
const auto settings = &AyuSettings::getInstance();
|
const auto& settings = AyuSettings::getInstance();
|
||||||
if (!settings->sendReadMessages && settings->markReadAfterAction && item)
|
if (!settings.sendReadMessages && settings.markReadAfterAction && item)
|
||||||
{
|
{
|
||||||
readHistory(item);
|
readHistory(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
|
|
||||||
void create(
|
void create(
|
||||||
const PollData &data,
|
const PollData &data,
|
||||||
const SendAction &action,
|
SendAction action,
|
||||||
Fn<void()> done,
|
Fn<void()> done,
|
||||||
Fn<void()> fail);
|
Fn<void()> fail);
|
||||||
void sendVotes(
|
void sendVotes(
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_text_entities.h"
|
#include "api/api_text_entities.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
|
#include "data/data_channel.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_peer_values.h"
|
#include "data/data_peer_values.h"
|
||||||
|
@ -377,15 +378,15 @@ const Data::PremiumSubscriptionOptions &Premium::subscriptionOptions() const {
|
||||||
return _subscriptionOptions;
|
return _subscriptionOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<> Premium::somePremiumRequiredResolved() const {
|
rpl::producer<> Premium::someMessageMoneyRestrictionsResolved() const {
|
||||||
return _somePremiumRequiredResolved.events();
|
return _someMessageMoneyRestrictionsResolved.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Premium::resolvePremiumRequired(not_null<UserData*> user) {
|
void Premium::resolveMessageMoneyRestrictions(not_null<UserData*> user) {
|
||||||
_resolvePremiumRequiredUsers.emplace(user);
|
_resolveMessageMoneyRequiredUsers.emplace(user);
|
||||||
if (!_premiumRequiredRequestScheduled
|
if (!_messageMoneyRequestScheduled
|
||||||
&& _resolvePremiumRequestedUsers.empty()) {
|
&& _resolveMessageMoneyRequestedUsers.empty()) {
|
||||||
_premiumRequiredRequestScheduled = true;
|
_messageMoneyRequestScheduled = true;
|
||||||
crl::on_main(_session, [=] {
|
crl::on_main(_session, [=] {
|
||||||
requestPremiumRequiredSlice();
|
requestPremiumRequiredSlice();
|
||||||
});
|
});
|
||||||
|
@ -393,50 +394,65 @@ void Premium::resolvePremiumRequired(not_null<UserData*> user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Premium::requestPremiumRequiredSlice() {
|
void Premium::requestPremiumRequiredSlice() {
|
||||||
_premiumRequiredRequestScheduled = false;
|
_messageMoneyRequestScheduled = false;
|
||||||
if (!_resolvePremiumRequestedUsers.empty()
|
if (!_resolveMessageMoneyRequestedUsers.empty()
|
||||||
|| _resolvePremiumRequiredUsers.empty()) {
|
|| _resolveMessageMoneyRequiredUsers.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
constexpr auto kPerRequest = 100;
|
constexpr auto kPerRequest = 100;
|
||||||
auto users = MTP_vector_from_range(_resolvePremiumRequiredUsers
|
auto users = MTP_vector_from_range(_resolveMessageMoneyRequiredUsers
|
||||||
| ranges::views::transform(&UserData::inputUser));
|
| ranges::views::transform(&UserData::inputUser));
|
||||||
if (users.v.size() > kPerRequest) {
|
if (users.v.size() > kPerRequest) {
|
||||||
auto shortened = users.v;
|
auto shortened = users.v;
|
||||||
shortened.resize(kPerRequest);
|
shortened.resize(kPerRequest);
|
||||||
users = MTP_vector<MTPInputUser>(std::move(shortened));
|
users = MTP_vector<MTPInputUser>(std::move(shortened));
|
||||||
const auto from = begin(_resolvePremiumRequiredUsers);
|
const auto from = begin(_resolveMessageMoneyRequiredUsers);
|
||||||
_resolvePremiumRequestedUsers = { from, from + kPerRequest };
|
_resolveMessageMoneyRequestedUsers = { from, from + kPerRequest };
|
||||||
_resolvePremiumRequiredUsers.erase(from, from + kPerRequest);
|
_resolveMessageMoneyRequiredUsers.erase(from, from + kPerRequest);
|
||||||
} else {
|
} else {
|
||||||
_resolvePremiumRequestedUsers
|
_resolveMessageMoneyRequestedUsers
|
||||||
= base::take(_resolvePremiumRequiredUsers);
|
= base::take(_resolveMessageMoneyRequiredUsers);
|
||||||
}
|
}
|
||||||
const auto finish = [=](const QVector<MTPBool> &list) {
|
const auto finish = [=](const QVector<MTPRequirementToContact> &list) {
|
||||||
constexpr auto me = UserDataFlag::MeRequiresPremiumToWrite;
|
|
||||||
constexpr auto known = UserDataFlag::RequirePremiumToWriteKnown;
|
|
||||||
constexpr auto mask = me | known;
|
|
||||||
|
|
||||||
auto index = 0;
|
auto index = 0;
|
||||||
for (const auto &user : base::take(_resolvePremiumRequestedUsers)) {
|
for (const auto &user : base::take(_resolveMessageMoneyRequestedUsers)) {
|
||||||
const auto require = (index < list.size())
|
const auto set = [&](bool requirePremium, int stars) {
|
||||||
&& mtpIsTrue(list[index++]);
|
using Flag = UserDataFlag;
|
||||||
user->setFlags((user->flags() & ~mask)
|
constexpr auto me = Flag::RequiresPremiumToWrite;
|
||||||
|
constexpr auto known = Flag::MessageMoneyRestrictionsKnown;
|
||||||
|
constexpr auto hasPrem = Flag::HasRequirePremiumToWrite;
|
||||||
|
constexpr auto hasStars = Flag::HasStarsPerMessage;
|
||||||
|
user->setStarsPerMessage(stars);
|
||||||
|
user->setFlags((user->flags() & ~(me | hasPrem | hasStars))
|
||||||
| known
|
| known
|
||||||
| (require ? me : UserDataFlag()));
|
| (requirePremium ? (me | hasPrem) : Flag())
|
||||||
|
| (stars ? hasStars : Flag()));
|
||||||
|
};
|
||||||
|
if (index >= list.size()) {
|
||||||
|
set(false, 0);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (!_premiumRequiredRequestScheduled
|
list[index++].match([&](const MTPDrequirementToContactEmpty &) {
|
||||||
&& !_resolvePremiumRequiredUsers.empty()) {
|
set(false, 0);
|
||||||
_premiumRequiredRequestScheduled = true;
|
}, [&](const MTPDrequirementToContactPremium &) {
|
||||||
|
set(true, 0);
|
||||||
|
}, [&](const MTPDrequirementToContactPaidMessages &data) {
|
||||||
|
set(false, data.vstars_amount().v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!_messageMoneyRequestScheduled
|
||||||
|
&& !_resolveMessageMoneyRequiredUsers.empty()) {
|
||||||
|
_messageMoneyRequestScheduled = true;
|
||||||
crl::on_main(_session, [=] {
|
crl::on_main(_session, [=] {
|
||||||
requestPremiumRequiredSlice();
|
requestPremiumRequiredSlice();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_somePremiumRequiredResolved.fire({});
|
_someMessageMoneyRestrictionsResolved.fire({});
|
||||||
};
|
};
|
||||||
_session->api().request(
|
_session->api().request(
|
||||||
MTPusers_GetIsPremiumRequiredToContact(std::move(users))
|
MTPusers_GetRequirementsToContact(std::move(users))
|
||||||
).done([=](const MTPVector<MTPBool> &result) {
|
).done([=](const MTPVector<MTPRequirementToContact> &result) {
|
||||||
finish(result.v);
|
finish(result.v);
|
||||||
}).fail([=] {
|
}).fail([=] {
|
||||||
finish({});
|
finish({});
|
||||||
|
@ -463,10 +479,14 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::request() {
|
||||||
for (const auto &tlOption : result.v) {
|
for (const auto &tlOption : result.v) {
|
||||||
const auto &data = tlOption.data();
|
const auto &data = tlOption.data();
|
||||||
tlMapOptions[data.vusers().v].push_back(tlOption);
|
tlMapOptions[data.vusers().v].push_back(tlOption);
|
||||||
|
if (qs(data.vcurrency()) == Ui::kCreditsCurrency) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const auto token = Token{ data.vusers().v, data.vmonths().v };
|
const auto token = Token{ data.vusers().v, data.vmonths().v };
|
||||||
_stores[token] = Store{
|
_stores[token] = Store{
|
||||||
.amount = data.vamount().v,
|
.amount = data.vamount().v,
|
||||||
|
.currency = qs(data.vcurrency()),
|
||||||
.product = qs(data.vstore_product().value_or_empty()),
|
.product = qs(data.vstore_product().value_or_empty()),
|
||||||
.quantity = data.vstore_quantity().value_or_empty(),
|
.quantity = data.vstore_quantity().value_or_empty(),
|
||||||
};
|
};
|
||||||
|
@ -475,14 +495,14 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::request() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &[amount, tlOptions] : tlMapOptions) {
|
for (const auto &[amount, tlOptions] : tlMapOptions) {
|
||||||
if (amount == 1 && _optionsForOnePerson.currency.isEmpty()) {
|
if (amount == 1 && _optionsForOnePerson.currencies.empty()) {
|
||||||
_optionsForOnePerson.currency = qs(
|
|
||||||
tlOptions.front().data().vcurrency());
|
|
||||||
for (const auto &option : tlOptions) {
|
for (const auto &option : tlOptions) {
|
||||||
_optionsForOnePerson.months.push_back(
|
_optionsForOnePerson.months.push_back(
|
||||||
option.data().vmonths().v);
|
option.data().vmonths().v);
|
||||||
_optionsForOnePerson.totalCosts.push_back(
|
_optionsForOnePerson.totalCosts.push_back(
|
||||||
option.data().vamount().v);
|
option.data().vamount().v);
|
||||||
|
_optionsForOnePerson.currencies.push_back(
|
||||||
|
qs(option.data().vcurrency()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_subscriptionOptions[amount] = GiftCodesFromTL(tlOptions);
|
_subscriptionOptions[amount] = GiftCodesFromTL(tlOptions);
|
||||||
|
@ -509,7 +529,7 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::applyPrepaid(
|
||||||
_api.request(MTPpayments_LaunchPrepaidGiveaway(
|
_api.request(MTPpayments_LaunchPrepaidGiveaway(
|
||||||
_peer->input,
|
_peer->input,
|
||||||
MTP_long(prepaidId),
|
MTP_long(prepaidId),
|
||||||
invoice.creditsAmount
|
invoice.giveawayCredits
|
||||||
? Payments::InvoiceCreditsGiveawayToTL(invoice)
|
? Payments::InvoiceCreditsGiveawayToTL(invoice)
|
||||||
: Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
|
: Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
@ -540,7 +560,7 @@ Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
|
||||||
const auto token = Token{ users, months };
|
const auto token = Token{ users, months };
|
||||||
const auto &store = _stores[token];
|
const auto &store = _stores[token];
|
||||||
return Payments::InvoicePremiumGiftCode{
|
return Payments::InvoicePremiumGiftCode{
|
||||||
.currency = _optionsForOnePerson.currency,
|
.currency = store.currency,
|
||||||
.storeProduct = store.product,
|
.storeProduct = store.product,
|
||||||
.randomId = randomId,
|
.randomId = randomId,
|
||||||
.amount = store.amount,
|
.amount = store.amount,
|
||||||
|
@ -553,14 +573,15 @@ Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice(
|
||||||
std::vector<GiftOptionData> PremiumGiftCodeOptions::optionsForPeer() const {
|
std::vector<GiftOptionData> PremiumGiftCodeOptions::optionsForPeer() const {
|
||||||
auto result = std::vector<GiftOptionData>();
|
auto result = std::vector<GiftOptionData>();
|
||||||
|
|
||||||
if (!_optionsForOnePerson.currency.isEmpty()) {
|
if (!_optionsForOnePerson.currencies.empty()) {
|
||||||
const auto count = int(_optionsForOnePerson.months.size());
|
const auto count = int(_optionsForOnePerson.months.size());
|
||||||
result.reserve(count);
|
result.reserve(count);
|
||||||
for (auto i = 0; i != count; ++i) {
|
for (auto i = 0; i != count; ++i) {
|
||||||
Assert(i < _optionsForOnePerson.totalCosts.size());
|
Assert(i < _optionsForOnePerson.totalCosts.size());
|
||||||
|
Assert(i < _optionsForOnePerson.currencies.size());
|
||||||
result.push_back({
|
result.push_back({
|
||||||
.cost = _optionsForOnePerson.totalCosts[i],
|
.cost = _optionsForOnePerson.totalCosts[i],
|
||||||
.currency = _optionsForOnePerson.currency,
|
.currency = _optionsForOnePerson.currencies[i],
|
||||||
.months = _optionsForOnePerson.months[i],
|
.months = _optionsForOnePerson.months[i],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -581,7 +602,7 @@ Data::PremiumSubscriptionOptions PremiumGiftCodeOptions::options(int amount) {
|
||||||
MTP_int(_optionsForOnePerson.months[i]),
|
MTP_int(_optionsForOnePerson.months[i]),
|
||||||
MTPstring(),
|
MTPstring(),
|
||||||
MTPint(),
|
MTPint(),
|
||||||
MTP_string(_optionsForOnePerson.currency),
|
MTP_string(_optionsForOnePerson.currencies[i]),
|
||||||
MTP_long(_optionsForOnePerson.totalCosts[i] * amount)));
|
MTP_long(_optionsForOnePerson.totalCosts[i] * amount)));
|
||||||
}
|
}
|
||||||
_subscriptionOptions[amount] = GiftCodesFromTL(tlOptions);
|
_subscriptionOptions[amount] = GiftCodesFromTL(tlOptions);
|
||||||
|
@ -694,28 +715,38 @@ rpl::producer<rpl::no_value, QString> SponsoredToggle::setToggled(bool v) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
RequirePremiumState ResolveRequiresPremiumToWrite(
|
MessageMoneyRestriction ResolveMessageMoneyRestrictions(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
History *maybeHistory) {
|
History *maybeHistory) {
|
||||||
const auto user = peer->asUser();
|
if (const auto channel = peer->asChannel()) {
|
||||||
if (!user
|
return {
|
||||||
|| !user->someRequirePremiumToWrite()
|
.starsPerMessage = channel->starsPerMessageChecked(),
|
||||||
|| user->session().premium()) {
|
.known = true,
|
||||||
return RequirePremiumState::No;
|
};
|
||||||
} else if (user->requirePremiumToWriteKnown()) {
|
}
|
||||||
return user->meRequiresPremiumToWrite()
|
const auto user = peer->asUser();
|
||||||
? RequirePremiumState::Yes
|
if (!user) {
|
||||||
: RequirePremiumState::No;
|
return { .known = true };
|
||||||
} else if (user->flags() & UserDataFlag::MutualContact) {
|
} else if (user->messageMoneyRestrictionsKnown()) {
|
||||||
return RequirePremiumState::No;
|
return {
|
||||||
} else if (!maybeHistory) {
|
.starsPerMessage = user->starsPerMessageChecked(),
|
||||||
return RequirePremiumState::Unknown;
|
.premiumRequired = (user->requiresPremiumToWrite()
|
||||||
|
&& !user->session().premium()),
|
||||||
|
.known = true,
|
||||||
|
};
|
||||||
|
} else if (user->hasStarsPerMessage()) {
|
||||||
|
return {};
|
||||||
|
} else if (!user->hasRequirePremiumToWrite()) {
|
||||||
|
return { .known = true };
|
||||||
|
} else if (user->flags() & UserDataFlag::MutualContact) {
|
||||||
|
return { .known = true };
|
||||||
|
} else if (!maybeHistory) {
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto update = [&](bool require) {
|
const auto update = [&](bool require) {
|
||||||
using Flag = UserDataFlag;
|
using Flag = UserDataFlag;
|
||||||
constexpr auto known = Flag::RequirePremiumToWriteKnown;
|
constexpr auto known = Flag::MessageMoneyRestrictionsKnown;
|
||||||
constexpr auto me = Flag::MeRequiresPremiumToWrite;
|
constexpr auto me = Flag::RequiresPremiumToWrite;
|
||||||
user->setFlags((user->flags() & ~me)
|
user->setFlags((user->flags() & ~me)
|
||||||
| known
|
| known
|
||||||
| (require ? me : Flag()));
|
| (require ? me : Flag()));
|
||||||
|
@ -727,16 +758,19 @@ RequirePremiumState ResolveRequiresPremiumToWrite(
|
||||||
const auto item = view->data();
|
const auto item = view->data();
|
||||||
if (!item->out() && !item->isService()) {
|
if (!item->out() && !item->isService()) {
|
||||||
update(false);
|
update(false);
|
||||||
return RequirePremiumState::No;
|
return { .known = true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (user->isContact() // Here we know, that we're not in his contacts.
|
if (user->isContact() // Here we know, that we're not in his contacts.
|
||||||
&& maybeHistory->loadedAtTop() // And no incoming messages.
|
&& maybeHistory->loadedAtTop() // And no incoming messages.
|
||||||
&& maybeHistory->loadedAtBottom()) {
|
&& maybeHistory->loadedAtBottom()) {
|
||||||
update(true);
|
return {
|
||||||
|
.premiumRequired = !user->session().premium(),
|
||||||
|
.known = true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return RequirePremiumState::Unknown;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<DocumentData*> RandomHelloStickerValue(
|
rpl::producer<DocumentData*> RandomHelloStickerValue(
|
||||||
|
@ -765,6 +799,7 @@ std::optional<Data::StarGift> FromTL(
|
||||||
return gift.match([&](const MTPDstarGift &data) {
|
return gift.match([&](const MTPDstarGift &data) {
|
||||||
const auto document = session->data().processDocument(
|
const auto document = session->data().processDocument(
|
||||||
data.vsticker());
|
data.vsticker());
|
||||||
|
const auto resellPrice = data.vresell_min_stars().value_or_empty();
|
||||||
const auto remaining = data.vavailability_remains();
|
const auto remaining = data.vavailability_remains();
|
||||||
const auto total = data.vavailability_total();
|
const auto total = data.vavailability_total();
|
||||||
if (!document->sticker()) {
|
if (!document->sticker()) {
|
||||||
|
@ -775,13 +810,17 @@ std::optional<Data::StarGift> FromTL(
|
||||||
.stars = int64(data.vstars().v),
|
.stars = int64(data.vstars().v),
|
||||||
.starsConverted = int64(data.vconvert_stars().v),
|
.starsConverted = int64(data.vconvert_stars().v),
|
||||||
.starsToUpgrade = int64(data.vupgrade_stars().value_or_empty()),
|
.starsToUpgrade = int64(data.vupgrade_stars().value_or_empty()),
|
||||||
|
.starsResellMin = int64(resellPrice),
|
||||||
.document = document,
|
.document = document,
|
||||||
|
.resellTitle = qs(data.vtitle().value_or_empty()),
|
||||||
|
.resellCount = int(data.vavailability_resale().value_or_empty()),
|
||||||
.limitedLeft = remaining.value_or_empty(),
|
.limitedLeft = remaining.value_or_empty(),
|
||||||
.limitedCount = total.value_or_empty(),
|
.limitedCount = total.value_or_empty(),
|
||||||
.firstSaleDate = data.vfirst_sale_date().value_or_empty(),
|
.firstSaleDate = data.vfirst_sale_date().value_or_empty(),
|
||||||
.lastSaleDate = data.vlast_sale_date().value_or_empty(),
|
.lastSaleDate = data.vlast_sale_date().value_or_empty(),
|
||||||
.upgradable = data.vupgrade_stars().has_value(),
|
.upgradable = data.vupgrade_stars().has_value(),
|
||||||
.birthday = data.is_birthday(),
|
.birthday = data.is_birthday(),
|
||||||
|
.soldOut = data.is_sold_out(),
|
||||||
});
|
});
|
||||||
}, [&](const MTPDstarGiftUnique &data) {
|
}, [&](const MTPDstarGiftUnique &data) {
|
||||||
const auto total = data.vavailability_total().v;
|
const auto total = data.vavailability_total().v;
|
||||||
|
@ -814,6 +853,7 @@ std::optional<Data::StarGift> FromTL(
|
||||||
? peerFromMTP(*data.vowner_id())
|
? peerFromMTP(*data.vowner_id())
|
||||||
: PeerId()),
|
: PeerId()),
|
||||||
.number = data.vnum().v,
|
.number = data.vnum().v,
|
||||||
|
.starsForResale = int(data.vresell_stars().value_or_empty()),
|
||||||
.model = *model,
|
.model = *model,
|
||||||
.pattern = *pattern,
|
.pattern = *pattern,
|
||||||
}),
|
}),
|
||||||
|
@ -846,8 +886,11 @@ std::optional<Data::SavedStarGift> FromTL(
|
||||||
} else if (const auto unique = parsed->unique.get()) {
|
} else if (const auto unique = parsed->unique.get()) {
|
||||||
unique->starsForTransfer = data.vtransfer_stars().value_or(-1);
|
unique->starsForTransfer = data.vtransfer_stars().value_or(-1);
|
||||||
unique->exportAt = data.vcan_export_at().value_or_empty();
|
unique->exportAt = data.vcan_export_at().value_or_empty();
|
||||||
|
unique->canTransferAt = data.vcan_transfer_at().value_or_empty();
|
||||||
|
unique->canResellAt = data.vcan_resell_at().value_or_empty();
|
||||||
}
|
}
|
||||||
using Id = Data::SavedStarGiftId;
|
using Id = Data::SavedStarGiftId;
|
||||||
|
const auto hasUnique = parsed->unique != nullptr;
|
||||||
return Data::SavedStarGift{
|
return Data::SavedStarGift{
|
||||||
.info = std::move(*parsed),
|
.info = std::move(*parsed),
|
||||||
.manageId = (to->isUser()
|
.manageId = (to->isUser()
|
||||||
|
@ -870,6 +913,7 @@ std::optional<Data::SavedStarGift> FromTL(
|
||||||
.date = data.vdate().v,
|
.date = data.vdate().v,
|
||||||
.upgradable = data.is_can_upgrade(),
|
.upgradable = data.is_can_upgrade(),
|
||||||
.anonymous = data.is_name_hidden(),
|
.anonymous = data.is_name_hidden(),
|
||||||
|
.pinned = data.is_pinned_to_top() && hasUnique,
|
||||||
.hidden = data.is_unsaved(),
|
.hidden = data.is_unsaved(),
|
||||||
.mine = to->isSelf(),
|
.mine = to->isSelf(),
|
||||||
};
|
};
|
||||||
|
@ -899,7 +943,7 @@ Data::UniqueGiftPattern FromTL(
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::UniqueGiftBackdrop FromTL(const MTPDstarGiftAttributeBackdrop &data) {
|
Data::UniqueGiftBackdrop FromTL(const MTPDstarGiftAttributeBackdrop &data) {
|
||||||
auto result = Data::UniqueGiftBackdrop();
|
auto result = Data::UniqueGiftBackdrop{ .id = data.vbackdrop_id().v };
|
||||||
result.name = qs(data.vname());
|
result.name = qs(data.vname());
|
||||||
result.rarityPermille = data.vrarity_permille().v;
|
result.rarityPermille = data.vrarity_permille().v;
|
||||||
result.centerColor = Ui::ColorFromSerialized(
|
result.centerColor = Ui::ColorFromSerialized(
|
||||||
|
|
|
@ -116,8 +116,9 @@ public:
|
||||||
[[nodiscard]] auto subscriptionOptions() const
|
[[nodiscard]] auto subscriptionOptions() const
|
||||||
-> const Data::PremiumSubscriptionOptions &;
|
-> const Data::PremiumSubscriptionOptions &;
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> somePremiumRequiredResolved() const;
|
[[nodiscard]] auto someMessageMoneyRestrictionsResolved() const
|
||||||
void resolvePremiumRequired(not_null<UserData*> user);
|
-> rpl::producer<>;
|
||||||
|
void resolveMessageMoneyRestrictions(not_null<UserData*> user);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reloadPromo();
|
void reloadPromo();
|
||||||
|
@ -166,10 +167,10 @@ private:
|
||||||
|
|
||||||
Data::PremiumSubscriptionOptions _subscriptionOptions;
|
Data::PremiumSubscriptionOptions _subscriptionOptions;
|
||||||
|
|
||||||
rpl::event_stream<> _somePremiumRequiredResolved;
|
rpl::event_stream<> _someMessageMoneyRestrictionsResolved;
|
||||||
base::flat_set<not_null<UserData*>> _resolvePremiumRequiredUsers;
|
base::flat_set<not_null<UserData*>> _resolveMessageMoneyRequiredUsers;
|
||||||
base::flat_set<not_null<UserData*>> _resolvePremiumRequestedUsers;
|
base::flat_set<not_null<UserData*>> _resolveMessageMoneyRequestedUsers;
|
||||||
bool _premiumRequiredRequestScheduled = false;
|
bool _messageMoneyRequestScheduled = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -208,6 +209,7 @@ private:
|
||||||
};
|
};
|
||||||
struct Store final {
|
struct Store final {
|
||||||
uint64 amount = 0;
|
uint64 amount = 0;
|
||||||
|
QString currency;
|
||||||
QString product;
|
QString product;
|
||||||
int quantity = 0;
|
int quantity = 0;
|
||||||
};
|
};
|
||||||
|
@ -218,7 +220,7 @@ private:
|
||||||
struct {
|
struct {
|
||||||
std::vector<int> months;
|
std::vector<int> months;
|
||||||
std::vector<int64> totalCosts;
|
std::vector<int64> totalCosts;
|
||||||
QString currency;
|
std::vector<QString> currencies;
|
||||||
} _optionsForOnePerson;
|
} _optionsForOnePerson;
|
||||||
|
|
||||||
std::vector<int> _availablePresets;
|
std::vector<int> _availablePresets;
|
||||||
|
@ -244,12 +246,20 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class RequirePremiumState {
|
struct MessageMoneyRestriction {
|
||||||
Unknown,
|
int starsPerMessage = 0;
|
||||||
Yes,
|
bool premiumRequired = false;
|
||||||
No,
|
bool known = false;
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return starsPerMessage != 0 || premiumRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline bool operator==(
|
||||||
|
const MessageMoneyRestriction &,
|
||||||
|
const MessageMoneyRestriction &) = default;
|
||||||
};
|
};
|
||||||
[[nodiscard]] RequirePremiumState ResolveRequiresPremiumToWrite(
|
[[nodiscard]] MessageMoneyRestriction ResolveMessageMoneyRestrictions(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
History *maybeHistory);
|
History *maybeHistory);
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,17 @@ Data::PremiumSubscriptionOption CreateSubscriptionOption(
|
||||||
* kDiscountDivider;
|
* kDiscountDivider;
|
||||||
}();
|
}();
|
||||||
return {
|
return {
|
||||||
|
.months = months,
|
||||||
.duration = Ui::FormatTTL(months * 86400 * 31),
|
.duration = Ui::FormatTTL(months * 86400 * 31),
|
||||||
.discount = discount
|
.discount = (discount > 0)
|
||||||
? QString::fromUtf8("\xe2\x88\x92%1%").arg(discount)
|
? QString::fromUtf8("\xe2\x88\x92%1%").arg(discount)
|
||||||
: QString(),
|
: QString(),
|
||||||
.costPerMonth = Ui::FillAmountAndCurrency(
|
.costPerMonth = Ui::FillAmountAndCurrency(
|
||||||
amount / float64(months),
|
amount / float64(months),
|
||||||
currency),
|
currency),
|
||||||
|
.costNoDiscount = Ui::FillAmountAndCurrency(
|
||||||
|
monthlyAmount * months,
|
||||||
|
currency),
|
||||||
.costTotal = Ui::FillAmountAndCurrency(amount, currency),
|
.costTotal = Ui::FillAmountAndCurrency(amount, currency),
|
||||||
.botUrl = botUrl,
|
.botUrl = botUrl,
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,15 +24,26 @@ template<typename Option>
|
||||||
if (tlOpts.isEmpty()) {
|
if (tlOpts.isEmpty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
auto monthlyAmountPerCurrency = base::flat_map<QString, int>();
|
||||||
auto result = Data::PremiumSubscriptionOptions();
|
auto result = Data::PremiumSubscriptionOptions();
|
||||||
const auto monthlyAmount = [&] {
|
const auto monthlyAmount = [&](const QString ¤cy) -> int {
|
||||||
|
const auto it = monthlyAmountPerCurrency.find(currency);
|
||||||
|
if (it != end(monthlyAmountPerCurrency)) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
const auto &min = ranges::min_element(
|
const auto &min = ranges::min_element(
|
||||||
tlOpts,
|
tlOpts,
|
||||||
ranges::less(),
|
ranges::less(),
|
||||||
[](const Option &o) { return o.data().vamount().v; }
|
[&](const Option &o) {
|
||||||
|
return currency == qs(o.data().vcurrency())
|
||||||
|
? o.data().vamount().v
|
||||||
|
: std::numeric_limits<int64_t>::max();
|
||||||
|
}
|
||||||
)->data();
|
)->data();
|
||||||
return min.vamount().v / float64(min.vmonths().v);
|
const auto monthly = min.vamount().v / float64(min.vmonths().v);
|
||||||
}();
|
monthlyAmountPerCurrency.emplace(currency, monthly);
|
||||||
|
return monthly;
|
||||||
|
};
|
||||||
result.reserve(tlOpts.size());
|
result.reserve(tlOpts.size());
|
||||||
for (const auto &tlOption : tlOpts) {
|
for (const auto &tlOption : tlOpts) {
|
||||||
const auto &option = tlOption.data();
|
const auto &option = tlOption.data();
|
||||||
|
@ -45,7 +56,7 @@ template<typename Option>
|
||||||
const auto currency = qs(option.vcurrency());
|
const auto currency = qs(option.vcurrency());
|
||||||
result.push_back(CreateSubscriptionOption(
|
result.push_back(CreateSubscriptionOption(
|
||||||
months,
|
months,
|
||||||
monthlyAmount,
|
monthlyAmount(currency),
|
||||||
amount,
|
amount,
|
||||||
currency,
|
currency,
|
||||||
botUrl));
|
botUrl));
|
||||||
|
|
|
@ -118,8 +118,8 @@ void SendProgressManager::send(const Key &key, int progress) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AyuGram sendUploadProgress
|
// AyuGram sendUploadProgress
|
||||||
const auto settings = &AyuSettings::getInstance();
|
const auto& settings = AyuSettings::getInstance();
|
||||||
if (!settings->sendUploadProgress)
|
if (!settings.sendUploadProgress)
|
||||||
{
|
{
|
||||||
DEBUG_LOG(("[AyuGram] Don't send upload progress"));
|
DEBUG_LOG(("[AyuGram] Don't send upload progress"));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -95,7 +95,9 @@ void SendSimpleMedia(SendAction action, MTPInputMedia inputMedia) {
|
||||||
const auto messagePostAuthor = peer->isBroadcast()
|
const auto messagePostAuthor = peer->isBroadcast()
|
||||||
? session->user()->name()
|
? session->user()->name()
|
||||||
: QString();
|
: QString();
|
||||||
|
const auto starsPaid = std::min(
|
||||||
|
peer->starsPerMessageChecked(),
|
||||||
|
action.options.starsApproved);
|
||||||
if (action.options.scheduled) {
|
if (action.options.scheduled) {
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
flags |= MessageFlag::IsOrWasScheduled;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||||
|
@ -111,6 +113,10 @@ void SendSimpleMedia(SendAction action, MTPInputMedia inputMedia) {
|
||||||
flags |= MessageFlag::InvertMedia;
|
flags |= MessageFlag::InvertMedia;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
||||||
}
|
}
|
||||||
|
if (starsPaid) {
|
||||||
|
action.options.starsApproved -= starsPaid;
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
|
||||||
|
}
|
||||||
|
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
|
@ -129,7 +135,8 @@ void SendSimpleMedia(SendAction action, MTPInputMedia inputMedia) {
|
||||||
MTP_int(action.options.scheduled),
|
MTP_int(action.options.scheduled),
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||||
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
||||||
MTP_long(action.options.effectId)
|
MTP_long(action.options.effectId),
|
||||||
|
MTP_long(starsPaid)
|
||||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
api->sendMessageFail(error, peer, randomId);
|
api->sendMessageFail(error, peer, randomId);
|
||||||
|
@ -160,7 +167,7 @@ void SendExistingMedia(
|
||||||
? (*localMessageId)
|
? (*localMessageId)
|
||||||
: session->data().nextLocalMessageId());
|
: session->data().nextLocalMessageId());
|
||||||
const auto randomId = base::RandomValue<uint64>();
|
const auto randomId = base::RandomValue<uint64>();
|
||||||
const auto &action = message.action;
|
auto &action = message.action;
|
||||||
|
|
||||||
auto flags = NewMessageFlags(peer);
|
auto flags = NewMessageFlags(peer);
|
||||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||||
|
@ -190,7 +197,9 @@ void SendExistingMedia(
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_entities;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_entities;
|
||||||
}
|
}
|
||||||
const auto captionText = caption.text;
|
const auto captionText = caption.text;
|
||||||
|
const auto starsPaid = std::min(
|
||||||
|
peer->starsPerMessageChecked(),
|
||||||
|
action.options.starsApproved);
|
||||||
if (action.options.scheduled) {
|
if (action.options.scheduled) {
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
flags |= MessageFlag::IsOrWasScheduled;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||||
|
@ -206,6 +215,10 @@ void SendExistingMedia(
|
||||||
flags |= MessageFlag::InvertMedia;
|
flags |= MessageFlag::InvertMedia;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
||||||
}
|
}
|
||||||
|
if (starsPaid) {
|
||||||
|
action.options.starsApproved -= starsPaid;
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
|
||||||
|
}
|
||||||
|
|
||||||
session->data().registerMessageRandomId(randomId, newId);
|
session->data().registerMessageRandomId(randomId, newId);
|
||||||
|
|
||||||
|
@ -216,6 +229,7 @@ void SendExistingMedia(
|
||||||
.replyTo = action.replyTo,
|
.replyTo = action.replyTo,
|
||||||
.date = NewMessageDate(action.options),
|
.date = NewMessageDate(action.options),
|
||||||
.shortcutId = action.options.shortcutId,
|
.shortcutId = action.options.shortcutId,
|
||||||
|
.starsPaid = starsPaid,
|
||||||
.postAuthor = NewMessagePostAuthor(action),
|
.postAuthor = NewMessagePostAuthor(action),
|
||||||
.effectId = action.options.effectId,
|
.effectId = action.options.effectId,
|
||||||
}, media, caption);
|
}, media, caption);
|
||||||
|
@ -240,7 +254,8 @@ void SendExistingMedia(
|
||||||
MTP_int(action.options.scheduled),
|
MTP_int(action.options.scheduled),
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||||
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
||||||
MTP_long(action.options.effectId)
|
MTP_long(action.options.effectId),
|
||||||
|
MTP_long(starsPaid)
|
||||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
if (error.code() == 400
|
if (error.code() == 400
|
||||||
|
@ -341,7 +356,7 @@ bool SendDice(MessageToSend &message) {
|
||||||
message.action.generateLocal = true;
|
message.action.generateLocal = true;
|
||||||
|
|
||||||
|
|
||||||
const auto &action = message.action;
|
auto &action = message.action;
|
||||||
api->sendAction(action);
|
api->sendAction(action);
|
||||||
|
|
||||||
const auto newId = FullMsgId(
|
const auto newId = FullMsgId(
|
||||||
|
@ -380,6 +395,13 @@ bool SendDice(MessageToSend &message) {
|
||||||
flags |= MessageFlag::InvertMedia;
|
flags |= MessageFlag::InvertMedia;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
||||||
}
|
}
|
||||||
|
const auto starsPaid = std::min(
|
||||||
|
peer->starsPerMessageChecked(),
|
||||||
|
action.options.starsApproved);
|
||||||
|
if (starsPaid) {
|
||||||
|
action.options.starsApproved -= starsPaid;
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
|
||||||
|
}
|
||||||
|
|
||||||
session->data().registerMessageRandomId(randomId, newId);
|
session->data().registerMessageRandomId(randomId, newId);
|
||||||
|
|
||||||
|
@ -390,6 +412,7 @@ bool SendDice(MessageToSend &message) {
|
||||||
.replyTo = action.replyTo,
|
.replyTo = action.replyTo,
|
||||||
.date = NewMessageDate(action.options),
|
.date = NewMessageDate(action.options),
|
||||||
.shortcutId = action.options.shortcutId,
|
.shortcutId = action.options.shortcutId,
|
||||||
|
.starsPaid = starsPaid,
|
||||||
.postAuthor = NewMessagePostAuthor(action),
|
.postAuthor = NewMessagePostAuthor(action),
|
||||||
.effectId = action.options.effectId,
|
.effectId = action.options.effectId,
|
||||||
}, TextWithEntities(), MTP_messageMediaDice(
|
}, TextWithEntities(), MTP_messageMediaDice(
|
||||||
|
@ -411,7 +434,8 @@ bool SendDice(MessageToSend &message) {
|
||||||
MTP_int(action.options.scheduled),
|
MTP_int(action.options.scheduled),
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||||
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
||||||
MTP_long(action.options.effectId)
|
MTP_long(action.options.effectId),
|
||||||
|
MTP_long(starsPaid)
|
||||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
api->sendMessageFail(error, peer, randomId, newId);
|
api->sendMessageFail(error, peer, randomId, newId);
|
||||||
|
@ -610,6 +634,9 @@ void SendConfirmedFile(
|
||||||
.replyTo = file->to.replyTo,
|
.replyTo = file->to.replyTo,
|
||||||
.date = NewMessageDate(file->to.options),
|
.date = NewMessageDate(file->to.options),
|
||||||
.shortcutId = file->to.options.shortcutId,
|
.shortcutId = file->to.options.shortcutId,
|
||||||
|
.starsPaid = std::min(
|
||||||
|
history->peer->starsPerMessageChecked(),
|
||||||
|
file->to.options.starsApproved),
|
||||||
.postAuthor = NewMessagePostAuthor(action),
|
.postAuthor = NewMessagePostAuthor(action),
|
||||||
.groupedId = groupId,
|
.groupedId = groupId,
|
||||||
.effectId = file->to.options.effectId,
|
.effectId = file->to.options.effectId,
|
||||||
|
|
|
@ -313,7 +313,7 @@ void PublicForwards::request(
|
||||||
const auto msgId = IdFromMessage(message);
|
const auto msgId = IdFromMessage(message);
|
||||||
const auto peerId = PeerFromMessage(message);
|
const auto peerId = PeerFromMessage(message);
|
||||||
const auto lastDate = DateFromMessage(message);
|
const auto lastDate = DateFromMessage(message);
|
||||||
if (const auto peer = owner.peerLoaded(peerId)) {
|
if (owner.peerLoaded(peerId)) {
|
||||||
if (!lastDate) {
|
if (!lastDate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,11 @@ EntitiesInText EntitiesFromMTP(
|
||||||
d.vlength().v,
|
d.vlength().v,
|
||||||
});
|
});
|
||||||
}, [&](const MTPDmessageEntityBankCard &d) {
|
}, [&](const MTPDmessageEntityBankCard &d) {
|
||||||
// Skipping cards. // #TODO entities
|
result.push_back({
|
||||||
|
EntityType::BankCard,
|
||||||
|
d.voffset().v,
|
||||||
|
d.vlength().v,
|
||||||
|
});
|
||||||
}, [&](const MTPDmessageEntitySpoiler &d) {
|
}, [&](const MTPDmessageEntitySpoiler &d) {
|
||||||
result.push_back({
|
result.push_back({
|
||||||
EntityType::Spoiler,
|
EntityType::Spoiler,
|
||||||
|
@ -273,6 +277,9 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
|
||||||
case EntityType::Phone: {
|
case EntityType::Phone: {
|
||||||
v.push_back(MTP_messageEntityPhone(offset, length));
|
v.push_back(MTP_messageEntityPhone(offset, length));
|
||||||
} break;
|
} break;
|
||||||
|
case EntityType::BankCard: {
|
||||||
|
v.push_back(MTP_messageEntityBankCard(offset, length));
|
||||||
|
} break;
|
||||||
case EntityType::Hashtag: {
|
case EntityType::Hashtag: {
|
||||||
v.push_back(MTP_messageEntityHashtag(offset, length));
|
v.push_back(MTP_messageEntityHashtag(offset, length));
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mtproto/mtproto_dc_options.h"
|
#include "mtproto/mtproto_dc_options.h"
|
||||||
#include "data/business/data_shortcut_messages.h"
|
#include "data/business/data_shortcut_messages.h"
|
||||||
#include "data/components/credits.h"
|
#include "data/components/credits.h"
|
||||||
|
#include "data/components/promo_suggestions.h"
|
||||||
#include "data/components/scheduled_messages.h"
|
#include "data/components/scheduled_messages.h"
|
||||||
#include "data/components/top_peers.h"
|
#include "data/components/top_peers.h"
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
|
@ -307,14 +308,19 @@ void Updates::feedUpdateVector(
|
||||||
auto list = updates.v;
|
auto list = updates.v;
|
||||||
const auto hasGroupCallParticipantUpdates = ranges::contains(
|
const auto hasGroupCallParticipantUpdates = ranges::contains(
|
||||||
list,
|
list,
|
||||||
mtpc_updateGroupCallParticipants,
|
true,
|
||||||
&MTPUpdate::type);
|
[](const MTPUpdate &update) {
|
||||||
|
return update.type() == mtpc_updateGroupCallParticipants
|
||||||
|
|| update.type() == mtpc_updateGroupCallChainBlocks;
|
||||||
|
});
|
||||||
if (hasGroupCallParticipantUpdates) {
|
if (hasGroupCallParticipantUpdates) {
|
||||||
ranges::stable_sort(list, std::less<>(), [](const MTPUpdate &entry) {
|
ranges::stable_sort(list, std::less<>(), [](const MTPUpdate &entry) {
|
||||||
if (entry.type() == mtpc_updateGroupCallParticipants) {
|
if (entry.type() == mtpc_updateGroupCallChainBlocks) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else if (entry.type() == mtpc_updateGroupCallParticipants) {
|
||||||
return 1;
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants) {
|
} else if (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants) {
|
||||||
|
@ -328,7 +334,8 @@ void Updates::feedUpdateVector(
|
||||||
if ((policy == SkipUpdatePolicy::SkipMessageIds
|
if ((policy == SkipUpdatePolicy::SkipMessageIds
|
||||||
&& type == mtpc_updateMessageID)
|
&& type == mtpc_updateMessageID)
|
||||||
|| (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants
|
|| (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants
|
||||||
&& type != mtpc_updateGroupCallParticipants)) {
|
&& type != mtpc_updateGroupCallParticipants
|
||||||
|
&& type != mtpc_updateGroupCallChainBlocks)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
feedUpdate(entry);
|
feedUpdate(entry);
|
||||||
|
@ -958,7 +965,8 @@ void Updates::applyGroupCallParticipantUpdates(const MTPUpdates &updates) {
|
||||||
data.vupdates(),
|
data.vupdates(),
|
||||||
SkipUpdatePolicy::SkipExceptGroupCallParticipants);
|
SkipUpdatePolicy::SkipExceptGroupCallParticipants);
|
||||||
}, [&](const MTPDupdateShort &data) {
|
}, [&](const MTPDupdateShort &data) {
|
||||||
if (data.vupdate().type() == mtpc_updateGroupCallParticipants) {
|
if (data.vupdate().type() == mtpc_updateGroupCallParticipants
|
||||||
|
|| data.vupdate().type() == mtpc_updateGroupCallChainBlocks) {
|
||||||
feedUpdate(data.vupdate());
|
feedUpdate(data.vupdate());
|
||||||
}
|
}
|
||||||
}, [](const auto &) {
|
}, [](const auto &) {
|
||||||
|
@ -990,10 +998,10 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// AyuGram sendOnlinePackets
|
// AyuGram sendOnlinePackets
|
||||||
const auto settings = &AyuSettings::getInstance();
|
const auto& settings = AyuSettings::getInstance();
|
||||||
const auto& config = _session->serverConfig();
|
const auto& config = _session->serverConfig();
|
||||||
bool isOnlineOrig = Core::App().hasActiveWindow(&session());
|
bool isOnlineOrig = Core::App().hasActiveWindow(&session());
|
||||||
bool isOnline = settings->sendOnlinePackets && isOnlineOrig;
|
bool isOnline = settings.sendOnlinePackets && isOnlineOrig;
|
||||||
|
|
||||||
int updateIn = config.onlineUpdatePeriod;
|
int updateIn = config.onlineUpdatePeriod;
|
||||||
Assert(updateIn >= 0);
|
Assert(updateIn >= 0);
|
||||||
|
@ -1227,7 +1235,8 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||||
MTPint(), // quick_reply_shortcut_id
|
MTPint(), // quick_reply_shortcut_id
|
||||||
MTPlong(), // effect
|
MTPlong(), // effect
|
||||||
MTPFactCheck(),
|
MTPFactCheck(),
|
||||||
MTPint()), // report_delivery_until_date
|
MTPint(), // report_delivery_until_date
|
||||||
|
MTPlong()), // paid_message_stars
|
||||||
MessageFlags(),
|
MessageFlags(),
|
||||||
NewMessageType::Unread);
|
NewMessageType::Unread);
|
||||||
} break;
|
} break;
|
||||||
|
@ -1265,7 +1274,8 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||||
MTPint(), // quick_reply_shortcut_id
|
MTPint(), // quick_reply_shortcut_id
|
||||||
MTPlong(), // effect
|
MTPlong(), // effect
|
||||||
MTPFactCheck(),
|
MTPFactCheck(),
|
||||||
MTPint()), // report_delivery_until_date
|
MTPint(), // report_delivery_until_date
|
||||||
|
MTPlong()), // paid_message_stars
|
||||||
MessageFlags(),
|
MessageFlags(),
|
||||||
NewMessageType::Unread);
|
NewMessageType::Unread);
|
||||||
} break;
|
} break;
|
||||||
|
@ -1315,7 +1325,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
||||||
user->madeAction(base::unixtime::now());
|
user->madeAction(base::unixtime::now());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClearMediaAsExpired(item);
|
item->clearMediaAsExpired();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Perhaps it was an unread mention!
|
// Perhaps it was an unread mention!
|
||||||
|
@ -2067,6 +2077,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
|
|
||||||
case mtpc_updateConfig: {
|
case mtpc_updateConfig: {
|
||||||
session().mtp().requestConfig();
|
session().mtp().requestConfig();
|
||||||
|
session().promoSuggestions().invalidate();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updateUserPhone: {
|
case mtpc_updateUserPhone: {
|
||||||
|
@ -2116,6 +2127,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
case mtpc_updatePhoneCall:
|
case mtpc_updatePhoneCall:
|
||||||
case mtpc_updatePhoneCallSignalingData:
|
case mtpc_updatePhoneCallSignalingData:
|
||||||
case mtpc_updateGroupCallParticipants:
|
case mtpc_updateGroupCallParticipants:
|
||||||
|
case mtpc_updateGroupCallChainBlocks:
|
||||||
case mtpc_updateGroupCallConnection:
|
case mtpc_updateGroupCallConnection:
|
||||||
case mtpc_updateGroupCall: {
|
case mtpc_updateGroupCall: {
|
||||||
Core::App().calls().handleUpdate(&session(), update);
|
Core::App().calls().handleUpdate(&session(), update);
|
||||||
|
|
|
@ -210,6 +210,7 @@ MTPInputPrivacyKey KeyToTL(UserPrivacy::Key key) {
|
||||||
case Key::About: return MTP_inputPrivacyKeyAbout();
|
case Key::About: return MTP_inputPrivacyKeyAbout();
|
||||||
case Key::Birthday: return MTP_inputPrivacyKeyBirthday();
|
case Key::Birthday: return MTP_inputPrivacyKeyBirthday();
|
||||||
case Key::GiftsAutoSave: return MTP_inputPrivacyKeyStarGiftsAutoSave();
|
case Key::GiftsAutoSave: return MTP_inputPrivacyKeyStarGiftsAutoSave();
|
||||||
|
case Key::NoPaidMessages: return MTP_inputPrivacyKeyNoPaidMessages();
|
||||||
}
|
}
|
||||||
Unexpected("Key in Api::UserPrivacy::KetToTL.");
|
Unexpected("Key in Api::UserPrivacy::KetToTL.");
|
||||||
}
|
}
|
||||||
|
@ -241,6 +242,8 @@ std::optional<UserPrivacy::Key> TLToKey(mtpTypeId type) {
|
||||||
case mtpc_inputPrivacyKeyBirthday: return Key::Birthday;
|
case mtpc_inputPrivacyKeyBirthday: return Key::Birthday;
|
||||||
case mtpc_privacyKeyStarGiftsAutoSave:
|
case mtpc_privacyKeyStarGiftsAutoSave:
|
||||||
case mtpc_inputPrivacyKeyStarGiftsAutoSave: return Key::GiftsAutoSave;
|
case mtpc_inputPrivacyKeyStarGiftsAutoSave: return Key::GiftsAutoSave;
|
||||||
|
case mtpc_privacyKeyNoPaidMessages:
|
||||||
|
case mtpc_inputPrivacyKeyNoPaidMessages: return Key::NoPaidMessages;
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
About,
|
About,
|
||||||
Birthday,
|
Birthday,
|
||||||
GiftsAutoSave,
|
GiftsAutoSave,
|
||||||
|
NoPaidMessages,
|
||||||
};
|
};
|
||||||
enum class Option {
|
enum class Option {
|
||||||
Everyone,
|
Everyone,
|
||||||
|
|