Compare commits
372 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5f90cd40d | ||
|
|
a10d668131 | ||
|
|
8a62bacaa6 | ||
|
|
bacab01f7e | ||
|
|
5d3400033a | ||
|
|
0e571ea679 | ||
|
|
b959262140 | ||
|
|
fd3ce905c0 | ||
|
|
29debc07c4 | ||
|
|
5334096d68 | ||
|
|
bb3f8fbbe8 | ||
|
|
2f0b50cb37 | ||
|
|
6185fa980d | ||
|
|
1cce1e8a90 | ||
|
|
237baf11df | ||
|
|
46023f4260 | ||
|
|
8459c29073 | ||
|
|
f072173d7c | ||
|
|
bec34c34b1 | ||
|
|
04ab148b2e | ||
|
|
e314abefb8 | ||
|
|
cdaa23363f | ||
|
|
5401d00548 | ||
|
|
c06699e8e7 | ||
|
|
2f40a44b5c | ||
|
|
0945e04f6b | ||
|
|
db7c16f82b | ||
|
|
30548c2859 | ||
|
|
0163938e00 | ||
|
|
3421b656db | ||
|
|
39b80c98c7 | ||
|
|
323500f6dd | ||
|
|
11cf0486cb | ||
|
|
46579ac84d | ||
|
|
f324c53440 | ||
|
|
87df90227e | ||
|
|
6f57302562 | ||
|
|
d116c8fea0 | ||
|
|
32462fca9b | ||
|
|
55a174190e | ||
|
|
9f738cded2 | ||
|
|
87c1329490 | ||
|
|
ded2015dc2 | ||
|
|
98a71cce89 | ||
|
|
a3ba1ba2a1 | ||
|
|
42842619b0 | ||
|
|
32d3b90cdc | ||
|
|
b182aeb51e | ||
|
|
7049929a59 | ||
|
|
aa5413da4e | ||
|
|
32dfe0f65e | ||
|
|
5d33290218 | ||
|
|
852196a013 | ||
|
|
0ff3d4b2ed | ||
|
|
b843dab87a | ||
|
|
20bd7db4d9 | ||
|
|
92f0358800 | ||
|
|
0372f2be9c | ||
|
|
7dfb93f7c2 | ||
|
|
3c150d9742 | ||
|
|
3c5cace175 | ||
|
|
7e7fd6f1b4 | ||
|
|
eebe7adbcb | ||
|
|
5561bdeb5e | ||
|
|
a670095294 | ||
|
|
104ba4db7c | ||
|
|
9a6ab3b0f2 | ||
|
|
e5b89b1572 | ||
|
|
65a80766f4 | ||
|
|
736b489eb7 | ||
|
|
d3778f92d2 | ||
|
|
30e694420a | ||
|
|
091c13bc23 | ||
|
|
5130c5df80 | ||
|
|
7542f04010 | ||
|
|
dff4191ac9 | ||
|
|
15e2874da8 | ||
|
|
8eb49d5efc | ||
|
|
230761eb23 | ||
|
|
bb0ab27244 | ||
|
|
bdeaf4f27a | ||
|
|
6d608bed98 | ||
|
|
5a47acf1d2 | ||
|
|
02a306ba70 | ||
|
|
75e19235cd | ||
|
|
7d9b4e1e03 | ||
|
|
d0fff1611c | ||
|
|
e4ca8ae847 | ||
|
|
f53b64bc72 | ||
|
|
981909e567 | ||
|
|
ce6fc19b84 | ||
|
|
a38f731265 | ||
|
|
d55dd7dffd | ||
|
|
37478d951a | ||
|
|
814de17f28 | ||
|
|
5f97d683df | ||
|
|
95d4e02ae1 | ||
|
|
abf9764640 | ||
|
|
80ee38f9fb | ||
|
|
b4ab20bbe9 | ||
|
|
f6a95df550 | ||
|
|
f3f660a180 | ||
|
|
eda7118df9 | ||
|
|
7c468052e6 | ||
|
|
43eca490a7 | ||
|
|
3710d61a09 | ||
|
|
5daa5a00f0 | ||
|
|
6e31993777 | ||
|
|
1cfad14437 | ||
|
|
3829ed5880 | ||
|
|
e5cda0e2b1 | ||
|
|
c765bee0cd | ||
|
|
16942d487a | ||
|
|
5cb4cfef32 | ||
|
|
4d86ced1e6 | ||
|
|
ad03431b0a | ||
|
|
474f1118b6 | ||
|
|
e63d573414 | ||
|
|
33643ff7fc | ||
|
|
ca25ad57b1 | ||
|
|
c364383cf0 | ||
|
|
5033b9ef0d | ||
|
|
605b255e32 | ||
|
|
d3fdfe4b29 | ||
|
|
c452694348 | ||
|
|
83fc19e143 | ||
|
|
6686fe110d | ||
|
|
ed027c23d0 | ||
|
|
2213bedc12 | ||
|
|
ac7958f335 | ||
|
|
3301d28615 | ||
|
|
6033071e61 | ||
|
|
06775b5623 | ||
|
|
93a734eecf | ||
|
|
6f64fea0b1 | ||
|
|
6b910e11e5 | ||
|
|
b31bb6dd33 | ||
|
|
104cf504ab | ||
|
|
b462d7627f | ||
|
|
cb4781360a | ||
|
|
8895e49466 | ||
|
|
d1f4463c2a | ||
|
|
f9b5789cf7 | ||
|
|
5273fbf57b | ||
|
|
ad6890e7dd | ||
|
|
46ddc7364c | ||
|
|
a2c0491ae0 | ||
|
|
c686ac8603 | ||
|
|
268613e1db | ||
|
|
5ba918d213 | ||
|
|
21dcb7b13c | ||
|
|
40ff71b2cd | ||
|
|
b017cc07ce | ||
|
|
fa773c3024 | ||
|
|
a1369aaad0 | ||
|
|
6516c7aef3 | ||
|
|
c43dfecec6 | ||
|
|
53e95a7f74 | ||
|
|
2a81a617e1 | ||
|
|
37067f17e2 | ||
|
|
f8caa02f10 | ||
|
|
fc2f41096f | ||
|
|
3eefaac885 | ||
|
|
0dfe37f998 | ||
|
|
e2439984ae | ||
|
|
9401e7cb51 | ||
|
|
4471eb587d | ||
|
|
3c6037a798 | ||
|
|
d1a0dfbb97 | ||
|
|
94a542a1d1 | ||
|
|
f5fcfaba0c | ||
|
|
9c151ca151 | ||
|
|
e667436a98 | ||
|
|
9aacff8b54 | ||
|
|
9b43d204e2 | ||
|
|
0faf801de7 | ||
|
|
dd1cca1a0a | ||
|
|
eca8c28dea | ||
|
|
333ef9b48a | ||
|
|
1e98e19aaf | ||
|
|
308fdcf9cf | ||
|
|
d803b3ae7d | ||
|
|
aa121aa1de | ||
|
|
8138a26c2d | ||
|
|
26fa3db66d | ||
|
|
7779d021b4 | ||
|
|
6b44143f5b | ||
|
|
0f207faa3e | ||
|
|
28b43eff7c | ||
|
|
c257b75a66 | ||
|
|
893e14cc39 | ||
|
|
30d5b7fd66 | ||
|
|
2ef8136308 | ||
|
|
fccc93ca53 | ||
|
|
37d1940993 | ||
|
|
f25638f492 | ||
|
|
6e6f15e711 | ||
|
|
b38e72dcd9 | ||
|
|
9287af1752 | ||
|
|
254ca57bf3 | ||
|
|
52ef8e780a | ||
|
|
16a2d4ec96 | ||
|
|
3b50bc71b3 | ||
|
|
bb31357c58 | ||
|
|
66afcbdae8 | ||
|
|
5a28e69f1a | ||
|
|
ce78074df7 | ||
|
|
973f91b5e4 | ||
|
|
d2246337a2 | ||
|
|
c7f11eb05a | ||
|
|
758219265a | ||
|
|
d8d9441731 | ||
|
|
098e797045 | ||
|
|
69f8cb5951 | ||
|
|
ca86dce760 | ||
|
|
5cf0b6b50e | ||
|
|
7a139ecda7 | ||
|
|
e52fe9ddb0 | ||
|
|
cee2961632 | ||
|
|
5933535c9b | ||
|
|
a3b91da66c | ||
|
|
34d9a21aae | ||
|
|
233c6b18ed | ||
|
|
4274f9d3f3 | ||
|
|
c8dd94601b | ||
|
|
382dab4ecb | ||
|
|
bdf67645bb | ||
|
|
5c29cc59c8 | ||
|
|
ca9caa36da | ||
|
|
0b5f05c7d4 | ||
|
|
676e85983d | ||
|
|
7638f4cc3d | ||
|
|
e2e55312b8 | ||
|
|
c51a8816eb | ||
|
|
175914f02b | ||
|
|
fbd6b5b640 | ||
|
|
1b11731d6b | ||
|
|
8ecb49f132 | ||
|
|
0ae537478f | ||
|
|
4aa432ecbe | ||
|
|
d5a0f4890d | ||
|
|
5e255e56eb | ||
|
|
a4d7309209 | ||
|
|
a30d0eccda | ||
|
|
a4f4e4564a | ||
|
|
bfe7683cdb | ||
|
|
fbc600a978 | ||
|
|
70eb452a09 | ||
|
|
9f7c74ae72 | ||
|
|
65a3cf136b | ||
|
|
2d86ec1e84 | ||
|
|
fdef19a009 | ||
|
|
26df482b54 | ||
|
|
ee5b7a5100 | ||
|
|
bd67bc4433 | ||
|
|
9d582040e6 | ||
|
|
f3bda59019 | ||
|
|
0d72d47318 | ||
|
|
29646707a1 | ||
|
|
e6b9a07163 | ||
|
|
4b297bfa09 | ||
|
|
00e785a3af | ||
|
|
78e6b3e13f | ||
|
|
ad84750130 | ||
|
|
686310489b | ||
|
|
84c5310262 | ||
|
|
f53397e26a | ||
|
|
2a8a74b5b1 | ||
|
|
9392550c01 | ||
|
|
d2565dc944 | ||
|
|
22f68b430d | ||
|
|
3962e5a680 | ||
|
|
a1c7a48958 | ||
|
|
85286684e3 | ||
|
|
c2712b0104 | ||
|
|
1cb5ef7476 | ||
|
|
9f0b42bbbd | ||
|
|
634687881a | ||
|
|
878b4bb5af | ||
|
|
452257dcd5 | ||
|
|
4e6d8f06d9 | ||
|
|
fd417024fb | ||
|
|
18c4d210e5 | ||
|
|
ead40c759e | ||
|
|
be9aa3a097 | ||
|
|
bdcb146d06 | ||
|
|
70115a24bb | ||
|
|
ea37e83b13 | ||
|
|
931c17418d | ||
|
|
5a47ed268c | ||
|
|
d63ebbe62c | ||
|
|
cb4fce251e | ||
|
|
4aa8a41119 | ||
|
|
13cba72945 | ||
|
|
cf63b0138e | ||
|
|
3cbe0aae4a | ||
|
|
5ab8e68366 | ||
|
|
1d345299f5 | ||
|
|
fc50d5c30f | ||
|
|
4e3c1460f6 | ||
|
|
5bc954396c | ||
|
|
b24290b019 | ||
|
|
23cce64d00 | ||
|
|
73690d14f7 | ||
|
|
2a5698cf34 | ||
|
|
fd64718502 | ||
|
|
941126ad69 | ||
|
|
0e8058adb1 | ||
|
|
01906c1161 | ||
|
|
9201cf24f1 | ||
|
|
d5a1c354d0 | ||
|
|
41ae1f56ed | ||
|
|
ed7212f864 | ||
|
|
8bcb784f12 | ||
|
|
431549c81a | ||
|
|
12110e17a2 | ||
|
|
db8338156a | ||
|
|
de8b09d7fc | ||
|
|
fddbce5dce | ||
|
|
081817f62a | ||
|
|
8efbd7a1cb | ||
|
|
bce310d5c8 | ||
|
|
ed9ecbd235 | ||
|
|
1e756dd380 | ||
|
|
b9b6226692 | ||
|
|
82d73e2396 | ||
|
|
cd5a6025f6 | ||
|
|
b6c679449e | ||
|
|
ac744b957a | ||
|
|
805a5d73b6 | ||
|
|
6aaf841a73 | ||
|
|
60e72768e1 | ||
|
|
94e8f2a791 | ||
|
|
1fb4a2f4ba | ||
|
|
28d68acfe6 | ||
|
|
d87a0a2d25 | ||
|
|
8e92778b62 | ||
|
|
f7e2c7977b | ||
|
|
4337f0b509 | ||
|
|
2b960a1f21 | ||
|
|
4b9648d8d9 | ||
|
|
62f9f3c94b | ||
|
|
e854f0b60c | ||
|
|
19f38f3c6f | ||
|
|
d56724f290 | ||
|
|
8abc35ca86 | ||
|
|
e135f8954f | ||
|
|
f5b59c9456 | ||
|
|
6471d43c71 | ||
|
|
563b8d1468 | ||
|
|
f41a3fe01f | ||
|
|
29c9266ef5 | ||
|
|
1a856e359f | ||
|
|
59099a8d46 | ||
|
|
98c6a3ff79 | ||
|
|
cccc2ce0f1 | ||
|
|
88b20f6700 | ||
|
|
3adbfb1fb5 | ||
|
|
0ee0ffa7f1 | ||
|
|
4c82620677 | ||
|
|
73294bfabf | ||
|
|
6c42095108 | ||
|
|
fbe93b0afc | ||
|
|
e173c727f7 | ||
|
|
85f56217a8 | ||
|
|
06564efe0e | ||
|
|
664ebe4ed0 | ||
|
|
cb3dece478 | ||
|
|
c86ca6a61a | ||
|
|
8e2240d9d9 | ||
|
|
28acaf06ad | ||
|
|
fe12c3639b |
5
.github/workflows/docker.yml
vendored
@@ -28,6 +28,7 @@ jobs:
|
||||
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@f68fdb76e2ea636224182cfb7377ff9a1708f9b8
|
||||
@@ -40,6 +41,4 @@ jobs:
|
||||
|
||||
- name: Push the Docker image.
|
||||
if: ${{ github.ref_name == github.event.repository.default_branch }}
|
||||
run: |
|
||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
|
||||
docker push $IMAGE_TAG
|
||||
run: docker push $IMAGE_TAG
|
||||
|
||||
27
.github/workflows/linux.yml
vendored
@@ -43,15 +43,6 @@ jobs:
|
||||
linux:
|
||||
name: Rocky Linux 8
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/${{ github.repository }}/centos_env
|
||||
credentials:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: scl enable gcc-toolset-12 -- bash --noprofile --norc -eo pipefail {0}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -75,12 +66,13 @@ jobs:
|
||||
|
||||
- name: First set up.
|
||||
run: |
|
||||
gcc --version
|
||||
ln -s /usr/src/Libraries
|
||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
|
||||
docker pull ghcr.io/$GITHUB_REPOSITORY/centos_env
|
||||
docker tag ghcr.io/$GITHUB_REPOSITORY/centos_env tdesktop:centos_env
|
||||
|
||||
- name: Telegram Desktop build.
|
||||
run: |
|
||||
cd $REPO_NAME/Telegram
|
||||
cd $REPO_NAME
|
||||
|
||||
DEFINE=""
|
||||
if [ -n "${{ matrix.defines }}" ]; then
|
||||
@@ -91,18 +83,21 @@ jobs:
|
||||
echo "ARTIFACT_NAME=Telegram" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
./configure.sh \
|
||||
docker run --rm \
|
||||
-v $PWD:/usr/src/tdesktop \
|
||||
-e CONFIG=Debug \
|
||||
tdesktop:centos_env \
|
||||
/usr/src/tdesktop/Telegram/build/docker/centos_env/build.sh \
|
||||
-D CMAKE_C_FLAGS_DEBUG="" \
|
||||
-D CMAKE_CXX_FLAGS_DEBUG="" \
|
||||
-D CMAKE_C_FLAGS="-Werror" \
|
||||
-D CMAKE_CXX_FLAGS="-Werror" \
|
||||
-D CMAKE_EXE_LINKER_FLAGS="-s" \
|
||||
-D TDESKTOP_API_TEST=ON \
|
||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF \
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF \
|
||||
$DEFINE
|
||||
|
||||
cmake --build ../out --config Debug --parallel
|
||||
|
||||
- name: Check.
|
||||
run: |
|
||||
filePath="$REPO_NAME/out/Debug/Telegram"
|
||||
@@ -121,7 +116,7 @@ jobs:
|
||||
run: |
|
||||
cd $REPO_NAME/out/Debug
|
||||
mkdir artifact
|
||||
mv Telegram artifact/
|
||||
mv {Telegram,Updater} artifact/
|
||||
- uses: actions/upload-artifact@master
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
name: Upload artifact.
|
||||
|
||||
1
.github/workflows/mac.yml
vendored
@@ -115,6 +115,7 @@ jobs:
|
||||
-D CMAKE_CXX_FLAGS="-Werror" \
|
||||
-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO \
|
||||
-D TDESKTOP_API_TEST=ON \
|
||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF \
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF \
|
||||
$DEFINE
|
||||
|
||||
|
||||
1
.github/workflows/mac_packaged.yml
vendored
@@ -73,6 +73,7 @@ jobs:
|
||||
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
||||
|
||||
xcodebuild -version > CACHE_KEY.txt
|
||||
brew list --versions >> CACHE_KEY.txt
|
||||
echo $MANUAL_CACHING >> CACHE_KEY.txt
|
||||
echo "$GITHUB_WORKSPACE" >> CACHE_KEY.txt
|
||||
if [ "$AUTO_CACHING" = "1" ]; then
|
||||
|
||||
31
.github/workflows/no-response.yml
vendored
@@ -9,11 +9,38 @@ on:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
noResponse:
|
||||
waiting-for-answer:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: lee-dohm/no-response@v0.5.0
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
# Label requiring a response
|
||||
responseRequiredLabel: waiting for answer
|
||||
|
||||
needs-user-action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: lee-dohm/no-response@v0.5.0
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
responseRequiredLabel: needs user action
|
||||
|
||||
cant-reproduce:
|
||||
if: github.event_name != 'issue_comment'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: lee-dohm/no-response@v0.5.0
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
responseRequiredLabel: cant reproduce
|
||||
closeComment: >
|
||||
This issue has been automatically closed because no developer succeeded to
|
||||
reproduce the issue with the given reproduction steps. With only the
|
||||
information that is currently in the issue, we don't have enough
|
||||
information to take action. Please reach out if you find what's missing to
|
||||
reproduce the issue so that we can investigate further.
|
||||
|
||||
|
||||
Note that GitHub is a developer communication platform. If you're an ordinary
|
||||
user seeking for help, get to support crew via `Settings -> Ask question` in
|
||||
the application.
|
||||
|
||||
5
.github/workflows/win.yml
vendored
@@ -169,6 +169,7 @@ jobs:
|
||||
%TDESKTOP_BUILD_GENERATOR% ^
|
||||
%TDESKTOP_BUILD_ARCH% ^
|
||||
%TDESKTOP_BUILD_API% ^
|
||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF ^
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF ^
|
||||
-D DESKTOP_APP_NO_PDB=ON ^
|
||||
%TDESKTOP_BUILD_DEFINE%
|
||||
@@ -178,8 +179,10 @@ jobs:
|
||||
- name: Move artifact.
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
||||
run: |
|
||||
set OUT=%TBUILD%\%REPO_NAME%\out\Debug
|
||||
mkdir artifact
|
||||
move %TBUILD%\%REPO_NAME%\out\Debug\Telegram.exe artifact/
|
||||
move %OUT%\Telegram.exe artifact/
|
||||
move %OUT%\Updater.exe artifact/
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload artifact.
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
||||
|
||||
@@ -60,9 +60,9 @@ include(cmake/options.cmake)
|
||||
|
||||
if (NOT DESKTOP_APP_USE_PACKAGED)
|
||||
if (WIN32)
|
||||
set(qt_version 5.15.11)
|
||||
set(qt_version 5.15.12)
|
||||
elseif (APPLE)
|
||||
set(qt_version 6.2.6)
|
||||
set(qt_version 6.2.7)
|
||||
endif()
|
||||
endif()
|
||||
include(cmake/external/qt/package.cmake)
|
||||
|
||||
2
LEGAL
@@ -1,7 +1,7 @@
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
Copyright (c) 2014-2023 The Telegram Desktop Authors.
|
||||
Copyright (c) 2014-2024 The Telegram Desktop Authors.
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -406,6 +406,8 @@ PRIVATE
|
||||
chat_helpers/tabbed_section.h
|
||||
chat_helpers/tabbed_selector.cpp
|
||||
chat_helpers/tabbed_selector.h
|
||||
chat_helpers/ttl_media_layer_widget.cpp
|
||||
chat_helpers/ttl_media_layer_widget.h
|
||||
core/application.cpp
|
||||
core/application.h
|
||||
core/base_integration.cpp
|
||||
@@ -513,6 +515,7 @@ PRIVATE
|
||||
data/data_groups.h
|
||||
data/data_histories.cpp
|
||||
data/data_histories.h
|
||||
data/data_lastseen_status.h
|
||||
data/data_location.cpp
|
||||
data/data_location.h
|
||||
data/data_media_rotation.cpp
|
||||
@@ -550,6 +553,10 @@ PRIVATE
|
||||
data/data_replies_list.h
|
||||
data/data_reply_preview.cpp
|
||||
data/data_reply_preview.h
|
||||
data/data_saved_messages.cpp
|
||||
data/data_saved_messages.h
|
||||
data/data_saved_sublist.cpp
|
||||
data/data_saved_sublist.h
|
||||
data/data_search_controller.cpp
|
||||
data/data_search_controller.h
|
||||
data/data_send_action.cpp
|
||||
@@ -605,6 +612,8 @@ PRIVATE
|
||||
dialogs/dialogs_row.h
|
||||
dialogs/dialogs_search_from_controllers.cpp
|
||||
dialogs/dialogs_search_from_controllers.h
|
||||
dialogs/dialogs_search_tags.cpp
|
||||
dialogs/dialogs_search_tags.h
|
||||
dialogs/dialogs_widget.cpp
|
||||
dialogs/dialogs_widget.h
|
||||
dialogs/ui/dialogs_layout.cpp
|
||||
@@ -744,6 +753,8 @@ PRIVATE
|
||||
history/view/reactions/history_view_reactions_strip.h
|
||||
history/view/reactions/history_view_reactions_tabs.cpp
|
||||
history/view/reactions/history_view_reactions_tabs.h
|
||||
history/view/history_view_about_view.cpp
|
||||
history/view/history_view_about_view.h
|
||||
history/view/history_view_bottom_info.cpp
|
||||
history/view/history_view_bottom_info.h
|
||||
history/view/history_view_contact_status.cpp
|
||||
@@ -796,6 +807,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_transcribe_button.cpp
|
||||
history/view/history_view_transcribe_button.h
|
||||
history/view/history_view_translate_bar.cpp
|
||||
@@ -897,6 +910,8 @@ PRIVATE
|
||||
info/profile/info_profile_values.h
|
||||
info/profile/info_profile_widget.cpp
|
||||
info/profile/info_profile_widget.h
|
||||
info/saved/info_saved_sublists_widget.cpp
|
||||
info/saved/info_saved_sublists_widget.h
|
||||
info/settings/info_settings_widget.cpp
|
||||
info/settings/info_settings_widget.h
|
||||
info/similar_channels/info_similar_channels_widget.cpp
|
||||
@@ -1004,6 +1019,7 @@ PRIVATE
|
||||
media/audio/media_audio.h
|
||||
media/audio/media_audio_capture.cpp
|
||||
media/audio/media_audio_capture.h
|
||||
media/audio/media_audio_capture_common.h
|
||||
media/audio/media_audio_ffmpeg_loader.cpp
|
||||
media/audio/media_audio_ffmpeg_loader.h
|
||||
media/audio/media_audio_loader.cpp
|
||||
@@ -1219,8 +1235,6 @@ PRIVATE
|
||||
platform/mac/touchbar/mac_touchbar_manager.mm
|
||||
platform/mac/touchbar/mac_touchbar_media_view.h
|
||||
platform/mac/touchbar/mac_touchbar_media_view.mm
|
||||
platform/win/audio_win.cpp
|
||||
platform/win/audio_win.h
|
||||
platform/win/file_utilities_win.cpp
|
||||
platform/win/file_utilities_win.h
|
||||
platform/win/launcher_win.cpp
|
||||
@@ -1244,7 +1258,6 @@ PRIVATE
|
||||
platform/win/windows_autostart_task.h
|
||||
platform/win/windows_toast_activator.cpp
|
||||
platform/win/windows_toast_activator.h
|
||||
platform/platform_audio.h
|
||||
platform/platform_file_utilities.h
|
||||
platform/platform_launcher.h
|
||||
platform/platform_integration.cpp
|
||||
|
||||
BIN
Telegram/Resources/animations/voice_ttl_idle.tgs
Normal file
BIN
Telegram/Resources/animations/voice_ttl_start.tgs
Normal file
4
Telegram/Resources/art/ttl/video_message_icon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg baseProfile="tiny" version="1.2" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m27.57 30.79q0.77-0.44 1.14-1.28 4.38-9.86 4.67-24.25 0.03-1.64 1.63-1.54 1.14 0.07 1.9 0.65c14.45 10.9 28.35 31.97 18.06 50.37-9.55 17.08-32.38 15.75-41.59-0.69-5.25-9.37-0.83-23.06 4.26-32.03a2.13 2.12 43.5 0 1 3.64-0.09l5.53 8.68a0.57 0.56-31.3 0 0 0.76 0.18z" fill="#fff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 427 B |
BIN
Telegram/Resources/art/winners.tgs
Normal file
BIN
Telegram/Resources/icons/chat/audio_once.png
Normal file
|
After Width: | Height: | Size: 776 B |
BIN
Telegram/Resources/icons/chat/audio_once@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/chat/audio_once@3x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Telegram/Resources/icons/chat/large_lockedchat.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/chat/large_lockedchat@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram/Resources/icons/chat/large_lockedchat@3x.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
Telegram/Resources/icons/chat/mini_media_once.png
Normal file
|
After Width: | Height: | Size: 561 B |
BIN
Telegram/Resources/icons/chat/mini_media_once@2x.png
Normal file
|
After Width: | Height: | Size: 1011 B |
BIN
Telegram/Resources/icons/chat/mini_media_once@3x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/dialogs/avatar_hidden.png
Normal file
|
After Width: | Height: | Size: 919 B |
BIN
Telegram/Resources/icons/dialogs/avatar_hidden@2x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/dialogs/avatar_hidden@3x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Telegram/Resources/icons/dialogs/avatar_notes.png
Normal file
|
After Width: | Height: | Size: 753 B |
BIN
Telegram/Resources/icons/dialogs/avatar_notes@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/dialogs/avatar_notes@3x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/dialogs/mini_arrow.png
Normal file
|
After Width: | Height: | Size: 212 B |
BIN
Telegram/Resources/icons/dialogs/mini_arrow@2x.png
Normal file
|
After Width: | Height: | Size: 267 B |
BIN
Telegram/Resources/icons/dialogs/mini_arrow@3x.png
Normal file
|
After Width: | Height: | Size: 368 B |
BIN
Telegram/Resources/icons/dialogs/mini_tag_lock.png
Normal file
|
After Width: | Height: | Size: 283 B |
BIN
Telegram/Resources/icons/dialogs/mini_tag_lock@2x.png
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
Telegram/Resources/icons/dialogs/mini_tag_lock@3x.png
Normal file
|
After Width: | Height: | Size: 550 B |
BIN
Telegram/Resources/icons/info/info_media_saved.png
Normal file
|
After Width: | Height: | Size: 380 B |
BIN
Telegram/Resources/icons/info/info_media_saved@2x.png
Normal file
|
After Width: | Height: | Size: 664 B |
BIN
Telegram/Resources/icons/info/info_media_saved@3x.png
Normal file
|
After Width: | Height: | Size: 954 B |
BIN
Telegram/Resources/icons/menu/tag_filter.png
Normal file
|
After Width: | Height: | Size: 634 B |
BIN
Telegram/Resources/icons/menu/tag_filter@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/menu/tag_filter@3x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/menu/tag_remove.png
Normal file
|
After Width: | Height: | Size: 692 B |
BIN
Telegram/Resources/icons/menu/tag_remove@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/menu/tag_remove@3x.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
Telegram/Resources/icons/menu/tag_rename.png
Normal file
|
After Width: | Height: | Size: 614 B |
BIN
Telegram/Resources/icons/menu/tag_rename@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/menu/tag_rename@3x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/settings/premium/large_lastseen.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/settings/premium/large_lastseen@2x.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
Telegram/Resources/icons/settings/premium/large_lastseen@3x.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
Telegram/Resources/icons/settings/premium/large_readtime.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/settings/premium/large_readtime@2x.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
Telegram/Resources/icons/settings/premium/large_readtime@3x.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
Telegram/Resources/icons/settings/premium/tags.png
Normal file
|
After Width: | Height: | Size: 593 B |
BIN
Telegram/Resources/icons/settings/premium/tags@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/settings/premium/tags@3x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/voice_lock/audio_once_bg.png
Normal file
|
After Width: | Height: | Size: 496 B |
BIN
Telegram/Resources/icons/voice_lock/audio_once_bg@2x.png
Normal file
|
After Width: | Height: | Size: 895 B |
BIN
Telegram/Resources/icons/voice_lock/audio_once_bg@3x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/voice_lock/audio_once_number.png
Normal file
|
After Width: | Height: | Size: 269 B |
BIN
Telegram/Resources/icons/voice_lock/audio_once_number@2x.png
Normal file
|
After Width: | Height: | Size: 389 B |
BIN
Telegram/Resources/icons/voice_lock/audio_once_number@3x.png
Normal file
|
After Width: | Height: | Size: 529 B |
BIN
Telegram/Resources/icons/voice_lock/input_mic_s.png
Normal file
|
After Width: | Height: | Size: 528 B |
BIN
Telegram/Resources/icons/voice_lock/input_mic_s@2x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Telegram/Resources/icons/voice_lock/input_mic_s@3x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/voice_lock/recorded_delete.png
Normal file
|
After Width: | Height: | Size: 614 B |
BIN
Telegram/Resources/icons/voice_lock/recorded_delete@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/voice_lock/recorded_delete@3x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/win_quit.png
Normal file
|
After Width: | Height: | Size: 406 B |
BIN
Telegram/Resources/icons/win_quit@2x.png
Normal file
|
After Width: | Height: | Size: 686 B |
BIN
Telegram/Resources/icons/win_quit@3x.png
Normal file
|
After Width: | Height: | Size: 952 B |
@@ -141,6 +141,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_status_last_week" = "last seen within a week";
|
||||
"lng_status_last_month" = "last seen within a month";
|
||||
"lng_status_lastseen_now" = "last seen just now";
|
||||
"lng_status_lastseen_when" = "when?";
|
||||
"lng_status_lastseen_minutes#one" = "last seen {count} minute ago";
|
||||
"lng_status_lastseen_minutes#other" = "last seen {count} minutes ago";
|
||||
"lng_status_lastseen_hours#one" = "last seen {count} hour ago";
|
||||
@@ -168,6 +169,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_remember" = "Remember this choice";
|
||||
|
||||
"lng_lastseen_show_title" = "Show Your Last Seen";
|
||||
"lng_lastseen_show_about" = "To see **{user}'s** Last Seen time, either start\nshowing your own Last Seen time...";
|
||||
"lng_lastseen_show_button" = "Show My Last Seen";
|
||||
"lng_lastseen_or" = "or";
|
||||
"lng_lastseen_premium_title" = "Upgrade to Premium";
|
||||
"lng_lastseen_premium_about" = "Subscription will let you see **{user}'s** Last Seen\nstatus without showing yours.";
|
||||
"lng_lastseen_premium_button" = "Subscribe to Telegram Premium";
|
||||
"lng_lastseen_shown_toast" = "Your last seen time is now visible.";
|
||||
|
||||
"lng_readtime_show_title" = "Show Your Read Date";
|
||||
"lng_readtime_show_about" = "To see when **{user}** read the message,\neither start showing your own read time...";
|
||||
"lng_readtime_show_button" = "Show My Read Time";
|
||||
"lng_readtime_or" = "or";
|
||||
"lng_readtime_premium_title" = "Upgrade to Premium";
|
||||
"lng_readtime_premium_about" = "Subscription will let you see **{user}'s** read time\nwithout showing yours.";
|
||||
"lng_readtime_premium_button" = "Subscribe to Telegram Premium";
|
||||
"lng_readtime_shown_toast" = "Your read times are now visible.";
|
||||
|
||||
"lng_channels_limit_title" = "Too Many Communities";
|
||||
"lng_channels_limit1#one" = "You are a member of **{count}** groups and channels.";
|
||||
"lng_channels_limit1#other" = "You are a member of **{count}** groups and channels.";
|
||||
@@ -395,6 +414,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_dlg_new_bot_name" = "Bot name";
|
||||
"lng_no_chats" = "Your chats will be here";
|
||||
"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...";
|
||||
"lng_contacts_not_found" = "No contacts found";
|
||||
"lng_topics_not_found" = "No topics found.";
|
||||
@@ -413,7 +433,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_username_invalid" = "This username is invalid.";
|
||||
"lng_username_occupied" = "This username is already occupied.";
|
||||
"lng_username_too_short" = "This username is too short.";
|
||||
"lng_username_purchase_available" = "Sorry, this link is occupied by someone. But it's available for purchase through\nofficial {link}.";
|
||||
"lng_username_purchase_available" = "**This username is already taken.** However, it is currently available for purchase. {link}";
|
||||
"lng_username_purchase_available_link" = "Learn more...";
|
||||
"lng_username_bad_symbols" = "Only a-z, 0-9, and underscores allowed.";
|
||||
"lng_username_available" = "This username is available.";
|
||||
"lng_username_not_found" = "User @{user} not found.";
|
||||
@@ -591,6 +612,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_section_background" = "Chat background";
|
||||
"lng_settings_bg_from_gallery" = "Choose from gallery";
|
||||
"lng_settings_bg_from_file" = "Choose from file";
|
||||
"lng_settings_bg_remove" = "Remove wallpaper";
|
||||
"lng_settings_bg_theme_edit" = "Edit theme";
|
||||
"lng_settings_bg_theme_create" = "Create new theme";
|
||||
"lng_settings_bg_cloud_themes" = "Custom themes";
|
||||
@@ -609,6 +631,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_call_accept_calls" = "Accept calls from this device";
|
||||
"lng_settings_call_device_default" = "Same as the System";
|
||||
|
||||
"lng_settings_section_devices" = "Speakers and Camera";
|
||||
"lng_settings_devices_calls" = "Calls and video chats";
|
||||
"lng_settings_devices_calls_same" = "Use the same devices for calls";
|
||||
"lng_settings_devices_inactive" = "Unavailable";
|
||||
|
||||
"lng_settings_language" = "Language";
|
||||
"lng_settings_default_scale" = "Default interface scale";
|
||||
"lng_settings_connection_type" = "Connection type";
|
||||
@@ -622,6 +649,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_phone_number_privacy" = "Phone number";
|
||||
"lng_settings_forwards_privacy" = "Forwarded messages";
|
||||
"lng_settings_profile_photo_privacy" = "Profile photo";
|
||||
"lng_settings_messages_privacy" = "Messages";
|
||||
"lng_settings_voices_privacy" = "Voice messages";
|
||||
"lng_settings_bio_privacy" = "Bio";
|
||||
"lng_settings_privacy_premium" = "Only subscribers of {link} can restrict receiving voice messages.";
|
||||
@@ -813,6 +841,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_manage_enabled_dictionary" = "Dictionary is enabled";
|
||||
"lng_settings_manage_remove_dictionary" = "Remove Dictionary";
|
||||
|
||||
"lng_settings_gift_premium" = "Premium Gifting";
|
||||
"lng_settings_gift_premium_users_confirm" = "Proceed";
|
||||
"lng_settings_gift_premium_users_error#one" = "You can select maximum {count} user.";
|
||||
"lng_settings_gift_premium_users_error#other" = "You can select maximum {count} users.";
|
||||
|
||||
"lng_backgrounds_header" = "Choose Wallpaper";
|
||||
"lng_theme_sure_keep" = "Keep this theme?";
|
||||
"lng_theme_reverting#one" = "Reverting to the old theme in {count} second.";
|
||||
@@ -833,6 +866,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_background_blur" = "Blurred";
|
||||
"lng_background_sure_delete" = "Are you sure you want to delete this background?";
|
||||
"lng_background_other_info" = "{user} will be able to apply this wallpaper";
|
||||
"lng_background_other_channel" = "All subscribers will see this wallpaper";
|
||||
"lng_background_apply1" = "Apply the wallpaper in this chat.";
|
||||
"lng_background_apply2" = "Enjoy the view.";
|
||||
"lng_background_apply_button" = "Apply For This Chat";
|
||||
@@ -841,6 +875,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_background_reset_default" = "Reset";
|
||||
"lng_background_apply_me" = "Apply for me";
|
||||
"lng_background_apply_both" = "Apply for me and {user}";
|
||||
"lng_background_apply_channel" = "Apply For Channel";
|
||||
|
||||
"lng_download_path_ask" = "Ask download path for each file";
|
||||
"lng_download_path" = "Download path";
|
||||
@@ -1051,6 +1086,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_privacy_contacts" = "My contacts";
|
||||
"lng_edit_privacy_close_friends" = "Close friends";
|
||||
"lng_edit_privacy_nobody" = "Nobody";
|
||||
"lng_edit_privacy_premium" = "Premium users";
|
||||
"lng_edit_privacy_exceptions" = "Add exceptions";
|
||||
|
||||
"lng_edit_privacy_exceptions_count#one" = "{count} user";
|
||||
@@ -1077,6 +1113,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_privacy_lastseen_exceptions" = "These settings will override the values above.";
|
||||
"lng_edit_privacy_lastseen_always_title" = "Always share with";
|
||||
"lng_edit_privacy_lastseen_never_title" = "Never share with";
|
||||
"lng_edit_lastseen_hide_read_time" = "Hide read time";
|
||||
"lng_edit_lastseen_hide_read_time_about" = "Hide the time when you read messages from people who can't see your last seen. If you turn this on, their read time will also be hidden from you. This setting does not affect group chats.";
|
||||
"lng_edit_lastseen_subscribe" = "Subscribe to Telegram Premium";
|
||||
"lng_edit_lastseen_subscribe_about" = "If you subscribe to Premium, you will see other users' last seen and read time even if you hid yours from them (unless they specifically restricted it).";
|
||||
|
||||
"lng_edit_privacy_groups_title" = "Group invite settings";
|
||||
"lng_edit_privacy_groups_header" = "Who can invite you to groups and channels";
|
||||
@@ -1148,6 +1188,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_privacy_voices_always_title" = "Always allow";
|
||||
"lng_edit_privacy_voices_never_title" = "Never allow";
|
||||
|
||||
"lng_messages_privacy_title" = "Messages";
|
||||
"lng_messages_privacy_subtitle" = "Who can send me messages?";
|
||||
"lng_messages_privacy_everyone" = "Everybody";
|
||||
"lng_messages_privacy_restricted" = "My Contacts and Premium Users";
|
||||
"lng_messages_privacy_about" = "You can restrict incoming messages to only contacts and Premium users.";
|
||||
"lng_messages_privacy_premium_button" = "Subscribe to Telegram Premium";
|
||||
"lng_messages_privacy_premium_about" = "Subscribe now to change this setting and get access to other exclusive features of Telegram Premium.";
|
||||
"lng_messages_privacy_premium" = "Only subscribers of {link} can select this option.";
|
||||
"lng_messages_privacy_premium_link" = "Telegram Premium";
|
||||
|
||||
"lng_self_destruct_title" = "Account self-destruction";
|
||||
"lng_self_destruct_description" = "If you don't come online at least once within this period, your account will be deleted along with all groups, messages and contacts.";
|
||||
"lng_self_destruct_sessions_title" = "Session termination";
|
||||
@@ -1179,6 +1229,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_common_groups#other" = "{count} groups in common";
|
||||
"lng_profile_similar_channels#one" = "{count} similar channel";
|
||||
"lng_profile_similar_channels#other" = "{count} similar channels";
|
||||
"lng_profile_saved_messages#one" = "{count} saved message";
|
||||
"lng_profile_saved_messages#other" = "{count} saved messages";
|
||||
"lng_profile_participants_section" = "Members";
|
||||
"lng_profile_subscribers_section" = "Subscribers";
|
||||
"lng_profile_add_contact" = "Add Contact";
|
||||
@@ -1453,6 +1505,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_report_messages_none" = "Select Messages";
|
||||
"lng_report_messages_count#one" = "Report {count} Message";
|
||||
"lng_report_messages_count#other" = "Report {count} Messages";
|
||||
"lng_report_reaction" = "Report reaction";
|
||||
"lng_report_and_ban" = "Ban and report";
|
||||
"lng_report_reaction_title" = "Report reaction";
|
||||
"lng_report_reaction_about" = "Are you sure you want to report reactions from this user?";
|
||||
"lng_report_and_ban_button" = "Ban user";
|
||||
"lng_report_details_about" = "Please enter any additional details relevant to your report.";
|
||||
"lng_report_details" = "Additional Details";
|
||||
"lng_report_reason_spam" = "Spam";
|
||||
@@ -1682,7 +1739,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_giveaway_started" = "{from} just started a giveaway of Telegram Premium subscriptions to its followers.";
|
||||
"lng_action_giveaway_results#one" = "{count} winner of the giveaway was randomly selected by Telegram and received private messages with giftcodes.";
|
||||
"lng_action_giveaway_results#other" = "{count} winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes.";
|
||||
"lng_action_giveaway_results_some" = "Some winners of the giveaway was randomly selected by Telegram and received private messages with giftcodes.";
|
||||
"lng_action_giveaway_results_some" = "Some winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes.";
|
||||
"lng_action_giveaway_results_none" = "No winners of the giveaway could be selected.";
|
||||
|
||||
"lng_similar_channels_title" = "Similar channels";
|
||||
@@ -1704,6 +1761,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_ttl_video_received" = "{from} sent you a self-destructing video. Please view it on your mobile.";
|
||||
"lng_ttl_video_sent" = "You sent a self-destructing video.";
|
||||
"lng_ttl_video_expired" = "Video has expired";
|
||||
"lng_ttl_voice_sent" = "You sent a self-destructing voice messsage.";
|
||||
"lng_ttl_voice_expired" = "Voice message expired";
|
||||
"lng_ttl_round_sent" = "You sent a self-destructing video message.";
|
||||
"lng_ttl_round_expired" = "Round message expired";
|
||||
"lng_ttl_voice_tooltip_in" = "This voice message can only be played once.";
|
||||
"lng_ttl_voice_tooltip_out" = "This message will disappear once **{user}** plays it once.";
|
||||
"lng_ttl_voice_close_in" = "Delete and close";
|
||||
"lng_ttl_round_tooltip_in" = "This video message can only be played once.";
|
||||
"lng_ttl_round_tooltip_out" = "This message will disappear once **{user}** plays it once.";
|
||||
|
||||
"lng_profile_add_more_after_create" = "You will be able to add more members after you create the group.";
|
||||
"lng_profile_camera_title" = "Capture yourself";
|
||||
@@ -1836,6 +1902,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_sponsored_message_title" = "Sponsored";
|
||||
"lng_recommended_message_title" = "Recommended";
|
||||
"lng_edited" = "edited";
|
||||
"lng_commented" = "commented";
|
||||
"lng_edited_date" = "Edited: {date}";
|
||||
"lng_sent_date" = "Sent: {date}";
|
||||
"lng_views_tooltip#one" = "Views: {count}";
|
||||
@@ -1964,6 +2031,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_premium_summary_about_emoji_status" = "Add any of thousands emoji next to your name to display current activity.";
|
||||
"lng_premium_summary_subtitle_infinite_reactions" = "Infinite Reactions";
|
||||
"lng_premium_summary_about_infinite_reactions" = "React with thousands of emoji — with multiple reactions per message.";
|
||||
"lng_premium_summary_subtitle_tags_for_messages" = "Tags for Messages";
|
||||
"lng_premium_summary_about_tags_for_messages" = "Organize your Saved Messages with tags for quicker access.";
|
||||
"lng_premium_summary_subtitle_premium_stickers" = "Premium Stickers";
|
||||
"lng_premium_summary_about_premium_stickers" = "Exclusive enlarged stickers featuring additional effects, updated monthly.";
|
||||
"lng_premium_summary_subtitle_animated_emoji" = "Animated Emoji";
|
||||
@@ -2055,6 +2124,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_premium_gift_per" = "{cost} / month";
|
||||
"lng_premium_gift_terms" = "You can review the list of features and terms of use for Telegram Premium {link}.";
|
||||
"lng_premium_gift_terms_link" = "here";
|
||||
"lng_premium_gifts_about_user1" = "Give **{user}** access to exclusive features.";
|
||||
"lng_premium_gifts_about_user2" = "Give **{user}** and **{second_user}** access to exclusive features.";
|
||||
"lng_premium_gifts_about_user3" = "Give **{user}**, **{second_user}** and **{name}** access to exclusive features.";
|
||||
"lng_premium_gifts_about_user_more#one" = "Give **{user}**, **{second_user}**, **{name}** and **{count}** more friend access to exclusive features.";
|
||||
"lng_premium_gifts_about_user_more#other" = "Give **{user}**, **{second_user}**, **{name}** and **{count}** more friends access to exclusive features.";
|
||||
"lng_premium_gifts_about_reward#one" = "You will receive {emoji}**{count}** boost.";
|
||||
"lng_premium_gifts_about_reward#other" = "You will receive {emoji}**{count}** boosts.";
|
||||
"lng_premium_gifts_about_paid_title" = "Gifts Sent!";
|
||||
"lng_premium_gifts_about_paid1" = "**{user}** has been notified about the gifts you purchased.";
|
||||
"lng_premium_gifts_about_paid2" = "**{user}** and **{second_user}** have been notified about the gifts you purchased.";
|
||||
"lng_premium_gifts_about_paid3" = "**{user}**, **{second_user}** and **{name}** have been notified about the gifts you purchased.";
|
||||
"lng_premium_gifts_about_paid_more#one" = "**{user}**, **{second_user}**, **{name}** and **{count}** other have been notified about the gifts you purchased.";
|
||||
"lng_premium_gifts_about_paid_more#other" = "**{user}**, **{second_user}**, **{name}** and **{count}** others have been notified about the gifts you purchased.";
|
||||
"lng_premium_gifts_about_paid_below#one" = "They now have access to additional features.";
|
||||
"lng_premium_gifts_about_paid_below#other" = "They now have access to additional features.";
|
||||
"lng_premium_gifts_summary_subtitle" = "What's Included";
|
||||
"lng_premium_gifts_terms" = "By gifting Telegram Premium, you agree to the Telegram {link} and {policy}.";
|
||||
"lng_premium_gifts_terms_policy" = "Privacy Policy";
|
||||
|
||||
"lng_boost_channel_button" = "Boost Channel";
|
||||
"lng_boost_again_button" = "Boost Again";
|
||||
@@ -2111,6 +2198,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_boost_channel_needs_level_color#one" = "Your channel needs to reach **Level {count}** to change channel color.";
|
||||
"lng_boost_channel_needs_level_color#other" = "Your channel needs to reach **Level {count}** to change channel color.";
|
||||
|
||||
"lng_boost_channel_title_wallpaper" = "Enable wallpapers";
|
||||
"lng_boost_channel_needs_level_wallpaper#one" = "Your channel needs to reach **Level {count}** to change channel wallpaper.";
|
||||
"lng_boost_channel_needs_level_wallpaper#other" = "Your channel needs to reach **Level {count}** to change channel wallpaper.";
|
||||
|
||||
"lng_boost_channel_title_status" = "Enable emoji status";
|
||||
"lng_boost_channel_needs_level_status#one" = "Your channel needs to reach **Level {count}** to set emoji status.";
|
||||
"lng_boost_channel_needs_level_status#other" = "Your channel needs to reach **Level {count}** to set emoji status.";
|
||||
|
||||
"lng_boost_channel_title_reactions" = "Custom reactions";
|
||||
"lng_boost_channel_needs_level_reactions#one" = "Your channel needs to reach **Level {count}** to add **{same_count}** custom emoji as a reaction.";
|
||||
"lng_boost_channel_needs_level_reactions#other" = "Your channel needs to reach **Level {count}** to add **{same_count}** custom emoji as reactions.";
|
||||
@@ -2170,6 +2265,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_giveaway_maximum_users_error#other" = "You can select maximum {count} users.";
|
||||
"lng_giveaway_channels_confirm_title" = "Channel is Private";
|
||||
"lng_giveaway_channels_confirm_about" = "Are you sure you want to add a private channel? Users won't be able to join it without an invite link.";
|
||||
"lng_giveaway_additional_prizes" = "Additional prizes";
|
||||
"lng_giveaway_additional_about" = "Turn this on if you want to give the winners your own prizes in addition to Premium subscriptions.";
|
||||
"lng_giveaway_additional_prizes_ph" = "Enter your prize";
|
||||
"lng_giveaway_prizes_just_premium#one" = "All prizes: **{count}** Telegram Premium subscription {duration}.";
|
||||
"lng_giveaway_prizes_just_premium#other" = "All prizes: **{count}** Telegram Premium subscriptions {duration}.";
|
||||
"lng_giveaway_prizes_additional#one" = "All prizes: **{count}** {prize} with Telegram Premium subscription {duration}.";
|
||||
"lng_giveaway_prizes_additional#other" = "All prizes: **{count}** {prize} with Telegram Premium subscriptions {duration}.";
|
||||
"lng_giveaway_show_winners" = "Show winners";
|
||||
"lng_giveaway_show_winners_about" = "Choose whether to make the list of winners public when the giveaway ends.";
|
||||
|
||||
"lng_giveaway_created_title" = "Giveaway created";
|
||||
"lng_giveaway_created_body" = "Check your channels' {link} to see how this giveaway boosted your channel.";
|
||||
@@ -2189,6 +2293,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_prizes_title#one" = "Giveaway Prize";
|
||||
"lng_prizes_title#other" = "Giveaway Prizes";
|
||||
"lng_prizes_additional#one" = "**{count}** {prize}";
|
||||
"lng_prizes_additional#other" = "**{count}** {prize}";
|
||||
"lng_prizes_additional_with" = "with";
|
||||
"lng_prizes_about#one" = "**{count}** Telegram Premium Subscription {duration}.";
|
||||
"lng_prizes_about#other" = "**{count}** Telegram Premium Subscriptions {duration}.";
|
||||
"lng_prizes_participants" = "Participants";
|
||||
@@ -2207,6 +2314,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_prizes_end_text" = "This giveaway was sponsored by {admins}.";
|
||||
"lng_prizes_admins#one" = "the admins of {channel}, who aquired **{count} Telegram Premium** subscription {duration} for its followers";
|
||||
"lng_prizes_admins#other" = "the admins of {channel}, who aquired **{count} Telegram Premium** subscriptions {duration} for its followers.";
|
||||
"lng_prizes_additional_added#one" = "{channel} also included **{count} {prize}** in the prize. Admins of the channel are responsible for delivering this prize.";
|
||||
"lng_prizes_additional_added#other" = "{channel} also included **{count} {prize}** in the prizes. Admins of the channel are responsible for delivering these prizes.";
|
||||
"lng_prizes_how_when_finish" = "On {date}, Telegram will automatically select {winners}.";
|
||||
"lng_prizes_end_when_finish" = "On {date}, Telegram automatically selected {winners}.";
|
||||
"lng_prizes_end_activated#one" = "**{count}** of the winners already used their gift link.";
|
||||
@@ -2232,6 +2341,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_prizes_cancelled" = "The channel cancelled the prizes by reversing the payment for them.";
|
||||
"lng_prizes_badge" = "x{amount}";
|
||||
|
||||
"lng_prizes_results_title" = "Winners Selected!";
|
||||
"lng_prizes_results_about#one" = "**{count}** winner of the {link} was randomly selected by Telegram.";
|
||||
"lng_prizes_results_about#other" = "**{count}** winners of the {link} were randomly selected by Telegram.";
|
||||
"lng_prizes_results_link" = "Giveaway";
|
||||
"lng_prizes_results_winners" = "Winners";
|
||||
"lng_prizes_results_more#one" = "and {count} more!";
|
||||
"lng_prizes_results_more#other" = "and {count} more!";
|
||||
"lng_prizes_results_all" = "All winners received gift links in private messages.";
|
||||
"lng_prizes_results_some" = "Some winners couldn't be selected.";
|
||||
|
||||
"lng_gift_link_title" = "Gift Link";
|
||||
"lng_gift_link_about" = "This link allows you to activate\na **Telegram Premium** subscription.";
|
||||
"lng_gift_link_label_from" = "From";
|
||||
@@ -2334,6 +2453,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_in_dlg_contact" = "Contact";
|
||||
"lng_in_dlg_audio" = "Voice message";
|
||||
"lng_in_dlg_video_message" = "Video message";
|
||||
"lng_in_dlg_voice_message_ttl" = "One-time Voice Message";
|
||||
"lng_in_dlg_video_message_ttl" = "One-time Video Message";
|
||||
"lng_in_dlg_file" = "File";
|
||||
"lng_in_dlg_sticker" = "Sticker";
|
||||
"lng_in_dlg_sticker_emoji" = "{emoji} Sticker";
|
||||
@@ -2421,6 +2542,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_record_listen_cancel_sure" = "Are you sure you want to discard your recorded voice message?";
|
||||
"lng_record_lock_discard" = "Discard";
|
||||
"lng_record_hold_tip" = "Please hold the mouse button pressed to record a voice message.";
|
||||
"lng_record_once_first_tooltip" = "Click to set this message to **Play Once**.";
|
||||
"lng_record_once_active_tooltip" = "The recipients will be able to listen to it only once.";
|
||||
"lng_will_be_notified" = "Members will be notified when you post";
|
||||
"lng_wont_be_notified" = "Members will not be notified when you post";
|
||||
"lng_willbe_history" = "Please select a chat to start messaging";
|
||||
@@ -2435,6 +2558,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_saved_short" = "Save";
|
||||
"lng_saved_forward_here" = "Forward messages here for quick access";
|
||||
"lng_saved_quote_here" = "Quote here to save";
|
||||
"lng_saved_open_chat" = "Open Chat";
|
||||
"lng_saved_open_channel" = "Open Channel";
|
||||
"lng_saved_open_group" = "Open Group";
|
||||
"lng_saved_about_hidden" = "Senders of this messages restricted to link their name when forwarding.";
|
||||
|
||||
"lng_scheduled_messages" = "Scheduled Messages";
|
||||
"lng_scheduled_messages_empty" = "No scheduled messages here yet...";
|
||||
@@ -2461,6 +2588,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_comments_open_none" = "Leave a comment";
|
||||
"lng_replies_view_original" = "View in chat";
|
||||
"lng_replies_messages" = "Replies";
|
||||
"lng_hidden_author_messages" = "Author Hidden";
|
||||
"lng_my_notes" = "My Notes";
|
||||
"lng_replies_discussion_started" = "Discussion started";
|
||||
"lng_replies_no_comments" = "No comments here yet...";
|
||||
|
||||
@@ -2623,6 +2752,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_copy_email" = "Copy Email Address";
|
||||
"lng_context_copy_hashtag" = "Copy Hashtag";
|
||||
"lng_context_copy_mention" = "Copy Username";
|
||||
"lng_context_copy_filename" = "Copy Filename";
|
||||
"lng_context_save_image" = "Save Image As...";
|
||||
"lng_context_copy_image" = "Copy Image";
|
||||
"lng_context_cancel_download" = "Cancel Download";
|
||||
@@ -2677,17 +2807,34 @@ 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_set_as_quick" = "Set As Quick";
|
||||
"lng_context_set_as_quick" = "Set as Quick";
|
||||
"lng_context_filter_by_tag" = "Filter by Tag";
|
||||
"lng_context_tag_add_name" = "Add Name";
|
||||
"lng_context_tag_edit_name" = "Edit Name";
|
||||
"lng_context_remove_tag" = "Remove Tag";
|
||||
"lng_context_delete_from_disk" = "Delete from disk";
|
||||
"lng_context_delete_all_files" = "Delete all files";
|
||||
"lng_context_save_custom_sound" = "Save for notifications";
|
||||
"lng_context_translate" = "Translate";
|
||||
"lng_context_translate_selected" = "Translate Selected Text";
|
||||
"lng_context_read_hidden" = "read";
|
||||
"lng_context_read_show" = "show when";
|
||||
|
||||
"lng_add_tag_about" = "Tag this message with an emoji for quick search.";
|
||||
"lng_subscribe_tag_about" = "Organize your Saved Messages with tags. {link}";
|
||||
"lng_subscribe_tag_link" = "Learn More...";
|
||||
"lng_edit_tag_about" = "You can label your emoji tag with a text name.";
|
||||
"lng_edit_tag_name" = "Name";
|
||||
"lng_add_tag_button" = "Add tags";
|
||||
"lng_add_tag_phrase" = "to messages {arrow}";
|
||||
"lng_add_tag_phrase_long" = "to your Saved Messages {arrow}";
|
||||
"lng_unlock_tags" = "Unlock";
|
||||
|
||||
"lng_context_animated_emoji" = "This message contains emoji from **{name} pack**.";
|
||||
"lng_context_animated_emoji_many#one" = "This message contains emoji from **{count} pack**.";
|
||||
"lng_context_animated_emoji_many#other" = "This message contains emoji from **{count} packs**.";
|
||||
"lng_context_animated_reaction" = "This reaction is from **{name} pack**.";
|
||||
"lng_context_animated_tag" = "This tag is from **{name} pack**.";
|
||||
"lng_context_animated_reactions" = "Reactions contain emoji from **{name} pack**.";
|
||||
"lng_context_animated_reactions_many#one" = "Reactions contain emoji from **{count} pack**.";
|
||||
"lng_context_animated_reactions_many#other" = "Reactions contain emoji from **{count} packs**.";
|
||||
@@ -2801,6 +2948,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_sign_messages" = "Sign messages";
|
||||
"lng_edit_group" = "Edit group";
|
||||
"lng_edit_channel_color" = "Change name color";
|
||||
"lng_edit_channel_level_min" = "Level 1+";
|
||||
"lng_edit_channel_wallpaper" = "Channel wallpaper";
|
||||
"lng_edit_channel_wallpaper_about" = "Set a wallpaper that will be visible for everyone reading your channel.";
|
||||
"lng_edit_channel_status" = "Channel emoji status";
|
||||
"lng_edit_channel_status_about" = "Choose a status that will be shown next to the channel's name.";
|
||||
"lng_edit_self_title" = "Edit your name";
|
||||
"lng_confirm_contact_data" = "New Contact";
|
||||
"lng_add_contact" = "Create";
|
||||
@@ -3320,7 +3472,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_rtmp_key_copy" = "Copy Stream Key";
|
||||
"lng_group_call_rtmp_key_copied" = "Stream Key copied to clipboard.";
|
||||
"lng_group_call_rtmp_key_warning" = "**Never share your Stream Key with anyone or show it on stream!**";
|
||||
"lng_group_call_rtmp_info" = "To stream video with another app, enter these Server URL and Stream Key in your streaming app.\n\nOnce you start broadcasting in your streaming app, tap Start Streaming below.";
|
||||
"lng_group_call_rtmp_info" = "To stream video with another app, enter these Server URL and Stream Key in your streaming app.\n\nOnce you start broadcasting in your streaming app, click Start Streaming below.";
|
||||
"lng_group_call_rtmp_start" = "Start Streaming";
|
||||
"lng_group_call_rtmp_revoke" = "Revoke Stream Key";
|
||||
"lng_group_call_rtmp_revoke_sure" = "Are you sure you want to revoke your Server URL and Stream Key?";
|
||||
@@ -3488,6 +3640,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_restricted_send_voice_messages" = "{user} restricted sending of voice messages to them.";
|
||||
"lng_restricted_send_video_messages" = "{user} restricted sending of video messages to them.";
|
||||
"lng_restricted_send_non_premium" = "Only Premium users can message {user}.";
|
||||
"lng_restricted_send_non_premium_more" = "Learn more...";
|
||||
|
||||
"lng_send_non_premium_text" = "Subscribe to **Premium**\n to message {user}.";
|
||||
"lng_send_non_premium_go" = "Get Premium";
|
||||
"lng_send_non_premium_story" = "Replies restricted";
|
||||
"lng_send_non_premium_unlock" = "unlock";
|
||||
"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_exceptions_list_title" = "Exceptions";
|
||||
"lng_removed_list_title" = "Removed users";
|
||||
@@ -3615,6 +3776,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_set_background_emoji" = "{from} set channel background emoji to {emoji}";
|
||||
"lng_admin_log_change_background_emoji" = "{from} changed channel background emoji from {previous} to {emoji}";
|
||||
"lng_admin_log_removed_background_emoji" = "{from} removed channel background emoji {emoji}";
|
||||
"lng_admin_log_change_profile_color" = "{from} changed channel profile color from {previous} to {color}";
|
||||
"lng_admin_log_set_profile_background_emoji" = "{from} set channel profile background emoji to {emoji}";
|
||||
"lng_admin_log_change_profile_background_emoji" = "{from} changed channel profile background emoji from {previous} to {emoji}";
|
||||
"lng_admin_log_removed_profile_background_emoji" = "{from} removed channel profile background emoji {emoji}";
|
||||
"lng_admin_log_change_wallpaper" = "{from} changed channel wallpaper";
|
||||
"lng_admin_log_set_status" = "{from} set channel emoji status to {emoji}";
|
||||
"lng_admin_log_change_status" = "{from} changed channel emoji status from {previous} to {emoji}";
|
||||
"lng_admin_log_removed_status" = "{from} removed channel emoji status {emoji}";
|
||||
"lng_admin_log_set_status_until" = "{from} set channel emoji status to {emoji} until {date}";
|
||||
"lng_admin_log_change_status_until" = "{from} changed channel emoji status from {previous} to {emoji} until {date}";
|
||||
"lng_admin_log_user_with_username" = "{name} ({mention})";
|
||||
"lng_admin_log_messages_ttl_set" = "{from} enabled messages auto-delete after {duration}";
|
||||
"lng_admin_log_messages_ttl_changed" = "{from} changed messages auto-delete period from {previous} to {duration}";
|
||||
@@ -4145,7 +4316,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_sponsored_hide_ads" = "Hide";
|
||||
"lng_sponsored_title" = "What are sponsored messages?";
|
||||
"lng_sponsored_info_description1" = "Unlike other apps, Telegram never uses your private data to target ads. Sponsored messages on Telegram are based solely on the topic of the public channels in which they are shown. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored messages.\n\nUnlike other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can’t spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers a free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible advertisers at:";
|
||||
"lng_sponsored_info_description1" = "Unlike other apps, Telegram never uses your private data to target ads. Sponsored messages on Telegram are based solely on the topic of the public channels in which they are shown. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored messages.\n\nUnlike other apps, Telegram doesn't track whether you clicked on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can’t spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers a free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible advertisers at:";
|
||||
"lng_sponsored_info_description2" = "Sponsored Messages are currently in test mode. Once they are fully launched and allow Telegram to cover its basic costs, we will start sharing ad revenue with the owners of public channels in which sponsored messages are displayed.\n\nOnline ads should no longer be synonymous with abuse of user privacy. Let us redefine how a tech company should operate – together.";
|
||||
"lng_sponsored_info_menu" = "About this ad";
|
||||
"lng_sponsored_info_submenu" = "Advertiser: {text}";
|
||||
@@ -4207,6 +4378,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_request_peer_confirm_rights" = "This will also add {bot} to {chat} with the following rights: {rights}.";
|
||||
"lng_request_peer_confirm_send" = "Send";
|
||||
"lng_request_user_title" = "Choose User";
|
||||
"lng_request_users_title" = "Choose Users";
|
||||
"lng_request_user_premium_yes" = "The user should have a Premium subscription.";
|
||||
"lng_request_user_premium_no" = "The user shouldn't have a Premium subscription.";
|
||||
"lng_request_user_no" = "No such users";
|
||||
@@ -4258,6 +4430,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stories_views#one" = "{count} view";
|
||||
"lng_stories_views#other" = "{count} views";
|
||||
"lng_stories_no_views" = "No views";
|
||||
"lng_stories_view_reactions" = "View reactions";
|
||||
"lng_stories_unsupported" = "This story is not supported\nby your version of Telegram.";
|
||||
"lng_stories_cant_reply" = "You can't reply to this story.";
|
||||
"lng_stories_about_silent" = "This video has no sound.";
|
||||
@@ -4312,6 +4485,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stories_channel_archive_done_many#one" = "{count} story is hidden from the channel page.";
|
||||
"lng_stories_channel_archive_done_many#other" = "{count} stories are hidden from the channel page.";
|
||||
"lng_stories_save_promo" = "Subscribe to {link} to download other people's unprotected stories to disk.";
|
||||
"lng_stories_reaction_as_message" = "Send reaction as a private message";
|
||||
|
||||
"lng_stealth_mode_menu_item" = "Stealth Mode";
|
||||
"lng_stealth_mode_title" = "Stealth Mode";
|
||||
|
||||
@@ -11,5 +11,7 @@
|
||||
<file alias="ttl.tgs">../../animations/ttl.tgs</file>
|
||||
<file alias="discussion.tgs">../../animations/discussion.tgs</file>
|
||||
<file alias="stats.tgs">../../animations/stats.tgs</file>
|
||||
<file alias="voice_ttl_idle.tgs">../../animations/voice_ttl_idle.tgs</file>
|
||||
<file alias="voice_ttl_start.tgs">../../animations/voice_ttl_start.tgs</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<file alias="art/slot_2_idle.tgs">../../art/slot_2_idle.tgs</file>
|
||||
<file alias="art/slot_back.tgs">../../art/slot_back.tgs</file>
|
||||
<file alias="art/slot_pull.tgs">../../art/slot_pull.tgs</file>
|
||||
<file alias="art/winners.tgs">../../art/winners.tgs</file>
|
||||
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
|
||||
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
|
||||
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
|
||||
@@ -25,6 +26,7 @@
|
||||
<file alias="recording/info_audio.svg">../../art/recording/recording_info_audio.svg</file>
|
||||
<file alias="recording/info_video_landscape.svg">../../art/recording/recording_info_video_landscape.svg</file>
|
||||
<file alias="recording/info_video_portrait.svg">../../art/recording/recording_info_video_portrait.svg</file>
|
||||
<file alias="ttl/video_message_icon.svg">../../art/ttl/video_message_icon.svg</file>
|
||||
<file alias="icons/settings/dino.svg">../../icons/settings/dino.svg</file>
|
||||
<file alias="icons/settings/star.svg">../../icons/settings/star.svg</file>
|
||||
<file alias="icons/settings/starmini.svg">../../icons/settings/starmini.svg</file>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="4.12.0.0" />
|
||||
Version="4.14.15.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 4,12,0,0
|
||||
PRODUCTVERSION 4,12,0,0
|
||||
FILEVERSION 4,14,15,0
|
||||
PRODUCTVERSION 4,14,15,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "4.12.0.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "FileVersion", "4.14.15.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "4.12.0.0"
|
||||
VALUE "ProductVersion", "4.14.15.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,12,0,0
|
||||
PRODUCTVERSION 4,12,0,0
|
||||
FILEVERSION 4,14,15,0
|
||||
PRODUCTVERSION 4,14,15,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", "4.12.0.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "FileVersion", "4.14.15.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "4.12.0.0"
|
||||
VALUE "ProductVersion", "4.14.15.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -6,6 +6,7 @@ For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
@@ -537,11 +537,12 @@ HANDLE _generateDumpFileAtPath(const WCHAR *path) {
|
||||
|
||||
GetLocalTime(&stLocalTime);
|
||||
|
||||
wsprintf(szFileName, L"%s%s-%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
|
||||
szPath, szExeName, updaterVersionStr,
|
||||
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
|
||||
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
|
||||
GetCurrentProcessId(), GetCurrentThreadId());
|
||||
wsprintf(
|
||||
szFileName, L"%s%s-%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
|
||||
szPath, szExeName, updaterVersionStr,
|
||||
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
|
||||
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
|
||||
GetCurrentProcessId(), GetCurrentThreadId());
|
||||
return CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
|
||||
}
|
||||
|
||||
@@ -562,7 +563,7 @@ void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) {
|
||||
DWORD len = GetModuleFileName(GetModuleHandle(0), szPath, maxFileLen);
|
||||
if (!len) return;
|
||||
|
||||
WCHAR *pathEnd = szPath + len;
|
||||
WCHAR *pathEnd = szPath + len;
|
||||
|
||||
if (!_wcsicmp(pathEnd - wcslen(_exeName), _exeName)) {
|
||||
wsprintf(pathEnd - wcslen(_exeName), L"");
|
||||
|
||||
@@ -415,12 +415,16 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
||||
const auto peer = item->history()->peer;
|
||||
const auto itemId = item->id;
|
||||
const auto id = int32(button->buttonId);
|
||||
const auto chosen = [=](not_null<PeerData*> result) {
|
||||
const auto chosen = [=](std::vector<not_null<PeerData*>> result) {
|
||||
peer->session().api().request(MTPmessages_SendBotRequestedPeer(
|
||||
peer->input,
|
||||
MTP_int(itemId),
|
||||
MTP_int(id),
|
||||
result->input
|
||||
MTP_vector_from_range(
|
||||
result
|
||||
| ranges::views::transform([](
|
||||
not_null<PeerData*> peer) {
|
||||
return MTPInputPeer(peer->input); }))
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
peer->session().api().applyUpdates(result);
|
||||
}).send();
|
||||
|
||||
@@ -25,6 +25,7 @@ struct SendOptions {
|
||||
bool silent = false;
|
||||
bool handleSupportSwitch = false;
|
||||
bool hideViaBot = false;
|
||||
crl::time ttlSeconds = 0;
|
||||
};
|
||||
[[nodiscard]] SendOptions DefaultSendWhenOnlineOptions();
|
||||
|
||||
|
||||
@@ -84,18 +84,61 @@ void GlobalPrivacy::dismissArchiveAndMuteSuggestion() {
|
||||
u"AUTOARCHIVE_POPULAR"_q);
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updateHideReadTime(bool hide) {
|
||||
update(
|
||||
archiveAndMuteCurrent(),
|
||||
unarchiveOnNewMessageCurrent(),
|
||||
hide,
|
||||
newRequirePremiumCurrent());
|
||||
}
|
||||
|
||||
bool GlobalPrivacy::hideReadTimeCurrent() const {
|
||||
return _hideReadTime.current();
|
||||
}
|
||||
|
||||
rpl::producer<bool> GlobalPrivacy::hideReadTime() const {
|
||||
return _hideReadTime.value();
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updateNewRequirePremium(bool value) {
|
||||
update(
|
||||
archiveAndMuteCurrent(),
|
||||
unarchiveOnNewMessageCurrent(),
|
||||
hideReadTimeCurrent(),
|
||||
value);
|
||||
}
|
||||
|
||||
bool GlobalPrivacy::newRequirePremiumCurrent() const {
|
||||
return _newRequirePremium.current();
|
||||
}
|
||||
|
||||
rpl::producer<bool> GlobalPrivacy::newRequirePremium() const {
|
||||
return _newRequirePremium.value();
|
||||
}
|
||||
|
||||
|
||||
void GlobalPrivacy::updateArchiveAndMute(bool value) {
|
||||
update(value, unarchiveOnNewMessageCurrent());
|
||||
update(
|
||||
value,
|
||||
unarchiveOnNewMessageCurrent(),
|
||||
hideReadTimeCurrent(),
|
||||
newRequirePremiumCurrent());
|
||||
}
|
||||
|
||||
void GlobalPrivacy::updateUnarchiveOnNewMessage(
|
||||
UnarchiveOnNewMessage value) {
|
||||
update(archiveAndMuteCurrent(), value);
|
||||
update(
|
||||
archiveAndMuteCurrent(),
|
||||
value,
|
||||
hideReadTimeCurrent(),
|
||||
newRequirePremiumCurrent());
|
||||
}
|
||||
|
||||
void GlobalPrivacy::update(
|
||||
bool archiveAndMute,
|
||||
UnarchiveOnNewMessage unarchiveOnNewMessage) {
|
||||
UnarchiveOnNewMessage unarchiveOnNewMessage,
|
||||
bool hideReadTime,
|
||||
bool newRequirePremium) {
|
||||
using Flag = MTPDglobalPrivacySettings::Flag;
|
||||
|
||||
_api.request(_requestId).cancel();
|
||||
@@ -108,17 +151,26 @@ void GlobalPrivacy::update(
|
||||
: Flag())
|
||||
| (unarchiveOnNewMessage != UnarchiveOnNewMessage::AnyUnmuted
|
||||
? Flag::f_keep_archived_folders
|
||||
: Flag())
|
||||
| (hideReadTime ? Flag::f_hide_read_marks : Flag())
|
||||
| ((newRequirePremium && _session->premium())
|
||||
? Flag::f_new_noncontact_peers_require_premium
|
||||
: Flag());
|
||||
_requestId = _api.request(MTPaccount_SetGlobalPrivacySettings(
|
||||
MTP_globalPrivacySettings(MTP_flags(flags))
|
||||
)).done([=](const MTPGlobalPrivacySettings &result) {
|
||||
_requestId = 0;
|
||||
apply(result);
|
||||
}).fail([=] {
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
if (error.type() == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
|
||||
update(archiveAndMute, unarchiveOnNewMessage, hideReadTime, {});
|
||||
}
|
||||
}).send();
|
||||
_archiveAndMute = archiveAndMute;
|
||||
_unarchiveOnNewMessage = unarchiveOnNewMessage;
|
||||
_hideReadTime = hideReadTime;
|
||||
_newRequirePremium = newRequirePremium;
|
||||
}
|
||||
|
||||
void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
|
||||
@@ -129,6 +181,8 @@ void GlobalPrivacy::apply(const MTPGlobalPrivacySettings &data) {
|
||||
: data.is_keep_archived_folders()
|
||||
? UnarchiveOnNewMessage::NotInFoldersUnmuted
|
||||
: UnarchiveOnNewMessage::AnyUnmuted;
|
||||
_hideReadTime = data.is_hide_read_marks();
|
||||
_newRequirePremium = data.is_new_noncontact_peers_require_premium();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,22 @@ public:
|
||||
[[nodiscard]] rpl::producer<> suggestArchiveAndMute() const;
|
||||
void dismissArchiveAndMuteSuggestion();
|
||||
|
||||
void updateHideReadTime(bool hide);
|
||||
[[nodiscard]] bool hideReadTimeCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> hideReadTime() const;
|
||||
|
||||
void updateNewRequirePremium(bool value);
|
||||
[[nodiscard]] bool newRequirePremiumCurrent() const;
|
||||
[[nodiscard]] rpl::producer<bool> newRequirePremium() const;
|
||||
|
||||
private:
|
||||
void apply(const MTPGlobalPrivacySettings &data);
|
||||
|
||||
void update(
|
||||
bool archiveAndMute,
|
||||
UnarchiveOnNewMessage unarchiveOnNewMessage);
|
||||
UnarchiveOnNewMessage unarchiveOnNewMessage,
|
||||
bool hideReadTime,
|
||||
bool newRequirePremium);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
@@ -55,6 +65,8 @@ private:
|
||||
rpl::variable<UnarchiveOnNewMessage> _unarchiveOnNewMessage
|
||||
= UnarchiveOnNewMessage::None;
|
||||
rpl::variable<bool> _showArchiveAndMute = false;
|
||||
rpl::variable<bool> _hideReadTime = false;
|
||||
rpl::variable<bool> _newRequirePremium = false;
|
||||
std::vector<Fn<void()>> _callbacks;
|
||||
|
||||
};
|
||||
|
||||
@@ -79,16 +79,19 @@ MTPInputMedia PrepareUploadedPhoto(
|
||||
not_null<HistoryItem*> item,
|
||||
RemoteFileInfo info) {
|
||||
using Flag = MTPDinputMediaUploadedPhoto::Flag;
|
||||
const auto spoiler = item->media()
|
||||
&& item->media()->hasSpoiler();
|
||||
const auto spoiler = item->media() && item->media()->hasSpoiler();
|
||||
const auto ttlSeconds = item->media()
|
||||
? item->media()->ttlSeconds()
|
||||
: 0;
|
||||
const auto flags = (spoiler ? Flag::f_spoiler : Flag())
|
||||
| (info.attachedStickers.empty() ? Flag() : Flag::f_stickers);
|
||||
| (info.attachedStickers.empty() ? Flag() : Flag::f_stickers)
|
||||
| (ttlSeconds ? Flag::f_ttl_seconds : Flag());
|
||||
return MTP_inputMediaUploadedPhoto(
|
||||
MTP_flags(flags),
|
||||
info.file,
|
||||
MTP_vector<MTPInputDocument>(
|
||||
ranges::to<QVector<MTPInputDocument>>(info.attachedStickers)),
|
||||
MTP_int(0));
|
||||
MTP_int(ttlSeconds));
|
||||
}
|
||||
|
||||
MTPInputMedia PrepareUploadedDocument(
|
||||
@@ -98,12 +101,15 @@ MTPInputMedia PrepareUploadedDocument(
|
||||
return MTP_inputMediaEmpty();
|
||||
}
|
||||
using Flag = MTPDinputMediaUploadedDocument::Flag;
|
||||
const auto spoiler = item->media()
|
||||
&& item->media()->hasSpoiler();
|
||||
const auto spoiler = item->media() && item->media()->hasSpoiler();
|
||||
const auto ttlSeconds = item->media()
|
||||
? item->media()->ttlSeconds()
|
||||
: 0;
|
||||
const auto flags = (spoiler ? Flag::f_spoiler : Flag())
|
||||
| (info.thumb ? Flag::f_thumb : Flag())
|
||||
| (item->groupId() ? Flag::f_nosound_video : Flag())
|
||||
| (info.attachedStickers.empty() ? Flag::f_stickers : Flag());
|
||||
| (info.attachedStickers.empty() ? Flag::f_stickers : Flag())
|
||||
| (ttlSeconds ? Flag::f_ttl_seconds : Flag());
|
||||
const auto document = item->media()->document();
|
||||
return MTP_inputMediaUploadedDocument(
|
||||
MTP_flags(flags),
|
||||
@@ -113,7 +119,7 @@ MTPInputMedia PrepareUploadedDocument(
|
||||
ComposeSendingDocumentAttributes(document),
|
||||
MTP_vector<MTPInputDocument>(
|
||||
ranges::to<QVector<MTPInputDocument>>(info.attachedStickers)),
|
||||
MTP_int(0));
|
||||
MTP_int(ttlSeconds));
|
||||
}
|
||||
|
||||
bool HasAttachedStickers(MTPInputMedia media) {
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_message_reaction_id.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
@@ -43,6 +44,23 @@ constexpr auto kSearchPerPage = 50;
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString RequestToToken(
|
||||
const MessagesSearch::Request &request) {
|
||||
auto result = request.query;
|
||||
if (request.from) {
|
||||
result += '\n' + QString::number(request.from->id.value);
|
||||
}
|
||||
for (const auto &tag : request.tags) {
|
||||
result += '\n';
|
||||
if (const auto customId = tag.custom()) {
|
||||
result += u"custom"_q + QString::number(customId);
|
||||
} else {
|
||||
result += u"emoji"_q + tag.emoji();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MessagesSearch::MessagesSearch(not_null<History*> history)
|
||||
@@ -54,9 +72,8 @@ MessagesSearch::~MessagesSearch() {
|
||||
base::take(_searchInHistoryRequest));
|
||||
}
|
||||
|
||||
void MessagesSearch::searchMessages(const QString &query, PeerData *from) {
|
||||
_query = query;
|
||||
_from = from;
|
||||
void MessagesSearch::searchMessages(Request request) {
|
||||
_request = std::move(request);
|
||||
_offsetId = {};
|
||||
searchRequest();
|
||||
}
|
||||
@@ -69,8 +86,7 @@ void MessagesSearch::searchMore() {
|
||||
}
|
||||
|
||||
void MessagesSearch::searchRequest() {
|
||||
const auto nextToken = _query
|
||||
+ QString::number(_from ? _from->id.value : 0);
|
||||
const auto nextToken = RequestToToken(_request);
|
||||
if (!_offsetId) {
|
||||
const auto it = _cacheOfStartByToken.find(nextToken);
|
||||
if (it != end(_cacheOfStartByToken)) {
|
||||
@@ -80,16 +96,21 @@ void MessagesSearch::searchRequest() {
|
||||
}
|
||||
}
|
||||
auto callback = [=](Fn<void()> finish) {
|
||||
const auto flags = _from
|
||||
? MTP_flags(MTPmessages_Search::Flag::f_from_id)
|
||||
: MTP_flags(0);
|
||||
using Flag = MTPmessages_Search::Flag;
|
||||
const auto from = _request.from;
|
||||
const auto fromPeer = _history->peer->isUser() ? nullptr : from;
|
||||
const auto savedPeer = _history->peer->isSelf() ? from : nullptr;
|
||||
_requestId = _history->session().api().request(MTPmessages_Search(
|
||||
flags,
|
||||
MTP_flags((fromPeer ? Flag::f_from_id : Flag())
|
||||
| (savedPeer ? Flag::f_saved_peer_id : Flag())
|
||||
| (_request.tags.empty() ? Flag() : Flag::f_saved_reaction)),
|
||||
_history->peer->input,
|
||||
MTP_string(_query),
|
||||
(_from
|
||||
? _from->input
|
||||
: MTP_inputPeerEmpty()),
|
||||
MTP_string(_request.query),
|
||||
(fromPeer ? fromPeer->input : MTP_inputPeerEmpty()),
|
||||
(savedPeer ? savedPeer->input : MTP_inputPeerEmpty()),
|
||||
MTP_vector_from_range(_request.tags | ranges::views::transform(
|
||||
Data::ReactionToMTP
|
||||
)),
|
||||
MTPint(), // top_msg_id
|
||||
MTP_inputMessagesFilterEmpty(),
|
||||
MTP_int(0), // min_date
|
||||
|
||||
@@ -7,10 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/qt/qt_compare.h"
|
||||
#include "data/data_message_reaction_id.h"
|
||||
|
||||
class HistoryItem;
|
||||
class History;
|
||||
class PeerData;
|
||||
|
||||
namespace Data {
|
||||
struct ReactionId;
|
||||
} // namespace Data
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct FoundMessages {
|
||||
@@ -21,10 +28,23 @@ struct FoundMessages {
|
||||
|
||||
class MessagesSearch final {
|
||||
public:
|
||||
struct Request {
|
||||
QString query;
|
||||
PeerData *from = nullptr;
|
||||
std::vector<Data::ReactionId> tags;
|
||||
|
||||
friend inline bool operator==(
|
||||
const Request &,
|
||||
const Request &) = default;
|
||||
friend inline auto operator<=>(
|
||||
const Request &,
|
||||
const Request &) = default;
|
||||
};
|
||||
|
||||
explicit MessagesSearch(not_null<History*> history);
|
||||
~MessagesSearch();
|
||||
|
||||
void searchMessages(const QString &query, PeerData *from);
|
||||
void searchMessages(Request request);
|
||||
void searchMore();
|
||||
|
||||
[[nodiscard]] rpl::producer<FoundMessages> messagesFounds() const;
|
||||
@@ -41,8 +61,7 @@ private:
|
||||
|
||||
base::flat_map<QString, TLMessages> _cacheOfStartByToken;
|
||||
|
||||
QString _query;
|
||||
PeerData *_from = nullptr;
|
||||
Request _request;
|
||||
MsgId _offsetId;
|
||||
|
||||
int _searchInHistoryRequest = 0; // Not real mtpRequestId.
|
||||
|
||||
@@ -11,12 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Api {
|
||||
|
||||
bool MessagesSearchMerged::RequestCompare::operator()(
|
||||
const Request &a,
|
||||
const Request &b) const {
|
||||
return (a.query < b.query) && (a.from < b.from);
|
||||
}
|
||||
|
||||
MessagesSearchMerged::MessagesSearchMerged(not_null<History*> history)
|
||||
: _apiSearch(history) {
|
||||
if (const auto migrated = history->migrateFrom()) {
|
||||
@@ -88,9 +82,9 @@ void MessagesSearchMerged::clear() {
|
||||
void MessagesSearchMerged::search(const Request &search) {
|
||||
if (_migratedSearch) {
|
||||
_waitingForTotal = true;
|
||||
_migratedSearch->searchMessages(search.query, search.from);
|
||||
_migratedSearch->searchMessages(search);
|
||||
}
|
||||
_apiSearch.searchMessages(search.query, search.from);
|
||||
_apiSearch.searchMessages(search);
|
||||
}
|
||||
|
||||
void MessagesSearchMerged::searchMore() {
|
||||
|
||||
@@ -12,19 +12,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
class History;
|
||||
class PeerData;
|
||||
|
||||
namespace Data {
|
||||
struct ReactionId;
|
||||
} // namespace Data
|
||||
|
||||
namespace Api {
|
||||
|
||||
// Search in both of history and migrated history, if it exists.
|
||||
class MessagesSearchMerged final {
|
||||
public:
|
||||
struct Request {
|
||||
QString query;
|
||||
PeerData *from = nullptr;
|
||||
};
|
||||
struct RequestCompare {
|
||||
bool operator()(const Request &a, const Request &b) const;
|
||||
};
|
||||
using CachedRequests = std::set<Request, RequestCompare>;
|
||||
using Request = MessagesSearch::Request;
|
||||
using CachedRequests = base::flat_set<Request>;
|
||||
|
||||
MessagesSearchMerged(not_null<History*> history);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_peer_colors.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
|
||||
namespace Api {
|
||||
@@ -62,6 +63,16 @@ auto PeerColors::indicesValue() const
|
||||
}));
|
||||
}
|
||||
|
||||
int PeerColors::requiredLevelFor(PeerId channel, uint8 index) const {
|
||||
if (Data::DecideColorIndex(channel) == index) {
|
||||
return 0;
|
||||
} else if (const auto i = _requiredLevels.find(index)
|
||||
; i != end(_requiredLevels)) {
|
||||
return i->second;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PeerColors::apply(const MTPDhelp_peerColors &data) {
|
||||
auto suggested = std::vector<uint8>();
|
||||
auto colors = std::make_shared<
|
||||
@@ -89,6 +100,7 @@ void PeerColors::apply(const MTPDhelp_peerColors &data) {
|
||||
};
|
||||
|
||||
const auto &list = data.vcolors().v;
|
||||
_requiredLevels.clear();
|
||||
suggested.reserve(list.size());
|
||||
for (const auto &color : list) {
|
||||
const auto &data = color.data();
|
||||
@@ -98,6 +110,9 @@ void PeerColors::apply(const MTPDhelp_peerColors &data) {
|
||||
continue;
|
||||
}
|
||||
const auto colorIndex = uint8(colorIndexBare);
|
||||
if (const auto min = data.vchannel_min_level()) {
|
||||
_requiredLevels[colorIndex] = min->v;
|
||||
}
|
||||
if (!data.is_hidden()) {
|
||||
suggested.push_back(colorIndex);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ public:
|
||||
[[nodiscard]] auto indicesValue() const
|
||||
-> rpl::producer<Ui::ColorIndicesCompressed>;
|
||||
|
||||
[[nodiscard]] int requiredLevelFor(
|
||||
PeerId channel,
|
||||
uint8 index) const;
|
||||
|
||||
private:
|
||||
void request();
|
||||
void apply(const MTPDhelp_peerColors &data);
|
||||
@@ -38,6 +42,7 @@ private:
|
||||
mtpRequestId _requestId = 0;
|
||||
base::Timer _timer;
|
||||
rpl::variable<std::vector<uint8>> _suggested;
|
||||
base::flat_map<uint8, int> _requiredLevels;
|
||||
rpl::event_stream<> _colorIndicesChanged;
|
||||
std::unique_ptr<Ui::ColorIndicesCompressed> _colorIndicesCurrent;
|
||||
|
||||
|
||||
@@ -515,6 +515,7 @@ auto PeerPhoto::emojiList(EmojiListType type) -> EmojiListData & {
|
||||
case EmojiListType::Profile: return _profileEmojiList;
|
||||
case EmojiListType::Group: return _groupEmojiList;
|
||||
case EmojiListType::Background: return _backgroundEmojiList;
|
||||
case EmojiListType::NoChannelStatus: return _noChannelStatusEmojiList;
|
||||
}
|
||||
Unexpected("Type in PeerPhoto::emojiList.");
|
||||
}
|
||||
@@ -551,6 +552,8 @@ void PeerPhoto::requestEmojiList(EmojiListType type) {
|
||||
? send(MTPaccount_GetDefaultProfilePhotoEmojis())
|
||||
: (type == EmojiListType::Group)
|
||||
? send(MTPaccount_GetDefaultGroupPhotoEmojis())
|
||||
: (type == EmojiListType::NoChannelStatus)
|
||||
? send(MTPaccount_GetChannelRestrictedStatusEmojis())
|
||||
: send(MTPaccount_GetDefaultBackgroundEmojis());
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
Profile,
|
||||
Group,
|
||||
Background,
|
||||
NoChannelStatus,
|
||||
};
|
||||
|
||||
struct UserPhoto {
|
||||
@@ -112,6 +113,7 @@ private:
|
||||
EmojiListData _profileEmojiList;
|
||||
EmojiListData _groupEmojiList;
|
||||
EmojiListData _backgroundEmojiList;
|
||||
EmojiListData _noChannelStatusEmojiList;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
@@ -26,7 +30,7 @@ namespace {
|
||||
|
||||
[[nodiscard]] GiftCode Parse(const MTPDpayments_checkedGiftCode &data) {
|
||||
return {
|
||||
.from = peerFromMTP(data.vfrom_id()),
|
||||
.from = data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(),
|
||||
.to = data.vto_id() ? peerFromUser(*data.vto_id()) : PeerId(),
|
||||
.giveawayId = data.vgiveaway_msg_id().value_or_empty(),
|
||||
.date = data.vdate().v,
|
||||
@@ -334,6 +338,72 @@ const Data::SubscriptionOptions &Premium::subscriptionOptions() const {
|
||||
return _subscriptionOptions;
|
||||
}
|
||||
|
||||
rpl::producer<> Premium::somePremiumRequiredResolved() const {
|
||||
return _somePremiumRequiredResolved.events();
|
||||
}
|
||||
|
||||
void Premium::resolvePremiumRequired(not_null<UserData*> user) {
|
||||
_resolvePremiumRequiredUsers.emplace(user);
|
||||
if (!_premiumRequiredRequestScheduled
|
||||
&& _resolvePremiumRequestedUsers.empty()) {
|
||||
_premiumRequiredRequestScheduled = true;
|
||||
crl::on_main(_session, [=] {
|
||||
requestPremiumRequiredSlice();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Premium::requestPremiumRequiredSlice() {
|
||||
_premiumRequiredRequestScheduled = false;
|
||||
if (!_resolvePremiumRequestedUsers.empty()
|
||||
|| _resolvePremiumRequiredUsers.empty()) {
|
||||
return;
|
||||
}
|
||||
constexpr auto kPerRequest = 100;
|
||||
auto users = MTP_vector_from_range(_resolvePremiumRequiredUsers
|
||||
| ranges::views::transform(&UserData::inputUser));
|
||||
if (users.v.size() > kPerRequest) {
|
||||
auto shortened = users.v;
|
||||
shortened.resize(kPerRequest);
|
||||
users = MTP_vector<MTPInputUser>(std::move(shortened));
|
||||
const auto from = begin(_resolvePremiumRequiredUsers);
|
||||
_resolvePremiumRequestedUsers = { from, from + kPerRequest };
|
||||
_resolvePremiumRequiredUsers.erase(from, from + kPerRequest);
|
||||
} else {
|
||||
_resolvePremiumRequestedUsers
|
||||
= base::take(_resolvePremiumRequiredUsers);
|
||||
}
|
||||
const auto finish = [=](const QVector<MTPBool> &list) {
|
||||
constexpr auto me = UserDataFlag::MeRequiresPremiumToWrite;
|
||||
constexpr auto known = UserDataFlag::RequirePremiumToWriteKnown;
|
||||
constexpr auto mask = me | known;
|
||||
|
||||
auto index = 0;
|
||||
for (const auto &user : base::take(_resolvePremiumRequestedUsers)) {
|
||||
const auto require = (index < list.size())
|
||||
&& mtpIsTrue(list[index++]);
|
||||
user->setFlags((user->flags() & ~mask)
|
||||
| known
|
||||
| (require ? me : UserDataFlag()));
|
||||
}
|
||||
if (!_premiumRequiredRequestScheduled
|
||||
&& !_resolvePremiumRequiredUsers.empty()) {
|
||||
_premiumRequiredRequestScheduled = true;
|
||||
crl::on_main(_session, [=] {
|
||||
requestPremiumRequiredSlice();
|
||||
});
|
||||
}
|
||||
_somePremiumRequiredResolved.fire({});
|
||||
};
|
||||
_session->api().request(
|
||||
MTPusers_GetIsPremiumRequiredToContact(std::move(users))
|
||||
).done([=](const MTPVector<MTPBool> &result) {
|
||||
finish(result.v);
|
||||
}).fail([=] {
|
||||
finish({});
|
||||
}).send();
|
||||
}
|
||||
|
||||
PremiumGiftCodeOptions::PremiumGiftCodeOptions(not_null<PeerData*> peer)
|
||||
: _peer(peer)
|
||||
, _api(&peer->session().api().instance()) {
|
||||
@@ -342,15 +412,12 @@ PremiumGiftCodeOptions::PremiumGiftCodeOptions(not_null<PeerData*> peer)
|
||||
rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::request() {
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
const auto channel = _peer->asChannel();
|
||||
if (!channel) {
|
||||
return lifetime;
|
||||
}
|
||||
|
||||
using TLOption = MTPPremiumGiftCodeOption;
|
||||
_api.request(MTPpayments_GetPremiumGiftCodeOptions(
|
||||
MTP_flags(
|
||||
MTPpayments_GetPremiumGiftCodeOptions::Flag::f_boost_peer),
|
||||
MTP_flags(_peer->isChannel()
|
||||
? MTPpayments_GetPremiumGiftCodeOptions::Flag::f_boost_peer
|
||||
: MTPpayments_GetPremiumGiftCodeOptions::Flag(0)),
|
||||
_peer->input
|
||||
)).done([=](const MTPVector<TLOption> &result) {
|
||||
auto tlMapOptions = base::flat_map<Amount, QVector<TLOption>>();
|
||||
@@ -420,6 +487,8 @@ const std::vector<int> &PremiumGiftCodeOptions::availablePresets() const {
|
||||
}
|
||||
|
||||
[[nodiscard]] int PremiumGiftCodeOptions::monthsFromPreset(int monthsIndex) {
|
||||
Expects(monthsIndex >= 0 && monthsIndex < _availablePresets.size());
|
||||
|
||||
return _optionsForOnePerson.months[monthsIndex];
|
||||
}
|
||||
|
||||
@@ -495,4 +564,49 @@ bool PremiumGiftCodeOptions::giveawayGiftsPurchaseAvailable() const {
|
||||
false);
|
||||
}
|
||||
|
||||
RequirePremiumState ResolveRequiresPremiumToWrite(
|
||||
not_null<PeerData*> peer,
|
||||
History *maybeHistory) {
|
||||
const auto user = peer->asUser();
|
||||
if (!user
|
||||
|| !user->someRequirePremiumToWrite()
|
||||
|| user->session().premium()) {
|
||||
return RequirePremiumState::No;
|
||||
} else if (user->requirePremiumToWriteKnown()) {
|
||||
return user->meRequiresPremiumToWrite()
|
||||
? RequirePremiumState::Yes
|
||||
: RequirePremiumState::No;
|
||||
} else if (user->flags() & UserDataFlag::MutualContact) {
|
||||
return RequirePremiumState::No;
|
||||
} else if (!maybeHistory) {
|
||||
return RequirePremiumState::Unknown;
|
||||
}
|
||||
|
||||
const auto update = [&](bool require) {
|
||||
using Flag = UserDataFlag;
|
||||
constexpr auto known = Flag::RequirePremiumToWriteKnown;
|
||||
constexpr auto me = Flag::MeRequiresPremiumToWrite;
|
||||
user->setFlags((user->flags() & ~me)
|
||||
| known
|
||||
| (require ? me : Flag()));
|
||||
};
|
||||
// We allow this potentially-heavy loop because in case we've opened
|
||||
// the chat and have a lot of messages `requires_premium` will be known.
|
||||
for (const auto &block : maybeHistory->blocks) {
|
||||
for (const auto &view : block->messages) {
|
||||
const auto item = view->data();
|
||||
if (!item->out() && !item->isService()) {
|
||||
update(false);
|
||||
return RequirePremiumState::No;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (user->isContact() // Here we know, that we're not in his contacts.
|
||||
&& maybeHistory->loadedAtTop() // And no incoming messages.
|
||||
&& maybeHistory->loadedAtBottom()) {
|
||||
update(true);
|
||||
}
|
||||
return RequirePremiumState::Unknown;
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_subscription_option.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class History;
|
||||
class ApiWrap;
|
||||
|
||||
namespace Main {
|
||||
@@ -103,10 +104,14 @@ public:
|
||||
[[nodiscard]] auto subscriptionOptions() const
|
||||
-> const Data::SubscriptionOptions &;
|
||||
|
||||
[[nodiscard]] rpl::producer<> somePremiumRequiredResolved() const;
|
||||
void resolvePremiumRequired(not_null<UserData*> user);
|
||||
|
||||
private:
|
||||
void reloadPromo();
|
||||
void reloadStickers();
|
||||
void reloadCloudSet();
|
||||
void requestPremiumRequiredSlice();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
@@ -143,6 +148,11 @@ private:
|
||||
|
||||
Data::SubscriptionOptions _subscriptionOptions;
|
||||
|
||||
rpl::event_stream<> _somePremiumRequiredResolved;
|
||||
base::flat_set<not_null<UserData*>> _resolvePremiumRequiredUsers;
|
||||
base::flat_set<not_null<UserData*>> _resolvePremiumRequestedUsers;
|
||||
bool _premiumRequiredRequestScheduled = false;
|
||||
|
||||
};
|
||||
|
||||
class PremiumGiftCodeOptions final {
|
||||
@@ -196,4 +206,13 @@ private:
|
||||
|
||||
};
|
||||
|
||||
enum class RequirePremiumState {
|
||||
Unknown,
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
[[nodiscard]] RequirePremiumState ResolveRequiresPremiumToWrite(
|
||||
not_null<PeerData*> peer,
|
||||
History *maybeHistory);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -161,14 +161,13 @@ bool SendProgressManager::skipRequest(const Key &key) const {
|
||||
return true;
|
||||
}
|
||||
const auto recently = base::unixtime::now() - kSendTypingsToOfflineFor;
|
||||
const auto online = user->onlineTill;
|
||||
if (online == -2) { // last seen recently
|
||||
const auto lastseen = user->lastseen();
|
||||
if (lastseen.isRecently()) {
|
||||
return false;
|
||||
} else if (online < 0) {
|
||||
return (-online < recently);
|
||||
} else {
|
||||
return (online < recently);
|
||||
} else if (const auto value = lastseen.onlineTill()) {
|
||||
return (value < recently);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SendProgressManager::done(mtpRequestId requestId) {
|
||||
|
||||
@@ -42,6 +42,9 @@ void InnerFillMessagePostFlags(
|
||||
not_null<PeerData*> peer,
|
||||
MessageFlags &flags) {
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
if (ShouldSendSilent(peer, options)) {
|
||||
flags |= MessageFlag::Silent;
|
||||
}
|
||||
if (!anonymousPost || options.sendAs) {
|
||||
flags |= MessageFlag::HasFromId;
|
||||
return;
|
||||
@@ -399,11 +402,7 @@ void SendConfirmedFile(
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, file->to.options);
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
flags |= MessageFlag::Silent;
|
||||
}
|
||||
if (file->to.options.scheduled) {
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
|
||||
@@ -443,11 +442,30 @@ void SendConfirmedFile(
|
||||
MTPDocument(), // alt_document
|
||||
MTPint());
|
||||
} else if (file->type == SendMediaType::Audio) {
|
||||
const auto ttlSeconds = file->to.options.ttlSeconds;
|
||||
const auto isVoice = [&] {
|
||||
return file->document.match([](const MTPDdocumentEmpty &d) {
|
||||
return false;
|
||||
}, [](const MTPDdocument &d) {
|
||||
return ranges::any_of(d.vattributes().v, [&](
|
||||
const MTPDocumentAttribute &attribute) {
|
||||
using Att = MTPDdocumentAttributeAudio;
|
||||
return attribute.match([](const Att &data) -> bool {
|
||||
return data.vflags().v & Att::Flag::f_voice;
|
||||
}, [](const auto &) {
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}();
|
||||
using Flag = MTPDmessageMediaDocument::Flag;
|
||||
return MTP_messageMediaDocument(
|
||||
MTP_flags(MTPDmessageMediaDocument::Flag::f_document),
|
||||
MTP_flags(Flag::f_document
|
||||
| (isVoice ? Flag::f_voice : Flag())
|
||||
| (ttlSeconds ? Flag::f_ttl_seconds : Flag())),
|
||||
file->document,
|
||||
MTPDocument(), // alt_document
|
||||
MTPint());
|
||||
MTP_int(ttlSeconds));
|
||||
} else {
|
||||
Unexpected("Type in sendFilesConfirmed.");
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_story.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "statistics/statistics_data_deserialize.h"
|
||||
@@ -359,161 +361,54 @@ PublicForwards::PublicForwards(
|
||||
void PublicForwards::request(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done) {
|
||||
if (!_requestId) {
|
||||
if (_fullId.messageId) {
|
||||
requestMessage(token, std::move(done));
|
||||
} else if (_fullId.storyId) {
|
||||
requestStory(token, std::move(done));
|
||||
}
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PublicForwards::requestMessage(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done) {
|
||||
Expects(_fullId.messageId);
|
||||
|
||||
const auto offsetPeer = channel()->owner().peer(token.fullId.peer);
|
||||
const auto tlOffsetPeer = offsetPeer
|
||||
? offsetPeer->input
|
||||
: MTP_inputPeerEmpty();
|
||||
constexpr auto kLimit = tl::make_int(100);
|
||||
_requestId = makeRequest(MTPstats_GetMessagePublicForwards(
|
||||
channel()->inputChannel,
|
||||
MTP_int(_fullId.messageId.msg),
|
||||
MTP_int(token.rate),
|
||||
tlOffsetPeer,
|
||||
MTP_int(token.fullId.msg),
|
||||
kLimit
|
||||
)).done([=, channel = channel()](const MTPmessages_Messages &result) {
|
||||
const auto channel = StatisticsRequestSender::channel();
|
||||
const auto processResult = [=](const MTPstats_PublicForwards &tl) {
|
||||
using Messages = QVector<Data::RecentPostId>;
|
||||
_requestId = 0;
|
||||
|
||||
auto nextToken = Data::PublicForwardsSlice::OffsetToken();
|
||||
const auto process = [&](const MTPVector<MTPMessage> &messages) {
|
||||
auto result = Messages();
|
||||
for (const auto &message : messages.v) {
|
||||
const auto msgId = IdFromMessage(message);
|
||||
const auto peerId = PeerFromMessage(message);
|
||||
const auto lastDate = DateFromMessage(message);
|
||||
if (const auto peer = channel->owner().peerLoaded(peerId)) {
|
||||
if (lastDate) {
|
||||
channel->owner().addNewMessage(
|
||||
message,
|
||||
MessageFlags(),
|
||||
NewMessageType::Existing);
|
||||
nextToken.fullId = { peerId, msgId };
|
||||
result.push_back({ .messageId = nextToken.fullId });
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const auto &data = tl.data();
|
||||
auto &owner = channel->owner();
|
||||
|
||||
auto allLoaded = false;
|
||||
auto fullCount = 0;
|
||||
auto messages = result.match([&](const MTPDmessages_messages &data) {
|
||||
channel->owner().processUsers(data.vusers());
|
||||
channel->owner().processChats(data.vchats());
|
||||
auto list = process(data.vmessages());
|
||||
allLoaded = true;
|
||||
fullCount = list.size();
|
||||
return list;
|
||||
}, [&](const MTPDmessages_messagesSlice &data) {
|
||||
channel->owner().processUsers(data.vusers());
|
||||
channel->owner().processChats(data.vchats());
|
||||
auto list = process(data.vmessages());
|
||||
owner.processUsers(data.vusers());
|
||||
owner.processChats(data.vchats());
|
||||
|
||||
if (const auto nextRate = data.vnext_rate()) {
|
||||
const auto rateUpdated = (nextRate->v != token.rate);
|
||||
if (rateUpdated) {
|
||||
nextToken.rate = nextRate->v;
|
||||
} else {
|
||||
allLoaded = true;
|
||||
}
|
||||
}
|
||||
fullCount = data.vcount().v;
|
||||
return list;
|
||||
}, [&](const MTPDmessages_channelMessages &data) {
|
||||
channel->owner().processUsers(data.vusers());
|
||||
channel->owner().processChats(data.vchats());
|
||||
auto list = process(data.vmessages());
|
||||
allLoaded = true;
|
||||
fullCount = data.vcount().v;
|
||||
return list;
|
||||
}, [&](const MTPDmessages_messagesNotModified &) {
|
||||
allLoaded = true;
|
||||
return Messages();
|
||||
});
|
||||
const auto nextToken = data.vnext_offset()
|
||||
? qs(*data.vnext_offset())
|
||||
: Data::PublicForwardsSlice::OffsetToken();
|
||||
|
||||
_lastTotal = std::max(_lastTotal, fullCount);
|
||||
done({
|
||||
.list = std::move(messages),
|
||||
.total = _lastTotal,
|
||||
.allLoaded = allLoaded,
|
||||
.token = nextToken,
|
||||
});
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void PublicForwards::requestStory(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done) {
|
||||
Expects(_fullId.storyId);
|
||||
|
||||
constexpr auto kLimit = tl::make_int(100);
|
||||
_requestId = makeRequest(MTPstats_GetStoryPublicForwards(
|
||||
channel()->input,
|
||||
MTP_int(_fullId.storyId.story),
|
||||
MTP_string(token.storyOffset),
|
||||
kLimit
|
||||
)).done([=, channel = channel()](
|
||||
const MTPstats_PublicForwards &tlForwards) {
|
||||
using Messages = QVector<Data::RecentPostId>;
|
||||
_requestId = 0;
|
||||
|
||||
const auto &data = tlForwards.data();
|
||||
|
||||
channel->owner().processUsers(data.vusers());
|
||||
channel->owner().processChats(data.vchats());
|
||||
|
||||
const auto nextToken = Data::PublicForwardsSlice::OffsetToken({
|
||||
.storyOffset = data.vnext_offset().value_or_empty(),
|
||||
});
|
||||
|
||||
const auto allLoaded = nextToken.storyOffset.isEmpty()
|
||||
|| (nextToken.storyOffset == token.storyOffset);
|
||||
const auto fullCount = data.vcount().v;
|
||||
|
||||
auto recentList = Messages();
|
||||
auto recentList = Messages(data.vforwards().v.size());
|
||||
for (const auto &tlForward : data.vforwards().v) {
|
||||
tlForward.match([&](const MTPDpublicForwardMessage &data) {
|
||||
const auto &message = data.vmessage();
|
||||
const auto msgId = IdFromMessage(message);
|
||||
const auto peerId = PeerFromMessage(message);
|
||||
const auto lastDate = DateFromMessage(message);
|
||||
if (const auto peer = channel->owner().peerLoaded(peerId)) {
|
||||
if (const auto peer = owner.peerLoaded(peerId)) {
|
||||
if (!lastDate) {
|
||||
return;
|
||||
}
|
||||
channel->owner().addNewMessage(
|
||||
owner.addNewMessage(
|
||||
message,
|
||||
MessageFlags(),
|
||||
NewMessageType::Existing);
|
||||
recentList.push_back({ .messageId = { peerId, msgId } });
|
||||
}
|
||||
}, [&](const MTPDpublicForwardStory &data) {
|
||||
data.vstory().match([&](const MTPDstoryItem &d) {
|
||||
recentList.push_back({
|
||||
.storyId = { peerFromMTP(data.vpeer()), d.vid().v }
|
||||
});
|
||||
}, [](const auto &) {
|
||||
});
|
||||
const auto story = owner.stories().applySingle(
|
||||
peerFromMTP(data.vpeer()),
|
||||
data.vstory());
|
||||
if (story) {
|
||||
recentList.push_back({ .storyId = story->fullId() });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const auto allLoaded = nextToken.isEmpty() || (nextToken == token);
|
||||
_lastTotal = std::max(_lastTotal, fullCount);
|
||||
done({
|
||||
.list = std::move(recentList),
|
||||
@@ -521,9 +416,24 @@ void PublicForwards::requestStory(
|
||||
.allLoaded = allLoaded,
|
||||
.token = nextToken,
|
||||
});
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
};
|
||||
|
||||
constexpr auto kLimit = tl::make_int(100);
|
||||
if (_fullId.messageId) {
|
||||
_requestId = makeRequest(MTPstats_GetMessagePublicForwards(
|
||||
channel->inputChannel,
|
||||
MTP_int(_fullId.messageId.msg),
|
||||
MTP_string(token),
|
||||
kLimit
|
||||
)).done(processResult).fail([=] { _requestId = 0; }).send();
|
||||
} else if (_fullId.storyId) {
|
||||
_requestId = makeRequest(MTPstats_GetStoryPublicForwards(
|
||||
channel->input,
|
||||
MTP_int(_fullId.storyId.story),
|
||||
MTP_string(token),
|
||||
kLimit
|
||||
)).done(processResult).fail([=] { _requestId = 0; }).send();
|
||||
}
|
||||
}
|
||||
|
||||
MessageStatistics::MessageStatistics(
|
||||
@@ -702,6 +612,7 @@ rpl::producer<rpl::no_value, QString> Boosts::request() {
|
||||
_peer->input
|
||||
)).done([=](const MTPpremium_BoostsStatus &result) {
|
||||
const auto &data = result.data();
|
||||
channel->updateLevelHint(data.vlevel().v);
|
||||
const auto hasPremium = !!data.vpremium_audience();
|
||||
const auto premiumMemberCount = hasPremium
|
||||
? std::max(0, int(data.vpremium_audience()->data().vpart().v))
|
||||
|
||||
@@ -77,13 +77,6 @@ public:
|
||||
Fn<void(Data::PublicForwardsSlice)> done);
|
||||
|
||||
private:
|
||||
void requestMessage(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done);
|
||||
void requestStory(
|
||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||
Fn<void(Data::PublicForwardsSlice)> done);
|
||||
|
||||
const Data::RecentPostId _fullId;
|
||||
mtpRequestId _requestId = 0;
|
||||
int _lastTotal = 0;
|
||||
|
||||
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mtproto/mtproto_dc_options.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_saved_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_chat.h"
|
||||
@@ -44,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "history/history_unread_things.h"
|
||||
#include "core/application.h"
|
||||
#include "storage/storage_account.h"
|
||||
@@ -942,7 +944,9 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
|
||||
}
|
||||
|
||||
const auto self = session().user();
|
||||
self->onlineTill = base::unixtime::now() + (isOnline ? (config.onlineUpdatePeriod / 1000) : -1);
|
||||
const auto onlineFor = (config.onlineUpdatePeriod / 1000);
|
||||
self->updateLastseen(Data::LastseenStatus::OnlineTill(
|
||||
base::unixtime::now() + (isOnline ? onlineFor : -1)));
|
||||
session().changes().peerUpdated(
|
||||
self,
|
||||
Data::PeerUpdate::Flag::OnlineStatus);
|
||||
@@ -1111,6 +1115,7 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
? peerToMTP(_session->userPeerId())
|
||||
: MTP_peerUser(d.vuser_id())),
|
||||
MTP_peerUser(d.vuser_id()),
|
||||
MTPPeer(), // saved_peer_id
|
||||
d.vfwd_from() ? *d.vfwd_from() : MTPMessageFwdHeader(),
|
||||
MTP_long(d.vvia_bot_id().value_or_empty()),
|
||||
d.vreply_to() ? *d.vreply_to() : MTPMessageReplyHeader(),
|
||||
@@ -1142,6 +1147,7 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
d.vid(),
|
||||
MTP_peerUser(d.vfrom_id()),
|
||||
MTP_peerChat(d.vchat_id()),
|
||||
MTPPeer(), // saved_peer_id
|
||||
d.vfwd_from() ? *d.vfwd_from() : MTPMessageFwdHeader(),
|
||||
MTP_long(d.vvia_bot_id().value_or_empty()),
|
||||
d.vreply_to() ? *d.vreply_to() : MTPMessageReplyHeader(),
|
||||
@@ -1202,12 +1208,13 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
||||
item->markMediaAndMentionRead();
|
||||
_session->data().requestItemRepaint(item);
|
||||
|
||||
if (item->out()
|
||||
&& item->history()->peer->isUser()
|
||||
&& !requestingDifference()) {
|
||||
item->history()->peer->asUser()->madeAction(
|
||||
base::unixtime::now());
|
||||
if (item->out()) {
|
||||
const auto user = item->history()->peer->asUser();
|
||||
if (user && !requestingDifference()) {
|
||||
user->madeAction(base::unixtime::now());
|
||||
}
|
||||
}
|
||||
ClearMediaAsExpired(item);
|
||||
}
|
||||
} else {
|
||||
// Perhaps it was an unread mention!
|
||||
@@ -1845,23 +1852,13 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
case mtpc_updateUserStatus: {
|
||||
auto &d = update.c_updateUserStatus();
|
||||
if (auto user = session().data().userLoaded(d.vuser_id())) {
|
||||
switch (d.vstatus().type()) {
|
||||
case mtpc_userStatusEmpty: user->onlineTill = 0; break;
|
||||
case mtpc_userStatusRecently:
|
||||
if (user->onlineTill > -10) { // don't modify pseudo-online
|
||||
user->onlineTill = -2;
|
||||
}
|
||||
break;
|
||||
case mtpc_userStatusLastWeek: user->onlineTill = -3; break;
|
||||
case mtpc_userStatusLastMonth: user->onlineTill = -4; break;
|
||||
case mtpc_userStatusOffline: user->onlineTill = d.vstatus().c_userStatusOffline().vwas_online().v; break;
|
||||
case mtpc_userStatusOnline: user->onlineTill = d.vstatus().c_userStatusOnline().vexpires().v; break;
|
||||
if (const auto user = session().data().userLoaded(d.vuser_id())) {
|
||||
const auto now = LastseenFromMTP(d.vstatus(), user->lastseen());
|
||||
if (user->updateLastseen(now)) {
|
||||
session().changes().peerUpdated(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::OnlineStatus);
|
||||
}
|
||||
session().changes().peerUpdated(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::OnlineStatus);
|
||||
session().data().maybeStopWatchForOffline(user);
|
||||
}
|
||||
if (UserId(d.vuser_id()) == session().userId()) {
|
||||
if (d.vstatus().type() == mtpc_userStatusOffline
|
||||
@@ -2204,6 +2201,16 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updatePinnedSavedDialogs: {
|
||||
session().data().savedMessages().apply(
|
||||
update.c_updatePinnedSavedDialogs());
|
||||
} break;
|
||||
|
||||
case mtpc_updateSavedDialogPinned: {
|
||||
session().data().savedMessages().apply(
|
||||
update.c_updateSavedDialogPinned());
|
||||
} break;
|
||||
|
||||
case mtpc_updateChannel: {
|
||||
auto &d = update.c_updateChannel();
|
||||
if (const auto channel = session().data().channelLoaded(d.vchannel_id())) {
|
||||
@@ -2493,6 +2500,10 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
session().data().reactions().refreshRecentDelayed();
|
||||
} break;
|
||||
|
||||
case mtpc_updateSavedReactionTags: {
|
||||
session().data().reactions().refreshMyTagsDelayed();
|
||||
} break;
|
||||
|
||||
////// Cloud saved GIFs
|
||||
case mtpc_updateSavedGifs: {
|
||||
session().data().stickers().setLastSavedGifsUpdate(0);
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_who_reacted.h"
|
||||
|
||||
#include "api/api_global_privacy.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
@@ -19,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_message_reaction_id.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
@@ -36,10 +38,11 @@ namespace {
|
||||
constexpr auto kContextReactionsLimit = 50;
|
||||
|
||||
using Data::ReactionId;
|
||||
using WhoReadState = Ui::WhoReadState;
|
||||
|
||||
struct Peers {
|
||||
std::vector<WhoReadPeer> list;
|
||||
bool unknown = false;
|
||||
WhoReadState state = WhoReadState::Empty;
|
||||
|
||||
friend inline bool operator==(
|
||||
const Peers &a,
|
||||
@@ -59,7 +62,7 @@ struct PeersWithReactions {
|
||||
std::vector<PeerWithReaction> list;
|
||||
std::vector<WhoReadPeer> read;
|
||||
int fullReactionsCount = 0;
|
||||
bool unknown = false;
|
||||
WhoReadState state = WhoReadState::Empty;
|
||||
|
||||
friend inline bool operator==(
|
||||
const PeersWithReactions &a,
|
||||
@@ -68,7 +71,7 @@ struct PeersWithReactions {
|
||||
|
||||
struct CachedRead {
|
||||
CachedRead()
|
||||
: data(Peers{ .unknown = true }) {
|
||||
: data(Peers{ .state = WhoReadState::Unknown }) {
|
||||
}
|
||||
rpl::variable<Peers> data;
|
||||
mtpRequestId requestId = 0;
|
||||
@@ -76,7 +79,7 @@ struct CachedRead {
|
||||
|
||||
struct CachedReacted {
|
||||
CachedReacted()
|
||||
: data(PeersWithReactions{ .unknown = true }) {
|
||||
: data(PeersWithReactions{ .state = WhoReadState::Unknown }) {
|
||||
}
|
||||
rpl::variable<PeersWithReactions> data;
|
||||
mtpRequestId requestId = 0;
|
||||
@@ -186,6 +189,27 @@ struct State {
|
||||
context->cachedReacted.erase(j);
|
||||
}
|
||||
}, context->subscriptions[session]);
|
||||
Data::AmPremiumValue(
|
||||
session
|
||||
) | rpl::skip(1) | rpl::filter(
|
||||
rpl::mappers::_1
|
||||
) | rpl::start_with_next([=] {
|
||||
for (auto &[item, cache] : context->cachedRead) {
|
||||
if (cache.data.current().state == Ui::WhoReadState::MyHidden) {
|
||||
cache.data = Peers{ .state = Ui::WhoReadState::Unknown };
|
||||
}
|
||||
}
|
||||
}, context->subscriptions[session]);
|
||||
session->api().globalPrivacy().hideReadTime(
|
||||
) | rpl::skip(1) | rpl::filter(
|
||||
!rpl::mappers::_1
|
||||
) | rpl::start_with_next([=] {
|
||||
for (auto &[item, cache] : context->cachedRead) {
|
||||
if (cache.data.current().state == Ui::WhoReadState::MyHidden) {
|
||||
cache.data = Peers{ .state = Ui::WhoReadState::Unknown };
|
||||
}
|
||||
}
|
||||
}, context->subscriptions[session]);
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -222,7 +246,38 @@ struct State {
|
||||
}
|
||||
const auto context = PreparedContextAt(weak.data(), session);
|
||||
auto &entry = context->cacheRead(item);
|
||||
if (!entry.requestId) {
|
||||
if (entry.requestId) {
|
||||
} else if (const auto user = item->history()->peer->asUser()) {
|
||||
entry.requestId = session->api().request(
|
||||
MTPmessages_GetOutboxReadDate(
|
||||
user->input,
|
||||
MTP_int(item->id)
|
||||
)
|
||||
).done([=](const MTPOutboxReadDate &result) {
|
||||
const auto &data = result.data();
|
||||
auto &entry = context->cacheRead(item);
|
||||
entry.requestId = 0;
|
||||
auto parsed = Peers();
|
||||
parsed.list.push_back({
|
||||
.peer = user->id,
|
||||
.date = data.vdate().v,
|
||||
});
|
||||
entry.data = std::move(parsed);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
auto &entry = context->cacheRead(item);
|
||||
entry.requestId = 0;
|
||||
if (entry.data.current().state == WhoReadState::Unknown) {
|
||||
const auto &text = error.type();
|
||||
entry.data = (text == u"YOUR_PRIVACY_RESTRICTED"_q)
|
||||
? Peers{ .state = WhoReadState::MyHidden }
|
||||
: (text == u"USER_PRIVACY_RESTRICTED"_q)
|
||||
? Peers{ .state = WhoReadState::HisHidden }
|
||||
: (text == u"MESSAGE_TOO_OLD"_q)
|
||||
? Peers{ .state = WhoReadState::TooOld }
|
||||
: Peers{ .state = WhoReadState::Empty };
|
||||
}
|
||||
}).send();
|
||||
} else {
|
||||
entry.requestId = session->api().request(
|
||||
MTPmessages_GetMessageReadParticipants(
|
||||
item->history()->peer->input,
|
||||
@@ -243,8 +298,8 @@ struct State {
|
||||
}).fail([=] {
|
||||
auto &entry = context->cacheRead(item);
|
||||
entry.requestId = 0;
|
||||
if (entry.data.current().unknown) {
|
||||
entry.data = Peers();
|
||||
if (entry.data.current().state == WhoReadState::Unknown) {
|
||||
entry.data = Peers{ .state = WhoReadState::Empty };
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
@@ -258,7 +313,7 @@ struct State {
|
||||
.list = peers.list | ranges::views::transform([](WhoReadPeer peer) {
|
||||
return PeerWithReaction{ .peerWithDate = peer };
|
||||
}) | ranges::to_vector,
|
||||
.unknown = peers.unknown,
|
||||
.state = peers.state,
|
||||
};
|
||||
result.read = std::move(peers.list);
|
||||
return result;
|
||||
@@ -319,8 +374,10 @@ struct State {
|
||||
}).fail([=] {
|
||||
auto &entry = context->cacheReacted(item, reaction);
|
||||
entry.requestId = 0;
|
||||
if (entry.data.current().unknown) {
|
||||
entry.data = PeersWithReactions();
|
||||
if (entry.data.current().state == WhoReadState::Unknown) {
|
||||
entry.data = PeersWithReactions{
|
||||
.state = WhoReadState::Empty,
|
||||
};
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
@@ -336,8 +393,9 @@ struct State {
|
||||
WhoReactedIds(item, {}, context),
|
||||
WhoReadIds(item, context)
|
||||
) | rpl::map([=](PeersWithReactions &&reacted, Peers &&read) {
|
||||
if (reacted.unknown || read.unknown) {
|
||||
return PeersWithReactions{ .unknown = true };
|
||||
if (reacted.state == WhoReadState::Unknown
|
||||
|| read.state == WhoReadState::Unknown) {
|
||||
return PeersWithReactions{ .state = WhoReadState::Unknown};
|
||||
}
|
||||
auto &list = reacted.list;
|
||||
for (const auto &peerWithDate : read.list) {
|
||||
@@ -531,16 +589,17 @@ rpl::producer<Ui::WhoReadContent> WhoReacted(
|
||||
std::move(
|
||||
idsWithReactions
|
||||
) | rpl::start_with_next([=](PeersWithReactions &&peers) {
|
||||
if (peers.unknown) {
|
||||
if (peers.state == WhoReadState::Unknown) {
|
||||
state->userpics.clear();
|
||||
consumer.put_next(Ui::WhoReadContent{
|
||||
.type = state->current.type,
|
||||
.fullReactionsCount = state->current.fullReactionsCount,
|
||||
.fullReadCount = state->current.fullReadCount,
|
||||
.unknown = true,
|
||||
.state = WhoReadState::Unknown,
|
||||
});
|
||||
return;
|
||||
}
|
||||
state->current.state = peers.state;
|
||||
state->current.fullReadCount = int(peers.read.size());
|
||||
state->current.fullReactionsCount = peers.fullReactionsCount;
|
||||
if (whoReadIds) {
|
||||
@@ -631,6 +690,22 @@ bool WhoReadExists(not_null<HistoryItem*> item) {
|
||||
}
|
||||
const auto history = item->history();
|
||||
const auto peer = history->peer;
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (user->isSelf()
|
||||
|| user->isBot()
|
||||
|| user->isServiceUser()
|
||||
|| user->readDatesPrivate()) {
|
||||
return false;
|
||||
}
|
||||
const auto &appConfig = peer->session().account().appConfig();
|
||||
const auto expirePeriod = appConfig.get<int>(
|
||||
"pm_read_date_expire_period",
|
||||
7 * 86400);
|
||||
if (item->date() + int64(expirePeriod) <= int64(base::unixtime::now())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const auto chat = peer->asChat();
|
||||
const auto megagroup = peer->asMegagroup();
|
||||
if ((!chat && !megagroup)
|
||||
|
||||
@@ -39,6 +39,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_sublist.h"
|
||||
#include "data/data_search_controller.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_session.h"
|
||||
@@ -221,11 +222,11 @@ void ApiWrap::setupSupportMode() {
|
||||
void ApiWrap::requestChangelog(
|
||||
const QString &sinceVersion,
|
||||
Fn<void(const MTPUpdates &result)> callback) {
|
||||
request(MTPhelp_GetAppChangelog(
|
||||
MTP_string(sinceVersion)
|
||||
)).done(
|
||||
callback
|
||||
).send();
|
||||
//request(MTPhelp_GetAppChangelog(
|
||||
// MTP_string(sinceVersion)
|
||||
//)).done(
|
||||
// callback
|
||||
//).send();
|
||||
}
|
||||
|
||||
void ApiWrap::refreshTopPromotion() {
|
||||
@@ -440,6 +441,26 @@ void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) {
|
||||
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);
|
||||
}
|
||||
Unexpected("Key type in pinnedDialogsOrder().");
|
||||
};
|
||||
auto peers = QVector<MTPInputDialogPeer>();
|
||||
peers.reserve(order.size());
|
||||
ranges::transform(
|
||||
order,
|
||||
ranges::back_inserter(peers),
|
||||
input);
|
||||
request(MTPmessages_ReorderPinnedSavedDialogs(
|
||||
MTP_flags(MTPmessages_ReorderPinnedSavedDialogs::Flag::f_force),
|
||||
MTP_vector(peers)
|
||||
)).send();
|
||||
}
|
||||
|
||||
void ApiWrap::toggleHistoryArchived(
|
||||
not_null<History*> history,
|
||||
bool archived,
|
||||
@@ -1901,28 +1922,28 @@ void ApiWrap::saveDraftToCloudDelayed(not_null<Data::Thread*> thread) {
|
||||
|
||||
void ApiWrap::updatePrivacyLastSeens() {
|
||||
const auto now = base::unixtime::now();
|
||||
_session->data().enumerateUsers([&](UserData *user) {
|
||||
if (user->isSelf() || !user->isLoaded()) {
|
||||
return;
|
||||
}
|
||||
if (user->onlineTill <= 0) {
|
||||
return;
|
||||
}
|
||||
if (!_session->premium()) {
|
||||
_session->data().enumerateUsers([&](not_null<UserData*> user) {
|
||||
if (user->isSelf()
|
||||
|| !user->isLoaded()
|
||||
|| user->lastseen().isHidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (user->onlineTill + 3 * 86400 >= now) {
|
||||
user->onlineTill = -2; // recently
|
||||
} else if (user->onlineTill + 7 * 86400 >= now) {
|
||||
user->onlineTill = -3; // last week
|
||||
} else if (user->onlineTill + 30 * 86400 >= now) {
|
||||
user->onlineTill = -4; // last month
|
||||
} else {
|
||||
user->onlineTill = 0;
|
||||
}
|
||||
session().changes().peerUpdated(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::OnlineStatus);
|
||||
session().data().maybeStopWatchForOffline(user);
|
||||
});
|
||||
const auto till = user->lastseen().onlineTill();
|
||||
user->updateLastseen((till + 3 * 86400 >= now)
|
||||
? Data::LastseenStatus::Recently(true)
|
||||
: (till + 7 * 86400 >= now)
|
||||
? Data::LastseenStatus::WithinWeek(true)
|
||||
: (till + 30 * 86400 >= now)
|
||||
? Data::LastseenStatus::WithinMonth(true)
|
||||
: Data::LastseenStatus::LongAgo(true));
|
||||
session().changes().peerUpdated(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::OnlineStatus);
|
||||
session().data().maybeStopWatchForOffline(user);
|
||||
});
|
||||
}
|
||||
|
||||
if (_contactsStatusesRequestId) {
|
||||
request(_contactsStatusesRequestId).cancel();
|
||||
@@ -1930,20 +1951,17 @@ void ApiWrap::updatePrivacyLastSeens() {
|
||||
_contactsStatusesRequestId = request(MTPcontacts_GetStatuses(
|
||||
)).done([=](const MTPVector<MTPContactStatus> &result) {
|
||||
_contactsStatusesRequestId = 0;
|
||||
for (const auto &item : result.v) {
|
||||
Assert(item.type() == mtpc_contactStatus);
|
||||
auto &data = item.c_contactStatus();
|
||||
if (auto user = _session->data().userLoaded(data.vuser_id())) {
|
||||
auto oldOnlineTill = user->onlineTill;
|
||||
auto newOnlineTill = OnlineTillFromStatus(
|
||||
for (const auto &status : result.v) {
|
||||
const auto &data = status.data();
|
||||
const auto userId = UserId(data.vuser_id());
|
||||
if (const auto user = _session->data().userLoaded(userId)) {
|
||||
const auto status = LastseenFromMTP(
|
||||
data.vstatus(),
|
||||
oldOnlineTill);
|
||||
if (oldOnlineTill != newOnlineTill) {
|
||||
user->onlineTill = newOnlineTill;
|
||||
user->lastseen());
|
||||
if (user->updateLastseen(status)) {
|
||||
session().changes().peerUpdated(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::OnlineStatus);
|
||||
session().data().maybeStopWatchForOffline(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1952,22 +1970,6 @@ void ApiWrap::updatePrivacyLastSeens() {
|
||||
}).send();
|
||||
}
|
||||
|
||||
int ApiWrap::OnlineTillFromStatus(
|
||||
const MTPUserStatus &status,
|
||||
int currentOnlineTill) {
|
||||
switch (status.type()) {
|
||||
case mtpc_userStatusEmpty: return 0;
|
||||
case mtpc_userStatusRecently:
|
||||
// Don't modify pseudo-online.
|
||||
return (currentOnlineTill > -10) ? -2 : currentOnlineTill;
|
||||
case mtpc_userStatusLastWeek: return -3;
|
||||
case mtpc_userStatusLastMonth: return -4;
|
||||
case mtpc_userStatusOffline: return status.c_userStatusOffline().vwas_online().v;
|
||||
case mtpc_userStatusOnline: return status.c_userStatusOnline().vexpires().v;
|
||||
}
|
||||
Unexpected("Bad UserStatus type.");
|
||||
}
|
||||
|
||||
void ApiWrap::clearHistory(not_null<PeerData*> peer, bool revoke) {
|
||||
deleteHistory(peer, true, revoke);
|
||||
}
|
||||
|
||||