Compare commits
260 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9717a8b5fa | ||
|
|
aff4f69b64 | ||
|
|
9de4c42555 | ||
|
|
1de144a48d | ||
|
|
0690d14f1b | ||
|
|
53ac4c00ad | ||
|
|
f064692e57 | ||
|
|
3d54a263b8 | ||
|
|
47bb8ec687 | ||
|
|
3a2b772a5d | ||
|
|
bc8f8bc68c | ||
|
|
bc7975ece7 | ||
|
|
52cca98144 | ||
|
|
5540b0bb8b | ||
|
|
7de9bcad03 | ||
|
|
367b028094 | ||
|
|
8b27aa5331 | ||
|
|
9697567b8d | ||
|
|
1fdfa94497 | ||
|
|
1373bd0af1 | ||
|
|
4f2b0531f8 | ||
|
|
ca67ac913f | ||
|
|
4033a091b5 | ||
|
|
0179a2ca10 | ||
|
|
f58874572d | ||
|
|
143b9682a4 | ||
|
|
00c962e557 | ||
|
|
1cabfaa6a4 | ||
|
|
b788ae0ae4 | ||
|
|
3f6399f13d | ||
|
|
b6fc418d32 | ||
|
|
245d644cd7 | ||
|
|
2aa0b674cd | ||
|
|
654784ce9f | ||
|
|
744eccc51e | ||
|
|
ce49714533 | ||
|
|
ae2c858dc9 | ||
|
|
f0b5dc42f9 | ||
|
|
9c213bf1c0 | ||
|
|
0c1175f9cd | ||
|
|
0c1312419a | ||
|
|
7e9695b213 | ||
|
|
093fcc3821 | ||
|
|
6f89598a7b | ||
|
|
6ccd53689d | ||
|
|
cd506dfff5 | ||
|
|
5a3733b5b6 | ||
|
|
22a85016e3 | ||
|
|
26c7a95a9f | ||
|
|
9acf617c9f | ||
|
|
72af170484 | ||
|
|
4db2505f5d | ||
|
|
4d40336be0 | ||
|
|
616531b0d0 | ||
|
|
473803edb8 | ||
|
|
a33ca97298 | ||
|
|
a711c89409 | ||
|
|
24ec0e0866 | ||
|
|
e6df927e30 | ||
|
|
638ea3111f | ||
|
|
983d9e6eee | ||
|
|
4b6d74dd9b | ||
|
|
8d70a62ee8 | ||
|
|
a0af748fc5 | ||
|
|
f10ef26226 | ||
|
|
4ebc62afd2 | ||
|
|
18cb26fed6 | ||
|
|
d965385356 | ||
|
|
5cc4066b65 | ||
|
|
6b084301be | ||
|
|
498e82b804 | ||
|
|
8c224f7aca | ||
|
|
f3a2460a54 | ||
|
|
04212140cc | ||
|
|
4e1904b137 | ||
|
|
0299ba4873 | ||
|
|
46ce0df832 | ||
|
|
d66debd802 | ||
|
|
454fe8cdf7 | ||
|
|
c4dfc634d0 | ||
|
|
b08fa069b4 | ||
|
|
3d20958bb4 | ||
|
|
c693fcb2b0 | ||
|
|
ddad42d80e | ||
|
|
c6f66e83ee | ||
|
|
8bb3b7fada | ||
|
|
1d24d29afa | ||
|
|
0536a479f9 | ||
|
|
7fef7e6315 | ||
|
|
c6ef2b057e | ||
|
|
784f10678c | ||
|
|
92dbd7089b | ||
|
|
415990c913 | ||
|
|
e42af74dd2 | ||
|
|
bd1a46252d | ||
|
|
874e5e0a61 | ||
|
|
81457693f1 | ||
|
|
3a700650be | ||
|
|
d642c3f3b5 | ||
|
|
4be03ffc25 | ||
|
|
dcac3146c7 | ||
|
|
10012d6b31 | ||
|
|
3aa1b1e9ae | ||
|
|
4e8a1f8d29 | ||
|
|
11e03a181d | ||
|
|
4e366dc86e | ||
|
|
015277c4d3 | ||
|
|
745bbfe268 | ||
|
|
e8a58c4c8d | ||
|
|
d4f2c96322 | ||
|
|
bd1d0417a9 | ||
|
|
4a78eb100a | ||
|
|
7fa5ca192b | ||
|
|
371510cfe2 | ||
|
|
622c1a910b | ||
|
|
ce3279143d | ||
|
|
3e6ba53a04 | ||
|
|
41cb37b091 | ||
|
|
264dd0c1d2 | ||
|
|
163e549708 | ||
|
|
035a19b41e | ||
|
|
6ac5f32796 | ||
|
|
0c4c4b2fcf | ||
|
|
a106d6e804 | ||
|
|
6b7c33f0ee | ||
|
|
8d2cacac80 | ||
|
|
cc9eb7f893 | ||
|
|
94c2969f8b | ||
|
|
719bed6e85 | ||
|
|
8634c1f7f3 | ||
|
|
def1266216 | ||
|
|
2e02f27a5c | ||
|
|
04855f1697 | ||
|
|
c29730650e | ||
|
|
6257445d5e | ||
|
|
405c8125da | ||
|
|
62da24c20b | ||
|
|
e8df47c926 | ||
|
|
433c147dd0 | ||
|
|
8f4fdb6d0d | ||
|
|
aecdc01e41 | ||
|
|
bdce2d5e25 | ||
|
|
5968219fe4 | ||
|
|
f81271d1fe | ||
|
|
9f3af7234e | ||
|
|
90c0929407 | ||
|
|
1e31cda78d | ||
|
|
f7e4f18e9b | ||
|
|
0fb42ed82a | ||
|
|
c535a7c564 | ||
|
|
c32f2e71e8 | ||
|
|
a38f7b357c | ||
|
|
438f69e1b2 | ||
|
|
891b4a91a3 | ||
|
|
889139f31f | ||
|
|
247b1f64ca | ||
|
|
13ad590a51 | ||
|
|
e021e0beb3 | ||
|
|
b097bd7225 | ||
|
|
27f85df562 | ||
|
|
e484bc78d0 | ||
|
|
d89be1d1d4 | ||
|
|
ab429212e5 | ||
|
|
f53f934001 | ||
|
|
a287dec242 | ||
|
|
f73b0f0b0d | ||
|
|
61d89113d4 | ||
|
|
7862443fcb | ||
|
|
1a40f2b3ef | ||
|
|
4c1213ce9e | ||
|
|
afbc0c498f | ||
|
|
a91c078fb1 | ||
|
|
6eedeb3852 | ||
|
|
8af559e711 | ||
|
|
7f928a92ea | ||
|
|
22dc7601f5 | ||
|
|
9abca29f4c | ||
|
|
cf48152853 | ||
|
|
883c3ecf65 | ||
|
|
9a96298ef7 | ||
|
|
a1a845dbf1 | ||
|
|
40e925d3f9 | ||
|
|
808e8dcf4f | ||
|
|
c2bb2526d3 | ||
|
|
59abe95754 | ||
|
|
040f29abe6 | ||
|
|
e9dffe78e3 | ||
|
|
3a51303fb0 | ||
|
|
008a301755 | ||
|
|
be14456290 | ||
|
|
4a94a0c438 | ||
|
|
608d8307d9 | ||
|
|
6f9ea1cc01 | ||
|
|
47170da813 | ||
|
|
01ab6e6d4d | ||
|
|
b8424b1d89 | ||
|
|
78d83a2c69 | ||
|
|
beb623bee2 | ||
|
|
d42ce87c09 | ||
|
|
60002555c3 | ||
|
|
fb20be3e6c | ||
|
|
31e1ed216a | ||
|
|
ce91caa820 | ||
|
|
95a579f25f | ||
|
|
9fe82480e1 | ||
|
|
17549ad5ea | ||
|
|
f22a804220 | ||
|
|
c563df7d9d | ||
|
|
1849f01b15 | ||
|
|
f8b83dd186 | ||
|
|
f0e1d2fd02 | ||
|
|
734d834a20 | ||
|
|
b3eb41b989 | ||
|
|
45419205c6 | ||
|
|
204645a715 | ||
|
|
50a0429786 | ||
|
|
00cdae0369 | ||
|
|
437c9320cd | ||
|
|
0888901d79 | ||
|
|
55edb3bdfe | ||
|
|
fcdc4cd465 | ||
|
|
49c230b898 | ||
|
|
883a62c0a2 | ||
|
|
58008ab7b0 | ||
|
|
94468ecf6d | ||
|
|
91118bf087 | ||
|
|
6805085bbc | ||
|
|
78d874e9a3 | ||
|
|
8d5e356733 | ||
|
|
4c2779bbaf | ||
|
|
70c993774a | ||
|
|
f128665f6b | ||
|
|
0cd68f866d | ||
|
|
242ced4022 | ||
|
|
23aef6c365 | ||
|
|
210e3f0cb6 | ||
|
|
d86b4659d6 | ||
|
|
f1cf6b4896 | ||
|
|
8fd1253266 | ||
|
|
5991cd4350 | ||
|
|
309372164c | ||
|
|
f1cdc7e3f9 | ||
|
|
dfad68a0b8 | ||
|
|
0f887b3432 | ||
|
|
077f0c393e | ||
|
|
7d29f9ce17 | ||
|
|
6635d03818 | ||
|
|
e523492de0 | ||
|
|
c77f1bf082 | ||
|
|
3c8c059447 | ||
|
|
612e0d4a10 | ||
|
|
78a2835bbf | ||
|
|
ea8e256a23 | ||
|
|
2f2de84b43 | ||
|
|
ead6892857 | ||
|
|
2b642d4da9 | ||
|
|
a474074705 | ||
|
|
d34eabdc11 | ||
|
|
f9be304e54 | ||
|
|
39b0662a2c |
21
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels: []
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: |
|
||||
Hey there!
|
||||
|
||||
This issue will be automatically closed in 7 days if there would be no activity. We therefore assume that the user has lost interest or resolved the problem on their own.
|
||||
|
||||
Don't worry though; if this is an error, let us know with a comment and we'll be happy to reopen the issue.
|
||||
|
||||
Thanks!
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
# Process only issues
|
||||
only: issues
|
||||
4
.github/workflows/linux.yml
vendored
@@ -182,7 +182,7 @@ jobs:
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone $GIT/01org/libva.git
|
||||
git clone $GIT/intel/libva.git
|
||||
cd libva
|
||||
./autogen.sh --enable-static
|
||||
make -j$(nproc)
|
||||
@@ -222,7 +222,6 @@ jobs:
|
||||
--disable-network \
|
||||
--disable-autodetect \
|
||||
--disable-everything \
|
||||
--disable-neon \
|
||||
--disable-alsa \
|
||||
--disable-iconv \
|
||||
--enable-libopus \
|
||||
@@ -444,6 +443,7 @@ jobs:
|
||||
-qt-harfbuzz \
|
||||
-qt-pcre \
|
||||
-qt-xcb \
|
||||
-no-icu \
|
||||
-no-gtk \
|
||||
-static \
|
||||
-dbus-runtime \
|
||||
|
||||
14
.github/workflows/mac.yml
vendored
@@ -167,7 +167,7 @@ jobs:
|
||||
id: cache-opus
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/opus
|
||||
path: ${{ env.LibrariesPath }}/opus-cache
|
||||
key: ${{ runner.OS }}-opus-${{ env.CACHE_KEY }}
|
||||
- name: Opus.
|
||||
if: steps.cache-opus.outputs.cache-hit != 'true'
|
||||
@@ -180,16 +180,17 @@ jobs:
|
||||
./autogen.sh
|
||||
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
|
||||
make -j$(nproc)
|
||||
sudo make DESTDIR="$LibrariesPath/opus-cache" install
|
||||
- name: Opus install.
|
||||
run: |
|
||||
cd $LibrariesPath/opus
|
||||
sudo make install
|
||||
cd $LibrariesPath
|
||||
sudo cp -R opus-cache/. /
|
||||
|
||||
- name: Libiconv cache.
|
||||
id: cache-libiconv
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/${{ env.LIBICONV_VER }}
|
||||
path: ${{ env.LibrariesPath }}/libiconv-cache
|
||||
key: ${{ runner.OS }}-${{ env.LIBICONV_VER }}-${{ env.CACHE_KEY }}
|
||||
- name: Libiconv.
|
||||
if: steps.cache-libiconv.outputs.cache-hit != 'true'
|
||||
@@ -201,10 +202,11 @@ jobs:
|
||||
cd $LIBICONV_VER
|
||||
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --enable-static --prefix=$PREFIX
|
||||
make -j$(nproc)
|
||||
sudo make DESTDIR="$LibrariesPath/libiconv-cache" install
|
||||
- name: Libiconv install.
|
||||
run: |
|
||||
cd $LibrariesPath/$LIBICONV_VER
|
||||
sudo make install
|
||||
cd $LibrariesPath
|
||||
sudo cp -R libiconv-cache/. /
|
||||
|
||||
- name: FFmpeg cache.
|
||||
id: cache-ffmpeg
|
||||
|
||||
9
.github/workflows/snap.yml
vendored
@@ -12,7 +12,6 @@ on:
|
||||
- '!.github/workflows/snap.yml'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- '!Telegram/Patches/ffmpeg.diff'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -31,7 +30,6 @@ on:
|
||||
- '!.github/workflows/snap.yml'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- '!Telegram/Patches/ffmpeg.diff'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -43,8 +41,8 @@ on:
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
name: Ubuntu 20.04
|
||||
runs-on: ubuntu-20.04
|
||||
name: Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
@@ -57,7 +55,10 @@ jobs:
|
||||
|
||||
- name: First set up.
|
||||
run: |
|
||||
sudo apt-get purge --autoremove lxd
|
||||
|
||||
sudo snap install --classic snapcraft
|
||||
sudo snap install lxd
|
||||
|
||||
# Workaround for snapcraft
|
||||
# See https://forum.snapcraft.io/t/13258
|
||||
|
||||
90
.github/workflows/user_agent_updater.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
name: User-agent updater.
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: ["Restart user_agent_updater workflow."]
|
||||
schedule:
|
||||
# At 00:00 on day-of-month 1.
|
||||
- cron: '0 0 1 * *'
|
||||
|
||||
jobs:
|
||||
User-agent:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
code_file: "Telegram/SourceFiles/mtproto/details/mtproto_domain_resolver.cpp"
|
||||
skip: "0"
|
||||
|
||||
steps:
|
||||
- name: Clone.
|
||||
if: env.skip == '0'
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Write a new version of Google Chrome to the user-agent for DNS.
|
||||
if: env.skip == '0'
|
||||
shell: python
|
||||
run: |
|
||||
import subprocess, os, re;
|
||||
|
||||
regExpVersion = "[0-9]+.[0-9]+.[0-9]+.[0-9]+";
|
||||
chrome = "Chrome/";
|
||||
|
||||
def newVersion():
|
||||
output = subprocess.check_output(["google-chrome", "--version"]);
|
||||
version = re.search(regExpVersion, output);
|
||||
if not version:
|
||||
print("Can't find a Chrome version.");
|
||||
exit();
|
||||
return version.group(0);
|
||||
|
||||
newChromeVersion = newVersion();
|
||||
print(newChromeVersion);
|
||||
|
||||
def writeUserAgent():
|
||||
p = os.environ['code_file'];
|
||||
w = open(p, "r");
|
||||
content = w.read();
|
||||
w.close();
|
||||
|
||||
regExpChrome = chrome + regExpVersion;
|
||||
|
||||
version = re.search(regExpChrome, content);
|
||||
if not version:
|
||||
print("Can't find an user-agent in the code.");
|
||||
exit();
|
||||
content = re.sub(regExpChrome, chrome + newChromeVersion, content);
|
||||
|
||||
w = open(p, "w");
|
||||
w.write(content);
|
||||
|
||||
print("::set-env name=ChromeVersion::" + newChromeVersion);
|
||||
|
||||
writeUserAgent();
|
||||
|
||||
- name: Push to the current branch.
|
||||
if: env.skip == '0' && env.ChromeVersion != ''
|
||||
run: |
|
||||
token=${{ secrets.TOKEN_FOR_MASTER_UPDATER }}
|
||||
if [ -z "${token}" ]; then
|
||||
echo "Token is unset. Nothing to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
url=https://x-access-token:$token@github.com/$GITHUB_REPOSITORY
|
||||
|
||||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "GitHub Action"
|
||||
|
||||
git diff > git_diff.txt
|
||||
if [[ ! -s git_diff.txt ]]; then
|
||||
echo "Nothing to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add $code_file
|
||||
git commit -m "Update User-Agent for DNS to Chrome $ChromeVersion."
|
||||
|
||||
git remote set-url origin $url
|
||||
|
||||
git push origin HEAD:$GITHUB_REF
|
||||
echo "Done!"
|
||||
7
.github/workflows/win.yml
vendored
@@ -169,7 +169,7 @@ jobs:
|
||||
move ossl_static.pdb out32.dbg\ossl_static
|
||||
nmake clean
|
||||
move out32.dbg\ossl_static out32.dbg\ossl_static.pdb
|
||||
perl Configure no-shared VC-WIN32
|
||||
perl Configure no-shared no-tests VC-WIN32
|
||||
nmake
|
||||
mkdir out32
|
||||
move libcrypto.lib out32
|
||||
@@ -206,11 +206,12 @@ jobs:
|
||||
cd openal-soft
|
||||
git checkout fix_capture
|
||||
cd build
|
||||
cmake ^
|
||||
cmake .. ^
|
||||
-G "Visual Studio 16 2019" ^
|
||||
-A Win32 ^
|
||||
-D LIBTYPE:STRING=STATIC ^
|
||||
-D FORCE_STATIC_VCRT:STRING=ON ..
|
||||
-D FORCE_STATIC_VCRT=ON ^
|
||||
-D ALSOFT_BACKEND_WASAPI=OFF
|
||||
|
||||
msbuild -m OpenAL.vcxproj /property:Configuration=Debug
|
||||
|
||||
|
||||
9
.gitmodules
vendored
@@ -1,9 +1,6 @@
|
||||
[submodule "Telegram/ThirdParty/libtgvoip"]
|
||||
path = Telegram/ThirdParty/libtgvoip
|
||||
url = https://github.com/telegramdesktop/libtgvoip
|
||||
[submodule "Telegram/ThirdParty/variant"]
|
||||
path = Telegram/ThirdParty/variant
|
||||
url = https://github.com/desktop-app/variant.git
|
||||
[submodule "Telegram/ThirdParty/GSL"]
|
||||
path = Telegram/ThirdParty/GSL
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
@@ -85,12 +82,6 @@
|
||||
[submodule "Telegram/ThirdParty/qt5ct"]
|
||||
path = Telegram/ThirdParty/qt5ct
|
||||
url = https://github.com/desktop-app/qt5ct.git
|
||||
[submodule "Telegram/ThirdParty/lxqt-qtplugin"]
|
||||
path = Telegram/ThirdParty/lxqt-qtplugin
|
||||
url = https://github.com/lxqt/lxqt-qtplugin.git
|
||||
[submodule "Telegram/ThirdParty/libqtxdg"]
|
||||
path = Telegram/ThirdParty/libqtxdg
|
||||
url = https://github.com/lxqt/libqtxdg.git
|
||||
[submodule "Telegram/ThirdParty/fcitx5-qt"]
|
||||
path = Telegram/ThirdParty/fcitx5-qt
|
||||
url = https://github.com/fcitx/fcitx5-qt.git
|
||||
|
||||
@@ -36,5 +36,9 @@ include(cmake/options.cmake)
|
||||
|
||||
include(cmake/external/qt/package.cmake)
|
||||
|
||||
set(desktop_app_skip_libs
|
||||
variant
|
||||
)
|
||||
|
||||
add_subdirectory(cmake)
|
||||
add_subdirectory(Telegram)
|
||||
|
||||
@@ -34,6 +34,7 @@ Version **1.8.15** was the last that supports older systems
|
||||
|
||||
* Qt 5.12.8, 5.6.2 and 5.3.2 slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html))
|
||||
* OpenSSL 1.1.1 and 1.0.1 ([OpenSSL License](https://www.openssl.org/source/license.html))
|
||||
* WebRTC ([New BSD License](https://github.com/desktop-app/tg_owt/blob/master/src/LICENSE))
|
||||
* zlib 1.2.11 ([zlib License](http://www.zlib.net/zlib_license.html))
|
||||
* LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html))
|
||||
* liblzma ([public domain](http://tukaani.org/xz/))
|
||||
@@ -45,7 +46,6 @@ Version **1.8.15** was the last that supports older systems
|
||||
* Opus codec ([BSD License](http://www.opus-codec.org/license/))
|
||||
* FFmpeg ([LGPL](https://www.ffmpeg.org/legal.html))
|
||||
* Guideline Support Library ([MIT License](https://github.com/Microsoft/GSL/blob/master/LICENSE))
|
||||
* Mapbox Variant ([BSD License](https://github.com/mapbox/variant/blob/master/LICENSE))
|
||||
* Range-v3 ([Boost License](https://github.com/ericniebler/range-v3/blob/master/LICENSE.txt))
|
||||
* Open Sans font ([Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html))
|
||||
* Vazir font ([License](https://github.com/rastikerdar/vazir-font/blob/master/LICENSE))
|
||||
|
||||
@@ -21,21 +21,21 @@ add_subdirectory(lib_qr)
|
||||
add_subdirectory(lib_webrtc)
|
||||
add_subdirectory(codegen)
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(lib_ui/cmake/generate_styles.cmake)
|
||||
include(cmake/generate_lang.cmake)
|
||||
include(cmake/generate_numbers.cmake)
|
||||
|
||||
get_filename_component(src_loc SourceFiles REALPATH)
|
||||
get_filename_component(res_loc Resources REALPATH)
|
||||
|
||||
include(cmake/telegram_options.cmake)
|
||||
include(cmake/lib_export.cmake)
|
||||
include(cmake/lib_ffmpeg.cmake)
|
||||
include(cmake/lib_mtproto.cmake)
|
||||
include(cmake/lib_scheme.cmake)
|
||||
include(cmake/lib_tgvoip.cmake)
|
||||
include(cmake/lib_tgcalls.cmake)
|
||||
include(cmake/td_export.cmake)
|
||||
include(cmake/td_mtproto.cmake)
|
||||
include(cmake/td_lang.cmake)
|
||||
include(cmake/td_scheme.cmake)
|
||||
include(cmake/td_ui.cmake)
|
||||
|
||||
set(style_files
|
||||
boxes/boxes.style
|
||||
@@ -61,10 +61,10 @@ set(dependent_style_files
|
||||
${submodules_loc}/lib_ui/ui/basic.style
|
||||
${submodules_loc}/lib_ui/ui/layers/layers.style
|
||||
${submodules_loc}/lib_ui/ui/widgets/widgets.style
|
||||
${src_loc}/ui/td_common.style
|
||||
)
|
||||
|
||||
generate_styles(Telegram ${src_loc} "${style_files}" "${dependent_style_files}")
|
||||
generate_lang(Telegram ${res_loc}/langs/lang.strings)
|
||||
generate_numbers(Telegram ${res_loc}/numbers.txt)
|
||||
|
||||
set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON)
|
||||
@@ -74,9 +74,11 @@ PRIVATE
|
||||
tdesktop::lib_tgcalls_legacy
|
||||
tdesktop::lib_tgcalls
|
||||
tdesktop::lib_tgvoip
|
||||
tdesktop::lib_mtproto
|
||||
tdesktop::lib_scheme
|
||||
tdesktop::lib_export
|
||||
tdesktop::td_export
|
||||
tdesktop::td_mtproto
|
||||
tdesktop::td_lang
|
||||
tdesktop::td_scheme
|
||||
tdesktop::td_ui
|
||||
desktop-app::lib_webrtc
|
||||
desktop-app::lib_base
|
||||
desktop-app::lib_crl
|
||||
@@ -104,17 +106,12 @@ if (LINUX)
|
||||
desktop-app::external_materialdecoration
|
||||
desktop-app::external_nimf_qt5
|
||||
desktop-app::external_qt5ct_support
|
||||
desktop-app::external_xcb_screensaver
|
||||
desktop-app::external_xcb
|
||||
desktop-app::external_glib
|
||||
)
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
||||
# conflicts with Qt static link
|
||||
if (DESKTOP_APP_USE_PACKAGED_LAZY_PLATFORMTHEMES)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_lxqt_qtplugin
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_statusnotifieritem
|
||||
@@ -135,36 +132,6 @@ if (LINUX)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DESKTOP_APP_USE_PACKAGED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(XCB_SCREENSAVER REQUIRED IMPORTED_TARGET xcb-screensaver)
|
||||
pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb)
|
||||
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
PkgConfig::XCB_SCREENSAVER
|
||||
PkgConfig::XCB
|
||||
)
|
||||
else()
|
||||
target_link_static_libraries(Telegram PRIVATE xcb-screensaver)
|
||||
target_link_libraries(Telegram PRIVATE xcb)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GLIB2 REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
pkg_check_modules(GOBJECT REQUIRED IMPORTED_TARGET gobject-2.0)
|
||||
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
|
||||
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
PkgConfig::GLIB2
|
||||
PkgConfig::GOBJECT
|
||||
PkgConfig::GIO
|
||||
)
|
||||
|
||||
target_compile_definitions(Telegram PRIVATE G_LOG_DOMAIN="Telegram")
|
||||
target_compile_options(Telegram PRIVATE -Wno-register)
|
||||
|
||||
if (NOT TDESKTOP_DISABLE_GTK_INTEGRATION)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
@@ -190,6 +157,8 @@ nice_target_sources(Telegram ${src_loc}
|
||||
PRIVATE
|
||||
${style_files}
|
||||
|
||||
api/api_authorizations.cpp
|
||||
api/api_authorizations.h
|
||||
api/api_bot.cpp
|
||||
api/api_bot.h
|
||||
api/api_chat_filters.cpp
|
||||
@@ -468,6 +437,8 @@ PRIVATE
|
||||
data/data_poll.h
|
||||
data/data_pts_waiter.cpp
|
||||
data/data_pts_waiter.h
|
||||
data/data_replies_list.cpp
|
||||
data/data_replies_list.h
|
||||
data/data_reply_preview.cpp
|
||||
data/data_reply_preview.h
|
||||
data/data_search_controller.cpp
|
||||
@@ -589,10 +560,14 @@ PRIVATE
|
||||
history/view/history_view_message.cpp
|
||||
history/view/history_view_message.h
|
||||
history/view/history_view_object.h
|
||||
history/view/history_view_replies_section.cpp
|
||||
history/view/history_view_replies_section.h
|
||||
history/view/history_view_schedule_box.cpp
|
||||
history/view/history_view_schedule_box.h
|
||||
history/view/history_view_scheduled_section.cpp
|
||||
history/view/history_view_scheduled_section.h
|
||||
history/view/history_view_send_action.cpp
|
||||
history/view/history_view_send_action.h
|
||||
history/view/history_view_service_message.cpp
|
||||
history/view/history_view_service_message.h
|
||||
history/view/history_view_top_bar_widget.cpp
|
||||
@@ -712,23 +687,12 @@ PRIVATE
|
||||
intro/intro_widget.h
|
||||
lang/lang_cloud_manager.cpp
|
||||
lang/lang_cloud_manager.h
|
||||
lang/lang_file_parser.cpp
|
||||
lang/lang_file_parser.h
|
||||
lang/lang_hardcoded.h
|
||||
lang/lang_instance.cpp
|
||||
lang/lang_instance.h
|
||||
lang/lang_keys.cpp
|
||||
lang/lang_keys.h
|
||||
lang/lang_numbers_animation.cpp
|
||||
lang/lang_numbers_animation.h
|
||||
lang/lang_tag.cpp
|
||||
lang/lang_tag.h
|
||||
lang/lang_text_entity.cpp
|
||||
lang/lang_text_entity.h
|
||||
lang/lang_translator.cpp
|
||||
lang/lang_translator.h
|
||||
lang/lang_values.cpp
|
||||
lang/lang_values.h
|
||||
main/main_account.cpp
|
||||
main/main_account.h
|
||||
main/main_app_config.cpp
|
||||
@@ -1142,6 +1106,7 @@ PRIVATE
|
||||
qt_static_plugins.cpp
|
||||
settings.cpp
|
||||
settings.h
|
||||
stdafx.h
|
||||
)
|
||||
|
||||
if (NOT LINUX)
|
||||
@@ -1291,6 +1256,7 @@ target_compile_definitions(Telegram
|
||||
PRIVATE
|
||||
TDESKTOP_API_ID=${TDESKTOP_API_ID}
|
||||
TDESKTOP_API_HASH=${TDESKTOP_API_HASH}
|
||||
G_LOG_DOMAIN="Telegram"
|
||||
)
|
||||
|
||||
if (APPLE OR NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL "" OR NOT "${output_name}" STREQUAL "Telegram")
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
diff --git a/libavcodec/aarch64/Makefile b/libavcodec/aarch64/Makefile
|
||||
index 00f93bf59f..52da7036f3 100644
|
||||
--- a/libavcodec/aarch64/Makefile
|
||||
+++ b/libavcodec/aarch64/Makefile
|
||||
@@ -6,6 +6,7 @@ OBJS-$(CONFIG_H264DSP) += aarch64/h264dsp_init_aarch64.o
|
||||
OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_init.o
|
||||
OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_init_aarch64.o
|
||||
OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o
|
||||
+OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o
|
||||
OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o
|
||||
OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o
|
||||
OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp_init.o
|
||||
@@ -21,6 +22,7 @@ OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_init_aarch64.o
|
||||
OBJS-$(CONFIG_VORBIS_DECODER) += aarch64/vorbisdsp_init.o
|
||||
OBJS-$(CONFIG_VP9_DECODER) += aarch64/vp9dsp_init_10bpp_aarch64.o \
|
||||
aarch64/vp9dsp_init_12bpp_aarch64.o \
|
||||
+ aarch64/vp9mc_aarch64.o \
|
||||
aarch64/vp9dsp_init_aarch64.o
|
||||
|
||||
# ARMv8 optimizations
|
||||
@@ -41,8 +43,7 @@ NEON-OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_neon.o
|
||||
NEON-OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_neon.o \
|
||||
aarch64/hpeldsp_neon.o
|
||||
NEON-OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_neon.o
|
||||
-NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o \
|
||||
- aarch64/simple_idct_neon.o
|
||||
+NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/simple_idct_neon.o
|
||||
NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o
|
||||
NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o
|
||||
NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o
|
||||
diff --git a/libavcodec/aarch64/idctdsp_init_aarch64.c b/libavcodec/aarch64/idctdsp_init_aarch64.c
|
||||
index 0406e60830..742a3372e3 100644
|
||||
--- a/libavcodec/aarch64/idctdsp_init_aarch64.c
|
||||
+++ b/libavcodec/aarch64/idctdsp_init_aarch64.c
|
||||
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
+#include "libavutil/cpu.h"
|
||||
+#include "libavutil/arm/cpu.h"
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavcodec/idctdsp.h"
|
||||
#include "idct.h"
|
||||
@@ -28,7 +30,9 @@
|
||||
av_cold void ff_idctdsp_init_aarch64(IDCTDSPContext *c, AVCodecContext *avctx,
|
||||
unsigned high_bit_depth)
|
||||
{
|
||||
- if (!avctx->lowres && !high_bit_depth) {
|
||||
+ int cpu_flags = av_get_cpu_flags();
|
||||
+
|
||||
+ if (have_neon(cpu_flags) && !avctx->lowres && !high_bit_depth) {
|
||||
if (avctx->idct_algo == FF_IDCT_AUTO ||
|
||||
avctx->idct_algo == FF_IDCT_SIMPLEAUTO ||
|
||||
avctx->idct_algo == FF_IDCT_SIMPLENEON) {
|
||||
diff --git a/libavcodec/aarch64/vp9mc_16bpp_neon.S b/libavcodec/aarch64/vp9mc_16bpp_neon.S
|
||||
index cac6428709..53b372c262 100644
|
||||
--- a/libavcodec/aarch64/vp9mc_16bpp_neon.S
|
||||
+++ b/libavcodec/aarch64/vp9mc_16bpp_neon.S
|
||||
@@ -25,31 +25,6 @@
|
||||
// const uint8_t *ref, ptrdiff_t ref_stride,
|
||||
// int h, int mx, int my);
|
||||
|
||||
-function ff_vp9_copy128_aarch64, export=1
|
||||
-1:
|
||||
- ldp x5, x6, [x2]
|
||||
- ldp x7, x8, [x2, #16]
|
||||
- stp x5, x6, [x0]
|
||||
- ldp x9, x10, [x2, #32]
|
||||
- stp x7, x8, [x0, #16]
|
||||
- subs w4, w4, #1
|
||||
- ldp x11, x12, [x2, #48]
|
||||
- stp x9, x10, [x0, #32]
|
||||
- stp x11, x12, [x0, #48]
|
||||
- ldp x5, x6, [x2, #64]
|
||||
- ldp x7, x8, [x2, #80]
|
||||
- stp x5, x6, [x0, #64]
|
||||
- ldp x9, x10, [x2, #96]
|
||||
- stp x7, x8, [x0, #80]
|
||||
- ldp x11, x12, [x2, #112]
|
||||
- stp x9, x10, [x0, #96]
|
||||
- stp x11, x12, [x0, #112]
|
||||
- add x2, x2, x3
|
||||
- add x0, x0, x1
|
||||
- b.ne 1b
|
||||
- ret
|
||||
-endfunc
|
||||
-
|
||||
function ff_vp9_avg64_16_neon, export=1
|
||||
mov x5, x0
|
||||
sub x1, x1, #64
|
||||
diff --git a/libavcodec/aarch64/vp9mc_aarch64.S b/libavcodec/aarch64/vp9mc_aarch64.S
|
||||
new file mode 100644
|
||||
index 0000000000..f17a8cf04a
|
||||
--- /dev/null
|
||||
+++ b/libavcodec/aarch64/vp9mc_aarch64.S
|
||||
@@ -0,0 +1,81 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2016 Google Inc.
|
||||
+ *
|
||||
+ * This file is part of FFmpeg.
|
||||
+ *
|
||||
+ * FFmpeg is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * FFmpeg is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with FFmpeg; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
+ */
|
||||
+
|
||||
+#include "libavutil/aarch64/asm.S"
|
||||
+
|
||||
+// All public functions in this file have the following signature:
|
||||
+// typedef void (*vp9_mc_func)(uint8_t *dst, ptrdiff_t dst_stride,
|
||||
+// const uint8_t *ref, ptrdiff_t ref_stride,
|
||||
+// int h, int mx, int my);
|
||||
+
|
||||
+function ff_vp9_copy128_aarch64, export=1
|
||||
+1:
|
||||
+ ldp x5, x6, [x2]
|
||||
+ ldp x7, x8, [x2, #16]
|
||||
+ stp x5, x6, [x0]
|
||||
+ ldp x9, x10, [x2, #32]
|
||||
+ stp x7, x8, [x0, #16]
|
||||
+ subs w4, w4, #1
|
||||
+ ldp x11, x12, [x2, #48]
|
||||
+ stp x9, x10, [x0, #32]
|
||||
+ stp x11, x12, [x0, #48]
|
||||
+ ldp x5, x6, [x2, #64]
|
||||
+ ldp x7, x8, [x2, #80]
|
||||
+ stp x5, x6, [x0, #64]
|
||||
+ ldp x9, x10, [x2, #96]
|
||||
+ stp x7, x8, [x0, #80]
|
||||
+ ldp x11, x12, [x2, #112]
|
||||
+ stp x9, x10, [x0, #96]
|
||||
+ stp x11, x12, [x0, #112]
|
||||
+ add x2, x2, x3
|
||||
+ add x0, x0, x1
|
||||
+ b.ne 1b
|
||||
+ ret
|
||||
+endfunc
|
||||
+
|
||||
+function ff_vp9_copy64_aarch64, export=1
|
||||
+1:
|
||||
+ ldp x5, x6, [x2]
|
||||
+ ldp x7, x8, [x2, #16]
|
||||
+ stp x5, x6, [x0]
|
||||
+ ldp x9, x10, [x2, #32]
|
||||
+ stp x7, x8, [x0, #16]
|
||||
+ subs w4, w4, #1
|
||||
+ ldp x11, x12, [x2, #48]
|
||||
+ stp x9, x10, [x0, #32]
|
||||
+ stp x11, x12, [x0, #48]
|
||||
+ add x2, x2, x3
|
||||
+ add x0, x0, x1
|
||||
+ b.ne 1b
|
||||
+ ret
|
||||
+endfunc
|
||||
+
|
||||
+function ff_vp9_copy32_aarch64, export=1
|
||||
+1:
|
||||
+ ldp x5, x6, [x2]
|
||||
+ ldp x7, x8, [x2, #16]
|
||||
+ stp x5, x6, [x0]
|
||||
+ subs w4, w4, #1
|
||||
+ stp x7, x8, [x0, #16]
|
||||
+ add x2, x2, x3
|
||||
+ add x0, x0, x1
|
||||
+ b.ne 1b
|
||||
+ ret
|
||||
+endfunc
|
||||
diff --git a/libavcodec/aarch64/vp9mc_neon.S b/libavcodec/aarch64/vp9mc_neon.S
|
||||
index f67624ca04..abf2bae9db 100644
|
||||
--- a/libavcodec/aarch64/vp9mc_neon.S
|
||||
+++ b/libavcodec/aarch64/vp9mc_neon.S
|
||||
@@ -25,23 +25,6 @@
|
||||
// const uint8_t *ref, ptrdiff_t ref_stride,
|
||||
// int h, int mx, int my);
|
||||
|
||||
-function ff_vp9_copy64_aarch64, export=1
|
||||
-1:
|
||||
- ldp x5, x6, [x2]
|
||||
- ldp x7, x8, [x2, #16]
|
||||
- stp x5, x6, [x0]
|
||||
- ldp x9, x10, [x2, #32]
|
||||
- stp x7, x8, [x0, #16]
|
||||
- subs w4, w4, #1
|
||||
- ldp x11, x12, [x2, #48]
|
||||
- stp x9, x10, [x0, #32]
|
||||
- stp x11, x12, [x0, #48]
|
||||
- add x2, x2, x3
|
||||
- add x0, x0, x1
|
||||
- b.ne 1b
|
||||
- ret
|
||||
-endfunc
|
||||
-
|
||||
function ff_vp9_avg64_neon, export=1
|
||||
mov x5, x0
|
||||
1:
|
||||
@@ -64,19 +47,6 @@ function ff_vp9_avg64_neon, export=1
|
||||
ret
|
||||
endfunc
|
||||
|
||||
-function ff_vp9_copy32_aarch64, export=1
|
||||
-1:
|
||||
- ldp x5, x6, [x2]
|
||||
- ldp x7, x8, [x2, #16]
|
||||
- stp x5, x6, [x0]
|
||||
- subs w4, w4, #1
|
||||
- stp x7, x8, [x0, #16]
|
||||
- add x2, x2, x3
|
||||
- add x0, x0, x1
|
||||
- b.ne 1b
|
||||
- ret
|
||||
-endfunc
|
||||
-
|
||||
function ff_vp9_avg32_neon, export=1
|
||||
1:
|
||||
ld1 {v2.16b, v3.16b}, [x2], x3
|
||||
BIN
Telegram/Resources/icons/fast_comments.png
Normal file
|
After Width: | Height: | Size: 422 B |
BIN
Telegram/Resources/icons/fast_comments@2x.png
Normal file
|
After Width: | Height: | Size: 767 B |
BIN
Telegram/Resources/icons/fast_comments@3x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 330 B After Width: | Height: | Size: 414 B |
|
Before Width: | Height: | Size: 661 B After Width: | Height: | Size: 764 B |
|
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/fast_to_original.png
Normal file
|
After Width: | Height: | Size: 242 B |
BIN
Telegram/Resources/icons/fast_to_original@2x.png
Normal file
|
After Width: | Height: | Size: 346 B |
BIN
Telegram/Resources/icons/fast_to_original@3x.png
Normal file
|
After Width: | Height: | Size: 473 B |
BIN
Telegram/Resources/icons/history_comments.png
Normal file
|
After Width: | Height: | Size: 609 B |
BIN
Telegram/Resources/icons/history_comments@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/history_comments@3x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/history_comments_open.png
Normal file
|
After Width: | Height: | Size: 194 B |
BIN
Telegram/Resources/icons/history_comments_open@2x.png
Normal file
|
After Width: | Height: | Size: 312 B |
BIN
Telegram/Resources/icons/history_comments_open@3x.png
Normal file
|
After Width: | Height: | Size: 393 B |
BIN
Telegram/Resources/icons/history_replies.png
Normal file
|
After Width: | Height: | Size: 315 B |
BIN
Telegram/Resources/icons/history_replies@2x.png
Normal file
|
After Width: | Height: | Size: 553 B |
BIN
Telegram/Resources/icons/history_replies@3x.png
Normal file
|
After Width: | Height: | Size: 573 B |
BIN
Telegram/Resources/icons/replies_userpic.png
Normal file
|
After Width: | Height: | Size: 441 B |
BIN
Telegram/Resources/icons/replies_userpic@2x.png
Normal file
|
After Width: | Height: | Size: 909 B |
BIN
Telegram/Resources/icons/replies_userpic@3x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
@@ -812,6 +812,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_set_group_photo" = "Set Photo";
|
||||
"lng_profile_add_participant" = "Add Members";
|
||||
"lng_profile_view_channel" = "View Channel";
|
||||
"lng_profile_view_discussion" = "View discussion";
|
||||
"lng_profile_join_channel" = "Join Channel";
|
||||
"lng_profile_join_group" = "Join Group";
|
||||
"lng_profile_delete_and_exit" = "Leave";
|
||||
@@ -1319,6 +1320,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_message_ph" = "Write a message...";
|
||||
"lng_broadcast_ph" = "Broadcast a message...";
|
||||
"lng_broadcast_silent_ph" = "Silent broadcast...";
|
||||
"lng_send_anonymous_ph" = "Send anonymously...";
|
||||
"lng_record_cancel" = "Release outside this field to cancel";
|
||||
"lng_will_be_notified" = "Members will be notified when you post";
|
||||
"lng_wont_be_notified" = "Members will not be notified when you post";
|
||||
@@ -1330,7 +1332,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_restart_button" = "Restart";
|
||||
"lng_channel_mute" = "Mute";
|
||||
"lng_channel_unmute" = "Unmute";
|
||||
"lng_channel_discuss" = "Discuss";
|
||||
"lng_saved_messages" = "Saved Messages";
|
||||
"lng_saved_short" = "Save";
|
||||
"lng_saved_forward_here" = "Forward messages here for quick access";
|
||||
@@ -1344,6 +1345,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_scheduled_send_now_many#one" = "Send {count} message now?";
|
||||
"lng_scheduled_send_now_many#other" = "Send {count} messages now?";
|
||||
|
||||
"lng_replies_view#one" = "View {count} Reply";
|
||||
"lng_replies_view#other" = "View {count} Replies";
|
||||
"lng_replies_view_thread" = "View Thread";
|
||||
"lng_replies_header#one" = "{count} reply";
|
||||
"lng_replies_header#other" = "{count} replies";
|
||||
"lng_replies_header_none" = "Replies";
|
||||
"lng_comments_header#one" = "{count} comment";
|
||||
"lng_comments_header#other" = "{count} comments";
|
||||
"lng_comments_header_none" = "Comments";
|
||||
"lng_comments_open_count#one" = "{count} comment";
|
||||
"lng_comments_open_count#other" = "{count} comments";
|
||||
"lng_comments_open_none" = "Leave a comment";
|
||||
"lng_replies_view_original" = "View in chat";
|
||||
"lng_replies_messages" = "Replies";
|
||||
"lng_replies_discussion_started" = "Discussion started";
|
||||
"lng_replies_no_comments" = "No comments here yet...";
|
||||
|
||||
"lng_archived_name" = "Archived chats";
|
||||
"lng_archived_add" = "Archive";
|
||||
"lng_archived_remove" = "Unarchive";
|
||||
@@ -1439,6 +1457,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_unpin_from_top" = "Unpin from top";
|
||||
"lng_context_mark_unread" = "Mark as unread";
|
||||
"lng_context_mark_read" = "Mark as read";
|
||||
"lng_context_mark_read_sure" = "Are you sure you want to mark all chats from this folder as read?";
|
||||
"lng_context_mark_read_all" = "Mark all chats as read";
|
||||
"lng_context_mark_read_all_sure" = "Are you sure you want to mark all chats as read?";
|
||||
"lng_context_archive_expand" = "Expand";
|
||||
"lng_context_archive_collapse" = "Collapse";
|
||||
"lng_context_archive_to_menu" = "Move to main menu";
|
||||
@@ -1821,6 +1842,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_group_invite" = "Add users";
|
||||
"lng_rights_group_pin" = "Pin messages";
|
||||
"lng_rights_group_delete" = "Delete messages";
|
||||
"lng_rights_group_anonymous" = "Remain Anonymous";
|
||||
"lng_rights_add_admins" = "Add new admins";
|
||||
"lng_rights_chat_read" = "Read messages";
|
||||
"lng_rights_chat_send_text" = "Send messages";
|
||||
@@ -1853,6 +1875,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_transfer_done_group" = "{user} is now the owner of the group.";
|
||||
"lng_rights_transfer_done_channel" = "{user} is now the owner of the channel.";
|
||||
|
||||
"lng_bots_password_confirm_check_about" = "You can finish this action only if you have:";
|
||||
"lng_bots_password_confirm_title" = "Two-step verification";
|
||||
"lng_bots_password_confirm_description" = "Please enter your password to confirm the action.";
|
||||
|
||||
"lng_restricted_send_message" = "The admins of this group restricted you from writing here.";
|
||||
"lng_restricted_send_media" = "The admins of this group restricted you from posting media content here.";
|
||||
"lng_restricted_send_stickers" = "The admins of this group restricted you from posting stickers here.";
|
||||
@@ -2245,6 +2271,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_language_not_ready_link" = "translations platform";
|
||||
|
||||
"lng_launch_exe_warning" = "This file has a {extension} extension.\nAre you sure you want to run it?";
|
||||
"lng_launch_svg_warning" = "Opening this file can potentially expose your IP address to its sender. Continue?";
|
||||
"lng_launch_exe_sure" = "Run";
|
||||
"lng_launch_exe_dont_ask" = "Don't ask me again";
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.
|
||||
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
|
||||
|
||||
chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
|
||||
channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull;
|
||||
channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull;
|
||||
|
||||
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
|
||||
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
|
||||
@@ -141,8 +141,8 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
|
||||
chatPhoto#d20b9f3c flags:# has_video:flags.0?true photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
|
||||
|
||||
messageEmpty#83e5de54 id:int = Message;
|
||||
message#452c0e65 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
|
||||
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
|
||||
message#58ae39c9 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
|
||||
messageService#286fa604 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction = Message;
|
||||
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
|
||||
@@ -192,6 +192,7 @@ photoSizeEmpty#e17e23c type:string = PhotoSize;
|
||||
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
|
||||
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
|
||||
photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
|
||||
photoSizeProgressive#5aa86a51 type:string location:FileLocation w:int h:int sizes:Vector<int> = PhotoSize;
|
||||
|
||||
geoPointEmpty#1117dd5f = GeoPoint;
|
||||
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
|
||||
@@ -231,8 +232,6 @@ contact#f911c994 user_id:int mutual:Bool = Contact;
|
||||
|
||||
importedContact#d0028438 user_id:int client_id:long = ImportedContact;
|
||||
|
||||
contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
|
||||
|
||||
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
|
||||
|
||||
contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
|
||||
@@ -240,8 +239,8 @@ contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector
|
||||
|
||||
contacts.importedContacts#77d01c3b imported:Vector<ImportedContact> popular_invites:Vector<PopularContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts;
|
||||
|
||||
contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
|
||||
contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
|
||||
contacts.blocked#ade1591 blocked:Vector<PeerBlocked> chats:Vector<Chat> users:Vector<User> = contacts.Blocked;
|
||||
contacts.blockedSlice#e1664194 count:int blocked:Vector<PeerBlocked> chats:Vector<Chat> users:Vector<User> = contacts.Blocked;
|
||||
|
||||
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
|
||||
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
|
||||
@@ -292,7 +291,6 @@ updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update;
|
||||
updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update;
|
||||
updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update;
|
||||
updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
|
||||
updateUserBlocked#80ece81a user_id:int blocked:Bool = Update;
|
||||
updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
|
||||
updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update;
|
||||
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
|
||||
@@ -358,6 +356,11 @@ updateDialogFilterOrder#a5d72105 order:Vector<int> = Update;
|
||||
updateDialogFilters#3504914f = Update;
|
||||
updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update;
|
||||
updateChannelParticipant#65d2b464 flags:# channel_id:int date:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant qts:int = Update;
|
||||
updateChannelMessageForwards#6e8a84df channel_id:int id:int forwards:int = Update;
|
||||
updateReadChannelDiscussionInbox#1cc7de54 flags:# channel_id:int top_msg_id:int read_max_id:int broadcast_id:flags.0?int broadcast_post:flags.0?int = Update;
|
||||
updateReadChannelDiscussionOutbox#4638a26c channel_id:int top_msg_id:int read_max_id:int = Update;
|
||||
updatePeerBlocked#246a4b22 peer_id:Peer blocked:Bool = Update;
|
||||
updateChannelUserTyping#ff2abe9f flags:# channel_id:int top_msg_id:flags.0?int user_id:int action:SendMessageAction = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@@ -367,8 +370,8 @@ updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_mess
|
||||
updates.differenceTooLong#4afe8f6d pts:int = updates.Difference;
|
||||
|
||||
updatesTooLong#e317af7e = Updates;
|
||||
updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
|
||||
updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
|
||||
updateShortMessage#2296d2c8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> = Updates;
|
||||
updateShortChatMessage#402d5dbb flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> = Updates;
|
||||
updateShort#78d4dec1 update:Update date:int = Updates;
|
||||
updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
|
||||
updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
|
||||
@@ -547,7 +550,7 @@ botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = Bo
|
||||
|
||||
keyboardButton#a2fa4880 text:string = KeyboardButton;
|
||||
keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
|
||||
keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
|
||||
keyboardButtonCallback#35bbdb6b flags:# requires_password:flags.0?true text:string data:bytes = KeyboardButton;
|
||||
keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
|
||||
keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
|
||||
keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
|
||||
@@ -601,7 +604,7 @@ channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:
|
||||
|
||||
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
|
||||
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
|
||||
channelParticipantCreator#808d15a4 flags:# user_id:int rank:flags.0?string = ChannelParticipant;
|
||||
channelParticipantCreator#447dca4b flags:# user_id:int admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant;
|
||||
channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
|
||||
channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
|
||||
|
||||
@@ -648,7 +651,7 @@ messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_off
|
||||
|
||||
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
|
||||
|
||||
messageFwdHeader#353a686b flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader;
|
||||
messageFwdHeader#5f777dce flags:# from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader;
|
||||
|
||||
auth.codeTypeSms#72a3158c = auth.CodeType;
|
||||
auth.codeTypeCall#741cd3e3 = auth.CodeType;
|
||||
@@ -1029,7 +1032,7 @@ chatOnlines#f041e250 onlines:int = ChatOnlines;
|
||||
|
||||
statsURL#47a971e0 url:string = StatsURL;
|
||||
|
||||
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights;
|
||||
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true = ChatAdminRights;
|
||||
|
||||
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
|
||||
|
||||
@@ -1150,6 +1153,27 @@ stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAnd
|
||||
|
||||
globalPrivacySettings#bea2f424 flags:# archive_and_mute_new_noncontact_peers:flags.0?Bool = GlobalPrivacySettings;
|
||||
|
||||
help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector<string> patterns:flags.1?Vector<string> = help.CountryCode;
|
||||
|
||||
help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector<help.CountryCode> = help.Country;
|
||||
|
||||
help.countriesListNotModified#93cc1f32 = help.CountriesList;
|
||||
help.countriesList#87d0759e countries:Vector<help.Country> hash:int = help.CountriesList;
|
||||
|
||||
messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews;
|
||||
|
||||
messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> users:Vector<User> = messages.MessageViews;
|
||||
|
||||
stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats;
|
||||
|
||||
messages.discussionMessage#f5dd8f9d flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
|
||||
|
||||
messageReplyHeader#a6d57763 flags:# reply_to_msg_id:int reply_to_peer_id:flags.0?Peer reply_to_top_id:flags.1?int = MessageReplyHeader;
|
||||
|
||||
messageReplies#4128faac flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?int max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;
|
||||
|
||||
peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@@ -1257,8 +1281,8 @@ contacts.getContacts#c023849f hash:int = contacts.Contacts;
|
||||
contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts;
|
||||
contacts.deleteContacts#96a0e00 id:Vector<InputUser> = Updates;
|
||||
contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool;
|
||||
contacts.block#332b49fc id:InputUser = Bool;
|
||||
contacts.unblock#e54100bd id:InputUser = Bool;
|
||||
contacts.block#68cc1411 id:InputPeer = Bool;
|
||||
contacts.unblock#bea65d50 id:InputPeer = Bool;
|
||||
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
|
||||
contacts.search#11f812d8 q:string limit:int = contacts.Found;
|
||||
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
|
||||
@@ -1270,19 +1294,20 @@ contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
|
||||
contacts.addContact#e8f463d0 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string = Updates;
|
||||
contacts.acceptContact#f831a20f id:InputUser = Updates;
|
||||
contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates;
|
||||
contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates;
|
||||
|
||||
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
|
||||
messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
|
||||
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.search#4e17810b flags:# peer:InputPeer q:string from_id:flags.0?InputUser top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
|
||||
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
|
||||
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
|
||||
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
||||
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
|
||||
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
|
||||
messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
|
||||
messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
|
||||
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
|
||||
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
|
||||
messages.reportSpam#cf1592db peer:InputPeer = Bool;
|
||||
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
|
||||
messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool;
|
||||
@@ -1299,8 +1324,8 @@ messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerp
|
||||
messages.discardEncryption#edd923c5 chat_id:int = Bool;
|
||||
messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
|
||||
messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
|
||||
messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
|
||||
messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
|
||||
messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
|
||||
messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
|
||||
messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
|
||||
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
|
||||
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
|
||||
@@ -1315,10 +1340,10 @@ messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet
|
||||
messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult;
|
||||
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
|
||||
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
|
||||
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
|
||||
messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector<int> increment:Bool = messages.MessageViews;
|
||||
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
|
||||
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
|
||||
messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
messages.searchGlobal#4bc6589a flags:# folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
|
||||
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
|
||||
messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
|
||||
@@ -1329,7 +1354,7 @@ messages.sendInlineBotResult#220815b0 flags:# silent:flags.5?true background:fla
|
||||
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
||||
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
|
||||
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
|
||||
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
|
||||
messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer;
|
||||
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
|
||||
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
|
||||
messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
|
||||
@@ -1394,6 +1419,9 @@ messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
|
||||
messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
|
||||
messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
|
||||
messages.getOldFeaturedStickers#5fe7025b offset:int limit:int hash:int = messages.FeaturedStickers;
|
||||
messages.getReplies#24b581ba peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage;
|
||||
messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@@ -1434,6 +1462,7 @@ help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<Mess
|
||||
help.getPromoData#c0977421 = help.PromoData;
|
||||
help.hidePromoData#1e251c95 peer:InputPeer = Bool;
|
||||
help.dismissSuggestion#77fa99f suggestion:string = Bool;
|
||||
help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList;
|
||||
|
||||
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
|
||||
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
|
||||
@@ -1454,7 +1483,7 @@ channels.joinChannel#24b524c5 channel:InputChannel = Updates;
|
||||
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
|
||||
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
|
||||
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
|
||||
channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
|
||||
channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink;
|
||||
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats;
|
||||
channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates;
|
||||
@@ -1511,5 +1540,7 @@ folders.deleteFolder#1c295881 folder_id:int = Updates;
|
||||
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
|
||||
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
|
||||
stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats;
|
||||
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
|
||||
|
||||
// LAYER 117
|
||||
// LAYER 119
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.3.2.0" />
|
||||
Version="2.4.4.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,3,2,0
|
||||
PRODUCTVERSION 2,3,2,0
|
||||
FILEVERSION 2,4,4,0
|
||||
PRODUCTVERSION 2,4,4,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "2.3.2.0"
|
||||
VALUE "FileVersion", "2.4.4.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.3.2.0"
|
||||
VALUE "ProductVersion", "2.4.4.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,3,2,0
|
||||
PRODUCTVERSION 2,3,2,0
|
||||
FILEVERSION 2,4,4,0
|
||||
PRODUCTVERSION 2,4,4,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", "2.3.2.0"
|
||||
VALUE "FileVersion", "2.4.4.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.3.2.0"
|
||||
VALUE "ProductVersion", "2.4.4.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
166
Telegram/SourceFiles/api/api_authorizations.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_authorizations.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "core/changelogs.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto TestApiId = 17349;
|
||||
constexpr auto DesktopApiId = 2040;
|
||||
|
||||
Authorizations::Entry ParseEntry(const MTPDauthorization &data) {
|
||||
auto result = Authorizations::Entry();
|
||||
|
||||
result.hash = data.is_current() ? 0 : data.vhash().v;
|
||||
result.incomplete = data.is_password_pending();
|
||||
|
||||
const auto apiId = data.vapi_id().v;
|
||||
const auto isTest = (apiId == TestApiId);
|
||||
const auto isDesktop = (apiId == DesktopApiId) || isTest;
|
||||
|
||||
const auto appName = isDesktop
|
||||
? QString("Telegram Desktop%1").arg(isTest ? " (GitHub)" : QString())
|
||||
: qs(data.vapp_name());// +qsl(" for ") + qs(d.vplatform());
|
||||
const auto appVer = [&] {
|
||||
const auto version = qs(data.vapp_version());
|
||||
if (isDesktop) {
|
||||
const auto verInt = version.toInt();
|
||||
if (version == QString::number(verInt)) {
|
||||
return Core::FormatVersionDisplay(verInt);
|
||||
}
|
||||
} else {
|
||||
if (const auto index = version.indexOf('('); index >= 0) {
|
||||
return version.mid(index);
|
||||
}
|
||||
}
|
||||
return version;
|
||||
}();
|
||||
|
||||
result.name = QString("%1%2")
|
||||
.arg(appName)
|
||||
.arg(appVer.isEmpty() ? QString() : (' ' + appVer));
|
||||
|
||||
const auto country = qs(data.vcountry());
|
||||
const auto platform = qs(data.vplatform());
|
||||
//const auto &countries = countriesByISO2();
|
||||
//const auto j = countries.constFind(country);
|
||||
//if (j != countries.cend()) {
|
||||
// country = QString::fromUtf8(j.value()->name);
|
||||
//}
|
||||
|
||||
result.activeTime = data.vdate_active().v
|
||||
? data.vdate_active().v
|
||||
: data.vdate_created().v;
|
||||
result.info = QString("%1, %2%3")
|
||||
.arg(qs(data.vdevice_model()))
|
||||
.arg(platform.isEmpty() ? QString() : platform + ' ')
|
||||
.arg(qs(data.vsystem_version()));
|
||||
result.ip = qs(data.vip())
|
||||
+ (country.isEmpty()
|
||||
? QString()
|
||||
: QString::fromUtf8(" \xe2\x80\x93 ") + country);
|
||||
if (!result.hash) {
|
||||
result.active = tr::lng_status_online(tr::now);
|
||||
} else {
|
||||
const auto now = QDateTime::currentDateTime();
|
||||
const auto lastTime = base::unixtime::parse(result.activeTime);
|
||||
const auto nowDate = now.date();
|
||||
const auto lastDate = lastTime.date();
|
||||
if (lastDate == nowDate) {
|
||||
result.active = lastTime.toString(cTimeFormat());
|
||||
} else if (lastDate.year() == nowDate.year()
|
||||
&& lastDate.weekNumber() == nowDate.weekNumber()) {
|
||||
result.active = langDayOfWeek(lastDate);
|
||||
} else {
|
||||
result.active = lastDate.toString(qsl("d.MM.yy"));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Authorizations::Authorizations(not_null<ApiWrap*> api)
|
||||
: _api(&api->instance()) {
|
||||
}
|
||||
|
||||
void Authorizations::reload() {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
_requestId = _api.request(MTPaccount_GetAuthorizations(
|
||||
)).done([=](const MTPaccount_Authorizations &result) {
|
||||
_requestId = 0;
|
||||
_lastReceived = crl::now();
|
||||
result.match([&](const MTPDaccount_authorizations &auths) {
|
||||
_list = (
|
||||
auths.vauthorizations().v
|
||||
) | ranges::view::transform([](const MTPAuthorization &d) {
|
||||
return ParseEntry(d.c_authorization());
|
||||
}) | ranges::to<List>;
|
||||
_listChanges.fire({});
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Authorizations::cancelCurrentRequest() {
|
||||
_api.request(base::take(_requestId)).cancel();
|
||||
}
|
||||
|
||||
void Authorizations::requestTerminate(
|
||||
Fn<void(const MTPBool &result)> &&done,
|
||||
Fn<void(const RPCError &error)> &&fail,
|
||||
std::optional<uint64> hash) {
|
||||
auto request = hash
|
||||
? MTPaccount_ResetAuthorization(MTP_long(*hash))
|
||||
: MTPaccount_ResetAuthorization();
|
||||
_api.request(std::move(request))
|
||||
.done(std::move(done))
|
||||
.fail(std::move(fail))
|
||||
.send();
|
||||
}
|
||||
|
||||
Authorizations::List Authorizations::list() const {
|
||||
return _list;
|
||||
}
|
||||
|
||||
auto Authorizations::listChanges() const
|
||||
-> rpl::producer<Authorizations::List> {
|
||||
return rpl::single(
|
||||
list()
|
||||
) | rpl::then(
|
||||
_listChanges.events() | rpl::map([=] { return list(); }));
|
||||
}
|
||||
|
||||
rpl::producer<int> Authorizations::totalChanges() const {
|
||||
return rpl::single(
|
||||
total()
|
||||
) | rpl::then(
|
||||
_listChanges.events() | rpl::map([=] { return total(); }));
|
||||
}
|
||||
|
||||
int Authorizations::total() const {
|
||||
return ranges::count_if(
|
||||
_list,
|
||||
ranges::not_fn(&Entry::incomplete));
|
||||
}
|
||||
|
||||
crl::time Authorizations::lastReceivedTime() {
|
||||
return _lastReceived;
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
54
Telegram/SourceFiles/api/api_authorizations.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
|
||||
namespace Api {
|
||||
|
||||
class Authorizations final {
|
||||
public:
|
||||
explicit Authorizations(not_null<ApiWrap*> api);
|
||||
|
||||
struct Entry {
|
||||
uint64 hash = 0;
|
||||
|
||||
bool incomplete = false;
|
||||
TimeId activeTime = 0;
|
||||
QString name, active, info, ip;
|
||||
};
|
||||
using List = std::vector<Entry>;
|
||||
|
||||
void reload();
|
||||
void cancelCurrentRequest();
|
||||
void requestTerminate(
|
||||
Fn<void(const MTPBool &result)> &&done,
|
||||
Fn<void(const RPCError &error)> &&fail,
|
||||
std::optional<uint64> hash = std::nullopt);
|
||||
|
||||
[[nodiscard]] crl::time lastReceivedTime();
|
||||
|
||||
[[nodiscard]] List list() const;
|
||||
[[nodiscard]] rpl::producer<List> listChanges() const;
|
||||
[[nodiscard]] int total() const;
|
||||
[[nodiscard]] rpl::producer<int> totalChanges() const;
|
||||
|
||||
private:
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
List _list;
|
||||
rpl::event_stream<> _listChanges;
|
||||
|
||||
crl::time _lastReceived = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -8,9 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_bot.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "api/api_send_progress.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/share_box.h"
|
||||
#include "boxes/passcode_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_peer.h"
|
||||
@@ -20,10 +23,129 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_item_components.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
void SendBotCallbackData(
|
||||
not_null<HistoryItem*> item,
|
||||
int row,
|
||||
int column,
|
||||
std::optional<MTPInputCheckPasswordSRP> password = std::nullopt,
|
||||
Fn<void(const RPCError &)> handleError = nullptr) {
|
||||
if (!IsServerMsgId(item->id)) {
|
||||
return;
|
||||
}
|
||||
const auto history = item->history();
|
||||
const auto session = &history->session();
|
||||
const auto owner = &history->owner();
|
||||
const auto api = &session->api();
|
||||
const auto bot = item->getMessageBot();
|
||||
const auto fullId = item->fullId();
|
||||
const auto getButton = [=] {
|
||||
return HistoryMessageMarkupButton::Get(
|
||||
owner,
|
||||
fullId,
|
||||
row,
|
||||
column);
|
||||
};
|
||||
const auto button = getButton();
|
||||
if (!button || button->requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
using ButtonType = HistoryMessageMarkupButton::Type;
|
||||
const auto isGame = (button->type == ButtonType::Game);
|
||||
|
||||
auto flags = MTPmessages_GetBotCallbackAnswer::Flags(0);
|
||||
QByteArray sendData;
|
||||
if (isGame) {
|
||||
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_game;
|
||||
} else if (button->type == ButtonType::Callback
|
||||
|| button->type == ButtonType::CallbackWithPassword) {
|
||||
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data;
|
||||
sendData = button->data;
|
||||
}
|
||||
const auto withPassword = password.has_value();
|
||||
if (withPassword) {
|
||||
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_password;
|
||||
}
|
||||
button->requestId = api->request(MTPmessages_GetBotCallbackAnswer(
|
||||
MTP_flags(flags),
|
||||
history->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTP_bytes(sendData),
|
||||
password.value_or(MTP_inputCheckPasswordEmpty())
|
||||
)).done([=](const MTPmessages_BotCallbackAnswer &result) {
|
||||
const auto item = owner->message(fullId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
if (const auto button = getButton()) {
|
||||
button->requestId = 0;
|
||||
owner->requestItemRepaint(item);
|
||||
}
|
||||
result.match([&](const MTPDmessages_botCallbackAnswer &data) {
|
||||
if (const auto message = data.vmessage()) {
|
||||
if (data.is_alert()) {
|
||||
Ui::show(Box<InformBox>(qs(*message)));
|
||||
} else {
|
||||
if (withPassword) {
|
||||
Ui::hideLayer();
|
||||
}
|
||||
Ui::Toast::Show(qs(*message));
|
||||
}
|
||||
} else if (const auto url = data.vurl()) {
|
||||
const auto link = qs(*url);
|
||||
if (!isGame) {
|
||||
UrlClickHandler::Open(link);
|
||||
return;
|
||||
}
|
||||
const auto scoreLink = AppendShareGameScoreUrl(
|
||||
session,
|
||||
link,
|
||||
item->fullId());
|
||||
BotGameUrlClickHandler(bot, scoreLink).onClick({});
|
||||
session->sendProgressManager().update(
|
||||
history,
|
||||
Api::SendProgressType::PlayGame);
|
||||
} else if (withPassword) {
|
||||
Ui::hideLayer();
|
||||
}
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
const auto item = owner->message(fullId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
// Show error?
|
||||
if (const auto button = getButton()) {
|
||||
button->requestId = 0;
|
||||
owner->requestItemRepaint(item);
|
||||
}
|
||||
if (handleError) {
|
||||
handleError(error);
|
||||
}
|
||||
}).send();
|
||||
|
||||
session->changes().messageUpdated(
|
||||
item,
|
||||
Data::MessageUpdate::Flag::BotCallbackSent
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SendBotCallbackData(
|
||||
not_null<HistoryItem*> item,
|
||||
int row,
|
||||
int column) {
|
||||
SendBotCallbackData(item, row, column, MTP_inputCheckPasswordEmpty());
|
||||
}
|
||||
|
||||
void SendBotCallbackDataWithPassword(
|
||||
not_null<HistoryItem*> item,
|
||||
int row,
|
||||
int column) {
|
||||
@@ -44,74 +166,63 @@ void SendBotCallbackData(
|
||||
column);
|
||||
};
|
||||
const auto button = getButton();
|
||||
if (!button) {
|
||||
if (!button || button->requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
using ButtonType = HistoryMessageMarkupButton::Type;
|
||||
const auto isGame = (button->type == ButtonType::Game);
|
||||
|
||||
auto flags = MTPmessages_GetBotCallbackAnswer::Flags(0);
|
||||
QByteArray sendData;
|
||||
if (isGame) {
|
||||
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_game;
|
||||
} else if (button->type == ButtonType::Callback) {
|
||||
flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data;
|
||||
sendData = button->data;
|
||||
}
|
||||
button->requestId = api->request(MTPmessages_GetBotCallbackAnswer(
|
||||
MTP_flags(flags),
|
||||
history->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTP_bytes(sendData)
|
||||
)).done([=](const MTPmessages_BotCallbackAnswer &result) {
|
||||
const auto item = owner->message(fullId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
if (const auto button = getButton()) {
|
||||
button->requestId = 0;
|
||||
owner->requestItemRepaint(item);
|
||||
}
|
||||
result.match([&](const MTPDmessages_botCallbackAnswer &data) {
|
||||
if (const auto message = data.vmessage()) {
|
||||
if (data.is_alert()) {
|
||||
Ui::show(Box<InformBox>(qs(*message)));
|
||||
} else {
|
||||
Ui::Toast::Show(qs(*message));
|
||||
api->reloadPasswordState();
|
||||
SendBotCallbackData(item, row, column, MTP_inputCheckPasswordEmpty(), [=](const RPCError &error) {
|
||||
auto box = PrePasswordErrorBox(
|
||||
error,
|
||||
session,
|
||||
tr::lng_bots_password_confirm_check_about(
|
||||
tr::now,
|
||||
Ui::Text::WithEntities));
|
||||
if (box) {
|
||||
Ui::show(std::move(box));
|
||||
} else {
|
||||
auto lifetime = std::make_shared<rpl::lifetime>();
|
||||
button->requestId = -1;
|
||||
api->passwordState(
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) mutable {
|
||||
if (lifetime) {
|
||||
base::take(lifetime)->destroy();
|
||||
}
|
||||
} else if (const auto url = data.vurl()) {
|
||||
const auto link = qs(*url);
|
||||
if (!isGame) {
|
||||
UrlClickHandler::Open(link);
|
||||
if (const auto button = getButton()) {
|
||||
if (button->requestId == -1) {
|
||||
button->requestId = 0;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
const auto scoreLink = AppendShareGameScoreUrl(
|
||||
session,
|
||||
link,
|
||||
item->fullId());
|
||||
BotGameUrlClickHandler(bot, scoreLink).onClick({});
|
||||
session->sendProgressManager().update(
|
||||
history,
|
||||
Api::SendProgressType::PlayGame);
|
||||
}
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
const auto item = owner->message(fullId);
|
||||
if (!item) {
|
||||
return;
|
||||
const auto box = std::make_shared<QPointer<PasscodeBox>>();
|
||||
auto fields = PasscodeBox::CloudFields::From(state);
|
||||
fields.customTitle = tr::lng_bots_password_confirm_title();
|
||||
fields.customDescription
|
||||
= tr::lng_bots_password_confirm_description(tr::now);
|
||||
fields.customSubmitButton = tr::lng_passcode_submit();
|
||||
fields.customCheckCallback = [=](
|
||||
const Core::CloudPasswordResult &result) {
|
||||
if (const auto button = getButton()) {
|
||||
if (button->requestId) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (const auto item = owner->message(fullId)) {
|
||||
SendBotCallbackData(item, row, column, result.result, [=](const RPCError &error) {
|
||||
if (*box) {
|
||||
(*box)->handleCustomCheckError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
*box = Ui::show(Box<PasscodeBox>(session, fields));
|
||||
}, *lifetime);
|
||||
}
|
||||
// Show error?
|
||||
if (const auto button = getButton()) {
|
||||
button->requestId = 0;
|
||||
owner->requestItemRepaint(item);
|
||||
}
|
||||
}).send();
|
||||
|
||||
session->changes().messageUpdated(
|
||||
item,
|
||||
Data::MessageUpdate::Flag::BotCallbackSent
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -16,4 +16,9 @@ void SendBotCallbackData(
|
||||
int row,
|
||||
int column);
|
||||
|
||||
void SendBotCallbackDataWithPassword(
|
||||
not_null<HistoryItem*> item,
|
||||
int row,
|
||||
int column);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -10,12 +10,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "history/history.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_user.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kCancelTypingActionTimeout = crl::time(5000);
|
||||
constexpr auto kSetMyActionForMs = 10 * crl::time(1000);
|
||||
constexpr auto kSendTypingsToOfflineFor = TimeId(30);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -27,7 +32,14 @@ SendProgressManager::SendProgressManager(not_null<Main::Session*> session)
|
||||
void SendProgressManager::cancel(
|
||||
not_null<History*> history,
|
||||
SendProgressType type) {
|
||||
const auto i = _requests.find({ history, type });
|
||||
cancel(history, 0, type);
|
||||
}
|
||||
|
||||
void SendProgressManager::cancel(
|
||||
not_null<History*> history,
|
||||
MsgId topMsgId,
|
||||
SendProgressType type) {
|
||||
const auto i = _requests.find(Key{ history, topMsgId, type });
|
||||
if (i != _requests.end()) {
|
||||
_session->api().request(i->second).cancel();
|
||||
_requests.erase(i);
|
||||
@@ -42,29 +54,61 @@ void SendProgressManager::cancelTyping(not_null<History*> history) {
|
||||
void SendProgressManager::update(
|
||||
not_null<History*> history,
|
||||
SendProgressType type,
|
||||
int32 progress) {
|
||||
int progress) {
|
||||
update(history, 0, type, progress);
|
||||
}
|
||||
|
||||
void SendProgressManager::update(
|
||||
not_null<History*> history,
|
||||
MsgId topMsgId,
|
||||
SendProgressType type,
|
||||
int progress) {
|
||||
const auto peer = history->peer;
|
||||
if (peer->isSelf() || (peer->isChannel() && !peer->isMegagroup())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto doing = (progress >= 0);
|
||||
if (history->mySendActionUpdated(type, doing)) {
|
||||
cancel(history, type);
|
||||
const auto key = Key{ history, topMsgId, type };
|
||||
if (updated(key, doing)) {
|
||||
cancel(history, topMsgId, type);
|
||||
if (doing) {
|
||||
send(history, type, progress);
|
||||
send(key, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendProgressManager::send(
|
||||
not_null<History*> history,
|
||||
SendProgressType type,
|
||||
int32 progress) {
|
||||
bool SendProgressManager::updated(const Key &key, bool doing) {
|
||||
const auto now = crl::now();
|
||||
const auto i = _updated.find(key);
|
||||
if (doing) {
|
||||
if (i == end(_updated)) {
|
||||
_updated.emplace(key, now + kSetMyActionForMs);
|
||||
} else if (i->second > now + (kSetMyActionForMs / 2)) {
|
||||
return false;
|
||||
} else {
|
||||
i->second = now + kSetMyActionForMs;
|
||||
}
|
||||
} else {
|
||||
if (i == end(_updated)) {
|
||||
return false;
|
||||
} else if (i->second <= now) {
|
||||
return false;
|
||||
} else {
|
||||
_updated.erase(i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SendProgressManager::send(const Key &key, int progress) {
|
||||
if (skipRequest(key)) {
|
||||
return;
|
||||
}
|
||||
using Type = SendProgressType;
|
||||
const auto action = [&]() -> MTPsendMessageAction {
|
||||
const auto p = MTP_int(progress);
|
||||
switch (type) {
|
||||
switch (key.type) {
|
||||
case Type::Typing: return MTP_sendMessageTypingAction();
|
||||
case Type::RecordVideo: return MTP_sendMessageRecordVideoAction();
|
||||
case Type::UploadVideo: return MTP_sendMessageUploadVideoAction(p);
|
||||
@@ -81,19 +125,36 @@ void SendProgressManager::send(
|
||||
}
|
||||
}();
|
||||
const auto requestId = _session->api().request(MTPmessages_SetTyping(
|
||||
history->peer->input,
|
||||
MTP_flags(key.topMsgId
|
||||
? MTPmessages_SetTyping::Flag::f_top_msg_id
|
||||
: MTPmessages_SetTyping::Flag(0)),
|
||||
key.history->peer->input,
|
||||
MTP_int(key.topMsgId),
|
||||
action
|
||||
)).done([=](const MTPBool &result, mtpRequestId requestId) {
|
||||
done(result, requestId);
|
||||
}).send();
|
||||
_requests.emplace(Key{ history, type }, requestId);
|
||||
_requests.emplace(key, requestId);
|
||||
|
||||
if (type == Type::Typing) {
|
||||
_stopTypingHistory = history;
|
||||
if (key.type == Type::Typing) {
|
||||
_stopTypingHistory = key.history;
|
||||
_stopTypingTimer.callOnce(kCancelTypingActionTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
bool SendProgressManager::skipRequest(const Key &key) const {
|
||||
const auto user = key.history->peer->asUser();
|
||||
if (!user) {
|
||||
return false;
|
||||
} else if (user->isSelf()) {
|
||||
return true;
|
||||
} else if (user->isBot() && !user->isSupport()) {
|
||||
return true;
|
||||
}
|
||||
const auto recently = base::unixtime::now() - kSendTypingsToOfflineFor;
|
||||
return !Data::OnlineTextActive(user->onlineTill, recently);
|
||||
}
|
||||
|
||||
void SendProgressManager::done(
|
||||
const MTPBool &result,
|
||||
mtpRequestId requestId) {
|
||||
|
||||
@@ -55,7 +55,16 @@ public:
|
||||
void update(
|
||||
not_null<History*> history,
|
||||
SendProgressType type,
|
||||
int32 progress = 0);
|
||||
int progress = 0);
|
||||
void update(
|
||||
not_null<History*> history,
|
||||
MsgId topMsgId,
|
||||
SendProgressType type,
|
||||
int progress = 0);
|
||||
void cancel(
|
||||
not_null<History*> history,
|
||||
MsgId topMsgId,
|
||||
SendProgressType type);
|
||||
void cancel(
|
||||
not_null<History*> history,
|
||||
SendProgressType type);
|
||||
@@ -64,22 +73,28 @@ public:
|
||||
private:
|
||||
struct Key {
|
||||
not_null<History*> history;
|
||||
MsgId topMsgId = 0;
|
||||
SendProgressType type = SendProgressType();
|
||||
|
||||
inline bool operator<(const Key &other) const {
|
||||
return (history < other.history)
|
||||
|| (history == other.history && type < other.type);
|
||||
|| (history == other.history && topMsgId < other.topMsgId)
|
||||
|| (history == other.history
|
||||
&& topMsgId == other.topMsgId
|
||||
&& type < other.type);
|
||||
}
|
||||
};
|
||||
|
||||
void send(
|
||||
not_null<History*> history,
|
||||
SendProgressType type,
|
||||
int32 progress);
|
||||
bool updated(const Key &key, bool doing);
|
||||
|
||||
void send(const Key &key, int progress);
|
||||
void done(const MTPBool &result, mtpRequestId requestId);
|
||||
|
||||
[[nodiscard]] bool skipRequest(const Key &key) const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
base::flat_map<Key, mtpRequestId> _requests;
|
||||
base::flat_map<Key, crl::time> _updated;
|
||||
base::Timer _stopTypingTimer;
|
||||
History *_stopTypingHistory = nullptr;
|
||||
|
||||
|
||||
@@ -39,10 +39,12 @@ void InnerFillMessagePostFlags(
|
||||
const Api::SendOptions &options,
|
||||
not_null<PeerData*> peer,
|
||||
MTPDmessage::Flags &flags) {
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
if (!channelPost) {
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
if (!anonymousPost) {
|
||||
flags |= MTPDmessage::Flag::f_from_id;
|
||||
return;
|
||||
} else if (peer->asMegagroup()) {
|
||||
return;
|
||||
}
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
// Don't display views and author of a new post when it's scheduled.
|
||||
@@ -79,18 +81,18 @@ void SendExistingMedia(
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (message.action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = message.action.options.silent
|
||||
|| (channelPost && session->data().notifySilentPosts(peer));
|
||||
|| (peer->isBroadcast() && session->data().notifySilentPosts(peer));
|
||||
InnerFillMessagePostFlags(message.action.options, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : session->userId();
|
||||
auto messagePostAuthor = channelPost ? session->user()->name : QString();
|
||||
auto messageFromId = anonymousPost ? 0 : session->userPeerId();
|
||||
auto messagePostAuthor = peer->isBroadcast() ? session->user()->name : QString();
|
||||
|
||||
auto caption = TextWithEntities{
|
||||
message.textWithTags.text,
|
||||
@@ -249,18 +251,19 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (message.action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto replyHeader = NewMessageReplyHeader(message.action);
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = message.action.options.silent
|
||||
|| (channelPost && session->data().notifySilentPosts(peer));
|
||||
|| (peer->isBroadcast() && session->data().notifySilentPosts(peer));
|
||||
InnerFillMessagePostFlags(message.action.options, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : session->userId();
|
||||
auto messagePostAuthor = channelPost ? session->user()->name : QString();
|
||||
auto messageFromId = anonymousPost ? 0 : session->userPeerId();
|
||||
auto messagePostAuthor = peer->isBroadcast() ? session->user()->name : QString();
|
||||
const auto replyTo = message.action.replyTo;
|
||||
|
||||
if (message.action.options.scheduled) {
|
||||
@@ -272,23 +275,27 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
|
||||
session->data().registerMessageRandomId(randomId, newId);
|
||||
|
||||
const auto views = 1;
|
||||
const auto forwards = 0;
|
||||
history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
MTP_int(messageFromId),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(history->peer->id),
|
||||
MTPMessageFwdHeader(),
|
||||
MTP_int(0),
|
||||
MTP_int(replyTo),
|
||||
MTPint(), // via_bot_id
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(
|
||||
message.action.options.scheduled)),
|
||||
MTP_string(),
|
||||
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
|
||||
MTPReplyMarkup(),
|
||||
MTP_vector<MTPMessageEntity>(),
|
||||
MTP_int(1),
|
||||
MTPint(),
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTPlong(),
|
||||
//MTPMessageReactions(),
|
||||
@@ -387,9 +394,10 @@ void SendConfirmedFile(
|
||||
| MTPDmessage::Flag::f_media;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
if (file->to.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
}
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto replyHeader = NewMessageReplyHeader(action);
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = file->to.options.silent;
|
||||
Api::FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
@@ -406,11 +414,13 @@ void SendConfirmedFile(
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
}
|
||||
|
||||
const auto messageFromId = channelPost ? 0 : session->userId();
|
||||
const auto messagePostAuthor = channelPost
|
||||
const auto messageFromId = anonymousPost ? 0 : session->userPeerId();
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? session->user()->name
|
||||
: QString();
|
||||
|
||||
const auto views = 1;
|
||||
const auto forwards = 0;
|
||||
if (file->type == SendMediaType::Photo) {
|
||||
const auto photoFlags = MTPDmessageMediaPhoto::Flag::f_photo | 0;
|
||||
const auto photo = MTP_messageMediaPhoto(
|
||||
@@ -421,18 +431,20 @@ void SendConfirmedFile(
|
||||
const auto mtpMessage = MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
MTP_int(messageFromId),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(file->to.peer),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(),
|
||||
MTP_int(file->to.replyTo),
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||
MTP_string(caption.text),
|
||||
photo,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTP_int(1),
|
||||
MTPint(),
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTP_long(groupId),
|
||||
//MTPMessageReactions(),
|
||||
@@ -457,18 +469,20 @@ void SendConfirmedFile(
|
||||
const auto mtpMessage = MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
MTP_int(messageFromId),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(file->to.peer),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(),
|
||||
MTP_int(file->to.replyTo),
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||
MTP_string(caption.text),
|
||||
document,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTP_int(1),
|
||||
MTPint(),
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTP_long(groupId),
|
||||
//MTPMessageReactions(),
|
||||
@@ -496,19 +510,21 @@ void SendConfirmedFile(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
MTP_int(messageFromId),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(file->to.peer),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(),
|
||||
MTP_int(file->to.replyTo),
|
||||
replyHeader,
|
||||
MTP_int(
|
||||
HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||
MTP_string(caption.text),
|
||||
document,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTP_int(1),
|
||||
MTPint(),
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTP_long(groupId),
|
||||
//MTPMessageReactions(),
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_updates.h"
|
||||
|
||||
#include "api/api_authorizations.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
@@ -62,6 +63,22 @@ enum class DataIsLoadedResult {
|
||||
Ok = 3,
|
||||
};
|
||||
|
||||
void ProcessScheduledMessageWithElapsedTime(
|
||||
not_null<Main::Session*> session,
|
||||
bool needToAdd,
|
||||
const MTPDmessage &data) {
|
||||
if (needToAdd && !data.is_from_scheduled()) {
|
||||
// If we still need to add a new message,
|
||||
// we should first check if this message is in
|
||||
// the list of scheduled messages.
|
||||
// This is necessary to correctly update the file reference.
|
||||
// Note that when a message is scheduled until online
|
||||
// while the recipient is already online, the server sends
|
||||
// an ordinary new message with skipped "from_scheduled" flag.
|
||||
session->data().scheduledMessages().checkEntitiesAndUpdate(data);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
|
||||
return qs(data.vtype()).startsWith(qstr("AUTH_KEY_DROP_"));
|
||||
}
|
||||
@@ -97,20 +114,9 @@ bool ForwardedInfoDataLoaded(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPMessageFwdHeader &header) {
|
||||
return header.match([&](const MTPDmessageFwdHeader &data) {
|
||||
if (const auto channelId = data.vchannel_id()) {
|
||||
if (!session->data().channelLoaded(channelId->v)) {
|
||||
return false;
|
||||
}
|
||||
if (const auto fromId = data.vfrom_id()) {
|
||||
const auto from = session->data().user(fromId->v);
|
||||
// Minimal loaded is fine in this case.
|
||||
if (from->loadedStatus == PeerData::NotLoaded) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (const auto fromId = data.vfrom_id()) {
|
||||
if (const auto fromId = data.vfrom_id()) {
|
||||
// Fully loaded is required in this case.
|
||||
if (!session->data().userLoaded(fromId->v)) {
|
||||
if (!session->data().peerLoaded(peerFromMTP(*fromId))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -145,7 +151,7 @@ DataIsLoadedResult AllDataLoadedForMessage(
|
||||
return message.match([&](const MTPDmessage &message) {
|
||||
if (const auto fromId = message.vfrom_id()) {
|
||||
if (!message.is_post()
|
||||
&& !session->data().userLoaded(fromId->v)) {
|
||||
&& !session->data().peerLoaded(peerFromMTP(*fromId))) {
|
||||
return DataIsLoadedResult::FromNotLoaded;
|
||||
}
|
||||
}
|
||||
@@ -168,7 +174,7 @@ DataIsLoadedResult AllDataLoadedForMessage(
|
||||
}, [&](const MTPDmessageService &message) {
|
||||
if (const auto fromId = message.vfrom_id()) {
|
||||
if (!message.is_post()
|
||||
&& !session->data().userLoaded(fromId->v)) {
|
||||
&& !session->data().peerLoaded(peerFromMTP(*fromId))) {
|
||||
return DataIsLoadedResult::FromNotLoaded;
|
||||
}
|
||||
}
|
||||
@@ -890,23 +896,26 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
const auto peerUserId = d.is_out()
|
||||
? d.vuser_id()
|
||||
: MTP_int(_session->userId());
|
||||
const auto fwd = d.vfwd_from();
|
||||
_session->data().addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
d.vid(),
|
||||
d.is_out() ? MTP_int(_session->userId()) : d.vuser_id(),
|
||||
MTP_peerUser(peerUserId),
|
||||
fwd ? (*fwd) : MTPMessageFwdHeader(),
|
||||
(d.is_out()
|
||||
? peerToMTP(_session->userPeerId())
|
||||
: MTP_peerUser(d.vuser_id())),
|
||||
MTP_peerUser(d.vuser_id()),
|
||||
d.vfwd_from() ? *d.vfwd_from() : MTPMessageFwdHeader(),
|
||||
MTP_int(d.vvia_bot_id().value_or_empty()),
|
||||
MTP_int(d.vreply_to_msg_id().value_or_empty()),
|
||||
d.vreply_to() ? *d.vreply_to() : MTPMessageReplyHeader(),
|
||||
d.vdate(),
|
||||
d.vmessage(),
|
||||
MTP_messageMediaEmpty(),
|
||||
MTPReplyMarkup(),
|
||||
MTP_vector<MTPMessageEntity>(d.ventities().value_or_empty()),
|
||||
MTPint(),
|
||||
MTPint(),
|
||||
MTPint(), // views
|
||||
MTPint(), // forwards
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTPstring(),
|
||||
MTPlong(),
|
||||
//MTPMessageReactions(),
|
||||
@@ -917,24 +926,26 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
|
||||
case mtpc_updateShortChatMessage: {
|
||||
const auto &d = updates.c_updateShortChatMessage();
|
||||
const auto flags = mtpCastFlags(d.vflags().v) | MTPDmessage::Flag::f_from_id;
|
||||
const auto fwd = d.vfwd_from();
|
||||
const auto flags = mtpCastFlags(d.vflags().v)
|
||||
| MTPDmessage::Flag::f_from_id;
|
||||
_session->data().addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
d.vid(),
|
||||
d.vfrom_id(),
|
||||
MTP_peerUser(d.vfrom_id()),
|
||||
MTP_peerChat(d.vchat_id()),
|
||||
fwd ? (*fwd) : MTPMessageFwdHeader(),
|
||||
d.vfwd_from() ? *d.vfwd_from() : MTPMessageFwdHeader(),
|
||||
MTP_int(d.vvia_bot_id().value_or_empty()),
|
||||
MTP_int(d.vreply_to_msg_id().value_or_empty()),
|
||||
d.vreply_to() ? *d.vreply_to() : MTPMessageReplyHeader(),
|
||||
d.vdate(),
|
||||
d.vmessage(),
|
||||
MTP_messageMediaEmpty(),
|
||||
MTPReplyMarkup(),
|
||||
MTP_vector<MTPMessageEntity>(d.ventities().value_or_empty()),
|
||||
MTPint(),
|
||||
MTPint(),
|
||||
MTPint(), // views
|
||||
MTPint(), // forwards
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTPstring(),
|
||||
MTPlong(),
|
||||
//MTPMessageReactions(),
|
||||
@@ -963,17 +974,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
||||
LOG(("Skipping message, because it is already in blocks!"));
|
||||
needToAdd = false;
|
||||
}
|
||||
if (needToAdd && !data.is_from_scheduled()) {
|
||||
// If we still need to add a new message,
|
||||
// we should first check if this message is in
|
||||
// the list of scheduled messages.
|
||||
// This is necessary to correctly update the file reference.
|
||||
// Note that when a message is scheduled until online
|
||||
// while the recipient is already online, the server sends
|
||||
// an ordinary new message with skipped "from_scheduled" flag.
|
||||
_session->data().scheduledMessages().checkEntitiesAndUpdate(
|
||||
data);
|
||||
}
|
||||
ProcessScheduledMessageWithElapsedTime(_session, needToAdd, data);
|
||||
}
|
||||
if (needToAdd) {
|
||||
_session->data().addNewMessage(
|
||||
@@ -1062,10 +1063,12 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
||||
auto &d = update.c_updateNewChannelMessage();
|
||||
auto needToAdd = true;
|
||||
if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview
|
||||
if (_session->data().checkEntitiesAndViewsUpdate(d.vmessage().c_message())) { // already in blocks
|
||||
const auto &data = d.vmessage().c_message();
|
||||
if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks
|
||||
LOG(("Skipping message, because it is already in blocks!"));
|
||||
needToAdd = false;
|
||||
}
|
||||
ProcessScheduledMessageWithElapsedTime(_session, needToAdd, data);
|
||||
}
|
||||
if (needToAdd) {
|
||||
_session->data().addNewMessage(
|
||||
@@ -1541,26 +1544,51 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
const auto user = session().data().userLoaded(d.vuser_id().v);
|
||||
if (history && user) {
|
||||
const auto when = requestingDifference() ? 0 : base::unixtime::now();
|
||||
session().data().registerSendAction(history, user, d.vaction(), when);
|
||||
session().data().registerSendAction(
|
||||
history,
|
||||
MsgId(),
|
||||
user,
|
||||
d.vaction(),
|
||||
when);
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateChatUserTyping: {
|
||||
auto &d = update.c_updateChatUserTyping();
|
||||
const auto history = [&]() -> History* {
|
||||
if (const auto chat = session().data().chatLoaded(d.vchat_id().v)) {
|
||||
return session().data().historyLoaded(chat->id);
|
||||
} else if (const auto channel = session().data().channelLoaded(d.vchat_id().v)) {
|
||||
return session().data().historyLoaded(channel->id);
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
const auto history = session().data().historyLoaded(
|
||||
peerFromChat(d.vchat_id()));
|
||||
const auto user = (d.vuser_id().v == session().userId())
|
||||
? nullptr
|
||||
: session().data().userLoaded(d.vuser_id().v);
|
||||
if (history && user) {
|
||||
const auto when = requestingDifference() ? 0 : base::unixtime::now();
|
||||
session().data().registerSendAction(history, user, d.vaction(), when);
|
||||
session().data().registerSendAction(
|
||||
history,
|
||||
MsgId(),
|
||||
user,
|
||||
d.vaction(),
|
||||
when);
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateChannelUserTyping: {
|
||||
const auto &d = update.c_updateChannelUserTyping();
|
||||
const auto history = session().data().historyLoaded(
|
||||
peerFromChannel(d.vchannel_id()));
|
||||
const auto user = (d.vuser_id().v == session().userId())
|
||||
? nullptr
|
||||
: session().data().userLoaded(d.vuser_id().v);
|
||||
if (history && user) {
|
||||
const auto when = requestingDifference()
|
||||
? 0
|
||||
: base::unixtime::now();
|
||||
const auto rootId = d.vtop_msg_id().value_or_empty();
|
||||
session().data().registerSendAction(
|
||||
history,
|
||||
rootId,
|
||||
user,
|
||||
d.vaction(),
|
||||
when);
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1731,10 +1759,10 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
Core::App().calls().handleUpdate(&session(), update);
|
||||
} break;
|
||||
|
||||
case mtpc_updateUserBlocked: {
|
||||
const auto &d = update.c_updateUserBlocked();
|
||||
if (const auto user = session().data().userLoaded(d.vuser_id().v)) {
|
||||
user->setIsBlocked(mtpIsTrue(d.vblocked()));
|
||||
case mtpc_updatePeerBlocked: {
|
||||
const auto &d = update.c_updatePeerBlocked();
|
||||
if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer_id()))) {
|
||||
peer->setIsBlocked(mtpIsTrue(d.vblocked()));
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1753,7 +1781,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
}
|
||||
} else {
|
||||
session().data().serviceNotification(text, d.vmedia());
|
||||
session().data().checkNewAuthorization();
|
||||
session().api().authorizations().reload();
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1912,12 +1940,54 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
} break;
|
||||
|
||||
case mtpc_updateChannelMessageViews: {
|
||||
auto &d = update.c_updateChannelMessageViews();
|
||||
if (auto item = session().data().message(d.vchannel_id().v, d.vid().v)) {
|
||||
const auto &d = update.c_updateChannelMessageViews();
|
||||
if (const auto item = session().data().message(d.vchannel_id().v, d.vid().v)) {
|
||||
item->setViewsCount(d.vviews().v);
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateChannelMessageForwards: {
|
||||
const auto &d = update.c_updateChannelMessageForwards();
|
||||
if (const auto item = session().data().message(d.vchannel_id().v, d.vid().v)) {
|
||||
item->setForwardsCount(d.vforwards().v);
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateReadChannelDiscussionInbox: {
|
||||
const auto &d = update.c_updateReadChannelDiscussionInbox();
|
||||
const auto channelId = d.vchannel_id().v;
|
||||
const auto msgId = d.vtop_msg_id().v;
|
||||
const auto readTillId = d.vread_max_id().v;
|
||||
const auto item = session().data().message(channelId, msgId);
|
||||
if (item) {
|
||||
item->setRepliesInboxReadTill(readTillId);
|
||||
if (const auto post = item->lookupDiscussionPostOriginal()) {
|
||||
post->setRepliesInboxReadTill(readTillId);
|
||||
}
|
||||
}
|
||||
if (const auto broadcastId = d.vbroadcast_id()) {
|
||||
if (const auto post = session().data().message(
|
||||
broadcastId->v,
|
||||
d.vbroadcast_post()->v)) {
|
||||
post->setRepliesInboxReadTill(readTillId);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateReadChannelDiscussionOutbox: {
|
||||
const auto &d = update.c_updateReadChannelDiscussionOutbox();
|
||||
const auto channelId = d.vchannel_id().v;
|
||||
const auto msgId = d.vtop_msg_id().v;
|
||||
const auto readTillId = d.vread_max_id().v;
|
||||
const auto item = session().data().message(channelId, msgId);
|
||||
if (item) {
|
||||
item->setRepliesOutboxReadTill(readTillId);
|
||||
if (const auto post = item->lookupDiscussionPostOriginal()) {
|
||||
post->setRepliesOutboxReadTill(readTillId);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateChannelAvailableMessages: {
|
||||
auto &d = update.c_updateChannelAvailableMessages();
|
||||
if (const auto channel = session().data().channelLoaded(d.vchannel_id().v)) {
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "apiwrap.h"
|
||||
|
||||
#include "api/api_authorizations.h"
|
||||
#include "api/api_hash.h"
|
||||
#include "api/api_media.h"
|
||||
#include "api/api_sending.h"
|
||||
@@ -158,19 +159,19 @@ std::optional<ApiWrap::Privacy::Key> ApiWrap::Privacy::KeyFromMTP(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedUsersSlice::Item::operator==(const Item &other) const {
|
||||
return (user == other.user) && (date == other.date);
|
||||
bool ApiWrap::BlockedPeersSlice::Item::operator==(const Item &other) const {
|
||||
return (peer == other.peer) && (date == other.date);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedUsersSlice::Item::operator!=(const Item &other) const {
|
||||
bool ApiWrap::BlockedPeersSlice::Item::operator!=(const Item &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedUsersSlice::operator==(const BlockedUsersSlice &other) const {
|
||||
bool ApiWrap::BlockedPeersSlice::operator==(const BlockedPeersSlice &other) const {
|
||||
return (total == other.total) && (list == other.list);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedUsersSlice::operator!=(const BlockedUsersSlice &other) const {
|
||||
bool ApiWrap::BlockedPeersSlice::operator!=(const BlockedPeersSlice &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
@@ -186,6 +187,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
//, _feedReadTimer([=] { readFeeds(); }) // #feed
|
||||
, _topPromotionTimer([=] { refreshTopPromotion(); })
|
||||
, _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); })
|
||||
, _authorizations(std::make_unique<Api::Authorizations>(this))
|
||||
, _selfDestruct(std::make_unique<Api::SelfDestruct>(this))
|
||||
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this))
|
||||
, _globalPrivacy(std::make_unique<Api::GlobalPrivacy>(this)) {
|
||||
@@ -683,17 +685,57 @@ void ApiWrap::finalizeMessageDataRequest(
|
||||
}
|
||||
}
|
||||
|
||||
QString ApiWrap::exportDirectMessageLink(not_null<HistoryItem*> item) {
|
||||
QString ApiWrap::exportDirectMessageLink(
|
||||
not_null<HistoryItem*> item,
|
||||
bool inRepliesContext) {
|
||||
Expects(item->history()->peer->isChannel());
|
||||
|
||||
const auto itemId = item->fullId();
|
||||
const auto channel = item->history()->peer->asChannel();
|
||||
const auto fallback = [&] {
|
||||
const auto base = channel->hasUsername()
|
||||
? channel->username
|
||||
: "c/" + QString::number(channel->bareId());
|
||||
const auto query = base + '/' + QString::number(item->id);
|
||||
if (channel->hasUsername() && !channel->isMegagroup()) {
|
||||
auto linkChannel = channel;
|
||||
auto linkItemId = item->id;
|
||||
auto linkCommentId = 0;
|
||||
auto linkThreadId = 0;
|
||||
if (inRepliesContext) {
|
||||
if (const auto rootId = item->replyToTop()) {
|
||||
const auto root = item->history()->owner().message(
|
||||
channel->bareId(),
|
||||
rootId);
|
||||
const auto sender = root
|
||||
? root->discussionPostOriginalSender()
|
||||
: nullptr;
|
||||
if (sender && sender->hasUsername()) {
|
||||
// Comment to a public channel.
|
||||
const auto forwarded = root->Get<HistoryMessageForwarded>();
|
||||
linkItemId = forwarded->savedFromMsgId;
|
||||
if (linkItemId) {
|
||||
linkChannel = sender;
|
||||
linkCommentId = item->id;
|
||||
} else {
|
||||
linkItemId = item->id;
|
||||
}
|
||||
} else {
|
||||
// Reply in a thread, maybe comment in a private channel.
|
||||
linkThreadId = rootId;
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto base = linkChannel->hasUsername()
|
||||
? linkChannel->username
|
||||
: "c/" + QString::number(linkChannel->bareId());
|
||||
const auto query = base
|
||||
+ '/'
|
||||
+ QString::number(linkItemId)
|
||||
+ (linkCommentId
|
||||
? "?comment=" + QString::number(linkCommentId)
|
||||
: linkThreadId
|
||||
? "?thread=" + QString::number(linkThreadId)
|
||||
: "");
|
||||
if (linkChannel->hasUsername()
|
||||
&& !linkChannel->isMegagroup()
|
||||
&& !linkCommentId
|
||||
&& !linkThreadId) {
|
||||
if (const auto media = item->media()) {
|
||||
if (const auto document = media->document()) {
|
||||
if (document->isVideoMessage()) {
|
||||
@@ -709,9 +751,11 @@ QString ApiWrap::exportDirectMessageLink(not_null<HistoryItem*> item) {
|
||||
? i->second
|
||||
: fallback();
|
||||
request(MTPchannels_ExportMessageLink(
|
||||
MTP_flags(inRepliesContext
|
||||
? MTPchannels_ExportMessageLink::Flag::f_thread
|
||||
: MTPchannels_ExportMessageLink::Flag(0)),
|
||||
channel->inputChannel,
|
||||
MTP_int(item->id),
|
||||
MTP_bool(false)
|
||||
MTP_int(item->id)
|
||||
)).done([=](const MTPExportedMessageLink &result) {
|
||||
const auto link = result.match([&](const auto &data) {
|
||||
return qs(data.vlink());
|
||||
@@ -1495,9 +1539,13 @@ void ApiWrap::applyLastParticipantsList(
|
||||
});
|
||||
const auto adminCanEdit = (p.type() == mtpc_channelParticipantAdmin)
|
||||
? p.c_channelParticipantAdmin().is_can_edit()
|
||||
: (p.type() == mtpc_channelParticipantCreator)
|
||||
? channel->amCreator()
|
||||
: false;
|
||||
const auto adminRights = (p.type() == mtpc_channelParticipantAdmin)
|
||||
? p.c_channelParticipantAdmin().vadmin_rights()
|
||||
: (p.type() == mtpc_channelParticipantCreator)
|
||||
? p.c_channelParticipantCreator().vadmin_rights()
|
||||
: emptyAdminRights;
|
||||
const auto restrictedRights = (p.type() == mtpc_channelParticipantBanned)
|
||||
? p.c_channelParticipantBanned().vbanned_rights()
|
||||
@@ -2003,64 +2051,66 @@ void ApiWrap::leaveChannel(not_null<ChannelData*> channel) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::blockUser(not_null<UserData*> user) {
|
||||
if (user->isBlocked()) {
|
||||
void ApiWrap::blockPeer(not_null<PeerData*> peer) {
|
||||
if (peer->isBlocked()) {
|
||||
session().changes().peerUpdated(
|
||||
user,
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
} else if (_blockRequests.find(user) == end(_blockRequests)) {
|
||||
const auto requestId = request(MTPcontacts_Block(user->inputUser)).done([this, user](const MTPBool &result) {
|
||||
_blockRequests.erase(user);
|
||||
user->setIsBlocked(true);
|
||||
if (_blockedUsersSlice) {
|
||||
_blockedUsersSlice->list.insert(
|
||||
_blockedUsersSlice->list.begin(),
|
||||
{ user, base::unixtime::now() });
|
||||
++_blockedUsersSlice->total;
|
||||
_blockedUsersChanges.fire_copy(*_blockedUsersSlice);
|
||||
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
|
||||
const auto requestId = request(MTPcontacts_Block(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(true);
|
||||
if (_blockedPeersSlice) {
|
||||
_blockedPeersSlice->list.insert(
|
||||
_blockedPeersSlice->list.begin(),
|
||||
{ peer, base::unixtime::now() });
|
||||
++_blockedPeersSlice->total;
|
||||
_blockedPeersChanges.fire_copy(*_blockedPeersSlice);
|
||||
}
|
||||
}).fail([this, user](const RPCError &error) {
|
||||
_blockRequests.erase(user);
|
||||
}).fail([=](const RPCError &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
|
||||
_blockRequests.emplace(user, requestId);
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::unblockUser(not_null<UserData*> user, Fn<void()> onDone) {
|
||||
if (!user->isBlocked()) {
|
||||
void ApiWrap::unblockPeer(not_null<PeerData*> peer, Fn<void()> onDone) {
|
||||
if (!peer->isBlocked()) {
|
||||
session().changes().peerUpdated(
|
||||
user,
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
return;
|
||||
} else if (_blockRequests.find(user) != end(_blockRequests)) {
|
||||
} else if (_blockRequests.find(peer) != end(_blockRequests)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = request(MTPcontacts_Unblock(
|
||||
user->inputUser
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(user);
|
||||
user->setIsBlocked(false);
|
||||
if (_blockedUsersSlice) {
|
||||
auto &list = _blockedUsersSlice->list;
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(false);
|
||||
if (_blockedPeersSlice) {
|
||||
auto &list = _blockedPeersSlice->list;
|
||||
for (auto i = list.begin(); i != list.end(); ++i) {
|
||||
if (i->user == user) {
|
||||
if (i->peer == peer) {
|
||||
list.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_blockedUsersSlice->total > list.size()) {
|
||||
--_blockedUsersSlice->total;
|
||||
if (_blockedPeersSlice->total > list.size()) {
|
||||
--_blockedPeersSlice->total;
|
||||
}
|
||||
_blockedUsersChanges.fire_copy(*_blockedUsersSlice);
|
||||
_blockedPeersChanges.fire_copy(*_blockedPeersSlice);
|
||||
}
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
}).fail([=](const RPCError &error) {
|
||||
_blockRequests.erase(user);
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
_blockRequests.emplace(user, requestId);
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::exportInviteLink(not_null<PeerData*> peer) {
|
||||
@@ -2203,7 +2253,7 @@ void ApiWrap::handlePrivacyChange(
|
||||
void ApiWrap::updatePrivacyLastSeens(const QVector<MTPPrivacyRule> &rules) {
|
||||
const auto now = base::unixtime::now();
|
||||
_session->data().enumerateUsers([&](UserData *user) {
|
||||
if (user->isSelf() || user->loadedStatus != PeerData::FullLoaded) {
|
||||
if (user->isSelf() || !user->isFullLoaded()) {
|
||||
return;
|
||||
}
|
||||
if (user->onlineTill <= 0) {
|
||||
@@ -2682,14 +2732,14 @@ void ApiWrap::requestFileReference(
|
||||
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87122
|
||||
const auto &origin = p.first;
|
||||
const auto &reference = p.second;
|
||||
const auto documentId = base::get_if<DocumentFileLocationId>(
|
||||
const auto documentId = std::get_if<DocumentFileLocationId>(
|
||||
&origin);
|
||||
if (documentId) {
|
||||
_session->data().document(
|
||||
documentId->id
|
||||
)->refreshFileReference(reference);
|
||||
}
|
||||
const auto photoId = base::get_if<PhotoFileLocationId>(&origin);
|
||||
const auto photoId = std::get_if<PhotoFileLocationId>(&origin);
|
||||
if (photoId) {
|
||||
_session->data().photo(
|
||||
photoId->id
|
||||
@@ -2748,7 +2798,7 @@ void ApiWrap::refreshFileReference(
|
||||
const auto fail = [&] {
|
||||
handler(UpdatedFileReferences());
|
||||
};
|
||||
origin.data.match([&](Data::FileOriginMessage data) {
|
||||
v::match(origin.data, [&](Data::FileOriginMessage data) {
|
||||
if (const auto item = _session->data().message(data)) {
|
||||
if (item->isScheduled()) {
|
||||
const auto &scheduled = _session->data().scheduledMessages();
|
||||
@@ -2824,7 +2874,7 @@ void ApiWrap::refreshFileReference(
|
||||
MTP_long(data.themeId),
|
||||
MTP_long(data.accessHash)),
|
||||
MTP_long(0)));
|
||||
}, [&](std::nullopt_t) {
|
||||
}, [&](v::null_t) {
|
||||
fail();
|
||||
});
|
||||
}
|
||||
@@ -3896,9 +3946,9 @@ void ApiWrap::forwardMessages(
|
||||
|
||||
histories.readInbox(history);
|
||||
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = action.options.silent
|
||||
|| (channelPost && _session->data().notifySilentPosts(peer));
|
||||
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
|
||||
|
||||
auto flags = MTPDmessage::Flags(0);
|
||||
auto clientFlags = MTPDmessage_ClientFlags();
|
||||
@@ -3915,7 +3965,6 @@ void ApiWrap::forwardMessages(
|
||||
}
|
||||
|
||||
auto forwardFrom = items.front()->history()->peer;
|
||||
auto currentGroupId = items.front()->groupId();
|
||||
auto ids = QVector<MTPint>();
|
||||
auto randomIds = QVector<MTPlong>();
|
||||
auto localIds = std::shared_ptr<base::flat_map<uint64, FullMsgId>>();
|
||||
@@ -3924,14 +3973,10 @@ void ApiWrap::forwardMessages(
|
||||
if (shared) {
|
||||
++shared->requestsLeft;
|
||||
}
|
||||
const auto finalFlags = sendFlags
|
||||
| (currentGroupId == MessageGroupId()
|
||||
? MTPmessages_ForwardMessages::Flag(0)
|
||||
: MTPmessages_ForwardMessages::Flag::f_grouped);
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_ForwardMessages(
|
||||
MTP_flags(finalFlags),
|
||||
MTP_flags(sendFlags),
|
||||
forwardFrom->input,
|
||||
MTP_vector<MTPint>(ids),
|
||||
MTP_vector<MTPlong>(randomIds),
|
||||
@@ -3973,10 +4018,10 @@ void ApiWrap::forwardMessages(
|
||||
peerToChannel(peer->id),
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto self = _session->user();
|
||||
const auto messageFromId = channelPost
|
||||
? UserId(0)
|
||||
: peerToUser(self->id);
|
||||
const auto messagePostAuthor = channelPost
|
||||
const auto messageFromId = anonymousPost
|
||||
? PeerId(0)
|
||||
: self->id;
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? self->name
|
||||
: QString();
|
||||
history->addNewLocalMessage(
|
||||
@@ -3996,11 +4041,9 @@ void ApiWrap::forwardMessages(
|
||||
}
|
||||
const auto newFrom = item->history()->peer;
|
||||
const auto newGroupId = item->groupId();
|
||||
if (forwardFrom != newFrom
|
||||
|| currentGroupId != newGroupId) {
|
||||
if (forwardFrom != newFrom) {
|
||||
sendAccumulated();
|
||||
forwardFrom = newFrom;
|
||||
currentGroupId = newGroupId;
|
||||
}
|
||||
ids.push_back(MTP_int(item->id));
|
||||
randomIds.push_back(MTP_long(randomId));
|
||||
@@ -4048,34 +4091,36 @@ void ApiWrap::sendSharedContact(
|
||||
const auto newId = FullMsgId(
|
||||
history->channelId(),
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
if (action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
}
|
||||
const auto replyHeader = NewMessageReplyHeader(action);
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
}
|
||||
const auto messageFromId = channelPost ? 0 : _session->userId();
|
||||
const auto messagePostAuthor = channelPost
|
||||
const auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? _session->user()->name
|
||||
: QString();
|
||||
const auto vcard = QString();
|
||||
const auto views = 1;
|
||||
const auto forwards = 0;
|
||||
const auto item = history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
MTP_int(messageFromId),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(peer->id),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(),
|
||||
MTP_int(action.replyTo),
|
||||
MTPint(), // via_bot_id
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(action.options.scheduled)),
|
||||
MTP_string(),
|
||||
MTP_messageMediaContact(
|
||||
@@ -4087,7 +4132,9 @@ void ApiWrap::sendSharedContact(
|
||||
MTPReplyMarkup(),
|
||||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(views),
|
||||
MTPint(),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTPlong(),
|
||||
//MTPMessageReactions(),
|
||||
@@ -4101,7 +4148,9 @@ void ApiWrap::sendSharedContact(
|
||||
MTP_string(lastName),
|
||||
MTP_string(vcard));
|
||||
auto options = action.options;
|
||||
options.silent = _session->data().notifySilentPosts(peer);
|
||||
if (_session->data().notifySilentPosts(peer)) {
|
||||
options.silent = true;
|
||||
}
|
||||
sendMedia(item, media, options);
|
||||
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
@@ -4309,9 +4358,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto sendFlags = MTPmessages_SendMessage::Flags(0);
|
||||
if (action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto replyHeader = NewMessageReplyHeader(action);
|
||||
MTPMessageMedia media = MTP_messageMediaEmpty();
|
||||
if (message.webPageId == CancelledWebPageId) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage;
|
||||
@@ -4323,9 +4373,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
MTP_int(page->pendingTill)));
|
||||
flags |= MTPDmessage::Flag::f_media;
|
||||
}
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = action.options.silent
|
||||
|| (channelPost && _session->data().notifySilentPosts(peer));
|
||||
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
|
||||
@@ -4345,8 +4395,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
history->clearCloudDraft();
|
||||
history->setSentDraftText(QString());
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : _session->userId();
|
||||
auto messagePostAuthor = channelPost
|
||||
auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
|
||||
auto messagePostAuthor = peer->isBroadcast()
|
||||
? _session->user()->name
|
||||
: QString();
|
||||
if (action.options.scheduled) {
|
||||
@@ -4355,23 +4405,27 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
}
|
||||
const auto views = 1;
|
||||
const auto forwards = 0;
|
||||
lastMessage = history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
MTP_int(messageFromId),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(peer->id),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(),
|
||||
MTP_int(action.replyTo),
|
||||
MTPint(), // via_bot_id
|
||||
replyHeader,
|
||||
MTP_int(
|
||||
HistoryItem::NewMessageDate(action.options.scheduled)),
|
||||
msgText,
|
||||
media,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTP_int(1),
|
||||
MTPint(),
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTPlong(),
|
||||
//MTPMessageReactions(),
|
||||
@@ -4458,12 +4512,12 @@ void ApiWrap::sendInlineResult(
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
|
||||
if (action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
bool channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
bool silentPost = action.options.silent
|
||||
|| (channelPost && _session->data().notifySilentPosts(peer));
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = action.options.silent
|
||||
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
|
||||
@@ -4478,8 +4532,8 @@ void ApiWrap::sendInlineResult(
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
}
|
||||
|
||||
const auto messageFromId = channelPost ? 0 : _session->userId();
|
||||
const auto messagePostAuthor = channelPost
|
||||
const auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? _session->user()->name
|
||||
: QString();
|
||||
|
||||
@@ -5118,34 +5172,34 @@ auto ApiWrap::privacyValue(Privacy::Key key) -> rpl::producer<Privacy> {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::reloadBlockedUsers() {
|
||||
if (_blockedUsersRequestId) {
|
||||
void ApiWrap::reloadBlockedPeers() {
|
||||
if (_blockedPeersRequestId) {
|
||||
return;
|
||||
}
|
||||
_blockedUsersRequestId = request(MTPcontacts_GetBlocked(
|
||||
_blockedPeersRequestId = request(MTPcontacts_GetBlocked(
|
||||
MTP_int(0),
|
||||
MTP_int(kBlockedFirstSlice)
|
||||
)).done([=](const MTPcontacts_Blocked &result) {
|
||||
_blockedUsersRequestId = 0;
|
||||
_blockedPeersRequestId = 0;
|
||||
const auto push = [&](
|
||||
int count,
|
||||
const QVector<MTPContactBlocked> &list) {
|
||||
auto slice = BlockedUsersSlice();
|
||||
const QVector<MTPPeerBlocked> &list) {
|
||||
auto slice = BlockedPeersSlice();
|
||||
slice.total = std::max(count, list.size());
|
||||
slice.list.reserve(list.size());
|
||||
for (const auto &contact : list) {
|
||||
contact.match([&](const MTPDcontactBlocked &data) {
|
||||
const auto user = _session->data().userLoaded(
|
||||
data.vuser_id().v);
|
||||
if (user) {
|
||||
user->setIsBlocked(true);
|
||||
slice.list.push_back({ user, data.vdate().v });
|
||||
contact.match([&](const MTPDpeerBlocked &data) {
|
||||
const auto peer = _session->data().peerLoaded(
|
||||
peerFromMTP(data.vpeer_id()));
|
||||
if (peer) {
|
||||
peer->setIsBlocked(true);
|
||||
slice.list.push_back({ peer, data.vdate().v });
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!_blockedUsersSlice || *_blockedUsersSlice != slice) {
|
||||
_blockedUsersSlice = slice;
|
||||
_blockedUsersChanges.fire(std::move(slice));
|
||||
if (!_blockedPeersSlice || *_blockedPeersSlice != slice) {
|
||||
_blockedPeersSlice = slice;
|
||||
_blockedPeersChanges.fire(std::move(slice));
|
||||
}
|
||||
};
|
||||
result.match([&](const MTPDcontacts_blockedSlice &data) {
|
||||
@@ -5156,17 +5210,21 @@ void ApiWrap::reloadBlockedUsers() {
|
||||
push(0, data.vblocked().v);
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
_blockedUsersRequestId = 0;
|
||||
_blockedPeersRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
auto ApiWrap::blockedUsersSlice() -> rpl::producer<BlockedUsersSlice> {
|
||||
if (!_blockedUsersSlice) {
|
||||
reloadBlockedUsers();
|
||||
auto ApiWrap::blockedPeersSlice() -> rpl::producer<BlockedPeersSlice> {
|
||||
if (!_blockedPeersSlice) {
|
||||
reloadBlockedPeers();
|
||||
}
|
||||
return _blockedUsersSlice
|
||||
? _blockedUsersChanges.events_starting_with_copy(*_blockedUsersSlice)
|
||||
: (_blockedUsersChanges.events() | rpl::type_erased());
|
||||
return _blockedPeersSlice
|
||||
? _blockedPeersChanges.events_starting_with_copy(*_blockedPeersSlice)
|
||||
: (_blockedPeersChanges.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
Api::Authorizations &ApiWrap::authorizations() {
|
||||
return *_authorizations;
|
||||
}
|
||||
|
||||
Api::SelfDestruct &ApiWrap::selfDestruct() {
|
||||
@@ -5199,9 +5257,8 @@ void ApiWrap::createPoll(
|
||||
history->clearLocalDraft();
|
||||
history->clearCloudDraft();
|
||||
}
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto silentPost = action.options.silent
|
||||
|| (channelPost && _session->data().notifySilentPosts(peer));
|
||||
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ struct CloudPasswordState;
|
||||
namespace Api {
|
||||
|
||||
class Updates;
|
||||
class Authorizations;
|
||||
class SelfDestruct;
|
||||
class SensitiveContent;
|
||||
class GlobalPrivacy;
|
||||
@@ -121,9 +122,9 @@ public:
|
||||
static std::optional<Key> KeyFromMTP(mtpTypeId type);
|
||||
};
|
||||
|
||||
struct BlockedUsersSlice {
|
||||
struct BlockedPeersSlice {
|
||||
struct Item {
|
||||
UserData *user = nullptr;
|
||||
PeerData *peer = nullptr;
|
||||
TimeId date = 0;
|
||||
|
||||
bool operator==(const Item &other) const;
|
||||
@@ -133,8 +134,8 @@ public:
|
||||
QVector<Item> list;
|
||||
int total = 0;
|
||||
|
||||
bool operator==(const BlockedUsersSlice &other) const;
|
||||
bool operator!=(const BlockedUsersSlice &other) const;
|
||||
bool operator==(const BlockedPeersSlice &other) const;
|
||||
bool operator!=(const BlockedPeersSlice &other) const;
|
||||
};
|
||||
|
||||
explicit ApiWrap(not_null<Main::Session*> session);
|
||||
@@ -172,7 +173,9 @@ public:
|
||||
ChannelData *channel,
|
||||
MsgId msgId,
|
||||
RequestMessageDataCallback callback);
|
||||
QString exportDirectMessageLink(not_null<HistoryItem*> item);
|
||||
QString exportDirectMessageLink(
|
||||
not_null<HistoryItem*> item,
|
||||
bool inRepliesContext);
|
||||
|
||||
void requestContacts();
|
||||
void requestDialogs(Data::Folder *folder = nullptr);
|
||||
@@ -279,8 +282,8 @@ public:
|
||||
void joinChannel(not_null<ChannelData*> channel);
|
||||
void leaveChannel(not_null<ChannelData*> channel);
|
||||
|
||||
void blockUser(not_null<UserData*> user);
|
||||
void unblockUser(not_null<UserData*> user, Fn<void()> onDone = nullptr);
|
||||
void blockPeer(not_null<PeerData*> peer);
|
||||
void unblockPeer(not_null<PeerData*> peer, Fn<void()> onDone = nullptr);
|
||||
|
||||
void exportInviteLink(not_null<PeerData*> peer);
|
||||
void requestNotifySettings(const MTPInputNotifyPeer &peer);
|
||||
@@ -448,9 +451,10 @@ public:
|
||||
void reloadPrivacy(Privacy::Key key);
|
||||
rpl::producer<Privacy> privacyValue(Privacy::Key key);
|
||||
|
||||
void reloadBlockedUsers();
|
||||
rpl::producer<BlockedUsersSlice> blockedUsersSlice();
|
||||
void reloadBlockedPeers();
|
||||
rpl::producer<BlockedPeersSlice> blockedPeersSlice();
|
||||
|
||||
[[nodiscard]] Api::Authorizations &authorizations();
|
||||
[[nodiscard]] Api::SelfDestruct &selfDestruct();
|
||||
[[nodiscard]] Api::SensitiveContent &sensitiveContent();
|
||||
[[nodiscard]] Api::GlobalPrivacy &globalPrivacy();
|
||||
@@ -690,7 +694,7 @@ private:
|
||||
QMap<uint64, QPair<uint64, mtpRequestId> > _stickerSetRequests;
|
||||
|
||||
QMap<ChannelData*, mtpRequestId> _channelAmInRequests;
|
||||
base::flat_map<not_null<UserData*>, mtpRequestId> _blockRequests;
|
||||
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests;
|
||||
base::flat_map<not_null<PeerData*>, mtpRequestId> _exportInviteRequests;
|
||||
base::flat_map<PeerId, mtpRequestId> _notifySettingRequests;
|
||||
base::flat_map<not_null<History*>, mtpRequestId> _draftsSaveRequestIds;
|
||||
@@ -809,10 +813,11 @@ private:
|
||||
base::flat_map<Privacy::Key, Privacy> _privacyValues;
|
||||
std::map<Privacy::Key, rpl::event_stream<Privacy>> _privacyChanges;
|
||||
|
||||
mtpRequestId _blockedUsersRequestId = 0;
|
||||
std::optional<BlockedUsersSlice> _blockedUsersSlice;
|
||||
rpl::event_stream<BlockedUsersSlice> _blockedUsersChanges;
|
||||
mtpRequestId _blockedPeersRequestId = 0;
|
||||
std::optional<BlockedPeersSlice> _blockedPeersSlice;
|
||||
rpl::event_stream<BlockedPeersSlice> _blockedPeersChanges;
|
||||
|
||||
const std::unique_ptr<Api::Authorizations> _authorizations;
|
||||
const std::unique_ptr<Api::SelfDestruct> _selfDestruct;
|
||||
const std::unique_ptr<Api::SensitiveContent> _sensitiveContent;
|
||||
const std::unique_ptr<Api::GlobalPrivacy> _globalPrivacy;
|
||||
|
||||
@@ -125,7 +125,7 @@ QString telegramFaqLink() {
|
||||
const auto langpacked = [&](const char *language) {
|
||||
return result + '/' + language;
|
||||
};
|
||||
const auto current = Lang::Current().id();
|
||||
const auto current = Lang::Id();
|
||||
for (const auto language : { "de", "es", "it", "ko" }) {
|
||||
if (current.startsWith(QLatin1String(language))) {
|
||||
return langpacked(language);
|
||||
|
||||
@@ -244,7 +244,6 @@ private:
|
||||
|
||||
Fn<void()> _revokeCallback;
|
||||
mtpRequestId _revokeRequestId = 0;
|
||||
QPointer<ConfirmBox> _weakRevokeConfirmBox;
|
||||
|
||||
};
|
||||
|
||||
@@ -1417,21 +1416,21 @@ void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
lt_group,
|
||||
pressed->name);
|
||||
auto confirmText = tr::lng_channels_too_much_public_revoke(tr::now);
|
||||
_weakRevokeConfirmBox = Ui::show(Box<ConfirmBox>(text, confirmText, crl::guard(this, [this, pressed]() {
|
||||
auto callback = crl::guard(this, [=](Fn<void()> &&close) {
|
||||
if (_revokeRequestId) return;
|
||||
_revokeRequestId = _api.request(MTPchannels_UpdateUsername(
|
||||
pressed->asChannel()->inputChannel,
|
||||
MTP_string()
|
||||
)).done([=](const MTPBool &result) {
|
||||
const auto callback = _revokeCallback;
|
||||
if (_weakRevokeConfirmBox) {
|
||||
_weakRevokeConfirmBox->closeBox();
|
||||
}
|
||||
if (callback) {
|
||||
)).done([=, close = std::move(close)](const MTPBool &result) {
|
||||
close();
|
||||
if (const auto callback = _revokeCallback) {
|
||||
callback();
|
||||
}
|
||||
}).send();
|
||||
})), Ui::LayerOption::KeepOther);
|
||||
});
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(text, confirmText, std::move(callback)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ private:
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
using Selection = base::optional_variant<Selected, DeleteSelected>;
|
||||
using Selection = std::variant<v::null_t, Selected, DeleteSelected>;
|
||||
|
||||
int getSelectionIndex(const Selection &selection) const;
|
||||
void repaintPaper(int index);
|
||||
@@ -163,12 +163,9 @@ void BackgroundBox::prepare() {
|
||||
}
|
||||
|
||||
void BackgroundBox::removePaper(const Data::WallPaper &paper) {
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto session = &_controller->session();
|
||||
const auto remove = [=, weak = Ui::MakeWeak(this)]{
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
const auto remove = [=, weak = Ui::MakeWeak(this)](Fn<void()> &&close) {
|
||||
close();
|
||||
if (weak) {
|
||||
weak->_inner->removePaper(paper);
|
||||
}
|
||||
@@ -179,7 +176,7 @@ void BackgroundBox::removePaper(const Data::WallPaper &paper) {
|
||||
paper.mtpSettings()
|
||||
)).send();
|
||||
};
|
||||
*box = Ui::show(
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
tr::lng_background_sure_delete(tr::now),
|
||||
tr::lng_selected_delete(tr::now),
|
||||
@@ -358,16 +355,16 @@ void BackgroundBox::Inner::paintPaper(
|
||||
p.drawPixmap(x, y, paper.thumbnail);
|
||||
}
|
||||
|
||||
const auto over = _overDown ? _overDown : _over;
|
||||
const auto over = !v::is_null(_overDown) ? _overDown : _over;
|
||||
if (paper.data.id() == Window::Theme::Background()->id()) {
|
||||
const auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
|
||||
const auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
|
||||
_check->paint(p, checkLeft, checkTop, width());
|
||||
} else if (Data::IsCloudWallPaper(paper.data)
|
||||
&& !Data::IsDefaultWallPaper(paper.data)
|
||||
&& over.has_value()
|
||||
&& !v::is_null(over)
|
||||
&& (&paper == &_papers[getSelectionIndex(over)])) {
|
||||
const auto deleteSelected = over.is<DeleteSelected>();
|
||||
const auto deleteSelected = v::is<DeleteSelected>(over);
|
||||
const auto deletePos = QPoint(x + st::backgroundSize.width() - st::stickerPanDeleteIconBg.width(), y);
|
||||
p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityBgOver : st::stickerPanDeleteOpacityBg);
|
||||
st::stickerPanDeleteIconBg.paint(p, deletePos, width());
|
||||
@@ -414,7 +411,7 @@ void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
repaintPaper(getSelectionIndex(_over));
|
||||
_over = newOver;
|
||||
repaintPaper(getSelectionIndex(_over));
|
||||
setCursor((_over.has_value() || _overDown.has_value())
|
||||
setCursor((!v::is_null(_over) || !v::is_null(_overDown))
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
}
|
||||
@@ -442,22 +439,22 @@ void BackgroundBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
|
||||
int BackgroundBox::Inner::getSelectionIndex(
|
||||
const Selection &selection) const {
|
||||
return selection.match([](const Selected &data) {
|
||||
return v::match(selection, [](const Selected &data) {
|
||||
return data.index;
|
||||
}, [](const DeleteSelected &data) {
|
||||
return data.index;
|
||||
}, [](std::nullopt_t) {
|
||||
}, [](v::null_t) {
|
||||
return -1;
|
||||
});
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (base::take(_overDown) == _over && _over.has_value()) {
|
||||
if (base::take(_overDown) == _over && !v::is_null(_over)) {
|
||||
const auto index = getSelectionIndex(_over);
|
||||
if (index >= 0 && index < _papers.size()) {
|
||||
if (base::get_if<DeleteSelected>(&_over)) {
|
||||
if (std::get_if<DeleteSelected>(&_over)) {
|
||||
_backgroundRemove.fire_copy(_papers[index].data);
|
||||
} else if (base::get_if<Selected>(&_over)) {
|
||||
} else if (std::get_if<Selected>(&_over)) {
|
||||
auto &paper = _papers[index];
|
||||
if (!paper.dataMedia) {
|
||||
if (const auto document = paper.data.document()) {
|
||||
@@ -468,7 +465,7 @@ void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_backgroundChosen.fire_copy(paper.data);
|
||||
}
|
||||
}
|
||||
} else if (!_over.has_value()) {
|
||||
} else if (v::is_null(_over)) {
|
||||
setCursor(style::cur_default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +348,7 @@ sessionInfoFont: msgFont;
|
||||
sessionInfoFg: windowSubTextFg;
|
||||
sessionTerminateTop: 28px;
|
||||
sessionTerminateSkip: 22px;
|
||||
sessionNamePadding: margins(0px, 0px, 5px, 0px);
|
||||
sessionTerminate: IconButton {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
@@ -366,6 +367,15 @@ sessionTerminateAllButton: LinkButton(boxLinkButton) {
|
||||
color: attentionButtonFg;
|
||||
overColor: attentionButtonFg;
|
||||
}
|
||||
sessionNameStyle: TextStyle(defaultTextStyle) {
|
||||
font: sessionNameFont;
|
||||
}
|
||||
sessionWhenStyle: TextStyle(defaultTextStyle) {
|
||||
font: sessionWhenFont;
|
||||
}
|
||||
sessionInfoStyle: TextStyle(defaultTextStyle) {
|
||||
font: sessionInfoFont;
|
||||
}
|
||||
|
||||
passcodeHeaderFont: font(19px);
|
||||
passcodeHeaderHeight: 80px;
|
||||
|
||||
@@ -74,7 +74,7 @@ TextParseOptions kMarkedTextBoxOptions = {
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
FnMut<void()> confirmedCallback,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(tr::lng_box_ok(tr::now))
|
||||
, _cancelText(tr::lng_cancel(tr::now))
|
||||
@@ -89,7 +89,7 @@ ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
FnMut<void()> confirmedCallback,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(tr::lng_cancel(tr::now))
|
||||
@@ -104,7 +104,7 @@ ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const TextWithEntities &text,
|
||||
const QString &confirmText,
|
||||
FnMut<void()> confirmedCallback,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(tr::lng_cancel(tr::now))
|
||||
@@ -120,7 +120,7 @@ ConfirmBox::ConfirmBox(
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const style::RoundButton &confirmStyle,
|
||||
FnMut<void()> confirmedCallback,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(tr::lng_cancel(tr::now))
|
||||
@@ -136,7 +136,7 @@ ConfirmBox::ConfirmBox(
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const QString &cancelText,
|
||||
FnMut<void()> confirmedCallback,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(cancelText)
|
||||
@@ -153,7 +153,7 @@ ConfirmBox::ConfirmBox(
|
||||
const QString &confirmText,
|
||||
const style::RoundButton &confirmStyle,
|
||||
const QString &cancelText,
|
||||
FnMut<void()> confirmedCallback,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(cancelText)
|
||||
@@ -256,8 +256,16 @@ void ConfirmBox::textUpdated() {
|
||||
void ConfirmBox::confirmed() {
|
||||
if (!_confirmed) {
|
||||
_confirmed = true;
|
||||
if (auto callback = std::move(_confirmedCallback)) {
|
||||
callback();
|
||||
|
||||
const auto confirmed = &_confirmedCallback;
|
||||
if (const auto callbackPtr = std::get_if<1>(confirmed)) {
|
||||
if (auto callback = base::take(*callbackPtr)) {
|
||||
callback();
|
||||
}
|
||||
} else if (const auto callbackPtr = std::get_if<2>(confirmed)) {
|
||||
if (auto callback = base::take(*callbackPtr)) {
|
||||
callback([=] { closeBox(); });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -808,53 +816,7 @@ void DeleteMessagesBox::deleteAndClear() {
|
||||
_deleteConfirmedCallback();
|
||||
}
|
||||
|
||||
auto remove = std::vector<not_null<HistoryItem*>>();
|
||||
remove.reserve(_ids.size());
|
||||
base::flat_map<not_null<History*>, QVector<MTPint>> idsByPeer;
|
||||
base::flat_map<not_null<PeerData*>, QVector<MTPint>> scheduledIdsByPeer;
|
||||
for (const auto itemId : _ids) {
|
||||
if (const auto item = _session->data().message(itemId)) {
|
||||
const auto history = item->history();
|
||||
if (item->isScheduled()) {
|
||||
const auto wasOnServer = !item->isSending()
|
||||
&& !item->hasFailed();
|
||||
if (wasOnServer) {
|
||||
scheduledIdsByPeer[history->peer].push_back(MTP_int(
|
||||
_session->data().scheduledMessages().lookupId(item)));
|
||||
} else {
|
||||
_session->data().scheduledMessages().removeSending(item);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
remove.push_back(item);
|
||||
if (IsServerMsgId(item->id)) {
|
||||
idsByPeer[history].push_back(MTP_int(itemId.msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &[history, ids] : idsByPeer) {
|
||||
history->owner().histories().deleteMessages(history, ids, revoke);
|
||||
}
|
||||
for (const auto &[peer, ids] : scheduledIdsByPeer) {
|
||||
peer->session().api().request(MTPmessages_DeleteScheduledMessages(
|
||||
peer->input,
|
||||
MTP_vector<MTPint>(ids)
|
||||
)).done([peer=peer](const MTPUpdates &result) {
|
||||
peer->session().api().applyUpdates(result);
|
||||
}).send();
|
||||
}
|
||||
|
||||
for (const auto item : remove) {
|
||||
const auto history = item->history();
|
||||
const auto wasLast = (history->lastMessage() == item);
|
||||
const auto wasInChats = (history->chatListMessage() == item);
|
||||
item->destroy();
|
||||
|
||||
if (wasLast || wasInChats) {
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
}
|
||||
_session->data().histories().deleteMessages(_ids, revoke);
|
||||
|
||||
const auto session = _session;
|
||||
Ui::hideLayer();
|
||||
|
||||
@@ -28,12 +28,51 @@ class EmptyUserpic;
|
||||
class InformBox;
|
||||
class ConfirmBox : public Ui::BoxContent, public ClickHandlerHost {
|
||||
public:
|
||||
ConfirmBox(QWidget*, const QString &text, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(QWidget*, const QString &text, const QString &confirmText, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const QString &cancelText, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, const QString &cancelText, FnMut<void()> confirmedCallback = FnMut<void()>(), FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(QWidget*, const TextWithEntities &text, const QString &confirmText, FnMut<void()> confirmedCallback = nullptr, FnMut<void()> cancelledCallback = nullptr);
|
||||
|
||||
using ConfirmedCallback = std::variant<
|
||||
v::null_t,
|
||||
FnMut<void()>,
|
||||
FnMut<void(Fn<void()>)>>;
|
||||
|
||||
ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
ConfirmedCallback confirmedCallback = FnMut<void()>(),
|
||||
FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
ConfirmedCallback confirmedCallback = FnMut<void()>(),
|
||||
FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const style::RoundButton &confirmStyle,
|
||||
ConfirmedCallback confirmedCallback = FnMut<void()>(),
|
||||
FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const QString &cancelText,
|
||||
ConfirmedCallback confirmedCallback = FnMut<void()>(),
|
||||
FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const style::RoundButton &confirmStyle,
|
||||
const QString &cancelText,
|
||||
ConfirmedCallback confirmedCallback = FnMut<void()>(),
|
||||
FnMut<void()> cancelledCallback = FnMut<void()>());
|
||||
ConfirmBox(
|
||||
QWidget*,
|
||||
const TextWithEntities &text,
|
||||
const QString &confirmText,
|
||||
ConfirmedCallback confirmedCallback = v::null,
|
||||
FnMut<void()> cancelledCallback = nullptr);
|
||||
|
||||
void updateLink();
|
||||
|
||||
@@ -87,7 +126,7 @@ private:
|
||||
bool _confirmed = false;
|
||||
bool _cancelled = false;
|
||||
bool _strictCancel = false;
|
||||
FnMut<void()> _confirmedCallback;
|
||||
ConfirmBox::ConfirmedCallback _confirmedCallback;
|
||||
FnMut<void()> _cancelledCallback;
|
||||
|
||||
};
|
||||
|
||||
@@ -41,6 +41,48 @@ constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000);
|
||||
|
||||
using ProxyData = MTP::ProxyData;
|
||||
|
||||
class HostInput : public Ui::MaskedInputField {
|
||||
public:
|
||||
HostInput(
|
||||
QWidget *parent,
|
||||
const style::InputField &st,
|
||||
rpl::producer<QString> placeholder,
|
||||
const QString &val);
|
||||
|
||||
protected:
|
||||
void correctValue(
|
||||
const QString &was,
|
||||
int wasCursor,
|
||||
QString &now,
|
||||
int &nowCursor) override;
|
||||
};
|
||||
|
||||
HostInput::HostInput(
|
||||
QWidget *parent,
|
||||
const style::InputField &st,
|
||||
rpl::producer<QString> placeholder,
|
||||
const QString &val)
|
||||
: MaskedInputField(parent, st, std::move(placeholder), val) {
|
||||
}
|
||||
|
||||
void HostInput::correctValue(
|
||||
const QString &was,
|
||||
int wasCursor,
|
||||
QString &now,
|
||||
int &nowCursor) {
|
||||
QString newText;
|
||||
int newCursor = nowCursor;
|
||||
newText.reserve(now.size());
|
||||
for (auto i = 0, l = now.size(); i < l; ++i) {
|
||||
if (now[i] == ',') {
|
||||
newText.append('.');
|
||||
} else {
|
||||
newText.append(now[i]);
|
||||
}
|
||||
}
|
||||
setCorrectedText(now, nowCursor, newText, newCursor);
|
||||
}
|
||||
|
||||
class Base64UrlInput : public Ui::MaskedInputField {
|
||||
public:
|
||||
Base64UrlInput(
|
||||
@@ -209,7 +251,7 @@ private:
|
||||
std::shared_ptr<Ui::RadioenumGroup<Type>> _type;
|
||||
|
||||
QPointer<Ui::SlideWrap<>> _aboutSponsored;
|
||||
QPointer<Ui::InputField> _host;
|
||||
QPointer<HostInput> _host;
|
||||
QPointer<Ui::PortInput> _port;
|
||||
QPointer<Ui::InputField> _user;
|
||||
QPointer<Ui::PasswordInput> _password;
|
||||
@@ -767,12 +809,12 @@ ProxyBox::ProxyBox(
|
||||
void ProxyBox::prepare() {
|
||||
setTitle(tr::lng_proxy_edit());
|
||||
|
||||
connect(_host.data(), &Ui::InputField::changed, [=] {
|
||||
connect(_host.data(), &HostInput::changed, [=] {
|
||||
Ui::PostponeCall(_host, [=] {
|
||||
const auto host = _host->getLastText().trimmed();
|
||||
static const auto mask = u"^\\d+\\.\\d+\\.\\d+\\.\\d+:(\\d*)$"_q;
|
||||
const auto match = QRegularExpression(mask).match(host);
|
||||
if (_host->textCursor().position() == host.size()
|
||||
if (_host->cursorPosition() == host.size()
|
||||
&& match.hasMatch()) {
|
||||
const auto port = match.captured(1);
|
||||
_port->setText(port);
|
||||
@@ -881,7 +923,7 @@ void ProxyBox::setupSocketAddress(const ProxyData &data) {
|
||||
_content,
|
||||
st::connectionHostInputField.heightMin),
|
||||
st::proxyEditInputPadding);
|
||||
_host = Ui::CreateChild<Ui::InputField>(
|
||||
_host = Ui::CreateChild<HostInput>(
|
||||
address,
|
||||
st::connectionHostInputField,
|
||||
tr::lng_connection_host_ph(),
|
||||
@@ -1043,7 +1085,6 @@ void ProxiesBoxController::ShowApplyConfirmation(
|
||||
proxy.password = fields.value(qsl("secret"));
|
||||
}
|
||||
if (proxy) {
|
||||
const auto box = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto text = tr::lng_sure_enable_socks(
|
||||
tr::now,
|
||||
lt_server,
|
||||
@@ -1053,7 +1094,7 @@ void ProxiesBoxController::ShowApplyConfirmation(
|
||||
+ (proxy.type == Type::Mtproto
|
||||
? "\n\n" + tr::lng_proxy_sponsor_warning(tr::now)
|
||||
: QString());
|
||||
*box = Ui::show(Box<ConfirmBox>(text, tr::lng_sure_enable(tr::now), [=] {
|
||||
auto callback = [=](Fn<void()> &&close) {
|
||||
auto &proxies = Global::RefProxiesList();
|
||||
if (!ranges::contains(proxies, proxy)) {
|
||||
proxies.push_back(proxy);
|
||||
@@ -1062,10 +1103,14 @@ void ProxiesBoxController::ShowApplyConfirmation(
|
||||
proxy,
|
||||
ProxyData::Settings::Enabled);
|
||||
Local::writeSettings();
|
||||
if (const auto strong = box->data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
}), Ui::LayerOption::KeepOther);
|
||||
close();
|
||||
};
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
text,
|
||||
tr::lng_sure_enable(tr::now),
|
||||
std::move(callback)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
} else {
|
||||
Ui::show(Box<InformBox>(
|
||||
(proxy.status() == ProxyData::Status::Unsupported
|
||||
|
||||
@@ -225,7 +225,7 @@ auto AddButtonWithLoader(
|
||||
|
||||
buttonState->value(
|
||||
) | rpl::start_with_next([=](const DictState &state) {
|
||||
const auto isToggledSet = state.is<Active>();
|
||||
const auto isToggledSet = v::is<Active>(state);
|
||||
const auto toggled = isToggledSet ? 1. : 0.;
|
||||
const auto over = !button->isDisabled()
|
||||
&& (button->isDown() || button->isOver());
|
||||
@@ -252,7 +252,7 @@ auto AddButtonWithLoader(
|
||||
dictionaryRemoved->events(),
|
||||
buttonState->value(
|
||||
) | rpl::filter([](const DictState &state) {
|
||||
return state.is<Failed>();
|
||||
return v::is<Failed>(state);
|
||||
}) | rpl::to_empty
|
||||
) | rpl::map_to(false)
|
||||
)
|
||||
@@ -276,13 +276,14 @@ auto AddButtonWithLoader(
|
||||
});
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::filter([=](const DictState &state) {
|
||||
return !buttonState->current().is<Failed>() || !state.is<Available>();
|
||||
return !v::is<Failed>(buttonState->current())
|
||||
|| !v::is<Available>(state);
|
||||
});
|
||||
|
||||
button->toggledValue(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
const auto &state = buttonState->current();
|
||||
if (toggled && (state.is<Available>() || state.is<Failed>())) {
|
||||
if (toggled && (v::is<Available>(state) || v::is<Failed>(state))) {
|
||||
const auto weak = Ui::MakeWeak(button);
|
||||
setLocalLoader(base::make_unique_q<Loader>(
|
||||
QCoreApplication::instance(),
|
||||
@@ -292,7 +293,7 @@ auto AddButtonWithLoader(
|
||||
Spellchecker::DictPathByLangId(id),
|
||||
Spellchecker::GetDownloadSize(id),
|
||||
crl::guard(weak, destroyLocalLoader)));
|
||||
} else if (!toggled && state.is<Loading>()) {
|
||||
} else if (!toggled && v::is<Loading>(state)) {
|
||||
if (const auto g = rawGlobalLoaderPtr()) {
|
||||
g->destroy();
|
||||
return;
|
||||
|
||||
@@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_item.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "layout.h"
|
||||
#include "media/streaming/media_streaming_instance.h"
|
||||
#include "media/streaming/media_streaming_player.h"
|
||||
#include "media/streaming/media_streaming_document.h"
|
||||
@@ -47,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "window/window_session_controller.h"
|
||||
@@ -363,6 +363,12 @@ EditCaptionBox::EditCaptionBox(
|
||||
) | rpl::start_with_next([&](bool checked) {
|
||||
_asFile = checked;
|
||||
}, _wayWrap->lifetime());
|
||||
|
||||
_controller->session().data().itemRemoved(
|
||||
_msgId
|
||||
) | rpl::start_with_next([=] {
|
||||
closeBox();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
EditCaptionBox::~EditCaptionBox() = default;
|
||||
@@ -431,7 +437,7 @@ void EditCaptionBox::setupStreamedPreview(std::shared_ptr<Document> shared) {
|
||||
}
|
||||
|
||||
void EditCaptionBox::handleStreamingUpdate(Update &&update) {
|
||||
update.data.match([&](Information &update) {
|
||||
v::match(update.data, [&](Information &update) {
|
||||
streamingReady(std::move(update));
|
||||
}, [&](const PreloadedVideo &update) {
|
||||
}, [&](const UpdateVideo &update) {
|
||||
@@ -489,7 +495,7 @@ void EditCaptionBox::updateEditPreview() {
|
||||
auto isGif = false;
|
||||
auto shouldAsDoc = true;
|
||||
auto docPhotoSize = QSize();
|
||||
if (const auto image = base::get_if<Info::Image>(fileMedia)) {
|
||||
if (const auto image = std::get_if<Info::Image>(fileMedia)) {
|
||||
shouldAsDoc = !Storage::ValidateThumbDimensions(
|
||||
image->data.width(),
|
||||
image->data.height());
|
||||
@@ -501,14 +507,14 @@ void EditCaptionBox::updateEditPreview() {
|
||||
_animated = isGif;
|
||||
_photo = !isGif && !shouldAsDoc;
|
||||
_isImage = true;
|
||||
} else if (const auto video = base::get_if<Info::Video>(fileMedia)) {
|
||||
} else if (const auto video = std::get_if<Info::Video>(fileMedia)) {
|
||||
isGif = video->isGifv;
|
||||
_animated = true;
|
||||
shouldAsDoc = false;
|
||||
}
|
||||
if (shouldAsDoc) {
|
||||
auto nameString = filename;
|
||||
if (const auto song = base::get_if<Info::Song>(fileMedia)) {
|
||||
if (const auto song = std::get_if<Info::Song>(fileMedia)) {
|
||||
nameString = DocumentData::ComposeNameString(
|
||||
filename,
|
||||
song->title,
|
||||
@@ -684,7 +690,7 @@ bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
|
||||
const auto imageAsDoc = [&] {
|
||||
using Info = FileMediaInformation;
|
||||
const auto fileMedia = &file->information->media;
|
||||
if (const auto image = base::get_if<Info::Image>(fileMedia)) {
|
||||
if (const auto image = std::get_if<Info::Image>(fileMedia)) {
|
||||
return !Storage::ValidateThumbDimensions(
|
||||
image->data.width(),
|
||||
image->data.height());
|
||||
@@ -1030,7 +1036,7 @@ void EditCaptionBox::setName(QString nameString, qint64 size) {
|
||||
st::semiboldTextStyle,
|
||||
nameString,
|
||||
Ui::NameTextOptions());
|
||||
_status = formatSizeText(size);
|
||||
_status = Ui::FormatSizeText(size);
|
||||
}
|
||||
|
||||
void EditCaptionBox::keyPressEvent(QKeyEvent *e) {
|
||||
|
||||
@@ -86,7 +86,7 @@ void PrivacyExceptionsBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
}
|
||||
|
||||
std::unique_ptr<PrivacyExceptionsBoxController::Row> PrivacyExceptionsBoxController::createRow(not_null<History*> history) {
|
||||
if (history->peer->isSelf()) {
|
||||
if (history->peer->isSelf() || history->peer->isRepliesChat()) {
|
||||
return nullptr;
|
||||
} else if (!history->peer->isUser()
|
||||
&& !history->peer->isChat()
|
||||
|
||||
@@ -241,19 +241,31 @@ void FilterChatsPreview::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
for (auto &[history, userpic, button] : _removePeer) {
|
||||
const auto savedMessages = history->peer->isSelf();
|
||||
if (savedMessages) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(
|
||||
p,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
const auto repliesMessages = history->peer->isRepliesChat();
|
||||
if (savedMessages || repliesMessages) {
|
||||
if (savedMessages) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(
|
||||
p,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
} else {
|
||||
Ui::EmptyUserpic::PaintRepliesMessages(
|
||||
p,
|
||||
iconLeft,
|
||||
top + iconTop,
|
||||
width(),
|
||||
st.photoSize);
|
||||
}
|
||||
p.setPen(st::contactsNameFg);
|
||||
p.drawTextLeft(
|
||||
nameLeft,
|
||||
top + nameTop,
|
||||
width(),
|
||||
tr::lng_saved_messages(tr::now));
|
||||
(savedMessages
|
||||
? tr::lng_saved_messages(tr::now)
|
||||
: tr::lng_replies_messages(tr::now)));
|
||||
} else {
|
||||
history->peer->paintUserpicLeft(
|
||||
p,
|
||||
|
||||
@@ -170,6 +170,8 @@ ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
|
||||
QString ExceptionRow::generateName() {
|
||||
return peer()->isSelf()
|
||||
? tr::lng_saved_messages(tr::now)
|
||||
: peer()->isRepliesChat()
|
||||
? tr::lng_replies_messages(tr::now)
|
||||
: Row::generateName();
|
||||
}
|
||||
|
||||
@@ -180,10 +182,13 @@ QString ExceptionRow::generateShortName() {
|
||||
PaintRoundImageCallback ExceptionRow::generatePaintUserpicCallback() {
|
||||
const auto peer = this->peer();
|
||||
const auto saved = peer->isSelf();
|
||||
const auto replies = peer->isRepliesChat();
|
||||
auto userpic = saved ? nullptr : ensureUserpicView();
|
||||
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
|
||||
if (saved) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
|
||||
} else if (replies) {
|
||||
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
|
||||
} else {
|
||||
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ private:
|
||||
return (index == other.index);
|
||||
}
|
||||
};
|
||||
using Selection = base::optional_variant<RowSelection, MenuSelection>;
|
||||
using Selection = std::variant<v::null_t, RowSelection, MenuSelection>;
|
||||
|
||||
void updateSelected(Selection selected);
|
||||
void updatePressed(Selection pressed);
|
||||
@@ -196,7 +196,7 @@ std::pair<Languages, Languages> PrepareLists() {
|
||||
const auto projId = [](const Language &language) {
|
||||
return language.id;
|
||||
};
|
||||
const auto current = Lang::LanguageIdOrDefault(Lang::Current().id());
|
||||
const auto current = Lang::LanguageIdOrDefault(Lang::Id());
|
||||
auto official = Lang::CurrentCloudManager().languageList();
|
||||
auto recent = Local::readRecentLanguages();
|
||||
ranges::stable_partition(recent, [&](const Language &language) {
|
||||
@@ -207,13 +207,13 @@ std::pair<Languages, Languages> PrepareLists() {
|
||||
const auto generate = [&] {
|
||||
const auto name = (current == "#custom")
|
||||
? "Custom lang pack"
|
||||
: Lang::Current().name();
|
||||
: Lang::GetInstance().name();
|
||||
return Language{
|
||||
current,
|
||||
QString(),
|
||||
QString(),
|
||||
name,
|
||||
Lang::Current().nativeName()
|
||||
Lang::GetInstance().nativeName()
|
||||
};
|
||||
};
|
||||
const auto i = ranges::find(official, current, projId);
|
||||
@@ -327,7 +327,7 @@ void Rows::mouseMoveEvent(QMouseEvent *e) {
|
||||
|
||||
void Rows::mousePressEvent(QMouseEvent *e) {
|
||||
updatePressed(_selected);
|
||||
if (_pressed.has_value()
|
||||
if (!v::is_null(_pressed)
|
||||
&& !rowBySelection(_pressed).menuToggleForceRippled) {
|
||||
addRipple(_pressed, e->pos());
|
||||
}
|
||||
@@ -348,11 +348,11 @@ QRect Rows::menuToggleArea(not_null<const Row*> row) const {
|
||||
}
|
||||
|
||||
void Rows::addRipple(Selection selected, QPoint position) {
|
||||
Expects(selected.has_value());
|
||||
Expects(!v::is_null(selected));
|
||||
|
||||
ensureRippleBySelection(selected);
|
||||
|
||||
const auto menu = selected.is<MenuSelection>();
|
||||
const auto menu = v::is<MenuSelection>(selected);
|
||||
const auto &row = rowBySelection(selected);
|
||||
const auto menuArea = menuToggleArea(&row);
|
||||
auto &ripple = rippleBySelection(&row, selected);
|
||||
@@ -369,7 +369,7 @@ void Rows::ensureRippleBySelection(not_null<Row*> row, Selection selected) {
|
||||
if (ripple) {
|
||||
return;
|
||||
}
|
||||
const auto menu = selected.is<MenuSelection>();
|
||||
const auto menu = v::is<MenuSelection>(selected);
|
||||
const auto menuArea = menuToggleArea(row);
|
||||
auto mask = menu
|
||||
? Ui::RippleAnimation::ellipseMask(menuArea.size())
|
||||
@@ -391,11 +391,11 @@ void Rows::mouseReleaseEvent(QMouseEvent *e) {
|
||||
const auto pressed = _pressed;
|
||||
updatePressed({});
|
||||
if (pressed == _selected) {
|
||||
pressed.match([&](RowSelection data) {
|
||||
v::match(pressed, [&](RowSelection data) {
|
||||
activateByIndex(data.index);
|
||||
}, [&](MenuSelection data) {
|
||||
showMenu(data.index);
|
||||
}, [](std::nullopt_t) {});
|
||||
}, [](v::null_t) {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,11 +597,11 @@ int Rows::count() const {
|
||||
}
|
||||
|
||||
int Rows::indexFromSelection(Selection selected) const {
|
||||
return selected.match([&](RowSelection data) {
|
||||
return v::match(selected, [&](RowSelection data) {
|
||||
return data.index;
|
||||
}, [&](MenuSelection data) {
|
||||
return data.index;
|
||||
}, [](std::nullopt_t) {
|
||||
}, [](v::null_t) {
|
||||
return -1;
|
||||
});
|
||||
}
|
||||
@@ -648,7 +648,7 @@ rpl::producer<bool> Rows::isEmpty() const {
|
||||
}
|
||||
|
||||
void Rows::repaint(Selection selected) {
|
||||
selected.match([](std::nullopt_t) {
|
||||
v::match(selected, [](v::null_t) {
|
||||
}, [&](const auto &data) {
|
||||
repaint(data.index);
|
||||
});
|
||||
@@ -672,17 +672,17 @@ void Rows::repaintChecked(not_null<const Row*> row) {
|
||||
}
|
||||
|
||||
void Rows::updateSelected(Selection selected) {
|
||||
const auto changed = (_selected.has_value() != selected.has_value());
|
||||
const auto changed = (v::is_null(_selected) != v::is_null(selected));
|
||||
repaint(_selected);
|
||||
_selected = selected;
|
||||
repaint(_selected);
|
||||
if (changed) {
|
||||
_hasSelection.fire(_selected.has_value());
|
||||
_hasSelection.fire(!v::is_null(_selected));
|
||||
}
|
||||
}
|
||||
|
||||
void Rows::updatePressed(Selection pressed) {
|
||||
if (_pressed.has_value()) {
|
||||
if (!v::is_null(_pressed)) {
|
||||
if (!rowBySelection(_pressed).menuToggleForceRippled) {
|
||||
if (const auto ripple = rippleBySelection(_pressed).get()) {
|
||||
ripple->lastStop();
|
||||
@@ -725,7 +725,7 @@ const std::unique_ptr<Ui::RippleAnimation> &Rows::rippleBySelection(
|
||||
std::unique_ptr<Ui::RippleAnimation> &Rows::rippleBySelection(
|
||||
not_null<Row*> row,
|
||||
Selection selected) {
|
||||
return selected.is<MenuSelection>()
|
||||
return v::is<MenuSelection>(selected)
|
||||
? row->menuToggleRipple
|
||||
: row->ripple;
|
||||
}
|
||||
@@ -796,7 +796,7 @@ void Rows::paintEvent(QPaintEvent *e) {
|
||||
const auto menu = menuToggleArea();
|
||||
const auto selectedIndex = (_menuShownIndex >= 0)
|
||||
? _menuShownIndex
|
||||
: indexFromSelection(_pressed.has_value() ? _pressed : _selected);
|
||||
: indexFromSelection(!v::is_null(_pressed) ? _pressed : _selected);
|
||||
for (auto i = 0, till = count(); i != till; ++i) {
|
||||
const auto &row = rowByIndex(i);
|
||||
if (row.top + row.height <= clip.y()) {
|
||||
@@ -867,7 +867,7 @@ void Content::setupContent(
|
||||
const Languages &official) {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
const auto current = Lang::LanguageIdOrDefault(Lang::Current().id());
|
||||
const auto current = Lang::LanguageIdOrDefault(Lang::Id());
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
const auto add = [&](const Languages &list, bool areOfficial) {
|
||||
if (list.empty()) {
|
||||
@@ -1101,7 +1101,7 @@ void LanguageBox::prepare() {
|
||||
// "#custom" is applied each time it's passed to switchToLanguage().
|
||||
// So we check that the language really has changed.
|
||||
const auto currentId = [] {
|
||||
return Lang::LanguageIdOrDefault(Lang::Current().id());
|
||||
return Lang::LanguageIdOrDefault(Lang::Id());
|
||||
};
|
||||
if (language.id != currentId()) {
|
||||
Lang::CurrentCloudManager().switchToLanguage(language);
|
||||
|
||||
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "storage/cache/storage_cache_database.h"
|
||||
@@ -21,7 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwindow.h"
|
||||
#include "main/main_session.h"
|
||||
#include "layout.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
@@ -260,7 +260,7 @@ QString LocalStorageBox::Row::titleText(const Database::TaggedSummary &data) con
|
||||
|
||||
QString LocalStorageBox::Row::sizeText(const Database::TaggedSummary &data) const {
|
||||
return data.totalSize
|
||||
? formatSizeText(data.totalSize)
|
||||
? Ui::FormatSizeText(data.totalSize)
|
||||
: tr::lng_local_storage_empty(tr::now);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_domain.h"
|
||||
#include "core/application.h"
|
||||
#include "storage/storage_domain.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
@@ -24,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "passport/passport_encryption.h"
|
||||
#include "passport/passport_panel_edit_contact.h"
|
||||
#include "settings/settings_privacy_security.h"
|
||||
#include "facades.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_passport.h"
|
||||
@@ -31,6 +34,68 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace {
|
||||
|
||||
enum class PasswordErrorType {
|
||||
None,
|
||||
NoPassword,
|
||||
Later,
|
||||
};
|
||||
|
||||
void SetCloudPassword(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session) {
|
||||
session->api().passwordState(
|
||||
) | rpl::start_with_next([=] {
|
||||
using namespace Settings;
|
||||
const auto weak = Ui::MakeWeak(box);
|
||||
if (CheckEditCloudPassword(session)) {
|
||||
box->getDelegate()->show(
|
||||
EditCloudPasswordBox(session));
|
||||
} else {
|
||||
box->getDelegate()->show(CloudPasswordAppOutdatedBox());
|
||||
}
|
||||
if (weak) {
|
||||
weak->closeBox();
|
||||
}
|
||||
}, box->lifetime());
|
||||
}
|
||||
|
||||
void TransferPasswordError(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session,
|
||||
TextWithEntities &&about,
|
||||
PasswordErrorType error) {
|
||||
box->setTitle(tr::lng_rights_transfer_check());
|
||||
box->setWidth(st::transferCheckWidth);
|
||||
|
||||
auto text = std::move(about).append('\n').append('\n').append(
|
||||
tr::lng_rights_transfer_check_password(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue)
|
||||
).append('\n').append('\n').append(
|
||||
tr::lng_rights_transfer_check_session(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue)
|
||||
);
|
||||
if (error == PasswordErrorType::Later) {
|
||||
text.append('\n').append('\n').append(
|
||||
tr::lng_rights_transfer_check_later(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
box->addRow(object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
rpl::single(text),
|
||||
st::boxLabel));
|
||||
if (error == PasswordErrorType::Later) {
|
||||
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
|
||||
} else {
|
||||
box->addButton(tr::lng_rights_transfer_set_password(), [=] {
|
||||
SetCloudPassword(box, session);
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
|
||||
@@ -537,14 +602,11 @@ void PasscodeBox::submitOnlyCheckCloudPassword(const QString &oldPassword) {
|
||||
if (_cloudFields.turningOff && _cloudFields.notEmptyPassport) {
|
||||
Assert(!_cloudFields.customCheckCallback);
|
||||
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto confirmed = [=] {
|
||||
const auto confirmed = [=](Fn<void()> &&close) {
|
||||
send();
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
close();
|
||||
};
|
||||
*box = getDelegate()->show(Box<ConfirmBox>(
|
||||
getDelegate()->show(Box<ConfirmBox>(
|
||||
tr::lng_cloud_password_passport_losing(tr::now),
|
||||
tr::lng_continue(tr::now),
|
||||
confirmed));
|
||||
@@ -744,20 +806,16 @@ void PasscodeBox::changeCloudPassword(
|
||||
}
|
||||
|
||||
void PasscodeBox::suggestSecretReset(const QString &newPassword) {
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto resetSecretAndSave = [=] {
|
||||
checkPasswordHash([=](const Core::CloudPasswordResult &check) {
|
||||
resetSecret(check, newPassword, [=] {
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
});
|
||||
auto resetSecretAndSave = [=](Fn<void()> &&close) {
|
||||
checkPasswordHash([=, close = std::move(close)](
|
||||
const Core::CloudPasswordResult &check) {
|
||||
resetSecret(check, newPassword, std::move(close));
|
||||
});
|
||||
};
|
||||
*box = getDelegate()->show(Box<ConfirmBox>(
|
||||
getDelegate()->show(Box<ConfirmBox>(
|
||||
Lang::Hard::PassportCorruptedChange(),
|
||||
Lang::Hard::PassportCorruptedReset(),
|
||||
[=] { resetSecretAndSave(); }));
|
||||
std::move(resetSecretAndSave)));
|
||||
}
|
||||
|
||||
void PasscodeBox::resetSecret(
|
||||
@@ -1002,14 +1060,11 @@ void RecoverBox::submit() {
|
||||
}).handleFloodErrors().send();
|
||||
});
|
||||
if (_notEmptyPassport) {
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto confirmed = [=] {
|
||||
const auto confirmed = [=](Fn<void()> &&close) {
|
||||
send();
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
close();
|
||||
};
|
||||
*box = getDelegate()->show(Box<ConfirmBox>(
|
||||
getDelegate()->show(Box<ConfirmBox>(
|
||||
tr::lng_cloud_password_passport_losing(tr::now),
|
||||
tr::lng_continue(tr::now),
|
||||
confirmed));
|
||||
@@ -1139,3 +1194,28 @@ RecoveryEmailValidation ConfirmRecoveryEmail(
|
||||
*weak = box.data();
|
||||
return { std::move(box), reloads->events(), cancels->events() };
|
||||
}
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::GenericBox> PrePasswordErrorBox(
|
||||
const RPCError &error,
|
||||
not_null<Main::Session*> session,
|
||||
TextWithEntities &&about) {
|
||||
const auto type = [&] {
|
||||
const auto &type = error.type();
|
||||
if (type == qstr("PASSWORD_MISSING")) {
|
||||
return PasswordErrorType::NoPassword;
|
||||
} else if (type.startsWith(qstr("PASSWORD_TOO_FRESH_"))
|
||||
|| type.startsWith(qstr("SESSION_TOO_FRESH_"))) {
|
||||
return PasswordErrorType::Later;
|
||||
}
|
||||
return PasswordErrorType::None;
|
||||
}();
|
||||
if (type == PasswordErrorType::None) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Box(
|
||||
TransferPasswordError,
|
||||
session,
|
||||
std::move(about),
|
||||
type);
|
||||
}
|
||||
|
||||
@@ -214,3 +214,8 @@ struct RecoveryEmailValidation {
|
||||
[[nodiscard]] RecoveryEmailValidation ConfirmRecoveryEmail(
|
||||
not_null<Main::Session*> session,
|
||||
const QString &pattern);
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::GenericBox> PrePasswordErrorBox(
|
||||
const RPCError &error,
|
||||
not_null<Main::Session*> session,
|
||||
TextWithEntities &&about);
|
||||
|
||||
@@ -36,10 +36,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
PaintRoundImageCallback PaintUserpicCallback(
|
||||
not_null<PeerData*> peer,
|
||||
bool respectSavedMessagesChat) {
|
||||
if (respectSavedMessagesChat && peer->isSelf()) {
|
||||
return [](Painter &p, int x, int y, int outerWidth, int size) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
|
||||
};
|
||||
if (respectSavedMessagesChat) {
|
||||
if (peer->isSelf()) {
|
||||
return [](Painter &p, int x, int y, int outerWidth, int size) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
|
||||
};
|
||||
} else if (peer->isRepliesChat()) {
|
||||
return [](Painter &p, int x, int y, int outerWidth, int size) {
|
||||
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
|
||||
};
|
||||
}
|
||||
}
|
||||
auto userpic = std::shared_ptr<Data::CloudImageView>();
|
||||
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
|
||||
@@ -318,6 +324,8 @@ void PeerListBox::addSelectItem(
|
||||
const auto respect = _controller->respectSavedMessagesChat();
|
||||
const auto text = (respect && peer->isSelf())
|
||||
? tr::lng_saved_short(tr::now)
|
||||
: (respect && peer->isRepliesChat())
|
||||
? tr::lng_replies_messages(tr::now)
|
||||
: peer->shortName();
|
||||
addSelectItem(
|
||||
peer->id,
|
||||
@@ -400,14 +408,16 @@ PeerListRow::PeerListRow(not_null<PeerData*> peer, PeerListRowId id)
|
||||
, _peer(peer)
|
||||
, _initialized(false)
|
||||
, _isSearchResult(false)
|
||||
, _isSavedMessagesChat(false) {
|
||||
, _isSavedMessagesChat(false)
|
||||
, _isRepliesMessagesChat(false) {
|
||||
}
|
||||
|
||||
PeerListRow::PeerListRow(PeerListRowId id)
|
||||
: _id(id)
|
||||
, _initialized(false)
|
||||
, _isSearchResult(false)
|
||||
, _isSavedMessagesChat(false) {
|
||||
, _isSavedMessagesChat(false)
|
||||
, _isRepliesMessagesChat(false) {
|
||||
}
|
||||
|
||||
PeerListRow::~PeerListRow() = default;
|
||||
@@ -470,6 +480,8 @@ void PeerListRow::refreshName(const style::PeerListItem &st) {
|
||||
}
|
||||
const auto text = _isSavedMessagesChat
|
||||
? tr::lng_saved_messages(tr::now)
|
||||
: _isRepliesMessagesChat
|
||||
? tr::lng_replies_messages(tr::now)
|
||||
: generateName();
|
||||
_name.setText(st.nameStyle, text, Ui::NameTextOptions());
|
||||
}
|
||||
@@ -481,6 +493,8 @@ QString PeerListRow::generateName() {
|
||||
QString PeerListRow::generateShortName() {
|
||||
return _isSavedMessagesChat
|
||||
? tr::lng_saved_short(tr::now)
|
||||
: _isRepliesMessagesChat
|
||||
? tr::lng_replies_messages(tr::now)
|
||||
: peer()->shortName();
|
||||
}
|
||||
|
||||
@@ -493,11 +507,14 @@ std::shared_ptr<Data::CloudImageView> PeerListRow::ensureUserpicView() {
|
||||
|
||||
PaintRoundImageCallback PeerListRow::generatePaintUserpicCallback() {
|
||||
const auto saved = _isSavedMessagesChat;
|
||||
const auto replies = _isRepliesMessagesChat;
|
||||
const auto peer = this->peer();
|
||||
auto userpic = saved ? nullptr : ensureUserpicView();
|
||||
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
|
||||
if (saved) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
|
||||
} else if (replies) {
|
||||
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
|
||||
} else {
|
||||
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
|
||||
}
|
||||
@@ -603,6 +620,8 @@ void PeerListRow::paintDisabledCheckUserpic(
|
||||
|
||||
if (_isSavedMessagesChat) {
|
||||
Ui::EmptyUserpic::PaintSavedMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
|
||||
} else if (_isRepliesMessagesChat) {
|
||||
Ui::EmptyUserpic::PaintRepliesMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
|
||||
} else {
|
||||
peer()->paintUserpicLeft(p, _userpic, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
|
||||
}
|
||||
@@ -731,10 +750,12 @@ void PeerListContent::changeCheckState(
|
||||
}
|
||||
|
||||
void PeerListContent::addRowEntry(not_null<PeerListRow*> row) {
|
||||
if (_controller->respectSavedMessagesChat()
|
||||
&& !row->special()
|
||||
&& row->peer()->isSelf()) {
|
||||
row->setIsSavedMessagesChat(true);
|
||||
if (_controller->respectSavedMessagesChat() && !row->special()) {
|
||||
if (row->peer()->isSelf()) {
|
||||
row->setIsSavedMessagesChat(true);
|
||||
} else if (row->peer()->isRepliesChat()) {
|
||||
row->setIsRepliesMessagesChat(true);
|
||||
}
|
||||
}
|
||||
_rowsById.emplace(row->id(), row);
|
||||
if (!row->special()) {
|
||||
|
||||
@@ -146,12 +146,12 @@ public:
|
||||
void setIsSearchResult(bool isSearchResult) {
|
||||
_isSearchResult = isSearchResult;
|
||||
}
|
||||
bool isSavedMessagesChat() const {
|
||||
return _isSavedMessagesChat;
|
||||
}
|
||||
void setIsSavedMessagesChat(bool isSavedMessagesChat) {
|
||||
_isSavedMessagesChat = isSavedMessagesChat;
|
||||
}
|
||||
void setIsRepliesMessagesChat(bool isRepliesMessagesChat) {
|
||||
_isRepliesMessagesChat = isRepliesMessagesChat;
|
||||
}
|
||||
|
||||
template <typename UpdateCallback>
|
||||
void setChecked(
|
||||
@@ -234,6 +234,7 @@ private:
|
||||
bool _initialized : 1;
|
||||
bool _isSearchResult : 1;
|
||||
bool _isSavedMessagesChat : 1;
|
||||
bool _isRepliesMessagesChat : 1;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_histories.h"
|
||||
#include "apiwrap.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "history/history.h"
|
||||
#include "dialogs/dialogs_main_list.h"
|
||||
@@ -104,6 +105,20 @@ void AddBotToGroup(not_null<UserData*> bot, not_null<PeerData*> chat) {
|
||||
// return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
|
||||
//}
|
||||
|
||||
object_ptr<Ui::BoxContent> PrepareContactsBox(
|
||||
not_null<Window::SessionController*> sessionController) {
|
||||
const auto controller = sessionController;
|
||||
auto delegate = [=](not_null<PeerListBox*> box) {
|
||||
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
|
||||
box->addLeftButton(
|
||||
tr::lng_profile_add_contact(),
|
||||
[=] { controller->widget()->onShowAddContact(); });
|
||||
};
|
||||
return Box<PeerListBox>(
|
||||
std::make_unique<ContactsBoxController>(controller),
|
||||
std::move(delegate));
|
||||
}
|
||||
|
||||
void PeerListRowWithLink::setActionLink(const QString &action) {
|
||||
_action = action;
|
||||
refreshActionLink();
|
||||
@@ -584,8 +599,7 @@ void ChooseRecipientBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
auto ChooseRecipientBoxController::createRow(
|
||||
not_null<History*> history) -> std::unique_ptr<Row> {
|
||||
const auto peer = history->peer;
|
||||
const auto skip = peer->isChannel()
|
||||
&& !peer->isMegagroup()
|
||||
&& !peer->canWrite();
|
||||
const auto skip = (peer->isBroadcast() && !peer->canWrite())
|
||||
|| peer->isRepliesChat();
|
||||
return skip ? nullptr : std::make_unique<Row>(history);
|
||||
}
|
||||
|
||||
@@ -31,9 +31,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
class History;
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
class SessionNavigation;
|
||||
} // namespace Window
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareContactsBox(
|
||||
not_null<Window::SessionController*> sessionController);
|
||||
|
||||
class PeerListRowWithLink : public PeerListRow {
|
||||
public:
|
||||
using PeerListRow::PeerListRow;
|
||||
@@ -203,8 +207,7 @@ public:
|
||||
|
||||
protected:
|
||||
void prepareViewHook() override;
|
||||
std::unique_ptr<Row> createRow(
|
||||
not_null<History*> history) override;
|
||||
std::unique_ptr<Row> createRow(not_null<History*> history) override;
|
||||
|
||||
private:
|
||||
const not_null<Window::SessionNavigation*> _navigation;
|
||||
|
||||
@@ -576,11 +576,7 @@ void AddSpecialBoxController::showAdmin(
|
||||
}
|
||||
|
||||
// Finally show the admin.
|
||||
const auto currentRights = _additional.isCreator(user)
|
||||
? MTPChatAdminRights(MTP_chatAdminRights(
|
||||
MTP_flags(~MTPDchatAdminRights::Flag::f_add_admins
|
||||
| MTPDchatAdminRights::Flag::f_add_admins)))
|
||||
: adminRights
|
||||
const auto currentRights = adminRights
|
||||
? *adminRights
|
||||
: MTPChatAdminRights(MTP_chatAdminRights(MTP_flags(0)));
|
||||
auto box = Box<EditAdminBox>(
|
||||
@@ -618,6 +614,7 @@ void AddSpecialBoxController::editAdminDone(
|
||||
_additional.applyParticipant(MTP_channelParticipantCreator(
|
||||
MTP_flags(rank.isEmpty() ? Flag(0) : Flag::f_rank),
|
||||
MTP_int(user->bareId()),
|
||||
rights,
|
||||
MTP_string(rank)));
|
||||
} else if (rights.c_chatAdminRights().vflags().v == 0) {
|
||||
_additional.applyParticipant(MTP_channelParticipant(
|
||||
@@ -665,7 +662,7 @@ void AddSpecialBoxController::showRestricted(
|
||||
} else if (_additional.adminRights(user).has_value()
|
||||
|| _additional.isCreator(user)) {
|
||||
// The user is an admin or creator.
|
||||
if (_additional.canEditAdmin(user)) {
|
||||
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
|
||||
if (!sure) {
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
@@ -755,7 +752,7 @@ void AddSpecialBoxController::kickUser(
|
||||
if (_additional.adminRights(user).has_value()
|
||||
|| _additional.isCreator(user)) {
|
||||
// The user is an admin or creator.
|
||||
if (_additional.canEditAdmin(user)) {
|
||||
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
|
||||
if (!sure) {
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
|
||||
@@ -146,15 +146,12 @@ void Controller::choose(not_null<ChannelData*> chat) {
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
}
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto sure = [=] {
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
const auto sure = [=](Fn<void()> &&close) {
|
||||
close();
|
||||
const auto onstack = _callback;
|
||||
onstack(chat);
|
||||
};
|
||||
*box = Ui::show(
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
text,
|
||||
tr::lng_manage_discussion_group_link(tr::now),
|
||||
@@ -178,18 +175,15 @@ void Controller::choose(not_null<ChatData*> chat) {
|
||||
text.append(tr::lng_manage_discussion_group_warning(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue));
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto sure = [=] {
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
const auto sure = [=](Fn<void()> &&close) {
|
||||
close();
|
||||
const auto done = [=](not_null<ChannelData*> chat) {
|
||||
const auto onstack = _callback;
|
||||
onstack(chat);
|
||||
};
|
||||
chat->session().api().migrateChat(chat, crl::guard(this, done));
|
||||
};
|
||||
*box = Ui::show(
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
text,
|
||||
tr::lng_manage_discussion_group_link(tr::now),
|
||||
|
||||
@@ -47,70 +47,6 @@ constexpr auto kSecondsInDay = 24 * 60 * 60;
|
||||
constexpr auto kSecondsInWeek = 7 * kSecondsInDay;
|
||||
constexpr auto kAdminRoleLimit = 16;
|
||||
|
||||
enum class PasswordErrorType {
|
||||
None,
|
||||
NoPassword,
|
||||
Later,
|
||||
};
|
||||
|
||||
void SetCloudPassword(not_null<Ui::GenericBox*> box, not_null<UserData*> user) {
|
||||
user->session().api().passwordState(
|
||||
) | rpl::start_with_next([=] {
|
||||
using namespace Settings;
|
||||
const auto weak = Ui::MakeWeak(box);
|
||||
if (CheckEditCloudPassword(&user->session())) {
|
||||
box->getDelegate()->show(
|
||||
EditCloudPasswordBox(&user->session()));
|
||||
} else {
|
||||
box->getDelegate()->show(CloudPasswordAppOutdatedBox());
|
||||
}
|
||||
if (weak) {
|
||||
weak->closeBox();
|
||||
}
|
||||
}, box->lifetime());
|
||||
}
|
||||
|
||||
void TransferPasswordError(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<UserData*> user,
|
||||
PasswordErrorType error) {
|
||||
box->setTitle(tr::lng_rights_transfer_check());
|
||||
box->setWidth(st::transferCheckWidth);
|
||||
|
||||
auto text = tr::lng_rights_transfer_check_about(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(user->shortName()),
|
||||
Ui::Text::WithEntities
|
||||
).append('\n').append('\n').append(
|
||||
tr::lng_rights_transfer_check_password(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue)
|
||||
).append('\n').append('\n').append(
|
||||
tr::lng_rights_transfer_check_session(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue)
|
||||
);
|
||||
if (error == PasswordErrorType::Later) {
|
||||
text.append('\n').append('\n').append(
|
||||
tr::lng_rights_transfer_check_later(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
box->addRow(object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
rpl::single(text),
|
||||
st::boxLabel));
|
||||
if (error == PasswordErrorType::Later) {
|
||||
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
|
||||
} else {
|
||||
box->addButton(tr::lng_rights_transfer_set_password(), [=] {
|
||||
SetCloudPassword(box, user);
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class EditParticipantBox::Inner : public Ui::RpWidget {
|
||||
@@ -318,7 +254,7 @@ void EditAdminBox::prepare() {
|
||||
|
||||
const auto disabledMessages = [&] {
|
||||
auto result = std::map<Flags, QString>();
|
||||
if (!canSave() || (amCreator() && user()->isSelf())) {
|
||||
if (!canSave()) {
|
||||
result.emplace(
|
||||
~Flags(0),
|
||||
tr::lng_rights_about_admin_cant_edit(tr::now));
|
||||
@@ -327,7 +263,11 @@ void EditAdminBox::prepare() {
|
||||
disabledByDefaults,
|
||||
tr::lng_rights_permission_for_all(tr::now));
|
||||
if (const auto channel = peer()->asChannel()) {
|
||||
if (!channel->amCreator()) {
|
||||
if (amCreator() && user()->isSelf()) {
|
||||
result.emplace(
|
||||
~Flag::f_anonymous,
|
||||
tr::lng_rights_permission_cant_edit(tr::now));
|
||||
} else if (!channel->amCreator()) {
|
||||
result.emplace(
|
||||
~channel->adminRights(),
|
||||
tr::lng_rights_permission_cant_edit(tr::now));
|
||||
@@ -368,7 +308,7 @@ void EditAdminBox::prepare() {
|
||||
}, lifetime());
|
||||
|
||||
if (canTransferOwnership()) {
|
||||
const auto allFlags = FullAdminRights(isGroup);
|
||||
const auto allFlags = AdminRightsForOwnershipTransfer(isGroup);
|
||||
setupTransferButton(
|
||||
isGroup
|
||||
)->toggleOn(rpl::duplicate(
|
||||
@@ -520,22 +460,17 @@ void EditAdminBox::transferOwnership() {
|
||||
}
|
||||
|
||||
bool EditAdminBox::handleTransferPasswordError(const RPCError &error) {
|
||||
const auto type = [&] {
|
||||
const auto &type = error.type();
|
||||
if (type == qstr("PASSWORD_MISSING")) {
|
||||
return PasswordErrorType::NoPassword;
|
||||
} else if (type.startsWith(qstr("PASSWORD_TOO_FRESH_"))
|
||||
|| type.startsWith(qstr("SESSION_TOO_FRESH_"))) {
|
||||
return PasswordErrorType::Later;
|
||||
}
|
||||
return PasswordErrorType::None;
|
||||
}();
|
||||
if (type == PasswordErrorType::None) {
|
||||
return false;
|
||||
const auto session = &user()->session();
|
||||
auto about = tr::lng_rights_transfer_check_about(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(user()->shortName()),
|
||||
Ui::Text::WithEntities);
|
||||
if (auto box = PrePasswordErrorBox(error, session, std::move(about))) {
|
||||
getDelegate()->show(std::move(box));
|
||||
return true;
|
||||
}
|
||||
|
||||
getDelegate()->show(Box(TransferPasswordError, user(), type));
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditAdminBox::transferOwnershipChecked() {
|
||||
@@ -639,7 +574,9 @@ void EditAdminBox::sendTransferRequestFrom(
|
||||
|
||||
void EditAdminBox::refreshAboutAddAdminsText(bool canAddAdmins) {
|
||||
_aboutAddAdmins->setText([&] {
|
||||
if (!canSave() || (amCreator() && user()->isSelf())) {
|
||||
if (amCreator() && user()->isSelf()) {
|
||||
return QString();
|
||||
} else if (!canSave()) {
|
||||
return tr::lng_rights_about_admin_cant_edit(tr::now);
|
||||
} else if (canAddAdmins) {
|
||||
return tr::lng_rights_about_add_admins_yes(tr::now);
|
||||
|
||||
@@ -564,6 +564,12 @@ UserData *ParticipantsAdditionalData::applyCreator(
|
||||
const MTPDchannelParticipantCreator &data) {
|
||||
if (const auto user = applyRegular(data.vuser_id())) {
|
||||
_creator = user;
|
||||
_adminRights[user] = data.vadmin_rights();
|
||||
if (user->isSelf()) {
|
||||
_adminCanEdit.emplace(user);
|
||||
} else {
|
||||
_adminCanEdit.erase(user);
|
||||
}
|
||||
if (const auto rank = data.vrank()) {
|
||||
_adminRanks[user] = qs(*rank);
|
||||
} else {
|
||||
@@ -1459,11 +1465,7 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
|
||||
|
||||
void ParticipantsBoxController::showAdmin(not_null<UserData*> user) {
|
||||
const auto adminRights = _additional.adminRights(user);
|
||||
const auto currentRights = _additional.isCreator(user)
|
||||
? MTPChatAdminRights(MTP_chatAdminRights(
|
||||
MTP_flags(~MTPDchatAdminRights::Flag::f_add_admins
|
||||
| MTPDchatAdminRights::Flag::f_add_admins)))
|
||||
: adminRights
|
||||
const auto currentRights = adminRights
|
||||
? *adminRights
|
||||
: MTPChatAdminRights(MTP_chatAdminRights(MTP_flags(0)));
|
||||
auto box = Box<EditAdminBox>(
|
||||
@@ -1504,6 +1506,7 @@ void ParticipantsBoxController::editAdminDone(
|
||||
_additional.applyParticipant(MTP_channelParticipantCreator(
|
||||
MTP_flags(rank.isEmpty() ? Flag(0) : Flag::f_rank),
|
||||
MTP_int(user->bareId()),
|
||||
rights,
|
||||
MTP_string(rank)));
|
||||
} else if (rights.c_chatAdminRights().vflags().v == 0) {
|
||||
_additional.applyParticipant(MTP_channelParticipant(
|
||||
@@ -1783,6 +1786,7 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
|
||||
auto row = std::make_unique<PeerListRowWithLink>(user);
|
||||
refreshCustomStatus(row.get());
|
||||
if (_role == Role::Admins
|
||||
&& !_additional.isCreator(user)
|
||||
&& _additional.adminRights(user).has_value()
|
||||
&& _additional.canEditAdmin(user)) {
|
||||
row->setActionLink(tr::lng_profile_kick(tr::now));
|
||||
|
||||
@@ -135,6 +135,7 @@ std::vector<std::pair<ChatAdminRights, QString>> AdminRightLabels(
|
||||
? tr::lng_rights_group_invite_link(tr::now)
|
||||
: tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::f_pin_messages, tr::lng_rights_group_pin(tr::now) },
|
||||
{ Flag::f_anonymous, tr::lng_rights_group_anonymous(tr::now) },
|
||||
{ Flag::f_add_admins, tr::lng_rights_add_admins(tr::now) },
|
||||
};
|
||||
} else {
|
||||
@@ -297,10 +298,12 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) {
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
ChatAdminRights FullAdminRights(bool isGroup) {
|
||||
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup) {
|
||||
auto result = ChatAdminRights();
|
||||
for (const auto &[flag, label] : AdminRightLabels(isGroup, true)) {
|
||||
result |= flag;
|
||||
if (!(flag & ChatAdminRight::f_anonymous)) {
|
||||
result |= flag;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -71,4 +71,4 @@ EditFlagsControl<MTPDchatAdminRights::Flags> CreateEditAdminRights(
|
||||
|
||||
ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer);
|
||||
ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions);
|
||||
ChatAdminRights FullAdminRights(bool isGroup);
|
||||
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup);
|
||||
|
||||
@@ -546,17 +546,14 @@ void Controller::revokeInviteLink() {
|
||||
}
|
||||
|
||||
void Controller::exportInviteLink(const QString &confirmation) {
|
||||
const auto boxPointer = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto callback = crl::guard(this, [=] {
|
||||
if (const auto strong = *boxPointer) {
|
||||
strong->closeBox();
|
||||
}
|
||||
const auto callback = crl::guard(this, [=](Fn<void()> &&close) {
|
||||
close();
|
||||
_peer->session().api().exportInviteLink(_peer->migrateToOrMe());
|
||||
});
|
||||
auto box = Box<ConfirmBox>(
|
||||
confirmation,
|
||||
std::move(callback));
|
||||
*boxPointer = Ui::show(std::move(box), Ui::LayerOption::KeepOther);
|
||||
Ui::show(std::move(box), Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
bool Controller::canEditInviteLink() const {
|
||||
|
||||
@@ -9,8 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "history/history_item.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
@@ -18,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwindow.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/application.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_profile.h"
|
||||
@@ -207,3 +211,18 @@ void ReportBox::updateMaxHeight() {
|
||||
}
|
||||
setDimensions(st::boxWidth, newHeight);
|
||||
}
|
||||
|
||||
void BlockSenderFromRepliesBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
FullMsgId id) {
|
||||
const auto item = controller->session().data().message(id);
|
||||
Assert(item != nullptr);
|
||||
|
||||
PeerMenuBlockUserBox(
|
||||
box,
|
||||
&controller->window(),
|
||||
item->senderOriginal(),
|
||||
true,
|
||||
Window::ClearReply{ id });
|
||||
}
|
||||
|
||||
@@ -8,8 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
template <typename Enum>
|
||||
class RadioenumGroup;
|
||||
@@ -60,3 +65,8 @@ private:
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
};
|
||||
|
||||
void BlockSenderFromRepliesBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
FullMsgId id);
|
||||
|
||||
@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/grouped_layout.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "ui/special_buttons.h"
|
||||
@@ -41,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/window_session_controller.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "layout.h"
|
||||
#include "facades.h" // App::LambdaDelayed.
|
||||
#include "app.h"
|
||||
#include "styles/style_history.h"
|
||||
@@ -352,7 +352,7 @@ AlbumThumb::AlbumThumb(
|
||||
} else {
|
||||
auto fileinfo = QFileInfo(filepath);
|
||||
_name = fileinfo.fileName();
|
||||
_status = formatSizeText(fileinfo.size());
|
||||
_status = Ui::FormatSizeText(fileinfo.size());
|
||||
}
|
||||
_nameWidth = st::semiboldFont->width(_name);
|
||||
if (_nameWidth > availableFileWidth) {
|
||||
@@ -766,11 +766,11 @@ SingleMediaPreview *SingleMediaPreview::Create(
|
||||
auto preview = QImage();
|
||||
bool animated = false;
|
||||
bool animationPreview = false;
|
||||
if (const auto image = base::get_if<FileMediaInformation::Image>(
|
||||
if (const auto image = std::get_if<FileMediaInformation::Image>(
|
||||
&file.information->media)) {
|
||||
preview = image->data;
|
||||
animated = animationPreview = image->animated;
|
||||
} else if (const auto video = base::get_if<FileMediaInformation::Video>(
|
||||
} else if (const auto video = std::get_if<FileMediaInformation::Video>(
|
||||
&file.information->media)) {
|
||||
preview = video->thumbnail;
|
||||
animated = true;
|
||||
@@ -1004,10 +1004,10 @@ void SingleFilePreview::prepareThumb(const QImage &preview) {
|
||||
|
||||
void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) {
|
||||
auto preview = QImage();
|
||||
if (const auto image = base::get_if<FileMediaInformation::Image>(
|
||||
if (const auto image = std::get_if<FileMediaInformation::Image>(
|
||||
&file.information->media)) {
|
||||
preview = image->data;
|
||||
} else if (const auto video = base::get_if<FileMediaInformation::Video>(
|
||||
} else if (const auto video = std::get_if<FileMediaInformation::Video>(
|
||||
&file.information->media)) {
|
||||
preview = video->thumbnail;
|
||||
}
|
||||
@@ -1034,7 +1034,7 @@ void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) {
|
||||
auto songTitle = QString();
|
||||
auto songPerformer = QString();
|
||||
if (file.information) {
|
||||
if (const auto song = base::get_if<FileMediaInformation::Song>(
|
||||
if (const auto song = std::get_if<FileMediaInformation::Song>(
|
||||
&file.information->media)) {
|
||||
songTitle = song->title;
|
||||
songPerformer = song->performer;
|
||||
@@ -1050,7 +1050,7 @@ void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) {
|
||||
st::semiboldTextStyle,
|
||||
nameString,
|
||||
Ui::NameTextOptions());
|
||||
_statusText = formatSizeText(fileinfo.size());
|
||||
_statusText = Ui::FormatSizeText(fileinfo.size());
|
||||
_statusWidth = qMax(
|
||||
_nameText.maxWidth(),
|
||||
st::normalFont->width(_statusText));
|
||||
|
||||
@@ -7,24 +7,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/sessions_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_authorizations.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -32,7 +31,63 @@ constexpr auto kSessionsShortPollTimeout = 60 * crl::time(1000);
|
||||
|
||||
} // namespace
|
||||
|
||||
class SessionsBox::List : public Ui::RpWidget {
|
||||
class SessionsContent : public Ui::RpWidget {
|
||||
public:
|
||||
SessionsContent(QWidget*, not_null<Main::Session*> session);
|
||||
|
||||
void setupContent();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
Entry() = default;
|
||||
Entry(const Api::Authorizations::Entry &entry)
|
||||
: hash(entry.hash)
|
||||
, incomplete(entry.incomplete)
|
||||
, activeTime(entry.activeTime)
|
||||
, name(st::sessionNameStyle, entry.name)
|
||||
, active(st::sessionWhenStyle, entry.active)
|
||||
, info(st::sessionInfoStyle, entry.info)
|
||||
, ip(st::sessionInfoStyle, entry.ip) {
|
||||
};
|
||||
|
||||
uint64 hash = 0;
|
||||
|
||||
bool incomplete = false;
|
||||
TimeId activeTime = 0;
|
||||
Ui::Text::String name, active, info, ip;
|
||||
};
|
||||
struct Full {
|
||||
Entry current;
|
||||
std::vector<Entry> incomplete;
|
||||
std::vector<Entry> list;
|
||||
};
|
||||
class Inner;
|
||||
class List;
|
||||
|
||||
void shortPollSessions();
|
||||
void parse(const Api::Authorizations::List &list);
|
||||
|
||||
void terminate(Fn<void()> terminateRequest, QString message);
|
||||
void terminateOne(uint64 hash);
|
||||
void terminateAll();
|
||||
|
||||
const not_null<Api::Authorizations*> _authorizations;
|
||||
|
||||
rpl::variable<bool> _loading = false;
|
||||
Full _data;
|
||||
|
||||
object_ptr<Inner> _inner;
|
||||
QPointer<ConfirmBox> _terminateBox;
|
||||
|
||||
base::Timer _shortPollTimer;
|
||||
|
||||
};
|
||||
|
||||
class SessionsContent::List : public Ui::RpWidget {
|
||||
public:
|
||||
List(QWidget *parent);
|
||||
|
||||
@@ -43,11 +98,20 @@ public:
|
||||
void terminating(uint64 hash, bool terminating);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
struct RowWidth {
|
||||
int available = 0;
|
||||
int info = 0;
|
||||
};
|
||||
RowWidth _rowWidth;
|
||||
|
||||
void computeRowWidth();
|
||||
|
||||
std::vector<Entry> _items;
|
||||
std::map<uint64, std::unique_ptr<Ui::IconButton>> _terminateButtons;
|
||||
rpl::event_stream<uint64> _terminate;
|
||||
@@ -55,7 +119,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class SessionsBox::Inner : public Ui::RpWidget {
|
||||
class SessionsContent::Inner : public Ui::RpWidget {
|
||||
public:
|
||||
Inner(QWidget *parent);
|
||||
|
||||
@@ -75,22 +139,21 @@ private:
|
||||
|
||||
};
|
||||
|
||||
SessionsBox::SessionsBox(QWidget*, not_null<Main::Session*> session)
|
||||
: _session(session)
|
||||
, _api(&_session->mtp())
|
||||
SessionsContent::SessionsContent(QWidget*, not_null<Main::Session*> session)
|
||||
: _authorizations(&session->api().authorizations())
|
||||
, _inner(this)
|
||||
, _shortPollTimer([=] { shortPollSessions(); }) {
|
||||
}
|
||||
|
||||
void SessionsBox::prepare() {
|
||||
setTitle(tr::lng_sessions_other_header());
|
||||
|
||||
addButton(tr::lng_close(), [=] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWideWidth, st::sessionsHeight);
|
||||
|
||||
_inner = setInnerWidget(object_ptr<Inner>(this), st::sessionsScroll);
|
||||
void SessionsContent::setupContent() {
|
||||
_inner->resize(width(), st::noContactsHeight);
|
||||
|
||||
_inner->heightValue(
|
||||
) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](int height) {
|
||||
resize(width(), height);
|
||||
}, _inner->lifetime());
|
||||
|
||||
_inner->terminateOne(
|
||||
) | rpl::start_with_next([=](uint64 hash) {
|
||||
terminateOne(hash);
|
||||
@@ -101,34 +164,58 @@ void SessionsBox::prepare() {
|
||||
terminateAll();
|
||||
}, lifetime());
|
||||
|
||||
_session->data().newAuthorizationChecks(
|
||||
) | rpl::start_with_next([=] {
|
||||
shortPollSessions();
|
||||
_loading.changes(
|
||||
) | rpl::start_with_next([=](bool value) {
|
||||
_inner->setVisible(!value);
|
||||
}, lifetime());
|
||||
|
||||
setLoading(true);
|
||||
_authorizations->listChanges(
|
||||
) | rpl::start_with_next([=](const Api::Authorizations::List &list) {
|
||||
parse(list);
|
||||
}, lifetime());
|
||||
|
||||
_loading = true;
|
||||
shortPollSessions();
|
||||
}
|
||||
|
||||
void SessionsBox::setLoading(bool loading) {
|
||||
if (_loading != loading) {
|
||||
_loading = loading;
|
||||
setInnerVisible(!_loading);
|
||||
void SessionsContent::parse(const Api::Authorizations::List &list) {
|
||||
if (list.empty()) {
|
||||
return;
|
||||
}
|
||||
_data = Full();
|
||||
for (const auto &auth : list) {
|
||||
auto entry = Entry(auth);
|
||||
if (!entry.hash) {
|
||||
_data.current = std::move(entry);
|
||||
} else if (entry.incomplete) {
|
||||
_data.incomplete.push_back(std::move(entry));
|
||||
} else {
|
||||
_data.list.push_back(std::move(entry));
|
||||
}
|
||||
}
|
||||
|
||||
_loading = false;
|
||||
|
||||
ranges::sort(_data.list, std::greater<>(), &Entry::activeTime);
|
||||
ranges::sort(_data.incomplete, std::greater<>(), &Entry::activeTime);
|
||||
|
||||
_inner->showData(_data);
|
||||
|
||||
_shortPollTimer.callOnce(kSessionsShortPollTimeout);
|
||||
}
|
||||
|
||||
void SessionsBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
void SessionsContent::resizeEvent(QResizeEvent *e) {
|
||||
RpWidget::resizeEvent(e);
|
||||
|
||||
_inner->resize(width(), _inner->height());
|
||||
}
|
||||
|
||||
void SessionsBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
void SessionsContent::paintEvent(QPaintEvent *e) {
|
||||
RpWidget::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
if (_loading) {
|
||||
if (_loading.current()) {
|
||||
p.setFont(st::noContactsFont);
|
||||
p.setPen(st::noContactsColor);
|
||||
p.drawText(
|
||||
@@ -138,166 +225,43 @@ void SessionsBox::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void SessionsBox::got(const MTPaccount_Authorizations &result) {
|
||||
_shortPollRequest = 0;
|
||||
setLoading(false);
|
||||
_data = Full();
|
||||
|
||||
result.match([&](const MTPDaccount_authorizations &data) {
|
||||
const auto &list = data.vauthorizations().v;
|
||||
for (const auto &auth : list) {
|
||||
auth.match([&](const MTPDauthorization &data) {
|
||||
auto entry = ParseEntry(data);
|
||||
if (!entry.hash) {
|
||||
_data.current = std::move(entry);
|
||||
} else if (entry.incomplete) {
|
||||
_data.incomplete.push_back(std::move(entry));
|
||||
} else {
|
||||
_data.list.push_back(std::move(entry));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const auto getActiveTime = [](const Entry &entry) {
|
||||
return entry.activeTime;
|
||||
};
|
||||
ranges::sort(_data.list, std::greater<>(), getActiveTime);
|
||||
ranges::sort(_data.incomplete, std::greater<>(), getActiveTime);
|
||||
|
||||
_inner->showData(_data);
|
||||
|
||||
_shortPollTimer.callOnce(kSessionsShortPollTimeout);
|
||||
}
|
||||
|
||||
SessionsBox::Entry SessionsBox::ParseEntry(const MTPDauthorization &data) {
|
||||
auto result = Entry();
|
||||
|
||||
result.hash = data.is_current() ? 0 : data.vhash().v;
|
||||
result.incomplete = data.is_password_pending();
|
||||
|
||||
auto appName = QString();
|
||||
auto appVer = qs(data.vapp_version());
|
||||
const auto systemVer = qs(data.vsystem_version());
|
||||
const auto deviceModel = qs(data.vdevice_model());
|
||||
const auto apiId = data.vapi_id().v;
|
||||
if (apiId == 2040 || apiId == 17349) {
|
||||
appName = (apiId == 2040)
|
||||
? qstr("Telegram Desktop")
|
||||
: qstr("Telegram Desktop (GitHub)");
|
||||
//if (systemVer == qstr("windows")) {
|
||||
// deviceModel = qsl("Windows");
|
||||
//} else if (systemVer == qstr("os x")) {
|
||||
// deviceModel = qsl("OS X");
|
||||
//} else if (systemVer == qstr("linux")) {
|
||||
// deviceModel = qsl("Linux");
|
||||
//}
|
||||
if (appVer == QString::number(appVer.toInt())) {
|
||||
const auto ver = appVer.toInt();
|
||||
appVer = QString("%1.%2"
|
||||
).arg(ver / 1000000
|
||||
).arg((ver % 1000000) / 1000)
|
||||
+ ((ver % 1000)
|
||||
? ('.' + QString::number(ver % 1000))
|
||||
: QString());
|
||||
//} else {
|
||||
// appVer = QString();
|
||||
}
|
||||
void SessionsContent::shortPollSessions() {
|
||||
const auto left = kSessionsShortPollTimeout
|
||||
- (crl::now() - _authorizations->lastReceivedTime());
|
||||
if (left > 0) {
|
||||
parse(_authorizations->list());
|
||||
_shortPollTimer.cancel();
|
||||
_shortPollTimer.callOnce(left);
|
||||
} else {
|
||||
appName = qs(data.vapp_name());// +qsl(" for ") + qs(d.vplatform());
|
||||
if (appVer.indexOf('(') >= 0) {
|
||||
appVer = appVer.mid(appVer.indexOf('('));
|
||||
}
|
||||
_authorizations->reload();
|
||||
}
|
||||
result.name = appName;
|
||||
if (!appVer.isEmpty()) {
|
||||
result.name += ' ' + appVer;
|
||||
}
|
||||
|
||||
const auto country = qs(data.vcountry());
|
||||
const auto platform = qs(data.vplatform());
|
||||
//const auto &countries = countriesByISO2();
|
||||
//const auto j = countries.constFind(country);
|
||||
//if (j != countries.cend()) {
|
||||
// country = QString::fromUtf8(j.value()->name);
|
||||
//}
|
||||
|
||||
result.activeTime = data.vdate_active().v
|
||||
? data.vdate_active().v
|
||||
: data.vdate_created().v;
|
||||
result.info = qs(data.vdevice_model()) + qstr(", ") + (platform.isEmpty() ? QString() : platform + ' ') + qs(data.vsystem_version());
|
||||
result.ip = qs(data.vip()) + (country.isEmpty() ? QString() : QString::fromUtf8(" \xe2\x80\x93 ") + country);
|
||||
if (!result.hash) {
|
||||
result.active = tr::lng_status_online(tr::now);
|
||||
result.activeWidth = st::sessionWhenFont->width(tr::lng_status_online(tr::now));
|
||||
} else {
|
||||
const auto now = QDateTime::currentDateTime();
|
||||
const auto lastTime = base::unixtime::parse(result.activeTime);
|
||||
const auto nowDate = now.date();
|
||||
const auto lastDate = lastTime.date();
|
||||
if (lastDate == nowDate) {
|
||||
result.active = lastTime.toString(cTimeFormat());
|
||||
} else if (lastDate.year() == nowDate.year()
|
||||
&& lastDate.weekNumber() == nowDate.weekNumber()) {
|
||||
result.active = langDayOfWeek(lastDate);
|
||||
} else {
|
||||
result.active = lastDate.toString(qsl("d.MM.yy"));
|
||||
}
|
||||
result.activeWidth = st::sessionWhenFont->width(result.active);
|
||||
}
|
||||
|
||||
ResizeEntry(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SessionsBox::ResizeEntry(Entry &entry) {
|
||||
const auto available = st::boxWideWidth
|
||||
- st::sessionPadding.left()
|
||||
- st::sessionTerminateSkip;
|
||||
const auto availableInList = available
|
||||
- st::sessionTerminate.iconPosition.x();
|
||||
const auto availableListInfo = available - st::sessionTerminate.width;
|
||||
|
||||
const auto resize = [](
|
||||
const style::font &font,
|
||||
QString &string,
|
||||
int &stringWidth,
|
||||
int available) {
|
||||
stringWidth = font->width(string);
|
||||
if (stringWidth > available) {
|
||||
string = font->elided(string, available);
|
||||
stringWidth = font->width(string);
|
||||
}
|
||||
};
|
||||
const auto forName = entry.hash ? availableInList : available;
|
||||
const auto forInfo = entry.hash ? availableListInfo : available;
|
||||
resize(st::sessionNameFont, entry.name, entry.nameWidth, forName);
|
||||
resize(st::sessionInfoFont, entry.info, entry.infoWidth, forInfo);
|
||||
resize(st::sessionInfoFont, entry.ip, entry.ipWidth, available);
|
||||
}
|
||||
|
||||
void SessionsBox::shortPollSessions() {
|
||||
if (_shortPollRequest) {
|
||||
return;
|
||||
}
|
||||
_shortPollRequest = _api.request(MTPaccount_GetAuthorizations(
|
||||
)).done([=](const MTPaccount_Authorizations &result) {
|
||||
got(result);
|
||||
}).send();
|
||||
update();
|
||||
}
|
||||
|
||||
void SessionsBox::terminateOne(uint64 hash) {
|
||||
if (_terminateBox) _terminateBox->deleteLater();
|
||||
void SessionsContent::terminate(Fn<void()> terminateRequest, QString message) {
|
||||
if (_terminateBox) {
|
||||
_terminateBox->deleteLater();
|
||||
}
|
||||
const auto callback = crl::guard(this, [=] {
|
||||
if (_terminateBox) {
|
||||
_terminateBox->closeBox();
|
||||
_terminateBox = nullptr;
|
||||
}
|
||||
_api.request(MTPaccount_ResetAuthorization(
|
||||
MTP_long(hash)
|
||||
)).done([=](const MTPBool &result) {
|
||||
terminateRequest();
|
||||
});
|
||||
_terminateBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
message,
|
||||
tr::lng_settings_reset_button(tr::now),
|
||||
st::attentionBoxButton,
|
||||
callback),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void SessionsContent::terminateOne(uint64 hash) {
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
auto callback = [=] {
|
||||
auto done = crl::guard(weak, [=](const MTPBool &result) {
|
||||
_inner->terminatingOne(hash, false);
|
||||
const auto getHash = [](const Entry &entry) {
|
||||
return entry.hash;
|
||||
@@ -310,52 +274,40 @@ void SessionsBox::terminateOne(uint64 hash) {
|
||||
removeByHash(_data.incomplete);
|
||||
removeByHash(_data.list);
|
||||
_inner->showData(_data);
|
||||
}).fail([=](const RPCError &error) {
|
||||
});
|
||||
auto fail = crl::guard(weak, [=](const RPCError &error) {
|
||||
_inner->terminatingOne(hash, false);
|
||||
}).send();
|
||||
});
|
||||
_authorizations->requestTerminate(
|
||||
std::move(done),
|
||||
std::move(fail),
|
||||
hash);
|
||||
_inner->terminatingOne(hash, true);
|
||||
});
|
||||
_terminateBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
tr::lng_settings_reset_one_sure(tr::now),
|
||||
tr::lng_settings_reset_button(tr::now),
|
||||
st::attentionBoxButton,
|
||||
callback),
|
||||
Ui::LayerOption::KeepOther);
|
||||
};
|
||||
terminate(std::move(callback), tr::lng_settings_reset_one_sure(tr::now));
|
||||
}
|
||||
|
||||
void SessionsBox::terminateAll() {
|
||||
if (_terminateBox) _terminateBox->deleteLater();
|
||||
const auto callback = crl::guard(this, [=] {
|
||||
if (_terminateBox) {
|
||||
_terminateBox->closeBox();
|
||||
_terminateBox = nullptr;
|
||||
}
|
||||
_api.request(MTPauth_ResetAuthorizations(
|
||||
)).done([=](const MTPBool &result) {
|
||||
_api.request(base::take(_shortPollRequest)).cancel();
|
||||
void SessionsContent::terminateAll() {
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
auto callback = [=] {
|
||||
const auto reset = crl::guard(weak, [=] {
|
||||
_authorizations->cancelCurrentRequest();
|
||||
shortPollSessions();
|
||||
}).fail([=](const RPCError &result) {
|
||||
_api.request(base::take(_shortPollRequest)).cancel();
|
||||
shortPollSessions();
|
||||
}).send();
|
||||
setLoading(true);
|
||||
});
|
||||
_terminateBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
tr::lng_settings_reset_sure(tr::now),
|
||||
tr::lng_settings_reset_button(tr::now),
|
||||
st::attentionBoxButton,
|
||||
callback),
|
||||
Ui::LayerOption::KeepOther);
|
||||
});
|
||||
_authorizations->requestTerminate(
|
||||
[=](const MTPBool &result) { reset(); },
|
||||
[=](const RPCError &result) { reset(); });
|
||||
_loading = true;
|
||||
};
|
||||
terminate(std::move(callback), tr::lng_settings_reset_sure(tr::now));
|
||||
}
|
||||
|
||||
SessionsBox::Inner::Inner(QWidget *parent)
|
||||
SessionsContent::Inner::Inner(QWidget *parent)
|
||||
: RpWidget(parent) {
|
||||
setupContent();
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::setupContent() {
|
||||
void SessionsContent::Inner::setupContent() {
|
||||
using namespace Settings;
|
||||
using namespace rpl::mappers;
|
||||
|
||||
@@ -418,32 +370,40 @@ void SessionsBox::Inner::setupContent() {
|
||||
Ui::ResizeFitChild(this, content);
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::showData(const Full &data) {
|
||||
void SessionsContent::Inner::showData(const Full &data) {
|
||||
_current->showData({ &data.current, &data.current + 1 });
|
||||
_list->showData(data.list);
|
||||
_incomplete->showData(data.incomplete);
|
||||
}
|
||||
|
||||
rpl::producer<> SessionsBox::Inner::terminateAll() const {
|
||||
rpl::producer<> SessionsContent::Inner::terminateAll() const {
|
||||
return _terminateAll->clicks() | rpl::to_empty;
|
||||
}
|
||||
|
||||
rpl::producer<uint64> SessionsBox::Inner::terminateOne() const {
|
||||
rpl::producer<uint64> SessionsContent::Inner::terminateOne() const {
|
||||
return rpl::merge(
|
||||
_incomplete->terminate(),
|
||||
_list->terminate());
|
||||
}
|
||||
|
||||
void SessionsBox::Inner::terminatingOne(uint64 hash, bool terminating) {
|
||||
void SessionsContent::Inner::terminatingOne(uint64 hash, bool terminating) {
|
||||
_incomplete->terminating(hash, terminating);
|
||||
_list->terminating(hash, terminating);
|
||||
}
|
||||
|
||||
SessionsBox::List::List(QWidget *parent) : RpWidget(parent) {
|
||||
SessionsContent::List::List(QWidget *parent) : RpWidget(parent) {
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
}
|
||||
|
||||
void SessionsBox::List::showData(gsl::span<const Entry> items) {
|
||||
void SessionsContent::List::resizeEvent(QResizeEvent *e) {
|
||||
RpWidget::resizeEvent(e);
|
||||
|
||||
computeRowWidth();
|
||||
}
|
||||
|
||||
void SessionsContent::List::showData(gsl::span<const Entry> items) {
|
||||
computeRowWidth();
|
||||
|
||||
auto buttons = base::take(_terminateButtons);
|
||||
_items.clear();
|
||||
_items.insert(begin(_items), items.begin(), items.end());
|
||||
@@ -466,24 +426,27 @@ void SessionsBox::List::showData(gsl::span<const Entry> items) {
|
||||
_terminate.fire_copy(hash);
|
||||
});
|
||||
button->show();
|
||||
button->moveToRight(
|
||||
st::sessionTerminateSkip,
|
||||
((_terminateButtons.size() - 1) * st::sessionHeight
|
||||
+ st::sessionTerminateTop));
|
||||
const auto number = _terminateButtons.size() - 1;
|
||||
widthValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
button->moveToRight(
|
||||
st::sessionTerminateSkip,
|
||||
(number * st::sessionHeight + st::sessionTerminateTop));
|
||||
}, lifetime());
|
||||
}
|
||||
resizeToWidth(width());
|
||||
_itemsCount.fire(_items.size());
|
||||
}
|
||||
|
||||
rpl::producer<int> SessionsBox::List::itemsCount() const {
|
||||
rpl::producer<int> SessionsContent::List::itemsCount() const {
|
||||
return _itemsCount.events_starting_with(_items.size());
|
||||
}
|
||||
|
||||
rpl::producer<uint64> SessionsBox::List::terminate() const {
|
||||
rpl::producer<uint64> SessionsContent::List::terminate() const {
|
||||
return _terminate.events();
|
||||
}
|
||||
|
||||
void SessionsBox::List::terminating(uint64 hash, bool terminating) {
|
||||
void SessionsContent::List::terminating(uint64 hash, bool terminating) {
|
||||
const auto i = _terminateButtons.find(hash);
|
||||
if (i != _terminateButtons.cend()) {
|
||||
if (terminating) {
|
||||
@@ -495,11 +458,21 @@ void SessionsBox::List::terminating(uint64 hash, bool terminating) {
|
||||
}
|
||||
}
|
||||
|
||||
int SessionsBox::List::resizeGetHeight(int newWidth) {
|
||||
int SessionsContent::List::resizeGetHeight(int newWidth) {
|
||||
return _items.size() * st::sessionHeight;
|
||||
}
|
||||
|
||||
void SessionsBox::List::paintEvent(QPaintEvent *e) {
|
||||
void SessionsContent::List::computeRowWidth() {
|
||||
const auto available = width()
|
||||
- st::sessionPadding.left()
|
||||
- st::sessionTerminateSkip;
|
||||
_rowWidth = {
|
||||
.available = available,
|
||||
.info = available - st::sessionTerminate.width,
|
||||
};
|
||||
}
|
||||
|
||||
void SessionsContent::List::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
@@ -513,6 +486,7 @@ void SessionsBox::List::paintEvent(QPaintEvent *e) {
|
||||
0,
|
||||
count);
|
||||
|
||||
const auto available = _rowWidth.available;
|
||||
const auto x = st::sessionPadding.left();
|
||||
const auto y = st::sessionPadding.top();
|
||||
const auto w = width();
|
||||
@@ -522,23 +496,66 @@ void SessionsBox::List::paintEvent(QPaintEvent *e) {
|
||||
for (auto i = from; i != till; ++i) {
|
||||
const auto &entry = _items[i];
|
||||
|
||||
p.setFont(st::sessionNameFont);
|
||||
const auto activeW = entry.active.maxWidth();
|
||||
const auto nameW = available
|
||||
- activeW
|
||||
- st::sessionNamePadding.right();
|
||||
const auto nameH = entry.name.style()->font->height;
|
||||
const auto infoW = entry.hash ? _rowWidth.info : available;
|
||||
const auto infoH = entry.info.style()->font->height;
|
||||
|
||||
p.setPen(entry.hash ? st::sessionWhenFg : st::contactsStatusFgOnline);
|
||||
entry.active.drawRight(p, xact, y, activeW, w);
|
||||
|
||||
p.setPen(st::sessionNameFg);
|
||||
p.drawTextLeft(x, y, w, entry.name, entry.nameWidth);
|
||||
entry.name.drawLeftElided(p, x, y, nameW, w);
|
||||
|
||||
p.setFont(st::sessionWhenFont);
|
||||
p.setPen(st::sessionWhenFg);
|
||||
p.drawTextRight(xact, y, w, entry.active, entry.activeWidth);
|
||||
|
||||
const auto name = st::sessionNameFont->height;
|
||||
p.setFont(st::sessionInfoFont);
|
||||
p.setPen(st::boxTextFg);
|
||||
p.drawTextLeft(x, y + name, w, entry.info, entry.infoWidth);
|
||||
entry.info.drawLeftElided(p, x, y + nameH, infoW, w);
|
||||
|
||||
const auto info = st::sessionInfoFont->height;
|
||||
p.setPen(st::sessionInfoFg);
|
||||
p.drawTextLeft(x, y + name + info, w, entry.ip, entry.ipWidth);
|
||||
entry.ip.drawLeftElided(p, x, y + nameH + infoH, available, w);
|
||||
|
||||
p.translate(0, st::sessionHeight);
|
||||
}
|
||||
}
|
||||
|
||||
SessionsBox::SessionsBox(QWidget*, not_null<Main::Session*> session)
|
||||
: _session(session) {
|
||||
}
|
||||
|
||||
void SessionsBox::prepare() {
|
||||
setTitle(tr::lng_sessions_other_header());
|
||||
|
||||
addButton(tr::lng_close(), [=] { closeBox(); });
|
||||
|
||||
const auto w = st::boxWideWidth;
|
||||
|
||||
const auto content = setInnerWidget(
|
||||
object_ptr<SessionsContent>(this, _session),
|
||||
st::sessionsScroll);
|
||||
content->resize(w, st::noContactsHeight);
|
||||
content->setupContent();
|
||||
|
||||
setDimensions(w, st::sessionsHeight);
|
||||
}
|
||||
|
||||
namespace Settings {
|
||||
|
||||
Sessions::Sessions(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller)
|
||||
: Section(parent) {
|
||||
setupContent(controller);
|
||||
}
|
||||
|
||||
void Sessions::setupContent(not_null<Window::SessionController*> controller) {
|
||||
const auto container = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
const auto content = container->add(
|
||||
object_ptr<SessionsContent>(container, &controller->session()));
|
||||
content->setupContent();
|
||||
|
||||
Ui::ResizeFitChild(this, container);
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
@@ -8,20 +8,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
class ConfirmBox;
|
||||
|
||||
namespace Ui {
|
||||
class IconButton;
|
||||
class LinkButton;
|
||||
} // namespace Ui
|
||||
#include "settings/settings_common.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Settings {
|
||||
|
||||
class Sessions : public Section {
|
||||
public:
|
||||
Sessions(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller);
|
||||
|
||||
private:
|
||||
void setupContent(not_null<Window::SessionController*> controller);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
class SessionsBox : public Ui::BoxContent {
|
||||
public:
|
||||
SessionsBox(QWidget*, not_null<Main::Session*> session);
|
||||
@@ -29,46 +36,7 @@ public:
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
uint64 hash = 0;
|
||||
|
||||
bool incomplete = false;
|
||||
TimeId activeTime = 0;
|
||||
int nameWidth, activeWidth, infoWidth, ipWidth;
|
||||
QString name, active, info, ip;
|
||||
};
|
||||
struct Full {
|
||||
Entry current;
|
||||
std::vector<Entry> incomplete;
|
||||
std::vector<Entry> list;
|
||||
};
|
||||
class Inner;
|
||||
class List;
|
||||
|
||||
static Entry ParseEntry(const MTPDauthorization &data);
|
||||
static void ResizeEntry(Entry &entry);
|
||||
void setLoading(bool loading);
|
||||
void shortPollSessions();
|
||||
|
||||
void got(const MTPaccount_Authorizations &result);
|
||||
|
||||
void terminateOne(uint64 hash);
|
||||
void terminateAll();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
||||
bool _loading = false;
|
||||
Full _data;
|
||||
|
||||
QPointer<Inner> _inner;
|
||||
QPointer<ConfirmBox> _terminateBox;
|
||||
|
||||
base::Timer _shortPollTimer;
|
||||
mtpRequestId _shortPollRequest = 0;
|
||||
|
||||
};
|
||||
|
||||
@@ -635,7 +635,11 @@ void ShareBox::Inner::updateChat(not_null<PeerData*> peer) {
|
||||
void ShareBox::Inner::updateChatName(
|
||||
not_null<Chat*> chat,
|
||||
not_null<PeerData*> peer) {
|
||||
const auto text = peer->isSelf() ? tr::lng_saved_messages(tr::now) : peer->name;
|
||||
const auto text = peer->isSelf()
|
||||
? tr::lng_saved_messages(tr::now)
|
||||
: peer->isRepliesChat()
|
||||
? tr::lng_replies_messages(tr::now)
|
||||
: peer->name;
|
||||
chat->name.setText(st::shareNameStyle, text, Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/image/image_location_factory.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "lottie/lottie_multi_player.h"
|
||||
#include "lottie/lottie_animation.h"
|
||||
#include "chat_helpers/stickers_lottie.h"
|
||||
@@ -36,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "app.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
@@ -189,11 +192,10 @@ void StickerSetBox::addStickers() {
|
||||
_inner->install();
|
||||
}
|
||||
|
||||
void StickerSetBox::shareStickers() {
|
||||
void StickerSetBox::copyStickersLink() {
|
||||
const auto url = _controller->session().createInternalLinkFull(
|
||||
qsl("addstickers/") + _inner->shortName());
|
||||
QGuiApplication::clipboard()->setText(url);
|
||||
Ui::show(Box<InformBox>(tr::lng_stickers_copied(tr::now)));
|
||||
}
|
||||
|
||||
void StickerSetBox::updateTitleAndButtons() {
|
||||
@@ -207,10 +209,33 @@ void StickerSetBox::updateButtons() {
|
||||
if (_inner->notInstalled()) {
|
||||
addButton(tr::lng_stickers_add_pack(), [=] { addStickers(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
if (!_inner->shortName().isEmpty()) {
|
||||
const auto top = addTopButton(st::infoTopBarMenu);
|
||||
const auto share = [=] {
|
||||
copyStickersLink();
|
||||
Ui::Toast::Show(tr::lng_stickers_copied(tr::now));
|
||||
closeBox();
|
||||
};
|
||||
const auto menu =
|
||||
std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
|
||||
top->setClickedCallback([=] {
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(top);
|
||||
(*menu)->addAction(
|
||||
tr::lng_stickers_share_pack(tr::now),
|
||||
share);
|
||||
(*menu)->popup(QCursor::pos());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
} else if (_inner->official()) {
|
||||
addButton(tr::lng_about_done(), [=] { closeBox(); });
|
||||
} else {
|
||||
addButton(tr::lng_stickers_share_pack(), [=] { shareStickers(); });
|
||||
auto share = [=] {
|
||||
copyStickersLink();
|
||||
Ui::Toast::Show(tr::lng_stickers_copied(tr::now));
|
||||
};
|
||||
addButton(tr::lng_stickers_share_pack(), std::move(share));
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -41,7 +41,7 @@ private:
|
||||
void updateTitleAndButtons();
|
||||
void updateButtons();
|
||||
void addStickers();
|
||||
void shareStickers();
|
||||
void copyStickersLink();
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
MTPInputStickerSet _set;
|
||||
|
||||
@@ -179,7 +179,7 @@ private:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
using SelectedRow = base::optional_variant<MegagroupSet, int>;
|
||||
using SelectedRow = std::variant<v::null_t, MegagroupSet, int>;
|
||||
class AddressField : public Ui::UsernameInput {
|
||||
public:
|
||||
using UsernameInput::UsernameInput;
|
||||
@@ -1101,7 +1101,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
|
||||
|
||||
if (_megagroupSet) {
|
||||
auto selectedIndex = [&] {
|
||||
if (auto index = base::get_if<int>(&_selected)) {
|
||||
if (auto index = std::get_if<int>(&_selected)) {
|
||||
return *index;
|
||||
}
|
||||
return -1;
|
||||
@@ -1341,7 +1341,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
if (_actionSel >= 0) {
|
||||
setActionDown(_actionSel);
|
||||
update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
|
||||
} else if (auto selectedIndex = base::get_if<int>(&_selected)) {
|
||||
} else if (auto selectedIndex = std::get_if<int>(&_selected)) {
|
||||
if (_section == Section::Installed && !_rows[*selectedIndex]->isRecentSet() && _inDragArea) {
|
||||
_above = _dragging = _started = *selectedIndex;
|
||||
_dragStart = mapFromGlobal(_mouse);
|
||||
@@ -1394,7 +1394,7 @@ void StickersBox::Inner::setSelected(SelectedRow selected) {
|
||||
return;
|
||||
}
|
||||
auto countSelectedIndex = [&] {
|
||||
if (auto index = base::get_if<int>(&_selected)) {
|
||||
if (auto index = std::get_if<int>(&_selected)) {
|
||||
return *index;
|
||||
}
|
||||
return -1;
|
||||
@@ -1416,7 +1416,7 @@ void StickersBox::Inner::setPressed(SelectedRow pressed) {
|
||||
return;
|
||||
}
|
||||
auto countPressedIndex = [&] {
|
||||
if (auto index = base::get_if<int>(&_pressed)) {
|
||||
if (auto index = std::get_if<int>(&_pressed)) {
|
||||
return *index;
|
||||
}
|
||||
return -1;
|
||||
@@ -1544,7 +1544,7 @@ void StickersBox::Inner::updateCursor() {
|
||||
? ((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel))
|
||||
? style::cur_pointer
|
||||
: style::cur_default)
|
||||
: (_selected.has_value() || _pressed.has_value())
|
||||
: (!v::is_null(_selected) || !v::is_null(_pressed))
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
}
|
||||
@@ -1582,7 +1582,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_dragging = _started = -1;
|
||||
} else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) {
|
||||
const auto selectedIndex = [&] {
|
||||
if (auto index = base::get_if<int>(&_selected)) {
|
||||
if (auto index = std::get_if<int>(&_selected)) {
|
||||
return *index;
|
||||
}
|
||||
return -1;
|
||||
@@ -1602,7 +1602,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
showSetByRow(*row);
|
||||
}
|
||||
}
|
||||
} else if (_megagroupSelectedSet && _selected.is<MegagroupSet>()) {
|
||||
} else if (_megagroupSelectedSet && v::is<MegagroupSet>(_selected)) {
|
||||
showSetByRow(*_megagroupSelectedSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,8 +272,11 @@ void BoxController::prepare() {
|
||||
}, lifetime());
|
||||
|
||||
session().changes().messageUpdates(
|
||||
Data::MessageUpdate::Flag::CallAdded
|
||||
) | rpl::start_with_next([=](const Data::MessageUpdate &update) {
|
||||
Data::MessageUpdate::Flag::NewAdded
|
||||
) | rpl::filter([=](const Data::MessageUpdate &update) {
|
||||
const auto media = update.item->media();
|
||||
return (media != nullptr) && (media->call() != nullptr);
|
||||
}) | rpl::start_with_next([=](const Data::MessageUpdate &update) {
|
||||
insertRow(update.item, InsertWay::Prepend);
|
||||
}, lifetime());
|
||||
|
||||
@@ -294,6 +297,7 @@ void BoxController::loadMoreRows() {
|
||||
MTP_inputPeerEmpty(),
|
||||
MTP_string(),
|
||||
MTP_inputUserEmpty(),
|
||||
MTPint(), // top_msg_id
|
||||
MTP_inputMessagesFilterPhoneCalls(MTP_flags(0)),
|
||||
MTP_int(0),
|
||||
MTP_int(0),
|
||||
|
||||
@@ -1082,7 +1082,8 @@ void Call::handleControllerError(const QString &error) {
|
||||
|
||||
void Call::destroyController() {
|
||||
if (_instance) {
|
||||
const auto state = _instance->stop();
|
||||
_instance->stop([](tgcalls::FinalState) {
|
||||
});
|
||||
|
||||
DEBUG_LOG(("Call Info: Destroying call controller.."));
|
||||
_instance.reset();
|
||||
|
||||
@@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/window.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/platform/ui_platform_utility.h"
|
||||
@@ -38,7 +39,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "platform/platform_specific.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "window/main_window.h"
|
||||
#include "layout.h"
|
||||
#include "app.h"
|
||||
#include "webrtc/webrtc_video_track.h"
|
||||
#include "styles/style_calls.h"
|
||||
@@ -1070,7 +1070,7 @@ void Panel::updateStatusText(State state) {
|
||||
auto durationMs = _call->getDurationMs();
|
||||
auto durationSeconds = durationMs / 1000;
|
||||
startDurationUpdateTimer(durationMs);
|
||||
return formatDurationText(durationSeconds);
|
||||
return Ui::FormatDurationText(durationSeconds);
|
||||
}
|
||||
return tr::lng_call_status_ended(tr::now);
|
||||
} break;
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "core/application.h"
|
||||
#include "calls/calls_call.h"
|
||||
@@ -20,7 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "base/timer.h"
|
||||
#include "layout.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_calls.h"
|
||||
#include "styles/style_layers.h"
|
||||
@@ -162,7 +162,7 @@ void TopBar::updateDurationText() {
|
||||
auto durationMs = _call->getDurationMs();
|
||||
auto durationSeconds = durationMs / 1000;
|
||||
startDurationUpdateTimer(durationMs);
|
||||
_durationLabel->setText(formatDurationText(durationSeconds));
|
||||
_durationLabel->setText(Ui::FormatDurationText(durationSeconds));
|
||||
if (_durationLabel->width() != wasWidth) {
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
@@ -569,7 +569,7 @@ std::vector<QString> EmojiKeywords::languages() {
|
||||
const auto yieldList = [&](const QStringList &list) {
|
||||
result.insert(end(result), list.begin(), list.end());
|
||||
};
|
||||
yield(Lang::Current().id());
|
||||
yield(Lang::Id());
|
||||
yield(Lang::DefaultLanguageId());
|
||||
yield(Lang::CurrentCloudManager().suggestedLanguage());
|
||||
yield(Platform::SystemLanguage());
|
||||
|
||||
@@ -263,8 +263,8 @@ void Row::paintRadio(Painter &p) {
|
||||
const auto loading = _loading
|
||||
? _loading->computeState()
|
||||
: Ui::RadialState{ 0., 0, FullArcLength };
|
||||
const auto isToggledSet = _state.current().is<Active>();
|
||||
const auto isActiveSet = isToggledSet || _state.current().is<Loading>();
|
||||
const auto isToggledSet = v::is<Active>(_state.current());
|
||||
const auto isActiveSet = isToggledSet || v::is<Loading>(_state.current());
|
||||
const auto toggled = _toggled.value(isToggledSet ? 1. : 0.);
|
||||
const auto active = _active.value(isActiveSet ? 1. : 0.);
|
||||
const auto _st = &st::defaultRadio;
|
||||
@@ -345,7 +345,7 @@ void Row::onStateChanged(State was, StateChangeSource source) {
|
||||
}
|
||||
|
||||
void Row::updateStatusColorOverride() {
|
||||
const auto isToggledSet = _state.current().is<Active>();
|
||||
const auto isToggledSet = v::is<Active>(_state.current());
|
||||
const auto toggled = _toggled.value(isToggledSet ? 1. : 0.);
|
||||
const auto over = showOver();
|
||||
if (toggled == 0. && !over) {
|
||||
@@ -373,7 +373,8 @@ void Row::setupContent(const Set &set) {
|
||||
});
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::filter([=](const SetState &state) {
|
||||
return !_state.current().is<Failed>() || !state.is<Available>();
|
||||
return !v::is<Failed>(_state.current())
|
||||
|| !v::is<Available>(state);
|
||||
});
|
||||
|
||||
setupLabels(set);
|
||||
@@ -390,9 +391,10 @@ void Row::setupHandler() {
|
||||
clicks(
|
||||
) | rpl::filter([=] {
|
||||
const auto &state = _state.current();
|
||||
return !_switching && (state.is<Ready>() || state.is<Available>());
|
||||
return !_switching && (v::is<Ready>(state)
|
||||
|| v::is<Available>(state));
|
||||
}) | rpl::start_with_next([=] {
|
||||
if (_state.current().is<Available>()) {
|
||||
if (v::is<Available>(_state.current())) {
|
||||
load();
|
||||
return;
|
||||
}
|
||||
@@ -409,7 +411,7 @@ void Row::setupHandler() {
|
||||
|
||||
_state.value(
|
||||
) | rpl::map([=](const SetState &state) {
|
||||
return state.is<Ready>() || state.is<Available>();
|
||||
return v::is<Ready>(state) || v::is<Available>(state);
|
||||
}) | rpl::start_with_next([=](bool active) {
|
||||
setDisabled(!active);
|
||||
setPointerCursor(active);
|
||||
@@ -463,7 +465,7 @@ void Row::setupPreview(const Set &set) {
|
||||
|
||||
void Row::updateLoadingToFinished() {
|
||||
_loading->update(
|
||||
_state.current().is<Failed>() ? 0. : 1.,
|
||||
v::is<Failed>(_state.current()) ? 0. : 1.,
|
||||
true,
|
||||
crl::now());
|
||||
}
|
||||
@@ -471,7 +473,7 @@ void Row::updateLoadingToFinished() {
|
||||
void Row::radialAnimationCallback(crl::time now) {
|
||||
const auto updated = [&] {
|
||||
const auto state = _state.current();
|
||||
if (const auto loading = base::get_if<Loading>(&state)) {
|
||||
if (const auto loading = std::get_if<Loading>(&state)) {
|
||||
return _loading->update(CountProgress(loading), false, now);
|
||||
} else {
|
||||
updateLoadingToFinished();
|
||||
@@ -493,7 +495,7 @@ void Row::setupAnimation() {
|
||||
|
||||
_state.value(
|
||||
) | rpl::map(
|
||||
_1 == Active()
|
||||
_1 == SetState{ Active() }
|
||||
) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
_toggled.start(
|
||||
@@ -505,7 +507,7 @@ void Row::setupAnimation() {
|
||||
|
||||
_state.value(
|
||||
) | rpl::map([](const SetState &state) {
|
||||
return state.is<Loading>() || state.is<Active>();
|
||||
return v::is<Loading>(state) || v::is<Active>(state);
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool active) {
|
||||
_active.start(
|
||||
@@ -517,7 +519,7 @@ void Row::setupAnimation() {
|
||||
|
||||
_state.value(
|
||||
) | rpl::map([](const SetState &state) {
|
||||
return base::get_if<Loading>(&state);
|
||||
return std::get_if<Loading>(&state);
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](const Loading *loading) {
|
||||
if (loading && !_loading) {
|
||||
|
||||
@@ -150,13 +150,26 @@ void EditLinkBox::prepare() {
|
||||
session);
|
||||
InitSpellchecker(_controller, text);
|
||||
|
||||
const auto url = content->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
const auto placeholder = content->add(
|
||||
object_ptr<Ui::RpWidget>(content),
|
||||
st::markdownLinkFieldPadding);
|
||||
placeholder->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
const auto url = Ui::AttachParentChild(
|
||||
content,
|
||||
object_ptr<Ui::MaskedInputField>(
|
||||
content,
|
||||
st::defaultInputField,
|
||||
tr::lng_formatting_link_url(),
|
||||
_startLink.trimmed()),
|
||||
st::markdownLinkFieldPadding);
|
||||
_startLink.trimmed()));
|
||||
url->heightValue(
|
||||
) | rpl::start_with_next([placeholder](int height) {
|
||||
placeholder->resize(placeholder->width(), height);
|
||||
}, placeholder->lifetime());
|
||||
placeholder->widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
url->resize(width, url->height());
|
||||
}, placeholder->lifetime());
|
||||
url->move(placeholder->pos());
|
||||
|
||||
const auto submit = [=] {
|
||||
const auto linkText = text->getLastText();
|
||||
@@ -178,7 +191,7 @@ void EditLinkBox::prepare() {
|
||||
connect(text, &Ui::InputField::submitted, [=] {
|
||||
url->setFocusFast();
|
||||
});
|
||||
connect(url, &Ui::InputField::submitted, [=] {
|
||||
connect(url, &Ui::MaskedInputField::submitted, [=] {
|
||||
if (text->getLastText().isEmpty()) {
|
||||
text->setFocusFast();
|
||||
} else {
|
||||
@@ -198,7 +211,11 @@ void EditLinkBox::prepare() {
|
||||
setDimensions(st::boxWidth, content->height());
|
||||
|
||||
_setInnerFocus = [=] {
|
||||
(_startText.isEmpty() ? text : url)->setFocusFast();
|
||||
if (_startText.isEmpty()) {
|
||||
text->setFocusFast();
|
||||
} else {
|
||||
url->setFocusFast();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ std::vector<int> DefaultLanguages() {
|
||||
append(method->locale());
|
||||
}
|
||||
append(QLocale(Platform::SystemLanguage()));
|
||||
append(QLocale(Lang::LanguageIdOrDefault(Lang::Current().id())));
|
||||
append(QLocale(Lang::LanguageIdOrDefault(Lang::Id())));
|
||||
|
||||
return langs;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ private:
|
||||
Search,
|
||||
Settings,
|
||||
};
|
||||
using OverState = base::variant<SpecialOver, int>;
|
||||
using OverState = std::variant<SpecialOver, int>;
|
||||
|
||||
template <typename Callback>
|
||||
void enumerateVisibleIcons(Callback callback);
|
||||
@@ -548,7 +548,7 @@ void StickersListWidget::Footer::mouseMoveEvent(QMouseEvent *e) {
|
||||
|
||||
if (!_iconsDragging
|
||||
&& !_icons.empty()
|
||||
&& base::get_if<int>(&_iconDown) != nullptr) {
|
||||
&& v::is<int>(_iconDown)) {
|
||||
if ((_iconsMousePos - _iconsMouseDown).manhattanLength() >= QApplication::startDragDistance()) {
|
||||
_iconsDragging = true;
|
||||
}
|
||||
@@ -579,7 +579,7 @@ void StickersListWidget::Footer::mouseReleaseEvent(QMouseEvent *e) {
|
||||
|
||||
updateSelected();
|
||||
if (wasDown == _iconOver) {
|
||||
if (const auto index = base::get_if<int>(&_iconOver)) {
|
||||
if (const auto index = std::get_if<int>(&_iconOver)) {
|
||||
_iconSelX = anim::value(
|
||||
*index * st::stickerIconWidth,
|
||||
*index * st::stickerIconWidth);
|
||||
@@ -604,7 +604,7 @@ bool StickersListWidget::Footer::eventHook(QEvent *e) {
|
||||
if (e->type() == QEvent::TouchBegin) {
|
||||
} else if (e->type() == QEvent::Wheel) {
|
||||
if (!_icons.empty()
|
||||
&& (base::get_if<int>(&_iconOver) != nullptr)
|
||||
&& v::is<int>(_iconOver)
|
||||
&& (_iconDown == SpecialOver::None)) {
|
||||
scrollByWheelEvent(static_cast<QWheelEvent*>(e));
|
||||
}
|
||||
@@ -635,7 +635,7 @@ void StickersListWidget::Footer::scrollByWheelEvent(
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::updateSelected() {
|
||||
if (_iconDown >= 0) {
|
||||
if (_iconDown != SpecialOver::None) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1509,8 +1509,10 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
||||
}
|
||||
|
||||
auto &sets = shownSets();
|
||||
auto selectedSticker = base::get_if<OverSticker>(&_selected);
|
||||
auto selectedButton = base::get_if<OverButton>(_pressed ? &_pressed : &_selected);
|
||||
auto selectedSticker = std::get_if<OverSticker>(&_selected);
|
||||
auto selectedButton = std::get_if<OverButton>(!v::is_null(_pressed)
|
||||
? &_pressed
|
||||
: &_selected);
|
||||
|
||||
if (sets.empty() && _section == Section::Search) {
|
||||
paintEmptySearchResults(p);
|
||||
@@ -1625,7 +1627,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
||||
if (clip.top() + clip.height() <= info.rowsTop) {
|
||||
return true;
|
||||
} else if (set.id == Data::Stickers::MegagroupSetId && set.stickers.empty()) {
|
||||
auto buttonSelected = (base::get_if<OverGroupAdd>(&_selected) != nullptr);
|
||||
auto buttonSelected = (std::get_if<OverGroupAdd>(&_selected) != nullptr);
|
||||
paintMegagroupEmptySet(p, info.rowsTop, buttonSelected);
|
||||
return true;
|
||||
}
|
||||
@@ -1971,20 +1973,20 @@ void StickersListWidget::mousePressEvent(QMouseEvent *e) {
|
||||
}
|
||||
|
||||
void StickersListWidget::setPressed(OverState newPressed) {
|
||||
if (auto button = base::get_if<OverButton>(&_pressed)) {
|
||||
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||
auto &sets = shownSets();
|
||||
Assert(button->section >= 0 && button->section < sets.size());
|
||||
auto &set = sets[button->section];
|
||||
if (set.ripple) {
|
||||
set.ripple->lastStop();
|
||||
}
|
||||
} else if (base::get_if<OverGroupAdd>(&_pressed)) {
|
||||
} else if (std::get_if<OverGroupAdd>(&_pressed)) {
|
||||
if (_megagroupSetButtonRipple) {
|
||||
_megagroupSetButtonRipple->lastStop();
|
||||
}
|
||||
}
|
||||
_pressed = newPressed;
|
||||
if (auto button = base::get_if<OverButton>(&_pressed)) {
|
||||
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||
auto &sets = shownSets();
|
||||
Assert(button->section >= 0 && button->section < sets.size());
|
||||
auto &set = sets[button->section];
|
||||
@@ -1992,7 +1994,7 @@ void StickersListWidget::setPressed(OverState newPressed) {
|
||||
set.ripple = createButtonRipple(button->section);
|
||||
}
|
||||
set.ripple->add(mapFromGlobal(QCursor::pos()) - buttonRippleTopLeft(button->section));
|
||||
} else if (base::get_if<OverGroupAdd>(&_pressed)) {
|
||||
} else if (std::get_if<OverGroupAdd>(&_pressed)) {
|
||||
if (!_megagroupSetButtonRipple) {
|
||||
auto maskSize = _megagroupSetButtonRect.size();
|
||||
auto mask = Ui::RippleAnimation::roundRectMask(maskSize, st::buttonRadius);
|
||||
@@ -2059,10 +2061,10 @@ void StickersListWidget::fillContextMenu(
|
||||
SendMenu::Type type) {
|
||||
auto selected = _selected;
|
||||
auto &sets = shownSets();
|
||||
if (!selected || _pressed) {
|
||||
if (v::is_null(selected) || !v::is_null(_pressed)) {
|
||||
return;
|
||||
}
|
||||
if (auto sticker = base::get_if<OverSticker>(&selected)) {
|
||||
if (auto sticker = std::get_if<OverSticker>(&selected)) {
|
||||
Assert(sticker->section >= 0 && sticker->section < sets.size());
|
||||
auto &set = sets[sticker->section];
|
||||
Assert(sticker->index >= 0 && sticker->index < set.stickers.size());
|
||||
@@ -2109,7 +2111,7 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_previewTimer.cancel();
|
||||
|
||||
auto pressed = _pressed;
|
||||
setPressed(std::nullopt);
|
||||
setPressed(v::null);
|
||||
if (pressed != _selected) {
|
||||
update();
|
||||
}
|
||||
@@ -2124,8 +2126,8 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
updateSelected();
|
||||
|
||||
auto &sets = shownSets();
|
||||
if (pressed && pressed == _selected) {
|
||||
if (auto sticker = base::get_if<OverSticker>(&pressed)) {
|
||||
if (!v::is_null(pressed) && pressed == _selected) {
|
||||
if (auto sticker = std::get_if<OverSticker>(&pressed)) {
|
||||
Assert(sticker->section >= 0 && sticker->section < sets.size());
|
||||
auto &set = sets[sticker->section];
|
||||
Assert(sticker->index >= 0 && sticker->index < set.stickers.size());
|
||||
@@ -2145,10 +2147,10 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
} else {
|
||||
_chosen.fire_copy({ .document = document });
|
||||
}
|
||||
} else if (auto set = base::get_if<OverSet>(&pressed)) {
|
||||
} else if (auto set = std::get_if<OverSet>(&pressed)) {
|
||||
Assert(set->section >= 0 && set->section < sets.size());
|
||||
displaySet(sets[set->section].id);
|
||||
} else if (auto button = base::get_if<OverButton>(&pressed)) {
|
||||
} else if (auto button = std::get_if<OverButton>(&pressed)) {
|
||||
Assert(button->section >= 0 && button->section < sets.size());
|
||||
if (sets[button->section].externalLayout) {
|
||||
installSet(sets[button->section].id);
|
||||
@@ -2159,7 +2161,7 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
} else {
|
||||
removeSet(sets[button->section].id);
|
||||
}
|
||||
} else if (base::get_if<OverGroupAdd>(&pressed)) {
|
||||
} else if (std::get_if<OverGroupAdd>(&pressed)) {
|
||||
Ui::show(Box<StickersBox>(controller(), _megagroupSet));
|
||||
}
|
||||
}
|
||||
@@ -2271,8 +2273,8 @@ void StickersListWidget::enterFromChildEvent(QEvent *e, QWidget *child) {
|
||||
}
|
||||
|
||||
void StickersListWidget::clearSelection() {
|
||||
setPressed(std::nullopt);
|
||||
setSelected(std::nullopt);
|
||||
setPressed(v::null);
|
||||
setSelected(v::null);
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -2750,11 +2752,11 @@ bool StickersListWidget::preventAutoHide() {
|
||||
}
|
||||
|
||||
void StickersListWidget::updateSelected() {
|
||||
if (_pressed && !_previewShown) {
|
||||
if (!v::is_null(_pressed) && !_previewShown) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto newSelected = OverState { std::nullopt };
|
||||
auto newSelected = OverState { v::null };
|
||||
auto p = mapFromGlobal(_lastMousePosition);
|
||||
if (!rect().contains(p)
|
||||
|| p.y() < getVisibleTop() || p.y() >= getVisibleBottom()
|
||||
@@ -2827,13 +2829,15 @@ bool StickersListWidget::stickerHasDeleteButton(const Set &set, int index) const
|
||||
|
||||
void StickersListWidget::setSelected(OverState newSelected) {
|
||||
if (_selected != newSelected) {
|
||||
setCursor(newSelected ? style::cur_pointer : style::cur_default);
|
||||
setCursor(!v::is_null(newSelected)
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
|
||||
auto &sets = shownSets();
|
||||
auto updateSelected = [&]() {
|
||||
if (auto sticker = base::get_if<OverSticker>(&_selected)) {
|
||||
if (auto sticker = std::get_if<OverSticker>(&_selected)) {
|
||||
rtlupdate(stickerRect(sticker->section, sticker->index));
|
||||
} else if (auto button = base::get_if<OverButton>(&_selected)) {
|
||||
} else if (auto button = std::get_if<OverButton>(&_selected)) {
|
||||
if (button->section >= 0
|
||||
&& button->section < sets.size()
|
||||
&& sets[button->section].externalLayout) {
|
||||
@@ -2841,7 +2845,7 @@ void StickersListWidget::setSelected(OverState newSelected) {
|
||||
} else {
|
||||
rtlupdate(removeButtonRect(button->section));
|
||||
}
|
||||
} else if (base::get_if<OverGroupAdd>(&_selected)) {
|
||||
} else if (std::get_if<OverGroupAdd>(&_selected)) {
|
||||
rtlupdate(megagroupSetButtonRectFinal());
|
||||
}
|
||||
};
|
||||
@@ -2850,7 +2854,7 @@ void StickersListWidget::setSelected(OverState newSelected) {
|
||||
updateSelected();
|
||||
|
||||
if (_previewShown && _pressed != _selected) {
|
||||
if (const auto sticker = base::get_if<OverSticker>(&_selected)) {
|
||||
if (const auto sticker = std::get_if<OverSticker>(&_selected)) {
|
||||
_pressed = _selected;
|
||||
Assert(sticker->section >= 0 && sticker->section < sets.size());
|
||||
const auto &set = sets[sticker->section];
|
||||
@@ -2865,7 +2869,7 @@ void StickersListWidget::setSelected(OverState newSelected) {
|
||||
}
|
||||
|
||||
void StickersListWidget::showPreview() {
|
||||
if (const auto sticker = base::get_if<OverSticker>(&_pressed)) {
|
||||
if (const auto sticker = std::get_if<OverSticker>(&_pressed)) {
|
||||
const auto &sets = shownSets();
|
||||
Assert(sticker->section >= 0 && sticker->section < sets.size());
|
||||
const auto &set = sets[sticker->section];
|
||||
|
||||
@@ -121,30 +121,46 @@ private:
|
||||
int section = 0;
|
||||
int index = 0;
|
||||
bool overDelete = false;
|
||||
|
||||
inline bool operator==(OverSticker other) const {
|
||||
return (section == other.section)
|
||||
&& (index == other.index)
|
||||
&& (overDelete == other.overDelete);
|
||||
}
|
||||
inline bool operator!=(OverSticker other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
struct OverSet {
|
||||
int section = 0;
|
||||
|
||||
inline bool operator==(OverSet other) const {
|
||||
return (section == other.section);
|
||||
}
|
||||
inline bool operator!=(OverSet other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
struct OverButton {
|
||||
int section = 0;
|
||||
|
||||
inline bool operator==(OverButton other) const {
|
||||
return (section == other.section);
|
||||
}
|
||||
inline bool operator!=(OverButton other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
struct OverGroupAdd {
|
||||
inline bool operator==(OverGroupAdd other) const {
|
||||
return true;
|
||||
}
|
||||
inline bool operator!=(OverGroupAdd other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
friend inline bool operator==(OverSticker a, OverSticker b) {
|
||||
return (a.section == b.section)
|
||||
&& (a.index == b.index)
|
||||
&& (a.overDelete == b.overDelete);
|
||||
}
|
||||
friend inline bool operator==(OverSet a, OverSet b) {
|
||||
return (a.section == b.section);
|
||||
}
|
||||
friend inline bool operator==(OverButton a, OverButton b) {
|
||||
return (a.section == b.section);
|
||||
}
|
||||
friend inline bool operator==(OverGroupAdd a, OverGroupAdd b) {
|
||||
return true;
|
||||
}
|
||||
using OverState = base::optional_variant<
|
||||
using OverState = std::variant<
|
||||
v::null_t,
|
||||
OverSticker,
|
||||
OverSet,
|
||||
OverButton,
|
||||
|
||||
@@ -53,6 +53,7 @@ generate({
|
||||
'ipPortSecret#37982646',
|
||||
'accessPointRule#4679b65f',
|
||||
'help.configSimple#5a592a6c',
|
||||
'messageReplies#81834865',
|
||||
],
|
||||
|
||||
'renamedTypes': {
|
||||
|
||||
@@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_translator.h"
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "lang/lang_hardcoded.h"
|
||||
#include "lang/lang_instance.h"
|
||||
#include "mainwidget.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "main/main_account.h"
|
||||
|
||||
@@ -98,20 +98,6 @@ std::map<int, const char*> BetaLogs() {
|
||||
};
|
||||
};
|
||||
|
||||
QString FormatVersionDisplay(int version) {
|
||||
return QString::number(version / 1000000)
|
||||
+ '.' + QString::number((version % 1000000) / 1000)
|
||||
+ ((version % 1000)
|
||||
? ('.' + QString::number(version % 1000))
|
||||
: QString());
|
||||
}
|
||||
|
||||
QString FormatVersionPrecise(int version) {
|
||||
return QString::number(version / 1000000)
|
||||
+ '.' + QString::number((version % 1000000) / 1000)
|
||||
+ '.' + QString::number(version % 1000);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Changelogs::Changelogs(not_null<Main::Session*> session, int oldVersion)
|
||||
@@ -216,4 +202,18 @@ void Changelogs::addBetaLog(int changeVersion, const char *changes) {
|
||||
addLocalLog(log);
|
||||
}
|
||||
|
||||
QString FormatVersionDisplay(int version) {
|
||||
return QString::number(version / 1000000)
|
||||
+ '.' + QString::number((version % 1000000) / 1000)
|
||||
+ ((version % 1000)
|
||||
? ('.' + QString::number(version % 1000))
|
||||
: QString());
|
||||
}
|
||||
|
||||
QString FormatVersionPrecise(int version) {
|
||||
return QString::number(version / 1000000)
|
||||
+ '.' + QString::number((version % 1000000) / 1000)
|
||||
+ '.' + QString::number(version % 1000);
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -15,6 +15,9 @@ class Session;
|
||||
|
||||
namespace Core {
|
||||
|
||||
[[nodiscard]] QString FormatVersionDisplay(int version);
|
||||
[[nodiscard]] QString FormatVersionPrecise(int version);
|
||||
|
||||
class Changelogs : public base::has_weak_ptr, private base::Subscriber {
|
||||
public:
|
||||
Changelogs(not_null<Main::Session*> session, int oldVersion);
|
||||
|
||||
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_item.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_session.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "facades.h"
|
||||
#include "app.h"
|
||||
|
||||
@@ -112,7 +113,11 @@ void MentionClickHandler::onClick(ClickContext context) const {
|
||||
const auto button = context.button;
|
||||
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
|
||||
if (const auto m = App::main()) { // multi good
|
||||
m->openPeerByName(_tag.mid(1), ShowAtProfileMsgId);
|
||||
using Info = Window::SessionNavigation::PeerByLinkInfo;
|
||||
m->controller()->showPeerByLink(Info{
|
||||
.usernameOrId = _tag.mid(1),
|
||||
.messageId = ShowAtProfileMsgId
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ CloudPasswordResult ComputeCheck(
|
||||
}
|
||||
|
||||
bytes::vector ComputeHash(
|
||||
std::nullopt_t,
|
||||
v::null_t,
|
||||
bytes::const_span password) {
|
||||
Unexpected("Bad secure secret algorithm.");
|
||||
}
|
||||
@@ -199,10 +199,10 @@ CloudPasswordCheckRequest ParseCloudPasswordCheckRequest(
|
||||
}
|
||||
|
||||
CloudPasswordAlgo ValidateNewCloudPasswordAlgo(CloudPasswordAlgo &&parsed) {
|
||||
if (!parsed.is<CloudPasswordAlgoModPow>()) {
|
||||
return std::nullopt;
|
||||
if (!v::is<CloudPasswordAlgoModPow>(parsed)) {
|
||||
return v::null;
|
||||
}
|
||||
auto &value = parsed.get_unchecked<CloudPasswordAlgoModPow>();
|
||||
auto &value = v::get<CloudPasswordAlgoModPow>(parsed);
|
||||
const auto already = value.salt1.size();
|
||||
value.salt1.resize(already + kAdditionalSalt);
|
||||
bytes::set_random(bytes::make_span(value.salt1).subspan(already));
|
||||
@@ -210,13 +210,13 @@ CloudPasswordAlgo ValidateNewCloudPasswordAlgo(CloudPasswordAlgo &&parsed) {
|
||||
}
|
||||
|
||||
MTPPasswordKdfAlgo PrepareCloudPasswordAlgo(const CloudPasswordAlgo &data) {
|
||||
return data.match([](const CloudPasswordAlgoModPow &data) {
|
||||
return v::match(data, [](const CloudPasswordAlgoModPow &data) {
|
||||
return MTP_passwordKdfAlgoModPow(
|
||||
MTP_bytes(data.salt1),
|
||||
MTP_bytes(data.salt2),
|
||||
MTP_int(data.g),
|
||||
MTP_bytes(data.p));
|
||||
}, [](std::nullopt_t) {
|
||||
}, [](v::null_t) {
|
||||
return MTP_passwordKdfAlgoUnknown();
|
||||
});
|
||||
}
|
||||
@@ -228,9 +228,9 @@ CloudPasswordResult::operator bool() const {
|
||||
bytes::vector ComputeCloudPasswordHash(
|
||||
const CloudPasswordAlgo &algo,
|
||||
bytes::const_span password) {
|
||||
return algo.match([&](const CloudPasswordAlgoModPow &data) {
|
||||
return v::match(algo, [&](const CloudPasswordAlgoModPow &data) {
|
||||
return ComputeHash(data, password);
|
||||
}, [](std::nullopt_t) -> bytes::vector {
|
||||
}, [](v::null_t) -> bytes::vector {
|
||||
Unexpected("Bad cloud password algorithm.");
|
||||
});
|
||||
}
|
||||
@@ -238,9 +238,9 @@ bytes::vector ComputeCloudPasswordHash(
|
||||
CloudPasswordDigest ComputeCloudPasswordDigest(
|
||||
const CloudPasswordAlgo &algo,
|
||||
bytes::const_span password) {
|
||||
return algo.match([&](const CloudPasswordAlgoModPow &data) {
|
||||
return v::match(algo, [&](const CloudPasswordAlgoModPow &data) {
|
||||
return ComputeDigest(data, password);
|
||||
}, [](std::nullopt_t) -> CloudPasswordDigest {
|
||||
}, [](v::null_t) -> CloudPasswordDigest {
|
||||
Unexpected("Bad cloud password algorithm.");
|
||||
});
|
||||
}
|
||||
@@ -248,9 +248,9 @@ CloudPasswordDigest ComputeCloudPasswordDigest(
|
||||
CloudPasswordResult ComputeCloudPasswordCheck(
|
||||
const CloudPasswordCheckRequest &request,
|
||||
bytes::const_span hash) {
|
||||
return request.algo.match([&](const CloudPasswordAlgoModPow &data) {
|
||||
return v::match(request.algo, [&](const CloudPasswordAlgoModPow &data) {
|
||||
return ComputeCheck(request, data, hash);
|
||||
}, [](std::nullopt_t) -> CloudPasswordResult {
|
||||
}, [](v::null_t) -> CloudPasswordResult {
|
||||
Unexpected("Bad cloud password algorithm.");
|
||||
});
|
||||
}
|
||||
@@ -270,10 +270,10 @@ SecureSecretAlgo ParseSecureSecretAlgo(
|
||||
}
|
||||
|
||||
SecureSecretAlgo ValidateNewSecureSecretAlgo(SecureSecretAlgo &&parsed) {
|
||||
if (!parsed.is<SecureSecretAlgoPBKDF2>()) {
|
||||
return std::nullopt;
|
||||
if (!v::is<SecureSecretAlgoPBKDF2>(parsed)) {
|
||||
return v::null;
|
||||
}
|
||||
auto &value = parsed.get_unchecked<SecureSecretAlgoPBKDF2>();
|
||||
auto &value = v::get<SecureSecretAlgoPBKDF2>(parsed);
|
||||
const auto already = value.salt.size();
|
||||
value.salt.resize(already + kAdditionalSalt);
|
||||
bytes::set_random(bytes::make_span(value.salt).subspan(already));
|
||||
@@ -282,12 +282,12 @@ SecureSecretAlgo ValidateNewSecureSecretAlgo(SecureSecretAlgo &&parsed) {
|
||||
|
||||
MTPSecurePasswordKdfAlgo PrepareSecureSecretAlgo(
|
||||
const SecureSecretAlgo &data) {
|
||||
return data.match([](const SecureSecretAlgoPBKDF2 &data) {
|
||||
return v::match(data, [](const SecureSecretAlgoPBKDF2 &data) {
|
||||
return MTP_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(
|
||||
MTP_bytes(data.salt));
|
||||
}, [](const SecureSecretAlgoSHA512 &data) {
|
||||
return MTP_securePasswordKdfAlgoSHA512(MTP_bytes(data.salt));
|
||||
}, [](std::nullopt_t) {
|
||||
}, [](v::null_t) {
|
||||
return MTP_securePasswordKdfAlgoUnknown();
|
||||
});
|
||||
}
|
||||
@@ -295,7 +295,7 @@ MTPSecurePasswordKdfAlgo PrepareSecureSecretAlgo(
|
||||
bytes::vector ComputeSecureSecretHash(
|
||||
const SecureSecretAlgo &algo,
|
||||
bytes::const_span password) {
|
||||
return algo.match([&](const auto &data) {
|
||||
return v::match(algo, [&](const auto &data) {
|
||||
return ComputeHash(data, password);
|
||||
});
|
||||
}
|
||||
@@ -317,4 +317,4 @@ CloudPasswordState ParseCloudPasswordState(
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
} // namespace Core
|
||||
|
||||
@@ -31,7 +31,7 @@ inline bool operator==(
|
||||
&& (a.p == b.p);
|
||||
}
|
||||
|
||||
using CloudPasswordAlgo = base::optional_variant<CloudPasswordAlgoModPow>;
|
||||
using CloudPasswordAlgo = std::variant<v::null_t, CloudPasswordAlgoModPow>;
|
||||
|
||||
CloudPasswordAlgo ParseCloudPasswordAlgo(const MTPPasswordKdfAlgo &data);
|
||||
CloudPasswordAlgo ValidateNewCloudPasswordAlgo(CloudPasswordAlgo &&parsed);
|
||||
@@ -43,7 +43,7 @@ struct CloudPasswordCheckRequest {
|
||||
CloudPasswordAlgo algo;
|
||||
|
||||
explicit operator bool() const {
|
||||
return !!algo;
|
||||
return !v::is_null(algo);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -106,7 +106,8 @@ inline bool operator==(
|
||||
return (a.salt == b.salt);
|
||||
}
|
||||
|
||||
using SecureSecretAlgo = base::optional_variant<
|
||||
using SecureSecretAlgo = std::variant<
|
||||
v::null_t,
|
||||
SecureSecretAlgoSHA512,
|
||||
SecureSecretAlgoPBKDF2>;
|
||||
|
||||
|
||||