Compare commits
454 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
719179c1c2 | ||
|
|
1851e0c02d | ||
|
|
5d7ae16b4a | ||
|
|
3bb8cb52f8 | ||
|
|
3d4d3b000e | ||
|
|
e3e97db101 | ||
|
|
057b8d9e74 | ||
|
|
003e42a2ae | ||
|
|
baf932dd8b | ||
|
|
e2acab67e1 | ||
|
|
095b171db3 | ||
|
|
9d36d7119b | ||
|
|
507bcbd332 | ||
|
|
71a15b7202 | ||
|
|
1718a123e8 | ||
|
|
b5c1046dca | ||
|
|
608481df38 | ||
|
|
4aab5da7ae | ||
|
|
79650cf318 | ||
|
|
170544f68d | ||
|
|
9bc26b0068 | ||
|
|
9765319027 | ||
|
|
3b1c7dc5e1 | ||
|
|
2a50d0856b | ||
|
|
23c0fcada6 | ||
|
|
aa499eab61 | ||
|
|
985324ac12 | ||
|
|
3c89907403 | ||
|
|
953487bb65 | ||
|
|
677891d0ff | ||
|
|
8d2a7b00dc | ||
|
|
d4d4f3c082 | ||
|
|
c26e8a69ca | ||
|
|
1c251a308a | ||
|
|
c8015898ff | ||
|
|
a1e36594c2 | ||
|
|
043bc754ae | ||
|
|
472d9dd467 | ||
|
|
f6a3662b0e | ||
|
|
fb777d0c3a | ||
|
|
2a3ee968ff | ||
|
|
0b2661ad45 | ||
|
|
d458748a7a | ||
|
|
7f346ef606 | ||
|
|
ca544dbbae | ||
|
|
5704a07b68 | ||
|
|
5b1739246d | ||
|
|
8ead33bc59 | ||
|
|
2f3792a3ee | ||
|
|
86d306632d | ||
|
|
cc79c2cb49 | ||
|
|
26b3b13bc4 | ||
|
|
bc20e65aae | ||
|
|
d458bf6be3 | ||
|
|
58375f06e5 | ||
|
|
cd39853dc8 | ||
|
|
c94a44aeb8 | ||
|
|
237d7c1ec1 | ||
|
|
a80b67fdc9 | ||
|
|
de44c57ada | ||
|
|
448356f534 | ||
|
|
2b16b0fc7c | ||
|
|
22515c8c29 | ||
|
|
bf050a2d5e | ||
|
|
74065714cb | ||
|
|
b95a39dc10 | ||
|
|
bcdd202ef9 | ||
|
|
20ce2ead75 | ||
|
|
a81b9344cf | ||
|
|
a7fe004344 | ||
|
|
66e8f9865a | ||
|
|
1cb4413869 | ||
|
|
be6dbefe7c | ||
|
|
f655297052 | ||
|
|
232c797507 | ||
|
|
25d4a9c7a6 | ||
|
|
65e3111e35 | ||
|
|
048d995922 | ||
|
|
dcac27e072 | ||
|
|
b754ad5248 | ||
|
|
321c7120df | ||
|
|
4b85c9e2df | ||
|
|
62aec34507 | ||
|
|
427487c598 | ||
|
|
ccb8c43961 | ||
|
|
fee892f9a2 | ||
|
|
9b990728f6 | ||
|
|
9b490c9552 | ||
|
|
133effef0e | ||
|
|
15706a7af8 | ||
|
|
2a15faf12e | ||
|
|
9149792846 | ||
|
|
c90c53c878 | ||
|
|
e6387738ce | ||
|
|
3882690ee1 | ||
|
|
4c049d0d75 | ||
|
|
e070af3163 | ||
|
|
1c35a91d13 | ||
|
|
4c20e79d1f | ||
|
|
669f46d6a1 | ||
|
|
ea89a9f706 | ||
|
|
918985449b | ||
|
|
18ab93a9f6 | ||
|
|
a6a8363527 | ||
|
|
90edb0903d | ||
|
|
ba1274ff3a | ||
|
|
60f91bff50 | ||
|
|
ef2e9406c7 | ||
|
|
3d6783597f | ||
|
|
7cab32f71b | ||
|
|
78a72b42b0 | ||
|
|
0514f13af0 | ||
|
|
e6a6763228 | ||
|
|
38c74bf2cf | ||
|
|
a770e47575 | ||
|
|
c998352ab7 | ||
|
|
3683fa3814 | ||
|
|
e62881e08b | ||
|
|
01e313e56b | ||
|
|
2dd5f80468 | ||
|
|
275fb3e96a | ||
|
|
3463916b9b | ||
|
|
a20de2515a | ||
|
|
79ea992a0f | ||
|
|
0132436dc8 | ||
|
|
a285c1abec | ||
|
|
1c41e01f0d | ||
|
|
f2e53ea490 | ||
|
|
bff86b90fb | ||
|
|
b5c9b6f552 | ||
|
|
23f5102f1b | ||
|
|
bf51e911b8 | ||
|
|
4039d7ab71 | ||
|
|
77a09a0e59 | ||
|
|
154c777788 | ||
|
|
628c36c87d | ||
|
|
a746b7abcf | ||
|
|
64184e6c90 | ||
|
|
ecc955d2ce | ||
|
|
f7e1b2c70c | ||
|
|
284cbda7c0 | ||
|
|
e5ca9e4c39 | ||
|
|
02aaa71e78 | ||
|
|
6afd4dcdd1 | ||
|
|
52bb189996 | ||
|
|
8ff6f9af45 | ||
|
|
36bb1d0cf3 | ||
|
|
c7c8e39e20 | ||
|
|
8e9630459b | ||
|
|
1c53fca925 | ||
|
|
7d78de0673 | ||
|
|
f8acc55365 | ||
|
|
c3157fe90d | ||
|
|
35b129287b | ||
|
|
d05155a403 | ||
|
|
f0aca45b11 | ||
|
|
d205e3b4a3 | ||
|
|
8b40a77297 | ||
|
|
a7e87cc722 | ||
|
|
09f106bd49 | ||
|
|
8a0869fb75 | ||
|
|
7ccf26310d | ||
|
|
e1420ba26c | ||
|
|
c693c9cd44 | ||
|
|
e698557092 | ||
|
|
1238c90450 | ||
|
|
e991dca5a0 | ||
|
|
37093c9f33 | ||
|
|
1dd4f62ece | ||
|
|
9ec27aad53 | ||
|
|
f1d3a946d5 | ||
|
|
fd24f7045e | ||
|
|
33671e7737 | ||
|
|
13ecc6a56b | ||
|
|
20815eecbc | ||
|
|
f2f5ffd861 | ||
|
|
b0971601b1 | ||
|
|
7253d764d2 | ||
|
|
71f3a1f7cf | ||
|
|
950659b29d | ||
|
|
b4392d0e3c | ||
|
|
4571302642 | ||
|
|
5121f04d66 | ||
|
|
77642d2876 | ||
|
|
ef69796798 | ||
|
|
869854fbc2 | ||
|
|
4584d912cc | ||
|
|
ddd3d38dac | ||
|
|
fcba6bc7d7 | ||
|
|
a147c0fb4f | ||
|
|
c3cc3fa9bd | ||
|
|
0f0e14132a | ||
|
|
a2c2ed0b4a | ||
|
|
8bebca4502 | ||
|
|
e9a550d458 | ||
|
|
bee567f2b1 | ||
|
|
0fd7061671 | ||
|
|
96951576c1 | ||
|
|
a665d7cc3c | ||
|
|
9b989329d4 | ||
|
|
eccfd75a83 | ||
|
|
7e8a152eef | ||
|
|
44810f95a5 | ||
|
|
bcd42dbb6a | ||
|
|
6e77126a65 | ||
|
|
735bbef655 | ||
|
|
7006a07dd3 | ||
|
|
7284926db4 | ||
|
|
b506bf9506 | ||
|
|
3fea28f8b0 | ||
|
|
cc6649667c | ||
|
|
24121fbbce | ||
|
|
ef280dae3e | ||
|
|
49f580a36b | ||
|
|
a56d2b1313 | ||
|
|
f083180401 | ||
|
|
7b870edefa | ||
|
|
a293fa1de6 | ||
|
|
3a8898dd24 | ||
|
|
b97c8b9a17 | ||
|
|
a0a8d76441 | ||
|
|
9199612cf7 | ||
|
|
abfd37c045 | ||
|
|
ac243136b9 | ||
|
|
c93e948bb3 | ||
|
|
388803ffdb | ||
|
|
a809ccf229 | ||
|
|
d1796a515e | ||
|
|
a11d3efed6 | ||
|
|
9d7aab4326 | ||
|
|
a3b76fed4c | ||
|
|
21f5f96d69 | ||
|
|
70d3061d59 | ||
|
|
8f7a66a21a | ||
|
|
cd8e944751 | ||
|
|
66e05594f6 | ||
|
|
d06a9e2e5c | ||
|
|
64df9222dd | ||
|
|
900ac46583 | ||
|
|
fda1c8399f | ||
|
|
c2cd4fc75f | ||
|
|
ef5a9eb777 | ||
|
|
8e3100acdd | ||
|
|
50d74fcf25 | ||
|
|
140862ce5a | ||
|
|
966453dd8f | ||
|
|
fcd37adc38 | ||
|
|
6a3989488e | ||
|
|
fbfdef8f9a | ||
|
|
b66c61573f | ||
|
|
9186b28b60 | ||
|
|
915a1b105c | ||
|
|
12b9b3ce71 | ||
|
|
deb4c48551 | ||
|
|
9dfaac8582 | ||
|
|
bd5b9f5347 | ||
|
|
ff4b9a3cfe | ||
|
|
e844d7ed89 | ||
|
|
f3ae8f7f75 | ||
|
|
f137eddbf9 | ||
|
|
c70f75b21a | ||
|
|
141fb875f9 | ||
|
|
344d47e7dd | ||
|
|
4840a9094b | ||
|
|
6f305c8974 | ||
|
|
c83bae3bb5 | ||
|
|
4c1b962486 | ||
|
|
b929e2a7b2 | ||
|
|
1ecd7aa7cf | ||
|
|
881aed50ea | ||
|
|
6272b79f70 | ||
|
|
0fa50f1951 | ||
|
|
dc19f2e76c | ||
|
|
498116c3f6 | ||
|
|
e29dcf7489 | ||
|
|
ec28eea7f0 | ||
|
|
ebce4d0f31 | ||
|
|
bf9492e083 | ||
|
|
cb987c1baf | ||
|
|
e4a4be1f53 | ||
|
|
f6d1fe6c04 | ||
|
|
7e5a29a5cc | ||
|
|
8dbc175c02 | ||
|
|
0473374d51 | ||
|
|
b2d7342b9e | ||
|
|
b965aecc6c | ||
|
|
9290c90bdc | ||
|
|
d83a80ec53 | ||
|
|
248fe1b53f | ||
|
|
bf217bf7aa | ||
|
|
e5de8e22b7 | ||
|
|
5666e84d92 | ||
|
|
a97d1b8669 | ||
|
|
06db13a0ab | ||
|
|
9832af7cce | ||
|
|
cf4a617f2b | ||
|
|
5a6a5fd4d1 | ||
|
|
e6ebc19b4f | ||
|
|
02dd0dbbef | ||
|
|
2e4a437d32 | ||
|
|
63e1d6dab6 | ||
|
|
23133499c7 | ||
|
|
67bd87b50c | ||
|
|
6d31a4246f | ||
|
|
d4f38b6d66 | ||
|
|
959229f143 | ||
|
|
22f9b1a0b1 | ||
|
|
a8fc5a722f | ||
|
|
6102119673 | ||
|
|
0c635a05ff | ||
|
|
307a7791df | ||
|
|
49b056a0ce | ||
|
|
af58ffadcb | ||
|
|
dcbda7b3af | ||
|
|
553cc0c6ae | ||
|
|
067dcbfbeb | ||
|
|
759258bb39 | ||
|
|
3667ef551c | ||
|
|
a3308087a5 | ||
|
|
bfb4652425 | ||
|
|
03c24e2906 | ||
|
|
dc61faace1 | ||
|
|
73ea86ceeb | ||
|
|
9a622ab466 | ||
|
|
65cfd6c81c | ||
|
|
08681ac1b9 | ||
|
|
f9acb5d19b | ||
|
|
e9e187c58b | ||
|
|
3bc20c3550 | ||
|
|
4b25406d14 | ||
|
|
265b7904a8 | ||
|
|
fb2274c58d | ||
|
|
3cfdc9d897 | ||
|
|
11986ac698 | ||
|
|
a08436ecd2 | ||
|
|
e92adf94a7 | ||
|
|
d25356917d | ||
|
|
0adb3b062f | ||
|
|
9316480884 | ||
|
|
4e5082f6c6 | ||
|
|
16d5dbe71c | ||
|
|
133d7874e3 | ||
|
|
4659d5db5d | ||
|
|
af061125dd | ||
|
|
5c4b1f6638 | ||
|
|
ee3d70f879 | ||
|
|
7dadaa1b28 | ||
|
|
a72782e232 | ||
|
|
8654ffb6fb | ||
|
|
90e445eec9 | ||
|
|
910b6d8879 | ||
|
|
8d1c2f832d | ||
|
|
158d2a4124 | ||
|
|
66473738d6 | ||
|
|
6a43107bb2 | ||
|
|
28e7afa412 | ||
|
|
8dc151e14d | ||
|
|
a330a3f2eb | ||
|
|
8f7195d3b2 | ||
|
|
a4e4502d50 | ||
|
|
902da90100 | ||
|
|
d775760f98 | ||
|
|
dfb6600104 | ||
|
|
41ed487d5e | ||
|
|
d156de05a5 | ||
|
|
f4582ddf36 | ||
|
|
7f7b764f7b | ||
|
|
dd8fdfc3d4 | ||
|
|
6c80d443b9 | ||
|
|
cd05586d51 | ||
|
|
dfc1ec3ccf | ||
|
|
ffe6786ad1 | ||
|
|
6068678fa1 | ||
|
|
50b761fab2 | ||
|
|
0d43f16db2 | ||
|
|
3278de9ba1 | ||
|
|
abe1962002 | ||
|
|
5b15f377cd | ||
|
|
d0e5ea78a5 | ||
|
|
853757e611 | ||
|
|
c3860cfe72 | ||
|
|
90b2c077a6 | ||
|
|
fdce4bada7 | ||
|
|
4c8ff1c7ec | ||
|
|
2a153214f6 | ||
|
|
d7c964afc5 | ||
|
|
5943052cd1 | ||
|
|
8512154b45 | ||
|
|
0e5419c60b | ||
|
|
1d26482298 | ||
|
|
126749f04c | ||
|
|
e0e69ce740 | ||
|
|
72b57924b7 | ||
|
|
fdbdeeb956 | ||
|
|
3dbdecf73d | ||
|
|
7dc8943840 | ||
|
|
646b852717 | ||
|
|
075f754a71 | ||
|
|
f65556acb7 | ||
|
|
b2c01991a6 | ||
|
|
4bc5e81513 | ||
|
|
2b24fe95c2 | ||
|
|
358e64f2cc | ||
|
|
5dc50b6d96 | ||
|
|
b91a040a32 | ||
|
|
76db55ff19 | ||
|
|
e17bf18350 | ||
|
|
43b4499125 | ||
|
|
c6d43a802c | ||
|
|
21f8403357 | ||
|
|
40053e3388 | ||
|
|
abcf7e3a47 | ||
|
|
f8913bf9b9 | ||
|
|
51878ab38e | ||
|
|
d3f9a84a0a | ||
|
|
23eedb468f | ||
|
|
9cb89fff45 | ||
|
|
79f0b22276 | ||
|
|
8b2a728a0d | ||
|
|
b4120b156e | ||
|
|
1ae3122c20 | ||
|
|
727acca217 | ||
|
|
5f8d662d67 | ||
|
|
81b432140c | ||
|
|
adc1ee71a9 | ||
|
|
5ac373d4aa | ||
|
|
5b9e24f3f4 | ||
|
|
0e44de2fe3 | ||
|
|
b0125e8165 | ||
|
|
a532067a93 | ||
|
|
f456071c08 | ||
|
|
3896f0995c | ||
|
|
56ff5808a3 | ||
|
|
15c817dd15 | ||
|
|
7246c3f304 | ||
|
|
e4f59f1ec4 | ||
|
|
5f0e9538cf | ||
|
|
73649128f3 | ||
|
|
edc84731ac | ||
|
|
108b116b06 | ||
|
|
dda587dc6f | ||
|
|
4a9dd43598 | ||
|
|
a64cfe661a | ||
|
|
7e418a16ae | ||
|
|
ecf1fa2bbd | ||
|
|
a6157a34bc | ||
|
|
8e37e66706 | ||
|
|
dd6a4931e5 | ||
|
|
2d000e826b | ||
|
|
c1028e7408 | ||
|
|
28b54fac37 | ||
|
|
845fddf5f2 | ||
|
|
e3e2a477c1 | ||
|
|
bf4442ecf5 |
42
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Docker.
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/docker.yml'
|
||||
- 'Telegram/build/docker/centos_env/**'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
name: Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref_name == github.event.repository.default_branch
|
||||
|
||||
env:
|
||||
IMAGE_TAG: ghcr.io/${{ github.repository }}/centos_env:latest
|
||||
|
||||
steps:
|
||||
- name: Clone.
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: First set up.
|
||||
run: |
|
||||
sudo apt update
|
||||
curl -sSL https://install.python-poetry.org | python3 -
|
||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
|
||||
|
||||
- name: Free up some disk space.
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||
with:
|
||||
tool-cache: true
|
||||
|
||||
- name: Docker image build.
|
||||
run: |
|
||||
cd Telegram/build/docker/centos_env
|
||||
poetry install
|
||||
DEBUG= LTO= poetry run gen_dockerfile | DOCKER_BUILDKIT=1 docker build -t $IMAGE_TAG -
|
||||
|
||||
- name: Push the Docker image.
|
||||
run: docker push $IMAGE_TAG
|
||||
19
.github/workflows/linux.yml
vendored
@@ -80,14 +80,26 @@ jobs:
|
||||
- name: Set up Docker Buildx.
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Libraries cache.
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/.buildx-cache
|
||||
key: ${{ runner.OS }}-libs-${{ hashFiles('Telegram/build/docker/centos_env/**') }}
|
||||
restore-keys: ${{ runner.OS }}-libs-
|
||||
|
||||
- name: Libraries.
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: Telegram/build/docker/centos_env
|
||||
load: ${{ env.ONLY_CACHE == 'false' }}
|
||||
tags: ${{ env.IMAGE_TAG }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
cache-from: type=local,src=${{ runner.temp }}/.buildx-cache
|
||||
cache-to: type=local,dest=${{ runner.temp }}/.buildx-cache-new,mode=max
|
||||
|
||||
- name: Move cache.
|
||||
run: |
|
||||
rm -rf ${{ runner.temp }}/.buildx-cache
|
||||
mv ${{ runner.temp }}/.buildx-cache{-new,}
|
||||
|
||||
- name: Telegram Desktop build.
|
||||
if: env.ONLY_CACHE == 'false'
|
||||
@@ -104,13 +116,12 @@ jobs:
|
||||
docker run --rm \
|
||||
-u $(id -u) \
|
||||
-v $PWD:/usr/src/tdesktop \
|
||||
-e CMAKE_CONFIG_TYPE=Debug \
|
||||
-e CONFIG=Debug \
|
||||
$IMAGE_TAG \
|
||||
/usr/src/tdesktop/Telegram/build/docker/centos_env/build.sh \
|
||||
-D CMAKE_CONFIGURATION_TYPES=Debug \
|
||||
-D CMAKE_C_FLAGS_DEBUG="-O0" \
|
||||
-D CMAKE_CXX_FLAGS_DEBUG="-O0" \
|
||||
-D CMAKE_EXE_LINKER_FLAGS="-s" \
|
||||
-D CMAKE_COMPILE_WARNING_AS_ERROR=ON \
|
||||
-D TDESKTOP_API_TEST=ON \
|
||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF \
|
||||
|
||||
2
.github/workflows/mac.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
macos:
|
||||
name: MacOS
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-13
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
4
.github/workflows/mac_packaged.yml
vendored
@@ -69,7 +69,7 @@ jobs:
|
||||
run: |
|
||||
brew update
|
||||
brew upgrade || true
|
||||
brew install ada-url autoconf automake boost cmake ffmpeg libtool openal-soft openh264 openssl opus ninja pkg-config python qt yasm xz
|
||||
brew install ada-url autoconf automake boost cmake ffmpeg jpeg-xl libavif libheif libtool openal-soft openh264 openssl opus ninja pkg-config python qt yasm xz
|
||||
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
||||
|
||||
xcodebuild -version > CACHE_KEY.txt
|
||||
@@ -166,9 +166,7 @@ jobs:
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_C_FLAGS_DEBUG="" \
|
||||
-DCMAKE_CXX_FLAGS_DEBUG="" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-s" \
|
||||
-DTDESKTOP_API_TEST=ON \
|
||||
-DDESKTOP_APP_USE_PACKAGED_LAZY=ON \
|
||||
$DEFINE
|
||||
|
||||
cmake --build build --parallel
|
||||
|
||||
11
.github/workflows/snap.yml
vendored
@@ -61,7 +61,16 @@ jobs:
|
||||
sudo lxd waitready
|
||||
|
||||
- name: Free up some disk space.
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||
uses: endersonmenezes/free-disk-space@4cae28d0d8e716a770938d92630f23db5184f61f
|
||||
with:
|
||||
remove_android: true
|
||||
remove_dotnet: true
|
||||
remove_haskell: true
|
||||
remove_tool_cache: true
|
||||
remove_swap: true
|
||||
remove_packages: "azure-cli google-cloud-cli microsoft-edge-stable google-chrome-stable firefox postgresql* temurin-* *llvm* mysql* dotnet-sdk-*"
|
||||
remove_packages_one_command: true
|
||||
remove_folders: "/usr/share/swift /usr/share/miniconda /usr/share/az* /usr/share/glade* /usr/local/lib/node_modules /usr/local/share/chromium /usr/local/share/powershell"
|
||||
|
||||
- name: Telegram Desktop snap build.
|
||||
run: sudo -u $USER snap run snapcraft --verbosity=debug
|
||||
|
||||
24
.github/workflows/win.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '!docs/building-win*.md'
|
||||
- '**.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
@@ -22,6 +23,7 @@ on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '!docs/building-win*.md'
|
||||
- '**.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
@@ -69,26 +71,34 @@ jobs:
|
||||
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.
|
||||
- name: First set up.
|
||||
shell: bash
|
||||
run: |
|
||||
echo "CACHE_KEY=$(sha256sum $TBUILD/$REPO_NAME/$PREPARE_PATH | awk '{ print $1 }')" >> $GITHUB_ENV
|
||||
DOCPATH=$TBUILD/$REPO_NAME/docs/building-win.md
|
||||
[ "${{ matrix.arch }}" != Win32 ] && DOCPATH=$TBUILD/$REPO_NAME/docs/building-win-${{ matrix.arch }}.md
|
||||
SDK="$(grep "SDK version" $DOCPATH | sed -r 's/.*\*\*(.*)\*\* SDK version.*/\1/')"
|
||||
echo "SDK=$SDK" >> $GITHUB_ENV
|
||||
|
||||
echo "$(sha256sum $TBUILD/$REPO_NAME/$PREPARE_PATH | awk '{ print $1 }')" >> CACHE_KEY.txt
|
||||
echo "$SDK" >> CACHE_KEY.txt
|
||||
echo "CACHE_KEY=$(sha256sum CACHE_KEY.txt | 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"
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
name: Native Tools Command Prompt.
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
sdk: ${{ env.SDK }}
|
||||
|
||||
- name: NuGet sources.
|
||||
run: |
|
||||
nuget sources Disable -Name "Microsoft Visual Studio Offline Packages"
|
||||
|
||||
11
.gitignore
vendored
@@ -53,3 +53,14 @@ stage
|
||||
*.*~
|
||||
.idea/
|
||||
cmake-build-debug/
|
||||
|
||||
# Local configuration files
|
||||
settings.local.json
|
||||
*.local.json
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Cursor IDE local settings (but keep .cursor/rules/)
|
||||
.cursor/*
|
||||
!.cursor/rules/
|
||||
|
||||
6
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "Telegram/ThirdParty/libtgvoip"]
|
||||
path = Telegram/ThirdParty/libtgvoip
|
||||
url = https://github.com/telegramdesktop/libtgvoip
|
||||
[submodule "Telegram/ThirdParty/GSL"]
|
||||
path = Telegram/ThirdParty/GSL
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
@@ -76,9 +73,6 @@
|
||||
[submodule "Telegram/lib_webview"]
|
||||
path = Telegram/lib_webview
|
||||
url = https://github.com/desktop-app/lib_webview.git
|
||||
[submodule "Telegram/ThirdParty/jemalloc"]
|
||||
path = Telegram/ThirdParty/jemalloc
|
||||
url = https://github.com/jemalloc/jemalloc
|
||||
[submodule "Telegram/ThirdParty/dispatch"]
|
||||
path = Telegram/ThirdParty/dispatch
|
||||
url = https://github.com/apple/swift-corelibs-libdispatch
|
||||
|
||||
@@ -12,19 +12,17 @@ include(cmake/validate_special_target.cmake)
|
||||
include(cmake/version.cmake)
|
||||
desktop_app_parse_version(Telegram/build/version)
|
||||
|
||||
set(project_langs C CXX)
|
||||
if (APPLE)
|
||||
list(APPEND project_langs OBJC OBJCXX)
|
||||
elseif (LINUX)
|
||||
list(APPEND project_langs ASM)
|
||||
endif()
|
||||
|
||||
project(Telegram
|
||||
LANGUAGES ${project_langs}
|
||||
LANGUAGES C CXX
|
||||
VERSION ${desktop_app_version_cmake}
|
||||
DESCRIPTION "Official Telegram Desktop messenger"
|
||||
HOMEPAGE_URL "https://desktop.telegram.org"
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
enable_language(OBJC OBJCXX)
|
||||
endif()
|
||||
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Telegram)
|
||||
|
||||
get_filename_component(third_party_loc "Telegram/ThirdParty" REALPATH)
|
||||
@@ -39,9 +37,7 @@ include(cmake/variables.cmake)
|
||||
include(cmake/nice_target_sources.cmake)
|
||||
include(cmake/target_compile_options_if_exists.cmake)
|
||||
include(cmake/target_link_frameworks.cmake)
|
||||
include(cmake/target_link_optional_libraries.cmake)
|
||||
include(cmake/target_link_options_if_exists.cmake)
|
||||
include(cmake/target_link_static_libraries.cmake)
|
||||
include(cmake/init_target.cmake)
|
||||
include(cmake/generate_target.cmake)
|
||||
include(cmake/nuget.cmake)
|
||||
|
||||
@@ -53,9 +53,7 @@ set_target_properties(Telegram PROPERTIES AUTOMOC ON)
|
||||
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
# tdesktop::lib_tgcalls_legacy
|
||||
tdesktop::lib_tgcalls
|
||||
# tdesktop::lib_tgvoip
|
||||
|
||||
# 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
|
||||
@@ -127,6 +125,8 @@ PRIVATE
|
||||
api/api_confirm_phone.h
|
||||
api/api_credits.cpp
|
||||
api/api_credits.h
|
||||
api/api_credits_history_entry.cpp
|
||||
api/api_credits_history_entry.h
|
||||
api/api_earn.cpp
|
||||
api/api_earn.h
|
||||
api/api_editing.cpp
|
||||
@@ -176,8 +176,12 @@ PRIVATE
|
||||
api/api_statistics_data_deserialize.h
|
||||
api/api_statistics_sender.cpp
|
||||
api/api_statistics_sender.h
|
||||
api/api_suggest_post.cpp
|
||||
api/api_suggest_post.h
|
||||
api/api_text_entities.cpp
|
||||
api/api_text_entities.h
|
||||
api/api_todo_lists.cpp
|
||||
api/api_todo_lists.h
|
||||
api/api_toggling_media.cpp
|
||||
api/api_toggling_media.h
|
||||
api/api_transcribes.cpp
|
||||
@@ -281,6 +285,8 @@ PRIVATE
|
||||
boxes/edit_caption_box.h
|
||||
boxes/edit_privacy_box.cpp
|
||||
boxes/edit_privacy_box.h
|
||||
boxes/edit_todo_list_box.cpp
|
||||
boxes/edit_todo_list_box.h
|
||||
boxes/gift_credits_box.cpp
|
||||
boxes/gift_credits_box.h
|
||||
boxes/gift_premium_box.cpp
|
||||
@@ -464,6 +470,7 @@ PRIVATE
|
||||
core/crash_report_window.h
|
||||
core/crash_reports.cpp
|
||||
core/crash_reports.h
|
||||
core/credits_amount.h
|
||||
core/deadlock_detector.h
|
||||
core/file_utilities.cpp
|
||||
core/file_utilities.h
|
||||
@@ -477,7 +484,6 @@ PRIVATE
|
||||
core/sandbox.h
|
||||
core/shortcuts.cpp
|
||||
core/shortcuts.h
|
||||
core/stars_amount.h
|
||||
core/ui_integration.cpp
|
||||
core/ui_integration.h
|
||||
core/update_checker.cpp
|
||||
@@ -505,6 +511,8 @@ PRIVATE
|
||||
data/components/promo_suggestions.h
|
||||
data/components/recent_peers.cpp
|
||||
data/components/recent_peers.h
|
||||
data/components/recent_shared_media_gifts.cpp
|
||||
data/components/recent_shared_media_gifts.h
|
||||
data/components/scheduled_messages.cpp
|
||||
data/components/scheduled_messages.h
|
||||
data/components/sponsored_messages.cpp
|
||||
@@ -604,6 +612,7 @@ PRIVATE
|
||||
data/data_peer_bot_command.h
|
||||
data/data_peer_bot_commands.cpp
|
||||
data/data_peer_bot_commands.h
|
||||
data/data_peer_common.h
|
||||
data/data_peer_id.cpp
|
||||
data/data_peer_id.h
|
||||
data/data_peer_values.cpp
|
||||
@@ -637,6 +646,7 @@ PRIVATE
|
||||
data/data_shared_media.h
|
||||
data/data_sparse_ids.cpp
|
||||
data/data_sparse_ids.h
|
||||
data/data_star_gift.cpp
|
||||
data/data_star_gift.h
|
||||
data/data_statistics.h
|
||||
data/data_stories.cpp
|
||||
@@ -649,6 +659,8 @@ PRIVATE
|
||||
data/data_streaming.h
|
||||
data/data_thread.cpp
|
||||
data/data_thread.h
|
||||
data/data_todo_list.cpp
|
||||
data/data_todo_list.h
|
||||
data/data_types.cpp
|
||||
data/data_types.h
|
||||
data/data_unread_value.cpp
|
||||
@@ -697,6 +709,8 @@ PRIVATE
|
||||
dialogs/dialogs_search_from_controllers.h
|
||||
dialogs/dialogs_search_tags.cpp
|
||||
dialogs/dialogs_search_tags.h
|
||||
dialogs/dialogs_search_posts.cpp
|
||||
dialogs/dialogs_search_posts.h
|
||||
dialogs/dialogs_top_bar_suggestion.cpp
|
||||
dialogs/dialogs_top_bar_suggestion.h
|
||||
dialogs/dialogs_widget.cpp
|
||||
@@ -749,6 +763,8 @@ PRIVATE
|
||||
history/view/controls/history_view_draft_options.h
|
||||
history/view/controls/history_view_forward_panel.cpp
|
||||
history/view/controls/history_view_forward_panel.h
|
||||
history/view/controls/history_view_suggest_options.cpp
|
||||
history/view/controls/history_view_suggest_options.h
|
||||
history/view/controls/history_view_ttl_button.cpp
|
||||
history/view/controls/history_view_ttl_button.h
|
||||
history/view/controls/history_view_voice_record_bar.cpp
|
||||
@@ -810,8 +826,12 @@ PRIVATE
|
||||
history/view/media/history_view_sticker_player_abstract.h
|
||||
history/view/media/history_view_story_mention.cpp
|
||||
history/view/media/history_view_story_mention.h
|
||||
history/view/media/history_view_suggest_decision.cpp
|
||||
history/view/media/history_view_suggest_decision.h
|
||||
history/view/media/history_view_theme_document.cpp
|
||||
history/view/media/history_view_theme_document.h
|
||||
history/view/media/history_view_todo_list.cpp
|
||||
history/view/media/history_view_todo_list.h
|
||||
history/view/media/history_view_unique_gift.cpp
|
||||
history/view/media/history_view_unique_gift.h
|
||||
history/view/media/history_view_userpic_suggestion.cpp
|
||||
@@ -836,6 +856,8 @@ PRIVATE
|
||||
history/view/history_view_bottom_info.h
|
||||
history/view/history_view_chat_preview.cpp
|
||||
history/view/history_view_chat_preview.h
|
||||
history/view/history_view_chat_section.cpp
|
||||
history/view/history_view_chat_section.h
|
||||
history/view/history_view_contact_status.cpp
|
||||
history/view/history_view_contact_status.h
|
||||
history/view/history_view_context_menu.cpp
|
||||
@@ -870,8 +892,6 @@ PRIVATE
|
||||
history/view/history_view_pinned_tracker.h
|
||||
history/view/history_view_quick_action.cpp
|
||||
history/view/history_view_quick_action.h
|
||||
history/view/history_view_replies_section.cpp
|
||||
history/view/history_view_replies_section.h
|
||||
history/view/history_view_reply.cpp
|
||||
history/view/history_view_reply.h
|
||||
history/view/history_view_requests_bar.cpp
|
||||
@@ -888,8 +908,8 @@ PRIVATE
|
||||
history/view/history_view_sponsored_click_handler.h
|
||||
history/view/history_view_sticker_toast.cpp
|
||||
history/view/history_view_sticker_toast.h
|
||||
history/view/history_view_sublist_section.cpp
|
||||
history/view/history_view_sublist_section.h
|
||||
history/view/history_view_subsection_tabs.cpp
|
||||
history/view/history_view_subsection_tabs.h
|
||||
history/view/history_view_text_helper.cpp
|
||||
history/view/history_view_text_helper.h
|
||||
history/view/history_view_transcribe_button.cpp
|
||||
@@ -990,6 +1010,8 @@ PRIVATE
|
||||
info/media/info_media_widget.h
|
||||
info/members/info_members_widget.cpp
|
||||
info/members/info_members_widget.h
|
||||
info/peer_gifts/info_peer_gifts_collections.cpp
|
||||
info/peer_gifts/info_peer_gifts_collections.h
|
||||
info/peer_gifts/info_peer_gifts_common.cpp
|
||||
info/peer_gifts/info_peer_gifts_common.h
|
||||
info/peer_gifts/info_peer_gifts_widget.cpp
|
||||
@@ -1040,6 +1062,9 @@ PRIVATE
|
||||
info/statistics/info_statistics_tag.h
|
||||
info/statistics/info_statistics_widget.cpp
|
||||
info/statistics/info_statistics_widget.h
|
||||
info/stories/info_stories_albums.cpp
|
||||
info/stories/info_stories_albums.h
|
||||
info/stories/info_stories_common.h
|
||||
info/stories/info_stories_inner_widget.cpp
|
||||
info/stories/info_stories_inner_widget.h
|
||||
info/stories/info_stories_provider.cpp
|
||||
@@ -1241,6 +1266,8 @@ PRIVATE
|
||||
media/view/media_view_playback_controls.h
|
||||
media/view/media_view_playback_progress.cpp
|
||||
media/view/media_view_playback_progress.h
|
||||
media/view/media_view_playback_sponsored.cpp
|
||||
media/view/media_view_playback_sponsored.h
|
||||
media/system_media_controls_manager.h
|
||||
media/system_media_controls_manager.cpp
|
||||
menu/menu_antispam_validator.cpp
|
||||
@@ -1446,6 +1473,8 @@ PRIVATE
|
||||
settings/cloud_password/settings_cloud_password_start.h
|
||||
settings/cloud_password/settings_cloud_password_step.cpp
|
||||
settings/cloud_password/settings_cloud_password_step.h
|
||||
settings/cloud_password/settings_cloud_password_validate_icon.cpp
|
||||
settings/cloud_password/settings_cloud_password_validate_icon.h
|
||||
settings/settings_active_sessions.cpp
|
||||
settings/settings_active_sessions.h
|
||||
settings/settings_advanced.cpp
|
||||
@@ -1864,11 +1893,7 @@ else()
|
||||
set(bundle_identifier "com.tdesktop.Telegram")
|
||||
endif()
|
||||
set(bundle_entitlements "Telegram.entitlements")
|
||||
if (LINUX AND DESKTOP_APP_USE_PACKAGED)
|
||||
set(output_name "telegram-desktop")
|
||||
else()
|
||||
set(output_name "Telegram")
|
||||
endif()
|
||||
set(output_name "Telegram")
|
||||
endif()
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL Xcode)
|
||||
@@ -1910,8 +1935,9 @@ PRIVATE
|
||||
G_LOG_DOMAIN="Telegram"
|
||||
)
|
||||
|
||||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if (APPLE
|
||||
OR "${CMAKE_GENERATOR}" STREQUAL "Ninja Multi-Config"
|
||||
OR is_multi_config
|
||||
OR NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL ""
|
||||
OR NOT "${output_name}" STREQUAL "Telegram")
|
||||
set(output_folder ${CMAKE_BINARY_DIR})
|
||||
@@ -1928,8 +1954,67 @@ if (MSVC)
|
||||
)
|
||||
target_link_options(Telegram
|
||||
PRIVATE
|
||||
/DELAYLOAD:secur32.dll
|
||||
/DELAYLOAD:winmm.dll
|
||||
/DELAYLOAD:ws2_32.dll
|
||||
/DELAYLOAD:user32.dll
|
||||
/DELAYLOAD:gdi32.dll
|
||||
/DELAYLOAD:advapi32.dll
|
||||
/DELAYLOAD:avrt.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()
|
||||
|
||||
target_prepare_qrc(Telegram)
|
||||
@@ -1960,6 +2045,22 @@ if (NOT DESKTOP_APP_DISABLE_AUTOUPDATE AND NOT build_macstore AND NOT build_wins
|
||||
base/platform/win/base_windows_safe_library.h
|
||||
)
|
||||
target_include_directories(Updater PRIVATE ${lib_base_loc})
|
||||
if (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)
|
||||
add_custom_command(TARGET Updater
|
||||
PRE_LINK
|
||||
@@ -1988,6 +2089,10 @@ if (NOT DESKTOP_APP_DISABLE_AUTOUPDATE AND NOT build_macstore AND NOT build_wins
|
||||
desktop-app::external_openssl
|
||||
)
|
||||
|
||||
if (DESKTOP_APP_USE_PACKAGED)
|
||||
target_compile_definitions(Packer PRIVATE PACKER_USE_PACKAGED)
|
||||
endif()
|
||||
|
||||
set_target_properties(Packer PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
|
||||
endif()
|
||||
elseif (build_winstore)
|
||||
|
||||
BIN
Telegram/Resources/animations/cloud_password/validate.tgs
Normal file
BIN
Telegram/Resources/animations/diamond.tgs
Normal file
BIN
Telegram/Resources/animations/edit_peers/direct_messages.tgs
Normal file
BIN
Telegram/Resources/animations/edit_peers/topics.tgs
Normal file
BIN
Telegram/Resources/animations/edit_peers/topics_list.tgs
Normal file
BIN
Telegram/Resources/animations/edit_peers/topics_tabs.tgs
Normal file
BIN
Telegram/Resources/animations/no_chats.tgs
Normal file
8
Telegram/Resources/icons/chat/input_paid.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Input / input_paid</title>
|
||||
<g id="Icon-/-Input-/-input_paid" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M20,9.8 C25.6299826,9.8 30.2,14.2730045 30.2,19.7983329 C30.2,25.3236612 25.6299826,29.7966657 20,29.7966657 C18.7457032,29.7966657 17.522531,29.57429 16.3765194,29.1472418 L16.049,29.018 L15.8675895,29.1274403 L15.6273764,29.2612632 C14.545782,29.8404011 13.0955737,30.1473058 11.2731839,30.1996583 C10.8153842,30.2127839 10.4336239,29.8523042 10.4204985,29.3945045 C10.4177264,29.2978179 10.4318913,29.2013918 10.4663408,29.0979123 C10.9468917,27.7307176 11.2958938,26.5818971 11.5130707,25.6565167 L11.566,25.42 L11.5361505,25.3785138 C10.4824637,23.8473989 9.87852612,22.0565089 9.80714989,20.1756532 L9.8,19.7983329 C9.8,14.2730045 14.3700174,9.8 20,9.8 Z M20,11.2 C15.1365724,11.2 11.2,15.0530063 11.2,19.7983329 C11.2,21.6384229 11.7922255,23.3893508 12.8759186,24.8453165 L13.0610907,25.0940992 L13.001223,25.3983974 C12.8243697,26.2973155 12.5137714,27.4099145 12.0719423,28.73207 L12.064,28.754 L12.2244984,28.7405395 C13.2682683,28.6413859 14.1190062,28.4334572 14.7754263,28.1231964 L14.9665215,28.0270547 C15.164827,27.9208723 15.3780604,27.7932923 15.605736,27.6441968 L15.9287098,27.4326945 L16.2799121,27.5930136 C17.4341359,28.1199012 18.6962936,28.3966657 20,28.3966657 C24.8634276,28.3966657 28.8,24.5436594 28.8,19.7983329 C28.8,15.0530063 24.8634276,11.2 20,11.2 Z" id="Shape---" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M20.2258661,25.6815247 C20.5071894,25.6815247 20.874026,25.4574745 20.874026,25.0631159 L20.874026,24.4093038 C22.5557139,24.2186972 23.4454545,23.1802196 23.4454545,21.6685117 C23.4454545,20.3671283 22.7015108,19.5784112 21.1573587,19.2234884 L19.8882782,18.9211469 C19.0943214,18.7371128 18.7067205,18.3558996 18.7067205,17.7972249 C18.7067205,17.1268153 19.2568638,16.6404397 20.1195884,16.6404397 C20.8197708,16.6404397 21.3073978,16.8902001 21.8512894,17.5277465 C22.126361,17.8300881 22.3389164,17.941823 22.6264913,17.941823 C22.9765824,17.941823 23.2454024,17.68549 23.2454024,17.3042767 C23.2454024,16.9362087 23.0390987,16.5352774 22.6890076,16.1737821 C22.2263871,15.713697 21.7022327,15.4113555 20.9207792,15.3061932 L20.9207792,14.6509738 C20.9207792,14.2631879 20.5009377,13.9363049 20.2133629,13.9363049 C19.9320396,13.9363049 19.5493506,14.2566152 19.5493506,14.6509738 L19.5493506,15.2864752 C17.930179,15.4442187 17.0312842,16.4629784 17.0312842,17.9221051 C17.0312842,19.1971979 17.7752279,20.0450688 19.2005991,20.3802736 L20.4696796,20.6891878 C21.3949206,20.9192303 21.7762699,21.2610078 21.7762699,21.8394004 C21.7762699,22.5886817 21.219875,23.061912 20.2258661,23.061912 C19.4819224,23.061912 18.8630112,22.766143 18.3003647,22.1285967 C17.9815316,21.7933919 17.8064861,21.7210928 17.5689242,21.7210928 C17.1875749,21.7210928 16.9,21.9774259 16.9,22.417793 C16.9,22.8055789 17.1125554,23.2065101 17.4939047,23.5548602 C17.9940349,24.0346632 18.7115432,24.3238594 19.5805195,24.4093038 L19.5805195,25.0565432 C19.5805195,25.4509018 19.9382912,25.6815247 20.2258661,25.6815247 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
BIN
Telegram/Resources/icons/chat/large_messages.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/chat/large_messages@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Telegram/Resources/icons/chat/large_messages@3x.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
7
Telegram/Resources/icons/chat/paid_approve.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Filled / paid_approve</title>
|
||||
<g id="Icon-/-Filled-/-paid_approve" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M12,4.5 C16.14,4.5 19.5,7.86 19.5,12 C19.5,16.14 16.14,19.5 12,19.5 C7.86,19.5 4.5,16.14 4.5,12 C4.5,7.86 7.86,4.5 12,4.5 Z M15.7577636,9.89127556 C15.4992394,9.62810439 15.0763217,9.62433727 14.8131506,9.88286145 L10.7479688,13.8761719 L9.18684944,12.3424898 C8.92367827,12.0839656 8.50076063,12.0877327 8.24223645,12.3509039 C7.98371227,12.6140751 7.98747939,13.0369927 8.25065056,13.2955169 L10.204967,15.2153247 C10.5064723,15.5115061 10.9896874,15.5115061 11.2911927,15.2153247 L15.7493494,10.8358886 C16.0125206,10.5773644 16.0162877,10.1544467 15.7577636,9.89127556 Z" id="Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 999 B |
7
Telegram/Resources/icons/chat/paid_decline.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Filled / paid_decline</title>
|
||||
<g id="Icon-/-Filled-/-paid_decline" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M12,4.5 C16.1421356,4.5 19.5,7.85786438 19.5,12 C19.5,16.1421356 16.1421356,19.5 12,19.5 C7.85786438,19.5 4.5,16.1421356 4.5,12 C4.5,7.85786438 7.85786438,4.5 12,4.5 Z M9.73375908,8.63964245 C9.43162712,8.33751049 8.94177442,8.33751049 8.63964245,8.63964245 L8.59853606,8.68404063 C8.33819559,8.98800138 8.35189772,9.44601435 8.63964245,9.73375908 L10.9059783,12 L8.63964245,14.2662409 C8.33751049,14.5683729 8.33751049,15.0582256 8.63964245,15.3603575 L8.68404063,15.4014639 C8.98800138,15.6618044 9.44601435,15.6481023 9.73375908,15.3603575 L12,13.0936701 L14.2662409,15.3603575 C14.5683729,15.6624895 15.0582256,15.6624895 15.3603575,15.3603575 L15.4014639,15.3159594 C15.6618044,15.0119986 15.6481023,14.5539856 15.3603575,14.2662409 L13.0936701,12 L15.3603575,9.73375908 C15.6624895,9.43162712 15.6624895,8.94177442 15.3603575,8.63964245 L15.3159594,8.59853606 C15.0119986,8.33819559 14.5539856,8.35189772 14.2662409,8.63964245 L12,10.9059783 L9.73375908,8.63964245 Z" id="Shape" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
7
Telegram/Resources/icons/chat/paid_edit.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Filled / paid_edit</title>
|
||||
<g id="Icon-/-Filled-/-paid_edit" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M13.5029106,7.64699152 C13.6056531,7.5472623 13.7697888,7.549705 13.869518,7.65244745 L16.2610253,10.1162122 C16.3593492,10.2175069 16.3585592,10.3788499 16.259248,10.4791768 L7.97687653,18.8462593 C7.87948817,18.9446437 7.74680196,19 7.6083679,19 L5.51851849,19 C5.23214864,19 5,18.7678513 5,18.4814815 L5,16.3683223 C5,16.2308422 5.05459809,16.0989896 5.15178971,16.0017551 L13.5029106,7.64699152 Z M16.0299869,5.19856593 C16.3408365,4.91998643 16.8161619,4.93645109 17.1069903,5.23587194 L18.7801411,6.95845528 C19.073802,7.26079221 19.0732123,7.74202152 18.7788114,8.04363789 L17.6449122,9.20518682 C17.5421105,9.3048549 17.3779763,9.30231456 17.2783082,9.19951281 L14.8031149,6.64621027 C14.707554,6.53957983 14.7165277,6.3756714 14.8231582,6.28011055 L16.0299869,5.19856593 Z" id="Shape" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
7
Telegram/Resources/icons/limits/filled_rating_crown.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Filled / Folder / filled_rating_crown</title>
|
||||
<g id="Icon-/-Filled-/-Folder-/-filled_rating_crown" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M12.006194,4 C12.2804747,4 12.5305167,4.06540388 12.7563199,4.19621163 C12.9821231,4.32701939 13.1625206,4.50276893 13.2975123,4.72346025 C13.4325041,4.94415157 13.5,5.18550018 13.5,5.44750606 C13.5,5.71705917 13.4325041,5.96227898 13.2975123,6.18316549 C13.1625206,6.404052 12.9821231,6.5799154 12.7563199,6.71075569 L15.4435899,11.5643277 C15.5815617,11.7639089 15.7563694,11.7899721 15.968013,11.6425174 L18.1781768,9.33989673 C18.0593923,9.13003568 18,8.89851056 18,8.64532138 C18,8.38325043 18.0675127,8.14188556 18.202538,7.92122677 C18.3375634,7.70056798 18.5179776,7.52481844 18.7437808,7.39397816 C18.969584,7.26313787 19.2198274,7.19771773 19.494511,7.19771773 C19.7726861,7.19771773 20.0256488,7.26313787 20.2533991,7.39397816 C20.4811495,7.52481844 20.6625206,7.69962458 20.7975123,7.91839656 C20.9325041,8.13716855 21,8.37947682 21,8.64532138 C21,8.91526486 20.9315305,9.16058227 20.7945916,9.38127359 C20.6576527,9.60196491 20.4753248,9.77771445 20.247608,9.90852221 C20.0847544,10.0020705 19.9099761,10.0621678 19.7232729,10.0888143 L18.6881679,14.8280591 L18.18147,17.2645439 C18.0360821,17.8406994 17.5858498,18.2705453 17.2433245,18.5609529 C16.9007991,18.8513606 16.024907,19 15.4030968,19 L8.60301533,19 C7.98112362,19 7.07922209,18.853651 6.73645226,18.5609529 C6.39368244,18.2682549 5.96970407,17.8361186 5.82537564,17.2645439 L5.33200224,14.8280591 L4.28780473,10.091804 C4.09296054,10.0668449 3.91161924,10.005751 3.74378084,9.90852221 C3.51797764,9.77771445 3.33756337,9.60196491 3.20253802,9.38127359 C3.06751267,9.16058227 3,8.91526486 3,8.64532138 C3,8.38325043 3.06751267,8.14188556 3.20253802,7.92122677 C3.33756337,7.70056798 3.51797764,7.52481844 3.74378084,7.39397816 C3.96958405,7.26313787 4.21982744,7.19771773 4.49451103,7.19771773 C4.77268607,7.19771773 5.02564877,7.26313787 5.25339913,7.39397816 C5.48114949,7.52481844 5.66252056,7.69962458 5.79751234,7.91839656 C5.93250411,8.13716855 6,8.37947682 6,8.64532138 C6,8.85527742 5.9585802,9.05033621 5.8757406,9.23049773 L5.8356,9.31024634 L8.05741354,11.6413327 C8.17558193,11.7218918 8.27307085,11.7527925 8.3498803,11.7340349 C8.42668976,11.7152773 8.49488107,11.6628546 8.55445424,11.576767 L11.2500459,6.70934707 C11.0234694,6.57865415 10.8419403,6.40326029 10.7054588,6.18316549 C10.5684863,5.96227898 10.5,5.71705917 10.5,5.44750606 C10.5,5.18172656 10.5675127,4.93943456 10.702538,4.72063004 C10.8375634,4.50182552 11.0189344,4.32701939 11.2466512,4.19621163 C11.474368,4.06540388 11.7275489,4 12.006194,4 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
7
Telegram/Resources/icons/limits/filled_understood.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Filled / Folder / filled_understood</title>
|
||||
<g id="Icon-/-Filled-/-Folder-/-filled_understood" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M12.8474094,2.35452236 C13.885383,1.47475174 14.8173541,2.39162557 15.6118925,3.37253311 L15.7012514,3.4837597 C16.5164257,4.50413739 16.896938,5.20519347 17.573079,6.45345067 C18.2023878,7.61607163 19,9.78891004 19,11.0676479 L18.9982623,11.4602681 C18.9876271,12.5429001 18.9217408,13.3886119 18.6297323,14.4132675 L18.4373147,15.0832437 C17.6686959,17.7193108 17.0159257,19.2763685 14.5216634,19.7807735 C13.10206,20.068163 10.6477559,20.1900858 9.65842399,19.3946847 C7.99649075,18.0581246 7.24548521,16.7868457 6.69332563,15.7108913 L6.48407363,15.2966137 C6.20747049,14.7436067 5.49035123,13.0903916 6.59969082,12.2935391 C7.07533115,11.9524455 7.88026093,12.0496935 8.21540442,12.3820783 C9.4579233,13.6143694 9.58232154,15.2464067 11.9078369,15.2464067 C13.3786631,15.2464067 13.9391869,14.2869904 13.9391869,12.58878 C13.9391869,11.3521345 12.1390712,10.1619357 9.97161486,11.0502304 C8.24621513,12.1140246 7.17909072,11.547078 6.86322591,10.7478144 L6.82781627,10.6508891 L6.79127892,10.5445502 C6.5448802,9.79724635 6.61229951,9.16312262 10.1911412,7.82363067 C10.6137438,7.6657143 11.3830789,7.698766 12.0161927,7.78792773 C12.8897042,8.04621996 13.6148836,8.35641256 14.1913276,8.71620571 C14.929645,9.17703372 15.7391454,9.82868756 16.6173642,10.6711738 C16.8017985,10.848104 17.0950516,10.8396614 17.2723632,10.6523169 C17.4496747,10.4649723 17.4439006,10.1696692 17.2594662,9.99273903 C16.7803672,9.5331334 16.3184045,9.12578598 15.8732309,8.77069768 L15.8624136,8.73672043 C15.3582916,7.35121785 14.8646161,6.25548747 14.3777651,5.44628421 C13.9445436,4.72621943 13.3206019,3.99276536 12.5068246,3.24305992 C12.4746432,2.90001775 12.5672164,2.59132364 12.8474094,2.35452236 Z M10.9668008,4.0469269 L11.0518595,3.98215031 C11.2745376,3.81947674 11.4718477,3.74284792 11.8308451,3.8850515 C12.6071746,4.59396408 13.1906226,5.27558261 13.5826599,5.9271944 C13.8835044,6.42723311 14.1925809,7.05721299 14.5092459,7.81609175 C13.7940229,7.39877614 12.9130339,7.05268239 11.8658275,6.77510676 L11.6720359,6.53222118 C11.6390059,6.49065589 11.6057339,6.44860798 11.5724054,6.40616676 L11.3960913,6.1777103 C10.8136406,5.40671311 10.3189783,4.5550951 10.9668008,4.0469269 Z" id="Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 470 B |
|
Before Width: | Height: | Size: 899 B After Width: | Height: | Size: 899 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/menu/cancel_fee.png
Normal file
|
After Width: | Height: | Size: 865 B |
BIN
Telegram/Resources/icons/menu/cancel_fee@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/menu/cancel_fee@3x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
11
Telegram/Resources/icons/menu/rating_gifts.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Menu / rating_gifts</title>
|
||||
<g id="Icon-/-Menu-/-rating_gifts" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M9.49180328,1 C11.2844653,1 12.6018066,2.18644541 12.6018066,3.65 C12.6018066,5.11355459 11.2844653,6.3 9.49180328,6.3 C7.6991413,6.3 6.24590164,5.11355459 6.24590164,3.65 C6.24590164,2.18644541 7.6991413,1 9.49180328,1 Z M9.49180328,2.2 C8.31430075,2.2 7.44590164,2.90897331 7.44590164,3.65 C7.44590164,4.39102669 8.31430075,5.1 9.49180328,5.1 C10.6309547,5.1 11.4018066,4.43203043 11.4018066,3.65 C11.4018066,2.86796957 10.6309547,2.2 9.49180328,2.2 Z" id="Oval" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M14.5081967,1 C16.3008587,1 17.7540984,2.18644541 17.7540984,3.65 C17.7540984,5.11355459 16.3008587,6.3 14.5081967,6.3 C12.7155347,6.3 11.4638672,5.11355459 11.4638672,3.65 C11.4638672,2.18644541 12.7155347,1 14.5081967,1 Z M14.5081967,2.2 C13.3883731,2.2 12.6638672,2.84700401 12.6638672,3.65 C12.6638672,4.45299599 13.3883731,5.1 14.5081967,5.1 C15.6856993,5.1 16.5540984,4.39102669 16.5540984,3.65 C16.5540984,2.90897331 15.6856993,2.2 14.5081967,2.2 Z" id="Oval" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M19.5245902,5.2245614 C20.6708074,5.2245614 21.6,6.15375404 21.6,7.29997124 L21.6,9.62036238 C21.6,10.2776718 21.0671455,10.8105263 20.4098361,10.8105263 L3.59016393,10.8105263 C2.93285454,10.8105263 2.4,10.2776718 2.4,9.62036238 L2.4,7.29997124 C2.4,6.15375404 3.32919263,5.2245614 4.47540984,5.2245614 L19.5245902,5.2245614 Z M19.5245902,6.4245614 L4.47540984,6.4245614 C3.99193433,6.4245614 3.6,6.81649574 3.6,7.29997124 L3.6,9.6095614 L20.4,9.6095614 L20.4,7.29997124 C20.4,6.85368616 20.0660441,6.48540066 19.6343997,6.43138209 L19.5245902,6.4245614 Z" id="Rectangle" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M5.07540984,10.7953216 L5.07540984,18.3761864 C5.07540984,19.3485697 5.86368226,20.1368421 6.83606557,20.1368421 L17.1639344,20.1368421 C18.1363177,20.1368421 18.9245902,19.3485697 18.9245902,18.3761864 L18.9245902,10.7953216 L20.1245902,10.7953216 L20.1245902,18.3761864 C20.1245902,20.0113114 18.7990594,21.3368421 17.1639344,21.3368421 L6.83606557,21.3368421 C5.20094056,21.3368421 3.87540984,20.0113114 3.87540984,18.3761864 L3.87540984,10.7953216 L5.07540984,10.7953216 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<polygon id="Path" fill="#FFFFFF" fill-rule="nonzero" points="11.4 6.11695906 11.4 21 12.6 21 12.6 6.11695906"></polygon>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
9
Telegram/Resources/icons/menu/rating_refund.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Menu / rating_refund</title>
|
||||
<g id="Icon-/-Menu-/-rating_refund" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M9.58495703,2.34314741 C14.845204,0.914046898 20.2520851,4.07916838 21.661564,9.41264412 C23.0710429,14.7461199 19.9493787,20.2282711 14.6891317,21.6573716 C9.70832403,23.0105542 4.55852362,20.241996 2.84766326,15.3548697 L2.79687536,15.2061286 C2.7724639,15.132795 2.65678419,14.7396157 2.52176727,14.2756688 L2.02361181,12.5403036 C1.92527607,12.1682007 2.1430666,11.785725 2.51006058,11.6860203 C2.87705455,11.5863156 3.25427881,11.807138 3.35261455,12.179241 L3.59432993,13.0275538 C3.80113943,13.7451404 4.06828557,14.6632038 4.10050903,14.760005 C5.52633258,19.0432668 10.0041242,21.485941 14.3330265,20.3098676 C18.8592855,19.0801764 21.5453687,14.3629766 20.3325613,9.77370673 C19.1197538,5.18443691 14.4673212,2.46096029 9.94106224,3.69065143 C7.52370963,4.34739623 5.56035445,6.02376558 4.49357103,8.2653952 C4.32845825,8.61234632 3.91721015,8.75789206 3.57502268,8.59048072 C3.23283521,8.42306937 3.08928781,8.00609621 3.25440059,7.65914509 C4.49336656,5.05570865 6.77676829,3.10607433 9.58495703,2.34314741 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M2.49794681,3.90217796 C2.49794681,3.51694863 2.80594913,3.20465855 3.18588925,3.20465855 C3.56582936,3.20465855 3.87383169,3.51694863 3.87383169,3.90217796 L3.87360558,7.52173176 L6.91980245,7.41555441 C7.2814361,7.4029357 7.58746725,7.67568116 7.62708143,8.03426422 L7.63099908,8.08867052 C7.64406681,8.47367193 7.34684021,8.79651819 6.96712488,8.80976784 L3.24117729,8.93977968 C2.86111038,8.95304159 2.53984537,8.66451926 2.50172057,8.28653895 L2.49800979,8.22097241 L2.49794681,3.90217796 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M12.3540269,17.3251877 C12.6431336,17.3251877 12.9561718,17.1659567 12.9561718,16.7838024 L12.9561718,16.1901404 C14.6843872,16.0054325 15.7076642,14.9990928 15.7076642,13.5341679 C15.7076642,12.2730587 14.9431377,11.50875 13.3562633,11.1648111 L12.0520711,10.8718262 C11.2361478,10.6934875 10.8378231,10.3240717 10.8378231,9.78268638 C10.8378231,9.13302405 11.4031872,8.66170039 12.289781,8.66170039 C13.0093353,8.66170039 13.5104536,8.90373146 14.0693931,9.5215476 C14.3520752,9.81453257 14.5705113,9.92280963 14.8660426,9.92280963 C15.2258197,9.92280963 15.5020772,9.67440933 15.5020772,9.30499349 C15.5020772,8.94831613 15.2900657,8.55979258 14.9302885,8.20948446 C14.4548686,7.76363776 13.7920916,7.47065278 12.9890176,7.36874497 L12.9890176,6.69989325 C12.9890176,6.32410818 12.6816811,6.16487722 12.3861499,6.16487722 C12.0970432,6.16487722 11.7838443,6.31773894 11.7838443,6.69989325 L11.7838443,7.34963725 C10.1198749,7.50249898 9.11603231,8.48973095 9.11603231,9.90370191 C9.11603231,11.1393342 9.88055881,11.960966 11.3453659,12.2857971 L12.6495582,12.5851513 C13.6003978,12.8080747 13.992298,13.1392751 13.992298,13.6997681 C13.992298,14.4258613 13.4205093,14.8844465 12.3989991,14.8844465 C11.6344726,14.8844465 10.9984379,14.5978307 10.4202246,13.9800146 C10.0925704,13.6551834 9.91268177,13.5851218 9.66854726,13.5851218 C9.27664712,13.5851218 8.98111587,13.8335221 8.98111587,14.2602611 C8.98111587,14.6360462 9.19955201,15.0245697 9.59145215,15.3621394 C10.1054195,15.8270938 10.852439,16.1137095 11.7454573,16.1965096 L11.7454573,16.7838024 C11.7454573,17.1659567 12.0584957,17.3251877 12.3540269,17.3251877 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
10
Telegram/Resources/icons/menu/users_stars.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Menu / users_stars</title>
|
||||
<g id="Icon-/-Menu-/-users_stars" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M10.6647222,14.6083333 C13.1679529,14.6083333 15.1972222,16.6376027 15.1972222,19.1408333 L15.1972222,19.1805556 C15.1972222,19.5119264 14.9285931,19.7805556 14.5972222,19.7805556 C14.2658514,19.7805556 13.9972222,19.5119264 13.9972222,19.1805556 L13.9972222,19.1408333 C13.9972222,17.3003444 12.5052112,15.8083333 10.6647222,15.8083333 L5.47983871,15.8083333 C3.75894714,15.8083333 2.36388889,17.2033916 2.36388889,18.9242832 C2.36388889,19.255654 2.09525974,19.5242832 1.76388889,19.5242832 C1.43251804,19.5242832 1.16388889,19.255654 1.16388889,18.9242832 C1.16388889,16.5406499 3.09620544,14.6083333 5.47983871,14.6083333 L10.6647222,14.6083333 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M8.47745116,3.81325275 C8.84434853,3.9691957 9.13648401,4.26133118 9.29242697,4.62822855 L9.837,5.91011111 L11.2536218,6.01848992 C12.0546381,6.07958882 12.6656371,6.74303885 12.6765549,7.53105369 L12.6721689,7.67131095 C12.640454,8.08709799 12.4414977,8.47225506 12.1207729,8.73875142 L11.07,9.61111111 L11.3938701,10.9206432 C11.5864903,11.7005519 11.1475494,12.4884712 10.4025244,12.745423 L10.2679383,12.785146 C9.87396987,12.8824474 9.45751925,12.8203294 9.10909531,12.6122923 L7.874,11.8751111 L6.65149995,12.6059661 C5.96413876,13.016376 5.08613461,12.8292111 4.62167189,12.196898 L4.53957882,12.0731599 C4.32863667,11.7198706 4.26783432,11.2968624 4.3707302,10.8984627 L4.60871396,9.97701978 C4.63955115,9.85762211 4.67934978,9.74174595 4.72741862,9.63019415 L4.781,9.51711111 C4.72402035,9.48693702 4.66830927,9.45442225 4.61377597,9.41969742 L4.45384681,9.30892937 L3.75085061,8.78062735 C3.07086182,8.2696154 2.93387902,7.30411853 3.44489097,6.62412974 C3.71113573,6.26984554 4.11709183,6.04742064 4.55898263,6.01371466 L5.912,5.91011111 L6.45757303,4.62822855 C6.79029762,3.84540525 7.69462787,3.48052816 8.47745116,3.81325275 Z M8.00805289,4.91763731 C7.83516435,4.84415422 7.63544068,4.92473827 7.5619576,5.09762682 L6.81242023,6.8611133 C6.762712,6.97806516 6.65195707,7.05755523 6.52524782,7.06722019 L4.65024959,7.21023893 C4.55265687,7.21768299 4.46300042,7.2668061 4.40419957,7.34505068 C4.29134126,7.49522796 4.32159427,7.70846043 4.47177155,7.82131874 L5.17476775,8.34962077 C5.44651754,8.55384088 5.78694643,8.64456615 6.12428682,8.60267031 L7.57841053,8.42207605 C7.70002725,8.40697192 7.81692252,8.4743167 7.86485999,8.58710305 C7.92415906,8.72662077 7.85912899,8.88779362 7.71961127,8.94709269 L6.4517079,9.48598834 C6.11405341,9.62950127 5.8623347,9.92186941 5.77058814,10.2771004 L5.53260437,11.1985433 C5.50987955,11.2865309 5.52330791,11.3799534 5.56989503,11.4579782 C5.66620013,11.6192716 5.87502492,11.671955 6.03631826,11.5756499 L7.70062419,10.5819253 C7.80803032,10.5177952 7.94196968,10.5177952 8.04937581,10.5819253 L9.72427701,11.5819761 C9.80122733,11.6279216 9.89320153,11.6416405 9.98021047,11.6201513 C10.1625874,11.5751082 10.2739185,11.3907479 10.2288754,11.208371 L9.77632428,9.37601536 C9.74506588,9.24945178 9.78889505,9.11615638 9.88916433,9.03284072 L11.3538674,7.81579097 C11.4247003,7.75693456 11.4686403,7.67187163 11.4756446,7.58004398 C11.4899322,7.3927312 11.3496676,7.2293018 11.1623548,7.21501419 L9.22475218,7.06722019 C9.09804293,7.05755523 8.987288,6.97806516 8.93757977,6.8611133 L8.1880424,5.09762682 C8.153602,5.01659659 8.08908313,4.95207771 8.00805289,4.91763731 Z" id="Star" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M18.0174227,5.90931057 C18.3486503,6.04652517 18.611812,6.3096869 18.7490266,6.64091449 L19.1044444,7.5 L20.0337984,7.57332883 C20.7344012,7.62815795 21.2683217,8.20775826 21.2801433,8.89635992 L21.2761548,9.02664858 C21.2481303,9.38474356 21.0787573,9.71696686 20.805417,9.94999576 L20.0974444,10.552 L20.3154363,11.4563406 C20.4799024,12.1395692 20.0937745,12.8265284 19.4425658,13.0506693 L19.3174274,13.0871582 C18.9686126,13.1711245 18.6007266,13.1129982 18.2947908,12.9255805 L17.4994444,12.438 L16.7339799,12.9079554 C16.1370798,13.2736191 15.3682309,13.1207349 14.9530722,12.5755767 L14.8749121,12.4613522 C14.6783232,12.1404454 14.6243898,11.7521195 14.7260855,11.389785 L14.9136874,10.721373 C14.9302657,10.6623057 14.9495081,10.6043097 14.9712932,10.5475329 L14.9924444,10.496 L14.8586084,10.4042198 L14.3173233,9.99771597 C13.7202762,9.54933497 13.5997585,8.701848 14.0481395,8.10480086 C14.2812853,7.79435268 14.6366446,7.59911993 15.0237072,7.56882844 L15.8944444,7.5 L16.2509734,6.64091449 C16.536738,5.95109613 17.3276044,5.6235459 18.0174227,5.90931057 Z M17.59643,6.9255611 C17.4678713,6.87230428 17.3204807,6.93334851 17.2672239,7.0619072 L16.7120856,8.40197687 C16.6758104,8.48954314 16.5934614,8.54934298 16.4989677,8.55673805 L15.1095308,8.66547529 C15.0373954,8.6711206 14.9711685,8.70750534 14.9277181,8.76536233 C14.8441551,8.87663162 14.8666155,9.03457438 14.9778848,9.11813736 L15.5191699,9.52464117 C15.7230236,9.67773481 15.9788884,9.7445585 16.2315688,9.71069694 L17.183292,9.58315701 C17.2805543,9.57012294 17.375435,9.61996727 17.4198915,9.70745139 C17.4776834,9.82117784 17.4323395,9.96022092 17.318613,10.0180128 L16.4184593,10.4754402 C16.2004755,10.5862121 16.0388382,10.7832041 15.9727639,11.0186219 L15.7851621,11.6870339 C15.7662094,11.7545607 15.7762608,11.8269315 15.8128983,11.8867376 C15.8855887,12.0053956 16.0407073,12.0426597 16.1593653,11.9699692 L17.3683823,11.2293199 C17.449152,11.17984 17.550848,11.17984 17.6316177,11.2293199 L18.8694054,11.9875943 C18.9264214,12.0225226 18.9949829,12.0333554 19.0599901,12.0177069 C19.1952788,11.9851403 19.2785516,11.8490667 19.245985,11.7137779 L18.9067247,10.304416 C18.8845188,10.212168 18.9160198,10.1152669 18.988225,10.0537103 L20.0917784,9.1129056 C20.1427197,9.06947694 20.1742851,9.00756181 20.1795079,8.94082508 C20.1903648,8.80209601 20.086704,8.68083261 19.9479749,8.66997568 L18.5010323,8.55673805 C18.4065386,8.54934298 18.3241896,8.48954314 18.2879144,8.40197687 L17.7327761,7.0619072 C17.707204,7.00017764 17.6581596,6.95113324 17.59643,6.9255611 Z" id="Star-Copy" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M18.2638889,14.6083333 C20.7890575,14.6083333 22.8361111,16.6553869 22.8361111,19.1805556 C22.8361111,19.5119264 22.567482,19.7805556 22.2361111,19.7805556 C21.9047403,19.7805556 21.6361111,19.5119264 21.6361111,19.1805556 C21.6361111,17.3181286 20.1263158,15.8083333 18.2638889,15.8083333 L15.8789648,15.8077138 C15.6342075,15.3537143 15.2908888,14.9468235 14.8660915,14.6068359 L18.2638889,14.6083333 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
15
Telegram/Resources/icons/payments/ton_emoji.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<svg width="72px" height="72px" viewBox="0 0 72 72">
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g transform="translate(9.000000, 14.000000)" stroke-width="7.2" stroke="rgb(255,255,255)">
|
||||
<path d="M2.96014341,0 L50.9898193,0 C51.9732032,-7.06402744e-15
|
||||
52.7703933,0.797190129 52.7703933,1.78057399 C52.7703933,2.08038611
|
||||
52.6946886,2.3753442 52.5502994,2.63809702 L29.699977,44.2200383
|
||||
C28.7527832,45.9436969 26.5876295,46.5731461 24.8639708,45.6259523
|
||||
C24.2556953,45.2916896 23.7583564,44.7869606 23.4331014,44.1738213
|
||||
L1.38718565,2.61498853 C0.926351231,1.74626794 1.25700829,0.668450654
|
||||
2.12572888,0.20761623 C2.38272962,0.0712838007 2.6692209,4.97530809e-16
|
||||
2.96014341,0 Z"></path>
|
||||
<line x1="27" y1="44.4532875" x2="27" y2="0"></line>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 835 B |
BIN
Telegram/Resources/icons/settings/earn.png
Normal file
|
After Width: | Height: | Size: 889 B |
BIN
Telegram/Resources/icons/settings/earn@2x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/settings/earn@3x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
12
Telegram/Resources/icons/settings/filled_verify_age.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="72px" height="72px" viewBox="0 0 72 72" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Filled / filled_verify_age</title>
|
||||
<g id="Filled-/-filled_verify_age" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M36,34.9473684 C33.5842105,34.9473684 31.5592105,34.1302632 29.925,32.4960526 C28.2907895,30.8618421 27.4736842,28.8368421 27.4736842,26.4210526 C27.4736842,24.0526316 28.2907895,22.0394737 29.925,20.3815789 C31.5592105,18.7236842 33.5842105,17.8947368 36,17.8947368 C38.3684211,17.8947368 40.3815789,18.7236842 42.0394737,20.3815789 C43.6973684,22.0394737 44.5263158,24.0526316 44.5263158,26.4210526 C44.5263158,28.8368421 43.6973684,30.8618421 42.0394737,32.4960526 C40.3815789,34.1302632 38.3684211,34.9473684 36,34.9473684 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M18.9473684,49.6842105 L18.9473684,47.1263158 C18.9473684,46.1315789 19.1960526,45.1960526 19.6934211,44.3197368 C20.1907895,43.4434211 20.8657895,42.7447368 21.7184211,42.2236842 C23.8973684,40.9447368 26.1828947,39.9736842 28.575,39.3105263 C30.9671053,38.6473684 33.4421053,38.3157895 36,38.3157895 C38.5578947,38.3157895 41.0328947,38.6473684 43.425,39.3105263 C45.8171053,39.9736842 48.1026316,40.9447368 50.2815789,42.2236842 C51.1342105,42.7447368 51.8092105,43.4434211 52.3065789,44.3197368 C52.8039474,45.1960526 53.0526316,46.1315789 53.0526316,47.1263158 L53.0526316,49.6842105 C53.0526316,50.4894737 52.7802632,51.1644737 52.2355263,51.7092105 C51.6907895,52.2539474 51.0157895,52.5263158 50.2105263,52.5263158 L21.7894737,52.5263158 C20.9842105,52.5263158 20.3092105,52.2539474 19.7644737,51.7092105 C19.2197368,51.1644737 18.9473684,50.4894737 18.9473684,49.6842105 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M11.6842105,66 C10.1210526,66 8.78289474,65.4434211 7.66973684,64.3302632 C6.55657895,63.2171053 6,61.8789474 6,60.3157895 L6,51.7894737 C6,50.9842105 6.27236842,50.3092105 6.81710526,49.7644737 C7.36184211,49.2197368 8.03684211,48.9473684 8.84210526,48.9473684 C9.64736842,48.9473684 10.3223684,49.2197368 10.8671053,49.7644737 C11.4118421,50.3092105 11.6842105,50.9842105 11.6842105,51.7894737 L11.6842105,60.3157895 L20.2105263,60.3157895 C21.0157895,60.3157895 21.6907895,60.5881579 22.2355263,61.1328947 C22.7802632,61.6776316 23.0526316,62.3526316 23.0526316,63.1578947 C23.0526316,63.9631579 22.7802632,64.6381579 22.2355263,65.1828947 C21.6907895,65.7276316 21.0157895,66 20.2105263,66 L11.6842105,66 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M6,20.2105263 L6,11.6842105 C6,10.1210526 6.55657895,8.78289474 7.66973684,7.66973684 C8.78289474,6.55657895 10.1210526,6 11.6842105,6 L20.2105263,6 C21.0157895,6 21.6907895,6.27236842 22.2355263,6.81710526 C22.7802632,7.36184211 23.0526316,8.03684211 23.0526316,8.84210526 C23.0526316,9.64736842 22.7802632,10.3223684 22.2355263,10.8671053 C21.6907895,11.4118421 21.0157895,11.6842105 20.2105263,11.6842105 L11.6842105,11.6842105 L11.6842105,20.2105263 C11.6842105,21.0157895 11.4118421,21.6907895 10.8671053,22.2355263 C10.3223684,22.7802632 9.64736842,23.0526316 8.84210526,23.0526316 C8.03684211,23.0526316 7.36184211,22.7802632 6.81710526,22.2355263 C6.27236842,21.6907895 6,21.0157895 6,20.2105263 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M60.3157895,66 L51.7894737,66 C50.9842105,66 50.3092105,65.7276316 49.7644737,65.1828947 C49.2197368,64.6381579 48.9473684,63.9631579 48.9473684,63.1578947 C48.9473684,62.3526316 49.2197368,61.6776316 49.7644737,61.1328947 C50.3092105,60.5881579 50.9842105,60.3157895 51.7894737,60.3157895 L60.3157895,60.3157895 L60.3157895,51.7894737 C60.3157895,50.9842105 60.5881579,50.3092105 61.1328947,49.7644737 C61.6776316,49.2197368 62.3526316,48.9473684 63.1578947,48.9473684 C63.9631579,48.9473684 64.6381579,49.2197368 65.1828947,49.7644737 C65.7276316,50.3092105 66,50.9842105 66,51.7894737 L66,60.3157895 C66,61.8789474 65.4434211,63.2171053 64.3302632,64.3302632 C63.2171053,65.4434211 61.8789474,66 60.3157895,66 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M60.3157895,20.2105263 L60.3157895,11.6842105 L51.7894737,11.6842105 C50.9842105,11.6842105 50.3092105,11.4118421 49.7644737,10.8671053 C49.2197368,10.3223684 48.9473684,9.64736842 48.9473684,8.84210526 C48.9473684,8.03684211 49.2197368,7.36184211 49.7644737,6.81710526 C50.3092105,6.27236842 50.9842105,6 51.7894737,6 L60.3157895,6 C61.8789474,6 63.2171053,6.55657895 64.3302632,7.66973684 C65.4434211,8.78289474 66,10.1210526 66,11.6842105 L66,20.2105263 C66,21.0157895 65.7276316,21.6907895 65.1828947,22.2355263 C64.6381579,22.7802632 63.9631579,23.0526316 63.1578947,23.0526316 C62.3526316,23.0526316 61.6776316,22.7802632 61.1328947,22.2355263 C60.5881579,21.6907895 60.3157895,21.0157895 60.3157895,20.2105263 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
BIN
Telegram/Resources/icons/settings/gift.png
Normal file
|
After Width: | Height: | Size: 574 B |
BIN
Telegram/Resources/icons/settings/gift@2x.png
Normal file
|
After Width: | Height: | Size: 1016 B |
BIN
Telegram/Resources/icons/settings/gift@3x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
7
Telegram/Resources/icons/settings/premium/checklist.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Filled / checklist</title>
|
||||
<g id="Icon-/-Filled-/-checklist" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M12,4 C16.416,4 20,7.584 20,12 C20,16.416 16.416,20 12,20 C7.584,20 4,16.416 4,12 C4,7.584 7.584,4 12,4 Z M16.4818432,9.54348643 C16.1872637,9.22288416 15.7053635,9.21829494 15.4054889,9.53323613 L10.7733532,14.3979954 L8.99451107,12.5296222 C8.69463652,12.2146811 8.21273632,12.2192703 7.91815685,12.5398725 C7.62357737,12.8604748 7.62786989,13.3756846 7.92774444,13.6906258 L10.1546212,16.0293878 C10.4981762,16.3902041 11.0487833,16.3902041 11.3923383,16.0293878 L16.4722556,10.6942397 C16.7721301,10.3792985 16.7764226,9.8640887 16.4818432,9.54348643 Z" id="Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 975 B |
@@ -13,6 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"cloud_lng_topup_purpose_subs" = "Buy **Stars** to keep your channel subscriptions.";
|
||||
|
||||
"cloud_lng_age_verify_about_gb#one" = "To access such content, you must confirm that you are at least **{count}** year old as required by UK law.";
|
||||
"cloud_lng_age_verify_about_gb#other" = "To access such content, you must confirm that you are at least **{count}** years old as required by UK law.";
|
||||
|
||||
"cloud_lng_passport_in_ar" = "Arabic";
|
||||
"cloud_lng_passport_in_az" = "Azerbaijani";
|
||||
"cloud_lng_passport_in_bg" = "Bulgarian";
|
||||
|
||||
@@ -164,11 +164,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_chat_status_members_online" = "{members_count}, {online_count}";
|
||||
"lng_chat_status_subscribers#one" = "{count} subscriber";
|
||||
"lng_chat_status_subscribers#other" = "{count} subscribers";
|
||||
"lng_chat_status_direct" = "Direct messages";
|
||||
|
||||
"lng_channel_status" = "channel";
|
||||
"lng_group_status" = "group";
|
||||
"lng_scam_badge" = "SCAM";
|
||||
"lng_fake_badge" = "FAKE";
|
||||
"lng_direct_badge" = "DIRECT";
|
||||
|
||||
"lng_remember" = "Remember this choice";
|
||||
|
||||
@@ -432,6 +434,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_dlg_new_channel_name" = "Channel name";
|
||||
"lng_dlg_new_bot_name" = "Bot name";
|
||||
"lng_no_chats" = "Your chats will be here";
|
||||
"lng_no_conversations" = "You have no\nconversations yet.";
|
||||
"lng_no_conversations_button" = "New Message";
|
||||
"lng_no_conversations_subtitle" = "Your contacts on Telegram";
|
||||
"lng_no_chats_filter" = "No chats currently belong to this folder.";
|
||||
"lng_no_saved_sublists" = "You can save messages from other chats here.";
|
||||
"lng_contacts_loading" = "Loading...";
|
||||
@@ -840,6 +845,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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_suggestion_password_title" = "Your password";
|
||||
"lng_settings_suggestion_password_about" = "Your account is protected by 2-Step Veritifaction. Do you still remember your password?";
|
||||
"lng_settings_suggestion_password_yes" = "Yes, definitely";
|
||||
"lng_settings_suggestion_password_no" = "Not sure";
|
||||
"lng_settings_suggestion_password_step_input_title" = "Enter your password";
|
||||
"lng_settings_suggestion_password_step_input_about" = "Do you still remember your password?";
|
||||
"lng_settings_suggestion_password_step_finish_title" = "Perfect!";
|
||||
"lng_settings_suggestion_password_step_finish_about" = "You still remember your password.";
|
||||
|
||||
"lng_settings_power_menu" = "Battery and Animations";
|
||||
"lng_settings_power_title" = "Power Usage";
|
||||
@@ -1152,6 +1165,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_proxy_menu_delete" = "Delete";
|
||||
"lng_proxy_menu_restore" = "Restore";
|
||||
"lng_proxy_edit_share" = "Share";
|
||||
"lng_proxy_edit_share_qr_box_title" = "Share proxy with QR code";
|
||||
"lng_proxy_edit_share_list_button" = "Share Proxy List";
|
||||
"lng_proxy_edit_share_list_toast" = "Proxy List copied to clipboard.";
|
||||
"lng_proxy_address_label" = "Socket address";
|
||||
"lng_proxy_credentials_optional" = "Credentials (optional)";
|
||||
"lng_proxy_credentials" = "Credentials";
|
||||
@@ -1190,6 +1206,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_faq_link" = "https://telegram.org/faq#general-questions";
|
||||
"lng_settings_features" = "Telegram Features";
|
||||
"lng_settings_credits" = "My Stars";
|
||||
"lng_settings_currency" = "My TON";
|
||||
"lng_settings_logout" = "Log out";
|
||||
"lng_sure_logout" = "Are you sure you want to log out?";
|
||||
|
||||
@@ -1481,6 +1498,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_hide_participants_about" = "Switch this on to hide the list of members in this group. Admins will remain visible.";
|
||||
"lng_profile_view_channel" = "View Channel";
|
||||
"lng_profile_view_discussion" = "View discussion";
|
||||
"lng_profile_direct_messages" = "Direct messages";
|
||||
"lng_profile_join_channel" = "Join Channel";
|
||||
"lng_profile_join_group" = "Join Group";
|
||||
"lng_profile_apply_to_join_group" = "Apply to Join Group";
|
||||
@@ -1858,6 +1876,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_star_ref_revoked_title" = "Link removed";
|
||||
"lng_star_ref_revoked_text" = "It will no longer work.";
|
||||
|
||||
"lng_stars_rating_title" = "Rating";
|
||||
"lng_stars_rating_future" = "Future Rating";
|
||||
"lng_stars_rating_subtitle" = "The rating update updates in 21 days after purchases.";
|
||||
"lng_stars_rating_pending#one" = "{count} point is pending. {link}";
|
||||
"lng_stars_rating_pending#other" = "{count} points are pending. {link}";
|
||||
"lng_stars_rating_pending_preview" = "Preview {arrow}";
|
||||
"lng_stars_rating_pending_back" = "Back {arrow}";
|
||||
"lng_stars_rating_about" = "This rating reflects **{name}'s** activity on Telegram. What affects it:";
|
||||
"lng_stars_rating_about_your" = "This rating reflects your activity on Telegram. What affects it:";
|
||||
"lng_stars_title_gifts_telegram" = "Gifts from Telegram";
|
||||
"lng_stars_about_gifts_telegram" = "{emoji} 100% of the Stars spent on gifts purchased from Telegram.";
|
||||
"lng_stars_title_gifts_users" = "Gifts and Posts from Users";
|
||||
"lng_stars_about_gifts_users" = "{emoji} 20% of the Stars spent on resold gifts, paid messages and channel posts.";
|
||||
"lng_stars_title_refunds" = "Refunds and Conversions";
|
||||
"lng_stars_about_refunds" = "{emoji} 10x of refunded Stars and 85% of bought gifts converted to Stars.";
|
||||
"lng_stars_rating_added" = "Added";
|
||||
"lng_stars_rating_deducted" = "Deducted";
|
||||
"lng_stars_rating_understood" = "Understood";
|
||||
|
||||
"lng_manage_discussion_group" = "Discussion";
|
||||
"lng_manage_discussion_group_add" = "Add a group";
|
||||
"lng_manage_linked_channel" = "Linked channel";
|
||||
@@ -1878,6 +1915,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_manage_linked_channel_posted" = "All new posts from this channel are forwarded to the group.";
|
||||
"lng_manage_discussion_group_warning" = "\"Chat history for new members\" will be switched to **Visible**.";
|
||||
|
||||
"lng_manage_monoforum" = "Direct Messages";
|
||||
"lng_manage_monoforum_off" = "Off";
|
||||
"lng_manage_monoforum_free" = "Free";
|
||||
"lng_manage_monoforum_allow" = "Allow Channel Messages";
|
||||
"lng_manage_monoforum_price" = "Price for each message";
|
||||
"lng_manage_monoforum_about" = "Allow users to send messages to your channel, with the option to charge a fee for each message.";
|
||||
"lng_manage_monoforum_price_about" = "Your channel will receive {percent} of the selected fee ({amount}) for each incoming message.";
|
||||
|
||||
"lng_manage_history_visibility_title" = "Chat history for new members";
|
||||
"lng_manage_history_visibility_shown" = "Visible";
|
||||
"lng_manage_history_visibility_shown_about" = "New members will see messages that were sent before they joined.";
|
||||
@@ -2061,6 +2106,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_changed_title" = "{from} changed group name to «{title}»";
|
||||
"lng_action_changed_title_channel" = "Channel name was changed to «{title}»";
|
||||
"lng_action_created_chat" = "{from} created the group «{title}»";
|
||||
"lng_action_created_monoforum" = "Direct messages were enabled in this channel.";
|
||||
"lng_action_ttl_changed" = "{from} set messages to auto-delete in {duration}";
|
||||
"lng_action_ttl_changed_you" = "You set messages to auto-delete in {duration}";
|
||||
"lng_action_ttl_changed_channel" = "Messages in this channel will be automatically deleted after {duration}";
|
||||
@@ -2152,6 +2198,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_gift_channel_about_unique" = "You can display this gift in channel's Gifts or turn it into unique collectible.";
|
||||
"lng_action_gift_for_stars#one" = "{count} Star";
|
||||
"lng_action_gift_for_stars#other" = "{count} Stars";
|
||||
"lng_action_gift_for_ton#one" = "{count} TON";
|
||||
"lng_action_gift_for_ton#other" = "{count} TON";
|
||||
"lng_action_gift_got_subtitle" = "Gift from {user}";
|
||||
"lng_action_gift_got_stars_text#one" = "Display this gift on your page or convert it to **{count}** Star.";
|
||||
"lng_action_gift_got_stars_text#other" = "Display this gift on your page or convert it to **{count}** Stars.";
|
||||
@@ -2168,6 +2216,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_gift_premium_months#other" = "{count} Months Premium";
|
||||
"lng_action_gift_premium_about" = "Subscription for exclusive Telegram features.";
|
||||
"lng_action_gift_refunded" = "This gift was downgraded because a request to refund the payment related to this gift was made, and the money was returned.";
|
||||
"lng_action_gift_got_ton" = "Use TON to suggest posts to channels.";
|
||||
"lng_action_suggested_photo_me" = "You suggested this photo for {user}'s Telegram profile.";
|
||||
"lng_action_suggested_photo" = "{user} suggests this photo for your Telegram profile.";
|
||||
"lng_action_suggested_photo_button" = "View Photo";
|
||||
@@ -2235,6 +2284,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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_action_direct_messages_enabled" = "Channel enabled Direct Messages.";
|
||||
"lng_action_direct_messages_paid#one" = "Channel allows Direct Messages for {count} Star each.";
|
||||
"lng_action_direct_messages_paid#other" = "Channel allows Direct Messages for {count} Stars each.";
|
||||
"lng_action_direct_messages_disabled" = "Channel disabled Direct Messages.";
|
||||
"lng_action_todo_marked_done" = "{from} marked {tasks} as done.";
|
||||
"lng_action_todo_marked_done_self" = "You marked {tasks} as done.";
|
||||
"lng_action_todo_marked_not_done" = "{from} marked {tasks} as not done.";
|
||||
"lng_action_todo_marked_not_done_self" = "You marked {tasks} as not done.";
|
||||
"lng_action_todo_added" = "{from} added {tasks} to the list.";
|
||||
"lng_action_todo_added_self" = "You added {tasks} to the list.";
|
||||
"lng_action_todo_tasks_fallback#one" = "task";
|
||||
"lng_action_todo_tasks_fallback#other" = "{count} tasks";
|
||||
"lng_action_todo_tasks_and_one" = "{tasks}, {task}";
|
||||
"lng_action_todo_tasks_and_last" = "{tasks} and {task}";
|
||||
"lng_action_suggest_success_stars#one" = "{from} has received {count} Star for publishing post.";
|
||||
"lng_action_suggest_success_stars#other" = "{from} has received {count} Stars for publishing post.";
|
||||
"lng_action_suggest_success_ton#one" = "{from} has received {count} TON for publishing post.";
|
||||
"lng_action_suggest_success_ton#other" = "{from} has received {count} TON for publishing post.";
|
||||
"lng_action_suggest_refund_user" = "User refunded the Stars so that post was deleted.";
|
||||
"lng_action_suggest_refund_admin" = "Admin deleted the post early so that the price was refunded to the user.";
|
||||
"lng_action_post_rejected" = "The post was rejected.";
|
||||
"lng_action_not_enough_funds" = "Transaction failed.";
|
||||
"lng_you_paid_stars#one" = "You paid {count} Star.";
|
||||
"lng_you_paid_stars#other" = "You paid {count} Stars.";
|
||||
|
||||
@@ -2539,6 +2610,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_premium_unlock_emoji" = "Unlock Animated Emoji";
|
||||
"lng_premium_unlock_status" = "Unlock Emoji Status";
|
||||
|
||||
"lng_premium_subscribe_months_24" = "2-Year";
|
||||
"lng_premium_subscribe_months_12" = "Annual";
|
||||
"lng_premium_subscribe_months_6" = "Semiannual";
|
||||
"lng_premium_subscribe_months_1" = "Monthly";
|
||||
@@ -2602,6 +2674,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_premium_summary_about_effects" = "Add over 500 animated effects to private messages.";
|
||||
"lng_premium_summary_subtitle_filter_tags" = "Tag Your Chats";
|
||||
"lng_premium_summary_about_filter_tags" = "Display folder names for each chat in the chat list.";
|
||||
"lng_premium_summary_subtitle_todo_lists" = "Checklists";
|
||||
"lng_premium_summary_about_todo_lists" = "Plan, assign, and complete tasks - seamlessly and efficiently.";
|
||||
"lng_premium_summary_bottom_subtitle" = "About Telegram Premium";
|
||||
"lng_premium_summary_bottom_about" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";
|
||||
"lng_premium_summary_button" = "Subscribe for {cost} per month";
|
||||
@@ -2732,6 +2806,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_credits_summary_title" = "Telegram Stars";
|
||||
"lng_credits_summary_about" = "Buy Stars to unlock content and services in miniapps on Telegram.";
|
||||
"lng_credits_currency_summary_title" = "TON Balance";
|
||||
"lng_credits_currency_summary_about" = "Offer TON to submit post suggestions to channels on Telegram.";
|
||||
"lng_credits_currency_summary_subtitle" = "You can withdraw your TON using Fragment.";
|
||||
"lng_credits_currency_summary_in_button" = "Top-up via Fragment";
|
||||
"lng_credits_currency_summary_in_subtitle" = "You can top-up your TON balance via Fragment.";
|
||||
"lng_credits_summary_options_subtitle" = "Choose package";
|
||||
"lng_credits_summary_options_credits#one" = "{count} Star";
|
||||
"lng_credits_summary_options_credits#other" = "{count} Stars";
|
||||
@@ -2755,8 +2834,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_credits_premium_gift_duration" = "Duration";
|
||||
"lng_credits_more_options" = "More Options";
|
||||
"lng_credits_balance_me" = "your balance";
|
||||
"lng_credits_buy_button" = "Buy More Stars";
|
||||
"lng_credits_balance_me_count" = "Your balance: {emoji} {amount}";
|
||||
"lng_credits_buy_button" = "Top Up Balance";
|
||||
"lng_credits_topup_button" = "{emoji} Top Up Balance";
|
||||
"lng_credits_buy_button_short" = "Top Up";
|
||||
"lng_credits_stats_button_short" = "Stats";
|
||||
"lng_credits_stats_button" = "View Statistics";
|
||||
"lng_credits_gift_button" = "Gift Stars to Friends";
|
||||
"lng_credits_earn_button" = "Earn Stars from Mini Apps";
|
||||
"lng_credits_box_out_title" = "Confirm Your Purchase";
|
||||
"lng_credits_box_out_sure#one" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Star**?";
|
||||
"lng_credits_box_out_sure#other" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Stars**?";
|
||||
@@ -2803,6 +2888,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_credits_box_history_entry_gift_converted" = "Converted Gift";
|
||||
"lng_credits_box_history_entry_gift_transfer" = "Gift Transfer";
|
||||
"lng_credits_box_history_entry_gift_unavailable" = "Unavailable";
|
||||
"lng_credits_box_history_entry_gift_released" = "released by {name}";
|
||||
"lng_credits_box_history_entry_gift_sold_out" = "This gift has sold out";
|
||||
"lng_credits_box_history_entry_gift_out_about" = "With Stars, **{user}** will be able to unlock content and services on Telegram.\n{link}";
|
||||
"lng_credits_box_history_entry_gift_in_about" = "Use Stars to unlock content and services on Telegram. {link}";
|
||||
@@ -2810,6 +2896,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_credits_box_history_entry_gift_examples" = "Examples";
|
||||
"lng_credits_box_history_entry_ads" = "Ads Platform";
|
||||
"lng_credits_box_history_entry_premium_bot" = "Stars Top-Up";
|
||||
"lng_credits_box_history_entry_currency_in" = "TON Top-Up";
|
||||
"lng_credits_box_history_entry_api" = "Paid Broadcast";
|
||||
"lng_credits_box_history_entry_floodskip_about#one" = "{count} Message";
|
||||
"lng_credits_box_history_entry_floodskip_about#other" = "{count} Messages";
|
||||
@@ -2873,6 +2960,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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_for_suggest" = "Buy **Stars** to suggest post to {channel}.";
|
||||
"lng_credits_small_balance_for_search" = "Buy **Stars** to search through public posts.";
|
||||
"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_enough" = "You have enough stars at the moment. {link}";
|
||||
@@ -3196,6 +3285,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_feature_transcribe" = "Voice-to-Text Conversion";
|
||||
"lng_feature_autotranslate" = "Autotranslation of Messages";
|
||||
|
||||
"lng_edit_topics_enable" = "Enable Topics";
|
||||
"lng_edit_topics_about" = "The group chat will be divided into topics created by admins or users.";
|
||||
"lng_edit_topics_layout" = "Topics layout";
|
||||
"lng_edit_topics_layout_about" = "Choose how topics appear for all members.";
|
||||
"lng_edit_topics_tabs" = "Tabs";
|
||||
"lng_edit_topics_list" = "List";
|
||||
|
||||
"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_group" = "Get more boosts for your group by gifting Premium to your members.";
|
||||
@@ -3432,6 +3528,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_stars_incoming" = "Use Stars to unlock content and services on Telegram.";
|
||||
"lng_gift_until" = "Until";
|
||||
|
||||
"lng_gift_ton_amount#one" = "{count} TON";
|
||||
"lng_gift_ton_amount#other" = "{count} TON";
|
||||
|
||||
"lng_gift_premium_title" = "Premium Gift";
|
||||
"lng_gift_premium_text#one" = "Subscribe to **Telegram Premium** to send up to **{count}** of these gifts and unlock access to multiple additional features.";
|
||||
"lng_gift_premium_text#other" = "Subscribe to **Telegram Premium** to send up to **{count}** of these gifts and unlock access to multiple additional features.";
|
||||
"lng_gift_premium_or_stars" = "Gift Premium or Stars";
|
||||
"lng_gift_premium_subtitle" = "Gift Premium";
|
||||
"lng_gift_premium_about" = "Give {name} access to exclusive features with Telegram Premium. {features}";
|
||||
@@ -3445,6 +3547,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_stars_sold_out" = "sold out";
|
||||
"lng_gift_stars_resale" = "resale";
|
||||
"lng_gift_stars_on_sale" = "on sale";
|
||||
"lng_gift_stars_premium" = "premium";
|
||||
"lng_gift_stars_tabs_all" = "All Gifts";
|
||||
"lng_gift_stars_tabs_my" = "My Gifts";
|
||||
"lng_gift_stars_tabs_limited" = "Limited";
|
||||
@@ -3473,6 +3576,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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_equals" = "Equals to {cost}";
|
||||
"lng_gift_buy_resale_only_ton" = "The seller only accepts TON as payment.";
|
||||
"lng_gift_buy_resale_pay_stars" = "Pay in Stars";
|
||||
"lng_gift_buy_resale_pay_ton" = "Pay in TON";
|
||||
"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!";
|
||||
@@ -3482,6 +3589,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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#other" = "You spent **{count}** Stars from your balance.";
|
||||
"lng_gift_sent_finished#one" = "You've already sent **{count}** of these gifts, and it's the limit.";
|
||||
"lng_gift_sent_finished#other" = "You've already sent **{count}** of these gifts, and it's the limit.";
|
||||
"lng_gift_sent_remains#one" = "You can send **{count}** more.";
|
||||
"lng_gift_sent_remains#other" = "You can send **{count}** more.";
|
||||
"lng_gift_limited_of_one" = "unique";
|
||||
"lng_gift_limited_of_count" = "1 of {amount}";
|
||||
"lng_gift_collectible_tag" = "gift";
|
||||
@@ -3509,12 +3620,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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_channel_title" = "Send a Gift";
|
||||
"lng_gift_channel_about" = "Select a gift to show appreciation for {name}.";
|
||||
"lng_gift_released_by" = "Released by {name}";
|
||||
"lng_gift_unique_owner" = "Owner";
|
||||
"lng_gift_unique_address_copied" = "Address copied to clipboard.";
|
||||
"lng_gift_unique_status" = "Status";
|
||||
"lng_gift_unique_status_non" = "Non-Unique";
|
||||
"lng_gift_unique_status_upgrade" = "upgrade";
|
||||
"lng_gift_unique_number" = "Collectible #{index}";
|
||||
"lng_gift_unique_number_by" = "Collectible #{index} by {name}";
|
||||
"lng_gift_unique_model" = "Model";
|
||||
"lng_gift_unique_backdrop" = "Backdrop";
|
||||
"lng_gift_unique_symbol" = "Symbol";
|
||||
@@ -3612,12 +3725,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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_only_ton" = "Only Accept TON";
|
||||
"lng_gift_sell_only_ton_about" = "If the buyer pays you in TON, there's no risk of refunds, unlike Stars payments.";
|
||||
"lng_gift_sell_amount_ton#one" = "You will receive **{count}** TON.";
|
||||
"lng_gift_sell_amount_ton#other" = "You will receive **{count}** TON.";
|
||||
"lng_gift_sell_min_price_ton#one" = "Minimum price is {count} TON.";
|
||||
"lng_gift_sell_min_price_ton#other" = "Minimum price is {count} TON.";
|
||||
"lng_gift_sell_title_ton" = "Price in TON";
|
||||
"lng_gift_sell_put" = "Put for Sale";
|
||||
"lng_gift_sell_update" = "Update the Price";
|
||||
"lng_gift_sell_toast" = "{name} is now for sale!";
|
||||
@@ -3657,9 +3776,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_resale_symbol" = "Symbol";
|
||||
"lng_gift_resale_symbols#one" = "{count} Symbol";
|
||||
"lng_gift_resale_symbols#other" = "{count} Symbols";
|
||||
"lng_gift_resale_switch_to" = "Switch to {currency}";
|
||||
"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_gift_collection_add" = "Add Collection";
|
||||
"lng_gift_collection_new_title" = "Create a New Collection";
|
||||
"lng_gift_collection_new_button" = "New Collection";
|
||||
"lng_gift_collection_new_text" = "Choose a name for your collection and start adding your gifts there.";
|
||||
"lng_gift_collection_new_ph" = "Title";
|
||||
"lng_gift_collection_new_create" = "Create";
|
||||
"lng_gift_collection_empty_title" = "Organize Your Gifts";
|
||||
"lng_gift_collection_empty_text" = "Add some of your gifts to this collection.";
|
||||
"lng_gift_collection_all" = "All Gifts";
|
||||
"lng_gift_collection_add_title" = "Add Gifts";
|
||||
"lng_gift_collection_share" = "Share Collection";
|
||||
"lng_gift_collection_edit" = "Edit Name";
|
||||
"lng_gift_collection_limit_title" = "Limit Reached";
|
||||
"lng_gift_collection_limit_text" = "Please remove one of the existing collections to add a new one.";
|
||||
"lng_gift_collection_delete" = "Delete Collection";
|
||||
"lng_gift_collection_delete_sure" = "Are you sure you want to delete this collection?";
|
||||
"lng_gift_collection_delete_button" = "Delete";
|
||||
"lng_gift_collection_add_to" = "Add to Collection";
|
||||
|
||||
"lng_accounts_limit_title" = "Limit Reached";
|
||||
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected account.";
|
||||
@@ -3758,6 +3896,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_in_dlg_sticker_emoji" = "{emoji} Sticker";
|
||||
"lng_in_dlg_poll" = "Poll";
|
||||
"lng_in_dlg_story" = "Story";
|
||||
"lng_in_dlg_todo_list" = "Checklist";
|
||||
"lng_in_dlg_story_expired" = "Expired story";
|
||||
"lng_in_dlg_media_count#one" = "{count} media";
|
||||
"lng_in_dlg_media_count#other" = "{count} media";
|
||||
@@ -3847,7 +3986,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_send_anonymous_ph" = "Send anonymously...";
|
||||
"lng_story_reply_ph" = "Reply privately...";
|
||||
"lng_story_comment_ph" = "Comment story...";
|
||||
"lng_message_paid_ph" = "Message for {amount}";
|
||||
"lng_message_stars_ph#one" = "Message for {count} Star";
|
||||
"lng_message_stars_ph#other" = "Message for {count} Stars";
|
||||
"lng_send_text_no" = "Text not allowed.";
|
||||
"lng_send_text_no_about" = "The admins of this group only allow sending {types}.";
|
||||
"lng_send_text_type_and_last" = "{types} and {last}";
|
||||
@@ -4183,9 +4323,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_to_msg" = "Go To Message";
|
||||
"lng_context_reply_msg" = "Reply";
|
||||
"lng_context_quote_and_reply" = "Quote & Reply";
|
||||
"lng_context_reply_to_task" = "Reply to Task";
|
||||
"lng_context_edit_msg" = "Edit";
|
||||
"lng_context_add_factcheck" = "Add Fact Check";
|
||||
"lng_context_edit_factcheck" = "Edit Fact Check";
|
||||
"lng_context_add_offer" = "Add Offer";
|
||||
"lng_context_forward_msg" = "Forward";
|
||||
"lng_context_send_now_msg" = "Send Now";
|
||||
"lng_context_reschedule" = "Reschedule";
|
||||
@@ -4197,6 +4339,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_pin_msg" = "Pin";
|
||||
"lng_context_unpin_msg" = "Unpin";
|
||||
"lng_context_cancel_upload" = "Cancel Upload";
|
||||
"lng_context_upload_edit_caption" = "Edit Caption";
|
||||
"lng_context_copy_selected" = "Copy Selected Text";
|
||||
"lng_context_copy_selected_items" = "Copy Selected as Text";
|
||||
"lng_context_forward_selected" = "Forward Selected";
|
||||
@@ -4220,6 +4363,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_seen_reacted#other" = "{count} Reacted";
|
||||
"lng_context_seen_reacted_none" = "Nobody Reacted";
|
||||
"lng_context_seen_reacted_all" = "Show All Reactions";
|
||||
"lng_context_sent_by" = "Sent by {user}";
|
||||
"lng_context_set_as_quick" = "Set As Quick";
|
||||
"lng_context_filter_by_tag" = "Filter by Tag";
|
||||
"lng_context_tag_add_name" = "Add Name";
|
||||
@@ -4235,6 +4379,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_edit_shortcut" = "Edit Shortcut";
|
||||
"lng_context_delete_shortcut" = "Delete Quick Reply";
|
||||
"lng_context_gift_send" = "Send Another Gift";
|
||||
"lng_context_charge_fee" = "Charge Fee";
|
||||
"lng_context_remove_fee" = "Remove Fee";
|
||||
"lng_context_fee_now" = "{name} pays {amount} per message.";
|
||||
"lng_context_fee_free" = "{name} can send messages for free.";
|
||||
|
||||
"lng_add_tag_about" = "Tag this message with an emoji for quick search.";
|
||||
"lng_subscribe_tag_about" = "Organize your Saved Messages with tags. {link}";
|
||||
@@ -4366,6 +4514,114 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_inline_switch_cant" = "Sorry, no way to write here :(";
|
||||
"lng_preview_reply_to" = "Reply to {name}";
|
||||
"lng_preview_reply_to_quote" = "Reply to quote from {name}";
|
||||
"lng_preview_reply_to_task" = "Reply to task from {title}";
|
||||
|
||||
"lng_suggest_bar_title" = "Suggest a Post Below";
|
||||
"lng_suggest_bar_text" = "Click to offer a price for publishing.";
|
||||
"lng_suggest_bar_priced" = "{amount} for publishing anytime.";
|
||||
"lng_suggest_bar_dated" = "Publish on {date}";
|
||||
"lng_suggest_options_title" = "Suggest a Message";
|
||||
"lng_suggest_options_change" = "Suggest Changes";
|
||||
"lng_suggest_options_stars_offer" = "Offer Stars";
|
||||
"lng_suggest_options_stars_request" = "Request Stars";
|
||||
"lng_suggest_options_stars_price" = "Enter Price in Stars";
|
||||
"lng_suggest_options_stars_price_about" = "Choose how many Stars to pay to publish this message.";
|
||||
"lng_suggest_options_ton_offer" = "Offer TON";
|
||||
"lng_suggest_options_ton_request" = "Request TON";
|
||||
"lng_suggest_options_ton_price" = "Enter Price in TON";
|
||||
"lng_suggest_options_ton_price_about" = "Choose how many TON to pay to publish this message.";
|
||||
"lng_suggest_options_date" = "Time";
|
||||
"lng_suggest_options_date_any" = "Anytime";
|
||||
"lng_suggest_options_date_publish" = "Publish";
|
||||
"lng_suggest_options_date_now" = "Publish Now";
|
||||
"lng_suggest_options_date_about" = "Select the date and time you want the message to be published. The post will remain available for at least 24 hours from this date.";
|
||||
"lng_suggest_options_you_get_stars#one" = "You will receive {count} Star ({percent}) for publishing this post.";
|
||||
"lng_suggest_options_you_get_stars#other" = "You will receive {count} Stars ({percent}) for publishing this post.";
|
||||
"lng_suggest_options_you_get_ton#one" = "You will receive {count} TON ({percent}) for publishing this post.";
|
||||
"lng_suggest_options_you_get_ton#other" = "You will receive {count} TON ({percent}) for publishing this post.";
|
||||
"lng_suggest_options_stars_warning" = "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust.";
|
||||
"lng_suggest_options_offer" = "Offer {amount}";
|
||||
"lng_suggest_options_offer_free" = "Offer for Free";
|
||||
"lng_suggest_options_update" = "Update Terms";
|
||||
"lng_suggest_options_update_date" = "Update Time";
|
||||
|
||||
"lng_suggest_action_decline" = "Decline";
|
||||
"lng_suggest_action_accept" = "Accept";
|
||||
"lng_suggest_action_change" = "Suggest Changes";
|
||||
"lng_suggest_action_your" = "You suggest to post this message.";
|
||||
"lng_suggest_action_his" = "{from} suggests to post this message.";
|
||||
"lng_suggest_action_price_label" = "Price";
|
||||
"lng_suggest_action_price_free" = "Free";
|
||||
"lng_suggest_action_time_label" = "Time";
|
||||
"lng_suggest_action_time_any" = "Anytime";
|
||||
"lng_suggest_action_agreement" = "Agreement reached!";
|
||||
"lng_suggest_action_agree_date" = "The post will be automatically published on {channel} {date}.";
|
||||
"lng_suggest_action_your_charged_stars#one" = "You have been charged **{count} Star**.";
|
||||
"lng_suggest_action_your_charged_stars#other" = "You have been charged **{count} Stars**.";
|
||||
"lng_suggest_action_your_charged_ton#one" = "You have been charged **{count} TON**.";
|
||||
"lng_suggest_action_your_charged_ton#other" = "You have been charged **{count} TON**.";
|
||||
"lng_suggest_action_his_charged_stars#one" = "{from} has been charged **{count} Star**.";
|
||||
"lng_suggest_action_his_charged_stars#other" = "{from} has been charged **{count} Stars**.";
|
||||
"lng_suggest_action_his_charged_ton#one" = "{from} has been charged **{count} TON**.";
|
||||
"lng_suggest_action_his_charged_ton#other" = "{from} has been charged **{count} TON**.";
|
||||
"lng_suggest_action_agree_receive_stars" = "{channel} will receive the Stars once the post has been live for 24 hours.";
|
||||
"lng_suggest_action_agree_receive_ton" = "{channel} will receive TON once the post has been live for 24 hours.";
|
||||
"lng_suggest_action_agree_removed_stars" = "If {channel} removes the post before it has been live for 24 hours, the Stars will be refunded.";
|
||||
"lng_suggest_action_agree_removed_ton" = "If {channel} removes the post before it has been live for 24 hours, TON will be refunded.";
|
||||
"lng_suggest_action_your_not_enough_stars" = "**Transaction failed** because you didn't have enough Stars.";
|
||||
"lng_suggest_action_your_not_enough_ton" = "**Transaction failed** because you didn't have enough TON.";
|
||||
"lng_suggest_action_his_not_enough_stars" = "**Transaction failed** because the user didn't have enough Stars.";
|
||||
"lng_suggest_action_his_not_enough_ton" = "**Transaction failed** because the user didn't have enough TON.";
|
||||
"lng_suggest_action_declined" = "{from} rejected the message.";
|
||||
"lng_suggest_action_declined_reason" = "{from} rejected the message with the comment.";
|
||||
"lng_suggest_change_price" = "{from} suggests a new price for the message.";
|
||||
"lng_suggest_change_time" = "{from} suggests a new time for the message.";
|
||||
"lng_suggest_change_price_time" = "{from} suggests a new price and time for the message.";
|
||||
"lng_suggest_change_content" = "{from} suggests changes for the message.";
|
||||
"lng_suggest_change_price_label" = "New Price";
|
||||
"lng_suggest_change_time_label" = "New Time";
|
||||
"lng_suggest_change_text_label" = "Check the suggested message below";
|
||||
"lng_suggest_menu_edit_message" = "Edit Message";
|
||||
"lng_suggest_menu_edit_price" = "Edit Price";
|
||||
"lng_suggest_menu_edit_time" = "Edit Time";
|
||||
"lng_suggest_decline_title" = "Decline";
|
||||
"lng_suggest_decline_text" = "Do you want to decline publishing this post from {from}?";
|
||||
"lng_suggest_decline_text_to" = "Do you want to decline publishing this post to {channel}?";
|
||||
"lng_suggest_decline_reason" = "Add a reason (optional)";
|
||||
"lng_suggest_accept_title" = "Accept Terms";
|
||||
"lng_suggest_accept_text" = "Do you want to publish this post from {from}?";
|
||||
"lng_suggest_accept_text_to" = "Do you want to publish this post to {channel}?";
|
||||
"lng_suggest_accept_receive_stars#one" = "{channel} will receive **{count} Star** ({percent}) for publishing {date}.";
|
||||
"lng_suggest_accept_receive_stars#other" = "{channel} will receive **{count} Stars** ({percent}) for publishing {date}.";
|
||||
"lng_suggest_accept_receive_ton#one" = "{channel} will receive **{count} TON** ({percent}) for publishing {date}.";
|
||||
"lng_suggest_accept_receive_ton#other" = "{channel} will receive **{count} TON** ({percent}) for publishing {date}.";
|
||||
"lng_suggest_accept_receive_now_stars#one" = "{channel} will receive **{count} Star** ({percent}) for publishing right now.";
|
||||
"lng_suggest_accept_receive_now_stars#other" = "{channel} will receive **{count} Stars** ({percent}) for publishing right now.";
|
||||
"lng_suggest_accept_receive_now_ton#one" = "{channel} will receive **{count} TON** ({percent}) for publishing right now.";
|
||||
"lng_suggest_accept_receive_now_ton#other" = "{channel} will receive **{count} TON** ({percent}) for publishing right now.";
|
||||
"lng_suggest_accept_receive_if" = "It must remain visible for at least **24** hours after publication.";
|
||||
"lng_suggest_accept_pay_stars#one" = "You will pay **{count} Star** for publishing {date}.";
|
||||
"lng_suggest_accept_pay_stars#other" = "You will pay **{count} Stars** for publishing {date}.";
|
||||
"lng_suggest_accept_pay_ton#one" = "You will pay **{count} TON** for publishing {date}.";
|
||||
"lng_suggest_accept_pay_ton#other" = "You will pay **{count} TON** for publishing {date}.";
|
||||
"lng_suggest_accept_pay_now_stars#one" = "You will pay **{count} Star** for publishing right now.";
|
||||
"lng_suggest_accept_pay_now_stars#other" = "You will pay **{count} Stars** for publishing right now.";
|
||||
"lng_suggest_accept_pay_now_ton#one" = "You will pay **{count} TON** for publishing right now.";
|
||||
"lng_suggest_accept_pay_now_ton#other" = "You will pay **{count} TON** for publishing right now.";
|
||||
"lng_suggest_accept_send" = "Publish";
|
||||
"lng_suggest_stars_amount#one" = "{count} Star";
|
||||
"lng_suggest_stars_amount#other" = "{count} Stars";
|
||||
"lng_suggest_ton_amount#one" = "{count} TON";
|
||||
"lng_suggest_ton_amount#other" = "{count} TON";
|
||||
"lng_suggest_warn_title_stars" = "Stars will be lost";
|
||||
"lng_suggest_warn_title_ton" = "TON will be lost";
|
||||
"lng_suggest_warn_text_stars" = "You won't receive **Stars** for the post if you delete it now. The post must remain visible for at least **24 hours** after it was published.";
|
||||
"lng_suggest_warn_text_ton" = "You won't receive **TON** for the post if you delete it now. The post must remain visible for at least **24 hours** after it was published.";
|
||||
"lng_suggest_warn_delete_anyway" = "Delete Anyway";
|
||||
"lng_suggest_low_ton_title" = "{amount} TON Needed";
|
||||
"lng_suggest_low_ton_text" = "You can add funds to your balance via the third-party platform Fragment.";
|
||||
"lng_suggest_low_ton_fragment" = "Add Funds via Fragment";
|
||||
"lng_suggest_low_ton_fragment_url" = "https://fragment.com/ads/topup";
|
||||
|
||||
"lng_reply_in_another_title" = "Reply in...";
|
||||
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
||||
@@ -5130,6 +5386,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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_channel" = "Do you want to allow {name} to message the channel 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";
|
||||
@@ -5159,6 +5416,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_channel_edit_stories" = "Edit stories of others";
|
||||
"lng_rights_channel_delete_stories" = "Delete stories of others";
|
||||
"lng_rights_channel_manage_calls" = "Manage live streams";
|
||||
"lng_rights_channel_manage_direct" = "Manage direct messages";
|
||||
"lng_rights_group_info" = "Change group info";
|
||||
"lng_rights_group_ban" = "Ban users";
|
||||
"lng_rights_group_invite_link" = "Invite users via link";
|
||||
@@ -5251,6 +5509,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_restricted_send_polls_all" = "Sorry, sending polls is not allowed in this group.";
|
||||
|
||||
"lng_restricted_send_public_polls" = "Sorry, polls with visible votes can't be forwarded to channels.";
|
||||
"lng_restricted_send_todo_lists" = "Sorry, Checklists can't be forwarded to channels.";
|
||||
"lng_restricted_send_paid_media" = "Sorry, paid media can't be sent to this channel.";
|
||||
|
||||
"lng_restricted_send_voice_messages" = "{user} doesn't accept voice messages.";
|
||||
@@ -5265,6 +5524,8 @@ 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_link" = "Telegram Premium";
|
||||
|
||||
"lng_send_charges_stars_channel" = "{channel} charges {amount} per message to its admin.";
|
||||
"lng_send_free_channel" = "Send a direct message to the administrator of {channel}.";
|
||||
"lng_send_charges_stars_text" = "{user} charges {amount} for each message.";
|
||||
"lng_send_charges_stars_go" = "Buy Stars";
|
||||
|
||||
@@ -5480,6 +5741,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_admin_create_topics" = "Create topics";
|
||||
"lng_admin_log_admin_manage_calls" = "Manage video chats";
|
||||
"lng_admin_log_admin_manage_calls_channel" = "Manage live streams";
|
||||
"lng_admin_log_admin_manage_direct" = "Manage direct messages";
|
||||
"lng_admin_log_admin_add_admins" = "Add new admins";
|
||||
"lng_admin_log_subscription_extend" = "{name} renewed subscription until {date}";
|
||||
|
||||
@@ -5779,6 +6041,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_polls_stop" = "Stop poll";
|
||||
"lng_polls_stop_warning" = "If you stop this poll now, nobody will be able to vote in it anymore. This action cannot be undone.";
|
||||
"lng_polls_stop_sure" = "Stop";
|
||||
"lng_polls_menu_item" = "Poll";
|
||||
"lng_polls_create" = "Create poll";
|
||||
"lng_polls_create_title" = "New poll";
|
||||
"lng_polls_create_question" = "Question";
|
||||
@@ -5807,6 +6070,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_polls_show_more#other" = "Show more ({count})";
|
||||
"lng_polls_votes_collapse" = "Collapse";
|
||||
|
||||
"lng_todo_title" = "Checklist";
|
||||
"lng_todo_title_group" = "Group Checklist";
|
||||
"lng_todo_completed#one" = "{count} of {total} completed";
|
||||
"lng_todo_completed#other" = "{count} of {total} completed";
|
||||
"lng_todo_completed_none" = "None of {total} completed";
|
||||
"lng_todo_menu_item" = "Checklist";
|
||||
"lng_todo_create" = "Create Checklist";
|
||||
"lng_todo_create_title" = "New Checklist";
|
||||
"lng_todo_create_title_placeholder" = "Title";
|
||||
"lng_todo_create_list" = "Tasks List";
|
||||
"lng_todo_create_list_add" = "Add a task...";
|
||||
"lng_todo_create_limit#one" = "You can add {count} more task.";
|
||||
"lng_todo_create_limit#other" = "You can add {count} more tasks.";
|
||||
"lng_todo_create_maximum" = "You have added the maximum number of tasks.";
|
||||
"lng_todo_create_settings" = "Settings";
|
||||
"lng_todo_create_allow_add" = "Allow Others to Add Tasks";
|
||||
"lng_todo_create_allow_mark" = "Allow Others to Mark As Done";
|
||||
"lng_todo_create_button" = "Create";
|
||||
"lng_todo_choose_title" = "Please enter a title.";
|
||||
"lng_todo_choose_tasks" = "Please enter at least one task.";
|
||||
|
||||
"lng_todo_add_title" = "Add Tasks";
|
||||
"lng_todo_create_premium" = "Only subscribers of {link} can create Checklists.";
|
||||
"lng_todo_add_premium" = "Only subscribers of {link} can add tasks.";
|
||||
"lng_todo_mark_premium" = "Only subscribers of {link} can mark tasks as done.";
|
||||
"lng_todo_premium_link" = "Telegram Premium";
|
||||
"lng_todo_mark_restricted" = "{user} has restricted others from marking tasks as done.";
|
||||
"lng_todo_mark_forwarded" = "You can't change forwarded checklists.";
|
||||
|
||||
"lng_outdated_title" = "PLEASE UPDATE YOUR OPERATING SYSTEM.";
|
||||
"lng_outdated_title_bits" = "PLEASE SWITCH TO A 64-BIT OPERATING SYSTEM.";
|
||||
"lng_outdated_soon" = "Otherwise, Telegram Desktop will stop updating on {date}.";
|
||||
@@ -5992,6 +6284,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_view_button_emojipack" = "View emoji";
|
||||
"lng_view_button_collectible" = "View collectible";
|
||||
"lng_view_button_call" = "Join call";
|
||||
"lng_view_button_storyalbum" = "View Album";
|
||||
"lng_view_button_collection" = "View Collection";
|
||||
|
||||
"lng_sponsored_hide_ads" = "Hide";
|
||||
"lng_sponsored_title" = "What are sponsored messages?";
|
||||
@@ -6071,6 +6365,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_forum_messages#other" = "{count} messages";
|
||||
"lng_forum_show_topics_list" = "Show Topics List";
|
||||
|
||||
"lng_monoforum_choose_to_reply" = "Choose a message to reply.";
|
||||
|
||||
"lng_request_peer_requirements" = "Requirements";
|
||||
"lng_request_peer_rights" = "You must have these admin rights: {rights}.";
|
||||
"lng_request_peer_rights_and" = "{rights} and {last}";
|
||||
@@ -6117,6 +6413,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_request_channel_delete_messages" = "delete messages";
|
||||
"lng_request_channel_add_subscribers" = "add subscribers";
|
||||
"lng_request_channel_manage_livestreams" = "manage live streams";
|
||||
"lng_request_channel_manage_direct" = "manage direct messages";
|
||||
"lng_request_channel_add_admins" = "add new admins";
|
||||
"lng_request_channel_create" = "Create a New Channel for This";
|
||||
|
||||
@@ -6153,6 +6450,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stories_archive_title" = "Story Archive";
|
||||
"lng_stories_archive_about" = "Only you can see archived stories unless you choose to post them to your profile.";
|
||||
"lng_stories_channel_archive_about" = "Only admins of the channel can see archived stories unless they are posted to the channel page.";
|
||||
"lng_stories_empty" = "Your stories will be here.";
|
||||
"lng_stories_empty_channel" = "Channel posts will be here.";
|
||||
"lng_stories_reply_sent" = "Message sent.";
|
||||
"lng_stories_hidden_to_contacts" = "Stories from {user} were moved to the **Archive**.";
|
||||
"lng_stories_shown_in_chats" = "Stories from {user} were returned from the **Archive**.";
|
||||
@@ -6188,6 +6487,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stories_save_promo" = "Subscribe to {link} to save other people's stories that are not protected.";
|
||||
"lng_stories_reaction_as_message" = "Send reaction as a private message";
|
||||
|
||||
"lng_stories_album_add" = "Add Album";
|
||||
"lng_stories_album_new_title" = "Create a New Album";
|
||||
"lng_stories_album_new_button" = "New Album";
|
||||
"lng_stories_album_new_text" = "Choose a name for your album and start adding your stories there.";
|
||||
"lng_stories_album_new_ph" = "Title";
|
||||
"lng_stories_album_new_create" = "Create";
|
||||
"lng_stories_album_empty_title" = "Organize Your Stories";
|
||||
"lng_stories_album_empty_text" = "Add some of your stories to this album.";
|
||||
"lng_stories_album_all" = "All Stories";
|
||||
"lng_stories_album_add_title" = "Add Stories";
|
||||
"lng_stories_album_share" = "Share Album";
|
||||
"lng_stories_album_edit" = "Edit Name";
|
||||
"lng_stories_album_limit_title" = "Limit Reached";
|
||||
"lng_stories_album_limit_text" = "Please remove one of the existing albums to add a new one.";
|
||||
"lng_stories_album_delete" = "Delete Album";
|
||||
"lng_stories_album_delete_sure" = "Are you sure you want to delete this album?";
|
||||
"lng_stories_album_delete_button" = "Delete";
|
||||
"lng_stories_album_add_to" = "Add to Album";
|
||||
|
||||
"lng_stealth_mode_menu_item" = "Hide My View";
|
||||
"lng_stealth_mode_title" = "Stealth Mode";
|
||||
"lng_stealth_mode_unlock_about" = "Subscribe to Telegram Premium to watch stories without appearing in the list of viewers.";
|
||||
@@ -6394,7 +6712,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_bot_earn_balance_button_locked" = "Withdraw";
|
||||
"lng_bot_earn_balance_button_buy_ads" = "Buy Ads";
|
||||
"lng_bot_earn_learn_credits_out_about" = "You can withdraw Stars using Fragment, or use Stars to advertise your bot. {link}";
|
||||
"lng_self_earn_learn_credits_out_about" = "You can withdraw from 10 Stars using Fragment. {link}";
|
||||
"lng_bot_earn_out_ph" = "Enter amount to withdraw";
|
||||
"lng_bot_earn_out_ph_max" = "Enter amount to withdraw (max. {amount})";
|
||||
"lng_bot_earn_balance_password_title" = "Two-step verification";
|
||||
"lng_bot_earn_balance_password_description" = "Please enter your password to collect.";
|
||||
"lng_bot_earn_credits_out_minimal" = "You cannot withdraw less than {link}.";
|
||||
@@ -6442,6 +6762,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_recent_chats" = "Chats";
|
||||
"lng_recent_channels" = "Channels";
|
||||
"lng_recent_apps" = "Apps";
|
||||
"lng_recent_posts" = "Posts";
|
||||
"lng_all_photos" = "Photos";
|
||||
"lng_all_videos" = "Videos";
|
||||
"lng_all_downloads" = "Downloads";
|
||||
@@ -6459,6 +6780,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_bot_apps_popular" = "Grossing apps";
|
||||
"lng_bot_apps_which" = "Which apps are included here? {link}";
|
||||
"lng_bot_apps_which_link" = "Learn >";
|
||||
"lng_posts_title" = "Global Search";
|
||||
"lng_posts_start" = "Type a keyword to search all posts from public channels.";
|
||||
"lng_posts_subscribe" = "Subscribe to Premium";
|
||||
"lng_posts_need_subscribe" = "Global search is a Premium feature.";
|
||||
"lng_posts_search_button" = "Search {query}";
|
||||
"lng_posts_remaining#one" = "{count} free search remaining today";
|
||||
"lng_posts_remaining#other" = "{count} free searches remaining today";
|
||||
"lng_posts_subtitle_empty" = "Telegram News";
|
||||
"lng_posts_subtitle" = "Public posts";
|
||||
"lng_posts_limit_reached" = "Limit Reached";
|
||||
"lng_posts_limit_about#one" = "You can make up to {count} search query per day.";
|
||||
"lng_posts_limit_about#other" = "You can make up to {count} search queries per day.";
|
||||
"lng_posts_limit_search_paid" = "Search for {cost}";
|
||||
"lng_posts_limit_unlocks" = "free search unlocks in {duration}";
|
||||
"lng_posts_paid_spent#one" = "**{count} Star** spent on extra search.";
|
||||
"lng_posts_paid_spent#other" = "**{count} Stars** spent on extra search.";
|
||||
|
||||
"lng_popular_apps_info_title" = "Top Mini Apps";
|
||||
"lng_popular_apps_info_text" = "This catalogue ranks mini apps based on their daily revenue, measured in Stars. To be listed, developers must set their main mini apps in {bot} (as described {link}), have over **1,000** daily users, and earn a daily revenue above **1,000** Stars, based on the weekly average.";
|
||||
@@ -6519,6 +6856,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_frozen_text3" = "Appeal via {link} before {date}, or your account will be deleted.";
|
||||
"lng_frozen_appeal_button" = "Submit an Appeal";
|
||||
|
||||
"lng_age_verify_title" = "Age Verification";
|
||||
"lng_age_verify_mobile" = "Please open this media in the official Telegram app for Android or iOS to verify your age.";
|
||||
"lng_age_verify_here" = "This is a one-time process using your phone's camera. Your selfie will not be stored by Telegram.";
|
||||
"lng_age_verify_button" = "Verify My Age";
|
||||
"lng_age_verify_sorry_title" = "Age Check Failed";
|
||||
"lng_age_verify_sorry_text" = "Sorry, you can't view 18+ content.";
|
||||
|
||||
"lng_context_bank_card_copy" = "Copy Card Number";
|
||||
"lng_context_bank_card_copied" = "Card number copied to clipboard.";
|
||||
|
||||
@@ -6576,6 +6920,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_mac_menu_new_channel" = "New Channel";
|
||||
"lng_mac_menu_show" = "Show Telegram";
|
||||
"lng_mac_menu_emoji_and_symbols" = "Emoji & Symbols";
|
||||
"lng_mac_menu_fullscreen" = "Toggle Full Screen";
|
||||
|
||||
"lng_mac_menu_player_pause" = "Pause";
|
||||
"lng_mac_menu_player_resume" = "Resume";
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<file alias="cloud_password/password_input.tgs">../../animations/cloud_password/password_input.tgs</file>
|
||||
<file alias="cloud_password/hint.tgs">../../animations/cloud_password/hint.tgs</file>
|
||||
<file alias="cloud_password/email.tgs">../../animations/cloud_password/email.tgs</file>
|
||||
<file alias="cloud_password/validate.tgs">../../animations/cloud_password/validate.tgs</file>
|
||||
<file alias="ttl.tgs">../../animations/ttl.tgs</file>
|
||||
<file alias="discussion.tgs">../../animations/discussion.tgs</file>
|
||||
<file alias="stats.tgs">../../animations/stats.tgs</file>
|
||||
@@ -25,6 +26,7 @@
|
||||
<file alias="hours.tgs">../../animations/hours.tgs</file>
|
||||
<file alias="phone.tgs">../../animations/phone.tgs</file>
|
||||
<file alias="chat_link.tgs">../../animations/chat_link.tgs</file>
|
||||
<file alias="diamond.tgs">../../animations/diamond.tgs</file>
|
||||
<file alias="collectible_username.tgs">../../animations/collectible_username.tgs</file>
|
||||
<file alias="collectible_phone.tgs">../../animations/collectible_phone.tgs</file>
|
||||
<file alias="search.tgs">../../animations/search.tgs</file>
|
||||
@@ -32,6 +34,11 @@
|
||||
<file alias="hello_status.tgs">../../animations/hello_status.tgs</file>
|
||||
<file alias="starref_link.tgs">../../animations/starref_link.tgs</file>
|
||||
<file alias="media_forbidden.tgs">../../animations/media_forbidden.tgs</file>
|
||||
<file alias="topics.tgs">../../animations/edit_peers/topics.tgs</file>
|
||||
<file alias="topics_tabs.tgs">../../animations/edit_peers/topics_tabs.tgs</file>
|
||||
<file alias="topics_list.tgs">../../animations/edit_peers/topics_list.tgs</file>
|
||||
<file alias="direct_messages.tgs">../../animations/edit_peers/direct_messages.tgs</file>
|
||||
<file alias="no_chats.tgs">../../animations/no_chats.tgs</file>
|
||||
|
||||
<file alias="dice_idle.tgs">../../animations/dice/dice_idle.tgs</file>
|
||||
<file alias="dart_idle.tgs">../../animations/dice/dart_idle.tgs</file>
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
<file alias="group_call_connect.mp3">../../sounds/group_call_connect.mp3</file>
|
||||
<file alias="group_call_end.mp3">../../sounds/group_call_end.mp3</file>
|
||||
<file alias="group_call_allowed.mp3">../../sounds/group_call_allowed.mp3</file>
|
||||
<file alias="group_call_recording_start.mp3">../../sounds/group_call_recording_start.mp3</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
BIN
Telegram/Resources/sounds/group_call_recording_start.mp3
Normal file
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="5.14.3.0" />
|
||||
Version="6.0.1.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,14,3,0
|
||||
PRODUCTVERSION 5,14,3,0
|
||||
FILEVERSION 6,0,1,0
|
||||
PRODUCTVERSION 6,0,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "5.14.3.0"
|
||||
VALUE "FileVersion", "6.0.1.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "5.14.3.0"
|
||||
VALUE "ProductVersion", "6.0.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,14,3,0
|
||||
PRODUCTVERSION 5,14,3,0
|
||||
FILEVERSION 6,0,1,0
|
||||
PRODUCTVERSION 6,0,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "5.14.3.0"
|
||||
VALUE "FileVersion", "6.0.1.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "5.14.3.0"
|
||||
VALUE "ProductVersion", "6.0.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -283,7 +283,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Compression start, size: " << resultSize << "\n";
|
||||
|
||||
QByteArray compressed, resultCheck;
|
||||
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined PACKER_USE_PACKAGED // use Lzma SDK for win
|
||||
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
|
||||
|
||||
compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size
|
||||
|
||||
@@ -27,7 +27,7 @@ extern "C" {
|
||||
#include <openssl/evp.h>
|
||||
} // extern "C"
|
||||
|
||||
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined PACKER_USE_PACKAGED // use Lzma SDK for win
|
||||
#include <LzmaLib.h>
|
||||
#else
|
||||
#include <lzma.h>
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "api/api_send_progress.h"
|
||||
#include "api/api_suggest_post.h"
|
||||
#include "boxes/share_box.h"
|
||||
#include "boxes/passcode_box.h"
|
||||
#include "boxes/url_auth_box.h"
|
||||
@@ -244,7 +245,7 @@ void SendBotCallbackDataWithPassword(
|
||||
fields.customSubmitButton = tr::lng_passcode_submit();
|
||||
fields.customCheckCallback = [=](
|
||||
const Core::CloudPasswordResult &result,
|
||||
QPointer<PasscodeBox> box) {
|
||||
base::weak_qptr<PasscodeBox> box) {
|
||||
if (const auto button = getButton()) {
|
||||
if (button->requestId) {
|
||||
return;
|
||||
@@ -399,10 +400,12 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
||||
}
|
||||
}
|
||||
const auto replyTo = FullReplyTo();
|
||||
const auto suggest = SuggestPostOptions();
|
||||
Window::PeerMenuCreatePoll(
|
||||
controller,
|
||||
item->history()->peer,
|
||||
replyTo,
|
||||
suggest,
|
||||
chosen,
|
||||
disabled);
|
||||
} break;
|
||||
@@ -519,6 +522,27 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
||||
controller->showToast(tr::lng_text_copied(tr::now));
|
||||
}
|
||||
} break;
|
||||
|
||||
case ButtonType::SuggestAccept: {
|
||||
Api::AcceptClickHandler(item)->onClick(ClickContext{
|
||||
Qt::LeftButton,
|
||||
QVariant::fromValue(context),
|
||||
});
|
||||
} break;
|
||||
|
||||
case ButtonType::SuggestDecline: {
|
||||
Api::DeclineClickHandler(item)->onClick(ClickContext{
|
||||
Qt::LeftButton,
|
||||
QVariant::fromValue(context),
|
||||
});
|
||||
} break;
|
||||
|
||||
case ButtonType::SuggestChange: {
|
||||
Api::SuggestChangesClickHandler(item)->onClick(ClickContext{
|
||||
Qt::LeftButton,
|
||||
QVariant::fromValue(context),
|
||||
});
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ void RemoveChatFilter(
|
||||
RemoveComplexChatFilter::RemoveComplexChatFilter() = default;
|
||||
|
||||
void RemoveComplexChatFilter::request(
|
||||
QPointer<Ui::RpWidget> widget,
|
||||
base::weak_qptr<Ui::RpWidget> widget,
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
FilterId id) {
|
||||
const auto session = &weak->session();
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
RemoveComplexChatFilter();
|
||||
|
||||
void request(
|
||||
QPointer<Ui::RpWidget> widget,
|
||||
base::weak_qptr<Ui::RpWidget> widget,
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
FilterId id);
|
||||
|
||||
|
||||
@@ -256,6 +256,7 @@ void ConfirmSubscriptionBox(
|
||||
{
|
||||
const auto balance = Settings::AddBalanceWidget(
|
||||
content,
|
||||
session,
|
||||
session->credits().balanceValue(),
|
||||
true);
|
||||
session->credits().load(true);
|
||||
@@ -271,7 +272,7 @@ void ConfirmSubscriptionBox(
|
||||
}, balance->lifetime());
|
||||
}
|
||||
|
||||
const auto sendCredits = [=, weak = Ui::MakeWeak(box)] {
|
||||
const auto sendCredits = [=, weak = base::make_weak(box)] {
|
||||
const auto show = box->uiShow();
|
||||
const auto buttonWidth = state->saveButton
|
||||
? state->saveButton->width()
|
||||
@@ -279,7 +280,7 @@ void ConfirmSubscriptionBox(
|
||||
const auto finish = [=] {
|
||||
state->api = std::nullopt;
|
||||
state->loading.force_assign(false);
|
||||
if (const auto strong = weak.data()) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
@@ -293,7 +294,7 @@ void ConfirmSubscriptionBox(
|
||||
}, [](const MTPDpayments_paymentVerificationNeeded &data) {
|
||||
});
|
||||
const auto refill = session->data().activeCreditsSubsRebuilder();
|
||||
const auto strong = weak.data();
|
||||
const auto strong = weak.get();
|
||||
if (!strong) {
|
||||
return;
|
||||
}
|
||||
@@ -436,6 +437,12 @@ void CheckChatInvite(
|
||||
}
|
||||
});
|
||||
}, [=](const MTP::Error &error) {
|
||||
if (MTP::IsFloodError(error)) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->show(Ui::MakeInformBox(tr::lng_flood_error()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (error.code() != 400) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class ChannelData;
|
||||
|
||||
namespace Info::Profile {
|
||||
class Badge;
|
||||
enum class BadgeType;
|
||||
enum class BadgeType : uchar;
|
||||
} // namespace Info::Profile
|
||||
|
||||
namespace Main {
|
||||
|
||||
@@ -494,8 +494,15 @@ void ChatParticipants::requestBots(not_null<ChannelData*> channel) {
|
||||
LOG(("API Error: "
|
||||
"channels.channelParticipantsNotModified received!"));
|
||||
});
|
||||
}).fail([=] {
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_botsRequests.remove(channel);
|
||||
if (error.type() == u"CHANNEL_MONOFORUM_UNSUPPORTED"_q) {
|
||||
channel->mgInfo->bots.clear();
|
||||
channel->mgInfo->botStatus = -1;
|
||||
channel->session().changes().peerUpdated(
|
||||
channel,
|
||||
Data::PeerUpdate::Flag::FullInfo);
|
||||
}
|
||||
}).send();
|
||||
|
||||
_botsRequests[channel] = requestId;
|
||||
@@ -648,10 +655,7 @@ void ChatParticipants::Restrict(
|
||||
channel->session().api().request(MTPchannels_EditBanned(
|
||||
channel->inputChannel,
|
||||
participant->input,
|
||||
MTP_chatBannedRights(
|
||||
MTP_flags(MTPDchatBannedRights::Flags::from_raw(
|
||||
uint32(newRights.flags))),
|
||||
MTP_int(newRights.until))
|
||||
RestrictionsToMTP(newRights)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
channel->session().api().applyUpdates(result);
|
||||
channel->applyEditBanned(participant, oldRights, newRights);
|
||||
@@ -756,10 +760,7 @@ void ChatParticipants::kick(
|
||||
const auto requestId = _api.request(MTPchannels_EditBanned(
|
||||
channel->inputChannel,
|
||||
participant->input,
|
||||
MTP_chatBannedRights(
|
||||
MTP_flags(
|
||||
MTPDchatBannedRights::Flags::from_raw(uint32(rights.flags))),
|
||||
MTP_int(rights.until))
|
||||
RestrictionsToMTP(rights)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
channel->session().api().applyUpdates(result);
|
||||
|
||||
|
||||
@@ -14,6 +14,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Api {
|
||||
|
||||
MTPSuggestedPost SuggestToMTP(SuggestPostOptions suggest) {
|
||||
using Flag = MTPDsuggestedPost::Flag;
|
||||
return suggest.exists
|
||||
? MTP_suggestedPost(
|
||||
MTP_flags((suggest.date ? Flag::f_schedule_date : Flag())
|
||||
| (suggest.price().empty() ? Flag() : Flag::f_price)),
|
||||
StarsAmountToTL(suggest.price()),
|
||||
MTP_int(suggest.date))
|
||||
: MTPSuggestedPost();
|
||||
}
|
||||
|
||||
SendAction::SendAction(
|
||||
not_null<Data::Thread*> thread,
|
||||
SendOptions options)
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace Api {
|
||||
|
||||
inline constexpr auto kScheduledUntilOnlineTimestamp = TimeId(0x7FFFFFFE);
|
||||
|
||||
[[nodiscard]] MTPSuggestedPost SuggestToMTP(SuggestPostOptions suggest);
|
||||
|
||||
struct SendOptions {
|
||||
uint64 price = 0;
|
||||
PeerData *sendAs = nullptr;
|
||||
@@ -31,6 +33,7 @@ struct SendOptions {
|
||||
bool invertCaption = false;
|
||||
bool hideViaBot = false;
|
||||
crl::time ttlSeconds = 0;
|
||||
SuggestPostOptions suggest;
|
||||
|
||||
friend inline bool operator==(
|
||||
const SendOptions &,
|
||||
|
||||
@@ -87,7 +87,7 @@ void ConfirmPhone::resolve(
|
||||
sentCodeLength,
|
||||
fragmentUrl,
|
||||
timeout);
|
||||
const auto boxWeak = Ui::MakeWeak(box.data());
|
||||
const auto boxWeak = base::make_weak(box.data());
|
||||
using LoginCode = rpl::event_stream<QString>;
|
||||
const auto codeHandles = box->lifetime().make_state<LoginCode>();
|
||||
controller->session().account().setHandleLoginCode([=](
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_credits.h"
|
||||
|
||||
#include "api/api_credits_history_entry.h"
|
||||
#include "api/api_premium.h"
|
||||
#include "api/api_statistics_data_deserialize.h"
|
||||
#include "api/api_updates.h"
|
||||
@@ -27,146 +28,6 @@ namespace {
|
||||
|
||||
constexpr auto kTransactionsLimit = 100;
|
||||
|
||||
[[nodiscard]] Data::CreditsHistoryEntry HistoryFromTL(
|
||||
const MTPStarsTransaction &tl,
|
||||
not_null<PeerData*> peer) {
|
||||
using HistoryPeerTL = MTPDstarsTransactionPeer;
|
||||
using namespace Data;
|
||||
const auto owner = &peer->owner();
|
||||
const auto photo = tl.data().vphoto()
|
||||
? owner->photoFromWeb(*tl.data().vphoto(), ImageLocation())
|
||||
: nullptr;
|
||||
auto extended = std::vector<CreditsHistoryMedia>();
|
||||
if (const auto list = tl.data().vextended_media()) {
|
||||
extended.reserve(list->v.size());
|
||||
for (const auto &media : list->v) {
|
||||
media.match([&](const MTPDmessageMediaPhoto &data) {
|
||||
if (const auto inner = data.vphoto()) {
|
||||
const auto photo = owner->processPhoto(*inner);
|
||||
if (!photo->isNull()) {
|
||||
extended.push_back(CreditsHistoryMedia{
|
||||
.type = CreditsHistoryMediaType::Photo,
|
||||
.id = photo->id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDmessageMediaDocument &data) {
|
||||
if (const auto inner = data.vdocument()) {
|
||||
const auto document = owner->processDocument(
|
||||
*inner,
|
||||
data.valt_documents());
|
||||
if (document->isAnimation()
|
||||
|| document->isVideoFile()
|
||||
|| document->isGifv()) {
|
||||
extended.push_back(CreditsHistoryMedia{
|
||||
.type = CreditsHistoryMediaType::Video,
|
||||
.id = document->id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [&](const auto &) {});
|
||||
}
|
||||
}
|
||||
const auto barePeerId = tl.data().vpeer().match([](
|
||||
const HistoryPeerTL &p) {
|
||||
return peerFromMTP(p.vpeer());
|
||||
}, [](const auto &) {
|
||||
return PeerId(0);
|
||||
}).value;
|
||||
const auto stargift = tl.data().vstargift();
|
||||
const auto nonUniqueGift = stargift
|
||||
? stargift->match([&](const MTPDstarGift &data) {
|
||||
return &data;
|
||||
}, [](const auto &) { return (const MTPDstarGift*)nullptr; })
|
||||
: nullptr;
|
||||
const auto reaction = tl.data().is_reaction();
|
||||
const auto amount = Data::FromTL(tl.data().vstars());
|
||||
const auto starrefAmount = tl.data().vstarref_amount()
|
||||
? Data::FromTL(*tl.data().vstarref_amount())
|
||||
: StarsAmount();
|
||||
const auto starrefCommission
|
||||
= tl.data().vstarref_commission_permille().value_or_empty();
|
||||
const auto starrefBarePeerId = tl.data().vstarref_peer()
|
||||
? peerFromMTP(*tl.data().vstarref_peer()).value
|
||||
: 0;
|
||||
const auto incoming = (amount >= StarsAmount());
|
||||
const auto paidMessagesCount
|
||||
= tl.data().vpaid_messages().value_or_empty();
|
||||
const auto premiumMonthsForStars
|
||||
= tl.data().vpremium_gift_months().value_or_empty();
|
||||
const auto saveActorId = (reaction
|
||||
|| !extended.empty()
|
||||
|| paidMessagesCount) && incoming;
|
||||
const auto parsedGift = stargift
|
||||
? FromTL(&peer->session(), *stargift)
|
||||
: std::optional<Data::StarGift>();
|
||||
const auto giftStickerId = parsedGift ? parsedGift->document->id : 0;
|
||||
return Data::CreditsHistoryEntry{
|
||||
.id = qs(tl.data().vid()),
|
||||
.title = qs(tl.data().vtitle().value_or_empty()),
|
||||
.description = { qs(tl.data().vdescription().value_or_empty()) },
|
||||
.date = base::unixtime::parse(tl.data().vdate().v),
|
||||
.photoId = photo ? photo->id : 0,
|
||||
.extended = std::move(extended),
|
||||
.credits = Data::FromTL(tl.data().vstars()),
|
||||
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
|
||||
.barePeerId = saveActorId ? peer->id.value : barePeerId,
|
||||
.bareGiveawayMsgId = uint64(
|
||||
tl.data().vgiveaway_post_id().value_or_empty()),
|
||||
.bareGiftStickerId = giftStickerId,
|
||||
.bareActorId = saveActorId ? barePeerId : uint64(0),
|
||||
.uniqueGift = parsedGift ? parsedGift->unique : nullptr,
|
||||
.starrefAmount = paidMessagesCount ? StarsAmount() : starrefAmount,
|
||||
.starrefCommission = paidMessagesCount ? 0 : starrefCommission,
|
||||
.starrefRecipientId = paidMessagesCount ? 0 : starrefBarePeerId,
|
||||
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Peer;
|
||||
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::PlayMarket;
|
||||
}, [](const MTPDstarsTransactionPeerFragment &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Fragment;
|
||||
}, [](const MTPDstarsTransactionPeerAppStore &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::AppStore;
|
||||
}, [](const MTPDstarsTransactionPeerUnsupported &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Unsupported;
|
||||
}, [](const MTPDstarsTransactionPeerPremiumBot &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::PremiumBot;
|
||||
}, [](const MTPDstarsTransactionPeerAds &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Ads;
|
||||
}, [](const MTPDstarsTransactionPeerAPI &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::API;
|
||||
}),
|
||||
.subscriptionUntil = tl.data().vsubscription_period()
|
||||
? base::unixtime::parse(base::unixtime::now()
|
||||
+ tl.data().vsubscription_period()->v)
|
||||
: QDateTime(),
|
||||
.successDate = tl.data().vtransaction_date()
|
||||
? base::unixtime::parse(tl.data().vtransaction_date()->v)
|
||||
: QDateTime(),
|
||||
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
|
||||
.paidMessagesCount = paidMessagesCount,
|
||||
.paidMessagesAmount = (paidMessagesCount
|
||||
? starrefAmount
|
||||
: StarsAmount()),
|
||||
.paidMessagesCommission = paidMessagesCount ? starrefCommission : 0,
|
||||
.starsConverted = int(nonUniqueGift
|
||||
? nonUniqueGift->vconvert_stars().v
|
||||
: 0),
|
||||
.premiumMonthsForStars = premiumMonthsForStars,
|
||||
.floodSkip = int(tl.data().vfloodskip_number().value_or(0)),
|
||||
.converted = stargift && incoming,
|
||||
.stargift = stargift.has_value(),
|
||||
.giftUpgraded = tl.data().is_stargift_upgrade(),
|
||||
.giftResale = tl.data().is_stargift_resale(),
|
||||
.reaction = tl.data().is_reaction(),
|
||||
.refunded = tl.data().is_refund(),
|
||||
.pending = tl.data().is_pending(),
|
||||
.failed = tl.data().is_failed(),
|
||||
.in = incoming,
|
||||
.gift = tl.data().is_gift() || stargift.has_value(),
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] Data::SubscriptionEntry SubscriptionFromTL(
|
||||
const MTPStarsSubscription &tl,
|
||||
not_null<PeerData*> peer) {
|
||||
@@ -203,7 +64,7 @@ constexpr auto kTransactionsLimit = 100;
|
||||
if (const auto history = data.vhistory()) {
|
||||
entries.reserve(history->v.size());
|
||||
for (const auto &tl : history->v) {
|
||||
entries.push_back(HistoryFromTL(tl, peer));
|
||||
entries.push_back(CreditsHistoryEntryFromTL(tl, peer));
|
||||
}
|
||||
}
|
||||
auto subscriptions = std::vector<Data::SubscriptionEntry>();
|
||||
@@ -216,7 +77,7 @@ constexpr auto kTransactionsLimit = 100;
|
||||
return Data::CreditsStatusSlice{
|
||||
.list = std::move(entries),
|
||||
.subscriptions = std::move(subscriptions),
|
||||
.balance = Data::FromTL(status.data().vbalance()),
|
||||
.balance = CreditsAmountFromTL(status.data().vbalance()),
|
||||
.subscriptionsMissingBalance
|
||||
= status.data().vsubscriptions_missing_balance().value_or_empty(),
|
||||
.allLoaded = !status.data().vnext_offset().has_value()
|
||||
@@ -300,11 +161,14 @@ void CreditsStatus::request(
|
||||
using TLResult = MTPpayments_StarsStatus;
|
||||
|
||||
_requestId = _api.request(MTPpayments_GetStarsStatus(
|
||||
MTP_flags(0),
|
||||
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input
|
||||
)).done([=](const TLResult &result) {
|
||||
_requestId = 0;
|
||||
const auto &balance = result.data().vbalance();
|
||||
_peer->session().credits().apply(_peer->id, Data::FromTL(balance));
|
||||
_peer->session().credits().apply(
|
||||
_peer->id,
|
||||
CreditsAmountFromTL(balance));
|
||||
if (const auto onstack = done) {
|
||||
onstack(StatusFromTL(result, _peer));
|
||||
}
|
||||
@@ -316,13 +180,18 @@ void CreditsStatus::request(
|
||||
}).send();
|
||||
}
|
||||
|
||||
CreditsHistory::CreditsHistory(not_null<PeerData*> peer, bool in, bool out)
|
||||
CreditsHistory::CreditsHistory(
|
||||
not_null<PeerData*> peer,
|
||||
bool in,
|
||||
bool out,
|
||||
bool currency)
|
||||
: _peer(peer)
|
||||
, _flags((in == out)
|
||||
, _flags(((in == out)
|
||||
? HistoryTL::Flags(0)
|
||||
: HistoryTL::Flags(0)
|
||||
| (in ? HistoryTL::Flag::f_inbound : HistoryTL::Flags(0))
|
||||
| (out ? HistoryTL::Flag::f_outbound : HistoryTL::Flags(0)))
|
||||
| (currency ? HistoryTL::Flag::f_ton : HistoryTL::Flags(0)))
|
||||
, _api(&peer->session().api().instance()) {
|
||||
}
|
||||
|
||||
@@ -414,19 +283,21 @@ rpl::producer<rpl::no_value, QString> CreditsEarnStatistics::request() {
|
||||
auto lifetime = rpl::lifetime();
|
||||
|
||||
const auto finish = [=](const QString &url) {
|
||||
makeRequest(MTPpayments_GetStarsRevenueStats(
|
||||
api().request(MTPpayments_GetStarsRevenueStats(
|
||||
MTP_flags(0),
|
||||
(_isUser ? user()->input : channel()->input)
|
||||
)).done([=](const MTPpayments_StarsRevenueStats &result) {
|
||||
const auto &data = result.data();
|
||||
const auto &status = data.vstatus().data();
|
||||
using Data::FromTL;
|
||||
_data = Data::CreditsEarnStatistics{
|
||||
.revenueGraph = StatisticalGraphFromTL(
|
||||
data.vrevenue_graph()),
|
||||
.currentBalance = FromTL(status.vcurrent_balance()),
|
||||
.availableBalance = FromTL(status.vavailable_balance()),
|
||||
.overallRevenue = FromTL(status.voverall_revenue()),
|
||||
.currentBalance = CreditsAmountFromTL(
|
||||
status.vcurrent_balance()),
|
||||
.availableBalance = CreditsAmountFromTL(
|
||||
status.vavailable_balance()),
|
||||
.overallRevenue = CreditsAmountFromTL(
|
||||
status.voverall_revenue()),
|
||||
.usdRate = data.vusd_rate().v,
|
||||
.isWithdrawalEnabled = status.is_withdrawal_enabled(),
|
||||
.nextWithdrawalAt = status.vnext_withdrawal_at()
|
||||
@@ -442,7 +313,7 @@ rpl::producer<rpl::no_value, QString> CreditsEarnStatistics::request() {
|
||||
}).send();
|
||||
};
|
||||
|
||||
makeRequest(
|
||||
api().request(
|
||||
MTPpayments_GetStarsRevenueAdsAccountUrl(
|
||||
(_isUser ? user()->input : channel()->input))
|
||||
).done([=](const MTPpayments_StarsRevenueAdsAccountUrl &result) {
|
||||
|
||||
@@ -75,7 +75,11 @@ private:
|
||||
|
||||
class CreditsHistory final {
|
||||
public:
|
||||
CreditsHistory(not_null<PeerData*> peer, bool in, bool out);
|
||||
CreditsHistory(
|
||||
not_null<PeerData*> peer,
|
||||
bool in,
|
||||
bool out,
|
||||
bool currency = false);
|
||||
|
||||
void request(
|
||||
const Data::CreditsStatusSlice::OffsetToken &token,
|
||||
|
||||
167
Telegram/SourceFiles/api/api_credits_history_entry.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
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_credits_history_entry.h"
|
||||
|
||||
#include "api/api_premium.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_credits.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
Data::CreditsHistoryEntry CreditsHistoryEntryFromTL(
|
||||
const MTPStarsTransaction &tl,
|
||||
not_null<PeerData*> peer) {
|
||||
using HistoryPeerTL = MTPDstarsTransactionPeer;
|
||||
using namespace Data;
|
||||
const auto owner = &peer->owner();
|
||||
const auto photo = tl.data().vphoto()
|
||||
? owner->photoFromWeb(*tl.data().vphoto(), ImageLocation())
|
||||
: nullptr;
|
||||
auto extended = std::vector<CreditsHistoryMedia>();
|
||||
if (const auto list = tl.data().vextended_media()) {
|
||||
extended.reserve(list->v.size());
|
||||
for (const auto &media : list->v) {
|
||||
media.match([&](const MTPDmessageMediaPhoto &data) {
|
||||
if (const auto inner = data.vphoto()) {
|
||||
const auto photo = owner->processPhoto(*inner);
|
||||
if (!photo->isNull()) {
|
||||
extended.push_back(CreditsHistoryMedia{
|
||||
.type = CreditsHistoryMediaType::Photo,
|
||||
.id = photo->id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDmessageMediaDocument &data) {
|
||||
if (const auto inner = data.vdocument()) {
|
||||
const auto document = owner->processDocument(
|
||||
*inner,
|
||||
data.valt_documents());
|
||||
if (document->isAnimation()
|
||||
|| document->isVideoFile()
|
||||
|| document->isGifv()) {
|
||||
extended.push_back(CreditsHistoryMedia{
|
||||
.type = CreditsHistoryMediaType::Video,
|
||||
.id = document->id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [&](const auto &) {});
|
||||
}
|
||||
}
|
||||
const auto barePeerId = tl.data().vpeer().match([](
|
||||
const HistoryPeerTL &p) {
|
||||
return peerFromMTP(p.vpeer());
|
||||
}, [](const auto &) {
|
||||
return PeerId(0);
|
||||
}).value;
|
||||
const auto stargift = tl.data().vstargift();
|
||||
const auto nonUniqueGift = stargift
|
||||
? stargift->match([&](const MTPDstarGift &data) {
|
||||
return &data;
|
||||
}, [](const auto &) { return (const MTPDstarGift*)nullptr; })
|
||||
: nullptr;
|
||||
const auto reaction = tl.data().is_reaction();
|
||||
const auto amount = CreditsAmountFromTL(tl.data().vamount());
|
||||
const auto starrefAmount = CreditsAmountFromTL(
|
||||
tl.data().vstarref_amount());
|
||||
const auto starrefCommission
|
||||
= tl.data().vstarref_commission_permille().value_or_empty();
|
||||
const auto starrefBarePeerId = tl.data().vstarref_peer()
|
||||
? peerFromMTP(*tl.data().vstarref_peer()).value
|
||||
: 0;
|
||||
const auto incoming = (amount >= CreditsAmount());
|
||||
const auto paidMessagesCount
|
||||
= tl.data().vpaid_messages().value_or_empty();
|
||||
const auto premiumMonthsForStars
|
||||
= tl.data().vpremium_gift_months().value_or_empty();
|
||||
const auto saveActorId = (reaction
|
||||
|| !extended.empty()
|
||||
|| paidMessagesCount) && incoming;
|
||||
const auto parsedGift = stargift
|
||||
? FromTL(&peer->session(), *stargift)
|
||||
: std::optional<Data::StarGift>();
|
||||
const auto giftStickerId = parsedGift ? parsedGift->document->id : 0;
|
||||
return Data::CreditsHistoryEntry{
|
||||
.id = qs(tl.data().vid()),
|
||||
.title = qs(tl.data().vtitle().value_or_empty()),
|
||||
.description = { qs(tl.data().vdescription().value_or_empty()) },
|
||||
.date = base::unixtime::parse(
|
||||
tl.data().vads_proceeds_from_date().value_or(
|
||||
tl.data().vdate().v)),
|
||||
.photoId = photo ? photo->id : 0,
|
||||
.extended = std::move(extended),
|
||||
.credits = CreditsAmountFromTL(tl.data().vamount()),
|
||||
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
|
||||
.barePeerId = saveActorId ? peer->id.value : barePeerId,
|
||||
.bareGiveawayMsgId = uint64(
|
||||
tl.data().vgiveaway_post_id().value_or_empty()),
|
||||
.bareGiftStickerId = giftStickerId,
|
||||
.bareActorId = saveActorId ? barePeerId : uint64(0),
|
||||
.uniqueGift = parsedGift ? parsedGift->unique : nullptr,
|
||||
.starrefAmount = paidMessagesCount ? CreditsAmount() : starrefAmount,
|
||||
.starrefCommission = paidMessagesCount ? 0 : starrefCommission,
|
||||
.starrefRecipientId = paidMessagesCount ? 0 : starrefBarePeerId,
|
||||
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Peer;
|
||||
}, [](const MTPDstarsTransactionPeerPlayMarket &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::PlayMarket;
|
||||
}, [](const MTPDstarsTransactionPeerFragment &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Fragment;
|
||||
}, [](const MTPDstarsTransactionPeerAppStore &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::AppStore;
|
||||
}, [](const MTPDstarsTransactionPeerUnsupported &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Unsupported;
|
||||
}, [](const MTPDstarsTransactionPeerPremiumBot &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::PremiumBot;
|
||||
}, [](const MTPDstarsTransactionPeerAds &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::Ads;
|
||||
}, [](const MTPDstarsTransactionPeerAPI &) {
|
||||
return Data::CreditsHistoryEntry::PeerType::API;
|
||||
}),
|
||||
.subscriptionUntil = tl.data().vsubscription_period()
|
||||
? base::unixtime::parse(base::unixtime::now()
|
||||
+ tl.data().vsubscription_period()->v)
|
||||
: QDateTime(),
|
||||
.adsProceedsToDate = tl.data().vads_proceeds_to_date()
|
||||
? base::unixtime::parse(tl.data().vads_proceeds_to_date()->v)
|
||||
: QDateTime(),
|
||||
.successDate = tl.data().vtransaction_date()
|
||||
? base::unixtime::parse(tl.data().vtransaction_date()->v)
|
||||
: QDateTime(),
|
||||
.successLink = qs(tl.data().vtransaction_url().value_or_empty()),
|
||||
.paidMessagesCount = paidMessagesCount,
|
||||
.paidMessagesAmount = (paidMessagesCount
|
||||
? starrefAmount
|
||||
: CreditsAmount()),
|
||||
.paidMessagesCommission = paidMessagesCount ? starrefCommission : 0,
|
||||
.starsConverted = int(nonUniqueGift
|
||||
? nonUniqueGift->vconvert_stars().v
|
||||
: 0),
|
||||
.premiumMonthsForStars = premiumMonthsForStars,
|
||||
.floodSkip = int(tl.data().vfloodskip_number().value_or(0)),
|
||||
.converted = stargift && incoming,
|
||||
.stargift = stargift.has_value(),
|
||||
.giftUpgraded = tl.data().is_stargift_upgrade(),
|
||||
.giftResale = tl.data().is_stargift_resale(),
|
||||
.reaction = tl.data().is_reaction(),
|
||||
.refunded = tl.data().is_refund(),
|
||||
.pending = tl.data().is_pending(),
|
||||
.failed = tl.data().is_failed(),
|
||||
.in = incoming,
|
||||
.gift = tl.data().is_gift() || stargift.has_value(),
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
22
Telegram/SourceFiles/api/api_credits_history_entry.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class PeerData;
|
||||
|
||||
namespace Data {
|
||||
struct CreditsHistoryEntry;
|
||||
} // namespace Data
|
||||
|
||||
namespace Api {
|
||||
|
||||
[[nodiscard]] Data::CreditsHistoryEntry CreditsHistoryEntryFromTL(
|
||||
const MTPStarsTransaction &tl,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
} // namespace Api
|
||||
@@ -56,7 +56,6 @@ void HandleWithdrawalButton(
|
||||
? ¤cyReceiver->session()
|
||||
: &creditsReceiver->session());
|
||||
|
||||
using ChannelOutUrl = MTPstats_BroadcastRevenueWithdrawalUrl;
|
||||
using CreditsOutUrl = MTPpayments_StarsRevenueWithdrawalUrl;
|
||||
|
||||
session->api().cloudPassword().reload();
|
||||
@@ -83,7 +82,7 @@ void HandleWithdrawalButton(
|
||||
fields.customSubmitButton = tr::lng_passcode_submit();
|
||||
fields.customCheckCallback = crl::guard(button, [=](
|
||||
const Core::CloudPasswordResult &result,
|
||||
QPointer<PasscodeBox> box) {
|
||||
base::weak_qptr<PasscodeBox> box) {
|
||||
const auto done = [=](const QString &result) {
|
||||
if (!result.isEmpty()) {
|
||||
UrlClickHandler::Open(result);
|
||||
@@ -98,19 +97,19 @@ void HandleWithdrawalButton(
|
||||
show->showToast(message);
|
||||
}
|
||||
};
|
||||
if (currencyReceiver) {
|
||||
session->api().request(
|
||||
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
||||
currencyReceiver->input,
|
||||
result.result
|
||||
)).done([=](const ChannelOutUrl &r) {
|
||||
done(qs(r.data().vurl()));
|
||||
}).fail(fail).send();
|
||||
} else if (creditsReceiver) {
|
||||
if (currencyReceiver || creditsReceiver) {
|
||||
using F = MTPpayments_getStarsRevenueWithdrawalUrl::Flag;
|
||||
session->api().request(
|
||||
MTPpayments_GetStarsRevenueWithdrawalUrl(
|
||||
creditsReceiver->input,
|
||||
MTP_long(receiver.creditsAmount()),
|
||||
MTP_flags(currencyReceiver
|
||||
? F::f_ton
|
||||
: F::f_amount),
|
||||
currencyReceiver
|
||||
? currencyReceiver->input
|
||||
: creditsReceiver->input,
|
||||
MTP_long(creditsReceiver
|
||||
? receiver.creditsAmount()
|
||||
: 0),
|
||||
result.result
|
||||
)).done([=](const CreditsOutUrl &r) {
|
||||
done(qs(r.data().vurl()));
|
||||
@@ -138,17 +137,19 @@ void HandleWithdrawalButton(
|
||||
processOut();
|
||||
}
|
||||
};
|
||||
if (currencyReceiver) {
|
||||
session->api().request(
|
||||
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
||||
currencyReceiver->input,
|
||||
MTP_inputCheckPasswordEmpty()
|
||||
)).fail(fail).send();
|
||||
} else if (creditsReceiver) {
|
||||
if (currencyReceiver || creditsReceiver) {
|
||||
using F = MTPpayments_getStarsRevenueWithdrawalUrl::Flag;
|
||||
session->api().request(
|
||||
MTPpayments_GetStarsRevenueWithdrawalUrl(
|
||||
creditsReceiver->input,
|
||||
MTP_long(receiver.creditsAmount()),
|
||||
MTP_flags(currencyReceiver
|
||||
? F::f_ton
|
||||
: F::f_amount),
|
||||
currencyReceiver
|
||||
? currencyReceiver->input
|
||||
: creditsReceiver->input,
|
||||
MTP_long(creditsReceiver
|
||||
? receiver.creditsAmount()
|
||||
: 0),
|
||||
MTP_inputCheckPasswordEmpty()
|
||||
)).fail(fail).send();
|
||||
}
|
||||
|
||||
@@ -10,15 +10,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_media.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "base/random.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "data/business/data_shortcut_messages.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_saved_sublist.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_todo_list.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "history/view/controls/history_view_compose_media_edit_manager.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/mtproto_response.h"
|
||||
@@ -45,6 +49,193 @@ template <typename T>
|
||||
constexpr auto ErrorWithoutId
|
||||
= is_callable_plain_v<T, QString>;
|
||||
|
||||
template <typename DoneCallback, typename FailCallback>
|
||||
mtpRequestId SuggestMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
const TextWithEntities &textWithEntities,
|
||||
Data::WebPageDraft webpage,
|
||||
SendOptions options,
|
||||
DoneCallback &&done,
|
||||
FailCallback &&fail) {
|
||||
Expects(options.suggest.exists);
|
||||
Expects(!options.scheduled);
|
||||
|
||||
const auto session = &item->history()->session();
|
||||
const auto api = &session->api();
|
||||
|
||||
const auto thread = item->history()->amMonoforumAdmin()
|
||||
? item->savedSublist()
|
||||
: (Data::Thread*)item->history();
|
||||
auto action = SendAction(thread, options);
|
||||
action.replyTo = FullReplyTo{
|
||||
.messageId = item->fullId(),
|
||||
.monoforumPeerId = (item->history()->amMonoforumAdmin()
|
||||
? item->sublistPeerId()
|
||||
: PeerId()),
|
||||
};
|
||||
|
||||
auto message = MessageToSend(std::move(action));
|
||||
message.textWithTags = TextWithTags{
|
||||
textWithEntities.text,
|
||||
TextUtilities::ConvertEntitiesToTextTags(textWithEntities.entities)
|
||||
};
|
||||
message.webPage = webpage;
|
||||
api->sendMessage(std::move(message));
|
||||
|
||||
const auto requestId = -1;
|
||||
crl::on_main(session, [=] {
|
||||
const auto type = u"MESSAGE_NOT_MODIFIED"_q;
|
||||
if constexpr (ErrorWithId<FailCallback>) {
|
||||
fail(type, requestId);
|
||||
} else if constexpr (ErrorWithoutId<FailCallback>) {
|
||||
fail(type);
|
||||
} else if constexpr (WithoutCallback<FailCallback>) {
|
||||
fail();
|
||||
} else {
|
||||
t_bad_callback(fail);
|
||||
}
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
template <typename DoneCallback, typename FailCallback>
|
||||
mtpRequestId SuggestMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const TextWithEntities &textWithEntities,
|
||||
Data::WebPageDraft webpage,
|
||||
SendOptions options,
|
||||
DoneCallback &&done,
|
||||
FailCallback &&fail,
|
||||
std::optional<MTPInputMedia> inputMedia) {
|
||||
Expects(options.suggest.exists);
|
||||
Expects(!options.scheduled);
|
||||
|
||||
const auto session = &item->history()->session();
|
||||
const auto api = &session->api();
|
||||
|
||||
const auto text = textWithEntities.text;
|
||||
const auto sentEntities = EntitiesToMTP(
|
||||
session,
|
||||
textWithEntities.entities,
|
||||
ConvertOption::SkipLocal);
|
||||
|
||||
const auto updateRecentStickers = inputMedia
|
||||
? Api::HasAttachedStickers(*inputMedia)
|
||||
: false;
|
||||
|
||||
const auto emptyFlag = MTPmessages_SendMedia::Flag(0);
|
||||
auto replyTo = FullReplyTo{
|
||||
.messageId = item->fullId(),
|
||||
.monoforumPeerId = (item->history()->amMonoforumAdmin()
|
||||
? item->sublistPeerId()
|
||||
: PeerId()),
|
||||
};
|
||||
const auto flags = emptyFlag
|
||||
| MTPmessages_SendMedia::Flag::f_reply_to
|
||||
| MTPmessages_SendMedia::Flag::f_suggested_post
|
||||
| (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert)
|
||||
|| options.invertCaption)
|
||||
? MTPmessages_SendMedia::Flag::f_invert_media
|
||||
: emptyFlag)
|
||||
| (!sentEntities.v.isEmpty()
|
||||
? MTPmessages_SendMedia::Flag::f_entities
|
||||
: emptyFlag)
|
||||
| (options.starsApproved
|
||||
? MTPmessages_SendMedia::Flag::f_allow_paid_stars
|
||||
: emptyFlag);
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
return api->request(MTPmessages_SendMedia(
|
||||
MTP_flags(flags),
|
||||
item->history()->peer->input,
|
||||
ReplyToForMTP(item->history(), replyTo),
|
||||
inputMedia.value_or(Data::WebPageForMTP(webpage, text.isEmpty())),
|
||||
MTP_string(text),
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTPint(), // schedule_date
|
||||
MTPInputPeer(), // send_as
|
||||
MTPInputQuickReplyShortcut(), // quick_reply_shortcut
|
||||
MTPlong(), // effect
|
||||
MTP_long(options.starsApproved),
|
||||
Api::SuggestToMTP(options.suggest)
|
||||
)).done([=](
|
||||
const MTPUpdates &result,
|
||||
[[maybe_unused]] mtpRequestId requestId) {
|
||||
const auto apply = [=] { api->applyUpdates(result); };
|
||||
|
||||
if constexpr (WithId<DoneCallback>) {
|
||||
done(apply, requestId);
|
||||
} else if constexpr (WithoutId<DoneCallback>) {
|
||||
done(apply);
|
||||
} else if constexpr (WithoutCallback<DoneCallback>) {
|
||||
done();
|
||||
apply();
|
||||
} else {
|
||||
t_bad_callback(done);
|
||||
}
|
||||
|
||||
if (updateRecentStickers) {
|
||||
api->requestSpecialStickersForce(false, false, true);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||
if constexpr (ErrorWithId<FailCallback>) {
|
||||
fail(error.type(), requestId);
|
||||
} else if constexpr (ErrorWithoutId<FailCallback>) {
|
||||
fail(error.type());
|
||||
} else if constexpr (WithoutCallback<FailCallback>) {
|
||||
fail();
|
||||
} else {
|
||||
t_bad_callback(fail);
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
template <typename DoneCallback, typename FailCallback>
|
||||
mtpRequestId SuggestMessageOrMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const TextWithEntities &textWithEntities,
|
||||
Data::WebPageDraft webpage,
|
||||
SendOptions options,
|
||||
DoneCallback &&done,
|
||||
FailCallback &&fail,
|
||||
std::optional<MTPInputMedia> inputMedia) {
|
||||
const auto wasMedia = item->media();
|
||||
if (!inputMedia && wasMedia && wasMedia->allowsEditCaption()) {
|
||||
if (const auto photo = wasMedia->photo()) {
|
||||
inputMedia = MTP_inputMediaPhoto(
|
||||
MTP_flags(0),
|
||||
photo->mtpInput(),
|
||||
MTPint()); // ttl_seconds
|
||||
} else if (const auto document = wasMedia->document()) {
|
||||
inputMedia = MTP_inputMediaDocument(
|
||||
MTP_flags(0),
|
||||
document->mtpInput(),
|
||||
MTPInputPhoto(), // video_cover
|
||||
MTPint(), // video_timestamp
|
||||
MTPint(), // ttl_seconds
|
||||
MTPstring()); // query
|
||||
}
|
||||
}
|
||||
if (inputMedia) {
|
||||
return SuggestMedia(
|
||||
item,
|
||||
textWithEntities,
|
||||
webpage,
|
||||
options,
|
||||
std::move(done),
|
||||
std::move(fail),
|
||||
inputMedia);
|
||||
}
|
||||
return SuggestMessage(
|
||||
item,
|
||||
textWithEntities,
|
||||
webpage,
|
||||
options,
|
||||
std::move(done),
|
||||
std::move(fail));
|
||||
}
|
||||
|
||||
template <typename DoneCallback, typename FailCallback>
|
||||
mtpRequestId EditMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
@@ -54,6 +245,18 @@ mtpRequestId EditMessage(
|
||||
DoneCallback &&done,
|
||||
FailCallback &&fail,
|
||||
std::optional<MTPInputMedia> inputMedia = std::nullopt) {
|
||||
if (item->computeSuggestionActions()
|
||||
== SuggestionActions::AcceptAndDecline) {
|
||||
return SuggestMessageOrMedia(
|
||||
item,
|
||||
textWithEntities,
|
||||
webpage,
|
||||
options,
|
||||
std::move(done),
|
||||
std::move(fail),
|
||||
inputMedia);
|
||||
}
|
||||
|
||||
const auto session = &item->history()->session();
|
||||
const auto api = &session->api();
|
||||
|
||||
@@ -70,31 +273,31 @@ mtpRequestId EditMessage(
|
||||
|
||||
const auto emptyFlag = MTPmessages_EditMessage::Flag(0);
|
||||
const auto flags = emptyFlag
|
||||
| ((!text.isEmpty() || media)
|
||||
? MTPmessages_EditMessage::Flag::f_message
|
||||
: emptyFlag)
|
||||
| ((media && inputMedia.has_value())
|
||||
? MTPmessages_EditMessage::Flag::f_media
|
||||
: emptyFlag)
|
||||
| (webpage.removed
|
||||
? MTPmessages_EditMessage::Flag::f_no_webpage
|
||||
: emptyFlag)
|
||||
| ((!webpage.removed && !webpage.url.isEmpty())
|
||||
? MTPmessages_EditMessage::Flag::f_media
|
||||
: emptyFlag)
|
||||
| (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert)
|
||||
|| options.invertCaption)
|
||||
? MTPmessages_EditMessage::Flag::f_invert_media
|
||||
: emptyFlag)
|
||||
| (!sentEntities.v.isEmpty()
|
||||
? MTPmessages_EditMessage::Flag::f_entities
|
||||
: emptyFlag)
|
||||
| (options.scheduled
|
||||
? MTPmessages_EditMessage::Flag::f_schedule_date
|
||||
: emptyFlag)
|
||||
| (item->isBusinessShortcut()
|
||||
? MTPmessages_EditMessage::Flag::f_quick_reply_shortcut_id
|
||||
: emptyFlag);
|
||||
| ((!text.isEmpty() || media)
|
||||
? MTPmessages_EditMessage::Flag::f_message
|
||||
: emptyFlag)
|
||||
| ((media && inputMedia.has_value())
|
||||
? MTPmessages_EditMessage::Flag::f_media
|
||||
: emptyFlag)
|
||||
| (webpage.removed
|
||||
? MTPmessages_EditMessage::Flag::f_no_webpage
|
||||
: emptyFlag)
|
||||
| ((!webpage.removed && !webpage.url.isEmpty())
|
||||
? MTPmessages_EditMessage::Flag::f_media
|
||||
: emptyFlag)
|
||||
| (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert)
|
||||
|| options.invertCaption)
|
||||
? MTPmessages_EditMessage::Flag::f_invert_media
|
||||
: emptyFlag)
|
||||
| (!sentEntities.v.isEmpty()
|
||||
? MTPmessages_EditMessage::Flag::f_entities
|
||||
: emptyFlag)
|
||||
| (options.scheduled
|
||||
? MTPmessages_EditMessage::Flag::f_schedule_date
|
||||
: emptyFlag)
|
||||
| (item->isBusinessShortcut()
|
||||
? MTPmessages_EditMessage::Flag::f_quick_reply_shortcut_id
|
||||
: emptyFlag);
|
||||
|
||||
const auto id = item->isScheduled()
|
||||
? session->scheduledMessages().lookupId(item)
|
||||
@@ -358,4 +561,22 @@ mtpRequestId EditTextMessage(
|
||||
std::nullopt);
|
||||
}
|
||||
|
||||
void EditTodoList(
|
||||
not_null<HistoryItem*> item,
|
||||
const TodoListData &data,
|
||||
SendOptions options,
|
||||
Fn<void(mtpRequestId requestId)> done,
|
||||
Fn<void(const QString &error, mtpRequestId requestId)> fail) {
|
||||
const auto callback = [=](Fn<void()> applyUpdates, mtpRequestId id) {
|
||||
applyUpdates();
|
||||
done(id);
|
||||
};
|
||||
EditMessage(
|
||||
item,
|
||||
options,
|
||||
callback,
|
||||
fail,
|
||||
MTP_inputMediaTodo(TodoListDataToMTP(&data)));
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -58,4 +58,11 @@ mtpRequestId EditTextMessage(
|
||||
Fn<void(const QString &error, mtpRequestId requestId)> fail,
|
||||
bool spoilered);
|
||||
|
||||
void EditTodoList(
|
||||
not_null<HistoryItem*> item,
|
||||
const TodoListData &data,
|
||||
SendOptions options,
|
||||
Fn<void(mtpRequestId requestId)> done,
|
||||
Fn<void(const QString &error, mtpRequestId requestId)> fail);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -47,6 +47,7 @@ void Polls::create(
|
||||
const auto topicRootId = action.replyTo.messageId
|
||||
? action.replyTo.topicRootId
|
||||
: 0;
|
||||
const auto monoforumPeerId = action.replyTo.monoforumPeerId;
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (action.replyTo) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||
@@ -54,9 +55,9 @@ void Polls::create(
|
||||
const auto clearCloudDraft = action.clearDraft;
|
||||
if (clearCloudDraft) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||
history->clearLocalDraft(topicRootId);
|
||||
history->clearCloudDraft(topicRootId);
|
||||
history->startSavingCloudDraft(topicRootId);
|
||||
history->clearLocalDraft(topicRootId, monoforumPeerId);
|
||||
history->clearCloudDraft(topicRootId, monoforumPeerId);
|
||||
history->startSavingCloudDraft(topicRootId, monoforumPeerId);
|
||||
}
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
const auto starsPaid = std::min(
|
||||
@@ -74,6 +75,9 @@ void Polls::create(
|
||||
if (action.options.effectId) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
}
|
||||
if (action.options.suggest) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_suggested_post;
|
||||
}
|
||||
if (starsPaid) {
|
||||
action.options.starsApproved -= starsPaid;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
|
||||
@@ -101,11 +105,13 @@ void Polls::create(
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(_session, action.options.shortcutId),
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(action.options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
_session->changes().historyUpdated(
|
||||
@@ -118,6 +124,7 @@ void Polls::create(
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
fail();
|
||||
|
||||
@@ -58,6 +58,30 @@ namespace {
|
||||
return options;
|
||||
}
|
||||
|
||||
[[nodiscard]] int FindStarsForResale(const MTPVector<MTPStarsAmount> *list) {
|
||||
if (!list) {
|
||||
return 0;
|
||||
}
|
||||
for (const auto &amount : list->v) {
|
||||
if (amount.type() == mtpc_starsAmount) {
|
||||
return int(amount.c_starsAmount().vamount().v);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] int64 FindTonForResale(const MTPVector<MTPStarsAmount> *list) {
|
||||
if (!list) {
|
||||
return 0;
|
||||
}
|
||||
for (const auto &amount : list->v) {
|
||||
if (amount.type() == mtpc_starsTonAmount) {
|
||||
return int64(amount.c_starsTonAmount().vamount().v);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Premium::Premium(not_null<ApiWrap*> api)
|
||||
@@ -424,7 +448,7 @@ void Premium::requestPremiumRequiredSlice() {
|
||||
constexpr auto hasPrem = Flag::HasRequirePremiumToWrite;
|
||||
constexpr auto hasStars = Flag::HasStarsPerMessage;
|
||||
user->setStarsPerMessage(stars);
|
||||
user->setFlags((user->flags() & ~(me | hasPrem | hasStars))
|
||||
user->setFlags((user->flags() & ~me)
|
||||
| known
|
||||
| (requirePremium ? (me | hasPrem) : Flag())
|
||||
| (stars ? hasStars : Flag()));
|
||||
@@ -619,6 +643,8 @@ auto PremiumGiftCodeOptions::requestStarGifts()
|
||||
MTP_int(0)
|
||||
)).done([=](const MTPpayments_StarGifts &result) {
|
||||
result.match([&](const MTPDpayments_starGifts &data) {
|
||||
_peer->owner().processUsers(data.vusers());
|
||||
_peer->owner().processChats(data.vchats());
|
||||
_giftsHash = data.vhash().v;
|
||||
const auto &list = data.vgifts().v;
|
||||
const auto session = &_peer->session();
|
||||
@@ -805,6 +831,12 @@ std::optional<Data::StarGift> FromTL(
|
||||
if (!document->sticker()) {
|
||||
return std::optional<Data::StarGift>();
|
||||
}
|
||||
const auto releasedById = data.vreleased_by()
|
||||
? peerFromMTP(*data.vreleased_by())
|
||||
: PeerId();
|
||||
const auto releasedBy = releasedById
|
||||
? session->data().peer(releasedById).get()
|
||||
: nullptr;
|
||||
return std::optional<Data::StarGift>(Data::StarGift{
|
||||
.id = uint64(data.vid().v),
|
||||
.stars = int64(data.vstars().v),
|
||||
@@ -812,12 +844,16 @@ std::optional<Data::StarGift> FromTL(
|
||||
.starsToUpgrade = int64(data.vupgrade_stars().value_or_empty()),
|
||||
.starsResellMin = int64(resellPrice),
|
||||
.document = document,
|
||||
.releasedBy = releasedBy,
|
||||
.resellTitle = qs(data.vtitle().value_or_empty()),
|
||||
.resellCount = int(data.vavailability_resale().value_or_empty()),
|
||||
.limitedLeft = remaining.value_or_empty(),
|
||||
.limitedCount = total.value_or_empty(),
|
||||
.perUserTotal = data.vper_user_total().value_or_empty(),
|
||||
.perUserRemains = data.vper_user_remains().value_or_empty(),
|
||||
.firstSaleDate = data.vfirst_sale_date().value_or_empty(),
|
||||
.lastSaleDate = data.vlast_sale_date().value_or_empty(),
|
||||
.requirePremium = data.is_require_premium(),
|
||||
.upgradable = data.vupgrade_stars().has_value(),
|
||||
.birthday = data.is_birthday(),
|
||||
.soldOut = data.is_sold_out(),
|
||||
@@ -841,6 +877,12 @@ std::optional<Data::StarGift> FromTL(
|
||||
|| !pattern->document->sticker()) {
|
||||
return std::optional<Data::StarGift>();
|
||||
}
|
||||
const auto releasedById = data.vreleased_by()
|
||||
? peerFromMTP(*data.vreleased_by())
|
||||
: PeerId();
|
||||
const auto releasedBy = releasedById
|
||||
? session->data().peer(releasedById).get()
|
||||
: nullptr;
|
||||
auto result = Data::StarGift{
|
||||
.id = uint64(data.vid().v),
|
||||
.unique = std::make_shared<Data::UniqueGift>(Data::UniqueGift{
|
||||
@@ -852,14 +894,20 @@ std::optional<Data::StarGift> FromTL(
|
||||
.ownerId = (data.vowner_id()
|
||||
? peerFromMTP(*data.vowner_id())
|
||||
: PeerId()),
|
||||
.releasedBy = releasedBy,
|
||||
.nanoTonForResale = FindTonForResale(data.vresell_amount()),
|
||||
.starsForResale = FindStarsForResale(data.vresell_amount()),
|
||||
.number = data.vnum().v,
|
||||
.starsForResale = int(data.vresell_stars().value_or_empty()),
|
||||
.onlyAcceptTon = data.is_resale_ton_only(),
|
||||
.model = *model,
|
||||
.pattern = *pattern,
|
||||
}),
|
||||
.document = model->document,
|
||||
.releasedBy = releasedBy,
|
||||
.limitedLeft = (total - data.vavailability_issued().v),
|
||||
.limitedCount = total,
|
||||
.resellTonOnly = data.is_resale_ton_only(),
|
||||
.requirePremium = data.is_require_premium(),
|
||||
};
|
||||
const auto unique = result.unique.get();
|
||||
for (const auto &attribute : data.vattributes().v) {
|
||||
@@ -896,6 +944,11 @@ std::optional<Data::SavedStarGift> FromTL(
|
||||
.manageId = (to->isUser()
|
||||
? Id::User(data.vmsg_id().value_or_empty())
|
||||
: Id::Chat(to, data.vsaved_id().value_or_empty())),
|
||||
.collectionIds = (data.vcollection_id()
|
||||
? (data.vcollection_id()->v
|
||||
| ranges::views::transform(&MTPint::v)
|
||||
| ranges::to_vector)
|
||||
: std::vector<int>()),
|
||||
.message = (data.vmessage()
|
||||
? TextWithEntities{
|
||||
.text = qs(data.vmessage()->data().vtext()),
|
||||
|
||||
@@ -109,6 +109,9 @@ void SendSimpleMedia(SendAction action, MTPInputMedia inputMedia) {
|
||||
if (action.options.effectId) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
}
|
||||
if (action.options.suggest) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_suggested_post;
|
||||
}
|
||||
if (action.options.invertCaption) {
|
||||
flags |= MessageFlag::InvertMedia;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
||||
@@ -136,7 +139,8 @@ void SendSimpleMedia(SendAction action, MTPInputMedia inputMedia) {
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(action.options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
api->sendMessageFail(error, peer, randomId);
|
||||
@@ -211,6 +215,9 @@ void SendExistingMedia(
|
||||
if (action.options.effectId) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
}
|
||||
if (action.options.suggest) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_suggested_post;
|
||||
}
|
||||
if (action.options.invertCaption) {
|
||||
flags |= MessageFlag::InvertMedia;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
||||
@@ -232,6 +239,7 @@ void SendExistingMedia(
|
||||
.starsPaid = starsPaid,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, media, caption);
|
||||
|
||||
const auto performRequest = [=](const auto &repeatRequest) -> void {
|
||||
@@ -255,7 +263,8 @@ void SendExistingMedia(
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(action.options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
if (error.code() == 400
|
||||
@@ -391,6 +400,9 @@ bool SendDice(MessageToSend &message) {
|
||||
if (action.options.effectId) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
}
|
||||
if (action.options.suggest) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_suggested_post;
|
||||
}
|
||||
if (action.options.invertCaption) {
|
||||
flags |= MessageFlag::InvertMedia;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
|
||||
@@ -415,6 +427,7 @@ bool SendDice(MessageToSend &message) {
|
||||
.starsPaid = starsPaid,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, TextWithEntities(), MTP_messageMediaDice(
|
||||
MTP_int(0),
|
||||
MTP_string(emoji)));
|
||||
@@ -435,7 +448,8 @@ bool SendDice(MessageToSend &message) {
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(session, action.options.shortcutId),
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(action.options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
@@ -624,6 +638,7 @@ void SendConfirmedFile(
|
||||
edition.useSameMarkup = true;
|
||||
edition.useSameReplies = true;
|
||||
edition.useSameReactions = true;
|
||||
edition.useSameSuggest = true;
|
||||
edition.savePreviousMedia = true;
|
||||
itemToEdit->applyEdition(std::move(edition));
|
||||
} else {
|
||||
@@ -640,6 +655,7 @@ void SendConfirmedFile(
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.groupedId = groupId,
|
||||
.effectId = file->to.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(file->to.options),
|
||||
}, caption, media);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ SensitiveContent::SensitiveContent(not_null<ApiWrap*> api)
|
||||
}
|
||||
|
||||
void SensitiveContent::preload() {
|
||||
if (!_loaded) {
|
||||
if (!_loaded && !_loadRequestId) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,6 @@ void SensitiveContent::reload(bool force) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
_loaded = true;
|
||||
_loadRequestId = _api.request(MTPaccount_GetContentSettings(
|
||||
)).done([=](const MTPaccount_ContentSettings &result) {
|
||||
_loadRequestId = 0;
|
||||
@@ -50,6 +49,10 @@ void SensitiveContent::reload(bool force) {
|
||||
_enabled = enabled;
|
||||
_canChange = canChange;
|
||||
}
|
||||
if (!_loaded) {
|
||||
_loaded = true;
|
||||
_loadedChanged.fire({});
|
||||
}
|
||||
if (base::take(_appConfigReloadForce) || changed) {
|
||||
_appConfigReloadTimer.callOnce(kRefreshAppConfigTimeout);
|
||||
}
|
||||
@@ -61,6 +64,19 @@ void SensitiveContent::reload(bool force) {
|
||||
}).send();
|
||||
}
|
||||
|
||||
bool SensitiveContent::loaded() const {
|
||||
return _loaded;
|
||||
}
|
||||
|
||||
rpl::producer<bool> SensitiveContent::loadedValue() const {
|
||||
if (_loaded) {
|
||||
return rpl::single(true);
|
||||
}
|
||||
return rpl::single(false) | rpl::then(
|
||||
_loadedChanged.events() | rpl::map_to(true)
|
||||
);
|
||||
}
|
||||
|
||||
bool SensitiveContent::enabledCurrent() const {
|
||||
return _enabled.current();
|
||||
}
|
||||
@@ -69,6 +85,10 @@ rpl::producer<bool> SensitiveContent::enabled() const {
|
||||
return _enabled.value();
|
||||
}
|
||||
|
||||
bool SensitiveContent::canChangeCurrent() const {
|
||||
return _canChange.current();
|
||||
}
|
||||
|
||||
rpl::producer<bool> SensitiveContent::canChange() const {
|
||||
return _canChange.value();
|
||||
}
|
||||
|
||||
@@ -26,12 +26,16 @@ public:
|
||||
void reload(bool force = false);
|
||||
void update(bool enabled);
|
||||
|
||||
[[nodiscard]] bool loaded() const;
|
||||
[[nodiscard]] rpl::producer<bool> loadedValue() const;
|
||||
[[nodiscard]] bool enabledCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> enabled() const;
|
||||
[[nodiscard]] bool canChangeCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> canChange() const;
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
rpl::event_stream<> _loadedChanged;
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _loadRequestId = 0;
|
||||
mtpRequestId _saveRequestId = 0;
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_statistics.h"
|
||||
|
||||
#include "api/api_credits_history_entry.h"
|
||||
#include "api/api_statistics_data_deserialize.h"
|
||||
#include "apiwrap.h"
|
||||
#include "base/unixtime.h"
|
||||
@@ -695,19 +696,23 @@ rpl::producer<rpl::no_value, QString> EarnStatistics::request() {
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
|
||||
makeRequest(MTPstats_GetBroadcastRevenueStats(
|
||||
MTP_flags(0),
|
||||
api().request(MTPpayments_GetStarsRevenueStats(
|
||||
MTP_flags(MTPpayments_getStarsRevenueStats::Flag::f_ton),
|
||||
(_isUser ? user()->input : channel()->input)
|
||||
)).done([=](const MTPstats_BroadcastRevenueStats &result) {
|
||||
)).done([=](const MTPpayments_StarsRevenueStats &result) {
|
||||
const auto &data = result.data();
|
||||
const auto &balances = data.vbalances().data();
|
||||
const auto &balances = data.vstatus().data();
|
||||
const auto amount = [](const auto &a) {
|
||||
return CreditsAmountFromTL(a);
|
||||
};
|
||||
_data = Data::EarnStatistics{
|
||||
.topHoursGraph = StatisticalGraphFromTL(
|
||||
data.vtop_hours_graph()),
|
||||
.topHoursGraph = data.vtop_hours_graph()
|
||||
? StatisticalGraphFromTL(*data.vtop_hours_graph())
|
||||
: Data::StatisticalGraph(),
|
||||
.revenueGraph = StatisticalGraphFromTL(data.vrevenue_graph()),
|
||||
.currentBalance = balances.vcurrent_balance().v,
|
||||
.availableBalance = balances.vavailable_balance().v,
|
||||
.overallRevenue = balances.voverall_revenue().v,
|
||||
.currentBalance = amount(balances.vcurrent_balance()),
|
||||
.availableBalance = amount(balances.vavailable_balance()),
|
||||
.overallRevenue = amount(balances.voverall_revenue()),
|
||||
.usdRate = data.vusd_rate().v,
|
||||
};
|
||||
|
||||
@@ -745,62 +750,35 @@ void EarnStatistics::requestHistory(
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr auto kTlFirstSlice = tl::make_int(kFirstSlice);
|
||||
constexpr auto kTlLimit = tl::make_int(kLimit);
|
||||
_requestId = api().request(MTPstats_GetBroadcastRevenueTransactions(
|
||||
|
||||
_requestId = api().request(MTPpayments_GetStarsTransactions(
|
||||
MTP_flags(MTPpayments_getStarsTransactions::Flag::f_ton),
|
||||
MTP_string(), // Subscription ID.
|
||||
(_isUser ? user()->input : channel()->input),
|
||||
MTP_int(token),
|
||||
(!token) ? kTlFirstSlice : kTlLimit
|
||||
)).done([=](const MTPstats_BroadcastRevenueTransactions &result) {
|
||||
MTP_string(token),
|
||||
token.isEmpty() ? kTlFirstSlice : kTlLimit
|
||||
)).done([=](const MTPpayments_StarsStatus &result) {
|
||||
_requestId = 0;
|
||||
|
||||
const auto &tlTransactions = result.data().vtransactions().v;
|
||||
const auto nextToken = result.data().vnext_offset().value_or_empty();
|
||||
|
||||
auto list = std::vector<Data::EarnHistoryEntry>();
|
||||
list.reserve(tlTransactions.size());
|
||||
for (const auto &tlTransaction : tlTransactions) {
|
||||
list.push_back(tlTransaction.match([&](
|
||||
const MTPDbroadcastRevenueTransactionProceeds &d) {
|
||||
return Data::EarnHistoryEntry{
|
||||
.type = Data::EarnHistoryEntry::Type::In,
|
||||
.amount = d.vamount().v,
|
||||
.date = base::unixtime::parse(d.vfrom_date().v),
|
||||
.dateTo = base::unixtime::parse(d.vto_date().v),
|
||||
};
|
||||
}, [&](const MTPDbroadcastRevenueTransactionWithdrawal &d) {
|
||||
return Data::EarnHistoryEntry{
|
||||
.type = Data::EarnHistoryEntry::Type::Out,
|
||||
.status = d.is_pending()
|
||||
? Data::EarnHistoryEntry::Status::Pending
|
||||
: d.is_failed()
|
||||
? Data::EarnHistoryEntry::Status::Failed
|
||||
: Data::EarnHistoryEntry::Status::Success,
|
||||
.amount = (std::numeric_limits<Data::EarnInt>::max()
|
||||
- d.vamount().v
|
||||
+ 1),
|
||||
.date = base::unixtime::parse(d.vdate().v),
|
||||
// .provider = qs(d.vprovider()),
|
||||
.successDate = d.vtransaction_date()
|
||||
? base::unixtime::parse(d.vtransaction_date()->v)
|
||||
: QDateTime(),
|
||||
.successLink = d.vtransaction_url()
|
||||
? qs(*d.vtransaction_url())
|
||||
: QString(),
|
||||
};
|
||||
}, [&](const MTPDbroadcastRevenueTransactionRefund &d) {
|
||||
return Data::EarnHistoryEntry{
|
||||
.type = Data::EarnHistoryEntry::Type::Return,
|
||||
.amount = d.vamount().v,
|
||||
.date = base::unixtime::parse(d.vdate().v),
|
||||
// .provider = qs(d.vprovider()),
|
||||
};
|
||||
}));
|
||||
}
|
||||
const auto nextToken = token + tlTransactions.size();
|
||||
const auto tlTransactions
|
||||
= result.data().vhistory().value_or_empty();
|
||||
|
||||
const auto peer = _isUser ? (PeerData*)user() : (PeerData*)channel();
|
||||
auto list = ranges::views::all(
|
||||
tlTransactions
|
||||
) | ranges::views::transform([=](const auto &d) {
|
||||
return CreditsHistoryEntryFromTL(d, peer);
|
||||
}) | ranges::to_vector;
|
||||
done(Data::EarnHistorySlice{
|
||||
.list = std::move(list),
|
||||
.total = result.data().vcount().v,
|
||||
.allLoaded = (result.data().vcount().v == nextToken),
|
||||
.total = int(tlTransactions.size()),
|
||||
// .total = result.data().vcount().v,
|
||||
.allLoaded = nextToken.isEmpty(),
|
||||
.token = Data::EarnHistorySlice::OffsetToken(nextToken),
|
||||
});
|
||||
}).fail([=] {
|
||||
|
||||
638
Telegram/SourceFiles/api/api_suggest_post.cpp
Normal file
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
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_suggest_post.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "data/components/credits.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_saved_sublist.h"
|
||||
#include "history/view/controls/history_view_suggest_options.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwindow.h"
|
||||
#include "settings/settings_credits_graphics.h"
|
||||
#include "ui/boxes/choose_date_time.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
void SendApproval(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item,
|
||||
TimeId scheduleDate = 0) {
|
||||
using Flag = MTPmessages_ToggleSuggestedPostApproval::Flag;
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (!suggestion
|
||||
|| suggestion->accepted
|
||||
|| suggestion->rejected
|
||||
|| suggestion->requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = item->fullId();
|
||||
const auto session = &show->session();
|
||||
const auto finish = [=] {
|
||||
if (const auto item = session->data().message(id)) {
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (suggestion) {
|
||||
suggestion->requestId = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
suggestion->requestId = session->api().request(
|
||||
MTPmessages_ToggleSuggestedPostApproval(
|
||||
MTP_flags(scheduleDate ? Flag::f_schedule_date : Flag()),
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id.bare),
|
||||
MTP_int(scheduleDate),
|
||||
MTPstring()) // reject_comment
|
||||
).done([=](const MTPUpdates &result) {
|
||||
session->api().applyUpdates(result);
|
||||
finish();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
finish();
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ConfirmApproval(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item,
|
||||
TimeId scheduleDate = 0,
|
||||
Fn<void()> accepted = nullptr) {
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (!suggestion
|
||||
|| suggestion->accepted
|
||||
|| suggestion->rejected
|
||||
|| suggestion->requestId) {
|
||||
return;
|
||||
}
|
||||
const auto id = item->fullId();
|
||||
const auto price = suggestion->price;
|
||||
const auto admin = item->history()->amMonoforumAdmin();
|
||||
if (!admin && !price.empty()) {
|
||||
const auto credits = &item->history()->session().credits();
|
||||
if (price.ton()) {
|
||||
if (!credits->tonLoaded()) {
|
||||
credits->tonLoad();
|
||||
return;
|
||||
} else if (price > credits->tonBalance()) {
|
||||
const auto peer = item->history()->peer;
|
||||
show->show(
|
||||
Box(HistoryView::InsufficientTonBox, peer, price));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!credits->loaded()) {
|
||||
credits->load();
|
||||
return;
|
||||
} else if (price > credits->balance()) {
|
||||
using namespace Settings;
|
||||
const auto peer = item->history()->peer;
|
||||
const auto broadcast = peer->monoforumBroadcast();
|
||||
const auto broadcastId = (broadcast ? broadcast : peer)->id;
|
||||
const auto done = [=](SmallBalanceResult result) {
|
||||
if (result == SmallBalanceResult::Success
|
||||
|| result == SmallBalanceResult::Already) {
|
||||
const auto item = peer->owner().message(id);
|
||||
if (item) {
|
||||
ConfirmApproval(
|
||||
show,
|
||||
item,
|
||||
scheduleDate,
|
||||
accepted);
|
||||
}
|
||||
}
|
||||
};
|
||||
MaybeRequestBalanceIncrease(
|
||||
show,
|
||||
int(base::SafeRound(price.value())),
|
||||
SmallBalanceForSuggest{ broadcastId },
|
||||
done);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto peer = item->history()->peer;
|
||||
const auto session = &peer->session();
|
||||
const auto broadcast = peer->monoforumBroadcast();
|
||||
const auto channelName = (broadcast ? broadcast : peer)->name();
|
||||
const auto amount = admin
|
||||
? HistoryView::PriceAfterCommission(session, price)
|
||||
: price;
|
||||
const auto commission = HistoryView::FormatAfterCommissionPercent(
|
||||
session,
|
||||
price);
|
||||
const auto date = langDateTime(base::unixtime::parse(scheduleDate));
|
||||
show->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto callback = std::make_shared<Fn<void()>>();
|
||||
auto text = admin
|
||||
? tr::lng_suggest_accept_text(
|
||||
tr::now,
|
||||
lt_from,
|
||||
Ui::Text::Bold(item->from()->shortName()),
|
||||
Ui::Text::WithEntities)
|
||||
: tr::lng_suggest_accept_text_to(
|
||||
tr::now,
|
||||
lt_channel,
|
||||
Ui::Text::Bold(channelName),
|
||||
Ui::Text::WithEntities);
|
||||
if (price) {
|
||||
text.append("\n\n").append(admin
|
||||
? (scheduleDate
|
||||
? (amount.stars()
|
||||
? tr::lng_suggest_accept_receive_stars
|
||||
: tr::lng_suggest_accept_receive_ton)(
|
||||
tr::now,
|
||||
lt_count_decimal,
|
||||
amount.value(),
|
||||
lt_channel,
|
||||
Ui::Text::Bold(channelName),
|
||||
lt_percent,
|
||||
TextWithEntities{ commission },
|
||||
lt_date,
|
||||
Ui::Text::Bold(date),
|
||||
Ui::Text::RichLangValue)
|
||||
: (amount.stars()
|
||||
? tr::lng_suggest_accept_receive_now_stars
|
||||
: tr::lng_suggest_accept_receive_now_ton)(
|
||||
tr::now,
|
||||
lt_count_decimal,
|
||||
amount.value(),
|
||||
lt_channel,
|
||||
Ui::Text::Bold(channelName),
|
||||
lt_percent,
|
||||
TextWithEntities{ commission },
|
||||
Ui::Text::RichLangValue))
|
||||
: (scheduleDate
|
||||
? (amount.stars()
|
||||
? tr::lng_suggest_accept_pay_stars
|
||||
: tr::lng_suggest_accept_pay_ton)(
|
||||
tr::now,
|
||||
lt_count_decimal,
|
||||
amount.value(),
|
||||
lt_date,
|
||||
Ui::Text::Bold(date),
|
||||
Ui::Text::RichLangValue)
|
||||
: (amount.stars()
|
||||
? tr::lng_suggest_accept_pay_now_stars
|
||||
: tr::lng_suggest_accept_pay_now_ton)(
|
||||
tr::now,
|
||||
lt_count_decimal,
|
||||
amount.value(),
|
||||
Ui::Text::RichLangValue)));
|
||||
if (admin) {
|
||||
text.append(' ').append(
|
||||
tr::lng_suggest_accept_receive_if(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue));
|
||||
if (price.stars()) {
|
||||
text.append("\n\n").append(
|
||||
tr::lng_suggest_options_stars_warning(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ui::ConfirmBox(box, {
|
||||
.text = text,
|
||||
.confirmed = [=](Fn<void()> close) { (*callback)(); close(); },
|
||||
.confirmText = tr::lng_suggest_accept_send(),
|
||||
.title = tr::lng_suggest_accept_title(),
|
||||
});
|
||||
*callback = [=, weak = base::make_weak(box)] {
|
||||
if (const auto onstack = accepted) {
|
||||
onstack();
|
||||
}
|
||||
const auto item = show->session().data().message(id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
SendApproval(show, item, scheduleDate);
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
void SendDecline(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item,
|
||||
const QString &comment) {
|
||||
using Flag = MTPmessages_ToggleSuggestedPostApproval::Flag;
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (!suggestion
|
||||
|| suggestion->accepted
|
||||
|| suggestion->rejected
|
||||
|| suggestion->requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = item->fullId();
|
||||
const auto session = &show->session();
|
||||
const auto finish = [=] {
|
||||
if (const auto item = session->data().message(id)) {
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (suggestion) {
|
||||
suggestion->requestId = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
suggestion->requestId = session->api().request(
|
||||
MTPmessages_ToggleSuggestedPostApproval(
|
||||
MTP_flags(Flag::f_reject
|
||||
| (comment.isEmpty() ? Flag() : Flag::f_reject_comment)),
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id.bare),
|
||||
MTPint(), // schedule_date
|
||||
MTP_string(comment))
|
||||
).done([=](const MTPUpdates &result) {
|
||||
session->api().applyUpdates(result);
|
||||
finish();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
finish();
|
||||
}).send();
|
||||
}
|
||||
|
||||
void RequestApprovalDate(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item) {
|
||||
const auto id = item->fullId();
|
||||
const auto weak = std::make_shared<base::weak_qptr<Ui::BoxContent>>();
|
||||
const auto close = [=] {
|
||||
if (const auto strong = weak->get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
const auto done = [=](TimeId result) {
|
||||
if (const auto item = show->session().data().message(id)) {
|
||||
ConfirmApproval(show, item, result, close);
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
};
|
||||
using namespace HistoryView;
|
||||
auto dateBox = Box(ChooseSuggestTimeBox, SuggestTimeBoxArgs{
|
||||
.session = &show->session(),
|
||||
.done = done,
|
||||
.mode = SuggestMode::Publish,
|
||||
});
|
||||
*weak = dateBox.data();
|
||||
show->show(std::move(dateBox));
|
||||
}
|
||||
|
||||
void RequestDeclineComment(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item) {
|
||||
const auto id = item->fullId();
|
||||
const auto admin = item->history()->amMonoforumAdmin();
|
||||
const auto peer = item->history()->peer;
|
||||
const auto broadcast = peer->monoforumBroadcast();
|
||||
const auto channelName = (broadcast ? broadcast : peer)->name();
|
||||
show->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto callback = std::make_shared<Fn<void()>>();
|
||||
Ui::ConfirmBox(box, {
|
||||
.text = (admin
|
||||
? tr::lng_suggest_decline_text(
|
||||
lt_from,
|
||||
rpl::single(Ui::Text::Bold(item->from()->shortName())),
|
||||
Ui::Text::WithEntities)
|
||||
: tr::lng_suggest_decline_text_to(
|
||||
lt_channel,
|
||||
rpl::single(Ui::Text::Bold(channelName)),
|
||||
Ui::Text::WithEntities)),
|
||||
.confirmed = [=](Fn<void()> close) { (*callback)(); close(); },
|
||||
.confirmText = tr::lng_suggest_action_decline(),
|
||||
.confirmStyle = &st::attentionBoxButton,
|
||||
.title = tr::lng_suggest_decline_title(),
|
||||
});
|
||||
const auto reason = box->addRow(object_ptr<Ui::InputField>(
|
||||
box,
|
||||
st::factcheckField,
|
||||
Ui::InputField::Mode::NoNewlines,
|
||||
tr::lng_suggest_decline_reason()));
|
||||
box->setFocusCallback([=] {
|
||||
reason->setFocusFast();
|
||||
});
|
||||
*callback = [=, weak = base::make_weak(box)] {
|
||||
const auto item = show->session().data().message(id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
SendDecline(show, item, reason->getLastText().trimmed());
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
reason->submits(
|
||||
) | rpl::start_with_next([=](Qt::KeyboardModifiers modifiers) {
|
||||
if (!(modifiers & Qt::ShiftModifier)) {
|
||||
(*callback)();
|
||||
}
|
||||
}, box->lifetime());
|
||||
}));
|
||||
}
|
||||
|
||||
struct SendSuggestState {
|
||||
SendPaymentHelper sendPayment;
|
||||
};
|
||||
void SendSuggest(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item,
|
||||
std::shared_ptr<SendSuggestState> state,
|
||||
Fn<void(SuggestPostOptions&)> modify,
|
||||
Fn<void()> done = nullptr,
|
||||
int starsApproved = 0) {
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
const auto id = item->fullId();
|
||||
const auto withPaymentApproved = [=](int stars) {
|
||||
if (const auto item = show->session().data().message(id)) {
|
||||
SendSuggest(show, item, state, modify, done, stars);
|
||||
}
|
||||
};
|
||||
const auto isForward = item->Get<HistoryMessageForwarded>();
|
||||
auto action = SendAction(item->history());
|
||||
action.options.suggest.exists = 1;
|
||||
if (suggestion) {
|
||||
action.options.suggest.date = suggestion->date;
|
||||
action.options.suggest.priceWhole = suggestion->price.whole();
|
||||
action.options.suggest.priceNano = suggestion->price.nano();
|
||||
action.options.suggest.ton = suggestion->price.ton() ? 1 : 0;
|
||||
}
|
||||
modify(action.options.suggest);
|
||||
action.options.starsApproved = starsApproved;
|
||||
action.replyTo.monoforumPeerId = item->history()->amMonoforumAdmin()
|
||||
? item->sublistPeerId()
|
||||
: PeerId();
|
||||
action.replyTo.messageId = item->fullId();
|
||||
|
||||
const auto checked = state->sendPayment.check(
|
||||
show,
|
||||
item->history()->peer,
|
||||
action.options,
|
||||
1,
|
||||
withPaymentApproved);
|
||||
if (!checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
show->session().api().sendAction(action);
|
||||
show->session().api().forwardMessages({
|
||||
.items = { item },
|
||||
.options = (isForward
|
||||
? Data::ForwardOptions::PreserveInfo
|
||||
: Data::ForwardOptions::NoSenderNames),
|
||||
}, action);
|
||||
if (const auto onstack = done) {
|
||||
onstack();
|
||||
}
|
||||
}
|
||||
|
||||
void SuggestApprovalDate(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item) {
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (!suggestion) {
|
||||
return;
|
||||
}
|
||||
const auto id = item->fullId();
|
||||
const auto state = std::make_shared<SendSuggestState>();
|
||||
const auto weak = std::make_shared<base::weak_qptr<Ui::BoxContent>>();
|
||||
const auto done = [=](TimeId result) {
|
||||
const auto item = show->session().data().message(id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const auto close = [=] {
|
||||
if (const auto strong = weak->get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
SendSuggest(
|
||||
show,
|
||||
item,
|
||||
state,
|
||||
[=](SuggestPostOptions &options) { options.date = result; },
|
||||
close);
|
||||
};
|
||||
using namespace HistoryView;
|
||||
auto dateBox = Box(ChooseSuggestTimeBox, SuggestTimeBoxArgs{
|
||||
.session = &show->session(),
|
||||
.done = done,
|
||||
.value = suggestion->date,
|
||||
.mode = SuggestMode::Change,
|
||||
});
|
||||
*weak = dateBox.data();
|
||||
show->show(std::move(dateBox));
|
||||
}
|
||||
|
||||
void SuggestOfferForMessage(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item,
|
||||
SuggestPostOptions values,
|
||||
HistoryView::SuggestMode mode) {
|
||||
const auto id = item->fullId();
|
||||
const auto state = std::make_shared<SendSuggestState>();
|
||||
const auto weak = std::make_shared<base::weak_qptr<Ui::BoxContent>>();
|
||||
const auto done = [=](SuggestPostOptions result) {
|
||||
const auto item = show->session().data().message(id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const auto close = [=] {
|
||||
if (const auto strong = weak->get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
SendSuggest(
|
||||
show,
|
||||
item,
|
||||
state,
|
||||
[=](SuggestPostOptions &options) { options = result; },
|
||||
close);
|
||||
};
|
||||
using namespace HistoryView;
|
||||
auto priceBox = Box(ChooseSuggestPriceBox, SuggestPriceBoxArgs{
|
||||
.peer = item->history()->peer,
|
||||
.done = done,
|
||||
.value = values,
|
||||
.mode = mode,
|
||||
});
|
||||
*weak = priceBox.data();
|
||||
show->show(std::move(priceBox));
|
||||
}
|
||||
|
||||
void SuggestApprovalPrice(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
not_null<HistoryItem*> item) {
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (!suggestion) {
|
||||
return;
|
||||
}
|
||||
using namespace HistoryView;
|
||||
SuggestOfferForMessage(show, item, {
|
||||
.exists = uint32(1),
|
||||
.priceWhole = uint32(suggestion->price.whole()),
|
||||
.priceNano = uint32(suggestion->price.nano()),
|
||||
.ton = uint32(suggestion->price.ton() ? 1 : 0),
|
||||
.date = suggestion->date,
|
||||
}, SuggestMode::Change);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<ClickHandler> AcceptClickHandler(
|
||||
not_null<HistoryItem*> item) {
|
||||
const auto session = &item->history()->session();
|
||||
const auto id = item->fullId();
|
||||
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
const auto controller = my.sessionWindow.get();
|
||||
if (!controller || &controller->session() != session) {
|
||||
return;
|
||||
}
|
||||
const auto item = session->data().message(id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const auto show = controller->uiShow();
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (!suggestion) {
|
||||
return;
|
||||
} else if (!suggestion->date) {
|
||||
RequestApprovalDate(show, item);
|
||||
} else {
|
||||
ConfirmApproval(show, item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<ClickHandler> DeclineClickHandler(
|
||||
not_null<HistoryItem*> item) {
|
||||
const auto session = &item->history()->session();
|
||||
const auto id = item->fullId();
|
||||
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
const auto controller = my.sessionWindow.get();
|
||||
if (!controller || &controller->session() != session) {
|
||||
return;
|
||||
}
|
||||
const auto item = session->data().message(id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
RequestDeclineComment(controller->uiShow(), item);
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<ClickHandler> SuggestChangesClickHandler(
|
||||
not_null<HistoryItem*> item) {
|
||||
const auto session = &item->history()->session();
|
||||
const auto id = item->fullId();
|
||||
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
const auto window = my.sessionWindow.get();
|
||||
if (!window || &window->session() != session) {
|
||||
return;
|
||||
}
|
||||
const auto item = session->data().message(id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const auto menu = Ui::CreateChild<Ui::PopupMenu>(
|
||||
window->widget(),
|
||||
st::popupMenuWithIcons);
|
||||
if (HistoryView::CanEditSuggestedMessage(item)) {
|
||||
menu->addAction(tr::lng_suggest_menu_edit_message(tr::now), [=] {
|
||||
const auto item = session->data().message(id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const auto suggestion = item->Get<HistoryMessageSuggestedPost>();
|
||||
if (!suggestion) {
|
||||
return;
|
||||
}
|
||||
const auto history = item->history();
|
||||
const auto editData = PrepareEditText(item);
|
||||
const auto cursor = MessageCursor{
|
||||
int(editData.text.size()),
|
||||
int(editData.text.size()),
|
||||
Ui::kQFixedMax
|
||||
};
|
||||
const auto monoforumPeerId = history->amMonoforumAdmin()
|
||||
? item->sublistPeerId()
|
||||
: PeerId();
|
||||
const auto previewDraft = Data::WebPageDraft::FromItem(item);
|
||||
history->setLocalEditDraft(std::make_unique<Data::Draft>(
|
||||
editData,
|
||||
FullReplyTo{
|
||||
.messageId = FullMsgId(history->peer->id, item->id),
|
||||
.monoforumPeerId = monoforumPeerId,
|
||||
},
|
||||
SuggestPostOptions{
|
||||
.exists = uint32(1),
|
||||
.priceWhole = uint32(suggestion->price.whole()),
|
||||
.priceNano = uint32(suggestion->price.nano()),
|
||||
.ton = uint32(suggestion->price.ton() ? 1 : 0),
|
||||
.date = suggestion->date,
|
||||
},
|
||||
cursor,
|
||||
previewDraft));
|
||||
history->session().changes().entryUpdated(
|
||||
(monoforumPeerId
|
||||
? item->savedSublist()
|
||||
: (Data::Thread*)history.get()),
|
||||
Data::EntryUpdate::Flag::LocalDraftSet);
|
||||
}, &st::menuIconEdit);
|
||||
}
|
||||
menu->addAction(tr::lng_suggest_menu_edit_price(tr::now), [=] {
|
||||
if (const auto item = session->data().message(id)) {
|
||||
SuggestApprovalPrice(window->uiShow(), item);
|
||||
}
|
||||
}, &st::menuIconTagSell);
|
||||
menu->addAction(tr::lng_suggest_menu_edit_time(tr::now), [=] {
|
||||
if (const auto item = session->data().message(id)) {
|
||||
SuggestApprovalDate(window->uiShow(), item);
|
||||
}
|
||||
}, &st::menuIconSchedule);
|
||||
menu->popup(QCursor::pos());
|
||||
});
|
||||
}
|
||||
|
||||
void AddOfferToMessage(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
FullMsgId itemId) {
|
||||
const auto session = &show->session();
|
||||
const auto item = session->data().message(itemId);
|
||||
if (!item || !HistoryView::CanAddOfferToMessage(item)) {
|
||||
return;
|
||||
}
|
||||
SuggestOfferForMessage(show, item, {}, HistoryView::SuggestMode::New);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
29
Telegram/SourceFiles/api/api_suggest_post.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class ClickHandler;
|
||||
|
||||
namespace Main {
|
||||
class SessionShow;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
[[nodiscard]] std::shared_ptr<ClickHandler> AcceptClickHandler(
|
||||
not_null<HistoryItem*> item);
|
||||
[[nodiscard]] std::shared_ptr<ClickHandler> DeclineClickHandler(
|
||||
not_null<HistoryItem*> item);
|
||||
[[nodiscard]] std::shared_ptr<ClickHandler> SuggestChangesClickHandler(
|
||||
not_null<HistoryItem*> item);
|
||||
|
||||
void AddOfferToMessage(
|
||||
std::shared_ptr<Main::SessionShow> show,
|
||||
FullMsgId itemId);
|
||||
|
||||
} // namespace Api
|
||||
257
Telegram/SourceFiles/api/api_todo_lists.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
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_todo_lists.h"
|
||||
|
||||
#include "api/api_editing.h"
|
||||
#include "apiwrap.h"
|
||||
#include "base/random.h"
|
||||
#include "data/business/data_shortcut_messages.h" // ShortcutIdToMTP
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_todo_list.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h" // ShouldSendSilent
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kSendTogglesDelay = 3 * crl::time(1000);
|
||||
|
||||
[[nodiscard]] TimeId UnixtimeFromMsgId(mtpMsgId msgId) {
|
||||
return TimeId(msgId >> 32);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TodoLists::TodoLists(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance())
|
||||
, _sendTimer([=] { sendAccumulatedToggles(false); }) {
|
||||
}
|
||||
|
||||
void TodoLists::create(
|
||||
const TodoListData &data,
|
||||
SendAction action,
|
||||
Fn<void()> done,
|
||||
Fn<void(QString)> fail) {
|
||||
_session->api().sendAction(action);
|
||||
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
const auto topicRootId = action.replyTo.messageId
|
||||
? action.replyTo.topicRootId
|
||||
: 0;
|
||||
const auto monoforumPeerId = action.replyTo.monoforumPeerId;
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (action.replyTo) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||
}
|
||||
const auto clearCloudDraft = action.clearDraft;
|
||||
if (clearCloudDraft) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||
history->clearLocalDraft(topicRootId, monoforumPeerId);
|
||||
history->clearCloudDraft(topicRootId, monoforumPeerId);
|
||||
history->startSavingCloudDraft(topicRootId, monoforumPeerId);
|
||||
}
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
const auto starsPaid = std::min(
|
||||
peer->starsPerMessageChecked(),
|
||||
action.options.starsApproved);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
if (action.options.scheduled) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
}
|
||||
if (action.options.shortcutId) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
|
||||
}
|
||||
if (action.options.effectId) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
}
|
||||
if (action.options.suggest) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_suggested_post;
|
||||
}
|
||||
if (starsPaid) {
|
||||
action.options.starsApproved -= starsPaid;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
|
||||
}
|
||||
const auto sendAs = action.options.sendAs;
|
||||
if (sendAs) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
}
|
||||
auto &histories = history->owner().histories();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
action.replyTo,
|
||||
randomId,
|
||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
Data::Histories::ReplyToPlaceholder(),
|
||||
TodoListDataToInputMedia(&data),
|
||||
MTP_string(),
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(_session, action.options.shortcutId),
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid),
|
||||
SuggestToMTP(action.options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
_session->changes().historyUpdated(
|
||||
history,
|
||||
(action.options.scheduled
|
||||
? Data::HistoryUpdate::Flag::ScheduledSent
|
||||
: Data::HistoryUpdate::Flag::MessageSent));
|
||||
if (const auto onstack = done) {
|
||||
onstack();
|
||||
}
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
if (const auto onstack = fail) {
|
||||
onstack(error.type());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TodoLists::edit(
|
||||
not_null<HistoryItem*> item,
|
||||
const TodoListData &data,
|
||||
SendOptions options,
|
||||
Fn<void()> done,
|
||||
Fn<void(QString)> fail) {
|
||||
EditTodoList(item, data, options, [=](mtpRequestId) {
|
||||
if (const auto onstack = done) {
|
||||
onstack();
|
||||
}
|
||||
}, [=](const QString &error, mtpRequestId) {
|
||||
if (const auto onstack = fail) {
|
||||
onstack(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TodoLists::add(
|
||||
not_null<HistoryItem*> item,
|
||||
const std::vector<TodoListItem> &items,
|
||||
Fn<void()> done,
|
||||
Fn<void(QString)> fail) {
|
||||
if (items.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto session = _session;
|
||||
_session->api().request(MTPmessages_AppendTodoList(
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id.bare),
|
||||
TodoListItemsToMTP(&item->history()->session(), items)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
session->api().applyUpdates(result);
|
||||
if (const auto onstack = done) {
|
||||
onstack();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (const auto onstack = fail) {
|
||||
onstack(error.type());
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
void TodoLists::toggleCompletion(FullMsgId itemId, int id, bool completed) {
|
||||
auto &entry = _toggles[itemId];
|
||||
if (completed) {
|
||||
const auto changed1 = entry.completed.emplace(id).second;
|
||||
const auto changed2 = entry.incompleted.remove(id);
|
||||
if (!changed1 && !changed2) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const auto changed1 = entry.incompleted.emplace(id).second;
|
||||
const auto changed2 = entry.completed.remove(id);
|
||||
if (!changed1 && !changed2) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
entry.scheduled = crl::now();
|
||||
if (!entry.requestId && !_sendTimer.isActive()) {
|
||||
_sendTimer.callOnce(kSendTogglesDelay);
|
||||
}
|
||||
}
|
||||
|
||||
void TodoLists::sendAccumulatedToggles(bool force) {
|
||||
const auto now = crl::now();
|
||||
auto nearest = crl::time(0);
|
||||
for (auto &[itemId, entry] : _toggles) {
|
||||
if (entry.requestId) {
|
||||
continue;
|
||||
}
|
||||
const auto wait = entry.scheduled + kSendTogglesDelay - now;
|
||||
if (wait <= 0) {
|
||||
entry.scheduled = 0;
|
||||
send(itemId, entry);
|
||||
} else if (!nearest || nearest > wait) {
|
||||
nearest = wait;
|
||||
}
|
||||
}
|
||||
if (nearest > 0) {
|
||||
_sendTimer.callOnce(nearest);
|
||||
}
|
||||
}
|
||||
|
||||
void TodoLists::send(FullMsgId itemId, Accumulated &entry) {
|
||||
const auto item = _session->data().message(itemId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
auto completed = entry.completed
|
||||
| ranges::views::transform([](int id) { return MTP_int(id); });
|
||||
auto incompleted = entry.incompleted
|
||||
| ranges::views::transform([](int id) { return MTP_int(id); });
|
||||
entry.requestId = _api.request(MTPmessages_ToggleTodoCompleted(
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTP_vector_from_range(completed),
|
||||
MTP_vector_from_range(incompleted)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_session->api().applyUpdates(result);
|
||||
finishRequest(itemId);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
finishRequest(itemId);
|
||||
}).send();
|
||||
entry.completed.clear();
|
||||
entry.incompleted.clear();
|
||||
}
|
||||
|
||||
void TodoLists::finishRequest(FullMsgId itemId) {
|
||||
auto &entry = _toggles[itemId];
|
||||
entry.requestId = 0;
|
||||
if (entry.completed.empty() && entry.incompleted.empty()) {
|
||||
_toggles.remove(itemId);
|
||||
} else {
|
||||
sendAccumulatedToggles(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
69
Telegram/SourceFiles/api/api_todo_lists.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
class HistoryItem;
|
||||
struct TodoListItem;
|
||||
struct TodoListData;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct SendAction;
|
||||
struct SendOptions;
|
||||
|
||||
class TodoLists final {
|
||||
public:
|
||||
explicit TodoLists(not_null<ApiWrap*> api);
|
||||
|
||||
void create(
|
||||
const TodoListData &data,
|
||||
SendAction action,
|
||||
Fn<void()> done,
|
||||
Fn<void(QString)> fail);
|
||||
void edit(
|
||||
not_null<HistoryItem*> item,
|
||||
const TodoListData &data,
|
||||
SendOptions options,
|
||||
Fn<void()> done,
|
||||
Fn<void(QString)> fail);
|
||||
void add(
|
||||
not_null<HistoryItem*> item,
|
||||
const std::vector<TodoListItem> &items,
|
||||
Fn<void()> done,
|
||||
Fn<void(QString)> fail);
|
||||
void toggleCompletion(FullMsgId itemId, int id, bool completed);
|
||||
|
||||
private:
|
||||
struct Accumulated {
|
||||
base::flat_set<int> completed;
|
||||
base::flat_set<int> incompleted;
|
||||
crl::time scheduled = 0;
|
||||
mtpRequestId requestId = 0;
|
||||
};
|
||||
|
||||
void sendAccumulatedToggles(bool force);
|
||||
void send(FullMsgId itemId, Accumulated &entry);
|
||||
void finishRequest(FullMsgId itemId);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<FullMsgId, Accumulated> _toggles;
|
||||
base::Timer _sendTimer;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_saved_sublist.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "history/history.h"
|
||||
@@ -31,7 +32,9 @@ UnreadThings::UnreadThings(not_null<ApiWrap*> api) : _api(api) {
|
||||
|
||||
bool UnreadThings::trackMentions(Data::Thread *thread) const {
|
||||
const auto peer = thread ? thread->peer().get() : nullptr;
|
||||
return peer && (peer->isChat() || peer->isMegagroup());
|
||||
return peer
|
||||
&& (peer->isChat() || peer->isMegagroup())
|
||||
&& !peer->isMonoforum();
|
||||
}
|
||||
|
||||
bool UnreadThings::trackReactions(Data::Thread *thread) const {
|
||||
@@ -93,7 +96,7 @@ void UnreadThings::cancelRequests(not_null<Data::Thread*> thread) {
|
||||
void UnreadThings::requestMentions(
|
||||
not_null<Data::Thread*> thread,
|
||||
int loaded) {
|
||||
if (_mentionsRequests.contains(thread)) {
|
||||
if (_mentionsRequests.contains(thread) || thread->asSublist()) {
|
||||
return;
|
||||
}
|
||||
const auto offsetId = std::max(
|
||||
@@ -138,12 +141,15 @@ void UnreadThings::requestReactions(
|
||||
const auto maxId = 0;
|
||||
const auto minId = 0;
|
||||
const auto history = thread->owningHistory();
|
||||
const auto sublist = thread->asSublist();
|
||||
const auto topic = thread->asTopic();
|
||||
using Flag = MTPmessages_GetUnreadReactions::Flag;
|
||||
const auto requestId = _api->request(MTPmessages_GetUnreadReactions(
|
||||
MTP_flags(topic ? Flag::f_top_msg_id : Flag()),
|
||||
MTP_flags((topic ? Flag::f_top_msg_id : Flag())
|
||||
| (sublist ? Flag::f_saved_peer_id : Flag())),
|
||||
history->peer->input,
|
||||
MTP_int(topic ? topic->rootId() : 0),
|
||||
(sublist ? sublist->sublistPeer()->input : MTPInputPeer()),
|
||||
MTP_int(offsetId),
|
||||
MTP_int(addOffset),
|
||||
MTP_int(limit),
|
||||
|
||||
@@ -1228,7 +1228,8 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
MTPlong(), // effect
|
||||
MTPFactCheck(),
|
||||
MTPint(), // report_delivery_until_date
|
||||
MTPlong()), // paid_message_stars
|
||||
MTPlong(), // paid_message_stars
|
||||
MTPSuggestedPost()),
|
||||
MessageFlags(),
|
||||
NewMessageType::Unread);
|
||||
} break;
|
||||
@@ -1267,7 +1268,8 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
MTPlong(), // effect
|
||||
MTPFactCheck(),
|
||||
MTPint(), // report_delivery_until_date
|
||||
MTPlong()), // paid_message_stars
|
||||
MTPlong(), // paid_message_stars
|
||||
MTPSuggestedPost()),
|
||||
MessageFlags(),
|
||||
NewMessageType::Unread);
|
||||
} break;
|
||||
@@ -1916,7 +1918,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
// Update web page anyway.
|
||||
session().data().processWebpage(d.vwebpage());
|
||||
session().data().sendWebPageGamePollNotifications();
|
||||
session().data().sendWebPageGamePollTodoListNotifications();
|
||||
|
||||
updateAndApply(d.vpts().v, d.vpts_count().v, update);
|
||||
} break;
|
||||
@@ -1926,7 +1928,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
// Update web page anyway.
|
||||
session().data().processWebpage(d.vwebpage());
|
||||
session().data().sendWebPageGamePollNotifications();
|
||||
session().data().sendWebPageGamePollTodoListNotifications();
|
||||
|
||||
auto channel = session().data().channelLoaded(d.vchannel_id());
|
||||
if (channel && !_handlingChannelDifference) {
|
||||
@@ -2442,6 +2444,32 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
session().data().updateRepliesReadTill({ id, readTillId, true });
|
||||
} break;
|
||||
|
||||
case mtpc_updateReadMonoForumInbox: {
|
||||
const auto &d = update.c_updateReadMonoForumInbox();
|
||||
const auto parentChatId = ChannelId(d.vchannel_id());
|
||||
const auto sublistPeerId = peerFromMTP(d.vsaved_peer_id());
|
||||
const auto readTillId = d.vread_max_id().v;
|
||||
session().data().updateSublistReadTill({
|
||||
parentChatId,
|
||||
sublistPeerId,
|
||||
readTillId,
|
||||
false,
|
||||
});
|
||||
} break;
|
||||
|
||||
case mtpc_updateReadMonoForumOutbox: {
|
||||
const auto &d = update.c_updateReadMonoForumOutbox();
|
||||
const auto parentChatId = ChannelId(d.vchannel_id());
|
||||
const auto sublistPeerId = peerFromMTP(d.vsaved_peer_id());
|
||||
const auto readTillId = d.vread_max_id().v;
|
||||
session().data().updateSublistReadTill({
|
||||
parentChatId,
|
||||
sublistPeerId,
|
||||
readTillId,
|
||||
true,
|
||||
});
|
||||
} break;
|
||||
|
||||
case mtpc_updateChannelAvailableMessages: {
|
||||
auto &d = update.c_updateChannelAvailableMessages();
|
||||
if (const auto channel = session().data().channelLoaded(d.vchannel_id())) {
|
||||
@@ -2661,13 +2689,22 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
const auto &data = update.c_updateDraftMessage();
|
||||
const auto peerId = peerFromMTP(data.vpeer());
|
||||
const auto topicRootId = data.vtop_msg_id().value_or_empty();
|
||||
const auto monoforumPeerId = data.vsaved_peer_id()
|
||||
? peerFromMTP(*data.vsaved_peer_id())
|
||||
: PeerId();
|
||||
data.vdraft().match([&](const MTPDdraftMessage &data) {
|
||||
Data::ApplyPeerCloudDraft(&session(), peerId, topicRootId, data);
|
||||
Data::ApplyPeerCloudDraft(
|
||||
&session(),
|
||||
peerId,
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
data);
|
||||
}, [&](const MTPDdraftMessageEmpty &data) {
|
||||
Data::ClearPeerCloudDraft(
|
||||
&session(),
|
||||
peerId,
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
data.vdate().value_or_empty());
|
||||
});
|
||||
} break;
|
||||
|
||||
@@ -240,13 +240,13 @@ struct State {
|
||||
[[nodiscard]] rpl::producer<Peers> WhoReadIds(
|
||||
not_null<HistoryItem*> item,
|
||||
not_null<QWidget*> context) {
|
||||
auto weak = QPointer<QWidget>(context.get());
|
||||
auto weak = base::make_weak(context);
|
||||
const auto session = &item->history()->session();
|
||||
return [=](auto consumer) {
|
||||
if (!weak) {
|
||||
return rpl::lifetime();
|
||||
}
|
||||
const auto context = PreparedContextAt(weak.data(), session);
|
||||
const auto context = PreparedContextAt(weak.get(), session);
|
||||
auto &entry = context->cacheRead(item);
|
||||
if (entry.requestId) {
|
||||
} else if (const auto user = item->history()->peer->asUser()) {
|
||||
@@ -325,13 +325,13 @@ struct State {
|
||||
not_null<HistoryItem*> item,
|
||||
const ReactionId &reaction,
|
||||
not_null<QWidget*> context) {
|
||||
auto weak = QPointer<QWidget>(context.get());
|
||||
auto weak = base::make_weak(context);
|
||||
const auto session = &item->history()->session();
|
||||
return [=](auto consumer) {
|
||||
if (!weak) {
|
||||
return rpl::lifetime();
|
||||
}
|
||||
const auto context = PreparedContextAt(weak.data(), session);
|
||||
const auto context = PreparedContextAt(weak.get(), session);
|
||||
auto &entry = context->cacheReacted(item, reaction);
|
||||
if (!entry.requestId) {
|
||||
using Flag = MTPmessages_GetMessageReactionsList::Flag;
|
||||
@@ -712,7 +712,8 @@ bool WhoReadExists(not_null<HistoryItem*> item) {
|
||||
const auto megagroup = peer->asMegagroup();
|
||||
if ((!chat && !megagroup)
|
||||
|| (megagroup
|
||||
&& (megagroup->flags() & ChannelDataFlag::ParticipantsHidden))) {
|
||||
&& (megagroup->flags() & ChannelDataFlag::ParticipantsHidden))
|
||||
|| (megagroup && megagroup->isMonoforum())) {
|
||||
return false;
|
||||
}
|
||||
const auto &appConfig = peer->session().appConfig();
|
||||
|
||||
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_polls.h"
|
||||
#include "api/api_sending.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_todo_lists.h"
|
||||
#include "api/api_self_destruct.h"
|
||||
#include "api/api_sensitive_content.h"
|
||||
#include "api/api_global_privacy.h"
|
||||
@@ -42,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_saved_messages.h"
|
||||
#include "data/data_saved_sublist.h"
|
||||
#include "data/data_search_controller.h"
|
||||
#include "data/data_session.h"
|
||||
@@ -177,6 +179,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
, _confirmPhone(std::make_unique<Api::ConfirmPhone>(this))
|
||||
, _peerPhoto(std::make_unique<Api::PeerPhoto>(this))
|
||||
, _polls(std::make_unique<Api::Polls>(this))
|
||||
, _todoLists(std::make_unique<Api::TodoLists>(this))
|
||||
, _chatParticipants(std::make_unique<Api::ChatParticipants>(this))
|
||||
, _unreadThings(std::make_unique<Api::UnreadThings>(this))
|
||||
, _ringtones(std::make_unique<Api::Ringtones>(this))
|
||||
@@ -321,7 +324,7 @@ void ApiWrap::checkChatInvite(
|
||||
request(base::take(_checkInviteRequestId)).cancel();
|
||||
_checkInviteRequestId = request(MTPmessages_CheckChatInvite(
|
||||
MTP_string(hash)
|
||||
)).done(std::move(done)).fail(std::move(fail)).send();
|
||||
)).done(std::move(done)).fail(std::move(fail)).handleFloodErrors().send();
|
||||
}
|
||||
|
||||
void ApiWrap::checkFilterInvite(
|
||||
@@ -381,10 +384,13 @@ void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
|
||||
}
|
||||
|
||||
void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) {
|
||||
if (saved->parentChat()) {
|
||||
return;
|
||||
}
|
||||
const auto &order = _session->data().pinnedChatsOrder(saved);
|
||||
const auto input = [](Dialogs::Key key) {
|
||||
if (const auto sublist = key.sublist()) {
|
||||
return MTP_inputDialogPeer(sublist->peer()->input);
|
||||
return MTP_inputDialogPeer(sublist->sublistPeer()->input);
|
||||
}
|
||||
Unexpected("Key type in pinnedDialogsOrder().");
|
||||
};
|
||||
@@ -1369,6 +1375,32 @@ void ApiWrap::deleteAllFromParticipantSend(
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::deleteSublistHistory(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> sublistPeer) {
|
||||
deleteSublistHistorySend(channel, sublistPeer);
|
||||
}
|
||||
|
||||
void ApiWrap::deleteSublistHistorySend(
|
||||
not_null<ChannelData*> parentChat,
|
||||
not_null<PeerData*> sublistPeer) {
|
||||
request(MTPmessages_DeleteSavedHistory(
|
||||
MTP_flags(MTPmessages_DeleteSavedHistory::Flag::f_parent_peer),
|
||||
parentChat->input,
|
||||
sublistPeer->input,
|
||||
MTP_int(0), // max_id
|
||||
MTP_int(0), // min_date
|
||||
MTP_int(0) // max_date
|
||||
)).done([=](const MTPmessages_AffectedHistory &result) {
|
||||
const auto offset = applyAffectedHistory(parentChat, result);
|
||||
if (offset > 0) {
|
||||
deleteSublistHistorySend(parentChat, sublistPeer);
|
||||
} else if (const auto monoforum = parentChat->monoforum()) {
|
||||
monoforum->applySublistDeleted(sublistPeer);
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) {
|
||||
if (!_stickerSetRequests.contains(setId)) {
|
||||
_stickerSetRequests.emplace(setId, StickerSetRequest{ access });
|
||||
@@ -2060,8 +2092,13 @@ void ApiWrap::saveCurrentDraftToCloud() {
|
||||
_session->local().writeDrafts(history);
|
||||
|
||||
const auto topicRootId = thread->topicRootId();
|
||||
const auto localDraft = history->localDraft(topicRootId);
|
||||
const auto cloudDraft = history->cloudDraft(topicRootId);
|
||||
const auto monoforumPeerId = thread->monoforumPeerId();
|
||||
const auto localDraft = history->localDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId);
|
||||
const auto cloudDraft = history->cloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId);
|
||||
if (!Data::DraftsAreEqual(localDraft, cloudDraft)
|
||||
&& !_session->supportMode()) {
|
||||
saveDraftToCloudDelayed(thread);
|
||||
@@ -2084,15 +2121,22 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
|
||||
const auto history = thread->owningHistory();
|
||||
const auto topicRootId = thread->topicRootId();
|
||||
auto cloudDraft = history->cloudDraft(topicRootId);
|
||||
auto localDraft = history->localDraft(topicRootId);
|
||||
const auto monoforumPeerId = thread->monoforumPeerId();
|
||||
auto cloudDraft = history->cloudDraft(topicRootId, monoforumPeerId);
|
||||
auto localDraft = history->localDraft(topicRootId, monoforumPeerId);
|
||||
if (cloudDraft && cloudDraft->saveRequestId) {
|
||||
request(base::take(cloudDraft->saveRequestId)).cancel();
|
||||
}
|
||||
if (!_session->supportMode()) {
|
||||
cloudDraft = history->createCloudDraft(topicRootId, localDraft);
|
||||
cloudDraft = history->createCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
localDraft);
|
||||
} else if (!cloudDraft) {
|
||||
cloudDraft = history->createCloudDraft(topicRootId, nullptr);
|
||||
cloudDraft = history->createCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
auto flags = MTPmessages_SaveDraft::Flags(0);
|
||||
@@ -2102,18 +2146,23 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
} else if (!cloudDraft->webpage.url.isEmpty()) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_media;
|
||||
}
|
||||
if (cloudDraft->reply.messageId || cloudDraft->reply.topicRootId) {
|
||||
if (cloudDraft->reply.messageId
|
||||
|| cloudDraft->reply.topicRootId
|
||||
|| cloudDraft->reply.monoforumPeerId) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_reply_to;
|
||||
}
|
||||
if (!textWithTags.tags.isEmpty()) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_entities;
|
||||
}
|
||||
if (cloudDraft->suggest) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_suggested_post;
|
||||
}
|
||||
auto entities = Api::EntitiesToMTP(
|
||||
_session,
|
||||
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags),
|
||||
Api::ConvertOption::SkipLocal);
|
||||
|
||||
history->startSavingCloudDraft(topicRootId);
|
||||
history->startSavingCloudDraft(topicRootId, monoforumPeerId);
|
||||
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
|
||||
MTP_flags(flags),
|
||||
ReplyToForMTP(history, cloudDraft->reply),
|
||||
@@ -2123,16 +2172,21 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
Data::WebPageForMTP(
|
||||
cloudDraft->webpage,
|
||||
textWithTags.text.isEmpty()),
|
||||
MTP_long(0) // effect
|
||||
MTP_long(0), // effect
|
||||
Api::SuggestToMTP(cloudDraft->suggest)
|
||||
)).done([=](const MTPBool &result, const MTP::Response &response) {
|
||||
const auto requestId = response.requestId;
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
if (const auto cloudDraft = history->cloudDraft(topicRootId)) {
|
||||
const auto cloudDraft = history->cloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId);
|
||||
if (cloudDraft) {
|
||||
if (cloudDraft->saveRequestId == requestId) {
|
||||
cloudDraft->saveRequestId = 0;
|
||||
history->draftSavedToCloud(topicRootId);
|
||||
history->draftSavedToCloud(topicRootId, monoforumPeerId);
|
||||
}
|
||||
}
|
||||
const auto i = _draftsSaveRequestIds.find(weak);
|
||||
@@ -2145,10 +2199,14 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
const auto requestId = response.requestId;
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
if (const auto cloudDraft = history->cloudDraft(topicRootId)) {
|
||||
const auto cloudDraft = history->cloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId);
|
||||
if (cloudDraft) {
|
||||
if (cloudDraft->saveRequestId == requestId) {
|
||||
history->clearCloudDraft(topicRootId);
|
||||
history->clearCloudDraft(topicRootId, monoforumPeerId);
|
||||
}
|
||||
}
|
||||
const auto i = _draftsSaveRequestIds.find(weak);
|
||||
@@ -2522,7 +2580,10 @@ void ApiWrap::refreshFileReference(
|
||||
});
|
||||
}
|
||||
|
||||
void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req) {
|
||||
void ApiWrap::gotWebPages(
|
||||
ChannelData *channel,
|
||||
const MTPmessages_Messages &result,
|
||||
mtpRequestId req) {
|
||||
WebPageData::ApplyChanges(_session, channel, result);
|
||||
for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend();) {
|
||||
if (i->second == req) {
|
||||
@@ -2536,7 +2597,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &resu
|
||||
++i;
|
||||
}
|
||||
}
|
||||
_session->data().sendWebPageGamePollNotifications();
|
||||
_session->data().sendWebPageGamePollTodoListNotifications();
|
||||
}
|
||||
|
||||
void ApiWrap::updateStickers() {
|
||||
@@ -2926,17 +2987,27 @@ void ApiWrap::resolveJumpToDate(
|
||||
Fn<void(not_null<PeerData*>, MsgId)> callback) {
|
||||
if (const auto peer = chat.peer()) {
|
||||
const auto topic = chat.topic();
|
||||
const auto rootId = topic ? topic->rootId() : 0;
|
||||
resolveJumpToHistoryDate(peer, rootId, date, std::move(callback));
|
||||
const auto sublist = chat.sublist();
|
||||
const auto rootId = topic ? topic->rootId() : MsgId();
|
||||
const auto monoforumPeerId = sublist
|
||||
? sublist->sublistPeer()->id
|
||||
: PeerId();
|
||||
resolveJumpToHistoryDate(
|
||||
peer,
|
||||
rootId,
|
||||
monoforumPeerId,
|
||||
date,
|
||||
std::move(callback));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void ApiWrap::requestMessageAfterDate(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
const QDate &date,
|
||||
Callback &&callback) {
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
const QDate &date,
|
||||
Callback &&callback) {
|
||||
// API returns a message with date <= offset_date.
|
||||
// So we request a message with offset_date = desired_date - 1 and add_offset = -1.
|
||||
// This should give us the first message with date >= desired_date.
|
||||
@@ -2959,7 +3030,7 @@ void ApiWrap::requestMessageAfterDate(
|
||||
return &messages.vmessages().v;
|
||||
};
|
||||
const auto list = result.match([&](
|
||||
const MTPDmessages_messages &data) {
|
||||
const MTPDmessages_messages &data) {
|
||||
return handleMessages(data);
|
||||
}, [&](const MTPDmessages_messagesSlice &data) {
|
||||
return handleMessages(data);
|
||||
@@ -3002,6 +3073,18 @@ void ApiWrap::requestMessageAfterDate(
|
||||
MTP_int(maxId),
|
||||
MTP_int(minId),
|
||||
MTP_long(historyHash)));
|
||||
} else if (monoforumPeerId) {
|
||||
send(MTPmessages_GetSavedHistory(
|
||||
MTP_flags(MTPmessages_GetSavedHistory::Flag::f_parent_peer),
|
||||
peer->input,
|
||||
session().data().peer(monoforumPeerId)->input,
|
||||
MTP_int(offsetId),
|
||||
MTP_int(offsetDate),
|
||||
MTP_int(addOffset),
|
||||
MTP_int(limit),
|
||||
MTP_int(maxId),
|
||||
MTP_int(minId),
|
||||
MTP_long(historyHash)));
|
||||
} else {
|
||||
send(MTPmessages_GetHistory(
|
||||
peer->input,
|
||||
@@ -3018,28 +3101,41 @@ void ApiWrap::requestMessageAfterDate(
|
||||
void ApiWrap::resolveJumpToHistoryDate(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
const QDate &date,
|
||||
Fn<void(not_null<PeerData*>, MsgId)> callback) {
|
||||
if (const auto channel = peer->migrateTo()) {
|
||||
return resolveJumpToHistoryDate(
|
||||
channel,
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
date,
|
||||
std::move(callback));
|
||||
}
|
||||
const auto jumpToDateInPeer = [=] {
|
||||
requestMessageAfterDate(peer, topicRootId, date, [=](MsgId itemId) {
|
||||
callback(peer, itemId);
|
||||
});
|
||||
requestMessageAfterDate(
|
||||
peer,
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
date,
|
||||
[=](MsgId itemId) { callback(peer, itemId); });
|
||||
};
|
||||
if (const auto chat = topicRootId ? nullptr : peer->migrateFrom()) {
|
||||
requestMessageAfterDate(chat, 0, date, [=](MsgId itemId) {
|
||||
if (itemId) {
|
||||
callback(chat, itemId);
|
||||
} else {
|
||||
jumpToDateInPeer();
|
||||
}
|
||||
});
|
||||
const auto migrated = (topicRootId || monoforumPeerId)
|
||||
? nullptr
|
||||
: peer->migrateFrom();
|
||||
if (migrated) {
|
||||
requestMessageAfterDate(
|
||||
migrated,
|
||||
MsgId(),
|
||||
PeerId(),
|
||||
date,
|
||||
[=](MsgId itemId) {
|
||||
if (itemId) {
|
||||
callback(migrated, itemId);
|
||||
} else {
|
||||
jumpToDateInPeer();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
jumpToDateInPeer();
|
||||
}
|
||||
@@ -3088,12 +3184,14 @@ void ApiWrap::requestHistory(
|
||||
void ApiWrap::requestSharedMedia(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
SharedMediaType type,
|
||||
MsgId messageId,
|
||||
SliceType slice) {
|
||||
const auto key = SharedMediaRequest{
|
||||
peer,
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
type,
|
||||
messageId,
|
||||
slice,
|
||||
@@ -3105,6 +3203,7 @@ void ApiWrap::requestSharedMedia(
|
||||
const auto prepared = Api::PrepareSearchRequest(
|
||||
peer,
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
type,
|
||||
QString(),
|
||||
messageId,
|
||||
@@ -3127,7 +3226,12 @@ void ApiWrap::requestSharedMedia(
|
||||
messageId,
|
||||
slice,
|
||||
result);
|
||||
sharedMediaDone(peer, topicRootId, type, std::move(parsed));
|
||||
sharedMediaDone(
|
||||
peer,
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
type,
|
||||
std::move(parsed));
|
||||
finish();
|
||||
}).fail([=] {
|
||||
_sharedMediaRequests.remove(key);
|
||||
@@ -3140,16 +3244,19 @@ void ApiWrap::requestSharedMedia(
|
||||
void ApiWrap::sharedMediaDone(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
SharedMediaType type,
|
||||
Api::SearchResult &&parsed) {
|
||||
const auto topic = peer->forumTopicFor(topicRootId);
|
||||
if (topicRootId && !topic) {
|
||||
const auto sublist = peer->monoforumSublistFor(monoforumPeerId);
|
||||
if ((topicRootId && !topic) || (monoforumPeerId && !sublist)) {
|
||||
return;
|
||||
}
|
||||
const auto hasMessages = !parsed.messageIds.empty();
|
||||
_session->storage().add(Storage::SharedMediaAddSlice(
|
||||
peer->id,
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
type,
|
||||
std::move(parsed.messageIds),
|
||||
parsed.noSkipRange,
|
||||
@@ -3160,6 +3267,9 @@ void ApiWrap::sharedMediaDone(
|
||||
if (topic) {
|
||||
topic->setHasPinnedMessages(true);
|
||||
}
|
||||
if (sublist) {
|
||||
sublist->setHasPinnedMessages(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3196,8 +3306,14 @@ void ApiWrap::sendAction(const SendAction &action) {
|
||||
const auto topic = topicRootId
|
||||
? action.history->peer->forumTopicFor(topicRootId)
|
||||
: nullptr;
|
||||
const auto monoforumPeerId = action.replyTo.monoforumPeerId;
|
||||
const auto sublist = monoforumPeerId
|
||||
? action.history->peer->monoforumSublistFor(monoforumPeerId)
|
||||
: nullptr;
|
||||
if (topic) {
|
||||
topic->readTillEnd();
|
||||
} else if (sublist) {
|
||||
sublist->readTillEnd();
|
||||
} else {
|
||||
_session->data().histories().readInbox(action.history);
|
||||
}
|
||||
@@ -3209,7 +3325,10 @@ void ApiWrap::sendAction(const SendAction &action) {
|
||||
void ApiWrap::finishForwarding(const SendAction &action) {
|
||||
const auto history = action.history;
|
||||
const auto topicRootId = action.replyTo.topicRootId;
|
||||
auto toForward = history->resolveForwardDraft(topicRootId);
|
||||
const auto monoforumPeerId = action.replyTo.monoforumPeerId;
|
||||
auto toForward = history->resolveForwardDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId);
|
||||
if (!toForward.items.empty()) {
|
||||
const auto error = GetErrorForSending(
|
||||
history->peer,
|
||||
@@ -3222,7 +3341,7 @@ void ApiWrap::finishForwarding(const SendAction &action) {
|
||||
}
|
||||
|
||||
forwardMessages(std::move(toForward), action);
|
||||
history->setForwardDraft(topicRootId, {});
|
||||
history->setForwardDraft(topicRootId, monoforumPeerId, {});
|
||||
}
|
||||
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
@@ -3291,6 +3410,9 @@ void ApiWrap::forwardMessages(
|
||||
if (sendAs) {
|
||||
sendFlags |= SendFlag::f_send_as;
|
||||
}
|
||||
if (action.options.suggest) {
|
||||
sendFlags |= SendFlag::f_suggested_post;
|
||||
}
|
||||
const auto kGeneralId = Data::ForumTopic::kGeneralId;
|
||||
const auto topicRootId = action.replyTo.topicRootId;
|
||||
const auto topMsgId = (topicRootId == kGeneralId)
|
||||
@@ -3299,6 +3421,13 @@ void ApiWrap::forwardMessages(
|
||||
if (topMsgId) {
|
||||
sendFlags |= SendFlag::f_top_msg_id;
|
||||
}
|
||||
const auto monoforumPeerId = action.replyTo.monoforumPeerId;
|
||||
const auto monoforumPeer = monoforumPeerId
|
||||
? session().data().peer(monoforumPeerId).get()
|
||||
: nullptr;
|
||||
if (monoforumPeer || (action.options.suggest && action.replyTo)) {
|
||||
sendFlags |= SendFlag::f_reply_to;
|
||||
}
|
||||
|
||||
auto forwardFrom = draft.items.front()->history()->peer;
|
||||
auto ids = QVector<MTPint>();
|
||||
@@ -3328,11 +3457,17 @@ void ApiWrap::forwardMessages(
|
||||
MTP_vector<MTPlong>(randomIds),
|
||||
peer->input,
|
||||
MTP_int(topMsgId),
|
||||
(action.options.suggest
|
||||
? ReplyToForMTP(history, action.replyTo)
|
||||
: monoforumPeer
|
||||
? MTP_inputReplyToMonoForum(monoforumPeer->input)
|
||||
: MTPInputReplyTo()),
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(_session, action.options.shortcutId),
|
||||
MTPint(), // video_timestamp
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
Api::SuggestToMTP(action.options.suggest)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
if (!scheduled) {
|
||||
this->updates().checkForSentToScheduled(result);
|
||||
@@ -3374,12 +3509,15 @@ void ApiWrap::forwardMessages(
|
||||
.id = newId.msg,
|
||||
.flags = flags,
|
||||
.from = NewMessageFromId(action),
|
||||
.replyTo = { .topicRootId = topMsgId },
|
||||
.replyTo = {
|
||||
.topicRootId = topMsgId,
|
||||
.monoforumPeerId = monoforumPeerId,
|
||||
},
|
||||
.date = NewMessageDate(action.options),
|
||||
.shortcutId = action.options.shortcutId,
|
||||
.starsPaid = action.options.starsApproved,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
// forwarded messages don't have effects
|
||||
//.effectId = action.options.effectId,
|
||||
}, item);
|
||||
@@ -3474,6 +3612,7 @@ void ApiWrap::sendSharedContact(
|
||||
.starsPaid = action.options.starsApproved,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, TextWithEntities(), MTP_messageMediaContact(
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
@@ -3522,7 +3661,19 @@ void ApiWrap::editMedia(
|
||||
if (list.files.empty()) return;
|
||||
|
||||
auto &file = list.files.front();
|
||||
const auto to = FileLoadTaskOptions(action);
|
||||
auto to = FileLoadTaskOptions(action);
|
||||
const auto existing = to.replaceMediaOf
|
||||
? session().data().message(action.history->peer, to.replaceMediaOf)
|
||||
: nullptr;
|
||||
if (existing && existing->computeSuggestionActions()
|
||||
== SuggestionActions::AcceptAndDecline) {
|
||||
to.replyTo.messageId = {
|
||||
action.history->peer->id,
|
||||
to.replaceMediaOf
|
||||
};
|
||||
to.replyTo.monoforumPeerId = existing->sublistPeerId();
|
||||
to.replaceMediaOf = MsgId();
|
||||
}
|
||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||
&session(),
|
||||
file.path,
|
||||
@@ -3701,6 +3852,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
|
||||
const auto clearCloudDraft = action.clearDraft;
|
||||
const auto draftTopicRootId = action.replyTo.topicRootId;
|
||||
const auto draftMonoforumPeerId = action.replyTo.monoforumPeerId;
|
||||
const auto replyTo = action.replyTo.messageId
|
||||
? peer->owner().message(action.replyTo.messageId)
|
||||
: nullptr;
|
||||
@@ -3810,8 +3962,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
if (clearCloudDraft) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||
history->clearCloudDraft(draftTopicRootId);
|
||||
history->startSavingCloudDraft(draftTopicRootId);
|
||||
history->clearCloudDraft(draftTopicRootId, draftMonoforumPeerId);
|
||||
history->startSavingCloudDraft(
|
||||
draftTopicRootId,
|
||||
draftMonoforumPeerId);
|
||||
}
|
||||
const auto sendAs = action.options.sendAs;
|
||||
if (sendAs) {
|
||||
@@ -3832,6 +3986,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_effect;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
}
|
||||
if (action.options.suggest) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_suggested_post;
|
||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_suggested_post;
|
||||
}
|
||||
const auto starsPaid = std::min(
|
||||
peer->starsPerMessageChecked(),
|
||||
action.options.starsApproved);
|
||||
@@ -3850,6 +4008,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
.starsPaid = starsPaid,
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
.effectId = action.options.effectId,
|
||||
.suggest = HistoryMessageSuggestInfo(action.options),
|
||||
}, sending, media);
|
||||
const auto done = [=](
|
||||
const MTPUpdates &result,
|
||||
@@ -3857,6 +4016,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
draftTopicRootId,
|
||||
draftMonoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
};
|
||||
@@ -3871,6 +4031,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
draftTopicRootId,
|
||||
draftMonoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
};
|
||||
@@ -3897,7 +4058,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
mtpShortcut,
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
Api::SuggestToMTP(action.options.suggest)
|
||||
), done, fail);
|
||||
} else {
|
||||
histories.sendPreparedMessage(
|
||||
@@ -3916,7 +4078,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
mtpShortcut,
|
||||
MTP_long(action.options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
Api::SuggestToMTP(action.options.suggest)
|
||||
), done, fail);
|
||||
}
|
||||
isFirst = false;
|
||||
@@ -3989,6 +4152,7 @@ void ApiWrap::sendInlineResult(
|
||||
const auto topicRootId = action.replyTo.messageId
|
||||
? action.replyTo.topicRootId
|
||||
: 0;
|
||||
const auto monoforumPeerId = action.replyTo.monoforumPeerId;
|
||||
|
||||
using SendFlag = MTPmessages_SendInlineBotResult::Flag;
|
||||
auto flags = NewMessageFlags(peer);
|
||||
@@ -4041,8 +4205,8 @@ void ApiWrap::sendInlineResult(
|
||||
.postAuthor = NewMessagePostAuthor(action),
|
||||
});
|
||||
|
||||
history->clearCloudDraft(topicRootId);
|
||||
history->startSavingCloudDraft(topicRootId);
|
||||
history->clearCloudDraft(topicRootId, monoforumPeerId);
|
||||
history->startSavingCloudDraft(topicRootId, monoforumPeerId);
|
||||
|
||||
auto &histories = history->owner().histories();
|
||||
histories.sendPreparedMessage(
|
||||
@@ -4063,6 +4227,7 @@ void ApiWrap::sendInlineResult(
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
if (done) {
|
||||
done(true);
|
||||
@@ -4071,6 +4236,7 @@ void ApiWrap::sendInlineResult(
|
||||
sendMessageFail(error, peer, randomId, newId);
|
||||
history->finishSavingCloudDraft(
|
||||
topicRootId,
|
||||
monoforumPeerId,
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
if (done) {
|
||||
done(false);
|
||||
@@ -4219,6 +4385,7 @@ void ApiWrap::sendMediaWithRandomId(
|
||||
| (options.sendAs ? Flag::f_send_as : Flag(0))
|
||||
| (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0))
|
||||
| (options.effectId ? Flag::f_effect : Flag(0))
|
||||
| (options.suggest ? Flag::f_suggested_post : Flag(0))
|
||||
| (options.invertCaption ? Flag::f_invert_media : Flag(0))
|
||||
| (starsPaid ? Flag::f_allow_paid_stars : Flag(0));
|
||||
|
||||
@@ -4247,7 +4414,8 @@ void ApiWrap::sendMediaWithRandomId(
|
||||
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(_session, options.shortcutId),
|
||||
MTP_long(options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
Api::SuggestToMTP(options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (done) done(true);
|
||||
if (updateRecentStickers) {
|
||||
@@ -4302,6 +4470,7 @@ void ApiWrap::sendMultiPaidMedia(
|
||||
| (options.sendAs ? Flag::f_send_as : Flag(0))
|
||||
| (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0))
|
||||
| (options.effectId ? Flag::f_effect : Flag(0))
|
||||
| (options.suggest ? Flag::f_suggested_post : Flag(0))
|
||||
| (options.invertCaption ? Flag::f_invert_media : Flag(0))
|
||||
| (starsPaid ? Flag::f_allow_paid_stars : Flag(0));
|
||||
|
||||
@@ -4329,7 +4498,8 @@ void ApiWrap::sendMultiPaidMedia(
|
||||
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()),
|
||||
Data::ShortcutIdToMTP(_session, options.shortcutId),
|
||||
MTP_long(options.effectId),
|
||||
MTP_long(starsPaid)
|
||||
MTP_long(starsPaid),
|
||||
Api::SuggestToMTP(options.suggest)
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (const auto album = _sendingAlbums.take(groupId)) {
|
||||
const auto copy = (*album)->items;
|
||||
@@ -4661,6 +4831,10 @@ Api::Polls &ApiWrap::polls() {
|
||||
return *_polls;
|
||||
}
|
||||
|
||||
Api::TodoLists &ApiWrap::todoLists() {
|
||||
return *_todoLists;
|
||||
}
|
||||
|
||||
Api::ChatParticipants &ApiWrap::chatParticipants() {
|
||||
return *_chatParticipants;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ class ConfirmPhone;
|
||||
class PeerPhoto;
|
||||
class PeerColors;
|
||||
class Polls;
|
||||
class TodoLists;
|
||||
class ChatParticipants;
|
||||
class UnreadThings;
|
||||
class Ringtones;
|
||||
@@ -231,6 +232,9 @@ public:
|
||||
void deleteAllFromParticipant(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> from);
|
||||
void deleteSublistHistory(
|
||||
not_null<ChannelData*> parentChat,
|
||||
not_null<PeerData*> sublistPeer);
|
||||
|
||||
void requestWebPageDelayed(not_null<WebPageData*> page);
|
||||
void clearWebPageRequest(not_null<WebPageData*> page);
|
||||
@@ -286,6 +290,7 @@ public:
|
||||
void requestSharedMedia(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
Storage::SharedMediaType type,
|
||||
MsgId messageId,
|
||||
SliceType slice);
|
||||
@@ -409,6 +414,7 @@ public:
|
||||
[[nodiscard]] Api::ConfirmPhone &confirmPhone();
|
||||
[[nodiscard]] Api::PeerPhoto &peerPhoto();
|
||||
[[nodiscard]] Api::Polls &polls();
|
||||
[[nodiscard]] Api::TodoLists &todoLists();
|
||||
[[nodiscard]] Api::ChatParticipants &chatParticipants();
|
||||
[[nodiscard]] Api::UnreadThings &unreadThings();
|
||||
[[nodiscard]] Api::Ringtones &ringtones();
|
||||
@@ -502,18 +508,21 @@ private:
|
||||
void resolveJumpToHistoryDate(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
const QDate &date,
|
||||
Fn<void(not_null<PeerData*>, MsgId)> callback);
|
||||
template <typename Callback>
|
||||
void requestMessageAfterDate(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
const QDate &date,
|
||||
Callback &&callback);
|
||||
|
||||
void sharedMediaDone(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
SharedMediaType type,
|
||||
Api::SearchResult &&parsed);
|
||||
void globalMediaDone(
|
||||
@@ -539,6 +548,9 @@ private:
|
||||
void deleteAllFromParticipantSend(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> from);
|
||||
void deleteSublistHistorySend(
|
||||
not_null<ChannelData*> parentChat,
|
||||
not_null<PeerData*> sublistPeer);
|
||||
|
||||
void uploadAlbumMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
@@ -659,6 +671,7 @@ private:
|
||||
struct SharedMediaRequest {
|
||||
not_null<PeerData*> peer;
|
||||
MsgId topicRootId = 0;
|
||||
PeerId monoforumPeerId = 0;
|
||||
SharedMediaType mediaType = {};
|
||||
MsgId aroundId = 0;
|
||||
SliceType sliceType = {};
|
||||
@@ -753,6 +766,7 @@ private:
|
||||
const std::unique_ptr<Api::ConfirmPhone> _confirmPhone;
|
||||
const std::unique_ptr<Api::PeerPhoto> _peerPhoto;
|
||||
const std::unique_ptr<Api::Polls> _polls;
|
||||
const std::unique_ptr<Api::TodoLists> _todoLists;
|
||||
const std::unique_ptr<Api::ChatParticipants> _chatParticipants;
|
||||
const std::unique_ptr<Api::UnreadThings> _unreadThings;
|
||||
const std::unique_ptr<Api::Ringtones> _ringtones;
|
||||
|
||||
@@ -7,18 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/about_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "core/application.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
@@ -57,78 +55,73 @@ rpl::producer<TextWithEntities> Text3() {
|
||||
|
||||
} // namespace
|
||||
|
||||
AboutBox::AboutBox(QWidget *parent)
|
||||
: _version(this, tr::lng_about_version(tr::now, lt_version, currentVersionText()), st::aboutVersionLink)
|
||||
, _text1(this, Text1(), st::aboutLabel)
|
||||
, _text2(this, Text2(), st::aboutLabel)
|
||||
, _text3(this, Text3(), st::aboutLabel) {
|
||||
}
|
||||
void AboutBox(not_null<Ui::GenericBox*> box) {
|
||||
box->setTitle(rpl::single(u"Telegram Desktop"_q));
|
||||
|
||||
void AboutBox::prepare() {
|
||||
setTitle(rpl::single(u"Telegram Desktop"_q));
|
||||
auto layout = box->verticalLayout();
|
||||
|
||||
addButton(tr::lng_close(), [this] { closeBox(); });
|
||||
const auto version = layout->add(
|
||||
object_ptr<Ui::LinkButton>(
|
||||
box,
|
||||
tr::lng_about_version(
|
||||
tr::now,
|
||||
lt_version,
|
||||
currentVersionText()),
|
||||
st::aboutVersionLink),
|
||||
QMargins(
|
||||
st::boxRowPadding.left(),
|
||||
-st::lineWidth * 3,
|
||||
st::boxRowPadding.right(),
|
||||
st::boxRowPadding.bottom()));
|
||||
version->setClickedCallback([=] {
|
||||
if (cRealAlphaVersion()) {
|
||||
auto url = u"https://tdesktop.com/"_q;
|
||||
if (Platform::IsWindows32Bit()) {
|
||||
url += u"win/%1.zip"_q;
|
||||
} else if (Platform::IsWindows64Bit()) {
|
||||
url += u"win64/%1.zip"_q;
|
||||
} else if (Platform::IsWindowsARM64()) {
|
||||
url += u"winarm/%1.zip"_q;
|
||||
} else if (Platform::IsMac()) {
|
||||
url += u"mac/%1.zip"_q;
|
||||
} else if (Platform::IsLinux()) {
|
||||
url += u"linux/%1.tar.xz"_q;
|
||||
} else {
|
||||
Unexpected("Platform value.");
|
||||
}
|
||||
url = url.arg(u"talpha%1_%2"_q
|
||||
.arg(cRealAlphaVersion())
|
||||
.arg(Core::countAlphaVersionSignature(cRealAlphaVersion())));
|
||||
|
||||
_text1->setLinksTrusted();
|
||||
_text2->setLinksTrusted();
|
||||
_text3->setLinksTrusted();
|
||||
QGuiApplication::clipboard()->setText(url);
|
||||
|
||||
_version->setClickedCallback([this] { showVersionHistory(); });
|
||||
|
||||
setDimensions(st::aboutWidth, st::aboutTextTop + _text1->height() + st::aboutSkip + _text2->height() + st::aboutSkip + _text3->height());
|
||||
}
|
||||
|
||||
void AboutBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
const auto available = width()
|
||||
- st::boxPadding.left()
|
||||
- st::boxPadding.right();
|
||||
_version->moveToLeft(st::boxPadding.left(), st::aboutVersionTop);
|
||||
_text1->resizeToWidth(available);
|
||||
_text1->moveToLeft(st::boxPadding.left(), st::aboutTextTop);
|
||||
_text2->resizeToWidth(available);
|
||||
_text2->moveToLeft(st::boxPadding.left(), _text1->y() + _text1->height() + st::aboutSkip);
|
||||
_text3->resizeToWidth(available);
|
||||
_text3->moveToLeft(st::boxPadding.left(), _text2->y() + _text2->height() + st::aboutSkip);
|
||||
}
|
||||
|
||||
void AboutBox::showVersionHistory() {
|
||||
if (cRealAlphaVersion()) {
|
||||
auto url = u"https://tdesktop.com/"_q;
|
||||
if (Platform::IsWindows32Bit()) {
|
||||
url += u"win/%1.zip"_q;
|
||||
} else if (Platform::IsWindows64Bit()) {
|
||||
url += u"win64/%1.zip"_q;
|
||||
} else if (Platform::IsWindowsARM64()) {
|
||||
url += u"winarm/%1.zip"_q;
|
||||
} else if (Platform::IsMac()) {
|
||||
url += u"mac/%1.zip"_q;
|
||||
} else if (Platform::IsLinux()) {
|
||||
url += u"linux/%1.tar.xz"_q;
|
||||
box->getDelegate()->show(
|
||||
Ui::MakeInformBox(
|
||||
"The link to the current private alpha "
|
||||
"version of Telegram Desktop was copied "
|
||||
"to the clipboard."));
|
||||
} else {
|
||||
Unexpected("Platform value.");
|
||||
File::OpenUrl(Core::App().changelogLink());
|
||||
}
|
||||
url = url.arg(u"talpha%1_%2"_q.arg(cRealAlphaVersion()).arg(Core::countAlphaVersionSignature(cRealAlphaVersion())));
|
||||
});
|
||||
|
||||
QGuiApplication::clipboard()->setText(url);
|
||||
Ui::AddSkip(layout, st::aboutTopSkip);
|
||||
|
||||
getDelegate()->show(
|
||||
Ui::MakeInformBox(
|
||||
"The link to the current private alpha "
|
||||
"version of Telegram Desktop was copied to the clipboard."),
|
||||
Ui::LayerOption::CloseOther);
|
||||
} else {
|
||||
File::OpenUrl(Core::App().changelogLink());
|
||||
}
|
||||
}
|
||||
const auto addText = [&](rpl::producer<TextWithEntities> text) {
|
||||
const auto label = layout->add(
|
||||
object_ptr<Ui::FlatLabel>(box, std::move(text), st::aboutLabel),
|
||||
st::boxRowPadding);
|
||||
label->setLinksTrusted();
|
||||
Ui::AddSkip(layout, st::aboutSkip);
|
||||
};
|
||||
|
||||
void AboutBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
closeBox();
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
addText(Text1());
|
||||
addText(Text2());
|
||||
addText(Text3());
|
||||
|
||||
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
|
||||
|
||||
box->setWidth(st::aboutWidth);
|
||||
}
|
||||
|
||||
QString telegramFaqLink() {
|
||||
@@ -160,5 +153,8 @@ QString currentVersionText() {
|
||||
} else if (Platform::IsWindowsARM64()) {
|
||||
result += " arm64";
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
result += " DEBUG";
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -7,32 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
||||
namespace Ui {
|
||||
class LinkButton;
|
||||
class FlatLabel;
|
||||
} // namespace Ui
|
||||
|
||||
class AboutBox : public Ui::BoxContent {
|
||||
public:
|
||||
AboutBox(QWidget*);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
void showVersionHistory();
|
||||
|
||||
object_ptr<Ui::LinkButton> _version;
|
||||
object_ptr<Ui::FlatLabel> _text1;
|
||||
object_ptr<Ui::FlatLabel> _text2;
|
||||
object_ptr<Ui::FlatLabel> _text3;
|
||||
|
||||
};
|
||||
void AboutBox(not_null<Ui::GenericBox*> box);
|
||||
|
||||
QString telegramFaqLink();
|
||||
QString currentVersionText();
|
||||
|
||||
@@ -37,11 +37,11 @@ void showBox(
|
||||
} // namespace internal
|
||||
|
||||
template <typename BoxType>
|
||||
QPointer<BoxType> show(
|
||||
base::weak_qptr<BoxType> show(
|
||||
object_ptr<BoxType> content,
|
||||
Ui::LayerOptions options = Ui::LayerOption::CloseOther,
|
||||
anim::type animated = anim::type::normal) {
|
||||
auto result = QPointer<BoxType>(content.data());
|
||||
auto result = base::weak_qptr<BoxType>(content.data());
|
||||
internal::showBox(std::move(content), options, animated);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -194,16 +194,16 @@ void ShowAddParticipantsError(
|
||||
&& channel->canAddAdmins()) {
|
||||
const auto makeAdmin = [=](Fn<void()> close) {
|
||||
const auto user = forbidden.users.front();
|
||||
const auto weak = std::make_shared<QPointer<EditAdminBox>>();
|
||||
const auto weak = std::make_shared<base::weak_qptr<EditAdminBox>>();
|
||||
const auto done = [=](auto&&...) {
|
||||
if (const auto strong = weak->data()) {
|
||||
if (const auto strong = weak->get()) {
|
||||
strong->uiShow()->showToast(
|
||||
tr::lng_box_done(tr::now));
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
const auto fail = [=] {
|
||||
if (const auto strong = weak->data()) {
|
||||
if (const auto strong = weak->get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
@@ -446,7 +446,7 @@ void AddContactBox::save() {
|
||||
firstName = lastName;
|
||||
lastName = QString();
|
||||
}
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto weak = base::make_weak(this);
|
||||
const auto session = _session;
|
||||
_sentName = firstName;
|
||||
_contactId = base::RandomValue<uint64>();
|
||||
@@ -559,7 +559,7 @@ void GroupInfoBox::prepare() {
|
||||
&_navigation->parentController()->window(),
|
||||
Ui::UserpicButton::Role::ChoosePhoto,
|
||||
st::defaultUserpicButton,
|
||||
(_type == Type::Forum));
|
||||
(_type == Type::Forum) ? Ui::PeerUserpicShape::Forum : Ui::PeerUserpicShape::Auto);
|
||||
_photo->showCustomOnChosen();
|
||||
_title.create(
|
||||
this,
|
||||
@@ -716,7 +716,7 @@ TimeId GroupInfoBox::ttlPeriod() const {
|
||||
}
|
||||
|
||||
void GroupInfoBox::createGroup(
|
||||
QPointer<Ui::BoxContent> selectUsersBox,
|
||||
base::weak_qptr<Ui::BoxContent> selectUsersBox,
|
||||
const QString &title,
|
||||
const std::vector<not_null<PeerData*>> &users) {
|
||||
if (_creationRequestId) {
|
||||
@@ -750,8 +750,8 @@ void GroupInfoBox::createGroup(
|
||||
_creationRequestId = 0;
|
||||
const auto controller = _navigation->parentController();
|
||||
if (type == u"NO_CHAT_TITLE"_q) {
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
if (const auto strong = selectUsersBox.data()) {
|
||||
const auto weak = base::make_weak(this);
|
||||
if (const auto strong = selectUsersBox.get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
if (weak) {
|
||||
@@ -792,10 +792,10 @@ void GroupInfoBox::submit() {
|
||||
} else if (_canAddBot) {
|
||||
createGroup(nullptr, title, { not_null<PeerData*>(_canAddBot) });
|
||||
} else {
|
||||
auto initBox = [title, weak = Ui::MakeWeak(this)](
|
||||
auto initBox = [title, weak = base::make_weak(this)](
|
||||
not_null<PeerListBox*> box) {
|
||||
auto create = [box, title, weak] {
|
||||
if (const auto strong = weak.data()) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->createGroup(
|
||||
box.get(),
|
||||
title,
|
||||
|
||||
@@ -129,7 +129,7 @@ protected:
|
||||
private:
|
||||
void createChannel(const QString &title, const QString &description);
|
||||
void createGroup(
|
||||
QPointer<Ui::BoxContent> selectUsersBox,
|
||||
base::weak_qptr<Ui::BoxContent> selectUsersBox,
|
||||
const QString &title,
|
||||
const std::vector<not_null<PeerData*>> &users);
|
||||
void submitName();
|
||||
|
||||
@@ -345,7 +345,7 @@ void BackgroundBox::resetForPeer() {
|
||||
api->applyUpdates(result);
|
||||
}).send();
|
||||
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto weak = base::make_weak(this);
|
||||
_forPeer->setWallPaper({});
|
||||
if (weak) {
|
||||
_controller->finishChatThemeEdit(_forPeer);
|
||||
@@ -358,7 +358,7 @@ bool BackgroundBox::forChannel() const {
|
||||
|
||||
void BackgroundBox::removePaper(const Data::WallPaper &paper) {
|
||||
const auto session = &_controller->session();
|
||||
const auto remove = [=, weak = Ui::MakeWeak(this)](Fn<void()> &&close) {
|
||||
const auto remove = [=, weak = base::make_weak(this)](Fn<void()> &&close) {
|
||||
close();
|
||||
if (weak) {
|
||||
weak->_inner->removePaper(paper);
|
||||
|
||||
@@ -241,12 +241,12 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
||||
}, lifetime());
|
||||
|
||||
const auto prepare = [=](bool dark, auto pointer) {
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto weak = base::make_weak(this);
|
||||
crl::async([=] {
|
||||
auto result = std::make_unique<style::palette>();
|
||||
Window::Theme::PreparePaletteCallback(dark, {})(*result);
|
||||
crl::on_main([=, result = std::move(result)]() mutable {
|
||||
if (const auto strong = weak.data()) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->*pointer = std::move(result);
|
||||
strong->paletteReady();
|
||||
}
|
||||
@@ -685,7 +685,7 @@ void BackgroundPreviewBox::checkLevelForChannel() {
|
||||
|
||||
const auto show = _controller->uiShow();
|
||||
_forPeerLevelCheck = true;
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto weak = base::make_weak(this);
|
||||
CheckBoostLevel(show, _forPeer, [=](int level) {
|
||||
if (!weak) {
|
||||
return std::optional<Ui::AskBoostReason>();
|
||||
|
||||
@@ -349,7 +349,7 @@ aboutVersionLink: LinkButton(defaultLinkButton) {
|
||||
color: windowSubTextFg;
|
||||
overColor: windowSubTextFg;
|
||||
}
|
||||
aboutTextTop: 34px;
|
||||
aboutTopSkip: 19px;
|
||||
aboutSkip: 14px;
|
||||
aboutLabel: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 300px;
|
||||
|
||||
@@ -16,9 +16,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_account.h"
|
||||
#include "mtproto/facade.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "ui/basic_click_handlers.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/boxes/peer_qr_box.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "ui/painter.h"
|
||||
@@ -32,6 +34,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/fields/number_input.h"
|
||||
#include "ui/widgets/fields/password_input.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/menu/menu_add_action_callback.h"
|
||||
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
@@ -44,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
@@ -54,6 +59,31 @@ constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000);
|
||||
|
||||
using ProxyData = MTP::ProxyData;
|
||||
|
||||
[[nodiscard]] std::vector<QString> ExtractUrlsSimple(const QString &input) {
|
||||
auto urls = std::vector<QString>();
|
||||
static auto urlRegex = QRegularExpression(R"((https?:\/\/[^\s]+))");
|
||||
|
||||
auto it = urlRegex.globalMatch(input);
|
||||
while (it.hasNext()) {
|
||||
urls.push_back(it.next().captured(1));
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString ProxyDataToString(const ProxyData &proxy) {
|
||||
using Type = ProxyData::Type;
|
||||
return u"https://t.me/"_q
|
||||
+ (proxy.type == Type::Socks5 ? "socks" : "proxy")
|
||||
+ "?server=" + proxy.host + "&port=" + QString::number(proxy.port)
|
||||
+ ((proxy.type == Type::Socks5 && !proxy.user.isEmpty())
|
||||
? "&user=" + qthelp::url_encode(proxy.user) : "")
|
||||
+ ((proxy.type == Type::Socks5 && !proxy.password.isEmpty())
|
||||
? "&pass=" + qthelp::url_encode(proxy.password) : "")
|
||||
+ ((proxy.type == Type::Mtproto && !proxy.password.isEmpty())
|
||||
? "&secret=" + proxy.password : "");
|
||||
}
|
||||
|
||||
[[nodiscard]] ProxyData ProxyDataFromFields(
|
||||
ProxyData::Type type,
|
||||
const QMap<QString, QString> &fields) {
|
||||
@@ -70,6 +100,102 @@ using ProxyData = MTP::ProxyData;
|
||||
return proxy;
|
||||
};
|
||||
|
||||
void AddProxyFromClipboard(
|
||||
not_null<ProxiesBoxController*> controller,
|
||||
std::shared_ptr<Ui::Show> show) {
|
||||
const auto proxyString = u"proxy"_q;
|
||||
const auto socksString = u"socks"_q;
|
||||
const auto protocol = u"tg://"_q;
|
||||
|
||||
const auto maybeUrls = ExtractUrlsSimple(
|
||||
QGuiApplication::clipboard()->text());
|
||||
const auto isSingle = maybeUrls.size() == 1;
|
||||
|
||||
enum class Result {
|
||||
Success,
|
||||
Failed,
|
||||
Unsupported,
|
||||
Invalid,
|
||||
};
|
||||
|
||||
const auto proceedUrl = [=](const auto &local) {
|
||||
const auto command = base::StringViewMid(
|
||||
local,
|
||||
protocol.size(),
|
||||
8192);
|
||||
|
||||
if (local.startsWith(protocol + proxyString)
|
||||
|| local.startsWith(protocol + socksString)) {
|
||||
|
||||
using namespace qthelp;
|
||||
const auto options = RegExOption::CaseInsensitive;
|
||||
for (const auto &[expression, _] : Core::LocalUrlHandlers()) {
|
||||
const auto midExpression = base::StringViewMid(
|
||||
expression,
|
||||
1);
|
||||
const auto isSocks = midExpression.startsWith(
|
||||
socksString);
|
||||
if (!midExpression.startsWith(proxyString)
|
||||
&& !isSocks) {
|
||||
continue;
|
||||
}
|
||||
const auto match = regex_match(
|
||||
expression,
|
||||
command,
|
||||
options);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
const auto type = isSocks
|
||||
? ProxyData::Type::Socks5
|
||||
: ProxyData::Type::Mtproto;
|
||||
const auto fields = url_parse_params(
|
||||
match->captured(1),
|
||||
qthelp::UrlParamNameTransform::ToLower);
|
||||
const auto proxy = ProxyDataFromFields(type, fields);
|
||||
if (!proxy) {
|
||||
return (proxy.status() == ProxyData::Status::Unsupported)
|
||||
? Result::Unsupported
|
||||
: Result::Invalid;
|
||||
}
|
||||
const auto contains = controller->contains(proxy);
|
||||
const auto toast = (contains
|
||||
? tr::lng_proxy_add_from_clipboard_existing_toast
|
||||
: tr::lng_proxy_add_from_clipboard_good_toast)(tr::now);
|
||||
if (isSingle) {
|
||||
show->showToast(toast);
|
||||
}
|
||||
if (!contains) {
|
||||
controller->addNewItem(proxy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Result::Success;
|
||||
}
|
||||
return Result::Failed;
|
||||
};
|
||||
|
||||
auto success = Result::Failed;
|
||||
for (const auto &maybeUrl : maybeUrls) {
|
||||
const auto result = proceedUrl(Core::TryConvertUrlToLocal(maybeUrl));
|
||||
if (success != Result::Success) {
|
||||
success = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (success != Result::Success) {
|
||||
if (success == Result::Failed) {
|
||||
show->showToast(
|
||||
tr::lng_proxy_add_from_clipboard_failed_toast(tr::now));
|
||||
} else {
|
||||
show->showBox(Ui::MakeInformBox(
|
||||
(success == Result::Unsupported
|
||||
? tr::lng_proxy_unsupported(tr::now)
|
||||
: tr::lng_proxy_invalid(tr::now))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HostInput : public Ui::MaskedInputField {
|
||||
public:
|
||||
HostInput(
|
||||
@@ -177,6 +303,7 @@ public:
|
||||
rpl::producer<> restoreClicks() const;
|
||||
rpl::producer<> editClicks() const;
|
||||
rpl::producer<> shareClicks() const;
|
||||
rpl::producer<> showQrClicks() const;
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
@@ -198,6 +325,7 @@ private:
|
||||
rpl::event_stream<> _restoreClicks;
|
||||
rpl::event_stream<> _editClicks;
|
||||
rpl::event_stream<> _shareClicks;
|
||||
rpl::event_stream<> _showQrClicks;
|
||||
base::unique_qptr<Ui::DropdownMenu> _menu;
|
||||
|
||||
bool _set = false;
|
||||
@@ -222,6 +350,7 @@ public:
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
void setupContent();
|
||||
@@ -319,6 +448,10 @@ rpl::producer<> ProxyRow::shareClicks() const {
|
||||
return _shareClicks.events();
|
||||
}
|
||||
|
||||
rpl::producer<> ProxyRow::showQrClicks() const {
|
||||
return _showQrClicks.events();
|
||||
}
|
||||
|
||||
void ProxyRow::setupControls(View &&view) {
|
||||
updateFields(std::move(view));
|
||||
_toggled.stop();
|
||||
@@ -563,6 +696,9 @@ void ProxyRow::showMenu() {
|
||||
addAction(tr::lng_proxy_edit_share(tr::now), [=] {
|
||||
_shareClicks.fire({});
|
||||
}, &st::menuIconShare);
|
||||
addAction(tr::lng_group_invite_context_qr(tr::now), [=] {
|
||||
_showQrClicks.fire({});
|
||||
}, &st::menuIconQrCode);
|
||||
}
|
||||
if (_view.deleted) {
|
||||
addAction(tr::lng_proxy_menu_restore(tr::now), [=] {
|
||||
@@ -617,6 +753,18 @@ ProxiesBox::ProxiesBox(
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void ProxiesBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Copy
|
||||
|| (e->key() == Qt::Key_C && e->modifiers() == Qt::ControlModifier)) {
|
||||
_controller->shareItems();
|
||||
} else if (e->key() == Qt::Key_Paste
|
||||
|| (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier)) {
|
||||
AddProxyFromClipboard(_controller, uiShow());
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxiesBox::prepare() {
|
||||
setTitle(tr::lng_proxy_settings());
|
||||
|
||||
@@ -631,67 +779,23 @@ void ProxiesBox::setupTopButton() {
|
||||
const auto top = addTopButton(st::infoTopBarMenu);
|
||||
const auto menu
|
||||
= top->lifetime().make_state<base::unique_qptr<Ui::PopupMenu>>();
|
||||
const auto callback = [=] {
|
||||
const auto maybeUrl = QGuiApplication::clipboard()->text();
|
||||
const auto local = Core::TryConvertUrlToLocal(maybeUrl);
|
||||
|
||||
const auto proxyString = u"proxy"_q;
|
||||
const auto socksString = u"socks"_q;
|
||||
const auto protocol = u"tg://"_q;
|
||||
const auto command = base::StringViewMid(
|
||||
local,
|
||||
protocol.size(),
|
||||
8192);
|
||||
|
||||
if (local.startsWith(protocol + proxyString)
|
||||
|| local.startsWith(protocol + socksString)) {
|
||||
|
||||
using namespace qthelp;
|
||||
const auto options = RegExOption::CaseInsensitive;
|
||||
for (const auto &[expression, _] : Core::LocalUrlHandlers()) {
|
||||
const auto midExpression = base::StringViewMid(
|
||||
expression,
|
||||
1);
|
||||
const auto isSocks = midExpression.startsWith(
|
||||
socksString);
|
||||
if (!midExpression.startsWith(proxyString)
|
||||
&& !isSocks) {
|
||||
continue;
|
||||
}
|
||||
const auto match = regex_match(
|
||||
expression,
|
||||
command,
|
||||
options);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
const auto type = isSocks
|
||||
? ProxyData::Type::Socks5
|
||||
: ProxyData::Type::Mtproto;
|
||||
const auto fields = url_parse_params(
|
||||
match->captured(1),
|
||||
qthelp::UrlParamNameTransform::ToLower);
|
||||
const auto proxy = ProxyDataFromFields(type, fields);
|
||||
const auto contains = _controller->contains(proxy);
|
||||
const auto toast = (contains
|
||||
? tr::lng_proxy_add_from_clipboard_existing_toast
|
||||
: tr::lng_proxy_add_from_clipboard_good_toast)(tr::now);
|
||||
uiShow()->showToast(toast);
|
||||
if (!contains) {
|
||||
_controller->addNewItem(proxy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
uiShow()->showToast(
|
||||
tr::lng_proxy_add_from_clipboard_failed_toast(tr::now));
|
||||
}
|
||||
};
|
||||
top->setClickedCallback([=] {
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(top, st::defaultPopupMenu);
|
||||
(*menu)->addAction(
|
||||
tr::lng_proxy_add_from_clipboard(tr::now),
|
||||
callback);
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
top,
|
||||
st::popupMenuWithIcons);
|
||||
const auto addAction = Ui::Menu::CreateAddActionCallback(*menu);
|
||||
addAction({
|
||||
.text = tr::lng_proxy_add_from_clipboard(tr::now),
|
||||
.handler = [=] { AddProxyFromClipboard(_controller, uiShow()); },
|
||||
.icon = &st::menuIconImportTheme,
|
||||
});
|
||||
addAction({
|
||||
.text = tr::lng_group_invite_context_delete_all(tr::now),
|
||||
.handler = [=] { _controller->deleteItems(); },
|
||||
.icon = &st::menuIconDeleteAttention,
|
||||
.isAttention = true,
|
||||
});
|
||||
(*menu)->popup(QCursor::pos());
|
||||
return true;
|
||||
});
|
||||
@@ -791,6 +895,23 @@ void ProxiesBox::setupContent() {
|
||||
refreshProxyForCalls();
|
||||
_proxyForCalls->finishAnimating();
|
||||
|
||||
{
|
||||
const auto wrap = inner->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
inner,
|
||||
object_ptr<Ui::VerticalLayout>(inner)));
|
||||
const auto shareList = Settings::AddButtonWithIcon(
|
||||
wrap->entity(),
|
||||
tr::lng_proxy_edit_share_list_button(),
|
||||
st::settingsButton,
|
||||
{ &st::menuIconCopy });
|
||||
shareList->setClickedCallback([=] {
|
||||
_controller->shareItems();
|
||||
});
|
||||
wrap->toggleOn(_controller->listShareableChanges());
|
||||
wrap->finishAnimating();
|
||||
}
|
||||
|
||||
inner->resizeToWidth(st::boxWideWidth);
|
||||
|
||||
inner->heightValue(
|
||||
@@ -898,9 +1019,11 @@ void ProxiesBox::setupButtons(int id, not_null<ProxyRow*> button) {
|
||||
getDelegate()->show(_controller->editItemBox(id));
|
||||
}, button->lifetime());
|
||||
|
||||
button->shareClicks(
|
||||
) | rpl::start_with_next([=] {
|
||||
_controller->shareItem(id);
|
||||
rpl::merge(
|
||||
button->shareClicks() | rpl::map_to(false),
|
||||
button->showQrClicks() | rpl::map_to(true)
|
||||
) | rpl::start_with_next([=](bool qr) {
|
||||
_controller->shareItem(id, qr);
|
||||
}, button->lifetime());
|
||||
|
||||
button->clicks(
|
||||
@@ -1407,12 +1530,32 @@ void ProxiesBoxController::deleteItem(int id) {
|
||||
setDeleted(id, true);
|
||||
}
|
||||
|
||||
void ProxiesBoxController::deleteItems() {
|
||||
for (const auto &item : _list) {
|
||||
setDeleted(item.id, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxiesBoxController::restoreItem(int id) {
|
||||
setDeleted(id, false);
|
||||
}
|
||||
|
||||
void ProxiesBoxController::shareItem(int id) {
|
||||
share(findById(id)->data);
|
||||
void ProxiesBoxController::shareItem(int id, bool qr) {
|
||||
share(findById(id)->data, qr);
|
||||
}
|
||||
|
||||
void ProxiesBoxController::shareItems() {
|
||||
auto result = QString();
|
||||
for (const auto &item : _list) {
|
||||
if (!item.deleted) {
|
||||
result += ProxyDataToString(item.data) + '\n' + '\n';
|
||||
}
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QGuiApplication::clipboard()->setText(result);
|
||||
_show->showToast(tr::lng_proxy_edit_share_list_toast(tr::now));
|
||||
}
|
||||
|
||||
void ProxiesBoxController::applyItem(int id) {
|
||||
@@ -1621,6 +1764,17 @@ auto ProxiesBoxController::views() const -> rpl::producer<ItemView> {
|
||||
return _views.events();
|
||||
}
|
||||
|
||||
rpl::producer<bool> ProxiesBoxController::listShareableChanges() const {
|
||||
return _views.events_starting_with(ItemView()) | rpl::map([=] {
|
||||
for (const auto &item : _list) {
|
||||
if (!item.deleted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void ProxiesBoxController::updateView(const Item &item) {
|
||||
const auto selected = (_settings.selected() == item.data);
|
||||
const auto deleted = item.deleted;
|
||||
@@ -1653,22 +1807,22 @@ void ProxiesBoxController::updateView(const Item &item) {
|
||||
deleted,
|
||||
!deleted && supportsShare,
|
||||
supportsCalls,
|
||||
state });
|
||||
state,
|
||||
});
|
||||
}
|
||||
|
||||
void ProxiesBoxController::share(const ProxyData &proxy) {
|
||||
void ProxiesBoxController::share(const ProxyData &proxy, bool qr) {
|
||||
if (proxy.type == Type::Http) {
|
||||
return;
|
||||
}
|
||||
const auto link = u"https://t.me/"_q
|
||||
+ (proxy.type == Type::Socks5 ? "socks" : "proxy")
|
||||
+ "?server=" + proxy.host + "&port=" + QString::number(proxy.port)
|
||||
+ ((proxy.type == Type::Socks5 && !proxy.user.isEmpty())
|
||||
? "&user=" + qthelp::url_encode(proxy.user) : "")
|
||||
+ ((proxy.type == Type::Socks5 && !proxy.password.isEmpty())
|
||||
? "&pass=" + qthelp::url_encode(proxy.password) : "")
|
||||
+ ((proxy.type == Type::Mtproto && !proxy.password.isEmpty())
|
||||
? "&secret=" + proxy.password : "");
|
||||
const auto link = ProxyDataToString(proxy);
|
||||
if (qr) {
|
||||
_show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
Ui::FillPeerQrBox(box, nullptr, link, rpl::single(QString()));
|
||||
box->setTitle(tr::lng_proxy_edit_share_qr_box_title());
|
||||
}));
|
||||
return;
|
||||
}
|
||||
QGuiApplication::clipboard()->setText(link);
|
||||
_show->showToast(tr::lng_username_copied(tr::now));
|
||||
}
|
||||
|
||||
@@ -72,8 +72,10 @@ public:
|
||||
};
|
||||
|
||||
void deleteItem(int id);
|
||||
void deleteItems();
|
||||
void restoreItem(int id);
|
||||
void shareItem(int id);
|
||||
void shareItem(int id, bool qr);
|
||||
void shareItems();
|
||||
void applyItem(int id);
|
||||
object_ptr<Ui::BoxContent> editItemBox(int id);
|
||||
object_ptr<Ui::BoxContent> addNewItemBox();
|
||||
@@ -87,6 +89,8 @@ public:
|
||||
|
||||
rpl::producer<ItemView> views() const;
|
||||
|
||||
rpl::producer<bool> listShareableChanges() const;
|
||||
|
||||
~ProxiesBoxController();
|
||||
|
||||
private:
|
||||
@@ -106,7 +110,7 @@ private:
|
||||
std::vector<Item>::iterator findByProxy(const ProxyData &proxy);
|
||||
void setDeleted(int id, bool deleted);
|
||||
void updateView(const Item &item);
|
||||
void share(const ProxyData &proxy);
|
||||
void share(const ProxyData &proxy, bool qr = false);
|
||||
void saveDelayed();
|
||||
void refreshChecker(Item &item);
|
||||
void setupChecker(int id, const Checker &checker);
|
||||
|
||||
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "menu/menu_send.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
@@ -113,7 +114,7 @@ private:
|
||||
void setPlaceholder() const;
|
||||
void removePlaceholder() const;
|
||||
|
||||
not_null<Ui::InputField*> field() const;
|
||||
[[nodiscard]] not_null<Ui::InputField*> field() const;
|
||||
|
||||
[[nodiscard]] PollAnswer toPollAnswer(int index) const;
|
||||
|
||||
@@ -510,7 +511,8 @@ Options::Options(
|
||||
}
|
||||
|
||||
bool Options::full() const {
|
||||
return (_list.size() == kMaxOptionsCount);
|
||||
const auto limit = _controller->session().appConfig().pollOptionsLimit();
|
||||
return (_list.size() >= limit);
|
||||
}
|
||||
|
||||
bool Options::hasOptions() const {
|
||||
@@ -1028,8 +1030,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
||||
setCloseByEscape(!count);
|
||||
setCloseByOutsideClick(!count);
|
||||
}) | rpl::map([=](int count) {
|
||||
return (count < kMaxOptionsCount)
|
||||
? tr::lng_polls_create_limit(tr::now, lt_count, kMaxOptionsCount - count)
|
||||
const auto appConfig = &_controller->session().appConfig();
|
||||
const auto max = appConfig->pollOptionsLimit();
|
||||
return (count < max)
|
||||
? tr::lng_polls_create_limit(tr::now, lt_count, max - count)
|
||||
: tr::lng_polls_create_maximum(tr::now);
|
||||
}) | rpl::after_next([=] {
|
||||
container->resizeToWidth(container->widthNoMargins());
|
||||
|
||||
@@ -21,8 +21,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "menu/menu_ttl_validator.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
@@ -492,7 +494,58 @@ void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
PaidPostType DeleteMessagesBox::paidPostType() const {
|
||||
auto result = PaidPostType::None;
|
||||
const auto now = base::unixtime::now();
|
||||
for (const auto &id : _ids) {
|
||||
if (const auto item = _session->data().message(id)) {
|
||||
const auto type = item->paidType();
|
||||
if (type != PaidPostType::None) {
|
||||
const auto date = item->date();
|
||||
const auto config = &item->history()->session().appConfig();
|
||||
const auto limit = config->suggestedPostAgeMin();
|
||||
if (now < date || now - date <= limit) {
|
||||
if (type == PaidPostType::Ton) {
|
||||
return type;
|
||||
} else if (type == PaidPostType::Stars) {
|
||||
result = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::deleteAndClear() {
|
||||
const auto warnPaidType = _confirmedDeletePaidSuggestedPosts
|
||||
? PaidPostType::None
|
||||
: paidPostType();
|
||||
if (warnPaidType != PaidPostType::None) {
|
||||
const auto weak = base::make_weak(this);
|
||||
const auto callback = [=](Fn<void()> close) {
|
||||
close();
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->_confirmedDeletePaidSuggestedPosts = true;
|
||||
strong->deleteAndClear();
|
||||
}
|
||||
};
|
||||
const auto ton = (warnPaidType == PaidPostType::Ton);
|
||||
uiShow()->show(Ui::MakeConfirmBox({
|
||||
.text = (ton
|
||||
? tr::lng_suggest_warn_text_ton
|
||||
: tr::lng_suggest_warn_text_stars)(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue),
|
||||
.confirmed = callback,
|
||||
.confirmText = tr::lng_suggest_warn_delete_anyway(tr::now),
|
||||
.confirmStyle = &st::attentionBoxButton,
|
||||
.title = (ton
|
||||
? tr::lng_suggest_warn_title_ton
|
||||
: tr::lng_suggest_warn_title_stars)(tr::now),
|
||||
}));
|
||||
return;
|
||||
}
|
||||
if (_revoke
|
||||
&& _revokeRemember
|
||||
&& _revokeRemember->toggled()
|
||||
@@ -506,11 +559,11 @@ void DeleteMessagesBox::deleteAndClear() {
|
||||
const auto invokeCallbackAndClose = [&] {
|
||||
// deleteMessages can initiate closing of the current section,
|
||||
// which will cause this box to be destroyed.
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto weak = base::make_weak(this);
|
||||
if (const auto callback = _deleteConfirmedCallback) {
|
||||
callback();
|
||||
}
|
||||
if (const auto strong = weak.data()) {
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "ui/layers/box_content.h"
|
||||
|
||||
enum class PaidPostType : uchar;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
@@ -58,6 +60,7 @@ private:
|
||||
[[nodiscard]] bool hasScheduledMessages() const;
|
||||
[[nodiscard]] std::optional<RevokeConfig> revokeText(
|
||||
not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] PaidPostType paidPostType() const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
@@ -82,6 +85,7 @@ private:
|
||||
object_ptr<Ui::LinkButton> _autoDeleteSettings = { nullptr };
|
||||
|
||||
int _fullHeight = 0;
|
||||
bool _confirmedDeletePaidSuggestedPosts = false;
|
||||
|
||||
Fn<void()> _deleteConfirmedCallback;
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ auto AddButtonWithLoader(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
const auto &state = buttonState->current();
|
||||
if (toggled && (v::is<Available>(state) || v::is<Failed>(state))) {
|
||||
const auto weak = Ui::MakeWeak(button);
|
||||
const auto weak = base::make_weak(button);
|
||||
setLocalLoader(base::make_unique_q<Loader>(
|
||||
QCoreApplication::instance(),
|
||||
session,
|
||||
|
||||