Compare commits
290 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31f15a2f09 | ||
|
|
45b5e1241c | ||
|
|
43d42b54f8 | ||
|
|
090277d7a1 | ||
|
|
766b393295 | ||
|
|
b2d647b579 | ||
|
|
1ed6844247 | ||
|
|
5276e5b4ae | ||
|
|
6587f89db1 | ||
|
|
fb262b265b | ||
|
|
95074ef304 | ||
|
|
4ac93806aa | ||
|
|
92b3149cdd | ||
|
|
98c87d4a16 | ||
|
|
9a93d5811a | ||
|
|
759e3270cc | ||
|
|
746b72166f | ||
|
|
0292df12ef | ||
|
|
1e86c07505 | ||
|
|
47b6956be9 | ||
|
|
df8708ef1e | ||
|
|
20c0be0df6 | ||
|
|
cefdc29a7f | ||
|
|
70e9b4a332 | ||
|
|
08939ac51d | ||
|
|
b5d9947408 | ||
|
|
78f0cf908e | ||
|
|
93ae5e71f7 | ||
|
|
b8b268c7cc | ||
|
|
c991bbc7e3 | ||
|
|
45bbe33929 | ||
|
|
5aaa72e8cd | ||
|
|
57345cec3b | ||
|
|
fba17a8c25 | ||
|
|
70147922ae | ||
|
|
44cc3c7809 | ||
|
|
c50a5db277 | ||
|
|
389ea2af83 | ||
|
|
4cf9bf18e9 | ||
|
|
7bc4b2c595 | ||
|
|
9075489c18 | ||
|
|
d361f5c6b0 | ||
|
|
1f95e00793 | ||
|
|
3d8899b9dc | ||
|
|
dba9aa30f7 | ||
|
|
3626943fc9 | ||
|
|
1f6a9ab556 | ||
|
|
f7085b40b1 | ||
|
|
7222bc63f7 | ||
|
|
3dacbc6bf6 | ||
|
|
9dfa29ff0f | ||
|
|
a1e67b6177 | ||
|
|
03a687c200 | ||
|
|
847c01d605 | ||
|
|
ea10cf5758 | ||
|
|
159beb138a | ||
|
|
36d6682122 | ||
|
|
25f6bea66e | ||
|
|
80461bd9fe | ||
|
|
6148edbc7d | ||
|
|
3fa529d858 | ||
|
|
9117b3cdfa | ||
|
|
d4fe5f7a83 | ||
|
|
fa6725c54a | ||
|
|
f9976005f7 | ||
|
|
c6e1b14429 | ||
|
|
30681e2e58 | ||
|
|
c15ba7d23a | ||
|
|
94d5d20281 | ||
|
|
b776308fd7 | ||
|
|
2d37920a4c | ||
|
|
ee05e0af06 | ||
|
|
2efd735243 | ||
|
|
adb0a9b6f0 | ||
|
|
c9e24c2283 | ||
|
|
041c922451 | ||
|
|
01c1096c62 | ||
|
|
2b11e45692 | ||
|
|
6163e922b3 | ||
|
|
1613495425 | ||
|
|
455c7280a4 | ||
|
|
746f8d835d | ||
|
|
d66e9a1b00 | ||
|
|
8cca75da5c | ||
|
|
8d0ff1b61d | ||
|
|
dd856b9e4a | ||
|
|
eb5ba12ba3 | ||
|
|
e2c5995a2e | ||
|
|
ef10bb2bd6 | ||
|
|
64aa5480ad | ||
|
|
816f422e21 | ||
|
|
6c0dccd9ff | ||
|
|
c2b505b78c | ||
|
|
d8fb5be9b5 | ||
|
|
51b259fdea | ||
|
|
d532b65d1c | ||
|
|
bef35b9bc3 | ||
|
|
ae261fcede | ||
|
|
c04cdff7f7 | ||
|
|
466aa5a14d | ||
|
|
4aac633413 | ||
|
|
ad328d35a2 | ||
|
|
c5140f34a7 | ||
|
|
419f6345b3 | ||
|
|
c2c53df886 | ||
|
|
b3f73bb6a9 | ||
|
|
eda5cd47ad | ||
|
|
0c906a5e6d | ||
|
|
352768053d | ||
|
|
79b1cec4f3 | ||
|
|
8d09190439 | ||
|
|
5cd0a3719e | ||
|
|
8b7cd4a0c7 | ||
|
|
937c2d3dce | ||
|
|
1fa5d273cc | ||
|
|
24fa3dbf8f | ||
|
|
c9b782fd63 | ||
|
|
e7cf560da0 | ||
|
|
86e07518ad | ||
|
|
8c71d03959 | ||
|
|
967e86f4ab | ||
|
|
730412fefe | ||
|
|
576883ddc8 | ||
|
|
992d636680 | ||
|
|
8cdd2f113f | ||
|
|
d5f935b73d | ||
|
|
84f561b251 | ||
|
|
21ac2b8f3a | ||
|
|
1790828b01 | ||
|
|
792b9090a7 | ||
|
|
8c21fad642 | ||
|
|
5136cc3c9c | ||
|
|
b78b27f517 | ||
|
|
85760ea92c | ||
|
|
c2212c719e | ||
|
|
fc8a0d0efd | ||
|
|
c052c37621 | ||
|
|
21f7cec781 | ||
|
|
64af456d29 | ||
|
|
7751c4ac1f | ||
|
|
ececdcb9c0 | ||
|
|
cb8f49aea0 | ||
|
|
e3ef7d6631 | ||
|
|
21aa1f49d7 | ||
|
|
51e80170e2 | ||
|
|
b2526ab7f6 | ||
|
|
e220447bdd | ||
|
|
ead695b101 | ||
|
|
4ea72f8f89 | ||
|
|
4ef550da9b | ||
|
|
1e660fc2a2 | ||
|
|
6adf791b3b | ||
|
|
d2a41a42e0 | ||
|
|
315549b5f8 | ||
|
|
fd4a543bab | ||
|
|
d525e56053 | ||
|
|
dab5d1f994 | ||
|
|
de3b52425c | ||
|
|
844fd58a97 | ||
|
|
de2bad51d3 | ||
|
|
1424ea3540 | ||
|
|
a8efd0ef3d | ||
|
|
1204e282d3 | ||
|
|
6588242793 | ||
|
|
b1ba9a42c6 | ||
|
|
ab0d2bf9c6 | ||
|
|
80028e41f3 | ||
|
|
2c581adc55 | ||
|
|
f0e8c1e325 | ||
|
|
a2db9de4d7 | ||
|
|
a228c62286 | ||
|
|
37d940eca6 | ||
|
|
f7c24c54a1 | ||
|
|
19ce1edc16 | ||
|
|
21b10cebe0 | ||
|
|
50435f7783 | ||
|
|
1b789de4f4 | ||
|
|
a50310f0c1 | ||
|
|
eb02a7861a | ||
|
|
8759ca4577 | ||
|
|
d5c6d9a231 | ||
|
|
63f179e93e | ||
|
|
cfcc1b1ce7 | ||
|
|
da1945d0ca | ||
|
|
12252ef1aa | ||
|
|
1eef94e8d9 | ||
|
|
0984e631fa | ||
|
|
ec064a904d | ||
|
|
b47692e920 | ||
|
|
132f127f3f | ||
|
|
5c44b851fe | ||
|
|
2f5bed2899 | ||
|
|
cf76933352 | ||
|
|
eaa4c5e5b1 | ||
|
|
a4b5b6e370 | ||
|
|
c1be1ca4ae | ||
|
|
b2df781b76 | ||
|
|
38815c1ca8 | ||
|
|
2ec92f541c | ||
|
|
7ce8b42216 | ||
|
|
17511749de | ||
|
|
4f6c7657bf | ||
|
|
54085c70a4 | ||
|
|
e6c4b96c54 | ||
|
|
b75221737a | ||
|
|
c336d725ea | ||
|
|
d0fcc40d25 | ||
|
|
422bfd973b | ||
|
|
d4db679ce8 | ||
|
|
2c7d8858c0 | ||
|
|
155bbed3f4 | ||
|
|
b1517c68fb | ||
|
|
d206ba7e1d | ||
|
|
af100c2d13 | ||
|
|
1f25777929 | ||
|
|
a566405598 | ||
|
|
b02967a44e | ||
|
|
e0135e509d | ||
|
|
8274fddcbc | ||
|
|
82c45871c7 | ||
|
|
2164caaab7 | ||
|
|
f4b162cbaf | ||
|
|
4bc4584868 | ||
|
|
890a126423 | ||
|
|
42cc24e167 | ||
|
|
26b9146c32 | ||
|
|
ab6f5ae2ac | ||
|
|
559d4cf4da | ||
|
|
449f2d2f94 | ||
|
|
038f19d055 | ||
|
|
10d405aef4 | ||
|
|
efd4cceb19 | ||
|
|
822a3b69b5 | ||
|
|
a632798383 | ||
|
|
cca08e3946 | ||
|
|
4d267327b8 | ||
|
|
06798adce4 | ||
|
|
34c0d97c54 | ||
|
|
4b7f594b0e | ||
|
|
cfb43081c7 | ||
|
|
703ea9aacd | ||
|
|
de9b21e436 | ||
|
|
73c0ea4b7d | ||
|
|
3e681e5449 | ||
|
|
bc2f96251f | ||
|
|
15f83892a1 | ||
|
|
b6fafdd8f7 | ||
|
|
139b9723d7 | ||
|
|
d152782115 | ||
|
|
35356a1736 | ||
|
|
ef27670954 | ||
|
|
8cf9dc3319 | ||
|
|
59f2f750b4 | ||
|
|
8069fdd873 | ||
|
|
52721847f4 | ||
|
|
e492bbb883 | ||
|
|
7f20cc7b44 | ||
|
|
7fbce765c9 | ||
|
|
f771ad8cb1 | ||
|
|
6a53fc7edc | ||
|
|
889c3293e7 | ||
|
|
fa4b7145f5 | ||
|
|
a5be9d78d8 | ||
|
|
21c562fcb7 | ||
|
|
626c062bf0 | ||
|
|
e92ae40ecb | ||
|
|
ce256161f1 | ||
|
|
3bf9a1c70b | ||
|
|
3202a5f081 | ||
|
|
e99f650eaa | ||
|
|
c6097d3d11 | ||
|
|
58b5b3deec | ||
|
|
5a63428093 | ||
|
|
0c42bca111 | ||
|
|
13bf089672 | ||
|
|
f73264025d | ||
|
|
0a6fb696a3 | ||
|
|
bc2e6c4fd1 | ||
|
|
d822f8e9ff | ||
|
|
86362875dd | ||
|
|
0a4a96d4cd | ||
|
|
1c33eee80a | ||
|
|
4f5558d28c | ||
|
|
3fbd68cff9 | ||
|
|
ee8c6f68d7 | ||
|
|
8d4174afb5 | ||
|
|
9150cc77f9 | ||
|
|
8d31769846 | ||
|
|
13c00949ed | ||
|
|
c4d822ba02 |
2
.github/workflows/linux.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: scl enable devtoolset-9 -- bash --noprofile --norc -eo pipefail {0}
|
||||
shell: scl enable llvm-toolset-7.0 -- scl enable devtoolset-9 -- bash --noprofile --norc -eo pipefail {0}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
8
.github/workflows/lock.yml
vendored
@@ -13,11 +13,3 @@ jobs:
|
||||
github-token: ${{ github.token }}
|
||||
issue-lock-inactive-days: 45
|
||||
pr-lock-inactive-days: 45
|
||||
issue-lock-comment: >
|
||||
This issue has been automatically locked since there
|
||||
has not been any recent activity after it was closed.
|
||||
Please open a new issue for related bugs.
|
||||
pr-lock-comment: >
|
||||
This pull request has been automatically locked since there
|
||||
has not been any recent activity after it was closed.
|
||||
Please open a new issue for related bugs.
|
||||
|
||||
448
.github/workflows/mac.yml
vendored
@@ -13,7 +13,7 @@ on:
|
||||
- '!.github/workflows/mac.yml'
|
||||
- 'lib/xdg/**'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/build/docker/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -31,7 +31,7 @@ on:
|
||||
- '!.github/workflows/mac.yml'
|
||||
- 'lib/xdg/**'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/build/docker/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -49,19 +49,8 @@ jobs:
|
||||
defines:
|
||||
- ""
|
||||
env:
|
||||
MIN_MAC: "-mmacosx-version-min=10.12"
|
||||
UNGUARDED: "-Werror=unguarded-availability-new"
|
||||
GIT: "https://github.com"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.12"
|
||||
XZ: "xz-5.2.5"
|
||||
QT: "5_15_2"
|
||||
OPENSSL_VER: "1_1_1"
|
||||
LIBICONV_VER: "libiconv-1.16"
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
ONLY_CACHE: "false"
|
||||
MANUAL_CACHING: "2"
|
||||
DOC_PATH: "docs/building-mac.md"
|
||||
AUTO_CACHING: "1"
|
||||
|
||||
steps:
|
||||
- name: Get repository name.
|
||||
@@ -84,433 +73,23 @@ jobs:
|
||||
|
||||
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
||||
|
||||
xcodebuild -version > CACHE_KEY.txt
|
||||
echo $MIN_MAC >> CACHE_KEY.txt
|
||||
echo $MANUAL_CACHING >> CACHE_KEY.txt
|
||||
echo "$GITHUB_WORKSPACE" >> CACHE_KEY.txt
|
||||
if [ "$AUTO_CACHING" == "1" ]; then
|
||||
thisFile=$REPO_NAME/.github/workflows/mac.yml
|
||||
echo `md5 -q $thisFile` >> CACHE_KEY.txt
|
||||
fi
|
||||
echo "CACHE_KEY=`md5 -q CACHE_KEY.txt`" >> $GITHUB_ENV
|
||||
|
||||
echo "$PWD/Libraries/depot_tools" >> $GITHUB_PATH
|
||||
|
||||
mkdir -p Libraries
|
||||
cd Libraries
|
||||
echo "LibrariesPath=`pwd`" >> $GITHUB_ENV
|
||||
echo "PREFIX=`pwd`/local" >> $GITHUB_ENV
|
||||
echo "QT_PREFIX=`pwd`/local/Qt-5.15.2" >> $GITHUB_ENV
|
||||
|
||||
curl -o tg_owt-version.json https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master
|
||||
|
||||
- name: Patches.
|
||||
run: |
|
||||
echo "Find necessary commit from doc."
|
||||
checkoutCommit=$(grep -A 1 "cd patches" $REPO_NAME/$DOC_PATH | sed -n 2p)
|
||||
cd $LibrariesPath
|
||||
git clone $GIT/desktop-app/patches.git
|
||||
cd Patches
|
||||
eval $checkoutCommit
|
||||
|
||||
- name: XZ.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
wget https://tukaani.org/xz/$XZ.tar.gz
|
||||
tar -xvzf $XZ.tar.gz
|
||||
cd $XZ
|
||||
CFLAGS="$MIN_MAC" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
- name: Zlib.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone $GIT/desktop-app/zlib.git
|
||||
cd zlib
|
||||
CFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
- name: MozJPEG.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone -b v4.0.1-rc2 $GIT/mozilla/mozjpeg.git
|
||||
cd mozjpeg
|
||||
cmake -B build . \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=$PREFIX \
|
||||
-DWITH_JPEG8=ON \
|
||||
-DPNG_SUPPORTED=OFF
|
||||
cmake --build build -j$(nproc)
|
||||
cmake --install build
|
||||
|
||||
- name: OpenSSL cache.
|
||||
id: cache-openssl
|
||||
- name: ThirdParty cache.
|
||||
id: cache-third-party
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/openssl_${{ env.OPENSSL_VER }}
|
||||
key: ${{ runner.OS }}-${{ env.OPENSSL_VER }}-${{ env.CACHE_KEY }}
|
||||
- name: OpenSSL.
|
||||
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
path: ThirdParty
|
||||
key: ${{ runner.OS }}-third-party
|
||||
|
||||
git clone $GIT/openssl/openssl openssl
|
||||
cd openssl
|
||||
git checkout OpenSSL_"$OPENSSL_VER"-stable
|
||||
./Configure \
|
||||
--prefix=$PREFIX \
|
||||
no-tests \
|
||||
darwin64-x86_64-cc \
|
||||
-static \
|
||||
$MIN_MAC
|
||||
make build_libs -j$(nproc)
|
||||
|
||||
SSL_DIR=$LibrariesPath/openssl_$OPENSSL_VER
|
||||
mkdir -p $SSL_DIR/include
|
||||
copyLib() {
|
||||
cp $1.a $SSL_DIR/$1.a
|
||||
}
|
||||
copyLib libssl
|
||||
copyLib libcrypto
|
||||
cp -R include/. $SSL_DIR/include/
|
||||
|
||||
- name: Opus cache.
|
||||
id: cache-opus
|
||||
- name: Libraries cache.
|
||||
id: cache-libs
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/opus-cache
|
||||
key: ${{ runner.OS }}-opus-${{ env.CACHE_KEY }}
|
||||
- name: Opus.
|
||||
if: steps.cache-opus.outputs.cache-hit != 'true'
|
||||
path: Libraries
|
||||
key: ${{ runner.OS }}-libs
|
||||
|
||||
- name: Libraries.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone $GIT/xiph/opus
|
||||
cd opus
|
||||
git checkout v1.3
|
||||
./autogen.sh
|
||||
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
|
||||
make -j$(nproc)
|
||||
make DESTDIR="$LibrariesPath/opus-cache" install
|
||||
- name: Opus install.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
cp -R opus-cache/. /
|
||||
|
||||
- name: Rnnoise.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone $GIT/desktop-app/rnnoise.git
|
||||
mkdir -p rnnoise/out/Debug
|
||||
cd rnnoise/out/Debug
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../..
|
||||
ninja
|
||||
|
||||
- name: Libiconv cache.
|
||||
id: cache-libiconv
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/libiconv-cache
|
||||
key: ${{ runner.OS }}-${{ env.LIBICONV_VER }}-${{ env.CACHE_KEY }}
|
||||
- name: Libiconv.
|
||||
if: steps.cache-libiconv.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
wget https://ftp.gnu.org/pub/gnu/libiconv/"$LIBICONV_VER".tar.gz
|
||||
tar -xvzf "$LIBICONV_VER".tar.gz
|
||||
cd $LIBICONV_VER
|
||||
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --enable-static --prefix=$PREFIX
|
||||
make -j$(nproc)
|
||||
make DESTDIR="$LibrariesPath/libiconv-cache" install
|
||||
- name: Libiconv install.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
cp -R libiconv-cache/. /
|
||||
|
||||
- name: FFmpeg cache.
|
||||
id: cache-ffmpeg
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/ffmpeg-cache
|
||||
key: ${{ runner.OS }}-ffmpeg-${{ env.CACHE_KEY }}
|
||||
- name: FFmpeg.
|
||||
if: steps.cache-ffmpeg.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone $GIT/FFmpeg/FFmpeg.git ffmpeg
|
||||
cd ffmpeg
|
||||
git checkout release/4.4
|
||||
CFLAGS=`freetype-config --cflags`
|
||||
LDFLAGS=`freetype-config --libs`
|
||||
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:/usr/X11/lib/pkgconfig
|
||||
|
||||
./configure --prefix=$LibrariesPath/ffmpeg-cache \
|
||||
--extra-cflags="$MIN_MAC $UNGUARDED" \
|
||||
--extra-cxxflags="$MIN_MAC $UNGUARDED" \
|
||||
--extra-ldflags="$MIN_MAC" \
|
||||
--x86asmexe=`pwd`/macos_yasm_wrap.sh \
|
||||
--enable-protocol=file \
|
||||
--enable-libopus \
|
||||
--disable-programs \
|
||||
--disable-doc \
|
||||
--disable-network \
|
||||
--disable-everything \
|
||||
--enable-hwaccel=h264_videotoolbox \
|
||||
--enable-hwaccel=hevc_videotoolbox \
|
||||
--enable-hwaccel=mpeg1_videotoolbox \
|
||||
--enable-hwaccel=mpeg2_videotoolbox \
|
||||
--enable-hwaccel=mpeg4_videotoolbox \
|
||||
--enable-decoder=aac \
|
||||
--enable-decoder=aac_at \
|
||||
--enable-decoder=aac_fixed \
|
||||
--enable-decoder=aac_latm \
|
||||
--enable-decoder=aasc \
|
||||
--enable-decoder=alac \
|
||||
--enable-decoder=alac_at \
|
||||
--enable-decoder=flac \
|
||||
--enable-decoder=gif \
|
||||
--enable-decoder=h264 \
|
||||
--enable-decoder=hevc \
|
||||
--enable-decoder=mp1 \
|
||||
--enable-decoder=mp1float \
|
||||
--enable-decoder=mp2 \
|
||||
--enable-decoder=mp2float \
|
||||
--enable-decoder=mp3 \
|
||||
--enable-decoder=mp3adu \
|
||||
--enable-decoder=mp3adufloat \
|
||||
--enable-decoder=mp3float \
|
||||
--enable-decoder=mp3on4 \
|
||||
--enable-decoder=mp3on4float \
|
||||
--enable-decoder=mpeg4 \
|
||||
--enable-decoder=msmpeg4v2 \
|
||||
--enable-decoder=msmpeg4v3 \
|
||||
--enable-decoder=opus \
|
||||
--enable-decoder=pcm_alaw \
|
||||
--enable-decoder=pcm_alaw_at \
|
||||
--enable-decoder=pcm_f32be \
|
||||
--enable-decoder=pcm_f32le \
|
||||
--enable-decoder=pcm_f64be \
|
||||
--enable-decoder=pcm_f64le \
|
||||
--enable-decoder=pcm_lxf \
|
||||
--enable-decoder=pcm_mulaw \
|
||||
--enable-decoder=pcm_mulaw_at \
|
||||
--enable-decoder=pcm_s16be \
|
||||
--enable-decoder=pcm_s16be_planar \
|
||||
--enable-decoder=pcm_s16le \
|
||||
--enable-decoder=pcm_s16le_planar \
|
||||
--enable-decoder=pcm_s24be \
|
||||
--enable-decoder=pcm_s24daud \
|
||||
--enable-decoder=pcm_s24le \
|
||||
--enable-decoder=pcm_s24le_planar \
|
||||
--enable-decoder=pcm_s32be \
|
||||
--enable-decoder=pcm_s32le \
|
||||
--enable-decoder=pcm_s32le_planar \
|
||||
--enable-decoder=pcm_s64be \
|
||||
--enable-decoder=pcm_s64le \
|
||||
--enable-decoder=pcm_s8 \
|
||||
--enable-decoder=pcm_s8_planar \
|
||||
--enable-decoder=pcm_u16be \
|
||||
--enable-decoder=pcm_u16le \
|
||||
--enable-decoder=pcm_u24be \
|
||||
--enable-decoder=pcm_u24le \
|
||||
--enable-decoder=pcm_u32be \
|
||||
--enable-decoder=pcm_u32le \
|
||||
--enable-decoder=pcm_u8 \
|
||||
--enable-decoder=vorbis \
|
||||
--enable-decoder=wavpack \
|
||||
--enable-decoder=wmalossless \
|
||||
--enable-decoder=wmapro \
|
||||
--enable-decoder=wmav1 \
|
||||
--enable-decoder=wmav2 \
|
||||
--enable-decoder=wmavoice \
|
||||
--enable-encoder=libopus \
|
||||
--enable-parser=aac \
|
||||
--enable-parser=aac_latm \
|
||||
--enable-parser=flac \
|
||||
--enable-parser=h264 \
|
||||
--enable-parser=hevc \
|
||||
--enable-parser=mpeg4video \
|
||||
--enable-parser=mpegaudio \
|
||||
--enable-parser=opus \
|
||||
--enable-parser=vorbis \
|
||||
--enable-demuxer=aac \
|
||||
--enable-demuxer=flac \
|
||||
--enable-demuxer=gif \
|
||||
--enable-demuxer=h264 \
|
||||
--enable-demuxer=hevc \
|
||||
--enable-demuxer=m4v \
|
||||
--enable-demuxer=mov \
|
||||
--enable-demuxer=mp3 \
|
||||
--enable-demuxer=ogg \
|
||||
--enable-demuxer=wav \
|
||||
--enable-muxer=ogg \
|
||||
--enable-muxer=opus
|
||||
|
||||
make -j$(nproc)
|
||||
make install
|
||||
- name: FFmpeg install.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
# List of files from cmake/external/ffmpeg/CMakeLists.txt.
|
||||
copyLib() {
|
||||
mkdir -p ffmpeg/$1
|
||||
\cp -fR ffmpeg-cache/lib/$1.a ffmpeg/$1/$1.a
|
||||
}
|
||||
copyLib libavformat
|
||||
copyLib libavcodec
|
||||
copyLib libswresample
|
||||
copyLib libswscale
|
||||
copyLib libavutil
|
||||
|
||||
cp -R ffmpeg-cache/. $PREFIX
|
||||
cp -R ffmpeg-cache/include/. ffmpeg/
|
||||
|
||||
- name: OpenAL Soft.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone --branch capture_with_webrtc $GIT/telegramdesktop/openal-soft.git
|
||||
cd openal-soft/build
|
||||
|
||||
CFLAGS="$UNGUARDED" CPPFLAGS="$UNGUARDED" cmake \
|
||||
-D CMAKE_INSTALL_PREFIX:PATH=$PREFIX \
|
||||
-D ALSOFT_EXAMPLES=OFF \
|
||||
-D LIBTYPE:STRING=STATIC \
|
||||
-D CMAKE_OSX_DEPLOYMENT_TARGET:STRING=$MACOSX_DEPLOYMENT_TARGET ..
|
||||
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
- name: Crashpad cache.
|
||||
id: cache-crashpad
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/crashpad
|
||||
key: ${{ runner.OS }}-crashpad-${{ env.CACHE_KEY }}-${{ hashFiles('**/crashpad.diff') }}-${{ hashFiles('**/mini_chromium.diff') }}
|
||||
- name: Crashpad.
|
||||
if: steps.cache-crashpad.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd Libraries
|
||||
echo Install GYP for Crashpad.
|
||||
git clone https://chromium.googlesource.com/external/gyp
|
||||
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
cd gyp
|
||||
git checkout 9f2a7bb1
|
||||
git apply $LibrariesPath/patches/gyp.diff
|
||||
./setup.py build
|
||||
sudo ./setup.py install
|
||||
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone https://chromium.googlesource.com/crashpad/crashpad.git
|
||||
cd crashpad
|
||||
git checkout feb3aa3923
|
||||
git apply ../patches/crashpad.diff
|
||||
cd third_party/mini_chromium
|
||||
git clone https://chromium.googlesource.com/chromium/mini_chromium
|
||||
cd mini_chromium
|
||||
git checkout 7c5b0c1ab4
|
||||
git apply ../../../../patches/mini_chromium.diff
|
||||
cd ../../gtest
|
||||
git clone https://chromium.googlesource.com/external/github.com/google/googletest gtest
|
||||
cd gtest
|
||||
git checkout d62d6c6556
|
||||
cd ../../..
|
||||
|
||||
build/gyp_crashpad.py -Dmac_deployment_target=10.10
|
||||
ninja -C out/Debug
|
||||
|
||||
- name: Qt 5.15.2 cache.
|
||||
id: cache-qt
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/qt-cache
|
||||
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_15_2/*') }}
|
||||
- name: Use cached Qt 5.15.2.
|
||||
if: steps.cache-qt.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
mv qt-cache Qt-5.15.2
|
||||
mkdir -p $QT_PREFIX
|
||||
mv -f Qt-5.15.2 "$(dirname "$QT_PREFIX")"/
|
||||
- name: Qt 5.15.2 build.
|
||||
if: steps.cache-qt.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone git://code.qt.io/qt/qt5.git qt_$QT
|
||||
cd qt_$QT
|
||||
perl init-repository --module-subset=qtbase,qtimageformats,qtsvg
|
||||
git checkout v5.15.2
|
||||
git submodule update qtbase
|
||||
git submodule update qtimageformats
|
||||
git submodule update qtsvg
|
||||
cd qtbase
|
||||
find ../../patches/qtbase_$QT -type f -print0 | sort -z | xargs -0 git apply
|
||||
cd ..
|
||||
|
||||
./configure \
|
||||
-prefix "$QT_PREFIX" \
|
||||
-debug \
|
||||
-force-debug-info \
|
||||
-opensource \
|
||||
-confirm-license \
|
||||
-static \
|
||||
-opengl desktop \
|
||||
-no-openssl \
|
||||
-securetransport \
|
||||
-nomake examples \
|
||||
-nomake tests \
|
||||
-platform macx-clang \
|
||||
-I "$PREFIX/include" \
|
||||
LIBJPEG_LIBS="$PREFIX/lib/libjpeg.a" \
|
||||
ZLIB_LIBS="$PREFIX/lib/libz.a"
|
||||
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
make clean
|
||||
cp -r $QT_PREFIX $LibrariesPath/qt-cache
|
||||
|
||||
- name: WebRTC cache.
|
||||
id: cache-webrtc
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/tg_owt
|
||||
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }}
|
||||
- name: WebRTC.
|
||||
if: steps.cache-webrtc.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone --recursive $GIT/desktop-app/tg_owt.git
|
||||
mkdir -p tg_owt/out/Debug
|
||||
cd tg_owt/out/Debug
|
||||
cmake -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DTG_OWT_SPECIAL_TARGET=mac \
|
||||
-DTG_OWT_BUILD_AUDIO_BACKENDS=OFF \
|
||||
-DTG_OWT_LIBJPEG_INCLUDE_PATH=$PREFIX/include \
|
||||
-DTG_OWT_OPENSSL_INCLUDE_PATH=`pwd`/../../../openssl_$OPENSSL_VER/include \
|
||||
-DTG_OWT_OPUS_INCLUDE_PATH=$PREFIX/include/opus \
|
||||
-DTG_OWT_FFMPEG_INCLUDE_PATH=$PREFIX/include \
|
||||
../..
|
||||
ninja
|
||||
|
||||
# Cleanup.
|
||||
cd $LibrariesPath/tg_owt
|
||||
mv out/Debug/libtg_owt.a libtg_owt.a
|
||||
rm -rf out
|
||||
mkdir -p out/Debug
|
||||
mv libtg_owt.a out/Debug/libtg_owt.a
|
||||
./$REPO_NAME/Telegram/build/prepare/mac.sh skip-release silent skip-qt5 qt6
|
||||
|
||||
- name: Telegram Desktop build.
|
||||
if: env.ONLY_CACHE == 'false'
|
||||
@@ -530,6 +109,7 @@ jobs:
|
||||
-D CMAKE_C_FLAGS="-Werror" \
|
||||
-D CMAKE_CXX_FLAGS="-Werror" \
|
||||
-D TDESKTOP_API_TEST=ON \
|
||||
-D DESKTOP_APP_QT6=ON \
|
||||
-D DESKTOP_APP_USE_PACKAGED=OFF \
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF \
|
||||
$DEFINE
|
||||
|
||||
86
.github/workflows/win.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
ONLY_CACHE: "false"
|
||||
MANUAL_CACHING: "0"
|
||||
DOC_PATH: "docs/building-win.md"
|
||||
PREPARE_PATH: "Telegram/build/prepare/prepare.py"
|
||||
AUTO_CACHING: "1"
|
||||
|
||||
defaults:
|
||||
@@ -132,24 +132,12 @@ jobs:
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
echo "Find necessary commit from doc."
|
||||
checkoutCommit=$(grep -A 1 "cd patches" $REPO_NAME/$DOC_PATH | sed -n 2p)
|
||||
checkoutCommit=$(grep -A 1 "cd patches" $REPO_NAME/$PREPARE_PATH | sed -n 2p)
|
||||
cd $LibrariesPath
|
||||
git clone $GIT/desktop-app/patches.git
|
||||
cd Patches
|
||||
cd patches
|
||||
eval $checkoutCommit
|
||||
|
||||
- name: Find any version of Python 2.
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Find any version of Python 2."
|
||||
p=`ls /c/hostedtoolcache/windows/python | grep "^2" | tail -1`
|
||||
if [ -z "$p" ]; then
|
||||
echo "Python 2 is not found."
|
||||
exit 1
|
||||
fi
|
||||
echo "PY2=C:\\hostedtoolcache\\windows\\Python\\$p\\x64" >> $GITHUB_ENV
|
||||
echo "Found $p."
|
||||
|
||||
- name: LZMA.
|
||||
run: |
|
||||
git clone %GIT%/telegramdesktop/lzma.git
|
||||
@@ -161,28 +149,27 @@ jobs:
|
||||
id: cache-openssl
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/openssl_${{ env.OPENSSL_VER }}
|
||||
path: ${{ env.LibrariesPath }}/openssl
|
||||
key: ${{ runner.OS }}-${{ env.CACHE_KEY }}-${{ env.OPENSSL_VER }}
|
||||
- name: OpenSSL.
|
||||
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone %GIT%/openssl/openssl.git openssl_%OPENSSL_VER%
|
||||
cd openssl_%OPENSSL_VER%
|
||||
git checkout OpenSSL_%OPENSSL_VER%-stable
|
||||
git clone -b OpenSSL_%OPENSSL_VER%-stable %GIT%/openssl/openssl.git
|
||||
cd openssl
|
||||
perl Configure no-shared no-tests debug-VC-WIN32
|
||||
nmake
|
||||
mkdir out32.dbg
|
||||
move libcrypto.lib out32.dbg
|
||||
move libssl.lib out32.dbg
|
||||
move ossl_static.pdb out32.dbg\ossl_static
|
||||
mkdir out.dbg
|
||||
move libcrypto.lib out.dbg
|
||||
move libssl.lib out.dbg
|
||||
move ossl_static.pdb out.dbg\ossl_static
|
||||
nmake clean
|
||||
move out32.dbg\ossl_static out32.dbg\ossl_static.pdb
|
||||
move out.dbg\ossl_static out.dbg\ossl_static.pdb
|
||||
perl Configure no-shared no-tests VC-WIN32
|
||||
nmake
|
||||
mkdir out32
|
||||
move libcrypto.lib out32
|
||||
move libssl.lib out32
|
||||
move ossl_static.pdb out32
|
||||
mkdir out
|
||||
move libcrypto.lib out
|
||||
move libssl.lib out
|
||||
move ossl_static.pdb out
|
||||
|
||||
rmdir /S /Q test
|
||||
rmdir /S /Q .git
|
||||
@@ -198,7 +185,7 @@ jobs:
|
||||
- name: MozJPEG.
|
||||
shell: cmd
|
||||
run: |
|
||||
git clone -b v4.0.1-rc2 %GIT%/mozilla/mozjpeg.git
|
||||
git clone -b v4.0.3 %GIT%/mozilla/mozjpeg.git
|
||||
cd mozjpeg
|
||||
cmake . ^
|
||||
-G "Visual Studio 16 2019" ^
|
||||
@@ -239,16 +226,17 @@ jobs:
|
||||
GYP_MSVS_VERSION: 2019
|
||||
if: steps.cache-breakpad.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone %GIT%/telegramdesktop/gyp.git
|
||||
git clone https://chromium.googlesource.com/external/gyp
|
||||
cd gyp
|
||||
SET PATH=%PY2%;%cd%;%PATH%
|
||||
git checkout tdesktop
|
||||
SET PATH=%cd%;%PATH%
|
||||
git checkout d6c5dd51dc
|
||||
git apply ../patches/gyp.diff
|
||||
|
||||
cd %LibrariesPath%
|
||||
|
||||
git clone %GIT%/google/breakpad
|
||||
git clone https://chromium.googlesource.com/breakpad/breakpad
|
||||
cd breakpad
|
||||
git checkout a1dbcdcb43
|
||||
git checkout bc8fb886
|
||||
git apply ../patches/breakpad.diff
|
||||
cd src
|
||||
git clone %GIT%/google/googletest testing
|
||||
@@ -258,10 +246,9 @@ jobs:
|
||||
ninja -C out/Debug common crash_generation_client exception_handler
|
||||
ninja -C out/Release common crash_generation_client exception_handler
|
||||
cd tools\windows\dump_syms
|
||||
call gyp dump_syms.gyp
|
||||
|
||||
call vcvars32.bat
|
||||
msbuild -m dump_syms.vcxproj /property:Configuration=Release
|
||||
call gyp dump_syms.gyp --format=ninja
|
||||
cd ..\..\..
|
||||
ninja -C out/Release dump_syms
|
||||
|
||||
- name: Opus cache.
|
||||
id: cache-opus
|
||||
@@ -272,12 +259,17 @@ jobs:
|
||||
- name: Opus.
|
||||
if: steps.cache-opus.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone %GIT%/telegramdesktop/opus.git
|
||||
git clone -b v1.3.1 %GIT%/xiph/opus.git
|
||||
cd opus
|
||||
git checkout tdesktop
|
||||
cd win32\VS2015
|
||||
msbuild -m opus.sln /property:Configuration=Debug /property:Platform="Win32"
|
||||
msbuild -m opus.sln /property:Configuration=Release /property:Platform="Win32"
|
||||
git cherry-pick 927de8453c
|
||||
cmake -B out . ^
|
||||
-A Win32 ^
|
||||
-DCMAKE_INSTALL_PREFIX=%LibrariesPath%/local/opus ^
|
||||
-DCMAKE_C_FLAGS_DEBUG="/MTd /Zi /Ob0 /Od /RTC1" ^
|
||||
-DCMAKE_C_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"
|
||||
cmake --build out --config Debug
|
||||
cmake --build out --config Release
|
||||
cmake --install out --config Release
|
||||
|
||||
- name: Rnnoise.
|
||||
run: |
|
||||
@@ -352,7 +344,7 @@ jobs:
|
||||
for /r %%i in (..\..\patches\qtbase_%QT%\*) do git apply %%i
|
||||
cd ..
|
||||
|
||||
SET SSL=%LibrariesPath%\openssl_%OPENSSL_VER%
|
||||
SET SSL=%LibrariesPath%\openssl
|
||||
SET SSL_LIBS=libcrypto.lib Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib
|
||||
|
||||
SET ANGLE=%LibrariesPath%\tg_angle
|
||||
@@ -380,8 +372,8 @@ jobs:
|
||||
QMAKE_LIBS_EGL_RELEASE="%ANGLE%\out\Release\tg_angle.lib %ZLIB%\ZlibStatReleaseWithoutAsm\zlibstat.lib %ANGLE_LIBS% Gdi32.lib User32.lib" ^
|
||||
-openssl-linked ^
|
||||
-I "%SSL%\include" ^
|
||||
OPENSSL_LIBS_DEBUG="%SSL%\out32.dbg\libssl.lib %SSL%\out32.dbg\%SSL_LIBS%" ^
|
||||
OPENSSL_LIBS_RELEASE="%SSL%\out32\libssl.lib %SSL%\out32\%SSL_LIBS%" ^
|
||||
OPENSSL_LIBS_DEBUG="%SSL%\out.dbg\libssl.lib %SSL%\out.dbg\%SSL_LIBS%" ^
|
||||
OPENSSL_LIBS_RELEASE="%SSL%\out\libssl.lib %SSL%\out\%SSL_LIBS%" ^
|
||||
-I "%LibrariesPath%\mozjpeg" ^
|
||||
LIBJPEG_LIBS_DEBUG="%LibrariesPath%\mozjpeg\Debug\jpeg-static.lib" ^
|
||||
LIBJPEG_LIBS_RELEASE="%LibrariesPath%\mozjpeg\Release\jpeg-static.lib" ^
|
||||
@@ -418,7 +410,7 @@ jobs:
|
||||
-DTG_OWT_SPECIAL_TARGET=win ^
|
||||
-DTG_OWT_BUILD_AUDIO_BACKENDS=OFF ^
|
||||
-DTG_OWT_LIBJPEG_INCLUDE_PATH=%cd%/../../../mozjpeg ^
|
||||
-DTG_OWT_OPENSSL_INCLUDE_PATH=%cd%/../../../openssl_%OPENSSL_VER%/include ^
|
||||
-DTG_OWT_OPENSSL_INCLUDE_PATH=%cd%/../../../openssl/include ^
|
||||
-DTG_OWT_OPUS_INCLUDE_PATH=%cd%/../../../opus/include ^
|
||||
-DTG_OWT_FFMPEG_INCLUDE_PATH=%cd%/../../../ffmpeg ^
|
||||
../..
|
||||
|
||||
@@ -39,6 +39,7 @@ include(cmake/init_target.cmake)
|
||||
include(cmake/generate_target.cmake)
|
||||
include(cmake/nuget.cmake)
|
||||
include(cmake/validate_d3d_compiler.cmake)
|
||||
include(cmake/target_prepare_qrc.cmake)
|
||||
|
||||
include(cmake/options.cmake)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
add_executable(Telegram WIN32 MACOSX_BUNDLE)
|
||||
init_target(Telegram)
|
||||
init_non_host_target(Telegram)
|
||||
|
||||
add_subdirectory(lib_rpl)
|
||||
add_subdirectory(lib_crl)
|
||||
@@ -42,16 +42,30 @@ include(cmake/generate_appdata_changelog.cmake)
|
||||
|
||||
if (WIN32)
|
||||
include(cmake/generate_midl.cmake)
|
||||
generate_midl(Telegram ${src_loc}/platform/win/windows_quiethours.idl)
|
||||
generate_midl(Telegram ${src_loc}
|
||||
platform/win/windows_quiethours.idl
|
||||
platform/win/windows_toastactivator.idl
|
||||
)
|
||||
|
||||
nuget_add_winrt(Telegram)
|
||||
endif()
|
||||
|
||||
set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON)
|
||||
set_target_properties(Telegram PROPERTIES AUTOMOC ON)
|
||||
target_prepare_qrc(Telegram)
|
||||
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
tdesktop::lib_tgcalls_legacy
|
||||
tdesktop::lib_tgcalls
|
||||
tdesktop::lib_tgvoip
|
||||
|
||||
# Order in this list defines the order of include paths in command line.
|
||||
# We need to place desktop-app::external_minizip this early to have its
|
||||
# include paths (usually ${PREFIX}/include/minizip) before any depend that
|
||||
# would add ${PREFIX}/include. This path may have a different <zip.h>,
|
||||
# for example installed by libzip (https://libzip.org).
|
||||
desktop-app::external_minizip
|
||||
|
||||
tdesktop::td_export
|
||||
tdesktop::td_mtproto
|
||||
tdesktop::td_lang
|
||||
@@ -71,7 +85,6 @@ PRIVATE
|
||||
desktop-app::external_lz4
|
||||
desktop-app::external_rlottie
|
||||
desktop-app::external_zlib
|
||||
desktop-app::external_minizip
|
||||
desktop-app::external_qt_static_plugins
|
||||
desktop-app::external_qt
|
||||
desktop-app::external_qr_code_generator
|
||||
@@ -102,6 +115,8 @@ PRIVATE
|
||||
api/api_cloud_password.cpp
|
||||
api/api_cloud_password.h
|
||||
api/api_common.h
|
||||
api/api_confirm_phone.cpp
|
||||
api/api_confirm_phone.h
|
||||
api/api_editing.cpp
|
||||
api/api_editing.h
|
||||
api/api_global_privacy.cpp
|
||||
@@ -112,6 +127,10 @@ PRIVATE
|
||||
api/api_invite_links.h
|
||||
api/api_media.cpp
|
||||
api/api_media.h
|
||||
api/api_peer_photo.cpp
|
||||
api/api_peer_photo.h
|
||||
api/api_polls.cpp
|
||||
api/api_polls.h
|
||||
api/api_self_destruct.cpp
|
||||
api/api_self_destruct.h
|
||||
api/api_send_progress.cpp
|
||||
@@ -130,6 +149,8 @@ PRIVATE
|
||||
api/api_updates.h
|
||||
api/api_user_privacy.cpp
|
||||
api/api_user_privacy.h
|
||||
api/api_views.cpp
|
||||
api/api_views.h
|
||||
api/api_who_read.cpp
|
||||
api/api_who_read.h
|
||||
boxes/filters/edit_filter_box.cpp
|
||||
@@ -146,6 +167,7 @@ PRIVATE
|
||||
boxes/peers/edit_participant_box.h
|
||||
boxes/peers/edit_participants_box.cpp
|
||||
boxes/peers/edit_participants_box.h
|
||||
boxes/peers/edit_peer_common.h
|
||||
boxes/peers/edit_peer_info_box.cpp
|
||||
boxes/peers/edit_peer_info_box.h
|
||||
boxes/peers/edit_peer_invite_link.cpp
|
||||
@@ -160,6 +182,8 @@ PRIVATE
|
||||
boxes/peers/edit_peer_permissions_box.h
|
||||
boxes/about_box.cpp
|
||||
boxes/about_box.h
|
||||
boxes/about_sponsored_box.cpp
|
||||
boxes/about_sponsored_box.h
|
||||
boxes/abstract_box.cpp
|
||||
boxes/abstract_box.h
|
||||
boxes/add_contact_box.cpp
|
||||
@@ -174,14 +198,12 @@ PRIVATE
|
||||
boxes/background_preview_box.h
|
||||
boxes/change_phone_box.cpp
|
||||
boxes/change_phone_box.h
|
||||
boxes/confirm_box.cpp
|
||||
boxes/confirm_box.h
|
||||
boxes/confirm_phone_box.cpp
|
||||
boxes/confirm_phone_box.h
|
||||
boxes/connection_box.cpp
|
||||
boxes/connection_box.h
|
||||
boxes/create_poll_box.cpp
|
||||
boxes/create_poll_box.h
|
||||
boxes/delete_messages_box.cpp
|
||||
boxes/delete_messages_box.h
|
||||
boxes/dictionaries_manager.cpp
|
||||
boxes/dictionaries_manager.h
|
||||
boxes/download_path_box.cpp
|
||||
@@ -196,6 +218,8 @@ PRIVATE
|
||||
boxes/language_box.h
|
||||
boxes/local_storage_box.cpp
|
||||
boxes/local_storage_box.h
|
||||
boxes/max_invite_box.cpp
|
||||
boxes/max_invite_box.h
|
||||
boxes/mute_settings_box.cpp
|
||||
boxes/mute_settings_box.h
|
||||
boxes/peer_list_box.cpp
|
||||
@@ -206,8 +230,10 @@ PRIVATE
|
||||
boxes/peer_lists_box.h
|
||||
boxes/passcode_box.cpp
|
||||
boxes/passcode_box.h
|
||||
boxes/rate_call_box.cpp
|
||||
boxes/rate_call_box.h
|
||||
boxes/phone_banned_box.cpp
|
||||
boxes/phone_banned_box.h
|
||||
boxes/pin_messages_box.cpp
|
||||
boxes/pin_messages_box.h
|
||||
boxes/self_destruction_box.cpp
|
||||
boxes/self_destruction_box.h
|
||||
boxes/send_files_box.cpp
|
||||
@@ -278,6 +304,8 @@ PRIVATE
|
||||
chat_helpers/bot_command.h
|
||||
chat_helpers/bot_keyboard.cpp
|
||||
chat_helpers/bot_keyboard.h
|
||||
chat_helpers/emoji_interactions.cpp
|
||||
chat_helpers/emoji_interactions.h
|
||||
chat_helpers/emoji_keywords.cpp
|
||||
chat_helpers/emoji_keywords.h
|
||||
chat_helpers/emoji_list_widget.cpp
|
||||
@@ -389,6 +417,7 @@ PRIVATE
|
||||
data/data_file_origin.cpp
|
||||
data/data_file_origin.h
|
||||
data/data_flags.h
|
||||
data/data_game.cpp
|
||||
data/data_game.h
|
||||
data/data_group_call.cpp
|
||||
data/data_group_call.h
|
||||
@@ -404,6 +433,7 @@ PRIVATE
|
||||
data/data_media_types.h
|
||||
data/data_messages.cpp
|
||||
data/data_messages.h
|
||||
data/data_msg_id.h
|
||||
data/data_notify_settings.cpp
|
||||
data/data_notify_settings.h
|
||||
data/data_peer.cpp
|
||||
@@ -436,6 +466,8 @@ PRIVATE
|
||||
data/data_shared_media.h
|
||||
data/data_sparse_ids.cpp
|
||||
data/data_sparse_ids.h
|
||||
data/data_sponsored_messages.cpp
|
||||
data/data_sponsored_messages.h
|
||||
data/data_streaming.cpp
|
||||
data/data_streaming.h
|
||||
data/data_types.cpp
|
||||
@@ -456,8 +488,6 @@ PRIVATE
|
||||
dialogs/dialogs_inner_widget.h
|
||||
dialogs/dialogs_key.cpp
|
||||
dialogs/dialogs_key.h
|
||||
dialogs/dialogs_layout.cpp
|
||||
dialogs/dialogs_layout.h
|
||||
dialogs/dialogs_list.cpp
|
||||
dialogs/dialogs_list.h
|
||||
dialogs/dialogs_main_list.cpp
|
||||
@@ -470,6 +500,10 @@ PRIVATE
|
||||
dialogs/dialogs_search_from_controllers.h
|
||||
dialogs/dialogs_widget.cpp
|
||||
dialogs/dialogs_widget.h
|
||||
dialogs/ui/dialogs_layout.cpp
|
||||
dialogs/ui/dialogs_layout.h
|
||||
dialogs/ui/dialogs_message_view.cpp
|
||||
dialogs/ui/dialogs_message_view.h
|
||||
editor/color_picker.cpp
|
||||
editor/color_picker.h
|
||||
editor/controllers/controllers.h
|
||||
@@ -581,6 +615,8 @@ PRIVATE
|
||||
history/view/history_view_cursor_state.h
|
||||
history/view/history_view_element.cpp
|
||||
history/view/history_view_element.h
|
||||
history/view/history_view_emoji_interactions.cpp
|
||||
history/view/history_view_emoji_interactions.h
|
||||
history/view/history_view_empty_list_bubble.cpp
|
||||
history/view/history_view_empty_list_bubble.h
|
||||
history/view/history_view_group_call_tracker.cpp
|
||||
@@ -608,6 +644,8 @@ PRIVATE
|
||||
history/view/history_view_service_message.h
|
||||
history/view/history_view_top_bar_widget.cpp
|
||||
history/view/history_view_top_bar_widget.h
|
||||
history/view/history_view_view_button.cpp
|
||||
history/view/history_view_view_button.h
|
||||
history/view/history_view_webpage_preview.cpp
|
||||
history/view/history_view_webpage_preview.h
|
||||
history/history.cpp
|
||||
@@ -618,6 +656,10 @@ PRIVATE
|
||||
history/history_item.h
|
||||
history/history_item_components.cpp
|
||||
history/history_item_components.h
|
||||
history/history_item_edition.cpp
|
||||
history/history_item_edition.h
|
||||
history/history_item_reply_markup.cpp
|
||||
history/history_item_reply_markup.h
|
||||
history/history_item_text.cpp
|
||||
history/history_item_text.h
|
||||
history/history_inner_widget.cpp
|
||||
@@ -930,6 +972,8 @@ PRIVATE
|
||||
platform/win/windows_dlls.h
|
||||
platform/win/windows_event_filter.cpp
|
||||
platform/win/windows_event_filter.h
|
||||
platform/win/windows_toast_activator.cpp
|
||||
platform/win/windows_toast_activator.h
|
||||
platform/platform_audio.h
|
||||
platform/platform_file_utilities.h
|
||||
platform/platform_launcher.h
|
||||
@@ -1027,6 +1071,8 @@ PRIVATE
|
||||
ui/chat/attach/attach_item_single_file_preview.h
|
||||
ui/chat/attach/attach_item_single_media_preview.cpp
|
||||
ui/chat/attach/attach_item_single_media_preview.h
|
||||
ui/chat/choose_theme_controller.cpp
|
||||
ui/chat/choose_theme_controller.h
|
||||
ui/effects/fireworks_animation.cpp
|
||||
ui/effects/fireworks_animation.h
|
||||
ui/effects/round_checkbox.cpp
|
||||
@@ -1039,10 +1085,6 @@ PRIVATE
|
||||
ui/image/image_location.h
|
||||
ui/image/image_location_factory.cpp
|
||||
ui/image/image_location_factory.h
|
||||
ui/widgets/continuous_sliders.cpp
|
||||
ui/widgets/continuous_sliders.h
|
||||
ui/widgets/discrete_sliders.cpp
|
||||
ui/widgets/discrete_sliders.h
|
||||
ui/widgets/level_meter.cpp
|
||||
ui/widgets/level_meter.h
|
||||
ui/widgets/multi_select.cpp
|
||||
@@ -1208,8 +1250,7 @@ elseif (APPLE)
|
||||
endif()
|
||||
|
||||
set(icons_path ${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Images.xcassets)
|
||||
set_target_properties(Telegram PROPERTIES RESOURCE ${icons_path})
|
||||
target_sources(Telegram PRIVATE ${icons_path})
|
||||
target_add_resource(Telegram ${icons_path})
|
||||
|
||||
set(lang_packs
|
||||
en
|
||||
@@ -1235,27 +1276,30 @@ elseif (APPLE)
|
||||
PRE_LINK
|
||||
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Frameworks
|
||||
COMMAND cp $<TARGET_FILE:Updater> $<TARGET_FILE_DIR:Telegram>/../Frameworks/
|
||||
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Resources
|
||||
COMMAND cp ${CMAKE_BINARY_DIR}/lib_ui.rcc $<TARGET_FILE_DIR:Telegram>/../Resources
|
||||
)
|
||||
if (NOT DESKTOP_APP_DISABLE_CRASH_REPORTS)
|
||||
if (DESKTOP_APP_MAC_ARCH STREQUAL "x86_64" OR DESKTOP_APP_MAC_ARCH STREQUAL "arm64")
|
||||
set(crashpad_dir_part ".${DESKTOP_APP_MAC_ARCH}")
|
||||
else()
|
||||
set(crashpad_dir_part "")
|
||||
endif()
|
||||
add_custom_command(TARGET Telegram
|
||||
PRE_LINK
|
||||
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Helpers
|
||||
COMMAND cp ${libs_loc}/crashpad/out/$<IF:$<CONFIG:Debug>,Debug,Release>/crashpad_handler $<TARGET_FILE_DIR:Telegram>/../Helpers/
|
||||
COMMAND cp ${libs_loc}/crashpad/out/$<IF:$<CONFIG:Debug>,Debug,Release>${crashpad_dir_part}/crashpad_handler $<TARGET_FILE_DIR:Telegram>/../Helpers/
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_glibmm
|
||||
desktop-app::external_glib
|
||||
)
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_statusnotifieritem
|
||||
desktop-app::external_dbusmenu_qt
|
||||
desktop-app::external_glibmm
|
||||
desktop-app::external_glib
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -1359,18 +1403,20 @@ if (WIN32)
|
||||
/DELAYLOAD:gdiplus.dll
|
||||
/DELAYLOAD:version.dll
|
||||
/DELAYLOAD:dwmapi.dll
|
||||
/DELAYLOAD:uxtheme.dll
|
||||
/DELAYLOAD:crypt32.dll
|
||||
/DELAYLOAD:bcrypt.dll
|
||||
/DELAYLOAD:imm32.dll
|
||||
/DELAYLOAD:netapi32.dll
|
||||
/DELAYLOAD:userenv.dll
|
||||
/DELAYLOAD:wtsapi32.dll
|
||||
/DELAYLOAD:propsys.dll
|
||||
)
|
||||
endif()
|
||||
|
||||
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT build_winstore)
|
||||
add_executable(Updater WIN32)
|
||||
init_target(Updater)
|
||||
init_non_host_target(Updater)
|
||||
|
||||
add_dependencies(Telegram Updater)
|
||||
|
||||
@@ -1382,7 +1428,9 @@ if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT
|
||||
_other/updater.h
|
||||
)
|
||||
|
||||
set_target_properties(Updater PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
|
||||
set_target_properties(Updater PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${output_folder}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
get_filename_component(lib_base_loc lib_base REALPATH)
|
||||
|
||||
|
Before Width: | Height: | Size: 117 KiB |
BIN
Telegram/Resources/art/themeimage.jpg
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
Telegram/Resources/day-custom-base.tdesktop-theme
Normal file
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 862 KiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 594 KiB |
BIN
Telegram/Resources/icons/dialogs/dialogs_mini_play.png
Normal file
|
After Width: | Height: | Size: 165 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_mini_play@2x.png
Normal file
|
After Width: | Height: | Size: 200 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_mini_play@3x.png
Normal file
|
After Width: | Height: | Size: 475 B |
|
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 453 B |
|
Before Width: | Height: | Size: 637 B After Width: | Height: | Size: 973 B |
|
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 946 B |
|
Before Width: | Height: | Size: 651 B After Width: | Height: | Size: 710 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.4 KiB |
@@ -357,6 +357,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_update_fail" = "Update check failed :(";
|
||||
"lng_settings_workmode_tray" = "Show tray icon";
|
||||
"lng_settings_workmode_window" = "Show taskbar icon";
|
||||
"lng_settings_close_to_taskbar" = "Close to taskbar";
|
||||
"lng_settings_native_frame" = "Use system window frame";
|
||||
"lng_settings_auto_start" = "Launch Telegram when system starts";
|
||||
"lng_settings_start_min" = "Launch minimized";
|
||||
@@ -1334,6 +1335,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_forwarded_imported" = "This message was imported from another app. It may not be real.";
|
||||
"lng_signed_author" = "Author: {user}";
|
||||
"lng_in_reply_to" = "In reply to";
|
||||
"lng_sponsored" = "sponsored";
|
||||
"lng_edited" = "edited";
|
||||
"lng_edited_date" = "Edited: {date}";
|
||||
"lng_sent_date" = "Sent: {date}";
|
||||
@@ -1617,6 +1619,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_user_action_upload_file" = "{user} is sending a file";
|
||||
"lng_send_action_choose_sticker" = "choosing a sticker";
|
||||
"lng_user_action_choose_sticker" = "{user} is choosing a sticker";
|
||||
"lng_user_action_watching_animations" = "watching {emoji}";
|
||||
"lng_unread_bar#one" = "{count} unread message";
|
||||
"lng_unread_bar#other" = "{count} unread messages";
|
||||
"lng_unread_bar_some" = "Unread messages";
|
||||
@@ -2237,7 +2240,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_recording_start_checkbox" = "Also record video";
|
||||
"lng_group_call_recording_start_audio_subtitle" = "This chat will be recorded into an audio file";
|
||||
"lng_group_call_recording_start_video_subtitle" = "Choose video orientation";
|
||||
"lng_group_call_is_recorded" = "Voice chat is being recorded.";
|
||||
"lng_group_call_is_recorded" = "The audio stream is being recorded.";
|
||||
"lng_group_call_is_recorded_video" = "The video stream is being recorded.";
|
||||
"lng_group_call_is_recorded_channel" = "Live stream is being recorded.";
|
||||
"lng_group_call_can_speak_here" = "You can now speak.";
|
||||
"lng_group_call_can_speak" = "You can now speak in {chat}.";
|
||||
@@ -2868,6 +2872,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_filters_remove_sure" = "This will remove the folder, your chats will not be deleted.";
|
||||
"lng_filters_remove_yes" = "Remove";
|
||||
|
||||
"lng_chat_theme_change" = "Change colors";
|
||||
"lng_chat_theme_none" = "No\nTheme";
|
||||
"lng_chat_theme_apply" = "Apply Theme";
|
||||
"lng_chat_theme_reset" = "Reset Theme";
|
||||
"lng_chat_theme_dont" = "Do Not Set Theme";
|
||||
"lng_chat_theme_title" = "Select theme";
|
||||
"lng_chat_theme_cant_voice" = "Sorry, you can't change the chat theme while you're having an unsent voice message.";
|
||||
|
||||
"lng_photo_editor_menu_delete" = "Delete";
|
||||
"lng_photo_editor_menu_flip" = "Flip";
|
||||
"lng_photo_editor_menu_duplicate" = "Duplicate";
|
||||
@@ -2877,6 +2889,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_voice_speed_fast" = "Fast";
|
||||
"lng_voice_speed_very_fast" = "Very fast";
|
||||
|
||||
"lng_view_button_user" = "View user";
|
||||
"lng_view_button_bot" = "View bot";
|
||||
"lng_view_button_group" = "View group";
|
||||
"lng_view_button_channel" = "View channel";
|
||||
"lng_view_button_background" = "View background";
|
||||
"lng_view_button_theme" = "View theme";
|
||||
"lng_view_button_message" = "View message";
|
||||
"lng_view_button_voice_chat" = "Voice chat";
|
||||
"lng_view_button_voice_chat_channel" = "Live stream";
|
||||
|
||||
"lng_sponsored_title" = "What are sponsored messages?";
|
||||
"lng_sponsored_info_description1" = "Unlike other apps, Telegram never uses your private data to target ads. Sponsored messages on Telegram are based solely on the topic of the public channels in which they are shown. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored messages.\n\nUnlike other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can’t spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers a free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible advertisers at:";
|
||||
"lng_sponsored_info_description2" = "Sponsored Messages are currently in test mode. Once they are fully launched and allow Telegram to cover its basic costs, we will start sharing ad revenue with the owners of public channels in which sponsored messages are displayed.\n\nOnline ads should no longer be synonymous with abuse of user privacy. Let us redefine how a tech company should operate – together.";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
||||
|
||||
BIN
Telegram/Resources/night-custom-base.tdesktop-theme
Normal file
@@ -47,7 +47,7 @@
|
||||
<file alias="art/bg_initial.jpg">../../art/bg_initial.jpg</file>
|
||||
<file alias="art/logo_256.png">../../art/logo_256.png</file>
|
||||
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
|
||||
<file alias="art/sunrise.jpg">../../art/sunrise.jpg</file>
|
||||
<file alias="art/themeimage.jpg">../../art/themeimage.jpg</file>
|
||||
<file alias="art/dice_idle.tgs">../../art/dice_idle.tgs</file>
|
||||
<file alias="art/dart_idle.tgs">../../art/dart_idle.tgs</file>
|
||||
<file alias="art/bball_idle.tgs">../../art/bball_idle.tgs</file>
|
||||
@@ -60,6 +60,8 @@
|
||||
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
|
||||
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
|
||||
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
|
||||
<file alias="day-custom-base.tdesktop-theme">../../day-custom-base.tdesktop-theme</file>
|
||||
<file alias="night-custom-base.tdesktop-theme">../../night-custom-base.tdesktop-theme</file>
|
||||
<file alias="icons/calls/hands.lottie">../../icons/calls/hands.lottie</file>
|
||||
<file alias="icons/calls/voice.lottie">../../icons/calls/voice.lottie</file>
|
||||
<file alias="recording/info_audio.svg">../../art/recording/recording_info_audio.svg</file>
|
||||
|
||||
@@ -467,7 +467,7 @@ sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction;
|
||||
speakingInGroupCallAction#d92c2285 = SendMessageAction;
|
||||
sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction;
|
||||
sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction;
|
||||
sendMessageEmojiInteraction#6a3233b6 emoticon:string interaction:DataJSON = SendMessageAction;
|
||||
sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction;
|
||||
sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction;
|
||||
|
||||
contacts.found#b3134d9d my_results:Vector<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
|
||||
@@ -560,6 +560,7 @@ inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
|
||||
inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
|
||||
inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
|
||||
inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet;
|
||||
|
||||
stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet;
|
||||
|
||||
@@ -907,7 +908,6 @@ channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvit
|
||||
channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeTheme#fe69018d prev_value:string new_value:string = ChannelAdminLogEventAction;
|
||||
|
||||
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="3.0.2.0" />
|
||||
Version="3.1.10.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,0,2,0
|
||||
PRODUCTVERSION 3,0,2,0
|
||||
FILEVERSION 3,1,10,0
|
||||
PRODUCTVERSION 3,1,10,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "3.0.2.0"
|
||||
VALUE "FileVersion", "3.1.10.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.0.2.0"
|
||||
VALUE "ProductVersion", "3.1.10.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,0,2,0
|
||||
PRODUCTVERSION 3,0,2,0
|
||||
FILEVERSION 3,1,10,0
|
||||
PRODUCTVERSION 3,1,10,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", "3.0.2.0"
|
||||
VALUE "FileVersion", "3.1.10.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.0.2.0"
|
||||
VALUE "ProductVersion", "3.1.10.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -161,6 +161,7 @@ int main(int argc, char *argv[])
|
||||
QString remove;
|
||||
int version = 0;
|
||||
[[maybe_unused]] bool targetwin64 = false;
|
||||
[[maybe_unused]] bool targetarmac = false;
|
||||
QFileInfoList files;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (string("-path") == argv[i] && i + 1 < argc) {
|
||||
@@ -170,6 +171,12 @@ int main(int argc, char *argv[])
|
||||
if (remove.isEmpty()) remove = info.canonicalPath() + "/";
|
||||
} else if (string("-target") == argv[i] && i + 1 < argc) {
|
||||
targetwin64 = (string("win64") == argv[i + 1]);
|
||||
} else if (string("-arch") == argv[i] && i + 1 < argc) {
|
||||
targetarmac = (string("arm64") == argv[i + 1]);
|
||||
if (!targetarmac && string("x86_64") != argv[i + 1]) {
|
||||
cout << "Bad -arch param value passed: " << argv[i + 1] << "\n";
|
||||
return -1;
|
||||
}
|
||||
} else if (string("-version") == argv[i] && i + 1 < argc) {
|
||||
version = QString(argv[i + 1]).toInt();
|
||||
} else if (string("-beta") == argv[i]) {
|
||||
@@ -494,7 +501,7 @@ int main(int argc, char *argv[])
|
||||
#ifdef Q_OS_WIN
|
||||
QString outName((targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version));
|
||||
#elif defined Q_OS_MAC
|
||||
QString outName(QString("tmacupd%1").arg(AlphaVersion ? AlphaVersion : version));
|
||||
QString outName((targetarmac ? QString("tarmacupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version));
|
||||
#elif defined Q_OS_UNIX
|
||||
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
|
||||
#else
|
||||
|
||||
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_attached_stickers.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "data/data_document.h"
|
||||
@@ -37,7 +37,7 @@ void AttachedStickers::request(
|
||||
}
|
||||
if (result.v.isEmpty()) {
|
||||
strongController->show(
|
||||
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
|
||||
Box<Ui::InformBox>(tr::lng_stickers_not_found(tr::now)));
|
||||
return;
|
||||
} else if (result.v.size() > 1) {
|
||||
strongController->show(
|
||||
@@ -63,7 +63,7 @@ void AttachedStickers::request(
|
||||
_requestId = 0;
|
||||
if (const auto strongController = weak.get()) {
|
||||
strongController->show(
|
||||
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
|
||||
Box<Ui::InformBox>(tr::lng_stickers_not_found(tr::now)));
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ Authorizations::Entry ParseEntry(const MTPDauthorization &data) {
|
||||
&& lastDate.weekNumber() == nowDate.weekNumber()) {
|
||||
result.active = langDayOfWeek(lastDate);
|
||||
} else {
|
||||
result.active = lastDate.toString(qsl("d.MM.yy"));
|
||||
result.active = lastDate.toString(cDateFormat());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ BlockedPeers::Slice TLToSlice(
|
||||
Data::Session &owner) {
|
||||
const auto create = [&](int count, const QVector<MTPPeerBlocked> &list) {
|
||||
auto slice = BlockedPeers::Slice();
|
||||
slice.total = std::max(count, list.size());
|
||||
slice.total = std::max(count, int(list.size()));
|
||||
slice.list.reserve(list.size());
|
||||
for (const auto &contact : list) {
|
||||
contact.match([&](const MTPDpeerBlocked &data) {
|
||||
|
||||
@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "api/api_send_progress.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/share_box.h"
|
||||
#include "boxes/passcode_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@@ -91,7 +91,7 @@ void SendBotCallbackData(
|
||||
result.match([&](const MTPDmessages_botCallbackAnswer &data) {
|
||||
if (const auto message = data.vmessage()) {
|
||||
if (data.is_alert()) {
|
||||
Ui::show(Box<InformBox>(qs(*message)));
|
||||
Ui::show(Box<Ui::InformBox>(qs(*message)));
|
||||
} else {
|
||||
if (withPassword) {
|
||||
Ui::hideLayer();
|
||||
|
||||
@@ -18,7 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_layers.h"
|
||||
@@ -86,7 +86,7 @@ void CheckChatInvite(
|
||||
Core::App().hideMediaView();
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->show(
|
||||
Box<InformBox>(tr::lng_group_invite_bad_link(tr::now)));
|
||||
Box<Ui::InformBox>(tr::lng_group_invite_bad_link(tr::now)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_cloud_password.h"
|
||||
|
||||
#include "base/openssl_help.h"
|
||||
#include "base/random.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
@@ -27,7 +27,7 @@ void CloudPassword::reload() {
|
||||
)).done([=](const MTPaccount_Password &result) {
|
||||
_requestId = 0;
|
||||
result.match([&](const MTPDaccount_password &data) {
|
||||
openssl::AddRandomSeed(bytes::make_span(data.vsecure_random().v));
|
||||
base::RandomAddSeed(bytes::make_span(data.vsecure_random().v));
|
||||
if (_state) {
|
||||
*_state = Core::ParseCloudPasswordState(data);
|
||||
} else {
|
||||
|
||||
125
Telegram/SourceFiles/api/api_confirm_phone.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
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_confirm_phone.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_phone_box.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
ConfirmPhone::ConfirmPhone(not_null<ApiWrap*> api)
|
||||
: _api(&api->instance()) {
|
||||
}
|
||||
|
||||
void ConfirmPhone::resolve(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const QString &phone,
|
||||
const QString &hash) {
|
||||
if (_sendRequestId) {
|
||||
return;
|
||||
}
|
||||
_sendRequestId = _api.request(MTPaccount_SendConfirmPhoneCode(
|
||||
MTP_string(hash),
|
||||
MTP_codeSettings(MTP_flags(0))
|
||||
)).done([=](const MTPauth_SentCode &result) {
|
||||
_sendRequestId = 0;
|
||||
|
||||
result.match([&](const MTPDauth_sentCode &data) {
|
||||
const auto sentCodeLength = data.vtype().match([&](
|
||||
const MTPDauth_sentCodeTypeApp &data) {
|
||||
LOG(("Error: should not be in-app code!"));
|
||||
return 0;
|
||||
}, [&](const MTPDauth_sentCodeTypeSms &data) {
|
||||
return data.vlength().v;
|
||||
}, [&](const MTPDauth_sentCodeTypeCall &data) {
|
||||
return data.vlength().v;
|
||||
}, [&](const MTPDauth_sentCodeTypeFlashCall &data) {
|
||||
LOG(("Error: should not be flashcall!"));
|
||||
return 0;
|
||||
});
|
||||
const auto phoneHash = qs(data.vphone_code_hash());
|
||||
const auto timeout = [&]() -> std::optional<int> {
|
||||
if (const auto nextType = data.vnext_type()) {
|
||||
if (nextType->type() == mtpc_auth_codeTypeCall) {
|
||||
return data.vtimeout().value_or(60);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}();
|
||||
auto box = Box<Ui::ConfirmPhoneBox>(
|
||||
phone,
|
||||
sentCodeLength,
|
||||
timeout);
|
||||
const auto boxWeak = Ui::MakeWeak(box.data());
|
||||
box->resendRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
_api.request(MTPauth_ResendCode(
|
||||
MTP_string(phone),
|
||||
MTP_string(phoneHash)
|
||||
)).done([=](const MTPauth_SentCode &result) {
|
||||
if (boxWeak) {
|
||||
boxWeak->callDone();
|
||||
}
|
||||
}).send();
|
||||
}, box->lifetime());
|
||||
box->checkRequests(
|
||||
) | rpl::start_with_next([=](const QString &code) {
|
||||
if (_checkRequestId) {
|
||||
return;
|
||||
}
|
||||
_checkRequestId = _api.request(MTPaccount_ConfirmPhone(
|
||||
MTP_string(phoneHash),
|
||||
MTP_string(code)
|
||||
)).done([=](const MTPBool &result) {
|
||||
_checkRequestId = 0;
|
||||
controller->show(
|
||||
Box<Ui::InformBox>(
|
||||
tr::lng_confirm_phone_success(
|
||||
tr::now,
|
||||
lt_phone,
|
||||
Ui::FormatPhone(phone))),
|
||||
Ui::LayerOption::CloseOther);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_checkRequestId = 0;
|
||||
if (!boxWeak) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto errorText = MTP::IsFloodError(error)
|
||||
? tr::lng_flood_error(tr::now)
|
||||
: (error.type() == (u"PHONE_CODE_EMPTY"_q)
|
||||
|| error.type() == (u"PHONE_CODE_INVALID"_q))
|
||||
? tr::lng_bad_code(tr::now)
|
||||
: Lang::Hard::ServerError();
|
||||
boxWeak->showServerError(errorText);
|
||||
}).handleFloodErrors().send();
|
||||
}, box->lifetime());
|
||||
|
||||
controller->show(std::move(box), Ui::LayerOption::CloseOther);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_sendRequestId = 0;
|
||||
_checkRequestId = 0;
|
||||
|
||||
const auto errorText = MTP::IsFloodError(error)
|
||||
? tr::lng_flood_error(tr::now)
|
||||
: (error.code() == 400)
|
||||
? tr::lng_confirm_phone_link_invalid(tr::now)
|
||||
: Lang::Hard::ServerError();
|
||||
controller->show(
|
||||
Box<Ui::InformBox>(errorText),
|
||||
Ui::LayerOption::CloseOther);
|
||||
}).handleFloodErrors().send();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
36
Telegram/SourceFiles/api/api_confirm_phone.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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 Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Api {
|
||||
|
||||
class ConfirmPhone final {
|
||||
public:
|
||||
explicit ConfirmPhone(not_null<ApiWrap*> api);
|
||||
|
||||
void resolve(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const QString &phone,
|
||||
const QString &hash);
|
||||
|
||||
private:
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _sendRequestId = 0;
|
||||
mtpRequestId _checkRequestId = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_media.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
@@ -149,7 +149,8 @@ void EditMessageWithUploadedMedia(
|
||||
session->data().sendHistoryChangeNotifications();
|
||||
if (mediaInvalid) {
|
||||
Ui::show(
|
||||
Box<InformBox>(tr::lng_edit_media_invalid_file(tr::now)),
|
||||
Box<Ui::InformBox>(
|
||||
tr::lng_edit_media_invalid_file(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
} else {
|
||||
|
||||
212
Telegram/SourceFiles/api/api_peer_photo.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_peer_photo.h"
|
||||
|
||||
#include "api/api_updates.h"
|
||||
#include "apiwrap.h"
|
||||
#include "base/random.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/file_upload.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/storage_user_photos.h"
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
SendMediaReady PreparePeerPhoto(
|
||||
MTP::DcId dcId,
|
||||
PeerId peerId,
|
||||
QImage &&image) {
|
||||
PreparedPhotoThumbs photoThumbs;
|
||||
QVector<MTPPhotoSize> photoSizes;
|
||||
|
||||
QByteArray jpeg;
|
||||
QBuffer jpegBuffer(&jpeg);
|
||||
image.save(&jpegBuffer, "JPG", 87);
|
||||
|
||||
const auto scaled = [&](int size) {
|
||||
return image.scaled(
|
||||
size,
|
||||
size,
|
||||
Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
};
|
||||
const auto push = [&](
|
||||
const char *type,
|
||||
QImage &&image,
|
||||
QByteArray bytes = QByteArray()) {
|
||||
photoSizes.push_back(MTP_photoSize(
|
||||
MTP_string(type),
|
||||
MTP_int(image.width()),
|
||||
MTP_int(image.height()), MTP_int(0)));
|
||||
photoThumbs.emplace(type[0], PreparedPhotoThumb{
|
||||
.image = std::move(image),
|
||||
.bytes = std::move(bytes)
|
||||
});
|
||||
};
|
||||
push("a", scaled(160));
|
||||
push("b", scaled(320));
|
||||
push("c", std::move(image), jpeg);
|
||||
|
||||
const auto id = base::RandomValue<PhotoId>();
|
||||
const auto photo = MTP_photo(
|
||||
MTP_flags(0),
|
||||
MTP_long(id),
|
||||
MTP_long(0),
|
||||
MTP_bytes(),
|
||||
MTP_int(base::unixtime::now()),
|
||||
MTP_vector<MTPPhotoSize>(photoSizes),
|
||||
MTPVector<MTPVideoSize>(),
|
||||
MTP_int(dcId));
|
||||
|
||||
QString file, filename;
|
||||
int32 filesize = 0;
|
||||
QByteArray data;
|
||||
|
||||
return SendMediaReady(
|
||||
SendMediaType::Photo,
|
||||
file,
|
||||
filename,
|
||||
filesize,
|
||||
data,
|
||||
id,
|
||||
id,
|
||||
u"jpg"_q,
|
||||
peerId,
|
||||
photo,
|
||||
photoThumbs,
|
||||
MTP_documentEmpty(MTP_long(0)),
|
||||
jpeg,
|
||||
0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PeerPhoto::PeerPhoto(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance()) {
|
||||
crl::on_main(_session, [=] {
|
||||
// You can't use _session->lifetime() in the constructor,
|
||||
// only queued, because it is not constructed yet.
|
||||
_session->uploader().photoReady(
|
||||
) | rpl::start_with_next([=](const Storage::UploadedPhoto &data) {
|
||||
ready(data.fullId, data.file);
|
||||
}, _session->lifetime());
|
||||
});
|
||||
}
|
||||
|
||||
void PeerPhoto::upload(not_null<PeerData*> peer, QImage &&image) {
|
||||
peer = peer->migrateToOrMe();
|
||||
const auto ready = PreparePeerPhoto(
|
||||
_api.instance().mainDcId(),
|
||||
peer->id,
|
||||
std::move(image));
|
||||
|
||||
const auto fakeId = FullMsgId(
|
||||
peerToChannel(peer->id),
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto already = ranges::find(
|
||||
_uploads,
|
||||
peer,
|
||||
[](const auto &pair) { return pair.second; });
|
||||
if (already != end(_uploads)) {
|
||||
_session->uploader().cancel(already->first);
|
||||
_uploads.erase(already);
|
||||
}
|
||||
_uploads.emplace(fakeId, peer);
|
||||
_session->uploader().uploadMedia(fakeId, ready);
|
||||
}
|
||||
|
||||
void PeerPhoto::clear(not_null<PhotoData*> photo) {
|
||||
const auto self = _session->user();
|
||||
if (self->userpicPhotoId() == photo->id) {
|
||||
_api.request(MTPphotos_UpdateProfilePhoto(
|
||||
MTP_inputPhotoEmpty()
|
||||
)).done([=](const MTPphotos_Photo &result) {
|
||||
self->setPhoto(MTP_userProfilePhotoEmpty());
|
||||
}).send();
|
||||
} else if (photo->peer && photo->peer->userpicPhotoId() == photo->id) {
|
||||
const auto applier = [=](const MTPUpdates &result) {
|
||||
_session->updates().applyUpdates(result);
|
||||
};
|
||||
if (const auto chat = photo->peer->asChat()) {
|
||||
_api.request(MTPmessages_EditChatPhoto(
|
||||
chat->inputChat,
|
||||
MTP_inputChatPhotoEmpty()
|
||||
)).done(applier).send();
|
||||
} else if (const auto channel = photo->peer->asChannel()) {
|
||||
_api.request(MTPchannels_EditPhoto(
|
||||
channel->inputChannel,
|
||||
MTP_inputChatPhotoEmpty()
|
||||
)).done(applier).send();
|
||||
}
|
||||
} else {
|
||||
_api.request(MTPphotos_DeletePhotos(
|
||||
MTP_vector<MTPInputPhoto>(1, photo->mtpInput())
|
||||
)).send();
|
||||
_session->storage().remove(Storage::UserPhotosRemoveOne(
|
||||
peerToUser(self->id),
|
||||
photo->id));
|
||||
}
|
||||
}
|
||||
|
||||
void PeerPhoto::ready(const FullMsgId &msgId, const MTPInputFile &file) {
|
||||
const auto maybePeer = _uploads.take(msgId);
|
||||
if (!maybePeer) {
|
||||
return;
|
||||
}
|
||||
const auto peer = *maybePeer;
|
||||
const auto applier = [=](const MTPUpdates &result) {
|
||||
_session->updates().applyUpdates(result);
|
||||
};
|
||||
if (peer->isSelf()) {
|
||||
_api.request(MTPphotos_UploadProfilePhoto(
|
||||
MTP_flags(MTPphotos_UploadProfilePhoto::Flag::f_file),
|
||||
file,
|
||||
MTPInputFile(), // video
|
||||
MTPdouble() // video_start_ts
|
||||
)).done([=](const MTPphotos_Photo &result) {
|
||||
result.match([&](const MTPDphotos_photo &data) {
|
||||
_session->data().processPhoto(data.vphoto());
|
||||
_session->data().processUsers(data.vusers());
|
||||
});
|
||||
}).send();
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
const auto history = _session->data().history(chat);
|
||||
history->sendRequestId = _api.request(MTPmessages_EditChatPhoto(
|
||||
chat->inputChat,
|
||||
MTP_inputChatUploadedPhoto(
|
||||
MTP_flags(MTPDinputChatUploadedPhoto::Flag::f_file),
|
||||
file,
|
||||
MTPInputFile(), // video
|
||||
MTPdouble()) // video_start_ts
|
||||
)).done(applier).afterRequest(history->sendRequestId).send();
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
const auto history = _session->data().history(channel);
|
||||
history->sendRequestId = _api.request(MTPchannels_EditPhoto(
|
||||
channel->inputChannel,
|
||||
MTP_inputChatUploadedPhoto(
|
||||
MTP_flags(MTPDinputChatUploadedPhoto::Flag::f_file),
|
||||
file,
|
||||
MTPInputFile(), // video
|
||||
MTPdouble()) // video_start_ts
|
||||
)).done(applier).afterRequest(history->sendRequestId).send();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
38
Telegram/SourceFiles/api/api_peer_photo.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
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;
|
||||
class PeerData;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
class PeerPhoto final {
|
||||
public:
|
||||
explicit PeerPhoto(not_null<ApiWrap*> api);
|
||||
|
||||
void upload(not_null<PeerData*> peer, QImage &&image);
|
||||
void clear(not_null<PhotoData*> photo);
|
||||
|
||||
private:
|
||||
void ready(const FullMsgId &msgId, const MTPInputFile &file);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<FullMsgId, not_null<PeerData*>> _uploads;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
201
Telegram/SourceFiles/api/api_polls.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
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_polls.h"
|
||||
|
||||
#include "api/api_common.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "apiwrap.h"
|
||||
#include "base/random.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_message.h" // ShouldSendSilent
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] TimeId UnixtimeFromMsgId(mtpMsgId msgId) {
|
||||
return TimeId(msgId >> 32);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Polls::Polls(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance()) {
|
||||
}
|
||||
|
||||
void Polls::create(
|
||||
const PollData &data,
|
||||
const SendAction &action,
|
||||
Fn<void()> done,
|
||||
Fn<void(const MTP::Error &error)> fail) {
|
||||
_session->api().sendAction(action);
|
||||
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (action.replyTo) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto clearCloudDraft = action.clearDraft;
|
||||
if (clearCloudDraft) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||
history->clearLocalDraft();
|
||||
history->clearCloudDraft();
|
||||
history->startSavingCloudDraft();
|
||||
}
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
if (action.options.scheduled) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
}
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
const auto replyTo = action.replyTo;
|
||||
history->sendRequestId = _api.request(MTPmessages_SendMedia(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(replyTo),
|
||||
PollDataToInputMedia(&data),
|
||||
MTP_string(),
|
||||
MTP_long(base::RandomValue<uint64>()),
|
||||
MTPReplyMarkup(),
|
||||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(action.options.scheduled)
|
||||
)).done([=](
|
||||
const MTPUpdates &result,
|
||||
const MTP::Response &response) mutable {
|
||||
_session->updates().applyUpdates(result);
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
_session->changes().historyUpdated(
|
||||
history,
|
||||
(action.options.scheduled
|
||||
? Data::HistoryUpdate::Flag::ScheduledSent
|
||||
: Data::HistoryUpdate::Flag::MessageSent));
|
||||
done();
|
||||
finish();
|
||||
}).fail([=](
|
||||
const MTP::Error &error,
|
||||
const MTP::Response &response) mutable {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
fail(error);
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
}
|
||||
|
||||
void Polls::sendVotes(
|
||||
FullMsgId itemId,
|
||||
const std::vector<QByteArray> &options) {
|
||||
if (_pollVotesRequestIds.contains(itemId)) {
|
||||
return;
|
||||
}
|
||||
const auto item = _session->data().message(itemId);
|
||||
const auto media = item ? item->media() : nullptr;
|
||||
const auto poll = media ? media->poll() : nullptr;
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto showSending = poll && !options.empty();
|
||||
const auto hideSending = [=] {
|
||||
if (showSending) {
|
||||
if (const auto item = _session->data().message(itemId)) {
|
||||
poll->sendingVotes.clear();
|
||||
_session->data().requestItemRepaint(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (showSending) {
|
||||
poll->sendingVotes = options;
|
||||
_session->data().requestItemRepaint(item);
|
||||
}
|
||||
|
||||
auto prepared = QVector<MTPbytes>();
|
||||
prepared.reserve(options.size());
|
||||
ranges::transform(
|
||||
options,
|
||||
ranges::back_inserter(prepared),
|
||||
[](const QByteArray &option) { return MTP_bytes(option); });
|
||||
const auto requestId = _api.request(MTPmessages_SendVote(
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTP_vector<MTPbytes>(prepared)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_pollVotesRequestIds.erase(itemId);
|
||||
hideSending();
|
||||
_session->updates().applyUpdates(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_pollVotesRequestIds.erase(itemId);
|
||||
hideSending();
|
||||
}).send();
|
||||
_pollVotesRequestIds.emplace(itemId, requestId);
|
||||
}
|
||||
|
||||
void Polls::close(not_null<HistoryItem*> item) {
|
||||
const auto itemId = item->fullId();
|
||||
if (_pollCloseRequestIds.contains(itemId)) {
|
||||
return;
|
||||
}
|
||||
const auto media = item ? item->media() : nullptr;
|
||||
const auto poll = media ? media->poll() : nullptr;
|
||||
if (!poll) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = _api.request(MTPmessages_EditMessage(
|
||||
MTP_flags(MTPmessages_EditMessage::Flag::f_media),
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTPstring(),
|
||||
PollDataToInputMedia(poll, true),
|
||||
MTPReplyMarkup(),
|
||||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(0) // schedule_date
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_pollCloseRequestIds.erase(itemId);
|
||||
_session->updates().applyUpdates(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_pollCloseRequestIds.erase(itemId);
|
||||
}).send();
|
||||
_pollCloseRequestIds.emplace(itemId, requestId);
|
||||
}
|
||||
|
||||
void Polls::reloadResults(not_null<HistoryItem*> item) {
|
||||
const auto itemId = item->fullId();
|
||||
if (!IsServerMsgId(item->id)
|
||||
|| _pollReloadRequestIds.contains(itemId)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = _api.request(MTPmessages_GetPollResults(
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_pollReloadRequestIds.erase(itemId);
|
||||
_session->updates().applyUpdates(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_pollReloadRequestIds.erase(itemId);
|
||||
}).send();
|
||||
_pollReloadRequestIds.emplace(itemId, requestId);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
49
Telegram/SourceFiles/api/api_polls.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
class HistoryItem;
|
||||
struct PollData;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct SendAction;
|
||||
|
||||
class Polls final {
|
||||
public:
|
||||
explicit Polls(not_null<ApiWrap*> api);
|
||||
|
||||
void create(
|
||||
const PollData &data,
|
||||
const SendAction &action,
|
||||
Fn<void()> done,
|
||||
Fn<void(const MTP::Error &error)> fail);
|
||||
void sendVotes(
|
||||
FullMsgId itemId,
|
||||
const std::vector<QByteArray> &options);
|
||||
void close(not_null<HistoryItem*> item);
|
||||
void reloadResults(not_null<HistoryItem*> item);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollVotesRequestIds;
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollCloseRequestIds;
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollReloadRequestIds;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_sending.h"
|
||||
|
||||
#include "api/api_text_entities.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "base/random.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_photo.h"
|
||||
@@ -76,7 +76,7 @@ void SendExistingMedia(
|
||||
const auto newId = FullMsgId(
|
||||
peerToChannel(peer->id),
|
||||
session->data().nextLocalMessageId());
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
|
||||
auto flags = NewMessageFlags(peer);
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
@@ -128,7 +128,7 @@ void SendExistingMedia(
|
||||
messagePostAuthor,
|
||||
media,
|
||||
caption,
|
||||
MTPReplyMarkup());
|
||||
HistoryMessageMarkupData());
|
||||
|
||||
auto performRequest = [=](const auto &repeatRequest) -> void {
|
||||
auto &histories = history->owner().histories();
|
||||
@@ -212,7 +212,7 @@ void SendExistingPhoto(
|
||||
}
|
||||
|
||||
bool SendDice(Api::MessageToSend &message) {
|
||||
const auto full = message.textWithTags.text.midRef(0).trimmed();
|
||||
const auto full = QStringView(message.textWithTags.text).trimmed();
|
||||
auto length = 0;
|
||||
if (!Ui::Emoji::Find(full.data(), full.data() + full.size(), &length)
|
||||
|| length != full.size()) {
|
||||
@@ -248,7 +248,7 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
const auto newId = FullMsgId(
|
||||
peerToChannel(peer->id),
|
||||
session->data().nextLocalMessageId());
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
|
||||
auto &histories = history->owner().histories();
|
||||
auto flags = NewMessageFlags(peer);
|
||||
@@ -288,7 +288,7 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
messagePostAuthor,
|
||||
TextWithEntities(),
|
||||
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
|
||||
MTPReplyMarkup());
|
||||
HistoryMessageMarkupData());
|
||||
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
@@ -335,7 +335,7 @@ void SendConfirmedFile(
|
||||
isEditing
|
||||
? file->to.replaceMediaOf
|
||||
: session->data().nextLocalMessageId());
|
||||
auto groupId = file->album ? file->album->groupId : uint64(0);
|
||||
const auto groupId = file->album ? file->album->groupId : uint64(0);
|
||||
if (file->album) {
|
||||
const auto proj = [](const SendingAlbum::Item &item) {
|
||||
return item.taskId;
|
||||
@@ -370,13 +370,6 @@ void SendConfirmedFile(
|
||||
session->user()).flags;
|
||||
TextUtilities::PrepareForSending(caption, prepareFlags);
|
||||
TextUtilities::Trim(caption);
|
||||
auto localEntities = Api::EntitiesToMTP(session, caption.entities);
|
||||
|
||||
if (itemToEdit) {
|
||||
if (const auto id = itemToEdit->groupId()) {
|
||||
groupId = id.value;
|
||||
}
|
||||
}
|
||||
|
||||
auto flags = isEditing ? MessageFlags() : NewMessageFlags(peer);
|
||||
if (file->to.replyTo) {
|
||||
@@ -397,13 +390,18 @@ void SendConfirmedFile(
|
||||
} else {
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
if (file->type == SendMediaType::Audio) {
|
||||
if (!peer->isChannel() || peer->isMegagroup()) {
|
||||
flags |= MessageFlag::MediaIsUnread;
|
||||
}
|
||||
}
|
||||
|
||||
const auto messageFromId = anonymousPost ? 0 : session->userPeerId();
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? session->user()->name
|
||||
: QString();
|
||||
|
||||
const auto media = [&] {
|
||||
const auto media = MTPMessageMedia([&] {
|
||||
if (file->type == SendMediaType::Photo) {
|
||||
return MTP_messageMediaPhoto(
|
||||
MTP_flags(MTPDmessageMediaPhoto::Flag::f_photo),
|
||||
@@ -422,38 +420,21 @@ void SendConfirmedFile(
|
||||
} else {
|
||||
Unexpected("Type in sendFilesConfirmed.");
|
||||
}
|
||||
}();
|
||||
}());
|
||||
|
||||
if (itemToEdit) {
|
||||
itemToEdit->savePreviousMedia();
|
||||
itemToEdit->applyEdition(MTP_message(
|
||||
MTP_flags(MTPDmessage::Flag::f_media
|
||||
| ((flags & MessageFlag::HideEdited)
|
||||
? MTPDmessage::Flag::f_edit_hide
|
||||
: MTPDmessage::Flag())
|
||||
| (localEntities.v.isEmpty()
|
||||
? MTPDmessage::Flag()
|
||||
: MTPDmessage::Flag::f_entities)),
|
||||
MTP_int(newId.msg),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(file->to.peer),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPlong(), // via_bot_id
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||
MTP_string(caption.text),
|
||||
media,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTPint(), // views
|
||||
MTPint(), // forwards
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTP_long(groupId),
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTPint()).c_message());
|
||||
auto edition = HistoryMessageEdition();
|
||||
edition.isEditHide = (flags & MessageFlag::HideEdited);
|
||||
edition.editDate = 0;
|
||||
edition.views = 0;
|
||||
edition.forwards = 0;
|
||||
edition.ttl = 0;
|
||||
edition.mtpMedia = &media;
|
||||
edition.textWithEntities = caption;
|
||||
edition.useSameMarkup = true;
|
||||
edition.useSameReplies = true;
|
||||
itemToEdit->applyEdition(std::move(edition));
|
||||
} else {
|
||||
const auto viaBotId = UserId();
|
||||
history->addNewLocalMessage(
|
||||
@@ -466,7 +447,7 @@ void SendConfirmedFile(
|
||||
messagePostAuthor,
|
||||
caption,
|
||||
media,
|
||||
MTPReplyMarkup(),
|
||||
HistoryMessageMarkupData(),
|
||||
groupId);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_send_action.h"
|
||||
#include "chat_helpers/emoji_interactions.h"
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
@@ -41,7 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/unixtime.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "apiwrap.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "app.h" // App::quitting
|
||||
@@ -984,36 +985,18 @@ void Updates::handleSendActionUpdate(
|
||||
const auto from = (fromId == session().userPeerId())
|
||||
? session().user().get()
|
||||
: session().data().peerLoaded(fromId);
|
||||
const auto isSpeakingInCall = (action.type()
|
||||
== mtpc_speakingInGroupCallAction);
|
||||
if (isSpeakingInCall) {
|
||||
if (!peer->isChat() && !peer->isChannel()) {
|
||||
return;
|
||||
}
|
||||
const auto call = peer->groupCall();
|
||||
const auto now = crl::now();
|
||||
if (call) {
|
||||
call->applyActiveUpdate(
|
||||
fromId,
|
||||
Data::LastSpokeTimes{ .anything = now, .voice = now },
|
||||
from);
|
||||
} else {
|
||||
const auto chat = peer->asChat();
|
||||
const auto channel = peer->asChannel();
|
||||
const auto active = chat
|
||||
? (chat->flags() & ChatDataFlag::CallActive)
|
||||
: (channel->flags() & ChannelDataFlag::CallActive);
|
||||
if (active) {
|
||||
_pendingSpeakingCallParticipants.emplace(
|
||||
peer).first->second[fromId] = now;
|
||||
if (peerIsUser(fromId)) {
|
||||
session().api().requestFullPeer(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (action.type() == mtpc_speakingInGroupCallAction) {
|
||||
handleSpeakingInCall(peer, fromId, from);
|
||||
}
|
||||
if (!from || !from->isUser() || from->isSelf()) {
|
||||
return;
|
||||
} else if (action.type() == mtpc_sendMessageEmojiInteraction) {
|
||||
handleEmojiInteraction(peer, action.c_sendMessageEmojiInteraction());
|
||||
return;
|
||||
} else if (action.type() == mtpc_sendMessageEmojiInteractionSeen) {
|
||||
const auto &data = action.c_sendMessageEmojiInteractionSeen();
|
||||
handleEmojiInteraction(peer, qs(data.vemoticon()));
|
||||
return;
|
||||
}
|
||||
const auto when = requestingDifference()
|
||||
? 0
|
||||
@@ -1026,6 +1009,76 @@ void Updates::handleSendActionUpdate(
|
||||
when);
|
||||
}
|
||||
|
||||
void Updates::handleEmojiInteraction(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPDsendMessageEmojiInteraction &data) {
|
||||
const auto json = data.vinteraction().match([&](
|
||||
const MTPDdataJSON &data) {
|
||||
return data.vdata().v;
|
||||
});
|
||||
handleEmojiInteraction(
|
||||
peer,
|
||||
data.vmsg_id().v,
|
||||
qs(data.vemoticon()),
|
||||
ChatHelpers::EmojiInteractions::Parse(json));
|
||||
}
|
||||
|
||||
void Updates::handleSpeakingInCall(
|
||||
not_null<PeerData*> peer,
|
||||
PeerId participantPeerId,
|
||||
PeerData *participantPeerLoaded) {
|
||||
if (!peer->isChat() && !peer->isChannel()) {
|
||||
return;
|
||||
}
|
||||
const auto call = peer->groupCall();
|
||||
const auto now = crl::now();
|
||||
if (call) {
|
||||
call->applyActiveUpdate(
|
||||
participantPeerId,
|
||||
Data::LastSpokeTimes{ .anything = now, .voice = now },
|
||||
participantPeerLoaded);
|
||||
} else {
|
||||
const auto chat = peer->asChat();
|
||||
const auto channel = peer->asChannel();
|
||||
const auto active = chat
|
||||
? (chat->flags() & ChatDataFlag::CallActive)
|
||||
: (channel->flags() & ChannelDataFlag::CallActive);
|
||||
if (active) {
|
||||
_pendingSpeakingCallParticipants.emplace(
|
||||
peer).first->second[participantPeerId] = now;
|
||||
if (peerIsUser(participantPeerId)) {
|
||||
session().api().requestFullPeer(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Updates::handleEmojiInteraction(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId messageId,
|
||||
const QString &emoticon,
|
||||
ChatHelpers::EmojiInteractionsBunch bunch) {
|
||||
if (session().windows().empty()) {
|
||||
return;
|
||||
}
|
||||
const auto window = session().windows().front();
|
||||
window->emojiInteractions().startIncoming(
|
||||
peer,
|
||||
messageId,
|
||||
emoticon,
|
||||
std::move(bunch));
|
||||
}
|
||||
|
||||
void Updates::handleEmojiInteraction(
|
||||
not_null<PeerData*> peer,
|
||||
const QString &emoticon) {
|
||||
if (session().windows().empty()) {
|
||||
return;
|
||||
}
|
||||
const auto window = session().windows().front();
|
||||
window->emojiInteractions().seenOutgoing(peer, emoticon);
|
||||
}
|
||||
|
||||
void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
switch (updates.type()) {
|
||||
case mtpc_updateShortMessage: {
|
||||
@@ -1923,7 +1976,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
} else if (d.is_popup()) {
|
||||
const auto &windows = session().windows();
|
||||
if (!windows.empty()) {
|
||||
windows.front()->window().show(Box<InformBox>(text));
|
||||
windows.front()->window().show(Box<Ui::InformBox>(text));
|
||||
}
|
||||
} else {
|
||||
session().data().serviceNotification(text, d.vmedia());
|
||||
|
||||
@@ -21,6 +21,10 @@ namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace ChatHelpers {
|
||||
struct EmojiInteractionsBunch;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Api {
|
||||
|
||||
class Updates final {
|
||||
@@ -139,6 +143,21 @@ private:
|
||||
MsgId rootId,
|
||||
PeerId fromId,
|
||||
const MTPSendMessageAction &action);
|
||||
void handleEmojiInteraction(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPDsendMessageEmojiInteraction &data);
|
||||
void handleSpeakingInCall(
|
||||
not_null<PeerData*> peer,
|
||||
PeerId participantPeerId,
|
||||
PeerData *participantPeerLoaded);
|
||||
void handleEmojiInteraction(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId messageId,
|
||||
const QString &emoticon,
|
||||
ChatHelpers::EmojiInteractionsBunch bunch);
|
||||
void handleEmojiInteraction(
|
||||
not_null<PeerData*> peer,
|
||||
const QString &emoticon);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
|
||||
136
Telegram/SourceFiles/api/api_views.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
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_views.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_id.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
// Send channel views each second.
|
||||
constexpr auto kSendViewsTimeout = crl::time(1000);
|
||||
|
||||
} // namespace
|
||||
|
||||
ViewsManager::ViewsManager(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance())
|
||||
, _incrementTimer([=] { viewsIncrement(); }) {
|
||||
}
|
||||
|
||||
void ViewsManager::scheduleIncrement(not_null<HistoryItem*> item) {
|
||||
auto peer = item->history()->peer;
|
||||
auto i = _incremented.find(peer);
|
||||
if (i != _incremented.cend()) {
|
||||
if (i->second.contains(item->id)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
i = _incremented.emplace(peer).first;
|
||||
}
|
||||
i->second.emplace(item->id);
|
||||
auto j = _toIncrement.find(peer);
|
||||
if (j == _toIncrement.cend()) {
|
||||
j = _toIncrement.emplace(peer).first;
|
||||
_incrementTimer.callOnce(kSendViewsTimeout);
|
||||
}
|
||||
j->second.emplace(item->id);
|
||||
}
|
||||
|
||||
void ViewsManager::removeIncremented(not_null<PeerData*> peer) {
|
||||
_incremented.remove(peer);
|
||||
}
|
||||
|
||||
void ViewsManager::viewsIncrement() {
|
||||
for (auto i = _toIncrement.begin(); i != _toIncrement.cend();) {
|
||||
if (_incrementRequests.contains(i->first)) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
QVector<MTPint> ids;
|
||||
ids.reserve(i->second.size());
|
||||
for (const auto &msgId : i->second) {
|
||||
ids.push_back(MTP_int(msgId));
|
||||
}
|
||||
const auto requestId = _api.request(MTPmessages_GetMessagesViews(
|
||||
i->first->input,
|
||||
MTP_vector<MTPint>(ids),
|
||||
MTP_bool(true)
|
||||
)).done([=](
|
||||
const MTPmessages_MessageViews &result,
|
||||
mtpRequestId requestId) {
|
||||
done(ids, result, requestId);
|
||||
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||
fail(error, requestId);
|
||||
}).afterDelay(5).send();
|
||||
|
||||
_incrementRequests.emplace(i->first, requestId);
|
||||
i = _toIncrement.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewsManager::done(
|
||||
QVector<MTPint> ids,
|
||||
const MTPmessages_MessageViews &result,
|
||||
mtpRequestId requestId) {
|
||||
const auto &data = result.c_messages_messageViews();
|
||||
auto &owner = _session->data();
|
||||
owner.processUsers(data.vusers());
|
||||
owner.processChats(data.vchats());
|
||||
auto &v = data.vviews().v;
|
||||
if (ids.size() == v.size()) {
|
||||
for (const auto &[peer, id] : _incrementRequests) {
|
||||
if (id != requestId) {
|
||||
continue;
|
||||
}
|
||||
const auto channel = peerToChannel(peer->id);
|
||||
for (auto j = 0, l = int(ids.size()); j < l; ++j) {
|
||||
if (const auto item = owner.message(channel, ids[j].v)) {
|
||||
v[j].match([&](const MTPDmessageViews &data) {
|
||||
if (const auto views = data.vviews()) {
|
||||
item->setViewsCount(views->v);
|
||||
}
|
||||
if (const auto forwards = data.vforwards()) {
|
||||
item->setForwardsCount(forwards->v);
|
||||
}
|
||||
if (const auto replies = data.vreplies()) {
|
||||
item->setReplies(
|
||||
HistoryMessageRepliesData(replies));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
_incrementRequests.erase(peer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_toIncrement.empty() && !_incrementTimer.isActive()) {
|
||||
_incrementTimer.callOnce(kSendViewsTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewsManager::fail(const MTP::Error &error, mtpRequestId requestId) {
|
||||
for (const auto &[peer, id] : _incrementRequests) {
|
||||
if (id == requestId) {
|
||||
_incrementRequests.erase(peer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_toIncrement.empty() && !_incrementTimer.isActive()) {
|
||||
_incrementTimer.callOnce(kSendViewsTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
49
Telegram/SourceFiles/api/api_views.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
class ApiWrap;
|
||||
class PeerData;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
class ViewsManager final {
|
||||
public:
|
||||
explicit ViewsManager(not_null<ApiWrap*> api);
|
||||
|
||||
void scheduleIncrement(not_null<HistoryItem*> item);
|
||||
void removeIncremented(not_null<PeerData*> peer);
|
||||
|
||||
private:
|
||||
void viewsIncrement();
|
||||
|
||||
void done(
|
||||
QVector<MTPint> ids,
|
||||
const MTPmessages_MessageViews &result,
|
||||
mtpRequestId requestId);
|
||||
void fail(const MTP::Error &error, mtpRequestId requestId);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<not_null<PeerData*>, base::flat_set<MsgId>> _incremented;
|
||||
base::flat_map<not_null<PeerData*>, base::flat_set<MsgId>> _toIncrement;
|
||||
base::flat_map<not_null<PeerData*>, mtpRequestId> _incrementRequests;
|
||||
base::flat_map<mtpRequestId, not_null<PeerData*>> _incrementByRequest;
|
||||
base::Timer _incrementTimer;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -130,7 +130,6 @@ struct State {
|
||||
not_null<HistoryItem*> item,
|
||||
not_null<QWidget*> context) {
|
||||
auto weak = QPointer<QWidget>(context.get());
|
||||
const auto fullId = item->fullId();
|
||||
const auto session = &item->history()->session();
|
||||
return [=](auto consumer) {
|
||||
if (!weak) {
|
||||
@@ -160,7 +159,7 @@ struct State {
|
||||
auto &entry = context->cache(item);
|
||||
entry.requestId = 0;
|
||||
auto peers = std::vector<PeerId>();
|
||||
peers.reserve(std::max(result.v.size(), 1));
|
||||
peers.reserve(std::max(int(result.v.size()), 1));
|
||||
for (const auto &id : result.v) {
|
||||
peers.push_back(UserId(id));
|
||||
}
|
||||
@@ -203,7 +202,7 @@ bool UpdateUserpics(
|
||||
}
|
||||
auto &was = state->userpics;
|
||||
auto now = std::vector<Userpic>();
|
||||
for (const auto peer : peers) {
|
||||
for (const auto &peer : peers) {
|
||||
if (ranges::contains(now, peer, &Userpic::peer)) {
|
||||
continue;
|
||||
}
|
||||
@@ -356,6 +355,8 @@ rpl::producer<Ui::WhoReadContent> WhoRead(
|
||||
} else if (UpdateUserpics(state, item, peers)) {
|
||||
RegenerateParticipants(state, small, large);
|
||||
pushNext();
|
||||
} else if (peers.empty()) {
|
||||
pushNext();
|
||||
}
|
||||
}, lifetime);
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_hash.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "api/api_media.h"
|
||||
#include "api/api_peer_photo.h"
|
||||
#include "api/api_polls.h"
|
||||
#include "api/api_sending.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_self_destruct.h"
|
||||
@@ -21,12 +23,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_global_privacy.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
#include "api/api_views.h"
|
||||
#include "api/api_confirm_phone.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_drafts.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_sparse_ids.h"
|
||||
@@ -46,6 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "core/application.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/random.h"
|
||||
#include "base/qt_adapters.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@@ -59,7 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "main/main_account.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "window/notifications_manager.h"
|
||||
@@ -140,15 +144,14 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this))
|
||||
, _globalPrivacy(std::make_unique<Api::GlobalPrivacy>(this))
|
||||
, _userPrivacy(std::make_unique<Api::UserPrivacy>(this))
|
||||
, _inviteLinks(std::make_unique<Api::InviteLinks>(this)) {
|
||||
, _inviteLinks(std::make_unique<Api::InviteLinks>(this))
|
||||
, _views(std::make_unique<Api::ViewsManager>(this))
|
||||
, _confirmPhone(std::make_unique<Api::ConfirmPhone>(this))
|
||||
, _peerPhoto(std::make_unique<Api::PeerPhoto>(this))
|
||||
, _polls(std::make_unique<Api::Polls>(this)) {
|
||||
crl::on_main(session, [=] {
|
||||
// You can't use _session->lifetime() in the constructor,
|
||||
// only queued, because it is not constructed yet.
|
||||
_session->uploader().photoReady(
|
||||
) | rpl::start_with_next([=](const Storage::UploadedPhoto &data) {
|
||||
photoUploadReady(data.fullId, data.file);
|
||||
}, _session->lifetime());
|
||||
|
||||
_session->data().chatsFilters().changed(
|
||||
) | rpl::filter([=] {
|
||||
return _session->data().chatsFilters().archiveNeeded();
|
||||
@@ -389,9 +392,9 @@ void ApiWrap::importChatInvite(const QString &hash) {
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
const auto &type = error.type();
|
||||
if (type == qstr("CHANNELS_TOO_MUCH")) {
|
||||
Ui::show(Box<InformBox>(tr::lng_join_channel_error(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_join_channel_error(tr::now)));
|
||||
} else if (error.code() == 400) {
|
||||
Ui::show(Box<InformBox>((type == qstr("USERS_TOO_MUCH"))
|
||||
Ui::show(Box<Ui::InformBox>((type == qstr("USERS_TOO_MUCH"))
|
||||
? tr::lng_group_invite_no_room(tr::now)
|
||||
: tr::lng_group_invite_bad_link(tr::now)));
|
||||
}
|
||||
@@ -463,19 +466,19 @@ void ApiWrap::sendMessageFail(
|
||||
uint64 randomId,
|
||||
FullMsgId itemId) {
|
||||
if (error.type() == qstr("PEER_FLOOD")) {
|
||||
Ui::show(Box<InformBox>(
|
||||
Ui::show(Box<Ui::InformBox>(
|
||||
PeerFloodErrorText(&session(), PeerFloodType::Send)));
|
||||
} else if (error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
|
||||
const auto link = textcmdLink(
|
||||
session().createInternalLinkFull(qsl("spambot")),
|
||||
tr::lng_cant_more_info(tr::now));
|
||||
Ui::show(Box<InformBox>(tr::lng_error_public_groups_denied(
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_error_public_groups_denied(
|
||||
tr::now,
|
||||
lt_more_info,
|
||||
link)));
|
||||
} else if (error.type().startsWith(qstr("SLOWMODE_WAIT_"))) {
|
||||
const auto chop = qstr("SLOWMODE_WAIT_").size();
|
||||
const auto left = error.type().midRef(chop).toInt();
|
||||
const auto left = base::StringViewMid(error.type(), chop).toInt();
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
const auto seconds = channel->slowmodeSeconds();
|
||||
if (seconds >= left) {
|
||||
@@ -490,7 +493,7 @@ void ApiWrap::sendMessageFail(
|
||||
Assert(peer->isUser());
|
||||
if (const auto item = scheduled.lookupItem(peer->id, itemId.msg)) {
|
||||
scheduled.removeSending(item);
|
||||
Ui::show(Box<InformBox>(tr::lng_cant_do_this(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now)));
|
||||
}
|
||||
}
|
||||
if (const auto item = _session->data().message(itemId)) {
|
||||
@@ -557,7 +560,8 @@ void ApiWrap::resolveMessageDatas() {
|
||||
)).done([=](
|
||||
const MTPmessages_Messages &result,
|
||||
mtpRequestId requestId) {
|
||||
gotMessageDatas(nullptr, result, requestId);
|
||||
_session->data().processExistingMessages(nullptr, result);
|
||||
finalizeMessageDataRequest(nullptr, requestId);
|
||||
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||
finalizeMessageDataRequest(nullptr, requestId);
|
||||
}).afterDelay(kSmallDelayMs).send();
|
||||
@@ -583,7 +587,8 @@ void ApiWrap::resolveMessageDatas() {
|
||||
)).done([=](
|
||||
const MTPmessages_Messages &result,
|
||||
mtpRequestId requestId) {
|
||||
gotMessageDatas(channel, result, requestId);
|
||||
_session->data().processExistingMessages(channel, result);
|
||||
finalizeMessageDataRequest(channel, requestId);
|
||||
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||
finalizeMessageDataRequest(channel, requestId);
|
||||
}).afterDelay(kSmallDelayMs).send();
|
||||
@@ -599,37 +604,6 @@ void ApiWrap::resolveMessageDatas() {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId requestId) {
|
||||
const auto handleResult = [&](auto &&result) {
|
||||
_session->data().processUsers(result.vusers());
|
||||
_session->data().processChats(result.vchats());
|
||||
_session->data().processMessages(
|
||||
result.vmessages(),
|
||||
NewMessageType::Existing);
|
||||
};
|
||||
switch (msgs.type()) {
|
||||
case mtpc_messages_messages:
|
||||
handleResult(msgs.c_messages_messages());
|
||||
break;
|
||||
case mtpc_messages_messagesSlice:
|
||||
handleResult(msgs.c_messages_messagesSlice());
|
||||
break;
|
||||
case mtpc_messages_channelMessages: {
|
||||
auto &d = msgs.c_messages_channelMessages();
|
||||
if (channel) {
|
||||
channel->ptsReceived(d.vpts().v);
|
||||
} else {
|
||||
LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotDependencyItem)"));
|
||||
}
|
||||
handleResult(d);
|
||||
} break;
|
||||
case mtpc_messages_messagesNotModified:
|
||||
LOG(("API Error: received messages.messagesNotModified! (ApiWrap::gotDependencyItem)"));
|
||||
break;
|
||||
}
|
||||
finalizeMessageDataRequest(channel, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::finalizeMessageDataRequest(
|
||||
ChannelData *channel,
|
||||
mtpRequestId requestId) {
|
||||
@@ -661,8 +635,8 @@ QString ApiWrap::exportDirectMessageLink(
|
||||
const auto fallback = [&] {
|
||||
auto linkChannel = channel;
|
||||
auto linkItemId = item->id;
|
||||
auto linkCommentId = 0;
|
||||
auto linkThreadId = 0;
|
||||
auto linkCommentId = MsgId();
|
||||
auto linkThreadId = MsgId();
|
||||
if (inRepliesContext) {
|
||||
if (const auto rootId = item->replyToTop()) {
|
||||
const auto root = item->history()->owner().message(
|
||||
@@ -692,11 +666,11 @@ QString ApiWrap::exportDirectMessageLink(
|
||||
: "c/" + QString::number(peerToChannel(linkChannel->id).bare);
|
||||
const auto query = base
|
||||
+ '/'
|
||||
+ QString::number(linkItemId)
|
||||
+ QString::number(linkItemId.bare)
|
||||
+ (linkCommentId
|
||||
? "?comment=" + QString::number(linkCommentId)
|
||||
? "?comment=" + QString::number(linkCommentId.bare)
|
||||
: linkThreadId
|
||||
? "?thread=" + QString::number(linkThreadId)
|
||||
? "?thread=" + QString::number(linkThreadId.bare)
|
||||
: "");
|
||||
if (linkChannel->hasUsername()
|
||||
&& !linkChannel->isMegagroup()
|
||||
@@ -1277,7 +1251,7 @@ void ApiWrap::migrateDone(
|
||||
void ApiWrap::migrateFail(not_null<PeerData*> peer, const MTP::Error &error) {
|
||||
const auto &type = error.type();
|
||||
if (type == qstr("CHANNELS_TOO_MUCH")) {
|
||||
Ui::show(Box<InformBox>(tr::lng_migrate_error(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_migrate_error(tr::now)));
|
||||
}
|
||||
if (auto handlers = _migrateCallbacks.take(peer)) {
|
||||
for (auto &handler : *handlers) {
|
||||
@@ -1758,7 +1732,7 @@ void ApiWrap::deleteAllFromUser(
|
||||
? history->collectMessagesFromUserToDelete(from)
|
||||
: QVector<MsgId>();
|
||||
const auto channelId = peerToChannel(channel->id);
|
||||
for (const auto msgId : ids) {
|
||||
for (const auto &msgId : ids) {
|
||||
if (const auto item = _session->data().message(channelId, msgId)) {
|
||||
item->destroy();
|
||||
}
|
||||
@@ -2110,13 +2084,14 @@ void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
|
||||
} else if (error.type() == qstr("CHANNEL_PRIVATE")
|
||||
|| error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA")
|
||||
|| error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
|
||||
Ui::show(Box<InformBox>(channel->isMegagroup()
|
||||
Ui::show(Box<Ui::InformBox>(channel->isMegagroup()
|
||||
? tr::lng_group_not_accessible(tr::now)
|
||||
: tr::lng_channel_not_accessible(tr::now)));
|
||||
} else if (error.type() == qstr("CHANNELS_TOO_MUCH")) {
|
||||
Ui::show(Box<InformBox>(tr::lng_join_channel_error(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(
|
||||
tr::lng_join_channel_error(tr::now)));
|
||||
} else if (error.type() == qstr("USERS_TOO_MUCH")) {
|
||||
Ui::show(Box<InformBox>(tr::lng_group_full(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_group_full(tr::now)));
|
||||
}
|
||||
_channelAmInRequests.remove(channel);
|
||||
}).send();
|
||||
@@ -3288,7 +3263,7 @@ void ApiWrap::requestMessageAfterDate(
|
||||
// So we request a message with offset_date = desired_date - 1 and add_offset = -1.
|
||||
// This should give us the first message with date >= desired_date.
|
||||
const auto offsetId = 0;
|
||||
const auto offsetDate = static_cast<int>(base::QDateToDateTime(date).toTime_t()) - 1;
|
||||
const auto offsetDate = static_cast<int>(date.startOfDay().toSecsSinceEpoch()) - 1;
|
||||
const auto addOffset = -1;
|
||||
const auto limit = 1;
|
||||
const auto maxId = 0;
|
||||
@@ -3652,8 +3627,9 @@ void ApiWrap::forwardMessages(
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
|
||||
histories.readInbox(history);
|
||||
|
||||
if (!action.options.scheduled) {
|
||||
histories.readInbox(history);
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
|
||||
@@ -3724,7 +3700,7 @@ void ApiWrap::forwardMessages(
|
||||
ids.reserve(count);
|
||||
randomIds.reserve(count);
|
||||
for (const auto item : draft.items) {
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
if (genClientSideMessage) {
|
||||
if (const auto message = item->toHistoryMessage()) {
|
||||
const auto newId = FullMsgId(
|
||||
@@ -3835,7 +3811,7 @@ void ApiWrap::sendSharedContact(
|
||||
MTP_string(lastName),
|
||||
MTP_string(), // vcard
|
||||
MTP_long(userId.bare)),
|
||||
MTPReplyMarkup());
|
||||
HistoryMessageMarkupData());
|
||||
|
||||
const auto media = MTP_inputMediaContact(
|
||||
MTP_string(phone),
|
||||
@@ -4034,7 +4010,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
auto newId = FullMsgId(
|
||||
peerToChannel(peer->id),
|
||||
_session->data().nextLocalMessageId());
|
||||
auto randomId = openssl::RandomValue<uint64>();
|
||||
auto randomId = base::RandomValue<uint64>();
|
||||
|
||||
TextUtilities::Trim(sending);
|
||||
|
||||
@@ -4099,7 +4075,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
messagePostAuthor,
|
||||
sending,
|
||||
media,
|
||||
MTPReplyMarkup());
|
||||
HistoryMessageMarkupData());
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_SendMessage(
|
||||
MTP_flags(sendFlags),
|
||||
@@ -4158,7 +4134,7 @@ void ApiWrap::sendBotStart(not_null<UserData*> bot, PeerData *chat) {
|
||||
sendMessage(std::move(message));
|
||||
return;
|
||||
}
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
request(MTPmessages_StartBot(
|
||||
bot->inputUser,
|
||||
chat ? chat->input : MTP_inputPeerEmpty(),
|
||||
@@ -4184,7 +4160,7 @@ void ApiWrap::sendInlineResult(
|
||||
const auto newId = FullMsgId(
|
||||
peerToChannel(peer->id),
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
|
||||
auto flags = NewMessageFlags(peer);
|
||||
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
|
||||
@@ -4340,7 +4316,7 @@ void ApiWrap::sendMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputMedia &media,
|
||||
Api::SendOptions options) {
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
_session->data().registerMessageRandomId(randomId, item->fullId());
|
||||
|
||||
sendMediaWithRandomId(item, media, options, randomId);
|
||||
@@ -4414,7 +4390,7 @@ void ApiWrap::sendAlbumWithUploaded(
|
||||
const MessageGroupId &groupId,
|
||||
const MTPInputMedia &media) {
|
||||
const auto localId = item->fullId();
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
_session->data().registerMessageRandomId(randomId, localId);
|
||||
|
||||
const auto albumIt = _sendingAlbums.find(groupId.raw());
|
||||
@@ -4523,105 +4499,6 @@ FileLoadTo ApiWrap::fileLoadTaskOptions(const SendAction &action) const {
|
||||
action.replaceMediaOf);
|
||||
}
|
||||
|
||||
void ApiWrap::uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image) {
|
||||
peer = peer->migrateToOrMe();
|
||||
const auto ready = PreparePeerPhoto(
|
||||
instance().mainDcId(),
|
||||
peer->id,
|
||||
std::move(image));
|
||||
|
||||
const auto fakeId = FullMsgId(
|
||||
peerToChannel(peer->id),
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto already = ranges::find(
|
||||
_peerPhotoUploads,
|
||||
peer,
|
||||
[](const auto &pair) { return pair.second; });
|
||||
if (already != end(_peerPhotoUploads)) {
|
||||
_session->uploader().cancel(already->first);
|
||||
_peerPhotoUploads.erase(already);
|
||||
}
|
||||
_peerPhotoUploads.emplace(fakeId, peer);
|
||||
_session->uploader().uploadMedia(fakeId, ready);
|
||||
}
|
||||
|
||||
void ApiWrap::photoUploadReady(
|
||||
const FullMsgId &msgId,
|
||||
const MTPInputFile &file) {
|
||||
if (const auto maybePeer = _peerPhotoUploads.take(msgId)) {
|
||||
const auto peer = *maybePeer;
|
||||
const auto applier = [=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
};
|
||||
if (peer->isSelf()) {
|
||||
request(MTPphotos_UploadProfilePhoto(
|
||||
MTP_flags(MTPphotos_UploadProfilePhoto::Flag::f_file),
|
||||
file,
|
||||
MTPInputFile(), // video
|
||||
MTPdouble() // video_start_ts
|
||||
)).done([=](const MTPphotos_Photo &result) {
|
||||
result.match([&](const MTPDphotos_photo &data) {
|
||||
_session->data().processPhoto(data.vphoto());
|
||||
_session->data().processUsers(data.vusers());
|
||||
});
|
||||
}).send();
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
const auto history = _session->data().history(chat);
|
||||
history->sendRequestId = request(MTPmessages_EditChatPhoto(
|
||||
chat->inputChat,
|
||||
MTP_inputChatUploadedPhoto(
|
||||
MTP_flags(MTPDinputChatUploadedPhoto::Flag::f_file),
|
||||
file,
|
||||
MTPInputFile(), // video
|
||||
MTPdouble()) // video_start_ts
|
||||
)).done(applier).afterRequest(history->sendRequestId).send();
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
const auto history = _session->data().history(channel);
|
||||
history->sendRequestId = request(MTPchannels_EditPhoto(
|
||||
channel->inputChannel,
|
||||
MTP_inputChatUploadedPhoto(
|
||||
MTP_flags(MTPDinputChatUploadedPhoto::Flag::f_file),
|
||||
file,
|
||||
MTPInputFile(), // video
|
||||
MTPdouble()) // video_start_ts
|
||||
)).done(applier).afterRequest(history->sendRequestId).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::clearPeerPhoto(not_null<PhotoData*> photo) {
|
||||
const auto self = _session->user();
|
||||
if (self->userpicPhotoId() == photo->id) {
|
||||
request(MTPphotos_UpdateProfilePhoto(
|
||||
MTP_inputPhotoEmpty()
|
||||
)).done([=](const MTPphotos_Photo &result) {
|
||||
self->setPhoto(MTP_userProfilePhotoEmpty());
|
||||
}).send();
|
||||
} else if (photo->peer && photo->peer->userpicPhotoId() == photo->id) {
|
||||
const auto applier = [=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
};
|
||||
if (const auto chat = photo->peer->asChat()) {
|
||||
request(MTPmessages_EditChatPhoto(
|
||||
chat->inputChat,
|
||||
MTP_inputChatPhotoEmpty()
|
||||
)).done(applier).send();
|
||||
} else if (const auto channel = photo->peer->asChannel()) {
|
||||
request(MTPchannels_EditPhoto(
|
||||
channel->inputChannel,
|
||||
MTP_inputChatPhotoEmpty()
|
||||
)).done(applier).send();
|
||||
}
|
||||
} else {
|
||||
request(MTPphotos_DeletePhotos(
|
||||
MTP_vector<MTPInputPhoto>(1, photo->mtpInput())
|
||||
)).send();
|
||||
_session->storage().remove(Storage::UserPhotosRemoveOne(
|
||||
peerToUser(self->id),
|
||||
photo->id));
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::reloadContactSignupSilent() {
|
||||
if (_contactSignupSilentRequestId) {
|
||||
return;
|
||||
@@ -4664,34 +4541,27 @@ void ApiWrap::saveContactSignupSilent(bool silent) {
|
||||
_contactSignupSilentRequestId = requestId;
|
||||
}
|
||||
|
||||
void ApiWrap::saveSelfBio(const QString &text, FnMut<void()> done) {
|
||||
if (_saveBioRequestId) {
|
||||
if (text != _saveBioText) {
|
||||
request(_saveBioRequestId).cancel();
|
||||
void ApiWrap::saveSelfBio(const QString &text) {
|
||||
if (_bio.requestId) {
|
||||
if (text != _bio.requestedText) {
|
||||
request(_bio.requestId).cancel();
|
||||
} else {
|
||||
if (done) {
|
||||
_saveBioDone = std::move(done);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
_saveBioText = text;
|
||||
_saveBioDone = std::move(done);
|
||||
_saveBioRequestId = request(MTPaccount_UpdateProfile(
|
||||
_bio.requestedText = text;
|
||||
_bio.requestId = request(MTPaccount_UpdateProfile(
|
||||
MTP_flags(MTPaccount_UpdateProfile::Flag::f_about),
|
||||
MTPstring(),
|
||||
MTPstring(),
|
||||
MTP_string(text)
|
||||
)).done([=](const MTPUser &result) {
|
||||
_saveBioRequestId = 0;
|
||||
_bio.requestId = 0;
|
||||
|
||||
_session->data().processUsers(MTP_vector<MTPUser>(1, result));
|
||||
_session->user()->setAbout(_saveBioText);
|
||||
if (_saveBioDone) {
|
||||
_saveBioDone();
|
||||
}
|
||||
_session->data().processUser(result);
|
||||
_session->user()->setAbout(_bio.requestedText);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_saveBioRequestId = 0;
|
||||
_bio.requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -4731,167 +4601,18 @@ Api::InviteLinks &ApiWrap::inviteLinks() {
|
||||
return *_inviteLinks;
|
||||
}
|
||||
|
||||
void ApiWrap::createPoll(
|
||||
const PollData &data,
|
||||
const SendAction &action,
|
||||
Fn<void()> done,
|
||||
Fn<void(const MTP::Error &error)> fail) {
|
||||
sendAction(action);
|
||||
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (action.replyTo) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto clearCloudDraft = action.clearDraft;
|
||||
if (clearCloudDraft) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||
history->clearLocalDraft();
|
||||
history->clearCloudDraft();
|
||||
history->startSavingCloudDraft();
|
||||
}
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
if (action.options.scheduled) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
}
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
const auto replyTo = action.replyTo;
|
||||
history->sendRequestId = request(MTPmessages_SendMedia(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(replyTo),
|
||||
PollDataToInputMedia(&data),
|
||||
MTP_string(),
|
||||
MTP_long(openssl::RandomValue<uint64>()),
|
||||
MTPReplyMarkup(),
|
||||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(action.options.scheduled)
|
||||
)).done([=](
|
||||
const MTPUpdates &result,
|
||||
const MTP::Response &response) mutable {
|
||||
applyUpdates(result);
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
_session->changes().historyUpdated(
|
||||
history,
|
||||
(action.options.scheduled
|
||||
? Data::HistoryUpdate::Flag::ScheduledSent
|
||||
: Data::HistoryUpdate::Flag::MessageSent));
|
||||
done();
|
||||
finish();
|
||||
}).fail([=](
|
||||
const MTP::Error &error,
|
||||
const MTP::Response &response) mutable {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
fail(error);
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
Api::ViewsManager &ApiWrap::views() {
|
||||
return *_views;
|
||||
}
|
||||
|
||||
void ApiWrap::sendPollVotes(
|
||||
FullMsgId itemId,
|
||||
const std::vector<QByteArray> &options) {
|
||||
if (_pollVotesRequestIds.contains(itemId)) {
|
||||
return;
|
||||
}
|
||||
const auto item = _session->data().message(itemId);
|
||||
const auto media = item ? item->media() : nullptr;
|
||||
const auto poll = media ? media->poll() : nullptr;
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto showSending = poll && !options.empty();
|
||||
const auto hideSending = [=] {
|
||||
if (showSending) {
|
||||
if (const auto item = _session->data().message(itemId)) {
|
||||
poll->sendingVotes.clear();
|
||||
_session->data().requestItemRepaint(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (showSending) {
|
||||
poll->sendingVotes = options;
|
||||
_session->data().requestItemRepaint(item);
|
||||
}
|
||||
|
||||
auto prepared = QVector<MTPbytes>();
|
||||
prepared.reserve(options.size());
|
||||
ranges::transform(
|
||||
options,
|
||||
ranges::back_inserter(prepared),
|
||||
[](const QByteArray &option) { return MTP_bytes(option); });
|
||||
const auto requestId = request(MTPmessages_SendVote(
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTP_vector<MTPbytes>(prepared)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_pollVotesRequestIds.erase(itemId);
|
||||
hideSending();
|
||||
applyUpdates(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_pollVotesRequestIds.erase(itemId);
|
||||
hideSending();
|
||||
}).send();
|
||||
_pollVotesRequestIds.emplace(itemId, requestId);
|
||||
Api::ConfirmPhone &ApiWrap::confirmPhone() {
|
||||
return *_confirmPhone;
|
||||
}
|
||||
|
||||
void ApiWrap::closePoll(not_null<HistoryItem*> item) {
|
||||
const auto itemId = item->fullId();
|
||||
if (_pollCloseRequestIds.contains(itemId)) {
|
||||
return;
|
||||
}
|
||||
const auto media = item ? item->media() : nullptr;
|
||||
const auto poll = media ? media->poll() : nullptr;
|
||||
if (!poll) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = request(MTPmessages_EditMessage(
|
||||
MTP_flags(MTPmessages_EditMessage::Flag::f_media),
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTPstring(),
|
||||
PollDataToInputMedia(poll, true),
|
||||
MTPReplyMarkup(),
|
||||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(0) // schedule_date
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_pollCloseRequestIds.erase(itemId);
|
||||
applyUpdates(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_pollCloseRequestIds.erase(itemId);
|
||||
}).send();
|
||||
_pollCloseRequestIds.emplace(itemId, requestId);
|
||||
Api::PeerPhoto &ApiWrap::peerPhoto() {
|
||||
return *_peerPhoto;
|
||||
}
|
||||
|
||||
void ApiWrap::reloadPollResults(not_null<HistoryItem*> item) {
|
||||
const auto itemId = item->fullId();
|
||||
if (!IsServerMsgId(item->id)
|
||||
|| _pollReloadRequestIds.contains(itemId)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = request(MTPmessages_GetPollResults(
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_pollReloadRequestIds.erase(itemId);
|
||||
applyUpdates(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_pollReloadRequestIds.erase(itemId);
|
||||
}).send();
|
||||
_pollReloadRequestIds.emplace(itemId, requestId);
|
||||
Api::Polls &ApiWrap::polls() {
|
||||
return *_polls;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,10 @@ class SensitiveContent;
|
||||
class GlobalPrivacy;
|
||||
class UserPrivacy;
|
||||
class InviteLinks;
|
||||
class ViewsManager;
|
||||
class ConfirmPhone;
|
||||
class PeerPhoto;
|
||||
class Polls;
|
||||
|
||||
namespace details {
|
||||
|
||||
@@ -381,15 +385,12 @@ public:
|
||||
uint64 randomId = 0,
|
||||
FullMsgId itemId = FullMsgId());
|
||||
|
||||
void uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image);
|
||||
void clearPeerPhoto(not_null<PhotoData*> photo);
|
||||
|
||||
void reloadContactSignupSilent();
|
||||
rpl::producer<bool> contactSignupSilent() const;
|
||||
std::optional<bool> contactSignupSilentCurrent() const;
|
||||
void saveContactSignupSilent(bool silent);
|
||||
|
||||
void saveSelfBio(const QString &text, FnMut<void()> done);
|
||||
void saveSelfBio(const QString &text);
|
||||
|
||||
[[nodiscard]] Api::Authorizations &authorizations();
|
||||
[[nodiscard]] Api::AttachedStickers &attachedStickers();
|
||||
@@ -400,17 +401,10 @@ public:
|
||||
[[nodiscard]] Api::GlobalPrivacy &globalPrivacy();
|
||||
[[nodiscard]] Api::UserPrivacy &userPrivacy();
|
||||
[[nodiscard]] Api::InviteLinks &inviteLinks();
|
||||
|
||||
void createPoll(
|
||||
const PollData &data,
|
||||
const SendAction &action,
|
||||
Fn<void()> done,
|
||||
Fn<void(const MTP::Error &error)> fail);
|
||||
void sendPollVotes(
|
||||
FullMsgId itemId,
|
||||
const std::vector<QByteArray> &options);
|
||||
void closePoll(not_null<HistoryItem*> item);
|
||||
void reloadPollResults(not_null<HistoryItem*> item);
|
||||
[[nodiscard]] Api::ViewsManager &views();
|
||||
[[nodiscard]] Api::ConfirmPhone &confirmPhone();
|
||||
[[nodiscard]] Api::PeerPhoto &peerPhoto();
|
||||
[[nodiscard]] Api::Polls &polls();
|
||||
|
||||
void updatePrivacyLastSeens();
|
||||
|
||||
@@ -456,7 +450,6 @@ private:
|
||||
void saveDraftsToCloud();
|
||||
|
||||
void resolveMessageDatas();
|
||||
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId requestId);
|
||||
void finalizeMessageDataRequest(
|
||||
ChannelData *channel,
|
||||
mtpRequestId requestId);
|
||||
@@ -573,8 +566,6 @@ private:
|
||||
FileReferencesHandler &&handler,
|
||||
Request &&data);
|
||||
|
||||
void photoUploadReady(const FullMsgId &msgId, const MTPInputFile &file);
|
||||
|
||||
void migrateDone(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<ChannelData*> channel);
|
||||
@@ -705,11 +696,10 @@ private:
|
||||
|
||||
std::vector<FnMut<void(const MTPUser &)>> _supportContactCallbacks;
|
||||
|
||||
base::flat_map<FullMsgId, not_null<PeerData*>> _peerPhotoUploads;
|
||||
|
||||
mtpRequestId _saveBioRequestId = 0;
|
||||
FnMut<void()> _saveBioDone;
|
||||
QString _saveBioText;
|
||||
struct {
|
||||
mtpRequestId requestId = 0;
|
||||
QString requestedText;
|
||||
} _bio;
|
||||
|
||||
const std::unique_ptr<Api::Authorizations> _authorizations;
|
||||
const std::unique_ptr<Api::AttachedStickers> _attachedStickers;
|
||||
@@ -720,10 +710,10 @@ private:
|
||||
const std::unique_ptr<Api::GlobalPrivacy> _globalPrivacy;
|
||||
const std::unique_ptr<Api::UserPrivacy> _userPrivacy;
|
||||
const std::unique_ptr<Api::InviteLinks> _inviteLinks;
|
||||
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollVotesRequestIds;
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollCloseRequestIds;
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollReloadRequestIds;
|
||||
const std::unique_ptr<Api::ViewsManager> _views;
|
||||
const std::unique_ptr<Api::ConfirmPhone> _confirmPhone;
|
||||
const std::unique_ptr<Api::PeerPhoto> _peerPhoto;
|
||||
const std::unique_ptr<Api::Polls> _polls;
|
||||
|
||||
mtpRequestId _wallPaperRequestId = 0;
|
||||
QString _wallPaperSlug;
|
||||
|
||||
@@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
@@ -104,7 +104,8 @@ void AboutBox::showVersionHistory() {
|
||||
|
||||
QGuiApplication::clipboard()->setText(url);
|
||||
|
||||
Ui::show(Box<InformBox>("The link to the current private alpha version of Telegram Desktop was copied to the clipboard."));
|
||||
Ui::show(Box<Ui::InformBox>("The link to the current private alpha "
|
||||
"version of Telegram Desktop was copied to the clipboard."));
|
||||
} else {
|
||||
UrlClickHandler::Open(Core::App().changelogLink());
|
||||
}
|
||||
|
||||
68
Telegram/SourceFiles/boxes/about_sponsored_box.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
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 "boxes/about_sponsored_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
#include <QtGui/QDesktopServices>
|
||||
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
constexpr auto kUrl = "https://telegram.org/ads"_cs;
|
||||
|
||||
} // namespace
|
||||
|
||||
void AboutSponsoredBox(not_null<Ui::GenericBox*> box) {
|
||||
box->setTitle(tr::lng_sponsored_title());
|
||||
box->setWidth(st::boxWideWidth);
|
||||
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
|
||||
|
||||
const auto addUrl = [&] {
|
||||
const auto &st = st::sponsoredUrlButton;
|
||||
const auto row = box->addRow(object_ptr<RpWidget>(box));
|
||||
row->resize(0, st.height + st.padding.top() + st.padding.bottom());
|
||||
const auto button = Ui::CreateChild<RoundButton>(
|
||||
row,
|
||||
rpl::single<QString>(kUrl.utf8()),
|
||||
st);
|
||||
button->setBrushOverride(Qt::NoBrush);
|
||||
button->setPenOverride(QPen(st::historyLinkInFg));
|
||||
button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||
rpl::combine(
|
||||
row->sizeValue(),
|
||||
button->sizeValue()
|
||||
) | rpl::start_with_next([=](
|
||||
const QSize &rowSize,
|
||||
const QSize &buttonSize) {
|
||||
button->moveToLeft(
|
||||
(rowSize.width() - buttonSize.width()) / 2,
|
||||
(rowSize.height() - buttonSize.height()) / 2);
|
||||
}, row->lifetime());
|
||||
button->addClickHandler([=] {
|
||||
QDesktopServices::openUrl({ kUrl.utf8() });
|
||||
});
|
||||
};
|
||||
|
||||
const auto &stLabel = st::aboutLabel;
|
||||
const auto info1 = box->addRow(object_ptr<FlatLabel>(box, stLabel));
|
||||
info1->setText(tr::lng_sponsored_info_description1(tr::now));
|
||||
|
||||
box->addSkip(st::sponsoredUrlButtonSkip);
|
||||
addUrl();
|
||||
box->addSkip(st::sponsoredUrlButtonSkip);
|
||||
|
||||
const auto info2 = box->addRow(object_ptr<FlatLabel>(box, stLabel));
|
||||
info2->setText(tr::lng_sponsored_info_description2(tr::now));
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
16
Telegram/SourceFiles/boxes/about_sponsored_box.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
void AboutSponsoredBox(not_null<Ui::GenericBox*> box);
|
||||
|
||||
} // namespace Ui
|
||||
@@ -8,15 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/add_contact_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "base/flat_set.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "base/random.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/add_participants_box.h"
|
||||
#include "boxes/peers/edit_peer_common.h"
|
||||
#include "boxes/peers/edit_participant_box.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/application.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "countries/countries_instance.h" // Countries::ExtractPhoneCode.
|
||||
@@ -36,26 +34,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_cloud_file.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "api/api_peer_photo.h"
|
||||
#include "main/main_session.h"
|
||||
#include "facades.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxGroupChannelTitle = 128; // See also edit_peer_info_box.
|
||||
constexpr auto kMaxUserFirstLastName = 64; // See also edit_contact_box.
|
||||
constexpr auto kMaxChannelDescription = 255; // See also edit_peer_info_box.
|
||||
constexpr auto kMinUsernameLength = 5;
|
||||
|
||||
bool IsValidPhone(QString phone) {
|
||||
phone = phone.replace(QRegularExpression(qsl("[^\\d]")), QString());
|
||||
return (phone.length() >= 8)
|
||||
@@ -73,7 +66,7 @@ void ChatCreateDone(
|
||||
const MTPUpdates &updates) {
|
||||
navigation->session().api().applyUpdates(updates);
|
||||
|
||||
auto success = base::make_optional(&updates)
|
||||
const auto success = base::make_optional(&updates)
|
||||
| [](auto updates) -> std::optional<const QVector<MTPChat>*> {
|
||||
switch (updates->type()) {
|
||||
case mtpc_updates:
|
||||
@@ -97,7 +90,7 @@ void ChatCreateDone(
|
||||
}
|
||||
| [&](not_null<ChatData*> chat) {
|
||||
if (!image.isNull()) {
|
||||
chat->session().api().uploadPeerPhoto(
|
||||
chat->session().api().peerPhoto().upload(
|
||||
chat,
|
||||
std::move(image));
|
||||
}
|
||||
@@ -164,7 +157,7 @@ void ShowAddParticipantsError(
|
||||
*weak = Ui::show(std::move(box));
|
||||
};
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_cant_invite_offer_admin(tr::now),
|
||||
tr::lng_cant_invite_make_admin(tr::now),
|
||||
tr::lng_cancel(tr::now),
|
||||
@@ -203,7 +196,7 @@ void ShowAddParticipantsError(
|
||||
}
|
||||
return tr::lng_failed_add_participant(tr::now);
|
||||
}();
|
||||
Ui::show(Box<InformBox>(text), Ui::LayerOption::KeepOther);
|
||||
Ui::show(Box<Ui::InformBox>(text), Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
class RevokePublicLinkBox::Inner : public TWidget {
|
||||
@@ -280,7 +273,8 @@ void AddContactBox::prepare() {
|
||||
setTabOrder(_last, _first);
|
||||
}
|
||||
const auto readyToAdd = !_phone->getLastText().isEmpty()
|
||||
&& (!_first->getLastText().isEmpty() || !_last->getLastText().isEmpty());
|
||||
&& (!_first->getLastText().isEmpty()
|
||||
|| !_last->getLastText().isEmpty());
|
||||
setTitle(readyToAdd
|
||||
? tr::lng_confirm_contact_data()
|
||||
: tr::lng_enter_contact_data());
|
||||
@@ -290,11 +284,21 @@ void AddContactBox::prepare() {
|
||||
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
|
||||
|
||||
setDimensions(st::boxWideWidth, st::contactPadding.top() + _first->height() + st::contactSkip + _last->height() + st::contactPhoneSkip + _phone->height() + st::contactPadding.bottom() + st::boxPadding.bottom());
|
||||
setDimensions(
|
||||
st::boxWideWidth,
|
||||
st::contactPadding.top()
|
||||
+ _first->height()
|
||||
+ st::contactSkip
|
||||
+ _last->height()
|
||||
+ st::contactPhoneSkip
|
||||
+ _phone->height()
|
||||
+ st::contactPadding.bottom()
|
||||
+ st::boxPadding.bottom());
|
||||
}
|
||||
|
||||
void AddContactBox::setInnerFocus() {
|
||||
if ((_first->getLastText().isEmpty() && _last->getLastText().isEmpty()) || !_phone->isEnabled()) {
|
||||
if ((_first->getLastText().isEmpty() && _last->getLastText().isEmpty())
|
||||
|| !_phone->isEnabled()) {
|
||||
(_invertOrder ? _last : _first)->setFocusFast();
|
||||
_phone->finishAnimating();
|
||||
} else {
|
||||
@@ -309,8 +313,18 @@ void AddContactBox::paintEvent(QPaintEvent *e) {
|
||||
if (_retrying) {
|
||||
p.setPen(st::boxTextFg);
|
||||
p.setFont(st::boxTextFont);
|
||||
auto textHeight = height() - st::contactPadding.top() - st::contactPadding.bottom() - st::boxPadding.bottom();
|
||||
p.drawText(QRect(st::boxPadding.left(), st::contactPadding.top(), width() - st::boxPadding.left() - st::boxPadding.right(), textHeight), tr::lng_contact_not_joined(tr::now, lt_name, _sentName), style::al_topleft);
|
||||
const auto textHeight = height()
|
||||
- st::contactPadding.top()
|
||||
- st::contactPadding.bottom()
|
||||
- st::boxPadding.bottom();
|
||||
p.drawText(
|
||||
QRect(
|
||||
st::boxPadding.left(),
|
||||
st::contactPadding.top(),
|
||||
width() - st::boxPadding.left() - st::boxPadding.right(),
|
||||
textHeight),
|
||||
tr::lng_contact_not_joined(tr::now, lt_name, _sentName),
|
||||
style::al_topleft);
|
||||
} else {
|
||||
st::contactUserIcon.paint(
|
||||
p,
|
||||
@@ -328,18 +342,25 @@ void AddContactBox::paintEvent(QPaintEvent *e) {
|
||||
void AddContactBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_first->resize(width() - st::boxPadding.left() - st::contactPadding.left() - st::boxPadding.right(), _first->height());
|
||||
_first->resize(
|
||||
width()
|
||||
- st::boxPadding.left()
|
||||
- st::contactPadding.left()
|
||||
- st::boxPadding.right(),
|
||||
_first->height());
|
||||
_last->resize(_first->width(), _last->height());
|
||||
_phone->resize(_first->width(), _last->height());
|
||||
if (_invertOrder) {
|
||||
_last->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), st::contactPadding.top());
|
||||
_first->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _last->y() + _last->height() + st::contactSkip);
|
||||
_phone->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _first->y() + _first->height() + st::contactPhoneSkip);
|
||||
} else {
|
||||
_first->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), st::contactPadding.top());
|
||||
_last->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _first->y() + _first->height() + st::contactSkip);
|
||||
_phone->moveToLeft(st::boxPadding.left() + st::contactPadding.left(), _last->y() + _last->height() + st::contactPhoneSkip);
|
||||
}
|
||||
const auto left = st::boxPadding.left() + st::contactPadding.left();
|
||||
const auto &firstRow = _invertOrder ? _last : _first;
|
||||
const auto &secondRow = _invertOrder ? _first : _last;
|
||||
const auto &thirdRow = _phone;
|
||||
firstRow->moveToLeft(left, st::contactPadding.top());
|
||||
secondRow->moveToLeft(
|
||||
left,
|
||||
firstRow->y() + firstRow->height() + st::contactSkip);
|
||||
thirdRow->moveToLeft(
|
||||
left,
|
||||
secondRow->y() + secondRow->height() + st::contactPhoneSkip);
|
||||
}
|
||||
|
||||
void AddContactBox::submit() {
|
||||
@@ -361,9 +382,11 @@ void AddContactBox::save() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto firstName = TextUtilities::PrepareForSending(_first->getLastText());
|
||||
auto lastName = TextUtilities::PrepareForSending(_last->getLastText());
|
||||
auto phone = _phone->getLastText().trimmed();
|
||||
auto firstName = TextUtilities::PrepareForSending(
|
||||
_first->getLastText());
|
||||
auto lastName = TextUtilities::PrepareForSending(
|
||||
_last->getLastText());
|
||||
const auto phone = _phone->getLastText().trimmed();
|
||||
if (firstName.isEmpty() && lastName.isEmpty()) {
|
||||
if (_invertOrder) {
|
||||
_last->setFocus();
|
||||
@@ -383,7 +406,7 @@ void AddContactBox::save() {
|
||||
lastName = QString();
|
||||
}
|
||||
_sentName = firstName;
|
||||
_contactId = openssl::RandomValue<uint64>();
|
||||
_contactId = base::RandomValue<uint64>();
|
||||
_addRequest = _session->api().request(MTPcontacts_ImportContacts(
|
||||
MTP_vector<MTPInputContact>(
|
||||
1,
|
||||
@@ -478,7 +501,7 @@ void GroupInfoBox::prepare() {
|
||||
? tr::lng_dlg_new_channel_name
|
||||
: tr::lng_dlg_new_group_name)(),
|
||||
_initialTitle);
|
||||
_title->setMaxLength(kMaxGroupChannelTitle);
|
||||
_title->setMaxLength(Ui::EditPeer::kMaxGroupChannelTitle);
|
||||
_title->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
_title->setInstantReplacesEnabled(
|
||||
Core::App().settings().replaceEmojiValue());
|
||||
@@ -494,16 +517,22 @@ void GroupInfoBox::prepare() {
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
tr::lng_create_group_description());
|
||||
_description->show();
|
||||
_description->setMaxLength(kMaxChannelDescription);
|
||||
_description->setMaxLength(Ui::EditPeer::kMaxChannelDescription);
|
||||
_description->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
_description->setInstantReplacesEnabled(
|
||||
Core::App().settings().replaceEmojiValue());
|
||||
_description->setSubmitSettings(
|
||||
Core::App().settings().sendSubmitWay());
|
||||
|
||||
connect(_description, &Ui::InputField::resized, [=] { descriptionResized(); });
|
||||
connect(_description, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_description, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
connect(_description, &Ui::InputField::resized, [=] {
|
||||
descriptionResized();
|
||||
});
|
||||
connect(_description, &Ui::InputField::submitted, [=] {
|
||||
submit();
|
||||
});
|
||||
connect(_description, &Ui::InputField::cancelled, [=] {
|
||||
closeBox();
|
||||
});
|
||||
|
||||
Ui::Emoji::SuggestionsController::Init(
|
||||
getDelegate()->outerContainer(),
|
||||
@@ -530,17 +559,34 @@ void GroupInfoBox::setInnerFocus() {
|
||||
void GroupInfoBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_photo->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top());
|
||||
_photo->moveToLeft(
|
||||
st::boxPadding.left() + st::newGroupInfoPadding.left(),
|
||||
st::boxPadding.top() + st::newGroupInfoPadding.top());
|
||||
|
||||
auto nameLeft = st::defaultUserpicButton.size.width()
|
||||
const auto nameLeft = st::defaultUserpicButton.size.width()
|
||||
+ st::newGroupNamePosition.x();
|
||||
_title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right() - nameLeft, _title->height());
|
||||
_title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y());
|
||||
_title->resize(
|
||||
width()
|
||||
- st::boxPadding.left()
|
||||
- st::newGroupInfoPadding.left()
|
||||
- st::boxPadding.right()
|
||||
- nameLeft,
|
||||
_title->height());
|
||||
_title->moveToLeft(
|
||||
st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft,
|
||||
st::boxPadding.top()
|
||||
+ st::newGroupInfoPadding.top()
|
||||
+ st::newGroupNamePosition.y());
|
||||
if (_description) {
|
||||
_description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description->height());
|
||||
auto descriptionLeft = st::boxPadding.left()
|
||||
_description->resize(
|
||||
width()
|
||||
- st::boxPadding.left()
|
||||
- st::newGroupInfoPadding.left()
|
||||
- st::boxPadding.right(),
|
||||
_description->height());
|
||||
const auto descriptionLeft = st::boxPadding.left()
|
||||
+ st::newGroupInfoPadding.left();
|
||||
auto descriptionTop = st::boxPadding.top()
|
||||
const auto descriptionTop = st::boxPadding.top()
|
||||
+ st::newGroupInfoPadding.top()
|
||||
+ st::defaultUserpicButton.size.height()
|
||||
+ st::newGroupDescriptionPadding.top();
|
||||
@@ -596,18 +642,18 @@ void GroupInfoBox::createGroup(
|
||||
}
|
||||
} else if (error.type() == qstr("USERS_TOO_FEW")) {
|
||||
Ui::show(
|
||||
Box<InformBox>(tr::lng_cant_invite_privacy(tr::now)),
|
||||
Box<Ui::InformBox>(tr::lng_cant_invite_privacy(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
} else if (error.type() == qstr("PEER_FLOOD")) {
|
||||
Ui::show(
|
||||
Box<InformBox>(
|
||||
Box<Ui::InformBox>(
|
||||
PeerFloodErrorText(
|
||||
&_navigation->session(),
|
||||
PeerFloodType::InviteGroup)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
} else if (error.type() == qstr("USER_RESTRICTED")) {
|
||||
Ui::show(
|
||||
Box<InformBox>(tr::lng_cant_do_this(tr::now)),
|
||||
Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
}).send();
|
||||
@@ -654,7 +700,9 @@ void GroupInfoBox::submit() {
|
||||
}
|
||||
}
|
||||
|
||||
void GroupInfoBox::createChannel(const QString &title, const QString &description) {
|
||||
void GroupInfoBox::createChannel(
|
||||
const QString &title,
|
||||
const QString &description) {
|
||||
Expects(!_creationRequestId);
|
||||
|
||||
const auto flags = (_type == Type::Megagroup)
|
||||
@@ -677,11 +725,13 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
|
||||
case mtpc_updatesCombined:
|
||||
return &updates->c_updatesCombined().vchats().v;
|
||||
}
|
||||
LOG(("API Error: unexpected update cons %1 (GroupInfoBox::createChannel)").arg(updates->type()));
|
||||
LOG(("API Error: unexpected update cons %1 "
|
||||
"(GroupInfoBox::createChannel)").arg(updates->type()));
|
||||
return std::nullopt;
|
||||
}
|
||||
| [](auto chats) {
|
||||
return (!chats->empty() && chats->front().type() == mtpc_channel)
|
||||
return (!chats->empty()
|
||||
&& chats->front().type() == mtpc_channel)
|
||||
? base::make_optional(chats)
|
||||
: std::nullopt;
|
||||
}
|
||||
@@ -692,7 +742,7 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
|
||||
| [&](not_null<ChannelData*> channel) {
|
||||
auto image = _photo->takeResultImage();
|
||||
if (!image.isNull()) {
|
||||
channel->session().api().uploadPeerPhoto(
|
||||
channel->session().api().peerPhoto().upload(
|
||||
channel,
|
||||
std::move(image));
|
||||
}
|
||||
@@ -700,7 +750,8 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
|
||||
checkInviteLink();
|
||||
};
|
||||
if (!success) {
|
||||
LOG(("API Error: channel not found in updates (GroupInfoBox::creationDone)"));
|
||||
LOG(("API Error: channel not found in updates "
|
||||
"(GroupInfoBox::creationDone)"));
|
||||
closeBox();
|
||||
}
|
||||
}).fail([this](const MTP::Error &error) {
|
||||
@@ -709,9 +760,9 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
|
||||
_title->setFocus();
|
||||
_title->showError();
|
||||
} else if (error.type() == qstr("USER_RESTRICTED")) {
|
||||
Ui::show(Box<InformBox>(tr::lng_cant_do_this(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now)));
|
||||
} else if (error.type() == qstr("CHANNELS_TOO_MUCH")) {
|
||||
Ui::show(Box<InformBox>(tr::lng_cant_do_this(tr::now))); // TODO
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now))); // TODO
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
@@ -813,7 +864,8 @@ SetupChannelBox::SetupChannelBox(
|
||||
st::setupChannelLink,
|
||||
nullptr,
|
||||
channel->username,
|
||||
channel->session().createInternalLink(QString())) {
|
||||
channel->session().createInternalLink(QString()))
|
||||
, _checkTimer([=] { check(); }) {
|
||||
}
|
||||
|
||||
void SetupChannelBox::prepare() {
|
||||
@@ -825,7 +877,8 @@ void SetupChannelBox::prepare() {
|
||||
_channel->inputChannel,
|
||||
MTP_string("preston")
|
||||
)).fail([=](const MTP::Error &error) {
|
||||
firstCheckFail(error);
|
||||
_checkRequestId = 0;
|
||||
firstCheckFail(error.type());
|
||||
}).send();
|
||||
|
||||
addButton(tr::lng_settings_save(), [=] { save(); });
|
||||
@@ -836,10 +889,9 @@ void SetupChannelBox::prepare() {
|
||||
connect(_link, &Ui::MaskedInputField::changed, [=] { handleChange(); });
|
||||
_link->setVisible(_privacyGroup->value() == Privacy::Public);
|
||||
|
||||
_checkTimer.setSingleShot(true);
|
||||
connect(&_checkTimer, &QTimer::timeout, [=] { check(); });
|
||||
|
||||
_privacyGroup->setChangedCallback([this](Privacy value) { privacyChanged(value); });
|
||||
_privacyGroup->setChangedCallback([=](Privacy value) {
|
||||
privacyChanged(value);
|
||||
});
|
||||
|
||||
_channel->session().changes().peerUpdates(
|
||||
_channel,
|
||||
@@ -866,9 +918,20 @@ void SetupChannelBox::setInnerFocus() {
|
||||
}
|
||||
|
||||
void SetupChannelBox::updateMaxHeight() {
|
||||
auto newHeight = st::boxPadding.top() + st::newGroupPadding.top() + _public->heightNoMargins() + _aboutPublicHeight + st::newGroupSkip + _private->heightNoMargins() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom();
|
||||
if (!_channel->isMegagroup() || _privacyGroup->value() == Privacy::Public) {
|
||||
newHeight += st::newGroupLinkPadding.top() + _link->height() + st::newGroupLinkPadding.bottom();
|
||||
auto newHeight = st::boxPadding.top()
|
||||
+ st::newGroupPadding.top()
|
||||
+ _public->heightNoMargins()
|
||||
+ _aboutPublicHeight
|
||||
+ st::newGroupSkip
|
||||
+ _private->heightNoMargins()
|
||||
+ _aboutPrivate.countHeight(_aboutPublicWidth)
|
||||
+ st::newGroupSkip
|
||||
+ st::newGroupPadding.bottom();
|
||||
if (!_channel->isMegagroup()
|
||||
|| _privacyGroup->value() == Privacy::Public) {
|
||||
newHeight += st::newGroupLinkPadding.top()
|
||||
+ _link->height()
|
||||
+ st::newGroupLinkPadding.bottom();
|
||||
}
|
||||
setDimensions(st::boxWideWidth, newHeight);
|
||||
}
|
||||
@@ -894,17 +957,43 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) {
|
||||
p.fillRect(e->rect(), st::boxBg);
|
||||
p.setPen(st::newGroupAboutFg);
|
||||
|
||||
QRect aboutPublic(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadio.diameter + st::defaultBoxCheckbox.textPosition.x(), _public->bottomNoMargins(), _aboutPublicWidth, _aboutPublicHeight);
|
||||
_aboutPublic.drawLeft(p, aboutPublic.x(), aboutPublic.y(), aboutPublic.width(), width());
|
||||
const auto aboutPublic = QRect(
|
||||
st::boxPadding.left()
|
||||
+ st::newGroupPadding.left()
|
||||
+ st::defaultRadio.diameter
|
||||
+ st::defaultBoxCheckbox.textPosition.x(),
|
||||
_public->bottomNoMargins(),
|
||||
_aboutPublicWidth,
|
||||
_aboutPublicHeight);
|
||||
_aboutPublic.drawLeft(
|
||||
p,
|
||||
aboutPublic.x(),
|
||||
aboutPublic.y(),
|
||||
aboutPublic.width(),
|
||||
width());
|
||||
|
||||
QRect aboutPrivate(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadio.diameter + st::defaultBoxCheckbox.textPosition.x(), _private->bottomNoMargins(), _aboutPublicWidth, _aboutPublicHeight);
|
||||
_aboutPrivate.drawLeft(p, aboutPrivate.x(), aboutPrivate.y(), aboutPrivate.width(), width());
|
||||
const auto aboutPrivate = QRect(
|
||||
st::boxPadding.left()
|
||||
+ st::newGroupPadding.left()
|
||||
+ st::defaultRadio.diameter
|
||||
+ st::defaultBoxCheckbox.textPosition.x(),
|
||||
_private->bottomNoMargins(),
|
||||
_aboutPublicWidth,
|
||||
_aboutPublicHeight);
|
||||
_aboutPrivate.drawLeft(
|
||||
p,
|
||||
aboutPrivate.x(),
|
||||
aboutPrivate.y(),
|
||||
aboutPrivate.width(),
|
||||
width());
|
||||
|
||||
if (!_channel->isMegagroup() || !_link->isHidden()) {
|
||||
p.setPen(st::boxTextFg);
|
||||
p.setFont(st::newGroupLinkFont);
|
||||
p.drawTextLeft(
|
||||
st::boxPadding.left() + st::newGroupPadding.left() + st::defaultInputField.textMargins.left(),
|
||||
st::boxPadding.left()
|
||||
+ st::newGroupPadding.left()
|
||||
+ st::defaultInputField.textMargins.left(),
|
||||
_link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop,
|
||||
width(),
|
||||
(_link->isHidden()
|
||||
@@ -916,20 +1005,29 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) {
|
||||
if (!_channel->isMegagroup()) {
|
||||
QTextOption option(style::al_left);
|
||||
option.setWrapMode(QTextOption::WrapAnywhere);
|
||||
p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont);
|
||||
p.setFont(_linkOver
|
||||
? st::boxTextFont->underline()
|
||||
: st::boxTextFont);
|
||||
p.setPen(st::defaultLinkButton.color);
|
||||
auto inviteLinkText = _channel->inviteLink().isEmpty() ? tr::lng_group_invite_create(tr::now) : _channel->inviteLink();
|
||||
const auto inviteLinkText = _channel->inviteLink().isEmpty()
|
||||
? tr::lng_group_invite_create(tr::now)
|
||||
: _channel->inviteLink();
|
||||
p.drawText(_invitationLink, inviteLinkText, option);
|
||||
}
|
||||
} else {
|
||||
const auto top = _link->y()
|
||||
- st::newGroupLinkPadding.top()
|
||||
+ st::newGroupLinkTop
|
||||
+ st::newGroupLinkFont->ascent
|
||||
- st::boxTextFont->ascent;
|
||||
if (!_errorText.isEmpty()) {
|
||||
p.setPen(st::boxTextFgError);
|
||||
p.setFont(st::boxTextFont);
|
||||
p.drawTextRight(st::boxPadding.right(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _errorText);
|
||||
p.drawTextRight(st::boxPadding.right(), top, width(), _errorText);
|
||||
} else if (!_goodText.isEmpty()) {
|
||||
p.setPen(st::boxTextFgGood);
|
||||
p.setFont(st::boxTextFont);
|
||||
p.drawTextRight(st::boxPadding.right(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodText);
|
||||
p.drawTextRight(st::boxPadding.right(), top, width(), _goodText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -937,12 +1035,32 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) {
|
||||
void SetupChannelBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_public->moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top());
|
||||
_private->moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _public->bottomNoMargins() + _aboutPublicHeight + st::newGroupSkip);
|
||||
const auto left = st::boxPadding.left() + st::newGroupPadding.left();
|
||||
_public->moveToLeft(
|
||||
left,
|
||||
st::boxPadding.top() + st::newGroupPadding.top());
|
||||
_private->moveToLeft(
|
||||
left,
|
||||
_public->bottomNoMargins() + _aboutPublicHeight + st::newGroupSkip);
|
||||
|
||||
_link->resize(width() - st::boxPadding.left() - st::newGroupLinkPadding.left() - st::boxPadding.right(), _link->height());
|
||||
_link->moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _private->bottomNoMargins() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top());
|
||||
_invitationLink = QRect(_link->x(), _link->y() + (_link->height() / 2) - st::boxTextFont->height, _link->width(), 2 * st::boxTextFont->height);
|
||||
_link->resize(
|
||||
width()
|
||||
- st::boxPadding.left()
|
||||
- st::newGroupLinkPadding.left()
|
||||
- st::boxPadding.right(),
|
||||
_link->height());
|
||||
_link->moveToLeft(
|
||||
st::boxPadding.left() + st::newGroupLinkPadding.left(),
|
||||
_private->bottomNoMargins()
|
||||
+ _aboutPrivate.countHeight(_aboutPublicWidth)
|
||||
+ st::newGroupSkip
|
||||
+ st::newGroupPadding.bottom()
|
||||
+ st::newGroupLinkPadding.top());
|
||||
_invitationLink = QRect(
|
||||
_link->x(),
|
||||
_link->y() + (_link->height() / 2) - st::boxTextFont->height,
|
||||
_link->width(),
|
||||
2 * st::boxTextFont->height);
|
||||
}
|
||||
|
||||
void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) {
|
||||
@@ -982,9 +1100,13 @@ void SetupChannelBox::save() {
|
||||
_channel->inputChannel,
|
||||
MTP_string(_sentUsername)
|
||||
)).done([=](const MTPBool &result) {
|
||||
updateDone(result);
|
||||
_channel->setName(
|
||||
TextUtilities::SingleLine(_channel->name),
|
||||
_sentUsername);
|
||||
closeBox();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
updateFail(error);
|
||||
_saveRequestId = 0;
|
||||
updateFail(error.type());
|
||||
}).send();
|
||||
};
|
||||
if (_saveRequestId) {
|
||||
@@ -1007,38 +1129,45 @@ void SetupChannelBox::save() {
|
||||
}
|
||||
|
||||
void SetupChannelBox::handleChange() {
|
||||
QString name = _link->text().trimmed();
|
||||
const auto name = _link->text().trimmed();
|
||||
if (name.isEmpty()) {
|
||||
if (!_errorText.isEmpty() || !_goodText.isEmpty()) {
|
||||
_errorText = _goodText = QString();
|
||||
update();
|
||||
}
|
||||
_checkTimer.stop();
|
||||
_checkTimer.cancel();
|
||||
} else {
|
||||
int32 len = name.size();
|
||||
for (int32 i = 0; i < len; ++i) {
|
||||
QChar ch = name.at(i);
|
||||
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') {
|
||||
if (_errorText != tr::lng_create_channel_link_bad_symbols(tr::now)) {
|
||||
_errorText = tr::lng_create_channel_link_bad_symbols(tr::now);
|
||||
const auto len = int(name.size());
|
||||
for (auto i = 0; i < len; ++i) {
|
||||
const auto ch = name.at(i);
|
||||
if ((ch < 'A' || ch > 'Z')
|
||||
&& (ch < 'a' || ch > 'z')
|
||||
&& (ch < '0' || ch > '9')
|
||||
&& ch != '_') {
|
||||
const auto badSymbols =
|
||||
tr::lng_create_channel_link_bad_symbols(tr::now);
|
||||
if (_errorText != badSymbols) {
|
||||
_errorText = badSymbols;
|
||||
update();
|
||||
}
|
||||
_checkTimer.stop();
|
||||
_checkTimer.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (name.size() < kMinUsernameLength) {
|
||||
if (_errorText != tr::lng_create_channel_link_too_short(tr::now)) {
|
||||
_errorText = tr::lng_create_channel_link_too_short(tr::now);
|
||||
if (name.size() < Ui::EditPeer::kMinUsernameLength) {
|
||||
const auto tooShort =
|
||||
tr::lng_create_channel_link_too_short(tr::now);
|
||||
if (_errorText != tooShort) {
|
||||
_errorText = tooShort;
|
||||
update();
|
||||
}
|
||||
_checkTimer.stop();
|
||||
_checkTimer.cancel();
|
||||
} else {
|
||||
if (!_errorText.isEmpty() || !_goodText.isEmpty()) {
|
||||
_errorText = _goodText = QString();
|
||||
update();
|
||||
}
|
||||
_checkTimer.start(UsernameCheckTimeout);
|
||||
_checkTimer.callOnce(Ui::EditPeer::kUsernameCheckTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1047,16 +1176,25 @@ void SetupChannelBox::check() {
|
||||
if (_checkRequestId) {
|
||||
_channel->session().api().request(_checkRequestId).cancel();
|
||||
}
|
||||
QString link = _link->text().trimmed();
|
||||
if (link.size() >= kMinUsernameLength) {
|
||||
const auto link = _link->text().trimmed();
|
||||
if (link.size() >= Ui::EditPeer::kMinUsernameLength) {
|
||||
_checkUsername = link;
|
||||
_checkRequestId = _api.request(MTPchannels_CheckUsername(
|
||||
_channel->inputChannel,
|
||||
MTP_string(link)
|
||||
)).done([=](const MTPBool &result) {
|
||||
checkDone(result);
|
||||
_checkRequestId = 0;
|
||||
_errorText = (mtpIsTrue(result)
|
||||
|| _checkUsername == _channel->username)
|
||||
? QString()
|
||||
: tr::lng_create_channel_link_occupied(tr::now);
|
||||
_goodText = _errorText.isEmpty()
|
||||
? tr::lng_create_channel_link_available(tr::now)
|
||||
: QString();
|
||||
update();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
checkFail(error);
|
||||
_checkRequestId = 0;
|
||||
checkFail(error.type());
|
||||
}).send();
|
||||
}
|
||||
}
|
||||
@@ -1090,26 +1228,20 @@ void SetupChannelBox::privacyChanged(Privacy value) {
|
||||
update();
|
||||
}
|
||||
|
||||
void SetupChannelBox::updateDone(const MTPBool &result) {
|
||||
_channel->setName(TextUtilities::SingleLine(_channel->name), _sentUsername);
|
||||
closeBox();
|
||||
}
|
||||
|
||||
void SetupChannelBox::updateFail(const MTP::Error &error) {
|
||||
_saveRequestId = 0;
|
||||
QString err(error.type());
|
||||
if (err == "USERNAME_NOT_MODIFIED"
|
||||
|| _sentUsername == _channel->username) {
|
||||
void SetupChannelBox::updateFail(const QString &error) {
|
||||
if ((error == "USERNAME_NOT_MODIFIED")
|
||||
|| (_sentUsername == _channel->username)) {
|
||||
_channel->setName(
|
||||
TextUtilities::SingleLine(_channel->name),
|
||||
TextUtilities::SingleLine(_sentUsername));
|
||||
closeBox();
|
||||
} else if (err == "USERNAME_INVALID") {
|
||||
} else if (error == "USERNAME_INVALID") {
|
||||
_link->setFocus();
|
||||
_link->showError();
|
||||
_errorText = tr::lng_create_channel_link_invalid(tr::now);
|
||||
update();
|
||||
} else if (err == "USERNAME_OCCUPIED" || err == "USERNAMES_UNAVAILABLE") {
|
||||
} else if ((error == "USERNAME_OCCUPIED")
|
||||
|| (error == "USERNAMES_UNAVAILABLE")) {
|
||||
_link->setFocus();
|
||||
_link->showError();
|
||||
_errorText = tr::lng_create_channel_link_occupied(tr::now);
|
||||
@@ -1119,33 +1251,21 @@ void SetupChannelBox::updateFail(const MTP::Error &error) {
|
||||
}
|
||||
}
|
||||
|
||||
void SetupChannelBox::checkDone(const MTPBool &result) {
|
||||
_checkRequestId = 0;
|
||||
QString newError = (mtpIsTrue(result) || _checkUsername == _channel->username) ? QString() : tr::lng_create_channel_link_occupied(tr::now);
|
||||
QString newGood = newError.isEmpty() ? tr::lng_create_channel_link_available(tr::now) : QString();
|
||||
if (_errorText != newError || _goodText != newGood) {
|
||||
_errorText = newError;
|
||||
_goodText = newGood;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void SetupChannelBox::checkFail(const MTP::Error &error) {
|
||||
_checkRequestId = 0;
|
||||
QString err(error.type());
|
||||
if (err == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
|
||||
void SetupChannelBox::checkFail(const QString &error) {
|
||||
if (error == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
|
||||
Ui::hideLayer();
|
||||
} else if (err == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
|
||||
} else if (error == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
|
||||
if (_existing) {
|
||||
showRevokePublicLinkBoxForEdit();
|
||||
} else {
|
||||
_tooMuchUsernames = true;
|
||||
_privacyGroup->setValue(Privacy::Private);
|
||||
}
|
||||
} else if (err == qstr("USERNAME_INVALID")) {
|
||||
} else if (error == qstr("USERNAME_INVALID")) {
|
||||
_errorText = tr::lng_create_channel_link_invalid(tr::now);
|
||||
update();
|
||||
} else if (err == qstr("USERNAME_OCCUPIED") && _checkUsername != _channel->username) {
|
||||
} else if (error == qstr("USERNAME_OCCUPIED")
|
||||
&& _checkUsername != _channel->username) {
|
||||
_errorText = tr::lng_create_channel_link_occupied(tr::now);
|
||||
update();
|
||||
} else {
|
||||
@@ -1171,12 +1291,10 @@ void SetupChannelBox::showRevokePublicLinkBoxForEdit() {
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void SetupChannelBox::firstCheckFail(const MTP::Error &error) {
|
||||
_checkRequestId = 0;
|
||||
const auto &type = error.type();
|
||||
if (type == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
|
||||
void SetupChannelBox::firstCheckFail(const QString &error) {
|
||||
if (error == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
|
||||
Ui::hideLayer();
|
||||
} else if (type == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
|
||||
} else if (error == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
|
||||
if (_existing) {
|
||||
showRevokePublicLinkBoxForEdit();
|
||||
} else {
|
||||
@@ -1192,8 +1310,16 @@ void SetupChannelBox::firstCheckFail(const MTP::Error &error) {
|
||||
EditNameBox::EditNameBox(QWidget*, not_null<UserData*> user)
|
||||
: _user(user)
|
||||
, _api(&_user->session().mtp())
|
||||
, _first(this, st::defaultInputField, tr::lng_signup_firstname(), _user->firstName)
|
||||
, _last(this, st::defaultInputField, tr::lng_signup_lastname(), _user->lastName)
|
||||
, _first(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
tr::lng_signup_firstname(),
|
||||
_user->firstName)
|
||||
, _last(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
tr::lng_signup_lastname(),
|
||||
_user->lastName)
|
||||
, _invertOrder(langFirstNameGoesSecond()) {
|
||||
}
|
||||
|
||||
@@ -1211,8 +1337,8 @@ void EditNameBox::prepare() {
|
||||
if (_invertOrder) {
|
||||
setTabOrder(_last, _first);
|
||||
}
|
||||
_first->setMaxLength(kMaxUserFirstLastName);
|
||||
_last->setMaxLength(kMaxUserFirstLastName);
|
||||
_first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
|
||||
_last->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
|
||||
|
||||
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
|
||||
@@ -1241,19 +1367,28 @@ void EditNameBox::submit() {
|
||||
void EditNameBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_first->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _first->height());
|
||||
_first->resize(
|
||||
width()
|
||||
- st::boxPadding.left()
|
||||
- st::newGroupInfoPadding.left()
|
||||
- st::boxPadding.right(),
|
||||
_first->height());
|
||||
_last->resize(_first->size());
|
||||
const auto left = st::boxPadding.left() + st::newGroupInfoPadding.left();
|
||||
const auto skip = st::contactSkip;
|
||||
if (_invertOrder) {
|
||||
_last->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::contactPadding.top());
|
||||
_first->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _last->y() + _last->height() + st::contactSkip);
|
||||
_last->moveToLeft(left, st::contactPadding.top());
|
||||
_first->moveToLeft(left, _last->y() + _last->height() + skip);
|
||||
} else {
|
||||
_first->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::contactPadding.top());
|
||||
_last->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _first->y() + _first->height() + st::contactSkip);
|
||||
_first->moveToLeft(left, st::contactPadding.top());
|
||||
_last->moveToLeft(left, _first->y() + _first->height() + skip);
|
||||
}
|
||||
}
|
||||
|
||||
void EditNameBox::save() {
|
||||
if (_requestId) return;
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto first = TextUtilities::PrepareForSending(_first->getLastText());
|
||||
auto last = TextUtilities::PrepareForSending(_last->getLastText());
|
||||
@@ -1279,29 +1414,27 @@ void EditNameBox::save() {
|
||||
MTP_string(first),
|
||||
MTP_string(last),
|
||||
MTPstring()
|
||||
)).done([=](const MTPUser &result) {
|
||||
saveSelfDone(result);
|
||||
)).done([=](const MTPUser &user) {
|
||||
_user->owner().processUser(user);
|
||||
closeBox();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
saveSelfFail(error);
|
||||
_requestId = 0;
|
||||
saveSelfFail(error.type());
|
||||
}).send();
|
||||
}
|
||||
|
||||
void EditNameBox::saveSelfDone(const MTPUser &user) {
|
||||
_user->owner().processUsers(MTP_vector<MTPUser>(1, user));
|
||||
closeBox();
|
||||
}
|
||||
|
||||
void EditNameBox::saveSelfFail(const MTP::Error &error) {
|
||||
auto err = error.type();
|
||||
auto first = TextUtilities::SingleLine(_first->getLastText().trimmed());
|
||||
auto last = TextUtilities::SingleLine(_last->getLastText().trimmed());
|
||||
if (err == "NAME_NOT_MODIFIED") {
|
||||
_user->setName(first, last, QString(), TextUtilities::SingleLine(_user->username));
|
||||
void EditNameBox::saveSelfFail(const QString &error) {
|
||||
if (error == "NAME_NOT_MODIFIED") {
|
||||
_user->setName(
|
||||
TextUtilities::SingleLine(_first->getLastText().trimmed()),
|
||||
TextUtilities::SingleLine(_last->getLastText().trimmed()),
|
||||
QString(),
|
||||
TextUtilities::SingleLine(_user->username));
|
||||
closeBox();
|
||||
} else if (err == "FIRSTNAME_INVALID") {
|
||||
} else if (error == "FIRSTNAME_INVALID") {
|
||||
_first->setFocus();
|
||||
_first->showError();
|
||||
} else if (err == "LASTNAME_INVALID") {
|
||||
} else if (error == "LASTNAME_INVALID") {
|
||||
_last->setFocus();
|
||||
_last->showError();
|
||||
} else {
|
||||
@@ -1316,8 +1449,11 @@ RevokePublicLinkBox::Inner::Inner(
|
||||
: TWidget(parent)
|
||||
, _session(session)
|
||||
, _api(&_session->mtp())
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
, _revokeWidth(st::normalFont->width(tr::lng_channels_too_much_public_revoke(tr::now)))
|
||||
, _rowHeight(st::contactsPadding.top()
|
||||
+ st::contactsPhotoSize
|
||||
+ st::contactsPadding.bottom())
|
||||
, _revokeWidth(st::normalFont->width(
|
||||
tr::lng_channels_too_much_public_revoke(tr::now)))
|
||||
, _revokeCallback(std::move(revokeCallback)) {
|
||||
setMouseTracking(true);
|
||||
|
||||
@@ -1367,7 +1503,9 @@ RevokePublicLinkBox::RevokePublicLinkBox(
|
||||
}
|
||||
|
||||
void RevokePublicLinkBox::prepare() {
|
||||
_innerTop = st::boxPadding.top() + _aboutRevoke->height() + st::boxPadding.top();
|
||||
_innerTop = st::boxPadding.top()
|
||||
+ _aboutRevoke->height()
|
||||
+ st::boxPadding.top();
|
||||
_inner = setInnerWidget(object_ptr<Inner>(this, _session, [=] {
|
||||
const auto callback = _revokeCallback;
|
||||
closeBox();
|
||||
@@ -1392,11 +1530,21 @@ void RevokePublicLinkBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
}
|
||||
|
||||
void RevokePublicLinkBox::Inner::updateSelected() {
|
||||
auto point = mapFromGlobal(QCursor::pos());
|
||||
const auto point = mapFromGlobal(QCursor::pos());
|
||||
PeerData *selected = nullptr;
|
||||
auto top = _rowsTop;
|
||||
for (const auto &row : _rows) {
|
||||
auto revokeLink = style::rtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - _revokeWidth, top + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, _revokeWidth, st::normalFont->height, width());
|
||||
const auto revokeLink = style::rtlrect(
|
||||
width()
|
||||
- st::contactsPadding.right()
|
||||
- st::contactsCheckPosition.x()
|
||||
- _revokeWidth,
|
||||
top
|
||||
+ st::contactsPadding.top()
|
||||
+ (st::contactsPhotoSize - st::normalFont->height) / 2,
|
||||
_revokeWidth,
|
||||
st::normalFont->height,
|
||||
width());
|
||||
if (revokeLink.contains(point)) {
|
||||
selected = row.peer;
|
||||
break;
|
||||
@@ -1405,7 +1553,9 @@ void RevokePublicLinkBox::Inner::updateSelected() {
|
||||
}
|
||||
if (selected != _selected) {
|
||||
_selected = selected;
|
||||
setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default);
|
||||
setCursor((_selected || _pressed)
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
update();
|
||||
}
|
||||
}
|
||||
@@ -1418,21 +1568,26 @@ void RevokePublicLinkBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
}
|
||||
|
||||
void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
auto pressed = base::take(_pressed);
|
||||
setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default);
|
||||
const auto pressed = base::take(_pressed);
|
||||
setCursor((_selected || _pressed)
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
if (pressed && pressed == _selected) {
|
||||
auto text_method = pressed->isMegagroup()
|
||||
const auto textMethod = pressed->isMegagroup()
|
||||
? tr::lng_channels_too_much_public_revoke_confirm_group
|
||||
: tr::lng_channels_too_much_public_revoke_confirm_channel;
|
||||
auto text = text_method(
|
||||
const auto text = textMethod(
|
||||
tr::now,
|
||||
lt_link,
|
||||
_session->createInternalLink(pressed->userName()),
|
||||
lt_group,
|
||||
pressed->name);
|
||||
auto confirmText = tr::lng_channels_too_much_public_revoke(tr::now);
|
||||
const auto confirmText = tr::lng_channels_too_much_public_revoke(
|
||||
tr::now);
|
||||
auto callback = crl::guard(this, [=](Fn<void()> &&close) {
|
||||
if (_revokeRequestId) return;
|
||||
if (_revokeRequestId) {
|
||||
return;
|
||||
}
|
||||
_revokeRequestId = _api.request(MTPchannels_UpdateUsername(
|
||||
pressed->asChannel()->inputChannel,
|
||||
MTP_string()
|
||||
@@ -1444,7 +1599,7 @@ void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
}).send();
|
||||
});
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(text, confirmText, std::move(callback)),
|
||||
Box<Ui::ConfirmBox>(text, confirmText, std::move(callback)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
}
|
||||
@@ -1464,18 +1619,33 @@ void RevokePublicLinkBox::resizeEvent(QResizeEvent *e) {
|
||||
_aboutRevoke->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
|
||||
}
|
||||
|
||||
void RevokePublicLinkBox::Inner::paintChat(Painter &p, const ChatRow &row, bool selected) const {
|
||||
auto peer = row.peer;
|
||||
peer->paintUserpicLeft(p, row.userpic, st::contactsPadding.left(), st::contactsPadding.top(), width(), st::contactsPhotoSize);
|
||||
void RevokePublicLinkBox::Inner::paintChat(
|
||||
Painter &p,
|
||||
const ChatRow &row,
|
||||
bool selected) const {
|
||||
const auto peer = row.peer;
|
||||
peer->paintUserpicLeft(
|
||||
p,
|
||||
row.userpic,
|
||||
st::contactsPadding.left(),
|
||||
st::contactsPadding.top(),
|
||||
width(),
|
||||
st::contactsPhotoSize);
|
||||
|
||||
p.setPen(st::contactsNameFg);
|
||||
|
||||
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
|
||||
int32 namew = width() - namex - st::contactsPadding.right() - (_revokeWidth + st::contactsCheckPosition.x() * 2);
|
||||
const auto namex = st::contactsPadding.left()
|
||||
+ st::contactsPhotoSize
|
||||
+ st::contactsPadding.left();
|
||||
auto namew = width()
|
||||
- namex
|
||||
- st::contactsPadding.right()
|
||||
- (_revokeWidth + st::contactsCheckPosition.x() * 2);
|
||||
|
||||
const auto badgeStyle = Ui::PeerBadgeStyle{
|
||||
&st::dialogsVerifiedIcon,
|
||||
&st::attentionButtonFg };
|
||||
&st::attentionButtonFg
|
||||
};
|
||||
namew -= Ui::DrawPeerBadgeGetWidth(
|
||||
peer,
|
||||
p,
|
||||
@@ -1487,14 +1657,32 @@ void RevokePublicLinkBox::Inner::paintChat(Painter &p, const ChatRow &row, bool
|
||||
namew,
|
||||
width(),
|
||||
badgeStyle);
|
||||
row.name.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew, width());
|
||||
row.name.drawLeftElided(
|
||||
p,
|
||||
namex,
|
||||
st::contactsPadding.top() + st::contactsNameTop,
|
||||
namew,
|
||||
width());
|
||||
|
||||
p.setFont(selected ? st::linkOverFont : st::linkFont);
|
||||
p.setPen(selected ? st::defaultLinkButton.overColor : st::defaultLinkButton.color);
|
||||
p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), tr::lng_channels_too_much_public_revoke(tr::now), _revokeWidth);
|
||||
p.setPen(selected
|
||||
? st::defaultLinkButton.overColor
|
||||
: st::defaultLinkButton.color);
|
||||
p.drawTextRight(
|
||||
st::contactsPadding.right() + st::contactsCheckPosition.x(),
|
||||
st::contactsPadding.top()
|
||||
+ (st::contactsPhotoSize - st::normalFont->height) / 2,
|
||||
width(),
|
||||
tr::lng_channels_too_much_public_revoke(tr::now),
|
||||
_revokeWidth);
|
||||
|
||||
p.setPen(st::contactsStatusFg);
|
||||
p.setTextPalette(st::revokePublicLinkStatusPalette);
|
||||
row.status.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsStatusTop, namew, width());
|
||||
row.status.drawLeftElided(
|
||||
p,
|
||||
namex,
|
||||
st::contactsPadding.top() + st::contactsStatusTop,
|
||||
namew,
|
||||
width());
|
||||
p.restoreTextPalette();
|
||||
}
|
||||
|
||||
@@ -8,12 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "base/timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
class ConfirmBox;
|
||||
class PeerListBox;
|
||||
|
||||
namespace Window {
|
||||
@@ -25,6 +22,7 @@ class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class ConfirmBox;
|
||||
class FlatLabel;
|
||||
class InputField;
|
||||
class PhoneInput;
|
||||
@@ -118,7 +116,10 @@ protected:
|
||||
|
||||
private:
|
||||
void createChannel(const QString &title, const QString &description);
|
||||
void createGroup(not_null<PeerListBox*> selectUsersBox, const QString &title, const std::vector<not_null<PeerData*>> &users);
|
||||
void createGroup(
|
||||
not_null<PeerListBox*> selectUsersBox,
|
||||
const QString &title,
|
||||
const std::vector<not_null<PeerData*>> &users);
|
||||
void submitName();
|
||||
void submit();
|
||||
void checkInviteLink();
|
||||
@@ -176,12 +177,10 @@ private:
|
||||
void check();
|
||||
void save();
|
||||
|
||||
void updateDone(const MTPBool &result);
|
||||
void updateFail(const MTP::Error &error);
|
||||
void updateFail(const QString &error);
|
||||
|
||||
void checkDone(const MTPBool &result);
|
||||
void checkFail(const MTP::Error &error);
|
||||
void firstCheckFail(const MTP::Error &error);
|
||||
void checkFail(const QString &error);
|
||||
void firstCheckFail(const QString &error);
|
||||
|
||||
void updateMaxHeight();
|
||||
|
||||
@@ -209,7 +208,7 @@ private:
|
||||
mtpRequestId _checkRequestId = 0;
|
||||
QString _sentUsername, _checkUsername, _errorText, _goodText;
|
||||
|
||||
QTimer _checkTimer;
|
||||
base::Timer _checkTimer;
|
||||
|
||||
};
|
||||
|
||||
@@ -226,8 +225,7 @@ protected:
|
||||
private:
|
||||
void submit();
|
||||
void save();
|
||||
void saveSelfDone(const MTPUser &user);
|
||||
void saveSelfFail(const MTP::Error &error);
|
||||
void saveSelfFail(const QString &error);
|
||||
|
||||
const not_null<UserData*> _user;
|
||||
MTP::Sender _api;
|
||||
|
||||
@@ -20,7 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "boxes/background_preview_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "styles/style_overview.h"
|
||||
@@ -176,7 +176,7 @@ void BackgroundBox::removePaper(const Data::WallPaper &paper) {
|
||||
)).send();
|
||||
};
|
||||
_controller->show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_background_sure_delete(tr::now),
|
||||
tr::lng_selected_delete(tr::now),
|
||||
tr::lng_cancel(tr::now),
|
||||
|
||||
@@ -28,7 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_document_resolver.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/background_preview_box.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_chat.h"
|
||||
@@ -210,7 +210,7 @@ void ServiceCheck::Generator::paintFrame(
|
||||
const auto frames = framesForStyle(st);
|
||||
auto &image = frames->image;
|
||||
const auto count = int(frames->ready.size());
|
||||
const auto index = int(std::round(toggled * (count - 1)));
|
||||
const auto index = int(base::SafeRound(toggled * (count - 1)));
|
||||
Assert(index >= 0 && index < count);
|
||||
if (!frames->ready[index]) {
|
||||
frames->ready[index] = true;
|
||||
@@ -288,7 +288,6 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
|
||||
bool out) {
|
||||
Expects(history->peer->isUser());
|
||||
|
||||
static auto id = ServerMaxMsgId + (ServerMaxMsgId / 3);
|
||||
const auto flags = MessageFlag::FakeHistoryItem
|
||||
| MessageFlag::HasFromId
|
||||
| (out ? MessageFlag::Outgoing : MessageFlag(0));
|
||||
@@ -296,7 +295,7 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
|
||||
const auto viaBotId = UserId();
|
||||
const auto groupedId = uint64();
|
||||
const auto item = history->makeMessage(
|
||||
++id,
|
||||
history->nextNonHistoryEntryId(),
|
||||
flags,
|
||||
replyTo,
|
||||
viaBotId,
|
||||
@@ -305,7 +304,7 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
|
||||
QString(),
|
||||
TextWithEntities{ TextUtilities::Clean(text) },
|
||||
MTP_messageMediaEmpty(),
|
||||
MTPReplyMarkup(),
|
||||
HistoryMessageMarkupData(),
|
||||
groupedId);
|
||||
return AdminLog::OwnedItem(delegate, item);
|
||||
}
|
||||
@@ -785,7 +784,7 @@ bool BackgroundPreviewBox::Start(
|
||||
}
|
||||
if (!IsValidWallPaperSlug(slug)) {
|
||||
controller->show(
|
||||
Box<InformBox>(tr::lng_background_bad_link(tr::now)));
|
||||
Box<Ui::InformBox>(tr::lng_background_bad_link(tr::now)));
|
||||
return false;
|
||||
}
|
||||
controller->session().api().requestWallPaper(slug, crl::guard(controller, [=](
|
||||
@@ -795,7 +794,7 @@ bool BackgroundPreviewBox::Start(
|
||||
result.withUrlParams(params)));
|
||||
}), crl::guard(controller, [=](const MTP::Error &error) {
|
||||
controller->show(
|
||||
Box<InformBox>(tr::lng_background_bad_link(tr::now)));
|
||||
Box<Ui::InformBox>(tr::lng_background_bad_link(tr::now)));
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -973,3 +973,21 @@ autolockTimeField: InputField(scheduleTimeField) {
|
||||
heightMin: 20px;
|
||||
}
|
||||
autolockTimeWidth: 52px;
|
||||
|
||||
sponsoredUrlButtonSkip: 11px;
|
||||
sponsoredUrlButton: RoundButton(defaultActiveButton) {
|
||||
height: 32px;
|
||||
width: -42px;
|
||||
textBg: transparent;
|
||||
textBgOver: transparent;
|
||||
radius: roundRadiusLarge;
|
||||
padding: margins(2px, 2px, 2px, 2px);
|
||||
textFg: historyLinkInFg;
|
||||
textFgOver: historyLinkInFg;
|
||||
textTop: 7px;
|
||||
font: normalFont;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,26 +9,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/sent_code_field.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/special_fields.h"
|
||||
#include "boxes/confirm_phone_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/phone_banned_box.h"
|
||||
#include "countries/countries_instance.h" // Countries::ExtractPhoneCode.
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "apiwrap.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void createErrorLabel(
|
||||
void CreateErrorLabel(
|
||||
QWidget *parent,
|
||||
object_ptr<Ui::FadeWrap<Ui::FlatLabel>> &label,
|
||||
const QString &text,
|
||||
@@ -67,7 +68,7 @@ void createErrorLabel(
|
||||
|
||||
class ChangePhoneBox::EnterPhone : public Ui::BoxContent {
|
||||
public:
|
||||
EnterPhone(QWidget*, not_null<Main::Session*> session);
|
||||
EnterPhone(QWidget*, not_null<Window::SessionController*> controller);
|
||||
|
||||
void setInnerFocus() override {
|
||||
_phone->setFocusFast();
|
||||
@@ -78,14 +79,16 @@ protected:
|
||||
|
||||
private:
|
||||
void submit();
|
||||
void sendPhoneDone(const MTPauth_SentCode &result, const QString &phoneNumber);
|
||||
void sendPhoneDone(
|
||||
const MTPauth_SentCode &result,
|
||||
const QString &phoneNumber);
|
||||
void sendPhoneFail(const MTP::Error &error, const QString &phoneNumber);
|
||||
void showError(const QString &text);
|
||||
void hideError() {
|
||||
showError(QString());
|
||||
}
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
MTP::Sender _api;
|
||||
|
||||
object_ptr<Ui::PhoneInput> _phone = { nullptr };
|
||||
@@ -129,41 +132,51 @@ private:
|
||||
QString _hash;
|
||||
int _codeLength = 0;
|
||||
int _callTimeout = 0;
|
||||
object_ptr<SentCodeField> _code = { nullptr };
|
||||
object_ptr<Ui::SentCodeField> _code = { nullptr };
|
||||
object_ptr<Ui::FadeWrap<Ui::FlatLabel>> _error = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _callLabel = { nullptr };
|
||||
mtpRequestId _requestId = 0;
|
||||
SentCodeCall _call;
|
||||
Ui::SentCodeCall _call;
|
||||
|
||||
};
|
||||
|
||||
ChangePhoneBox::EnterPhone::EnterPhone(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session)
|
||||
: _session(session)
|
||||
, _api(&session->mtp()) {
|
||||
not_null<Window::SessionController*> controller)
|
||||
: _controller(controller)
|
||||
, _api(&controller->session().mtp()) {
|
||||
}
|
||||
|
||||
void ChangePhoneBox::EnterPhone::prepare() {
|
||||
setTitle(tr::lng_change_phone_title());
|
||||
|
||||
auto phoneValue = QString();
|
||||
const auto phoneValue = QString();
|
||||
_phone.create(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
tr::lng_change_phone_new_title(),
|
||||
Countries::ExtractPhoneCode(_session->user()->phone()),
|
||||
Countries::ExtractPhoneCode(_controller->session().user()->phone()),
|
||||
phoneValue);
|
||||
|
||||
_phone->resize(st::boxWidth - 2 * st::boxPadding.left(), _phone->height());
|
||||
_phone->resize(
|
||||
st::boxWidth - 2 * st::boxPadding.left(),
|
||||
_phone->height());
|
||||
_phone->moveToLeft(st::boxPadding.left(), st::boxLittleSkip);
|
||||
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
|
||||
|
||||
auto description = object_ptr<Ui::FlatLabel>(this, tr::lng_change_phone_new_description(tr::now), st::changePhoneLabel);
|
||||
auto errorSkip = st::boxLittleSkip + st::changePhoneError.style.font->height;
|
||||
description->moveToLeft(st::boxPadding.left(), _phone->y() + _phone->height() + errorSkip + st::boxLittleSkip);
|
||||
const auto description = object_ptr<Ui::FlatLabel>(
|
||||
this,
|
||||
tr::lng_change_phone_new_description(tr::now),
|
||||
st::changePhoneLabel);
|
||||
const auto errorSkip = st::boxLittleSkip
|
||||
+ st::changePhoneError.style.font->height;
|
||||
description->moveToLeft(
|
||||
st::boxPadding.left(),
|
||||
_phone->y() + _phone->height() + errorSkip + st::boxLittleSkip);
|
||||
|
||||
setDimensions(st::boxWidth, description->bottomNoMargins() + st::boxLittleSkip);
|
||||
setDimensions(
|
||||
st::boxWidth,
|
||||
description->bottomNoMargins() + st::boxLittleSkip);
|
||||
|
||||
addButton(tr::lng_change_phone_new_submit(), [this] { submit(); });
|
||||
addButton(tr::lng_cancel(), [this] { closeBox(); });
|
||||
@@ -175,13 +188,15 @@ void ChangePhoneBox::EnterPhone::submit() {
|
||||
}
|
||||
hideError();
|
||||
|
||||
auto phoneNumber = _phone->getLastText().trimmed();
|
||||
const auto phoneNumber = _phone->getLastText().trimmed();
|
||||
_requestId = _api.request(MTPaccount_SendChangePhoneCode(
|
||||
MTP_string(phoneNumber),
|
||||
MTP_codeSettings(MTP_flags(0))
|
||||
)).done([=](const MTPauth_SentCode &result) {
|
||||
_requestId = 0;
|
||||
sendPhoneDone(result, phoneNumber);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
sendPhoneFail(error, phoneNumber);
|
||||
}).handleFloodErrors().send();
|
||||
}
|
||||
@@ -189,33 +204,45 @@ void ChangePhoneBox::EnterPhone::submit() {
|
||||
void ChangePhoneBox::EnterPhone::sendPhoneDone(
|
||||
const MTPauth_SentCode &result,
|
||||
const QString &phoneNumber) {
|
||||
Expects(result.type() == mtpc_auth_sentCode);
|
||||
_requestId = 0;
|
||||
using CodeData = const MTPDauth_sentCode&;
|
||||
const auto &data = result.match([](const auto &data) -> CodeData {
|
||||
return data;
|
||||
});
|
||||
|
||||
auto codeLength = 0;
|
||||
auto &data = result.c_auth_sentCode();
|
||||
switch (data.vtype().type()) {
|
||||
case mtpc_auth_sentCodeTypeApp:
|
||||
const auto hasLength = data.vtype().match([&](
|
||||
const MTPDauth_sentCodeTypeApp &typeData) {
|
||||
LOG(("Error: should not be in-app code!"));
|
||||
showError(Lang::Hard::ServerError());
|
||||
return;
|
||||
case mtpc_auth_sentCodeTypeSms: codeLength = data.vtype().c_auth_sentCodeTypeSms().vlength().v; break;
|
||||
case mtpc_auth_sentCodeTypeCall: codeLength = data.vtype().c_auth_sentCodeTypeCall().vlength().v; break;
|
||||
case mtpc_auth_sentCodeTypeFlashCall:
|
||||
return false;
|
||||
}, [&](const MTPDauth_sentCodeTypeSms &typeData) {
|
||||
codeLength = typeData.vlength().v;
|
||||
return true;
|
||||
}, [&](const MTPDauth_sentCodeTypeCall &typeData) {
|
||||
codeLength = typeData.vlength().v;
|
||||
return true;
|
||||
}, [&](const MTPDauth_sentCodeTypeFlashCall &typeData) {
|
||||
LOG(("Error: should not be flashcall!"));
|
||||
showError(Lang::Hard::ServerError());
|
||||
return false;
|
||||
});
|
||||
if (!hasLength) {
|
||||
return;
|
||||
}
|
||||
auto phoneCodeHash = qs(data.vphone_code_hash());
|
||||
auto callTimeout = 0;
|
||||
if (const auto nextType = data.vnext_type()) {
|
||||
if (nextType->type() == mtpc_auth_codeTypeCall) {
|
||||
callTimeout = data.vtimeout().value_or(60);
|
||||
const auto phoneCodeHash = qs(data.vphone_code_hash());
|
||||
const auto callTimeout = [&] {
|
||||
if (const auto nextType = data.vnext_type()) {
|
||||
return nextType->match([&](const MTPDauth_sentCodeTypeCall &) {
|
||||
return data.vtimeout().value_or(60);
|
||||
}, [](const auto &) {
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
Ui::show(
|
||||
return 0;
|
||||
}();
|
||||
_controller->show(
|
||||
Box<EnterCode>(
|
||||
_session,
|
||||
&_controller->session(),
|
||||
phoneNumber,
|
||||
phoneCodeHash,
|
||||
codeLength,
|
||||
@@ -223,28 +250,36 @@ void ChangePhoneBox::EnterPhone::sendPhoneDone(
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void ChangePhoneBox::EnterPhone::sendPhoneFail(const MTP::Error &error, const QString &phoneNumber) {
|
||||
_requestId = 0;
|
||||
void ChangePhoneBox::EnterPhone::sendPhoneFail(
|
||||
const MTP::Error &error,
|
||||
const QString &phoneNumber) {
|
||||
if (MTP::IsFloodError(error)) {
|
||||
showError(tr::lng_flood_error(tr::now));
|
||||
} else if (error.type() == qstr("PHONE_NUMBER_INVALID")) {
|
||||
showError(tr::lng_bad_phone(tr::now));
|
||||
} else if (error.type() == qstr("PHONE_NUMBER_BANNED")) {
|
||||
ShowPhoneBannedError(phoneNumber);
|
||||
Ui::ShowPhoneBannedError(&_controller->window(), phoneNumber);
|
||||
} else if (error.type() == qstr("PHONE_NUMBER_OCCUPIED")) {
|
||||
Ui::show(Box<InformBox>(
|
||||
tr::lng_change_phone_occupied(
|
||||
tr::now,
|
||||
lt_phone,
|
||||
Ui::FormatPhone(phoneNumber)),
|
||||
tr::lng_box_ok(tr::now)));
|
||||
_controller->show(
|
||||
Box<Ui::InformBox>(
|
||||
tr::lng_change_phone_occupied(
|
||||
tr::now,
|
||||
lt_phone,
|
||||
Ui::FormatPhone(phoneNumber)),
|
||||
tr::lng_box_ok(tr::now)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
} else {
|
||||
showError(Lang::Hard::ServerError());
|
||||
}
|
||||
}
|
||||
|
||||
void ChangePhoneBox::EnterPhone::showError(const QString &text) {
|
||||
createErrorLabel(this, _error, text, st::boxPadding.left(), _phone->y() + _phone->height() + st::boxLittleSkip);
|
||||
CreateErrorLabel(
|
||||
this,
|
||||
_error,
|
||||
text,
|
||||
st::boxPadding.left(),
|
||||
_phone->y() + _phone->height() + st::boxLittleSkip);
|
||||
if (!text.isEmpty()) {
|
||||
_phone->showError();
|
||||
}
|
||||
@@ -269,16 +304,23 @@ ChangePhoneBox::EnterCode::EnterCode(
|
||||
void ChangePhoneBox::EnterCode::prepare() {
|
||||
setTitle(tr::lng_change_phone_title());
|
||||
|
||||
auto descriptionText = tr::lng_change_phone_code_description(
|
||||
const auto descriptionText = tr::lng_change_phone_code_description(
|
||||
tr::now,
|
||||
lt_phone,
|
||||
Ui::Text::Bold(Ui::FormatPhone(_phone)),
|
||||
Ui::Text::WithEntities);
|
||||
auto description = object_ptr<Ui::FlatLabel>(this, rpl::single(descriptionText), st::changePhoneLabel);
|
||||
const auto description = object_ptr<Ui::FlatLabel>(
|
||||
this,
|
||||
rpl::single(descriptionText),
|
||||
st::changePhoneLabel);
|
||||
description->moveToLeft(st::boxPadding.left(), 0);
|
||||
|
||||
auto phoneValue = QString();
|
||||
_code.create(this, st::defaultInputField, tr::lng_change_phone_code_title(), phoneValue);
|
||||
const auto phoneValue = QString();
|
||||
_code.create(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
tr::lng_change_phone_code_title(),
|
||||
phoneValue);
|
||||
_code->setAutoSubmit(_codeLength, [=] { submit(); });
|
||||
_code->setChangedCallback([=] { hideError(); });
|
||||
|
||||
@@ -289,7 +331,7 @@ void ChangePhoneBox::EnterCode::prepare() {
|
||||
setDimensions(st::boxWidth, countHeight());
|
||||
|
||||
if (_callTimeout > 0) {
|
||||
_call.setStatus({ SentCodeCall::State::Waiting, _callTimeout });
|
||||
_call.setStatus({ Ui::SentCodeCall::State::Waiting, _callTimeout });
|
||||
updateCall();
|
||||
}
|
||||
|
||||
@@ -298,7 +340,8 @@ void ChangePhoneBox::EnterCode::prepare() {
|
||||
}
|
||||
|
||||
int ChangePhoneBox::EnterCode::countHeight() {
|
||||
auto errorSkip = st::boxLittleSkip + st::changePhoneError.style.font->height;
|
||||
const auto errorSkip = st::boxLittleSkip
|
||||
+ st::changePhoneError.style.font->height;
|
||||
return _code->bottomNoMargins() + errorSkip + 3 * st::boxLittleSkip;
|
||||
}
|
||||
|
||||
@@ -316,12 +359,14 @@ void ChangePhoneBox::EnterCode::submit() {
|
||||
MTP_string(_hash),
|
||||
MTP_string(code)
|
||||
)).done([=](const MTPUser &result) {
|
||||
_requestId = 0;
|
||||
session->data().processUser(result);
|
||||
if (weak) {
|
||||
Ui::hideLayer();
|
||||
}
|
||||
Ui::Toast::Show(tr::lng_change_phone_success(tr::now));
|
||||
}).fail(crl::guard(this, [=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
sendCodeFail(error);
|
||||
})).handleFloodErrors().send();
|
||||
}
|
||||
@@ -336,12 +381,14 @@ void ChangePhoneBox::EnterCode::sendCall() {
|
||||
}
|
||||
|
||||
void ChangePhoneBox::EnterCode::updateCall() {
|
||||
auto text = _call.getText();
|
||||
const auto text = _call.getText();
|
||||
if (text.isEmpty()) {
|
||||
_callLabel.destroy();
|
||||
} else if (!_callLabel) {
|
||||
_callLabel.create(this, text, st::changePhoneLabel);
|
||||
_callLabel->moveToLeft(st::boxPadding.left(), countHeight() - _callLabel->height());
|
||||
_callLabel->moveToLeft(
|
||||
st::boxPadding.left(),
|
||||
countHeight() - _callLabel->height());
|
||||
_callLabel->show();
|
||||
} else {
|
||||
_callLabel->setText(text);
|
||||
@@ -349,17 +396,22 @@ void ChangePhoneBox::EnterCode::updateCall() {
|
||||
}
|
||||
|
||||
void ChangePhoneBox::EnterCode::showError(const QString &text) {
|
||||
createErrorLabel(this, _error, text, st::boxPadding.left(), _code->y() + _code->height() + st::boxLittleSkip);
|
||||
CreateErrorLabel(
|
||||
this,
|
||||
_error,
|
||||
text,
|
||||
st::boxPadding.left(),
|
||||
_code->y() + _code->height() + st::boxLittleSkip);
|
||||
if (!text.isEmpty()) {
|
||||
_code->showError();
|
||||
}
|
||||
}
|
||||
|
||||
void ChangePhoneBox::EnterCode::sendCodeFail(const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
if (MTP::IsFloodError(error)) {
|
||||
showError(tr::lng_flood_error(tr::now));
|
||||
} else if (error.type() == qstr("PHONE_CODE_EMPTY") || error.type() == qstr("PHONE_CODE_INVALID")) {
|
||||
} else if (error.type() == qstr("PHONE_CODE_EMPTY")
|
||||
|| error.type() == qstr("PHONE_CODE_INVALID")) {
|
||||
showError(tr::lng_bad_code(tr::now));
|
||||
} else if (error.type() == qstr("PHONE_CODE_EXPIRED")
|
||||
|| error.type() == qstr("PHONE_NUMBER_BANNED")) {
|
||||
@@ -371,18 +423,25 @@ void ChangePhoneBox::EnterCode::sendCodeFail(const MTP::Error &error) {
|
||||
}
|
||||
}
|
||||
|
||||
ChangePhoneBox::ChangePhoneBox(QWidget*, not_null<Main::Session*> session)
|
||||
: _session(session) {
|
||||
ChangePhoneBox::ChangePhoneBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller)
|
||||
: _controller(controller) {
|
||||
}
|
||||
|
||||
void ChangePhoneBox::prepare() {
|
||||
const auto session = _session;
|
||||
|
||||
setTitle(tr::lng_change_phone_title());
|
||||
addButton(tr::lng_change_phone_button(), [=] {
|
||||
Ui::show(Box<ConfirmBox>(tr::lng_change_phone_warning(tr::now), [=] {
|
||||
Ui::show(Box<EnterPhone>(session));
|
||||
}));
|
||||
addButton(tr::lng_change_phone_button(), [=, controller = _controller] {
|
||||
auto callback = [=] {
|
||||
controller->show(
|
||||
Box<EnterPhone>(controller),
|
||||
Ui::LayerOption::CloseOther);
|
||||
};
|
||||
controller->show(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_change_phone_warning(tr::now),
|
||||
std::move(callback)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
});
|
||||
addButton(tr::lng_cancel(), [this] {
|
||||
closeBox();
|
||||
@@ -392,14 +451,22 @@ void ChangePhoneBox::prepare() {
|
||||
this,
|
||||
tr::lng_change_phone_about(Ui::Text::RichLangValue),
|
||||
st::changePhoneDescription);
|
||||
label->moveToLeft((st::boxWideWidth - label->width()) / 2, st::changePhoneDescriptionTop);
|
||||
label->moveToLeft(
|
||||
(st::boxWideWidth - label->width()) / 2,
|
||||
st::changePhoneDescriptionTop);
|
||||
|
||||
setDimensions(st::boxWideWidth, label->bottomNoMargins() + st::boxLittleSkip);
|
||||
setDimensions(
|
||||
st::boxWideWidth,
|
||||
label->bottomNoMargins() + st::boxLittleSkip);
|
||||
}
|
||||
|
||||
void ChangePhoneBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
st::changePhoneIcon.paint(p, (width() - st::changePhoneIcon.width()) / 2, st::changePhoneIconTop, width());
|
||||
st::changePhoneIcon.paint(
|
||||
p,
|
||||
(width() - st::changePhoneIcon.width()) / 2,
|
||||
st::changePhoneIconTop,
|
||||
width());
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
class ChangePhoneBox : public Ui::BoxContent {
|
||||
public:
|
||||
ChangePhoneBox(QWidget*, not_null<Main::Session*> session);
|
||||
ChangePhoneBox(QWidget*, not_null<Window::SessionController*> controller);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@@ -26,7 +26,7 @@ private:
|
||||
class EnterPhone;
|
||||
class EnterCode;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,983 +0,0 @@
|
||||
/*
|
||||
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 "boxes/confirm_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "history/view/controls/history_view_ttl_button.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "facades.h" // Ui::showChatsList
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
namespace {
|
||||
|
||||
TextParseOptions kInformBoxTextOptions = {
|
||||
(TextParseLinks
|
||||
| TextParseMultiline
|
||||
| TextParseMarkdown
|
||||
| TextParseRichText), // flags
|
||||
0, // maxw
|
||||
0, // maxh
|
||||
Qt::LayoutDirectionAuto, // dir
|
||||
};
|
||||
|
||||
TextParseOptions kMarkedTextBoxOptions = {
|
||||
(TextParseLinks
|
||||
| TextParseMultiline
|
||||
| TextParseMarkdown
|
||||
| TextParseRichText
|
||||
| TextParseMentions
|
||||
| TextParseHashtags), // flags
|
||||
0, // maxw
|
||||
0, // maxh
|
||||
Qt::LayoutDirectionAuto, // dir
|
||||
};
|
||||
|
||||
[[nodiscard]] bool IsOldForPin(MsgId id, not_null<PeerData*> peer) {
|
||||
const auto normal = peer->migrateToOrMe();
|
||||
const auto migrated = normal->migrateFrom();
|
||||
const auto top = Data::ResolveTopPinnedId(normal, migrated);
|
||||
if (!top) {
|
||||
return false;
|
||||
} else if (peer == migrated) {
|
||||
return top.channel || (id < top.msg);
|
||||
} else if (migrated) {
|
||||
return top.channel && (id < top.msg);
|
||||
} else {
|
||||
return (id < top.msg);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(tr::lng_box_ok(tr::now))
|
||||
, _cancelText(tr::lng_cancel(tr::now))
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
|
||||
, _confirmedCallback(std::move(confirmedCallback))
|
||||
, _cancelledCallback(std::move(cancelledCallback)) {
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(tr::lng_cancel(tr::now))
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
|
||||
, _confirmedCallback(std::move(confirmedCallback))
|
||||
, _cancelledCallback(std::move(cancelledCallback)) {
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const TextWithEntities &text,
|
||||
const QString &confirmText,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(tr::lng_cancel(tr::now))
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
|
||||
, _confirmedCallback(std::move(confirmedCallback))
|
||||
, _cancelledCallback(std::move(cancelledCallback)) {
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const style::RoundButton &confirmStyle,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(tr::lng_cancel(tr::now))
|
||||
, _confirmStyle(confirmStyle)
|
||||
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
|
||||
, _confirmedCallback(std::move(confirmedCallback))
|
||||
, _cancelledCallback(std::move(cancelledCallback)) {
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const QString &cancelText,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(cancelText)
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
|
||||
, _confirmedCallback(std::move(confirmedCallback))
|
||||
, _cancelledCallback(std::move(cancelledCallback)) {
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const style::RoundButton &confirmStyle,
|
||||
const QString &cancelText,
|
||||
ConfirmBox::ConfirmedCallback confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(cancelText)
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
|
||||
, _confirmedCallback(std::move(confirmedCallback))
|
||||
, _cancelledCallback(std::move(cancelledCallback)) {
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(
|
||||
const InformBoxTag &,
|
||||
const QString &text,
|
||||
const QString &doneText,
|
||||
Fn<void()> closedCallback)
|
||||
: _confirmText(doneText)
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _informative(true)
|
||||
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
|
||||
, _confirmedCallback(generateInformCallback(closedCallback))
|
||||
, _cancelledCallback(generateInformCallback(closedCallback)) {
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(
|
||||
const InformBoxTag &,
|
||||
const TextWithEntities &text,
|
||||
const QString &doneText,
|
||||
Fn<void()> closedCallback)
|
||||
: _confirmText(doneText)
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _informative(true)
|
||||
, _text(st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right())
|
||||
, _confirmedCallback(generateInformCallback(closedCallback))
|
||||
, _cancelledCallback(generateInformCallback(closedCallback)) {
|
||||
init(text);
|
||||
}
|
||||
|
||||
FnMut<void()> ConfirmBox::generateInformCallback(
|
||||
Fn<void()> closedCallback) {
|
||||
return crl::guard(this, [=] {
|
||||
closeBox();
|
||||
if (closedCallback) {
|
||||
closedCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ConfirmBox::init(const QString &text) {
|
||||
_text.setText(
|
||||
st::boxLabelStyle,
|
||||
text,
|
||||
_informative ? kInformBoxTextOptions : _textPlainOptions);
|
||||
}
|
||||
|
||||
void ConfirmBox::init(const TextWithEntities &text) {
|
||||
_text.setMarkedText(st::boxLabelStyle, text, kMarkedTextBoxOptions);
|
||||
}
|
||||
|
||||
void ConfirmBox::prepare() {
|
||||
addButton(
|
||||
rpl::single(_confirmText),
|
||||
[=] { confirmed(); },
|
||||
_confirmStyle);
|
||||
if (!_informative) {
|
||||
addButton(
|
||||
rpl::single(_cancelText),
|
||||
[=] { _cancelled = true; closeBox(); });
|
||||
}
|
||||
|
||||
boxClosing() | rpl::start_with_next([=] {
|
||||
if (!_confirmed && (!_strictCancel || _cancelled)) {
|
||||
if (auto callback = std::move(_cancelledCallback)) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
textUpdated();
|
||||
}
|
||||
|
||||
void ConfirmBox::setMaxLineCount(int count) {
|
||||
if (_maxLineCount != count) {
|
||||
_maxLineCount = count;
|
||||
textUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmBox::textUpdated() {
|
||||
_textWidth = st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right();
|
||||
_textHeight = _text.countHeight(_textWidth);
|
||||
if (_maxLineCount > 0) {
|
||||
accumulate_min(_textHeight, _maxLineCount * st::boxLabelStyle.lineHeight);
|
||||
}
|
||||
setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
|
||||
|
||||
setMouseTracking(_text.hasLinks());
|
||||
}
|
||||
|
||||
void ConfirmBox::confirmed() {
|
||||
if (!_confirmed) {
|
||||
_confirmed = true;
|
||||
|
||||
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)) {
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
callback(crl::guard(weak, [=] { closeBox(); }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmBox::mouseMoveEvent(QMouseEvent *e) {
|
||||
_lastMousePos = e->globalPos();
|
||||
updateHover();
|
||||
}
|
||||
|
||||
void ConfirmBox::mousePressEvent(QMouseEvent *e) {
|
||||
_lastMousePos = e->globalPos();
|
||||
updateHover();
|
||||
ClickHandler::pressed();
|
||||
return BoxContent::mousePressEvent(e);
|
||||
}
|
||||
|
||||
void ConfirmBox::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_lastMousePos = e->globalPos();
|
||||
updateHover();
|
||||
if (const auto activated = ClickHandler::unpressed()) {
|
||||
ActivateClickHandler(window(), activated, e->button());
|
||||
crl::on_main(this, [=] {
|
||||
closeBox();
|
||||
});
|
||||
return;
|
||||
}
|
||||
BoxContent::mouseReleaseEvent(e);
|
||||
}
|
||||
|
||||
void ConfirmBox::leaveEventHook(QEvent *e) {
|
||||
ClickHandler::clearActive(this);
|
||||
}
|
||||
|
||||
void ConfirmBox::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
|
||||
setCursor(active ? style::cur_pointer : style::cur_default);
|
||||
update();
|
||||
}
|
||||
|
||||
void ConfirmBox::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
|
||||
update();
|
||||
}
|
||||
|
||||
void ConfirmBox::updateLink() {
|
||||
_lastMousePos = QCursor::pos();
|
||||
updateHover();
|
||||
}
|
||||
|
||||
void ConfirmBox::updateHover() {
|
||||
auto m = mapFromGlobal(_lastMousePos);
|
||||
auto state = _text.getStateLeft(m - QPoint(st::boxPadding.left(), st::boxPadding.top()), _textWidth, width());
|
||||
|
||||
ClickHandler::setActive(state.link, this);
|
||||
}
|
||||
|
||||
void ConfirmBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
confirmed();
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::boxTextFg);
|
||||
if (_maxLineCount > 0) {
|
||||
_text.drawLeftElided(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), _maxLineCount, style::al_left);
|
||||
} else {
|
||||
_text.drawLeft(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), style::al_left);
|
||||
}
|
||||
}
|
||||
|
||||
InformBox::InformBox(QWidget*, const QString &text, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, tr::lng_box_ok(tr::now), std::move(closedCallback)) {
|
||||
}
|
||||
|
||||
InformBox::InformBox(QWidget*, const QString &text, const QString &doneText, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) {
|
||||
}
|
||||
|
||||
InformBox::InformBox(QWidget*, const TextWithEntities &text, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, tr::lng_box_ok(tr::now), std::move(closedCallback)) {
|
||||
}
|
||||
|
||||
InformBox::InformBox(QWidget*, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) {
|
||||
}
|
||||
|
||||
MaxInviteBox::MaxInviteBox(QWidget*, not_null<ChannelData*> channel) : BoxContent()
|
||||
, _channel(channel)
|
||||
, _text(
|
||||
st::boxLabelStyle,
|
||||
tr::lng_participant_invite_sorry(
|
||||
tr::now,
|
||||
lt_count,
|
||||
channel->session().serverConfig().chatSizeMax),
|
||||
kInformBoxTextOptions,
|
||||
(st::boxWidth
|
||||
- st::boxPadding.left()
|
||||
- st::defaultBox.buttonPadding.right())) {
|
||||
}
|
||||
|
||||
void MaxInviteBox::prepare() {
|
||||
setMouseTracking(true);
|
||||
|
||||
addButton(tr::lng_box_ok(), [=] { closeBox(); });
|
||||
|
||||
_textWidth = st::boxWidth - st::boxPadding.left() - st::defaultBox.buttonPadding.right();
|
||||
_textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxLabelStyle.lineHeight);
|
||||
setDimensions(st::boxWidth, st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom());
|
||||
|
||||
_channel->session().changes().peerUpdates(
|
||||
_channel,
|
||||
Data::PeerUpdate::Flag::InviteLinks
|
||||
) | rpl::start_with_next([=] {
|
||||
rtlupdate(_invitationLink);
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
|
||||
updateSelected(e->globalPos());
|
||||
}
|
||||
|
||||
void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
|
||||
mouseMoveEvent(e);
|
||||
if (_linkOver) {
|
||||
if (_channel->inviteLink().isEmpty()) {
|
||||
_channel->session().api().inviteLinks().create(_channel);
|
||||
} else {
|
||||
QGuiApplication::clipboard()->setText(_channel->inviteLink());
|
||||
Ui::Toast::Show(tr::lng_create_channel_link_copied(tr::now));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaxInviteBox::leaveEventHook(QEvent *e) {
|
||||
updateSelected(QCursor::pos());
|
||||
}
|
||||
|
||||
void MaxInviteBox::updateSelected(const QPoint &cursorGlobalPosition) {
|
||||
QPoint p(mapFromGlobal(cursorGlobalPosition));
|
||||
|
||||
bool linkOver = _invitationLink.contains(p);
|
||||
if (linkOver != _linkOver) {
|
||||
_linkOver = linkOver;
|
||||
update();
|
||||
setCursor(_linkOver ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
}
|
||||
|
||||
void MaxInviteBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::boxTextFg);
|
||||
_text.drawLeftElided(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, width(), 16, style::al_left);
|
||||
|
||||
QTextOption option(style::al_left);
|
||||
option.setWrapMode(QTextOption::WrapAnywhere);
|
||||
p.setFont(_linkOver ? st::defaultInputField.font->underline() : st::defaultInputField.font);
|
||||
p.setPen(st::defaultLinkButton.color);
|
||||
auto inviteLinkText = _channel->inviteLink().isEmpty() ? tr::lng_group_invite_create(tr::now) : _channel->inviteLink();
|
||||
p.drawText(_invitationLink, inviteLinkText, option);
|
||||
}
|
||||
|
||||
void MaxInviteBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
_invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height);
|
||||
}
|
||||
|
||||
PinMessageBox::PinMessageBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
MsgId msgId)
|
||||
: _peer(peer)
|
||||
, _api(&peer->session().mtp())
|
||||
, _msgId(msgId)
|
||||
, _pinningOld(IsOldForPin(msgId, peer))
|
||||
, _text(
|
||||
this,
|
||||
(_pinningOld
|
||||
? tr::lng_pinned_pin_old_sure(tr::now)
|
||||
: (peer->isChat() || peer->isMegagroup())
|
||||
? tr::lng_pinned_pin_sure_group(tr::now)
|
||||
: tr::lng_pinned_pin_sure(tr::now)),
|
||||
st::boxLabel) {
|
||||
}
|
||||
|
||||
void PinMessageBox::prepare() {
|
||||
addButton(tr::lng_pinned_pin(), [this] { pinMessage(); });
|
||||
addButton(tr::lng_cancel(), [this] { closeBox(); });
|
||||
|
||||
if (_peer->isUser() && !_peer->isSelf()) {
|
||||
_pinForPeer.create(
|
||||
this,
|
||||
tr::lng_pinned_also_for_other(
|
||||
tr::now,
|
||||
lt_user,
|
||||
_peer->shortName()),
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
_checkbox = _pinForPeer;
|
||||
} else if (!_pinningOld && (_peer->isChat() || _peer->isMegagroup())) {
|
||||
_notify.create(
|
||||
this,
|
||||
tr::lng_pinned_notify(tr::now),
|
||||
true,
|
||||
st::defaultBoxCheckbox);
|
||||
_checkbox = _notify;
|
||||
}
|
||||
|
||||
auto height = st::boxPadding.top() + _text->height() + st::boxPadding.bottom();
|
||||
if (_checkbox) {
|
||||
height += st::boxMediumSkip + _checkbox->heightNoMargins();
|
||||
}
|
||||
setDimensions(st::boxWidth, height);
|
||||
}
|
||||
|
||||
void PinMessageBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
|
||||
if (_checkbox) {
|
||||
_checkbox->moveToLeft(st::boxPadding.left(), _text->y() + _text->height() + st::boxMediumSkip);
|
||||
}
|
||||
}
|
||||
|
||||
void PinMessageBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
pinMessage();
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void PinMessageBox::pinMessage() {
|
||||
if (_requestId) return;
|
||||
|
||||
auto flags = MTPmessages_UpdatePinnedMessage::Flags(0);
|
||||
if (_notify && !_notify->checked()) {
|
||||
flags |= MTPmessages_UpdatePinnedMessage::Flag::f_silent;
|
||||
}
|
||||
if (_pinForPeer && !_pinForPeer->checked()) {
|
||||
flags |= MTPmessages_UpdatePinnedMessage::Flag::f_pm_oneside;
|
||||
}
|
||||
_requestId = _api.request(MTPmessages_UpdatePinnedMessage(
|
||||
MTP_flags(flags),
|
||||
_peer->input,
|
||||
MTP_int(_msgId)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_peer->session().api().applyUpdates(result);
|
||||
Ui::hideLayer();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
Ui::hideLayer();
|
||||
}).send();
|
||||
}
|
||||
|
||||
DeleteMessagesBox::DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<HistoryItem*> item,
|
||||
bool suggestModerateActions)
|
||||
: _session(&item->history()->session())
|
||||
, _ids(1, item->fullId()) {
|
||||
if (suggestModerateActions) {
|
||||
_moderateBan = item->suggestBanReport();
|
||||
_moderateDeleteAll = item->suggestDeleteAllReport();
|
||||
if (_moderateBan || _moderateDeleteAll) {
|
||||
_moderateFrom = item->from()->asUser();
|
||||
_moderateInChannel = item->history()->peer->asChannel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeleteMessagesBox::DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
MessageIdsList &&selected)
|
||||
: _session(session)
|
||||
, _ids(std::move(selected)) {
|
||||
Expects(!_ids.empty());
|
||||
}
|
||||
|
||||
DeleteMessagesBox::DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
bool justClear)
|
||||
: _session(&peer->session())
|
||||
, _wipeHistoryPeer(peer)
|
||||
, _wipeHistoryJustClear(justClear) {
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::prepare() {
|
||||
auto details = TextWithEntities();
|
||||
const auto appendDetails = [&](TextWithEntities &&text) {
|
||||
details.append(qstr("\n\n")).append(std::move(text));
|
||||
};
|
||||
auto deleteText = lifetime().make_state<rpl::variable<QString>>();
|
||||
*deleteText = tr::lng_box_delete();
|
||||
auto deleteStyle = &st::defaultBoxButton;
|
||||
auto canDelete = true;
|
||||
if (const auto peer = _wipeHistoryPeer) {
|
||||
if (_wipeHistoryJustClear) {
|
||||
const auto isChannel = peer->isBroadcast();
|
||||
const auto isPublicGroup = peer->isMegagroup()
|
||||
&& peer->asChannel()->isPublic();
|
||||
if (isChannel || isPublicGroup) {
|
||||
canDelete = false;
|
||||
}
|
||||
details.text = isChannel
|
||||
? tr::lng_no_clear_history_channel(tr::now)
|
||||
: isPublicGroup
|
||||
? tr::lng_no_clear_history_group(tr::now)
|
||||
: peer->isSelf()
|
||||
? tr::lng_sure_delete_saved_messages(tr::now)
|
||||
: peer->isUser()
|
||||
? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name)
|
||||
: tr::lng_sure_delete_group_history(tr::now, lt_group, peer->name);
|
||||
deleteStyle = &st::attentionBoxButton;
|
||||
} else {
|
||||
details.text = peer->isSelf()
|
||||
? tr::lng_sure_delete_saved_messages(tr::now)
|
||||
: peer->isUser()
|
||||
? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name)
|
||||
: peer->isChat()
|
||||
? tr::lng_sure_delete_and_exit(tr::now, lt_group, peer->name)
|
||||
: peer->isMegagroup()
|
||||
? tr::lng_sure_leave_group(tr::now)
|
||||
: tr::lng_sure_leave_channel(tr::now);
|
||||
if (!peer->isUser()) {
|
||||
*deleteText = tr::lng_box_leave();
|
||||
}
|
||||
deleteStyle = &st::attentionBoxButton;
|
||||
}
|
||||
if (auto revoke = revokeText(peer)) {
|
||||
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
|
||||
appendDetails(std::move(revoke->description));
|
||||
if (!peer->isUser() && !_wipeHistoryJustClear) {
|
||||
_revoke->checkedValue(
|
||||
) | rpl::start_with_next([=](bool revokeForAll) {
|
||||
*deleteText = revokeForAll
|
||||
? tr::lng_box_delete()
|
||||
: tr::lng_box_leave();
|
||||
}, _revoke->lifetime());
|
||||
}
|
||||
}
|
||||
} else if (_moderateFrom) {
|
||||
Assert(_moderateInChannel != nullptr);
|
||||
|
||||
details.text = tr::lng_selected_delete_sure_this(tr::now);
|
||||
if (_moderateBan) {
|
||||
_banUser.create(this, tr::lng_ban_user(tr::now), false, st::defaultBoxCheckbox);
|
||||
}
|
||||
_reportSpam.create(this, tr::lng_report_spam(tr::now), false, st::defaultBoxCheckbox);
|
||||
if (_moderateDeleteAll) {
|
||||
_deleteAll.create(this, tr::lng_delete_all_from(tr::now), false, st::defaultBoxCheckbox);
|
||||
}
|
||||
} else {
|
||||
details.text = (_ids.size() == 1)
|
||||
? tr::lng_selected_delete_sure_this(tr::now)
|
||||
: tr::lng_selected_delete_sure(tr::now, lt_count, _ids.size());
|
||||
if (const auto peer = checkFromSinglePeer()) {
|
||||
auto count = int(_ids.size());
|
||||
if (hasScheduledMessages()) {
|
||||
} else if (auto revoke = revokeText(peer)) {
|
||||
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
|
||||
appendDetails(std::move(revoke->description));
|
||||
} else if (peer->isChannel()) {
|
||||
if (peer->isMegagroup()) {
|
||||
appendDetails({ tr::lng_delete_for_everyone_hint(tr::now, lt_count, count) });
|
||||
}
|
||||
} else if (peer->isChat()) {
|
||||
appendDetails({ tr::lng_delete_for_me_chat_hint(tr::now, lt_count, count) });
|
||||
} else if (!peer->isSelf()) {
|
||||
appendDetails({ tr::lng_delete_for_me_hint(tr::now, lt_count, count) });
|
||||
}
|
||||
}
|
||||
}
|
||||
_text.create(this, rpl::single(std::move(details)), st::boxLabel);
|
||||
|
||||
if (_wipeHistoryJustClear
|
||||
&& _wipeHistoryPeer
|
||||
&& ((_wipeHistoryPeer->isUser()
|
||||
&& !_wipeHistoryPeer->isSelf()
|
||||
&& !_wipeHistoryPeer->isNotificationsUser())
|
||||
|| (_wipeHistoryPeer->isChat()
|
||||
&& _wipeHistoryPeer->asChat()->canDeleteMessages())
|
||||
|| (_wipeHistoryPeer->isChannel()
|
||||
&& _wipeHistoryPeer->asChannel()->canDeleteMessages()))) {
|
||||
_wipeHistoryPeer->updateFull();
|
||||
_autoDeleteSettings.create(
|
||||
this,
|
||||
(_wipeHistoryPeer->messagesTTL()
|
||||
? tr::lng_edit_auto_delete_settings(tr::now)
|
||||
: tr::lng_enable_auto_delete(tr::now)),
|
||||
st::boxLinkButton);
|
||||
_autoDeleteSettings->setClickedCallback([=] {
|
||||
getDelegate()->show(
|
||||
Box(
|
||||
HistoryView::Controls::AutoDeleteSettingsBox,
|
||||
_wipeHistoryPeer),
|
||||
Ui::LayerOption(0));
|
||||
});
|
||||
}
|
||||
|
||||
if (canDelete) {
|
||||
addButton(
|
||||
deleteText->value(),
|
||||
[=] { deleteAndClear(); },
|
||||
*deleteStyle);
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
} else {
|
||||
addButton(tr::lng_about_done(), [=] { closeBox(); });
|
||||
}
|
||||
|
||||
auto fullHeight = st::boxPadding.top() + _text->height() + st::boxPadding.bottom();
|
||||
if (_moderateFrom) {
|
||||
fullHeight += st::boxMediumSkip;
|
||||
if (_banUser) {
|
||||
fullHeight += _banUser->heightNoMargins() + st::boxLittleSkip;
|
||||
}
|
||||
fullHeight += _reportSpam->heightNoMargins();
|
||||
if (_deleteAll) {
|
||||
fullHeight += st::boxLittleSkip + _deleteAll->heightNoMargins();
|
||||
}
|
||||
} else if (_revoke) {
|
||||
fullHeight += st::boxMediumSkip + _revoke->heightNoMargins();
|
||||
}
|
||||
if (_autoDeleteSettings) {
|
||||
fullHeight += st::boxMediumSkip + _autoDeleteSettings->height() + st::boxLittleSkip;
|
||||
}
|
||||
setDimensions(st::boxWidth, fullHeight);
|
||||
}
|
||||
|
||||
bool DeleteMessagesBox::hasScheduledMessages() const {
|
||||
for (const auto &fullId : _ids) {
|
||||
if (const auto item = _session->data().message(fullId)) {
|
||||
if (item->isScheduled()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
|
||||
auto result = (PeerData*)nullptr;
|
||||
for (const auto &fullId : _ids) {
|
||||
if (const auto item = _session->data().message(fullId)) {
|
||||
const auto peer = item->history()->peer;
|
||||
if (!result) {
|
||||
result = peer;
|
||||
} else if (result != peer) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
|
||||
-> std::optional<RevokeConfig> {
|
||||
auto result = RevokeConfig();
|
||||
if (peer == _wipeHistoryPeer) {
|
||||
if (!peer->canRevokeFullHistory()) {
|
||||
return std::nullopt;
|
||||
} else if (const auto user = peer->asUser()) {
|
||||
result.checkbox = tr::lng_delete_for_other_check(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->firstName);
|
||||
} else if (_wipeHistoryJustClear) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
result.checkbox = tr::lng_delete_for_everyone_check(tr::now);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto items = ranges::views::all(
|
||||
_ids
|
||||
) | ranges::views::transform([&](FullMsgId id) {
|
||||
return peer->owner().message(id);
|
||||
}) | ranges::views::filter([](HistoryItem *item) {
|
||||
return (item != nullptr);
|
||||
}) | ranges::to_vector;
|
||||
|
||||
if (items.size() != _ids.size()) {
|
||||
// We don't have information about all messages.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto now = base::unixtime::now();
|
||||
const auto canRevoke = [&](HistoryItem * item) {
|
||||
return item->canDeleteForEveryone(now);
|
||||
};
|
||||
const auto cannotRevoke = [&](HistoryItem *item) {
|
||||
return !item->canDeleteForEveryone(now);
|
||||
};
|
||||
const auto canRevokeAll = ranges::none_of(items, cannotRevoke);
|
||||
auto outgoing = items | ranges::views::filter(&HistoryItem::out);
|
||||
const auto canRevokeOutgoingCount = canRevokeAll
|
||||
? -1
|
||||
: ranges::count_if(outgoing, canRevoke);
|
||||
|
||||
if (canRevokeAll) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
result.checkbox = tr::lng_delete_for_other_check(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->firstName);
|
||||
} else {
|
||||
result.checkbox = tr::lng_delete_for_everyone_check(tr::now);
|
||||
}
|
||||
return result;
|
||||
} else if (canRevokeOutgoingCount > 0) {
|
||||
result.checkbox = tr::lng_delete_for_other_my(tr::now);
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (canRevokeOutgoingCount == 1) {
|
||||
result.description = tr::lng_selected_unsend_about_user_one(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(user->shortName()),
|
||||
Ui::Text::WithEntities);
|
||||
} else {
|
||||
result.description = tr::lng_selected_unsend_about_user(
|
||||
tr::now,
|
||||
lt_count,
|
||||
canRevokeOutgoingCount,
|
||||
lt_user,
|
||||
Ui::Text::Bold(user->shortName()),
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
} else if (canRevokeOutgoingCount == 1) {
|
||||
result.description = tr::lng_selected_unsend_about_group_one(
|
||||
tr::now,
|
||||
Ui::Text::WithEntities);
|
||||
} else {
|
||||
result.description = tr::lng_selected_unsend_about_group(
|
||||
tr::now,
|
||||
lt_count,
|
||||
canRevokeOutgoingCount,
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
|
||||
auto top = _text->bottomNoMargins() + st::boxMediumSkip;
|
||||
if (_moderateFrom) {
|
||||
if (_banUser) {
|
||||
_banUser->moveToLeft(st::boxPadding.left(), top);
|
||||
top += _banUser->heightNoMargins() + st::boxLittleSkip;
|
||||
}
|
||||
_reportSpam->moveToLeft(st::boxPadding.left(), top);
|
||||
top += _reportSpam->heightNoMargins() + st::boxLittleSkip;
|
||||
if (_deleteAll) {
|
||||
_deleteAll->moveToLeft(st::boxPadding.left(), top);
|
||||
top += _deleteAll->heightNoMargins() + st::boxLittleSkip;
|
||||
}
|
||||
} else if (_revoke) {
|
||||
const auto availableWidth = width() - 2 * st::boxPadding.left();
|
||||
_revoke->resizeToNaturalWidth(availableWidth);
|
||||
_revoke->moveToLeft(st::boxPadding.left(), top);
|
||||
top += _revoke->heightNoMargins() + st::boxLittleSkip;
|
||||
}
|
||||
if (_autoDeleteSettings) {
|
||||
top += st::boxMediumSkip - st::boxLittleSkip;
|
||||
_autoDeleteSettings->moveToLeft(st::boxPadding.left(), top);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
// Don't make the clearing history so easy.
|
||||
if (!_wipeHistoryPeer) {
|
||||
deleteAndClear();
|
||||
}
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::deleteAndClear() {
|
||||
const auto revoke = _revoke ? _revoke->checked() : false;
|
||||
if (const auto peer = _wipeHistoryPeer) {
|
||||
const auto justClear = _wipeHistoryJustClear;
|
||||
closeBox();
|
||||
|
||||
if (justClear) {
|
||||
peer->session().api().clearHistory(peer, revoke);
|
||||
} else {
|
||||
for (const auto &controller : peer->session().windows()) {
|
||||
if (controller->activeChatCurrent().peer() == peer) {
|
||||
Ui::showChatsList(&peer->session());
|
||||
}
|
||||
}
|
||||
// Don't delete old history by default,
|
||||
// because Android app doesn't.
|
||||
//
|
||||
//if (const auto from = peer->migrateFrom()) {
|
||||
// peer->session().api().deleteConversation(from, false);
|
||||
//}
|
||||
peer->session().api().deleteConversation(peer, revoke);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_moderateFrom) {
|
||||
if (_banUser && _banUser->checked()) {
|
||||
_moderateInChannel->session().api().kickParticipant(
|
||||
_moderateInChannel,
|
||||
_moderateFrom,
|
||||
ChatRestrictionsInfo());
|
||||
}
|
||||
if (_reportSpam->checked()) {
|
||||
_moderateInChannel->session().api().request(
|
||||
MTPchannels_ReportSpam(
|
||||
_moderateInChannel->inputChannel,
|
||||
_moderateFrom->inputUser,
|
||||
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg)))
|
||||
).send();
|
||||
}
|
||||
if (_deleteAll && _deleteAll->checked()) {
|
||||
_moderateInChannel->session().api().deleteAllFromUser(
|
||||
_moderateInChannel,
|
||||
_moderateFrom);
|
||||
}
|
||||
}
|
||||
|
||||
if (_deleteConfirmedCallback) {
|
||||
_deleteConfirmedCallback();
|
||||
}
|
||||
|
||||
// deleteMessages can initiate closing of the current section,
|
||||
// which will cause this box to be destroyed.
|
||||
const auto session = _session;
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
|
||||
session->data().histories().deleteMessages(_ids, revoke);
|
||||
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
session->data().sendHistoryChangeNotifications();
|
||||
}
|
||||
|
||||
ConfirmDontWarnBox::ConfirmDontWarnBox(
|
||||
QWidget*,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
const QString &checkbox,
|
||||
rpl::producer<QString> confirm,
|
||||
FnMut<void(bool)> callback)
|
||||
: _confirm(std::move(confirm))
|
||||
, _content(setupContent(std::move(text), checkbox, std::move(callback))) {
|
||||
}
|
||||
|
||||
void ConfirmDontWarnBox::prepare() {
|
||||
setDimensionsToContent(st::boxWidth, _content);
|
||||
addButton(std::move(_confirm), [=] { _callback(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
}
|
||||
|
||||
not_null<Ui::RpWidget*> ConfirmDontWarnBox::setupContent(
|
||||
rpl::producer<TextWithEntities> text,
|
||||
const QString &checkbox,
|
||||
FnMut<void(bool)> callback) {
|
||||
const auto result = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
result->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
result,
|
||||
std::move(text),
|
||||
st::boxLabel),
|
||||
st::boxPadding);
|
||||
const auto control = result->add(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
result,
|
||||
checkbox,
|
||||
false,
|
||||
st::defaultBoxCheckbox),
|
||||
style::margins(
|
||||
st::boxPadding.left(),
|
||||
st::boxPadding.bottom(),
|
||||
st::boxPadding.right(),
|
||||
st::boxPadding.bottom()));
|
||||
_callback = [=, callback = std::move(callback)]() mutable {
|
||||
const auto checked = control->checked();
|
||||
auto local = std::move(callback);
|
||||
closeBox();
|
||||
local(checked);
|
||||
};
|
||||
return result;
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
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 "boxes/abstract_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Data {
|
||||
class PhotoMedia;
|
||||
class CloudImageView;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class Checkbox;
|
||||
class FlatLabel;
|
||||
class EmptyUserpic;
|
||||
class LinkButton;
|
||||
} // namespace Ui
|
||||
|
||||
class InformBox;
|
||||
class ConfirmBox : public Ui::BoxContent, public ClickHandlerHost {
|
||||
public:
|
||||
|
||||
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();
|
||||
|
||||
// If strict cancel is set the cancelledCallback is only called if the cancel button was pressed.
|
||||
void setStrictCancel(bool strictCancel) {
|
||||
_strictCancel = strictCancel;
|
||||
}
|
||||
|
||||
void setMaxLineCount(int count);
|
||||
|
||||
// ClickHandlerHost interface
|
||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
||||
private:
|
||||
struct InformBoxTag {
|
||||
};
|
||||
ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, Fn<void()> closedCallback);
|
||||
ConfirmBox(const InformBoxTag &, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback);
|
||||
FnMut<void()> generateInformCallback(Fn<void()> closedCallback);
|
||||
friend class InformBox;
|
||||
|
||||
void confirmed();
|
||||
void init(const QString &text);
|
||||
void init(const TextWithEntities &text);
|
||||
void textUpdated();
|
||||
void updateHover();
|
||||
|
||||
QString _confirmText;
|
||||
QString _cancelText;
|
||||
const style::RoundButton &_confirmStyle;
|
||||
bool _informative = false;
|
||||
|
||||
Ui::Text::String _text;
|
||||
int _textWidth = 0;
|
||||
int _textHeight = 0;
|
||||
int _maxLineCount = 16;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
bool _confirmed = false;
|
||||
bool _cancelled = false;
|
||||
bool _strictCancel = false;
|
||||
ConfirmBox::ConfirmedCallback _confirmedCallback;
|
||||
FnMut<void()> _cancelledCallback;
|
||||
|
||||
};
|
||||
|
||||
class InformBox : public ConfirmBox {
|
||||
public:
|
||||
InformBox(QWidget*, const QString &text, Fn<void()> closedCallback = nullptr);
|
||||
InformBox(QWidget*, const QString &text, const QString &doneText, Fn<void()> closedCallback = nullptr);
|
||||
InformBox(QWidget*, const TextWithEntities &text, Fn<void()> closedCallback = nullptr);
|
||||
InformBox(QWidget*, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback = nullptr);
|
||||
|
||||
};
|
||||
|
||||
class MaxInviteBox final : public Ui::BoxContent {
|
||||
public:
|
||||
MaxInviteBox(QWidget*, not_null<ChannelData*> channel);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
||||
private:
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
|
||||
not_null<ChannelData*> _channel;
|
||||
|
||||
Ui::Text::String _text;
|
||||
int32 _textWidth, _textHeight;
|
||||
|
||||
QRect _invitationLink;
|
||||
bool _linkOver = false;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
};
|
||||
|
||||
class PinMessageBox final : public Ui::BoxContent {
|
||||
public:
|
||||
PinMessageBox(QWidget*, not_null<PeerData*> peer, MsgId msgId);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
void pinMessage();
|
||||
|
||||
const not_null<PeerData*> _peer;
|
||||
MTP::Sender _api;
|
||||
MsgId _msgId = 0;
|
||||
bool _pinningOld = false;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _text;
|
||||
object_ptr<Ui::Checkbox> _notify = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _pinForPeer = { nullptr };
|
||||
QPointer<Ui::Checkbox> _checkbox;
|
||||
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
};
|
||||
|
||||
class DeleteMessagesBox final : public Ui::BoxContent {
|
||||
public:
|
||||
DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<HistoryItem*> item,
|
||||
bool suggestModerateActions);
|
||||
DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
MessageIdsList &&selected);
|
||||
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool justClear);
|
||||
|
||||
void setDeleteConfirmedCallback(Fn<void()> callback) {
|
||||
_deleteConfirmedCallback = std::move(callback);
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
struct RevokeConfig {
|
||||
QString checkbox;
|
||||
TextWithEntities description;
|
||||
};
|
||||
void deleteAndClear();
|
||||
[[nodiscard]] PeerData *checkFromSinglePeer() const;
|
||||
[[nodiscard]] bool hasScheduledMessages() const;
|
||||
[[nodiscard]] std::optional<RevokeConfig> revokeText(
|
||||
not_null<PeerData*> peer) const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
PeerData * const _wipeHistoryPeer = nullptr;
|
||||
const bool _wipeHistoryJustClear = false;
|
||||
const MessageIdsList _ids;
|
||||
UserData *_moderateFrom = nullptr;
|
||||
ChannelData *_moderateInChannel = nullptr;
|
||||
bool _moderateBan = false;
|
||||
bool _moderateDeleteAll = false;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _text = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _revoke = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _banUser = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _reportSpam = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _deleteAll = { nullptr };
|
||||
object_ptr<Ui::LinkButton> _autoDeleteSettings = { nullptr };
|
||||
|
||||
Fn<void()> _deleteConfirmedCallback;
|
||||
|
||||
};
|
||||
|
||||
class ConfirmDontWarnBox : public Ui::BoxContent {
|
||||
public:
|
||||
ConfirmDontWarnBox(
|
||||
QWidget*,
|
||||
rpl::producer<TextWithEntities> text,
|
||||
const QString &checkbox,
|
||||
rpl::producer<QString> confirm,
|
||||
FnMut<void(bool)> callback);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
not_null<Ui::RpWidget*> setupContent(
|
||||
rpl::producer<TextWithEntities> text,
|
||||
const QString &checkbox,
|
||||
FnMut<void(bool)> callback);
|
||||
|
||||
rpl::producer<QString> _confirm;
|
||||
FnMut<void()> _callback;
|
||||
not_null<Ui::RpWidget*> _content;
|
||||
|
||||
};
|
||||
@@ -1,416 +0,0 @@
|
||||
/*
|
||||
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 "boxes/confirm_phone_box.h"
|
||||
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "core/click_handler_types.h" // UrlClickHandler
|
||||
#include "base/qthelp_url.h" // qthelp::url_encode
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mtproto/facade.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
object_ptr<ConfirmPhoneBox> CurrentConfirmPhoneBox = { nullptr };
|
||||
|
||||
void SendToBannedHelp(const QString &phone) {
|
||||
const auto version = QString::fromLatin1(AppVersionStr)
|
||||
+ (cAlphaVersion()
|
||||
? qsl(" alpha %1").arg(cAlphaVersion())
|
||||
: (AppBetaVersion ? " beta" : ""));
|
||||
|
||||
const auto subject = qsl("Banned phone number: ") + phone;
|
||||
|
||||
const auto body = qsl("\
|
||||
I'm trying to use my mobile phone number: ") + phone + qsl("\n\
|
||||
But Telegram says it's banned. Please help.\n\
|
||||
\n\
|
||||
App version: ") + version + qsl("\n\
|
||||
OS version: ") + Platform::SystemVersionPretty() + qsl("\n\
|
||||
Locale: ") + Platform::SystemLanguage();
|
||||
|
||||
const auto url = "mailto:?to="
|
||||
+ qthelp::url_encode("login@stel.com")
|
||||
+ "&subject="
|
||||
+ qthelp::url_encode(subject)
|
||||
+ "&body="
|
||||
+ qthelp::url_encode(body);
|
||||
|
||||
UrlClickHandler::Open(url);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ShowPhoneBannedError(const QString &phone) {
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto close = [=] {
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
};
|
||||
*box = Ui::show(Box<ConfirmBox>(
|
||||
tr::lng_signin_banned_text(tr::now),
|
||||
tr::lng_box_ok(tr::now),
|
||||
tr::lng_signin_banned_help(tr::now),
|
||||
close,
|
||||
[=] { SendToBannedHelp(phone); close(); }));
|
||||
}
|
||||
|
||||
SentCodeField::SentCodeField(
|
||||
QWidget *parent,
|
||||
const style::InputField &st,
|
||||
rpl::producer<QString> placeholder,
|
||||
const QString &val)
|
||||
: Ui::InputField(parent, st, std::move(placeholder), val) {
|
||||
connect(this, &Ui::InputField::changed, [this] { fix(); });
|
||||
}
|
||||
|
||||
void SentCodeField::setAutoSubmit(int length, Fn<void()> submitCallback) {
|
||||
_autoSubmitLength = length;
|
||||
_submitCallback = std::move(submitCallback);
|
||||
}
|
||||
|
||||
void SentCodeField::setChangedCallback(Fn<void()> changedCallback) {
|
||||
_changedCallback = std::move(changedCallback);
|
||||
}
|
||||
|
||||
QString SentCodeField::getDigitsOnly() const {
|
||||
return QString(
|
||||
getLastText()
|
||||
).remove(
|
||||
QRegularExpression("[^\\d]")
|
||||
);
|
||||
}
|
||||
|
||||
void SentCodeField::fix() {
|
||||
if (_fixing) return;
|
||||
|
||||
_fixing = true;
|
||||
auto newText = QString();
|
||||
const auto now = getLastText();
|
||||
auto oldPos = textCursor().position();
|
||||
auto newPos = -1;
|
||||
auto oldLen = now.size();
|
||||
auto digitCount = 0;
|
||||
for (const auto &ch : now) {
|
||||
if (ch.isDigit()) {
|
||||
++digitCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (_autoSubmitLength > 0 && digitCount > _autoSubmitLength) {
|
||||
digitCount = _autoSubmitLength;
|
||||
}
|
||||
auto strict = (_autoSubmitLength > 0)
|
||||
&& (digitCount == _autoSubmitLength);
|
||||
|
||||
newText.reserve(oldLen);
|
||||
int i = 0;
|
||||
for (const auto &ch : now) {
|
||||
if (i++ == oldPos) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
if (ch.isDigit()) {
|
||||
if (!digitCount--) {
|
||||
break;
|
||||
}
|
||||
newText += ch;
|
||||
if (strict && !digitCount) {
|
||||
break;
|
||||
}
|
||||
} else if (ch == '-') {
|
||||
newText += ch;
|
||||
}
|
||||
}
|
||||
if (newPos < 0) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
if (newText != now) {
|
||||
setText(newText);
|
||||
setCursorPosition(newPos);
|
||||
}
|
||||
_fixing = false;
|
||||
|
||||
if (_changedCallback) {
|
||||
_changedCallback();
|
||||
}
|
||||
if (strict && _submitCallback) {
|
||||
_submitCallback();
|
||||
}
|
||||
}
|
||||
|
||||
SentCodeCall::SentCodeCall(
|
||||
FnMut<void()> callCallback,
|
||||
Fn<void()> updateCallback)
|
||||
: _call(std::move(callCallback))
|
||||
, _update(std::move(updateCallback)) {
|
||||
_timer.setCallback([=] {
|
||||
if (_status.state == State::Waiting) {
|
||||
if (--_status.timeout <= 0) {
|
||||
_status.state = State::Calling;
|
||||
_timer.cancel();
|
||||
if (_call) {
|
||||
_call();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_update) {
|
||||
_update();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void SentCodeCall::setStatus(const Status &status) {
|
||||
_status = status;
|
||||
if (_status.state == State::Waiting) {
|
||||
_timer.callEach(1000);
|
||||
}
|
||||
}
|
||||
|
||||
QString SentCodeCall::getText() const {
|
||||
switch (_status.state) {
|
||||
case State::Waiting: {
|
||||
if (_status.timeout >= 3600) {
|
||||
return tr::lng_code_call(tr::now, lt_minutes, qsl("%1:%2").arg(_status.timeout / 3600).arg((_status.timeout / 60) % 60, 2, 10, QChar('0')), lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0')));
|
||||
}
|
||||
return tr::lng_code_call(tr::now, lt_minutes, QString::number(_status.timeout / 60), lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0')));
|
||||
} break;
|
||||
case State::Calling: return tr::lng_code_calling(tr::now);
|
||||
case State::Called: return tr::lng_code_called(tr::now);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::Start(
|
||||
not_null<Main::Session*> session,
|
||||
const QString &phone,
|
||||
const QString &hash) {
|
||||
if (CurrentConfirmPhoneBox
|
||||
&& (CurrentConfirmPhoneBox->getPhone() != phone
|
||||
|| &CurrentConfirmPhoneBox->session() != session)) {
|
||||
CurrentConfirmPhoneBox.destroyDelayed();
|
||||
}
|
||||
if (!CurrentConfirmPhoneBox) {
|
||||
CurrentConfirmPhoneBox = Box<ConfirmPhoneBox>(session, phone, hash);
|
||||
}
|
||||
CurrentConfirmPhoneBox->checkPhoneAndHash();
|
||||
}
|
||||
|
||||
ConfirmPhoneBox::ConfirmPhoneBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
const QString &phone,
|
||||
const QString &hash)
|
||||
: _session(session)
|
||||
, _api(&session->mtp())
|
||||
, _phone(phone)
|
||||
, _hash(hash)
|
||||
, _call([this] { sendCall(); }, [this] { update(); }) {
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::sendCall() {
|
||||
_api.request(MTPauth_ResendCode(
|
||||
MTP_string(_phone),
|
||||
MTP_string(_phoneHash)
|
||||
)).done([=](const MTPauth_SentCode &result) {
|
||||
callDone(result);
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::checkPhoneAndHash() {
|
||||
if (_sendCodeRequestId) {
|
||||
return;
|
||||
}
|
||||
_sendCodeRequestId = _api.request(MTPaccount_SendConfirmPhoneCode(
|
||||
MTP_string(_hash),
|
||||
MTP_codeSettings(MTP_flags(0))
|
||||
)).done([=](const MTPauth_SentCode &result) {
|
||||
sendCodeDone(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
sendCodeFail(error);
|
||||
}).handleFloodErrors().send();
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::sendCodeDone(const MTPauth_SentCode &result) {
|
||||
result.match([&](const MTPDauth_sentCode &data) {
|
||||
_sendCodeRequestId = 0;
|
||||
_sentCodeLength = data.vtype().match([&](const MTPDauth_sentCodeTypeApp &data) {
|
||||
LOG(("Error: should not be in-app code!"));
|
||||
return 0;
|
||||
}, [&](const MTPDauth_sentCodeTypeSms &data) {
|
||||
return data.vlength().v;
|
||||
}, [&](const MTPDauth_sentCodeTypeCall &data) {
|
||||
return data.vlength().v;
|
||||
}, [&](const MTPDauth_sentCodeTypeFlashCall &data) {
|
||||
LOG(("Error: should not be flashcall!"));
|
||||
return 0;
|
||||
});
|
||||
_phoneHash = qs(data.vphone_code_hash());
|
||||
if (const auto nextType = data.vnext_type()) {
|
||||
if (nextType->type() == mtpc_auth_codeTypeCall) {
|
||||
_call.setStatus({ SentCodeCall::State::Waiting, data.vtimeout().value_or(60) });
|
||||
}
|
||||
}
|
||||
launch();
|
||||
});
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::sendCodeFail(const MTP::Error &error) {
|
||||
auto errorText = Lang::Hard::ServerError();
|
||||
if (MTP::IsFloodError(error)) {
|
||||
errorText = tr::lng_flood_error(tr::now);
|
||||
} else if (error.code() == 400) {
|
||||
errorText = tr::lng_confirm_phone_link_invalid(tr::now);
|
||||
}
|
||||
_sendCodeRequestId = 0;
|
||||
Ui::show(Box<InformBox>(errorText));
|
||||
if (this == CurrentConfirmPhoneBox) {
|
||||
CurrentConfirmPhoneBox.destroyDelayed();
|
||||
} else {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::launch() {
|
||||
if (!CurrentConfirmPhoneBox) return;
|
||||
Ui::show(std::move(CurrentConfirmPhoneBox));
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::prepare() {
|
||||
_about.create(
|
||||
this,
|
||||
tr::lng_confirm_phone_about(
|
||||
lt_phone,
|
||||
rpl::single(Ui::Text::Bold(Ui::FormatPhone(_phone))),
|
||||
Ui::Text::WithEntities),
|
||||
st::confirmPhoneAboutLabel);
|
||||
|
||||
_code.create(this, st::confirmPhoneCodeField, tr::lng_code_ph());
|
||||
_code->setAutoSubmit(_sentCodeLength, [=] { sendCode(); });
|
||||
_code->setChangedCallback([=] { showError(QString()); });
|
||||
|
||||
setTitle(tr::lng_confirm_phone_title());
|
||||
|
||||
addButton(tr::lng_confirm_phone_send(), [=] { sendCode(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWidth, st::usernamePadding.top() + _code->height() + st::usernameSkip + _about->height() + st::usernameSkip);
|
||||
|
||||
connect(_code, &Ui::InputField::submitted, [=] { sendCode(); });
|
||||
|
||||
showChildren();
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::callDone(const MTPauth_SentCode &result) {
|
||||
_call.callDone();
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::sendCode() {
|
||||
if (_sendCodeRequestId) {
|
||||
return;
|
||||
}
|
||||
const auto code = _code->getDigitsOnly();
|
||||
if (code.isEmpty()) {
|
||||
_code->showError();
|
||||
return;
|
||||
}
|
||||
|
||||
_code->setDisabled(true);
|
||||
setFocus();
|
||||
|
||||
showError(QString());
|
||||
|
||||
_sendCodeRequestId = _api.request(MTPaccount_ConfirmPhone(
|
||||
MTP_string(_phoneHash),
|
||||
MTP_string(code)
|
||||
)).done([=](const MTPBool &result) {
|
||||
confirmDone(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
confirmFail(error);
|
||||
}).handleFloodErrors().send();
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::confirmDone(const MTPBool &result) {
|
||||
_sendCodeRequestId = 0;
|
||||
Ui::show(Box<InformBox>(tr::lng_confirm_phone_success(tr::now, lt_phone, Ui::FormatPhone(_phone))));
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::confirmFail(const MTP::Error &error) {
|
||||
auto errorText = Lang::Hard::ServerError();
|
||||
if (MTP::IsFloodError(error)) {
|
||||
errorText = tr::lng_flood_error(tr::now);
|
||||
} else {
|
||||
auto &errorType = error.type();
|
||||
if (errorType == qstr("PHONE_CODE_EMPTY") || errorType == qstr("PHONE_CODE_INVALID")) {
|
||||
errorText = tr::lng_bad_code(tr::now);
|
||||
}
|
||||
}
|
||||
_sendCodeRequestId = 0;
|
||||
_code->setDisabled(false);
|
||||
_code->setFocus();
|
||||
showError(errorText);
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::showError(const QString &error) {
|
||||
_error = error;
|
||||
if (!_error.isEmpty()) {
|
||||
_code->showError();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
p.setFont(st::boxTextFont);
|
||||
auto callText = _call.getText();
|
||||
if (!callText.isEmpty()) {
|
||||
p.setPen(st::usernameDefaultFg);
|
||||
auto callTextRectLeft = st::usernamePadding.left();
|
||||
auto callTextRectTop = _about->y() + _about->height();
|
||||
auto callTextRectWidth = width() - 2 * st::usernamePadding.left();
|
||||
auto callTextRect = QRect(callTextRectLeft, callTextRectTop, callTextRectWidth, st::usernameSkip);
|
||||
p.drawText(callTextRect, callText, style::al_left);
|
||||
}
|
||||
auto errorText = _error;
|
||||
if (errorText.isEmpty()) {
|
||||
p.setPen(st::usernameDefaultFg);
|
||||
errorText = tr::lng_confirm_phone_enter_code(tr::now);
|
||||
} else {
|
||||
p.setPen(st::boxTextFgError);
|
||||
}
|
||||
auto errorTextRectLeft = st::usernamePadding.left();
|
||||
auto errorTextRectTop = _code->y() + _code->height();
|
||||
auto errorTextRectWidth = width() - 2 * st::usernamePadding.left();
|
||||
auto errorTextRect = QRect(errorTextRectLeft, errorTextRectTop, errorTextRectWidth, st::usernameSkip);
|
||||
p.drawText(errorTextRect, errorText, style::al_left);
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_code->resize(width() - st::usernamePadding.left() - st::usernamePadding.right(), _code->height());
|
||||
_code->moveToLeft(st::usernamePadding.left(), st::usernamePadding.top());
|
||||
|
||||
_about->moveToLeft(st::usernamePadding.left(), _code->y() + _code->height() + st::usernameSkip);
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::setInnerFocus() {
|
||||
_code->setFocusFast();
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
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 "boxes/abstract_box.h"
|
||||
#include "base/timer.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Ui {
|
||||
class InputField;
|
||||
class FlatLabel;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
void ShowPhoneBannedError(const QString &phone);
|
||||
|
||||
class SentCodeField : public Ui::InputField {
|
||||
public:
|
||||
SentCodeField(
|
||||
QWidget *parent,
|
||||
const style::InputField &st,
|
||||
rpl::producer<QString> placeholder = nullptr,
|
||||
const QString &val = QString());
|
||||
|
||||
void setAutoSubmit(int length, Fn<void()> submitCallback);
|
||||
void setChangedCallback(Fn<void()> changedCallback);
|
||||
QString getDigitsOnly() const;
|
||||
|
||||
private:
|
||||
void fix();
|
||||
|
||||
// Flag for not calling onTextChanged() recursively.
|
||||
bool _fixing = false;
|
||||
|
||||
int _autoSubmitLength = 0;
|
||||
Fn<void()> _submitCallback;
|
||||
Fn<void()> _changedCallback;
|
||||
|
||||
};
|
||||
|
||||
class SentCodeCall {
|
||||
public:
|
||||
SentCodeCall(
|
||||
FnMut<void()> callCallback,
|
||||
Fn<void()> updateCallback);
|
||||
|
||||
enum class State {
|
||||
Waiting,
|
||||
Calling,
|
||||
Called,
|
||||
Disabled,
|
||||
};
|
||||
struct Status {
|
||||
Status() {
|
||||
}
|
||||
Status(State state, int timeout) : state(state), timeout(timeout) {
|
||||
}
|
||||
|
||||
State state = State::Disabled;
|
||||
int timeout = 0;
|
||||
};
|
||||
void setStatus(const Status &status);
|
||||
|
||||
void callDone() {
|
||||
if (_status.state == State::Calling) {
|
||||
_status.state = State::Called;
|
||||
if (_update) {
|
||||
_update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString getText() const;
|
||||
|
||||
private:
|
||||
Status _status;
|
||||
base::Timer _timer;
|
||||
FnMut<void()> _call;
|
||||
Fn<void()> _update;
|
||||
|
||||
};
|
||||
|
||||
class ConfirmPhoneBox final : public Ui::BoxContent {
|
||||
public:
|
||||
static void Start(
|
||||
not_null<Main::Session*> session,
|
||||
const QString &phone,
|
||||
const QString &hash);
|
||||
|
||||
[[nodiscard]] Main::Session &session() const {
|
||||
return *_session;
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
void setInnerFocus() override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
ConfirmPhoneBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
const QString &phone,
|
||||
const QString &hash);
|
||||
friend class object_ptr<ConfirmPhoneBox>;
|
||||
|
||||
void sendCode();
|
||||
void sendCall();
|
||||
void checkPhoneAndHash();
|
||||
|
||||
void sendCodeDone(const MTPauth_SentCode &result);
|
||||
void sendCodeFail(const MTP::Error &error);
|
||||
|
||||
void callDone(const MTPauth_SentCode &result);
|
||||
|
||||
void confirmDone(const MTPBool &result);
|
||||
void confirmFail(const MTP::Error &error);
|
||||
|
||||
QString getPhone() const {
|
||||
return _phone;
|
||||
}
|
||||
void launch();
|
||||
|
||||
void showError(const QString &error);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _sendCodeRequestId = 0;
|
||||
|
||||
// _hash from the link for account.sendConfirmPhoneCode call.
|
||||
// _phoneHash from auth.sentCode for account.confirmPhone call.
|
||||
QString _phone, _hash;
|
||||
QString _phoneHash;
|
||||
|
||||
// If we receive the code length, we autosubmit _code field when enough symbols is typed.
|
||||
int _sentCodeLength = 0;
|
||||
|
||||
mtpRequestId _checkCodeRequestId = 0;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _about = { nullptr };
|
||||
object_ptr<SentCodeField> _code = { nullptr };
|
||||
|
||||
QString _error;
|
||||
SentCodeCall _call;
|
||||
|
||||
};
|
||||
@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/connection_box.h"
|
||||
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "base/qthelp_url.h"
|
||||
@@ -74,7 +74,7 @@ void HostInput::correctValue(
|
||||
QString newText;
|
||||
int newCursor = nowCursor;
|
||||
newText.reserve(now.size());
|
||||
for (auto i = 0, l = now.size(); i < l; ++i) {
|
||||
for (auto i = 0, l = int(now.size()); i < l; ++i) {
|
||||
if (now[i] == ',') {
|
||||
newText.append('.');
|
||||
} else {
|
||||
@@ -120,7 +120,7 @@ void Base64UrlInput::correctValue(
|
||||
QString newText;
|
||||
newText.reserve(now.size());
|
||||
auto newPos = nowCursor;
|
||||
for (auto i = 0, l = now.size(); i < l; ++i) {
|
||||
for (auto i = 0, l = int(now.size()); i < l; ++i) {
|
||||
const auto ch = now[i];
|
||||
if ((ch >= '0' && ch <= '9')
|
||||
|| (ch >= 'a' && ch <= 'z')
|
||||
@@ -537,8 +537,8 @@ void ProxyRow::showMenu() {
|
||||
_deleteClicks.fire({});
|
||||
});
|
||||
}
|
||||
const auto parentTopLeft = window()->mapToGlobal({ 0, 0 });
|
||||
const auto buttonTopLeft = _menuToggle->mapToGlobal({ 0, 0 });
|
||||
const auto parentTopLeft = window()->mapToGlobal(QPoint());
|
||||
const auto buttonTopLeft = _menuToggle->mapToGlobal(QPoint());
|
||||
const auto parent = QRect(parentTopLeft, window()->size());
|
||||
const auto button = QRect(buttonTopLeft, _menuToggle->size());
|
||||
const auto bottom = button.y()
|
||||
@@ -1131,13 +1131,13 @@ void ProxiesBoxController::ShowApplyConfirmation(
|
||||
close();
|
||||
};
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
text,
|
||||
tr::lng_sure_enable(tr::now),
|
||||
std::move(callback)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
} else {
|
||||
Ui::show(Box<InformBox>(
|
||||
Ui::show(Box<Ui::InformBox>(
|
||||
(proxy.status() == ProxyData::Status::Unsupported
|
||||
? tr::lng_proxy_unsupported(tr::now)
|
||||
: tr::lng_proxy_invalid(tr::now))));
|
||||
|
||||
@@ -30,7 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/unique_qptr.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "base/random.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -885,7 +885,7 @@ not_null<Ui::InputField*> CreatePollBox::setupSolution(
|
||||
object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
||||
using namespace Settings;
|
||||
|
||||
const auto id = openssl::RandomValue<uint64>();
|
||||
const auto id = base::RandomValue<uint64>();
|
||||
const auto error = lifetime().make_state<Errors>(Error::Question);
|
||||
|
||||
auto result = object_ptr<Ui::VerticalLayout>(this);
|
||||
|
||||
459
Telegram/SourceFiles/boxes/delete_messages_box.cpp
Normal file
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
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 "boxes/delete_messages_box.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/view/controls/history_view_ttl_button.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "facades.h" // Ui::showChatsList
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
DeleteMessagesBox::DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<HistoryItem*> item,
|
||||
bool suggestModerateActions)
|
||||
: _session(&item->history()->session())
|
||||
, _ids(1, item->fullId()) {
|
||||
if (suggestModerateActions) {
|
||||
_moderateBan = item->suggestBanReport();
|
||||
_moderateDeleteAll = item->suggestDeleteAllReport();
|
||||
if (_moderateBan || _moderateDeleteAll) {
|
||||
_moderateFrom = item->from()->asUser();
|
||||
_moderateInChannel = item->history()->peer->asChannel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeleteMessagesBox::DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
MessageIdsList &&selected)
|
||||
: _session(session)
|
||||
, _ids(std::move(selected)) {
|
||||
Expects(!_ids.empty());
|
||||
}
|
||||
|
||||
DeleteMessagesBox::DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
bool justClear)
|
||||
: _session(&peer->session())
|
||||
, _wipeHistoryPeer(peer)
|
||||
, _wipeHistoryJustClear(justClear) {
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::prepare() {
|
||||
auto details = TextWithEntities();
|
||||
const auto appendDetails = [&](TextWithEntities &&text) {
|
||||
details.append(qstr("\n\n")).append(std::move(text));
|
||||
};
|
||||
auto deleteText = lifetime().make_state<rpl::variable<QString>>();
|
||||
*deleteText = tr::lng_box_delete();
|
||||
auto deleteStyle = &st::defaultBoxButton;
|
||||
auto canDelete = true;
|
||||
if (const auto peer = _wipeHistoryPeer) {
|
||||
if (_wipeHistoryJustClear) {
|
||||
const auto isChannel = peer->isBroadcast();
|
||||
const auto isPublicGroup = peer->isMegagroup()
|
||||
&& peer->asChannel()->isPublic();
|
||||
if (isChannel || isPublicGroup) {
|
||||
canDelete = false;
|
||||
}
|
||||
details.text = isChannel
|
||||
? tr::lng_no_clear_history_channel(tr::now)
|
||||
: isPublicGroup
|
||||
? tr::lng_no_clear_history_group(tr::now)
|
||||
: peer->isSelf()
|
||||
? tr::lng_sure_delete_saved_messages(tr::now)
|
||||
: peer->isUser()
|
||||
? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name)
|
||||
: tr::lng_sure_delete_group_history(
|
||||
tr::now,
|
||||
lt_group,
|
||||
peer->name);
|
||||
deleteStyle = &st::attentionBoxButton;
|
||||
} else {
|
||||
details.text = peer->isSelf()
|
||||
? tr::lng_sure_delete_saved_messages(tr::now)
|
||||
: peer->isUser()
|
||||
? tr::lng_sure_delete_history(tr::now, lt_contact, peer->name)
|
||||
: peer->isChat()
|
||||
? tr::lng_sure_delete_and_exit(tr::now, lt_group, peer->name)
|
||||
: peer->isMegagroup()
|
||||
? tr::lng_sure_leave_group(tr::now)
|
||||
: tr::lng_sure_leave_channel(tr::now);
|
||||
if (!peer->isUser()) {
|
||||
*deleteText = tr::lng_box_leave();
|
||||
}
|
||||
deleteStyle = &st::attentionBoxButton;
|
||||
}
|
||||
if (auto revoke = revokeText(peer)) {
|
||||
_revoke.create(
|
||||
this,
|
||||
revoke->checkbox,
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
appendDetails(std::move(revoke->description));
|
||||
if (!peer->isUser() && !_wipeHistoryJustClear) {
|
||||
_revoke->checkedValue(
|
||||
) | rpl::start_with_next([=](bool revokeForAll) {
|
||||
*deleteText = revokeForAll
|
||||
? tr::lng_box_delete()
|
||||
: tr::lng_box_leave();
|
||||
}, _revoke->lifetime());
|
||||
}
|
||||
}
|
||||
} else if (_moderateFrom) {
|
||||
Assert(_moderateInChannel != nullptr);
|
||||
|
||||
details.text = tr::lng_selected_delete_sure_this(tr::now);
|
||||
if (_moderateBan) {
|
||||
_banUser.create(
|
||||
this,
|
||||
tr::lng_ban_user(tr::now),
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
}
|
||||
_reportSpam.create(
|
||||
this,
|
||||
tr::lng_report_spam(tr::now),
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
if (_moderateDeleteAll) {
|
||||
_deleteAll.create(
|
||||
this,
|
||||
tr::lng_delete_all_from(tr::now),
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
}
|
||||
} else {
|
||||
details.text = (_ids.size() == 1)
|
||||
? tr::lng_selected_delete_sure_this(tr::now)
|
||||
: tr::lng_selected_delete_sure(tr::now, lt_count, _ids.size());
|
||||
if (const auto peer = checkFromSinglePeer()) {
|
||||
auto count = int(_ids.size());
|
||||
if (hasScheduledMessages()) {
|
||||
} else if (auto revoke = revokeText(peer)) {
|
||||
_revoke.create(
|
||||
this,
|
||||
revoke->checkbox,
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
appendDetails(std::move(revoke->description));
|
||||
} else if (peer->isChannel()) {
|
||||
if (peer->isMegagroup()) {
|
||||
appendDetails({
|
||||
tr::lng_delete_for_everyone_hint(
|
||||
tr::now,
|
||||
lt_count,
|
||||
count)
|
||||
});
|
||||
}
|
||||
} else if (peer->isChat()) {
|
||||
appendDetails({
|
||||
tr::lng_delete_for_me_chat_hint(tr::now, lt_count, count)
|
||||
});
|
||||
} else if (!peer->isSelf()) {
|
||||
appendDetails({
|
||||
tr::lng_delete_for_me_hint(tr::now, lt_count, count)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
_text.create(this, rpl::single(std::move(details)), st::boxLabel);
|
||||
|
||||
if (_wipeHistoryJustClear
|
||||
&& _wipeHistoryPeer
|
||||
&& ((_wipeHistoryPeer->isUser()
|
||||
&& !_wipeHistoryPeer->isSelf()
|
||||
&& !_wipeHistoryPeer->isNotificationsUser())
|
||||
|| (_wipeHistoryPeer->isChat()
|
||||
&& _wipeHistoryPeer->asChat()->canDeleteMessages())
|
||||
|| (_wipeHistoryPeer->isChannel()
|
||||
&& _wipeHistoryPeer->asChannel()->canDeleteMessages()))) {
|
||||
_wipeHistoryPeer->updateFull();
|
||||
_autoDeleteSettings.create(
|
||||
this,
|
||||
(_wipeHistoryPeer->messagesTTL()
|
||||
? tr::lng_edit_auto_delete_settings(tr::now)
|
||||
: tr::lng_enable_auto_delete(tr::now)),
|
||||
st::boxLinkButton);
|
||||
_autoDeleteSettings->setClickedCallback([=] {
|
||||
getDelegate()->show(
|
||||
Box(
|
||||
HistoryView::Controls::AutoDeleteSettingsBox,
|
||||
_wipeHistoryPeer),
|
||||
Ui::LayerOption(0));
|
||||
});
|
||||
}
|
||||
|
||||
if (canDelete) {
|
||||
addButton(
|
||||
deleteText->value(),
|
||||
[=] { deleteAndClear(); },
|
||||
*deleteStyle);
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
} else {
|
||||
addButton(tr::lng_about_done(), [=] { closeBox(); });
|
||||
}
|
||||
|
||||
auto fullHeight = st::boxPadding.top()
|
||||
+ _text->height()
|
||||
+ st::boxPadding.bottom();
|
||||
if (_moderateFrom) {
|
||||
fullHeight += st::boxMediumSkip;
|
||||
if (_banUser) {
|
||||
fullHeight += _banUser->heightNoMargins() + st::boxLittleSkip;
|
||||
}
|
||||
fullHeight += _reportSpam->heightNoMargins();
|
||||
if (_deleteAll) {
|
||||
fullHeight += st::boxLittleSkip + _deleteAll->heightNoMargins();
|
||||
}
|
||||
} else if (_revoke) {
|
||||
fullHeight += st::boxMediumSkip + _revoke->heightNoMargins();
|
||||
}
|
||||
if (_autoDeleteSettings) {
|
||||
fullHeight += st::boxMediumSkip
|
||||
+ _autoDeleteSettings->height()
|
||||
+ st::boxLittleSkip;
|
||||
}
|
||||
setDimensions(st::boxWidth, fullHeight);
|
||||
}
|
||||
|
||||
bool DeleteMessagesBox::hasScheduledMessages() const {
|
||||
for (const auto &fullId : _ids) {
|
||||
if (const auto item = _session->data().message(fullId)) {
|
||||
if (item->isScheduled()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
|
||||
auto result = (PeerData*)nullptr;
|
||||
for (const auto &fullId : _ids) {
|
||||
if (const auto item = _session->data().message(fullId)) {
|
||||
const auto peer = item->history()->peer;
|
||||
if (!result) {
|
||||
result = peer;
|
||||
} else if (result != peer) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
|
||||
-> std::optional<RevokeConfig> {
|
||||
auto result = RevokeConfig();
|
||||
if (peer == _wipeHistoryPeer) {
|
||||
if (!peer->canRevokeFullHistory()) {
|
||||
return std::nullopt;
|
||||
} else if (const auto user = peer->asUser()) {
|
||||
result.checkbox = tr::lng_delete_for_other_check(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->firstName);
|
||||
} else if (_wipeHistoryJustClear) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
result.checkbox = tr::lng_delete_for_everyone_check(tr::now);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto items = ranges::views::all(
|
||||
_ids
|
||||
) | ranges::views::transform([&](FullMsgId id) {
|
||||
return peer->owner().message(id);
|
||||
}) | ranges::views::filter([](HistoryItem *item) {
|
||||
return (item != nullptr);
|
||||
}) | ranges::to_vector;
|
||||
|
||||
if (items.size() != _ids.size()) {
|
||||
// We don't have information about all messages.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto now = base::unixtime::now();
|
||||
const auto canRevoke = [&](HistoryItem * item) {
|
||||
return item->canDeleteForEveryone(now);
|
||||
};
|
||||
const auto cannotRevoke = [&](HistoryItem *item) {
|
||||
return !item->canDeleteForEveryone(now);
|
||||
};
|
||||
const auto canRevokeAll = ranges::none_of(items, cannotRevoke);
|
||||
auto outgoing = items | ranges::views::filter(&HistoryItem::out);
|
||||
const auto canRevokeOutgoingCount = canRevokeAll
|
||||
? -1
|
||||
: ranges::count_if(outgoing, canRevoke);
|
||||
|
||||
if (canRevokeAll) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
result.checkbox = tr::lng_delete_for_other_check(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->firstName);
|
||||
} else {
|
||||
result.checkbox = tr::lng_delete_for_everyone_check(tr::now);
|
||||
}
|
||||
return result;
|
||||
} else if (canRevokeOutgoingCount > 0) {
|
||||
result.checkbox = tr::lng_delete_for_other_my(tr::now);
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (canRevokeOutgoingCount == 1) {
|
||||
result.description = tr::lng_selected_unsend_about_user_one(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(user->shortName()),
|
||||
Ui::Text::WithEntities);
|
||||
} else {
|
||||
result.description = tr::lng_selected_unsend_about_user(
|
||||
tr::now,
|
||||
lt_count,
|
||||
canRevokeOutgoingCount,
|
||||
lt_user,
|
||||
Ui::Text::Bold(user->shortName()),
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
} else if (canRevokeOutgoingCount == 1) {
|
||||
result.description = tr::lng_selected_unsend_about_group_one(
|
||||
tr::now,
|
||||
Ui::Text::WithEntities);
|
||||
} else {
|
||||
result.description = tr::lng_selected_unsend_about_group(
|
||||
tr::now,
|
||||
lt_count,
|
||||
canRevokeOutgoingCount,
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
|
||||
auto top = _text->bottomNoMargins() + st::boxMediumSkip;
|
||||
if (_moderateFrom) {
|
||||
if (_banUser) {
|
||||
_banUser->moveToLeft(st::boxPadding.left(), top);
|
||||
top += _banUser->heightNoMargins() + st::boxLittleSkip;
|
||||
}
|
||||
_reportSpam->moveToLeft(st::boxPadding.left(), top);
|
||||
top += _reportSpam->heightNoMargins() + st::boxLittleSkip;
|
||||
if (_deleteAll) {
|
||||
_deleteAll->moveToLeft(st::boxPadding.left(), top);
|
||||
top += _deleteAll->heightNoMargins() + st::boxLittleSkip;
|
||||
}
|
||||
} else if (_revoke) {
|
||||
const auto availableWidth = width() - 2 * st::boxPadding.left();
|
||||
_revoke->resizeToNaturalWidth(availableWidth);
|
||||
_revoke->moveToLeft(st::boxPadding.left(), top);
|
||||
top += _revoke->heightNoMargins() + st::boxLittleSkip;
|
||||
}
|
||||
if (_autoDeleteSettings) {
|
||||
top += st::boxMediumSkip - st::boxLittleSkip;
|
||||
_autoDeleteSettings->moveToLeft(st::boxPadding.left(), top);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
// Don't make the clearing history so easy.
|
||||
if (!_wipeHistoryPeer) {
|
||||
deleteAndClear();
|
||||
}
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::deleteAndClear() {
|
||||
const auto revoke = _revoke ? _revoke->checked() : false;
|
||||
if (const auto peer = _wipeHistoryPeer) {
|
||||
const auto justClear = _wipeHistoryJustClear;
|
||||
closeBox();
|
||||
|
||||
if (justClear) {
|
||||
peer->session().api().clearHistory(peer, revoke);
|
||||
} else {
|
||||
for (const auto &controller : peer->session().windows()) {
|
||||
if (controller->activeChatCurrent().peer() == peer) {
|
||||
Ui::showChatsList(&peer->session());
|
||||
}
|
||||
}
|
||||
// Don't delete old history by default,
|
||||
// because Android app doesn't.
|
||||
//
|
||||
//if (const auto from = peer->migrateFrom()) {
|
||||
// peer->session().api().deleteConversation(from, false);
|
||||
//}
|
||||
peer->session().api().deleteConversation(peer, revoke);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_moderateFrom) {
|
||||
if (_banUser && _banUser->checked()) {
|
||||
_moderateInChannel->session().api().kickParticipant(
|
||||
_moderateInChannel,
|
||||
_moderateFrom,
|
||||
ChatRestrictionsInfo());
|
||||
}
|
||||
if (_reportSpam->checked()) {
|
||||
_moderateInChannel->session().api().request(
|
||||
MTPchannels_ReportSpam(
|
||||
_moderateInChannel->inputChannel,
|
||||
_moderateFrom->inputUser,
|
||||
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg)))
|
||||
).send();
|
||||
}
|
||||
if (_deleteAll && _deleteAll->checked()) {
|
||||
_moderateInChannel->session().api().deleteAllFromUser(
|
||||
_moderateInChannel,
|
||||
_moderateFrom);
|
||||
}
|
||||
}
|
||||
|
||||
if (_deleteConfirmedCallback) {
|
||||
_deleteConfirmedCallback();
|
||||
}
|
||||
|
||||
// deleteMessages can initiate closing of the current section,
|
||||
// which will cause this box to be destroyed.
|
||||
const auto session = _session;
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
|
||||
session->data().histories().deleteMessages(_ids, revoke);
|
||||
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
session->data().sendHistoryChangeNotifications();
|
||||
}
|
||||
74
Telegram/SourceFiles/boxes/delete_messages_box.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
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 "boxes/abstract_box.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class Checkbox;
|
||||
class FlatLabel;
|
||||
class LinkButton;
|
||||
} // namespace Ui
|
||||
|
||||
class DeleteMessagesBox final : public Ui::BoxContent {
|
||||
public:
|
||||
DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<HistoryItem*> item,
|
||||
bool suggestModerateActions);
|
||||
DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
MessageIdsList &&selected);
|
||||
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool justClear);
|
||||
|
||||
void setDeleteConfirmedCallback(Fn<void()> callback) {
|
||||
_deleteConfirmedCallback = std::move(callback);
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
struct RevokeConfig {
|
||||
QString checkbox;
|
||||
TextWithEntities description;
|
||||
};
|
||||
void deleteAndClear();
|
||||
[[nodiscard]] PeerData *checkFromSinglePeer() const;
|
||||
[[nodiscard]] bool hasScheduledMessages() const;
|
||||
[[nodiscard]] std::optional<RevokeConfig> revokeText(
|
||||
not_null<PeerData*> peer) const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
PeerData * const _wipeHistoryPeer = nullptr;
|
||||
const bool _wipeHistoryJustClear = false;
|
||||
const MessageIdsList _ids;
|
||||
UserData *_moderateFrom = nullptr;
|
||||
ChannelData *_moderateInChannel = nullptr;
|
||||
bool _moderateBan = false;
|
||||
bool _moderateDeleteAll = false;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _text = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _revoke = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _banUser = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _reportSpam = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _deleteAll = { nullptr };
|
||||
object_ptr<Ui::LinkButton> _autoDeleteSettings = { nullptr };
|
||||
|
||||
Fn<void()> _deleteConfirmedCallback;
|
||||
|
||||
};
|
||||
@@ -39,11 +39,6 @@ using DictState = BlobState;
|
||||
using QueryCallback = Fn<void(const QString &)>;
|
||||
constexpr auto kMaxQueryLength = 15;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||
#define OLD_QT
|
||||
using QStringView = QString;
|
||||
#endif
|
||||
|
||||
class Inner : public Ui::RpWidget {
|
||||
public:
|
||||
Inner(
|
||||
|
||||
@@ -22,7 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "core/application.h"
|
||||
@@ -478,7 +478,7 @@ void Rows::showMenu(int index) {
|
||||
}
|
||||
}
|
||||
const auto toggle = menuToggleArea(row);
|
||||
const auto parentTopLeft = window()->mapToGlobal({ 0, 0 });
|
||||
const auto parentTopLeft = window()->mapToGlobal(QPoint());
|
||||
const auto buttonTopLeft = mapToGlobal(toggle.topLeft());
|
||||
const auto parent = QRect(parentTopLeft, window()->size());
|
||||
const auto button = QRect(buttonTopLeft, toggle.size());
|
||||
|
||||
148
Telegram/SourceFiles/boxes/max_invite_box.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
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 "boxes/max_invite_box.h"
|
||||
|
||||
#include "api/api_invite_links.h"
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
namespace {
|
||||
|
||||
TextParseOptions kInformBoxTextOptions = {
|
||||
(TextParseLinks
|
||||
| TextParseMultiline
|
||||
| TextParseMarkdown
|
||||
| TextParseRichText), // flags
|
||||
0, // maxw
|
||||
0, // maxh
|
||||
Qt::LayoutDirectionAuto, // dir
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
MaxInviteBox::MaxInviteBox(QWidget*, not_null<ChannelData*> channel)
|
||||
: BoxContent()
|
||||
, _channel(channel)
|
||||
, _text(
|
||||
st::boxLabelStyle,
|
||||
tr::lng_participant_invite_sorry(
|
||||
tr::now,
|
||||
lt_count,
|
||||
channel->session().serverConfig().chatSizeMax),
|
||||
kInformBoxTextOptions,
|
||||
(st::boxWidth
|
||||
- st::boxPadding.left()
|
||||
- st::defaultBox.buttonPadding.right())) {
|
||||
}
|
||||
|
||||
void MaxInviteBox::prepare() {
|
||||
setMouseTracking(true);
|
||||
|
||||
addButton(tr::lng_box_ok(), [=] { closeBox(); });
|
||||
|
||||
_textWidth = st::boxWidth
|
||||
- st::boxPadding.left()
|
||||
- st::defaultBox.buttonPadding.right();
|
||||
_textHeight = std::min(
|
||||
_text.countHeight(_textWidth),
|
||||
16 * st::boxLabelStyle.lineHeight);
|
||||
setDimensions(
|
||||
st::boxWidth,
|
||||
st::boxPadding.top()
|
||||
+ _textHeight
|
||||
+ st::boxTextFont->height
|
||||
+ st::boxTextFont->height * 2
|
||||
+ st::newGroupLinkPadding.bottom());
|
||||
|
||||
_channel->session().changes().peerUpdates(
|
||||
_channel,
|
||||
Data::PeerUpdate::Flag::InviteLinks
|
||||
) | rpl::start_with_next([=] {
|
||||
rtlupdate(_invitationLink);
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
|
||||
updateSelected(e->globalPos());
|
||||
}
|
||||
|
||||
void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
|
||||
mouseMoveEvent(e);
|
||||
if (_linkOver) {
|
||||
if (_channel->inviteLink().isEmpty()) {
|
||||
_channel->session().api().inviteLinks().create(_channel);
|
||||
} else {
|
||||
QGuiApplication::clipboard()->setText(_channel->inviteLink());
|
||||
Ui::Toast::Show(tr::lng_create_channel_link_copied(tr::now));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaxInviteBox::leaveEventHook(QEvent *e) {
|
||||
updateSelected(QCursor::pos());
|
||||
}
|
||||
|
||||
void MaxInviteBox::updateSelected(const QPoint &cursorGlobalPosition) {
|
||||
const auto p = QPoint(mapFromGlobal(cursorGlobalPosition));
|
||||
|
||||
const auto linkOver = _invitationLink.contains(p);
|
||||
if (linkOver != _linkOver) {
|
||||
_linkOver = linkOver;
|
||||
update();
|
||||
setCursor(_linkOver ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
}
|
||||
|
||||
void MaxInviteBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::boxTextFg);
|
||||
_text.drawLeftElided(
|
||||
p,
|
||||
st::boxPadding.left(),
|
||||
st::boxPadding.top(),
|
||||
_textWidth,
|
||||
width(),
|
||||
16,
|
||||
style::al_left);
|
||||
|
||||
auto option = QTextOption(style::al_left);
|
||||
option.setWrapMode(QTextOption::WrapAnywhere);
|
||||
p.setFont(_linkOver
|
||||
? st::defaultInputField.font->underline()
|
||||
: st::defaultInputField.font);
|
||||
p.setPen(st::defaultLinkButton.color);
|
||||
const auto inviteLinkText = _channel->inviteLink().isEmpty()
|
||||
? tr::lng_group_invite_create(tr::now)
|
||||
: _channel->inviteLink();
|
||||
p.drawText(_invitationLink, inviteLinkText, option);
|
||||
}
|
||||
|
||||
void MaxInviteBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
_invitationLink = myrtlrect(
|
||||
st::boxPadding.left(),
|
||||
st::boxPadding.top() + _textHeight + st::boxTextFont->height,
|
||||
width() - st::boxPadding.left() - st::boxPadding.right(),
|
||||
2 * st::boxTextFont->height);
|
||||
}
|
||||
38
Telegram/SourceFiles/boxes/max_invite_box.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
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 "boxes/abstract_box.h"
|
||||
|
||||
class MaxInviteBox final : public Ui::BoxContent {
|
||||
public:
|
||||
MaxInviteBox(QWidget*, not_null<ChannelData*> channel);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
||||
private:
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
|
||||
not_null<ChannelData*> _channel;
|
||||
|
||||
Ui::Text::String _text;
|
||||
int32 _textWidth, _textHeight;
|
||||
|
||||
QRect _invitationLink;
|
||||
bool _linkOver = false;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
};
|
||||
@@ -9,8 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "base/bytes.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/confirm_phone_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
@@ -24,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/sent_code_field.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "passport/passport_encryption.h"
|
||||
@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_passport.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "base/qt_adapters.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -107,7 +108,7 @@ void StartPendingReset(
|
||||
auto finish = [=](const QString &message) mutable {
|
||||
if (const auto strong = weak.data()) {
|
||||
if (!message.isEmpty()) {
|
||||
strong->getDelegate()->show(Box<InformBox>(message));
|
||||
strong->getDelegate()->show(Box<Ui::InformBox>(message));
|
||||
}
|
||||
strong->closeBox();
|
||||
}
|
||||
@@ -138,7 +139,7 @@ void StartPendingReset(
|
||||
lt_count,
|
||||
minutes);
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->getDelegate()->show(Box<InformBox>(
|
||||
strong->getDelegate()->show(Box<Ui::InformBox>(
|
||||
tr::lng_cloud_password_reset_later(
|
||||
tr::now,
|
||||
lt_duration,
|
||||
@@ -440,7 +441,7 @@ void PasscodeBox::recoverPasswordDone(
|
||||
if (weak) {
|
||||
_newPasswordSet.fire_copy(newPasswordBytes);
|
||||
if (weak) {
|
||||
getDelegate()->show(Box<InformBox>(
|
||||
getDelegate()->show(Box<Ui::InformBox>(
|
||||
tr::lng_cloud_password_updated(tr::now)));
|
||||
if (weak) {
|
||||
closeBox();
|
||||
@@ -462,7 +463,7 @@ void PasscodeBox::setPasswordDone(const QByteArray &newPasswordBytes) {
|
||||
: _oldPasscode->isHidden()
|
||||
? tr::lng_cloud_password_was_set(tr::now)
|
||||
: tr::lng_cloud_password_updated(tr::now);
|
||||
getDelegate()->show(Box<InformBox>(text));
|
||||
getDelegate()->show(Box<Ui::InformBox>(text));
|
||||
if (weak) {
|
||||
closeBox();
|
||||
}
|
||||
@@ -525,7 +526,7 @@ void PasscodeBox::setPasswordFail(
|
||||
const MTP::Error &error) {
|
||||
const auto prefix = qstr("EMAIL_UNCONFIRMED_");
|
||||
if (error.type().startsWith(prefix)) {
|
||||
const auto codeLength = error.type().midRef(prefix.size()).toInt();
|
||||
const auto codeLength = base::StringViewMid(error.type(), prefix.size()).toInt();
|
||||
|
||||
closeReplacedBy();
|
||||
_setRequest = 0;
|
||||
@@ -562,7 +563,7 @@ void PasscodeBox::validateEmail(
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
_clearUnconfirmedPassword.fire({});
|
||||
if (weak) {
|
||||
auto box = Box<InformBox>(
|
||||
auto box = Box<Ui::InformBox>(
|
||||
Lang::Hard::EmailConfirmationExpired());
|
||||
weak->getDelegate()->show(
|
||||
std::move(box),
|
||||
@@ -689,7 +690,7 @@ void PasscodeBox::save(bool force) {
|
||||
if (!onlyCheck && !_recoverEmail->isHidden() && email.isEmpty() && !force) {
|
||||
_skipEmailWarning = true;
|
||||
_replacedBy = getDelegate()->show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_cloud_password_about_recover(tr::now),
|
||||
tr::lng_cloud_password_skip_email(tr::now),
|
||||
st::attentionBoxButton,
|
||||
@@ -726,7 +727,7 @@ void PasscodeBox::submitOnlyCheckCloudPassword(const QString &oldPassword) {
|
||||
send();
|
||||
close();
|
||||
};
|
||||
getDelegate()->show(Box<ConfirmBox>(
|
||||
getDelegate()->show(Box<Ui::ConfirmBox>(
|
||||
tr::lng_cloud_password_passport_losing(tr::now),
|
||||
tr::lng_continue(tr::now),
|
||||
confirmed));
|
||||
@@ -797,7 +798,7 @@ void PasscodeBox::requestPasswordData() {
|
||||
}
|
||||
|
||||
void PasscodeBox::serverError() {
|
||||
getDelegate()->show(Box<InformBox>(Lang::Hard::ServerError()));
|
||||
getDelegate()->show(Box<Ui::InformBox>(Lang::Hard::ServerError()));
|
||||
closeBox();
|
||||
}
|
||||
|
||||
@@ -952,7 +953,7 @@ void PasscodeBox::suggestSecretReset(const QString &newPassword) {
|
||||
resetSecret(check, newPassword, std::move(close));
|
||||
});
|
||||
};
|
||||
getDelegate()->show(Box<ConfirmBox>(
|
||||
getDelegate()->show(Box<Ui::ConfirmBox>(
|
||||
Lang::Hard::PassportCorruptedChange(),
|
||||
Lang::Hard::PassportCorruptedReset(),
|
||||
std::move(resetSecretAndSave)));
|
||||
@@ -1085,7 +1086,7 @@ void PasscodeBox::recoverByEmail() {
|
||||
}
|
||||
});
|
||||
});
|
||||
*confirmBox = getDelegate()->show(Box<ConfirmBox>(
|
||||
*confirmBox = getDelegate()->show(Box<Ui::ConfirmBox>(
|
||||
tr::lng_cloud_password_reset_no_email(tr::now),
|
||||
tr::lng_cloud_password_reset_ok(tr::now),
|
||||
reset));
|
||||
@@ -1170,7 +1171,7 @@ RecoverBox::RecoverBox(
|
||||
}
|
||||
});
|
||||
});
|
||||
*confirmBox = getDelegate()->show(Box<ConfirmBox>(
|
||||
*confirmBox = getDelegate()->show(Box<Ui::ConfirmBox>(
|
||||
tr::lng_cloud_password_reset_with_email(tr::now),
|
||||
tr::lng_cloud_password_reset_ok(tr::now),
|
||||
reset));
|
||||
@@ -1272,7 +1273,7 @@ void RecoverBox::submit() {
|
||||
send();
|
||||
close();
|
||||
};
|
||||
getDelegate()->show(Box<ConfirmBox>(
|
||||
getDelegate()->show(Box<Ui::ConfirmBox>(
|
||||
tr::lng_cloud_password_passport_losing(tr::now),
|
||||
tr::lng_continue(tr::now),
|
||||
confirmed));
|
||||
@@ -1297,7 +1298,7 @@ void RecoverBox::proceedToClear() {
|
||||
_submitRequest = 0;
|
||||
_newPasswordSet.fire({});
|
||||
getDelegate()->show(
|
||||
Box<InformBox>(tr::lng_cloud_password_removed(tr::now)),
|
||||
Box<Ui::InformBox>(tr::lng_cloud_password_removed(tr::now)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
}
|
||||
|
||||
@@ -1345,7 +1346,7 @@ void RecoverBox::checkSubmitFail(const MTP::Error &error) {
|
||||
if (err == qstr("PASSWORD_EMPTY")) {
|
||||
_newPasswordSet.fire(QByteArray());
|
||||
getDelegate()->show(
|
||||
Box<InformBox>(tr::lng_cloud_password_removed(tr::now)),
|
||||
Box<Ui::InformBox>(tr::lng_cloud_password_removed(tr::now)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
} else if (err == qstr("PASSWORD_RECOVERY_NA")) {
|
||||
closeBox();
|
||||
@@ -1386,7 +1387,8 @@ RecoveryEmailValidation ConfirmRecoveryEmail(
|
||||
reloads->fire({});
|
||||
if (*weak) {
|
||||
(*weak)->getDelegate()->show(
|
||||
Box<InformBox>(tr::lng_cloud_password_was_set(tr::now)),
|
||||
Box<Ui::InformBox>(
|
||||
tr::lng_cloud_password_was_set(tr::now)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
@@ -1398,7 +1400,7 @@ RecoveryEmailValidation ConfirmRecoveryEmail(
|
||||
} else if (error.type() == qstr("EMAIL_HASH_EXPIRED")) {
|
||||
cancels->fire({});
|
||||
if (*weak) {
|
||||
auto box = Box<InformBox>(
|
||||
auto box = Box<Ui::InformBox>(
|
||||
Lang::Hard::EmailConfirmationExpired());
|
||||
(*weak)->getDelegate()->show(
|
||||
std::move(box),
|
||||
|
||||
@@ -1240,7 +1240,7 @@ int PeerListContent::resizeGetHeight(int newWidth) {
|
||||
return belowTop + _belowHeight;
|
||||
}
|
||||
|
||||
void PeerListContent::enterEventHook(QEvent *e) {
|
||||
void PeerListContent::enterEventHook(QEnterEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -622,7 +622,7 @@ protected:
|
||||
int visibleBottom) override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void enterEventHook(QEvent *e) override;
|
||||
void enterEventHook(QEnterEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
|
||||
@@ -7,8 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
|
||||
#include "base/openssl_help.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "base/random.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "main/main_session.h"
|
||||
@@ -36,7 +36,7 @@ void ShareBotGame(not_null<UserData*> bot, not_null<PeerData*> chat) {
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
const auto api = &chat->session().api();
|
||||
history->sendRequestId = api->request(MTPmessages_SendMedia(
|
||||
MTP_flags(0),
|
||||
@@ -482,7 +482,7 @@ void AddBotToGroupBoxController::shareBotGame(not_null<PeerData*> chat) {
|
||||
return tr::lng_bot_sure_share_game_group(tr::now, lt_group, chat->name);
|
||||
}();
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(confirmText, std::move(send)),
|
||||
Box<Ui::ConfirmBox>(confirmText, std::move(send)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
@@ -490,7 +490,7 @@ void AddBotToGroupBoxController::addBotToGroup(not_null<PeerData*> chat) {
|
||||
if (const auto megagroup = chat->asMegagroup()) {
|
||||
if (!megagroup->canAddMembers()) {
|
||||
Ui::show(
|
||||
Box<InformBox>(tr::lng_error_cant_add_member(tr::now)),
|
||||
Box<Ui::InformBox>(tr::lng_error_cant_add_member(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
@@ -500,7 +500,7 @@ void AddBotToGroupBoxController::addBotToGroup(not_null<PeerData*> chat) {
|
||||
});
|
||||
auto confirmText = tr::lng_bot_sure_invite(tr::now, lt_group, chat->name);
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(confirmText, send),
|
||||
Box<Ui::ConfirmBox>(confirmText, send),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/peers/edit_participant_box.h"
|
||||
#include "boxes/peers/edit_peer_type_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/max_invite_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
@@ -105,7 +106,8 @@ void AddParticipantsBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
} else if (count >= serverConfig.chatSizeMax
|
||||
&& count < serverConfig.megagroupSizeMax) {
|
||||
Ui::show(
|
||||
Box<InformBox>(tr::lng_profile_add_more_after_create(tr::now)),
|
||||
Box<Ui::InformBox>(
|
||||
tr::lng_profile_add_more_after_create(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
}
|
||||
@@ -565,20 +567,20 @@ void AddSpecialBoxController::showAdmin(
|
||||
if (canBanMembers) {
|
||||
if (!sure) {
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_sure_add_admin_unremove(tr::now),
|
||||
showAdminSure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Ui::show(Box<InformBox>(
|
||||
Ui::show(Box<Ui::InformBox>(
|
||||
tr::lng_error_cant_add_admin_unban(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Ui::show(Box<InformBox>(
|
||||
Ui::show(Box<Ui::InformBox>(
|
||||
tr::lng_error_cant_add_admin_invite(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
@@ -588,14 +590,14 @@ void AddSpecialBoxController::showAdmin(
|
||||
if (canBanMembers) {
|
||||
if (!sure) {
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_sure_add_admin_unremove(tr::now),
|
||||
showAdminSure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Ui::show(Box<InformBox>(
|
||||
Ui::show(Box<Ui::InformBox>(
|
||||
tr::lng_error_cant_add_admin_unban(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
@@ -608,7 +610,7 @@ void AddSpecialBoxController::showAdmin(
|
||||
? tr::lng_sure_add_admin_invite
|
||||
: tr::lng_sure_add_admin_invite_channel)(tr::now);
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
text,
|
||||
showAdminSure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
@@ -616,7 +618,8 @@ void AddSpecialBoxController::showAdmin(
|
||||
}
|
||||
} else {
|
||||
Ui::show(
|
||||
Box<InformBox>(tr::lng_error_cant_add_admin_invite(tr::now)),
|
||||
Box<Ui::InformBox>(
|
||||
tr::lng_error_cant_add_admin_invite(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
@@ -716,7 +719,7 @@ void AddSpecialBoxController::showRestricted(
|
||||
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
|
||||
if (!sure) {
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_sure_ban_admin(tr::now),
|
||||
showRestrictedSure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
@@ -724,7 +727,7 @@ void AddSpecialBoxController::showRestricted(
|
||||
}
|
||||
} else {
|
||||
Ui::show(
|
||||
Box<InformBox>(tr::lng_error_cant_ban_admin(tr::now)),
|
||||
Box<Ui::InformBox>(tr::lng_error_cant_ban_admin(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
@@ -813,7 +816,7 @@ void AddSpecialBoxController::kickUser(
|
||||
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
|
||||
if (!sure) {
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_sure_ban_admin(tr::now),
|
||||
kickUserSure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
@@ -821,7 +824,7 @@ void AddSpecialBoxController::kickUser(
|
||||
}
|
||||
} else {
|
||||
Ui::show(
|
||||
Box<InformBox>(tr::lng_error_cant_ban_admin(tr::now)),
|
||||
Box<Ui::InformBox>(tr::lng_error_cant_ban_admin(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
@@ -836,7 +839,7 @@ void AddSpecialBoxController::kickUser(
|
||||
lt_user,
|
||||
participant->name);
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(text, kickUserSure),
|
||||
Box<Ui::ConfirmBox>(text, kickUserSure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_session.h"
|
||||
#include "boxes/peers/edit_peer_common.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
@@ -26,8 +27,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxUserFirstLastName = 64; // See also add_contact_box.
|
||||
|
||||
QString UserPhone(not_null<UserData*> user) {
|
||||
const auto phone = user->phone();
|
||||
return phone.isEmpty()
|
||||
@@ -222,8 +221,8 @@ void Controller::initNameFields(
|
||||
};
|
||||
QObject::connect(first, &Ui::InputField::submitted, submit);
|
||||
QObject::connect(last, &Ui::InputField::submitted, submit);
|
||||
first->setMaxLength(kMaxUserFirstLastName);
|
||||
first->setMaxLength(kMaxUserFirstLastName);
|
||||
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
|
||||
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
|
||||
}
|
||||
|
||||
void Controller::setupWarning() {
|
||||
|
||||
@@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "apiwrap.h"
|
||||
#include "facades.h"
|
||||
@@ -152,7 +152,7 @@ void Controller::choose(not_null<ChannelData*> chat) {
|
||||
onstack(chat);
|
||||
};
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
text,
|
||||
tr::lng_manage_discussion_group_link(tr::now),
|
||||
sure),
|
||||
@@ -184,7 +184,7 @@ void Controller::choose(not_null<ChatData*> chat) {
|
||||
chat->session().api().migrateChat(chat, crl::guard(this, done));
|
||||
};
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
text,
|
||||
tr::lng_manage_discussion_group_link(tr::now),
|
||||
sure),
|
||||
|
||||
@@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/special_buttons.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "settings/settings_privacy_security.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/passcode_box.h"
|
||||
#include "boxes/peers/edit_peer_permissions_box.h"
|
||||
#include "boxes/peers/edit_peer_info_box.h"
|
||||
@@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_user.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/qt_adapters.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "main/main_session.h"
|
||||
@@ -453,7 +452,14 @@ void EditAdminBox::transferOwnership() {
|
||||
)).fail([=](const MTP::Error &error) {
|
||||
_checkTransferRequestId = 0;
|
||||
if (!handleTransferPasswordError(error)) {
|
||||
getDelegate()->show(Box<ConfirmBox>(
|
||||
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
|
||||
const auto callback = crl::guard(this, [=] {
|
||||
transferOwnershipChecked();
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
});
|
||||
*box = getDelegate()->show(Box<Ui::ConfirmBox>(
|
||||
tr::lng_rights_transfer_about(
|
||||
tr::now,
|
||||
lt_group,
|
||||
@@ -462,7 +468,7 @@ void EditAdminBox::transferOwnership() {
|
||||
Ui::Text::Bold(user()->shortName()),
|
||||
Ui::Text::RichLangValue),
|
||||
tr::lng_rights_transfer_sure(tr::now),
|
||||
crl::guard(this, [=] { transferOwnershipChecked(); })));
|
||||
callback));
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
@@ -570,7 +576,7 @@ void EditAdminBox::sendTransferRequestFrom(
|
||||
|| (type == qstr("SESSION_TOO_FRESH_XXX"));
|
||||
}();
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
getDelegate()->show(Box<InformBox>(problem));
|
||||
getDelegate()->show(Box<Ui::InformBox>(problem));
|
||||
if (box) {
|
||||
box->closeBox();
|
||||
}
|
||||
@@ -703,7 +709,7 @@ void EditRestrictedBox::showRestrictUntil() {
|
||||
highlighted,
|
||||
[this](const QDate &date) {
|
||||
setRestrictUntil(
|
||||
static_cast<int>(base::QDateToDateTime(date).toTime_t()));
|
||||
static_cast<int>(date.startOfDay().toSecsSinceEpoch()));
|
||||
}),
|
||||
Ui::LayerOption::KeepOther);
|
||||
_restrictUntilBox->setMaxDate(
|
||||
|
||||
@@ -10,7 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/edit_participant_box.h"
|
||||
#include "boxes/peers/add_participants_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/max_invite_box.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
@@ -1690,7 +1691,7 @@ void ParticipantsBoxController::kickParticipant(not_null<PeerData*> participant)
|
||||
lt_user,
|
||||
user ? user->firstName : participant->name);
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
text,
|
||||
tr::lng_box_remove(tr::now),
|
||||
crl::guard(this, [=] { kickParticipantSure(participant); })),
|
||||
@@ -1729,7 +1730,7 @@ void ParticipantsBoxController::kickParticipantSure(
|
||||
|
||||
void ParticipantsBoxController::removeAdmin(not_null<UserData*> user) {
|
||||
_editBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_profile_sure_remove_admin(
|
||||
tr::now,
|
||||
lt_user,
|
||||
|
||||
18
Telegram/SourceFiles/boxes/peers/edit_peer_common.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Ui::EditPeer {
|
||||
|
||||
constexpr auto kMaxGroupChannelTitle = 128;
|
||||
constexpr auto kMaxUserFirstLastName = 64;
|
||||
constexpr auto kMaxChannelDescription = 255;
|
||||
constexpr auto kMinUsernameLength = 5;
|
||||
constexpr auto kUsernameCheckTimeout = crl::time(200);
|
||||
|
||||
} // namespace Ui::EditPeer
|
||||
@@ -8,11 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/peers/edit_peer_info_box.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_peer_photo.h"
|
||||
#include "main/main_session.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
#include "boxes/peers/edit_peer_common.h"
|
||||
#include "boxes/peers/edit_peer_type_box.h"
|
||||
#include "boxes/peers/edit_peer_history_visibility_box.h"
|
||||
#include "boxes/peers/edit_peer_permissions_box.h"
|
||||
@@ -249,9 +251,6 @@ void ShowEditPermissions(
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxGroupChannelTitle = 128; // See also add_contact_box.
|
||||
constexpr auto kMaxChannelDescription = 255; // See also add_contact_box.
|
||||
|
||||
class Controller : public base::has_weak_ptr {
|
||||
public:
|
||||
Controller(
|
||||
@@ -475,7 +474,7 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
|
||||
: tr::lng_dlg_new_channel_name)(),
|
||||
_peer->name),
|
||||
st::editPeerTitleMargins);
|
||||
result->entity()->setMaxLength(kMaxGroupChannelTitle);
|
||||
result->entity()->setMaxLength(Ui::EditPeer::kMaxGroupChannelTitle);
|
||||
result->entity()->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
result->entity()->setInstantReplacesEnabled(
|
||||
Core::App().settings().replaceEmojiValue());
|
||||
@@ -509,7 +508,7 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
|
||||
tr::lng_create_group_description(),
|
||||
_peer->about()),
|
||||
st::editPeerDescriptionMargins);
|
||||
result->entity()->setMaxLength(kMaxChannelDescription);
|
||||
result->entity()->setMaxLength(Ui::EditPeer::kMaxChannelDescription);
|
||||
result->entity()->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
result->entity()->setInstantReplacesEnabled(
|
||||
Core::App().settings().replaceEmojiValue());
|
||||
@@ -1471,7 +1470,7 @@ void Controller::savePhoto() {
|
||||
? _controls.photo->takeResultImage()
|
||||
: QImage();
|
||||
if (!image.isNull()) {
|
||||
_peer->session().api().uploadPeerPhoto(_peer, std::move(image));
|
||||
_peer->session().api().peerPhoto().upload(_peer, std::move(image));
|
||||
}
|
||||
_box->closeBox();
|
||||
}
|
||||
@@ -1487,7 +1486,7 @@ void Controller::deleteWithConfirmation() {
|
||||
deleteChannel();
|
||||
});
|
||||
_navigation->parentController()->show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
text,
|
||||
tr::lng_box_delete(tr::now),
|
||||
st::attentionBoxButton,
|
||||
@@ -1514,7 +1513,7 @@ void Controller::deleteChannel() {
|
||||
session->api().applyUpdates(result);
|
||||
//}).fail([=](const MTP::Error &error) {
|
||||
// if (error.type() == qstr("CHANNEL_TOO_LARGE")) {
|
||||
// Ui::show(Box<InformBox>(tr::lng_cant_delete_channel(tr::now)));
|
||||
// Ui::show(Box<Ui::InformBox>(tr::lng_cant_delete_channel(tr::now)));
|
||||
// }
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/history_view_group_call_tracker.h" // GenerateUs...
|
||||
#include "history/history_message.h" // GetErrorTextForSending.
|
||||
#include "history/history.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "mainwindow.h"
|
||||
#include "facades.h" // Ui::showPerProfile.
|
||||
@@ -680,7 +680,7 @@ void AddPermanentLinkBlock(
|
||||
}
|
||||
});
|
||||
const auto revokeLink = crl::guard(weak, [=] {
|
||||
const auto box = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
|
||||
const auto done = crl::guard(weak, [=] {
|
||||
const auto close = [=] {
|
||||
if (*box) {
|
||||
@@ -694,7 +694,9 @@ void AddPermanentLinkBlock(
|
||||
close);
|
||||
});
|
||||
*box = Ui::show(
|
||||
Box<ConfirmBox>(tr::lng_group_invite_about_new(tr::now), done),
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_group_invite_about_new(tr::now),
|
||||
done),
|
||||
Ui::LayerOption::KeepOther);
|
||||
});
|
||||
|
||||
@@ -868,7 +870,7 @@ void ShareInviteLinkBox(not_null<PeerData*> peer, const QString &link) {
|
||||
}
|
||||
text.append(error.first);
|
||||
Ui::show(
|
||||
Box<InformBox>(text),
|
||||
Box<Ui::InformBox>(text),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
@@ -968,7 +970,7 @@ void RevokeLink(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> admin,
|
||||
const QString &link) {
|
||||
const auto box = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
|
||||
const auto revoke = [=] {
|
||||
const auto done = [=](const LinkData &data) {
|
||||
if (*box) {
|
||||
@@ -978,7 +980,7 @@ void RevokeLink(
|
||||
peer->session().api().inviteLinks().revoke(peer, admin, link, done);
|
||||
};
|
||||
*box = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_group_invite_revoke_about(tr::now),
|
||||
revoke),
|
||||
Ui::LayerOption::KeepOther);
|
||||
@@ -988,7 +990,7 @@ void DeleteLink(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> admin,
|
||||
const QString &link) {
|
||||
const auto box = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
|
||||
const auto sure = [=] {
|
||||
const auto finish = [=] {
|
||||
if (*box) {
|
||||
@@ -1002,7 +1004,7 @@ void DeleteLink(
|
||||
finish);
|
||||
};
|
||||
*box = Ui::show(
|
||||
Box<ConfirmBox>(tr::lng_group_invite_delete_sure(tr::now), sure),
|
||||
Box<Ui::ConfirmBox>(tr::lng_group_invite_delete_sure(tr::now), sure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/edit_peer_invite_link.h"
|
||||
#include "settings/settings_common.h" // AddDivider.
|
||||
@@ -197,7 +197,7 @@ private:
|
||||
void DeleteAllRevoked(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> admin) {
|
||||
const auto box = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto box = std::make_shared<QPointer<Ui::ConfirmBox>>();
|
||||
const auto sure = [=] {
|
||||
const auto finish = [=] {
|
||||
if (*box) {
|
||||
@@ -210,7 +210,9 @@ void DeleteAllRevoked(
|
||||
finish);
|
||||
};
|
||||
*box = Ui::show(
|
||||
Box<ConfirmBox>(tr::lng_group_invite_delete_all_sure(tr::now), sure),
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_group_invite_delete_all_sure(tr::now),
|
||||
sure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
@@ -268,7 +270,8 @@ void Row::update(const InviteLinkData &data, TimeId now) {
|
||||
|
||||
void Row::updateExpireProgress(TimeId now) {
|
||||
const auto updated = ComputeProgress(_data, now);
|
||||
if (std::round(_progressTillExpire * 360) != std::round(updated * 360)) {
|
||||
if (base::SafeRound(_progressTillExpire * 360)
|
||||
!= base::SafeRound(updated * 360)) {
|
||||
_progressTillExpire = updated;
|
||||
const auto color = ComputeColor(_data, _progressTillExpire);
|
||||
if (_color != color) {
|
||||
@@ -291,7 +294,8 @@ crl::time Row::updateExpireIn() const {
|
||||
if (_data.expireDate <= start) {
|
||||
return 0;
|
||||
}
|
||||
return std::round((_data.expireDate - start) * crl::time(1000) / 720.);
|
||||
return base::SafeRound(
|
||||
(_data.expireDate - start) * crl::time(1000) / 720.);
|
||||
}
|
||||
|
||||
QString Row::generateName() {
|
||||
|
||||
@@ -11,9 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_invite_links.h"
|
||||
#include "main/main_session.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
#include "boxes/peers/edit_peer_common.h"
|
||||
#include "boxes/peers/edit_peer_info_box.h" // CreateButton.
|
||||
#include "boxes/peers/edit_peer_invite_link.h"
|
||||
#include "boxes/peers/edit_peer_invite_links.h"
|
||||
@@ -55,9 +56,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kUsernameCheckTimeout = crl::time(200);
|
||||
constexpr auto kMinUsernameLength = 5;
|
||||
|
||||
class Controller : public base::has_weak_ptr {
|
||||
public:
|
||||
Controller(
|
||||
@@ -419,7 +417,7 @@ void Controller::checkUsernameAvailability() {
|
||||
const auto checking = initial
|
||||
? qsl(".bad.")
|
||||
: getUsernameInput();
|
||||
if (checking.size() < kMinUsernameLength) {
|
||||
if (checking.size() < Ui::EditPeer::kMinUsernameLength) {
|
||||
return;
|
||||
}
|
||||
if (_checkUsernameRequestId) {
|
||||
@@ -496,11 +494,11 @@ void Controller::usernameChanged() {
|
||||
});
|
||||
if (bad) {
|
||||
showUsernameError(tr::lng_create_channel_link_bad_symbols());
|
||||
} else if (username.size() < kMinUsernameLength) {
|
||||
} else if (username.size() < Ui::EditPeer::kMinUsernameLength) {
|
||||
showUsernameError(tr::lng_create_channel_link_too_short());
|
||||
} else {
|
||||
_controls.usernameResult = nullptr;
|
||||
_checkUsernameTimer.callOnce(kUsernameCheckTimeout);
|
||||
_checkUsernameTimer.callOnce(Ui::EditPeer::kUsernameCheckTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
68
Telegram/SourceFiles/boxes/phone_banned_box.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
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 "boxes/phone_banned_box.h"
|
||||
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "core/click_handler_types.h" // UrlClickHandler
|
||||
#include "base/qthelp_url.h" // qthelp::url_encode
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
namespace {
|
||||
|
||||
void SendToBannedHelp(const QString &phone) {
|
||||
const auto version = QString::fromLatin1(AppVersionStr)
|
||||
+ (cAlphaVersion()
|
||||
? qsl(" alpha %1").arg(cAlphaVersion())
|
||||
: (AppBetaVersion ? " beta" : ""));
|
||||
|
||||
const auto subject = qsl("Banned phone number: ") + phone;
|
||||
|
||||
const auto body = qsl("\
|
||||
I'm trying to use my mobile phone number: ") + phone + qsl("\n\
|
||||
But Telegram says it's banned. Please help.\n\
|
||||
\n\
|
||||
App version: ") + version + qsl("\n\
|
||||
OS version: ") + ::Platform::SystemVersionPretty() + qsl("\n\
|
||||
Locale: ") + ::Platform::SystemLanguage();
|
||||
|
||||
const auto url = "mailto:?to="
|
||||
+ qthelp::url_encode("login@stel.com")
|
||||
+ "&subject="
|
||||
+ qthelp::url_encode(subject)
|
||||
+ "&body="
|
||||
+ qthelp::url_encode(body);
|
||||
|
||||
UrlClickHandler::Open(url);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ShowPhoneBannedError(
|
||||
not_null<Window::Controller*> controller,
|
||||
const QString &phone) {
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto close = [=] {
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
};
|
||||
*box = controller->show(
|
||||
Box<Ui::ConfirmBox>(
|
||||
tr::lng_signin_banned_text(tr::now),
|
||||
tr::lng_box_ok(tr::now),
|
||||
tr::lng_signin_banned_help(tr::now),
|
||||
close,
|
||||
[=] { SendToBannedHelp(phone); close(); }),
|
||||
Ui::LayerOption::CloseOther);
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
20
Telegram/SourceFiles/boxes/phone_banned_box.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Window {
|
||||
class Controller;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
|
||||
void ShowPhoneBannedError(
|
||||
not_null<Window::Controller*> controller,
|
||||
const QString &phone);
|
||||
|
||||
} // namespace Ui
|
||||
129
Telegram/SourceFiles/boxes/pin_messages_box.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/pin_messages_box.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool IsOldForPin(MsgId id, not_null<PeerData*> peer) {
|
||||
const auto normal = peer->migrateToOrMe();
|
||||
const auto migrated = normal->migrateFrom();
|
||||
const auto top = Data::ResolveTopPinnedId(normal, migrated);
|
||||
if (!top) {
|
||||
return false;
|
||||
} else if (peer == migrated) {
|
||||
return top.channel || (id < top.msg);
|
||||
} else if (migrated) {
|
||||
return top.channel && (id < top.msg);
|
||||
} else {
|
||||
return (id < top.msg);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PinMessageBox::PinMessageBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
MsgId msgId)
|
||||
: _peer(peer)
|
||||
, _api(&peer->session().mtp())
|
||||
, _msgId(msgId)
|
||||
, _pinningOld(IsOldForPin(msgId, peer))
|
||||
, _text(
|
||||
this,
|
||||
(_pinningOld
|
||||
? tr::lng_pinned_pin_old_sure(tr::now)
|
||||
: (peer->isChat() || peer->isMegagroup())
|
||||
? tr::lng_pinned_pin_sure_group(tr::now)
|
||||
: tr::lng_pinned_pin_sure(tr::now)),
|
||||
st::boxLabel) {
|
||||
}
|
||||
|
||||
void PinMessageBox::prepare() {
|
||||
addButton(tr::lng_pinned_pin(), [this] { pinMessage(); });
|
||||
addButton(tr::lng_cancel(), [this] { closeBox(); });
|
||||
|
||||
if (_peer->isUser() && !_peer->isSelf()) {
|
||||
_pinForPeer.create(
|
||||
this,
|
||||
tr::lng_pinned_also_for_other(
|
||||
tr::now,
|
||||
lt_user,
|
||||
_peer->shortName()),
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
_checkbox = _pinForPeer;
|
||||
} else if (!_pinningOld && (_peer->isChat() || _peer->isMegagroup())) {
|
||||
_notify.create(
|
||||
this,
|
||||
tr::lng_pinned_notify(tr::now),
|
||||
true,
|
||||
st::defaultBoxCheckbox);
|
||||
_checkbox = _notify;
|
||||
}
|
||||
|
||||
auto height = st::boxPadding.top()
|
||||
+ _text->height()
|
||||
+ st::boxPadding.bottom();
|
||||
if (_checkbox) {
|
||||
height += st::boxMediumSkip + _checkbox->heightNoMargins();
|
||||
}
|
||||
setDimensions(st::boxWidth, height);
|
||||
}
|
||||
|
||||
void PinMessageBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
_text->moveToLeft(st::boxPadding.left(), st::boxPadding.top());
|
||||
if (_checkbox) {
|
||||
_checkbox->moveToLeft(
|
||||
st::boxPadding.left(),
|
||||
_text->y() + _text->height() + st::boxMediumSkip);
|
||||
}
|
||||
}
|
||||
|
||||
void PinMessageBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
pinMessage();
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void PinMessageBox::pinMessage() {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto flags = MTPmessages_UpdatePinnedMessage::Flags(0);
|
||||
if (_notify && !_notify->checked()) {
|
||||
flags |= MTPmessages_UpdatePinnedMessage::Flag::f_silent;
|
||||
}
|
||||
if (_pinForPeer && !_pinForPeer->checked()) {
|
||||
flags |= MTPmessages_UpdatePinnedMessage::Flag::f_pm_oneside;
|
||||
}
|
||||
_requestId = _api.request(MTPmessages_UpdatePinnedMessage(
|
||||
MTP_flags(flags),
|
||||
_peer->input,
|
||||
MTP_int(_msgId)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_peer->session().api().applyUpdates(result);
|
||||
Ui::hideLayer();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
Ui::hideLayer();
|
||||
}).send();
|
||||
}
|
||||
43
Telegram/SourceFiles/boxes/pin_messages_box.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
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 "boxes/abstract_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Ui {
|
||||
class Checkbox;
|
||||
class FlatLabel;
|
||||
} // namespace Ui
|
||||
|
||||
class PinMessageBox final : public Ui::BoxContent {
|
||||
public:
|
||||
PinMessageBox(QWidget*, not_null<PeerData*> peer, MsgId msgId);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
void pinMessage();
|
||||
|
||||
const not_null<PeerData*> _peer;
|
||||
MTP::Sender _api;
|
||||
MsgId _msgId = 0;
|
||||
bool _pinningOld = false;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _text;
|
||||
object_ptr<Ui::Checkbox> _notify = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _pinForPeer = { nullptr };
|
||||
QPointer<Ui::Checkbox> _checkbox;
|
||||
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
};
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
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 "boxes/rate_call_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "mainwindow.h"
|
||||
#include "main/main_session.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "apiwrap.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_calls.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxRating = 5;
|
||||
constexpr auto kRateCallCommentLengthMax = 200;
|
||||
|
||||
} // namespace
|
||||
|
||||
RateCallBox::RateCallBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
uint64 callId,
|
||||
uint64 callAccessHash)
|
||||
: _session(session)
|
||||
, _api(&_session->mtp())
|
||||
, _callId(callId)
|
||||
, _callAccessHash(callAccessHash) {
|
||||
}
|
||||
|
||||
void RateCallBox::prepare() {
|
||||
setTitle(tr::lng_call_rate_label());
|
||||
addButton(tr::lng_cancel(), [this] { closeBox(); });
|
||||
|
||||
for (auto i = 0; i < kMaxRating; ++i) {
|
||||
_stars.emplace_back(this, st::callRatingStar);
|
||||
_stars.back()->setClickedCallback([this, value = i + 1] { ratingChanged(value); });
|
||||
_stars.back()->show();
|
||||
}
|
||||
|
||||
updateMaxHeight();
|
||||
}
|
||||
|
||||
void RateCallBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
auto starsWidth = (_stars.size() * st::callRatingStar.width);
|
||||
auto starLeft = (width() - starsWidth) / 2;
|
||||
auto starTop = st::callRatingStarTop;
|
||||
for (auto &star : _stars) {
|
||||
star->moveToLeft(starLeft, starTop);
|
||||
starLeft += star->width();
|
||||
}
|
||||
if (_comment) {
|
||||
_comment->moveToLeft(st::callRatingPadding.left(), _stars.back()->bottomNoMargins() + st::callRatingCommentTop);
|
||||
}
|
||||
}
|
||||
|
||||
void RateCallBox::ratingChanged(int value) {
|
||||
Expects(value > 0 && value <= kMaxRating);
|
||||
if (!_rating) {
|
||||
clearButtons();
|
||||
addButton(tr::lng_send_button(), [this] { send(); });
|
||||
addButton(tr::lng_cancel(), [this] { closeBox(); });
|
||||
}
|
||||
_rating = value;
|
||||
|
||||
for (auto i = 0; i < kMaxRating; ++i) {
|
||||
_stars[i]->setIconOverride((i < value) ? &st::callRatingStarFilled : nullptr);
|
||||
_stars[i]->setRippleColorOverride((i < value) ? &st::lightButtonBgOver : nullptr);
|
||||
}
|
||||
if (value < kMaxRating) {
|
||||
if (!_comment) {
|
||||
_comment.create(
|
||||
this,
|
||||
st::callRatingComment,
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
tr::lng_call_rate_comment());
|
||||
_comment->show();
|
||||
_comment->setSubmitSettings(Core::App().settings().sendSubmitWay());
|
||||
_comment->setMaxLength(kRateCallCommentLengthMax);
|
||||
_comment->resize(width() - (st::callRatingPadding.left() + st::callRatingPadding.right()), _comment->height());
|
||||
|
||||
updateMaxHeight();
|
||||
connect(_comment, &Ui::InputField::resized, [=] { commentResized(); });
|
||||
connect(_comment, &Ui::InputField::submitted, [=] { send(); });
|
||||
connect(_comment, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
}
|
||||
_comment->setFocusFast();
|
||||
} else if (_comment) {
|
||||
_comment.destroy();
|
||||
updateMaxHeight();
|
||||
}
|
||||
}
|
||||
|
||||
void RateCallBox::setInnerFocus() {
|
||||
if (_comment) {
|
||||
_comment->setFocusFast();
|
||||
} else {
|
||||
setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void RateCallBox::commentResized() {
|
||||
updateMaxHeight();
|
||||
update();
|
||||
}
|
||||
|
||||
void RateCallBox::send() {
|
||||
Expects(_rating > 0 && _rating <= kMaxRating);
|
||||
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
auto comment = _comment ? _comment->getLastText().trimmed() : QString();
|
||||
_requestId = _api.request(MTPphone_SetCallRating(
|
||||
MTP_flags(0),
|
||||
MTP_inputPhoneCall(MTP_long(_callId), MTP_long(_callAccessHash)),
|
||||
MTP_int(_rating),
|
||||
MTP_string(comment)
|
||||
)).done([=](const MTPUpdates &updates) {
|
||||
_session->api().applyUpdates(updates);
|
||||
closeBox();
|
||||
}).fail([=](const MTP::Error &error) { closeBox(); }).send();
|
||||
}
|
||||
|
||||
void RateCallBox::updateMaxHeight() {
|
||||
auto newHeight = st::callRatingPadding.top() + st::callRatingStarTop + _stars.back()->heightNoMargins() + st::callRatingPadding.bottom();
|
||||
if (_comment) {
|
||||
newHeight += st::callRatingCommentTop + _comment->height();
|
||||
}
|
||||
setDimensions(st::boxWideWidth, newHeight);
|
||||
}
|
||||
@@ -19,7 +19,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "confirm_box.h"
|
||||
#include "editor/photo_editor_layer_widget.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
@@ -549,9 +548,6 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||
block.takeWidget(),
|
||||
QMargins(0, _inner->count() ? st::sendMediaRowSkip : 0, 0, 0));
|
||||
|
||||
const auto preventDelete =
|
||||
widget->lifetime().make_state<rpl::event_stream<int>>();
|
||||
|
||||
block.itemDeleteRequest(
|
||||
) | rpl::filter([=] {
|
||||
return !_removingIndex;
|
||||
@@ -562,9 +558,9 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||
if (index < 0 || index >= _list.files.size()) {
|
||||
return;
|
||||
}
|
||||
// Prevent item delete if it is the only one.
|
||||
// Just close the box if it is the only one.
|
||||
if (_list.files.size() == 1) {
|
||||
preventDelete->fire_copy(0);
|
||||
closeBox();
|
||||
return;
|
||||
}
|
||||
_list.files.erase(_list.files.begin() + index);
|
||||
@@ -572,9 +568,7 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||
});
|
||||
}, widget->lifetime());
|
||||
|
||||
rpl::merge(
|
||||
block.itemReplaceRequest(),
|
||||
preventDelete->events()
|
||||
block.itemReplaceRequest(
|
||||
) | rpl::start_with_next([=](int index) {
|
||||
const auto replace = [=](Ui::PreparedList list) {
|
||||
if (list.files.empty()) {
|
||||
|
||||
@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_authorizations.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -81,7 +81,7 @@ private:
|
||||
Full _data;
|
||||
|
||||
object_ptr<Inner> _inner;
|
||||
QPointer<ConfirmBox> _terminateBox;
|
||||
QPointer<Ui::ConfirmBox> _terminateBox;
|
||||
|
||||
base::Timer _shortPollTimer;
|
||||
|
||||
@@ -250,7 +250,7 @@ void SessionsContent::terminate(Fn<void()> terminateRequest, QString message) {
|
||||
terminateRequest();
|
||||
});
|
||||
_terminateBox = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
Box<Ui::ConfirmBox>(
|
||||
message,
|
||||
tr::lng_settings_reset_button(tr::now),
|
||||
st::attentionBoxButton,
|
||||
|
||||
@@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwidget.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "apiwrap.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
@@ -72,7 +72,7 @@ protected:
|
||||
int visibleBottom) override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void enterEventHook(QEvent *e) override;
|
||||
void enterEventHook(QEnterEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
@@ -906,7 +906,7 @@ void ShareBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void ShareBox::Inner::enterEventHook(QEvent *e) {
|
||||
void ShareBox::Inner::enterEventHook(QEnterEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
@@ -1113,7 +1113,7 @@ QString AppendShareGameScoreUrl(
|
||||
auto channelAccessHash = uint64(channel ? channel->access : 0);
|
||||
shareHashDataInts[0] = session->userId().bare;
|
||||
shareHashDataInts[1] = fullId.channel.bare;
|
||||
shareHashDataInts[2] = fullId.msg;
|
||||
shareHashDataInts[2] = uint64(fullId.msg.bare);
|
||||
shareHashDataInts[3] = channelAccessHash;
|
||||
|
||||
// Count SHA1() of data.
|
||||
@@ -1155,7 +1155,8 @@ void ShareGameScoreByHash(
|
||||
|
||||
auto hashEncrypted = QByteArray::fromBase64(hash.toLatin1(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
if (hashEncrypted.size() <= key128Size || (hashEncrypted.size() != key128Size + 0x20)) {
|
||||
Ui::show(Box<InformBox>(tr::lng_confirm_phone_link_invalid(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(
|
||||
tr::lng_confirm_phone_link_invalid(tr::now)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1175,19 +1176,19 @@ void ShareGameScoreByHash(
|
||||
//// Check next 64 bits of SHA1() of data.
|
||||
//auto skipSha1Part = sizeof(channelAccessHash);
|
||||
//if (memcmp(dataSha1 + skipSha1Part, hashEncrypted.constData() + skipSha1Part, key128Size - skipSha1Part) != 0) {
|
||||
// Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
// Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
// return;
|
||||
//}
|
||||
|
||||
// Check 128 bits of SHA1() of data.
|
||||
if (memcmp(dataSha1, hashEncrypted.constData(), key128Size) != 0) {
|
||||
Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
return;
|
||||
}
|
||||
|
||||
auto hashDataInts = reinterpret_cast<uint64*>(hashData.data());
|
||||
if (hashDataInts[0] != session->userId().bare) {
|
||||
Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1195,20 +1196,19 @@ void ShareGameScoreByHash(
|
||||
auto channelAccessHash = hashDataInts[3];
|
||||
//auto channelAccessHashInts = reinterpret_cast<int32*>(&channelAccessHash);
|
||||
//if (channelAccessHashInts[0] != hashDataInts[3]) {
|
||||
// Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
// Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (((hashDataInts[1] >> 40) != 0)
|
||||
|| ((hashDataInts[2] >> 32) != 0)
|
||||
|| (!hashDataInts[1] && channelAccessHash)) {
|
||||
// If there is no channel id, there should be no channel access_hash.
|
||||
Ui::show(Box<InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
|
||||
return;
|
||||
}
|
||||
|
||||
auto channelId = ChannelId(hashDataInts[1]);
|
||||
auto msgId = MsgId(hashDataInts[2]);
|
||||
auto msgId = MsgId(int64(hashDataInts[2]));
|
||||
if (const auto item = session->data().message(channelId, msgId)) {
|
||||
FastShareMessage(item);
|
||||
} else {
|
||||
@@ -1219,7 +1219,8 @@ void ShareGameScoreByHash(
|
||||
if (const auto item = session->data().message(channel, msgId)) {
|
||||
FastShareMessage(item);
|
||||
} else {
|
||||
Ui::show(Box<InformBox>(tr::lng_edit_deleted(tr::now)));
|
||||
Ui::show(Box<Ui::InformBox>(
|
||||
tr::lng_edit_deleted(tr::now)));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -13,11 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "core/application.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "dialogs/dialogs_layout.h"
|
||||
#include "dialogs/ui/dialogs_layout.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/image/image.h"
|
||||
@@ -257,7 +257,7 @@ void StickerSetBox::handleError(Error error) {
|
||||
switch (error) {
|
||||
case Error::NotFound:
|
||||
_controller->show(
|
||||
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
|
||||
Box<Ui::InformBox>(tr::lng_stickers_not_found(tr::now)));
|
||||
break;
|
||||
default: Unexpected("Error in StickerSetBox::handleError.");
|
||||
}
|
||||
@@ -404,7 +404,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
|
||||
|
||||
auto p = StickersPack();
|
||||
p.reserve(stickers.size());
|
||||
for (auto j = 0, c = stickers.size(); j != c; ++j) {
|
||||
for (auto j = 0, c = int(stickers.size()); j != c; ++j) {
|
||||
auto doc = _controller->session().data().document(stickers[j].v);
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
@@ -532,7 +532,7 @@ void StickerSetBox::Inner::installDone(
|
||||
auto &order = isMasks
|
||||
? stickers.maskSetsOrderRef()
|
||||
: stickers.setsOrderRef();
|
||||
const auto insertAtIndex = 0, currentIndex = order.indexOf(_setId);
|
||||
const auto insertAtIndex = 0, currentIndex = int(order.indexOf(_setId));
|
||||
if (currentIndex != insertAtIndex) {
|
||||
if (currentIndex > 0) {
|
||||
order.removeAt(currentIndex);
|
||||
|
||||
@@ -11,13 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/timer.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
|
||||
class ConfirmBox;
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
class ConfirmBox;
|
||||
class PlainShadow;
|
||||
} // namespace Ui
|
||||
|
||||
|
||||