Compare commits
430 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b5500fe75 | ||
|
|
2845f48430 | ||
|
|
4ba959e6e1 | ||
|
|
72d9ac508a | ||
|
|
386600baf9 | ||
|
|
eb1825defd | ||
|
|
33069739ee | ||
|
|
dd8c526fb7 | ||
|
|
2701e63406 | ||
|
|
b972da059a | ||
|
|
81862215b4 | ||
|
|
a34e998c42 | ||
|
|
6d1193a751 | ||
|
|
0cd7399dc9 | ||
|
|
f1b0b60340 | ||
|
|
d1cf43f9a4 | ||
|
|
a0b3b1affd | ||
|
|
2a7fdfc832 | ||
|
|
672070e618 | ||
|
|
6a2b1bb48d | ||
|
|
db121c0839 | ||
|
|
ca9db9fd3f | ||
|
|
ecccf673a9 | ||
|
|
e0d7cae3fe | ||
|
|
241526f127 | ||
|
|
4148099115 | ||
|
|
5edf200157 | ||
|
|
bd7ba3acb1 | ||
|
|
e024d9bbb0 | ||
|
|
3d7b8b3162 | ||
|
|
8887272577 | ||
|
|
c86257568f | ||
|
|
ae25538706 | ||
|
|
21e417433b | ||
|
|
cb272be805 | ||
|
|
b79d8d6c82 | ||
|
|
be8aed6a95 | ||
|
|
d06337dddc | ||
|
|
0f3ec47074 | ||
|
|
3a5bad4b7a | ||
|
|
2aecd1035e | ||
|
|
5d04842a80 | ||
|
|
59c73a4814 | ||
|
|
25affe5484 | ||
|
|
399aed4087 | ||
|
|
31dbe2278e | ||
|
|
9ed064b7fc | ||
|
|
a59353df9f | ||
|
|
8acd47bf2f | ||
|
|
be53cb027c | ||
|
|
6ff8c1de05 | ||
|
|
2ebbf062d0 | ||
|
|
fd538bc6c8 | ||
|
|
c0959ceaeb | ||
|
|
6c382c647c | ||
|
|
8f9bed0443 | ||
|
|
dc3996c077 | ||
|
|
5bfd5e4495 | ||
|
|
d646de7184 | ||
|
|
bc2b0f8392 | ||
|
|
f2a7cf5c64 | ||
|
|
0df628dc7a | ||
|
|
a5d1fbff98 | ||
|
|
5cae57601a | ||
|
|
2b7fb7a9a6 | ||
|
|
feb238c5d9 | ||
|
|
0d888eea85 | ||
|
|
bfb6ecbac7 | ||
|
|
2152fe6a79 | ||
|
|
b113696fe6 | ||
|
|
b65a24df96 | ||
|
|
c655bf852f | ||
|
|
be495c17bc | ||
|
|
9785ff4be6 | ||
|
|
5ec37e9112 | ||
|
|
f9f84fd407 | ||
|
|
ed93669693 | ||
|
|
e79ddf2459 | ||
|
|
5efe47cfb6 | ||
|
|
b8045cbcc7 | ||
|
|
aa1090a585 | ||
|
|
0a5589f869 | ||
|
|
383b29dbd8 | ||
|
|
13a9b967e9 | ||
|
|
b798654ca7 | ||
|
|
a5e6890b77 | ||
|
|
2a3a38531b | ||
|
|
4ebf6ebb6f | ||
|
|
6fe736c9fc | ||
|
|
ef682e7023 | ||
|
|
5c3f667fc3 | ||
|
|
a95a055acd | ||
|
|
846499a4fb | ||
|
|
6afb3f70bb | ||
|
|
c063d94aa5 | ||
|
|
261720c941 | ||
|
|
7b3c452316 | ||
|
|
aa00f9bd34 | ||
|
|
b0ff443eac | ||
|
|
a886c598c1 | ||
|
|
2ce4abfdfe | ||
|
|
18c42954ae | ||
|
|
b57b4fa0f8 | ||
|
|
e66cde398a | ||
|
|
3706be77ea | ||
|
|
f481f1e142 | ||
|
|
84b09795f3 | ||
|
|
95954c4b1f | ||
|
|
a56a12a1ef | ||
|
|
5c4b459f57 | ||
|
|
9a616edf2a | ||
|
|
92332b45ea | ||
|
|
5a7fcc3a22 | ||
|
|
6c441353c4 | ||
|
|
b742c95516 | ||
|
|
a59c3da3d0 | ||
|
|
8399f4189f | ||
|
|
67b9fe846b | ||
|
|
0f4ccce0e1 | ||
|
|
01d763eed1 | ||
|
|
41c60419f1 | ||
|
|
195164d9d4 | ||
|
|
518d1da736 | ||
|
|
aade3d4f27 | ||
|
|
22356eb01c | ||
|
|
b5eb88a32f | ||
|
|
6887993f92 | ||
|
|
71b733a018 | ||
|
|
e2eb9cea00 | ||
|
|
99e96a5b13 | ||
|
|
7093254b66 | ||
|
|
f4544b0964 | ||
|
|
c27456277e | ||
|
|
2e824ace00 | ||
|
|
dafa286b18 | ||
|
|
003d01206f | ||
|
|
f0963a332a | ||
|
|
91bdb66f0d | ||
|
|
ffb48c42b0 | ||
|
|
8171828c2a | ||
|
|
a8aa66d191 | ||
|
|
e631d98230 | ||
|
|
1940c67a09 | ||
|
|
c574119718 | ||
|
|
648cd44ddd | ||
|
|
fde8dd9607 | ||
|
|
f1e0cd6c1d | ||
|
|
44df10d6cb | ||
|
|
b6a757842a | ||
|
|
4636c74586 | ||
|
|
2208621050 | ||
|
|
f133dd396c | ||
|
|
ccd04b98b9 | ||
|
|
d37b65e624 | ||
|
|
3e9b811875 | ||
|
|
44c562d8ba | ||
|
|
93c548c013 | ||
|
|
a7d9281768 | ||
|
|
3b369fc98e | ||
|
|
e5cd7e6d40 | ||
|
|
99d05ba967 | ||
|
|
ec9512899e | ||
|
|
26ea6c4e63 | ||
|
|
8e44a7f5c4 | ||
|
|
a093cb6274 | ||
|
|
64f2f330f6 | ||
|
|
473e30e594 | ||
|
|
dc95756ec9 | ||
|
|
2a935868a8 | ||
|
|
f48d8538c0 | ||
|
|
3372dfcd3e | ||
|
|
78d00bcf22 | ||
|
|
9dc9e019f6 | ||
|
|
178c0078c1 | ||
|
|
8478abe378 | ||
|
|
bfc9e43eb4 | ||
|
|
e174025a92 | ||
|
|
89f4408029 | ||
|
|
d7dc277003 | ||
|
|
32bc723745 | ||
|
|
c2ad765424 | ||
|
|
9799afa064 | ||
|
|
e880c14d61 | ||
|
|
e70465c633 | ||
|
|
4ed1835d32 | ||
|
|
19bbccd1a7 | ||
|
|
9d8b80cbce | ||
|
|
dec8264625 | ||
|
|
fe618bd652 | ||
|
|
d208236994 | ||
|
|
4d987f7278 | ||
|
|
193e454fd4 | ||
|
|
bdfb9b4143 | ||
|
|
c9716f3c72 | ||
|
|
7c1704e68b | ||
|
|
771a51224e | ||
|
|
cf275b152a | ||
|
|
98cb85df66 | ||
|
|
032694ad9e | ||
|
|
5437215677 | ||
|
|
5ec80238a0 | ||
|
|
ae6c152988 | ||
|
|
7d15cca1ee | ||
|
|
83c5a67af5 | ||
|
|
c9ad2cd1aa | ||
|
|
fe1f198d99 | ||
|
|
818662c2e6 | ||
|
|
05d0d2a6d6 | ||
|
|
c1a0dad2b7 | ||
|
|
4caf26d069 | ||
|
|
83bc6fb39c | ||
|
|
dbb7568b92 | ||
|
|
45fda44924 | ||
|
|
26f1ade5ba | ||
|
|
9dd93a77a0 | ||
|
|
331d1baad6 | ||
|
|
d3159d86da | ||
|
|
f9e1513491 | ||
|
|
b6e37b7730 | ||
|
|
f9d56eb4c1 | ||
|
|
95565c39ed | ||
|
|
890aacaeee | ||
|
|
e2f0886950 | ||
|
|
fe21b5a502 | ||
|
|
e7043c4d63 | ||
|
|
aae2101131 | ||
|
|
64afed0fb2 | ||
|
|
4d9464ed87 | ||
|
|
b43191506a | ||
|
|
c47781c25a | ||
|
|
f0c4868b3e | ||
|
|
35e5c2329b | ||
|
|
74fc5524ab | ||
|
|
2d4c99a6f7 | ||
|
|
69c73d0a2c | ||
|
|
58510e0208 | ||
|
|
0681d10c51 | ||
|
|
add2356c8a | ||
|
|
c66b2b2291 | ||
|
|
769923c6cc | ||
|
|
27528d084f | ||
|
|
299aa69058 | ||
|
|
d1cc09f40e | ||
|
|
a133b43eed | ||
|
|
9b57725b8c | ||
|
|
34b0f6f014 | ||
|
|
f5cc93ec64 | ||
|
|
4f3263d979 | ||
|
|
b28e374e06 | ||
|
|
918d58ef0a | ||
|
|
5a388d9dde | ||
|
|
0f4909621b | ||
|
|
55d3d8adc3 | ||
|
|
d2d6a6daa4 | ||
|
|
a7f4ac2797 | ||
|
|
25b5027dc7 | ||
|
|
93a967dc74 | ||
|
|
3cfc3dcecf | ||
|
|
e09510ea9f | ||
|
|
4c289fc8fb | ||
|
|
58cf0fa2b1 | ||
|
|
5ca12a73c3 | ||
|
|
fd8e9dad92 | ||
|
|
df0fe0a460 | ||
|
|
646d15b257 | ||
|
|
2eb6848eb8 | ||
|
|
9b3c103f16 | ||
|
|
6a2a13d346 | ||
|
|
b6edf4561d | ||
|
|
c2744700c0 | ||
|
|
f506a5ea6c | ||
|
|
2f702148e3 | ||
|
|
e10c928207 | ||
|
|
a1baa23a52 | ||
|
|
a70e72f75d | ||
|
|
4111da1dd0 | ||
|
|
e7804d014d | ||
|
|
bf87de3706 | ||
|
|
ebc2043055 | ||
|
|
69b1f6c4e1 | ||
|
|
2708777167 | ||
|
|
6e0d62bb65 | ||
|
|
6d706fd222 | ||
|
|
6066265717 | ||
|
|
805e4d01e7 | ||
|
|
e209299af4 | ||
|
|
b3f0a3c9f5 | ||
|
|
1da8841ac7 | ||
|
|
7df5df6351 | ||
|
|
bf85b0c109 | ||
|
|
314e30272b | ||
|
|
61b9a32504 | ||
|
|
01b7d4ffba | ||
|
|
8643972f8c | ||
|
|
1894b8fcf7 | ||
|
|
e59a68cd68 | ||
|
|
466c6da5e3 | ||
|
|
b8cb792831 | ||
|
|
0f9c2a62fe | ||
|
|
04350af96f | ||
|
|
287b3509ab | ||
|
|
2a5bcd3eec | ||
|
|
2a0b9a44dd | ||
|
|
c552db04d7 | ||
|
|
22f1ffc72b | ||
|
|
4f33be20d4 | ||
|
|
9728ddeaf9 | ||
|
|
3c44bdb6b7 | ||
|
|
b236844c94 | ||
|
|
67d12fa6d2 | ||
|
|
215856adc3 | ||
|
|
07e010dfb5 | ||
|
|
dba9ca2084 | ||
|
|
9a60e744d3 | ||
|
|
e1a2ab0d7e | ||
|
|
a605c110a8 | ||
|
|
18c6be0d3b | ||
|
|
ff728e2fc1 | ||
|
|
eff90395b6 | ||
|
|
f4d52b82b4 | ||
|
|
61419b57c8 | ||
|
|
441989a8e1 | ||
|
|
c5a41e1f55 | ||
|
|
0ce4d66601 | ||
|
|
d2d6b319b6 | ||
|
|
47edb71a68 | ||
|
|
1f8626b383 | ||
|
|
0d6a36e187 | ||
|
|
548a0c8517 | ||
|
|
09d85e25c1 | ||
|
|
51b5b14dea | ||
|
|
0d290a2c28 | ||
|
|
c1b3d589c7 | ||
|
|
65430d92ea | ||
|
|
8711830f66 | ||
|
|
c4d919d46b | ||
|
|
3e7a688811 | ||
|
|
2773a675d0 | ||
|
|
9bbdccc111 | ||
|
|
bb8defeb42 | ||
|
|
545dbd0791 | ||
|
|
c7469075ab | ||
|
|
54fa974789 | ||
|
|
2cd3cec478 | ||
|
|
c11b977f1d | ||
|
|
30e8f17b37 | ||
|
|
2c3190ce2a | ||
|
|
ea7796dccc | ||
|
|
a11ca58f36 | ||
|
|
496d711684 | ||
|
|
219b824338 | ||
|
|
df389a365c | ||
|
|
aa2c52c1f8 | ||
|
|
f48ae29f22 | ||
|
|
de00e0e15c | ||
|
|
79fea49272 | ||
|
|
8190b10680 | ||
|
|
1ebd9562a2 | ||
|
|
ebaf63393f | ||
|
|
7c168740d9 | ||
|
|
11b991cddc | ||
|
|
8306e58b75 | ||
|
|
4002739682 | ||
|
|
c259921269 | ||
|
|
2eb3041c1f | ||
|
|
d539d9b5d2 | ||
|
|
d17c985bcb | ||
|
|
e2668e7cfa | ||
|
|
18c2c61bee | ||
|
|
be0b0c1984 | ||
|
|
b00ca217b3 | ||
|
|
874d76b16b | ||
|
|
cfac261516 | ||
|
|
7b5e5c2587 | ||
|
|
db064381d9 | ||
|
|
096c310e0e | ||
|
|
0b87db8b45 | ||
|
|
71cf4a4885 | ||
|
|
a0c6104fae | ||
|
|
8e54ac4dcf | ||
|
|
97b0288c7d | ||
|
|
e3cc8652e4 | ||
|
|
8708a001c7 | ||
|
|
6fc4facddf | ||
|
|
e5536880fb | ||
|
|
44ff8f92ac | ||
|
|
95208267de | ||
|
|
9c579e0d5b | ||
|
|
d1be4c6d96 | ||
|
|
a65afdac95 | ||
|
|
22b47925d4 | ||
|
|
f291e365e5 | ||
|
|
6f176803d4 | ||
|
|
b6a3bb4080 | ||
|
|
c7c1deab81 | ||
|
|
2ded5870b5 | ||
|
|
57f2ae098f | ||
|
|
76c06923d5 | ||
|
|
fb7ac874f0 | ||
|
|
12905f0dcb | ||
|
|
68a313a58f | ||
|
|
152115bf2e | ||
|
|
8bd3051224 | ||
|
|
aa94ca6619 | ||
|
|
e397f72eb2 | ||
|
|
4d495b8d7c | ||
|
|
a142a2717c | ||
|
|
de4a477686 | ||
|
|
4e692e2c1e | ||
|
|
8237e6f7a3 | ||
|
|
d1a9f1feac | ||
|
|
ef1d38462f | ||
|
|
93c8e9aa1f | ||
|
|
ac2dce4bb1 | ||
|
|
f2e1d90c74 | ||
|
|
8e28a229f2 | ||
|
|
363f6cb329 | ||
|
|
b6f7832745 | ||
|
|
74c1db740d | ||
|
|
4bb5dcf50c | ||
|
|
b0d01389c6 | ||
|
|
3e22ada889 | ||
|
|
6d08394adc | ||
|
|
47bdeeef9a | ||
|
|
099440d008 | ||
|
|
eb7201a55b | ||
|
|
6d9f40db30 | ||
|
|
7960706e60 | ||
|
|
8b0e54a95c | ||
|
|
89e8f0ccc3 |
@@ -72,10 +72,6 @@ GOTO:EOF
|
||||
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION
|
||||
)
|
||||
|
||||
echo %BUILD_VERSION% | findstr /C:"disable_unity_integration">nul && (
|
||||
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_UNITY_INTEGRATION
|
||||
)
|
||||
|
||||
echo %BUILD_VERSION% | findstr /C:"disable_gtk_integration">nul && (
|
||||
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
)
|
||||
|
||||
@@ -14,7 +14,6 @@ env:
|
||||
- BUILD_VERSION="disable_crash_reports"
|
||||
- BUILD_VERSION="disable_network_proxy"
|
||||
- BUILD_VERSION="disable_desktop_file_generation"
|
||||
- BUILD_VERSION="disable_unity_integration"
|
||||
- BUILD_VERSION="disable_gtk_integration"
|
||||
|
||||
matrix:
|
||||
@@ -45,7 +44,7 @@ addons:
|
||||
- libopus-dev
|
||||
- libpulse-dev
|
||||
- libssl-dev
|
||||
- libunity-dev
|
||||
- libdee-dev
|
||||
- libva-dev
|
||||
- libvdpau-dev
|
||||
- libxcb-xkb-dev
|
||||
|
||||
@@ -116,10 +116,6 @@ build() {
|
||||
GYP_DEFINES+=",TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION"
|
||||
fi
|
||||
|
||||
if [[ $BUILD_VERSION == *"disable_unity_integration"* ]]; then
|
||||
GYP_DEFINES+=",TDESKTOP_DISABLE_UNITY_INTEGRATION"
|
||||
fi
|
||||
|
||||
if [[ $BUILD_VERSION == *"disable_gtk_integration"* ]]; then
|
||||
GYP_DEFINES+=",TDESKTOP_DISABLE_GTK_INTEGRATION"
|
||||
fi
|
||||
@@ -318,6 +314,7 @@ buildVdpau() {
|
||||
git clone git://anongit.freedesktop.org/vdpau/libvdpau
|
||||
|
||||
cd "$EXTERNAL/libvdpau"
|
||||
git checkout libvdpau-1.2
|
||||
./autogen.sh --prefix=$VDPAU_PATH --enable-static
|
||||
make $MAKE_ARGS
|
||||
sudo make install
|
||||
|
||||
2
LEGAL
@@ -1,7 +1,7 @@
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
Copyright (c) 2014-2018 John Preston, https://desktop.telegram.org
|
||||
Copyright (c) 2014-2019 John Preston, https://desktop.telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -15,8 +15,8 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
|
||||
* Windows XP - Windows 10 (**not** RT)
|
||||
* Mac OS X 10.8 - Mac OS X 10.11
|
||||
* Mac OS X 10.6 - Mac OS X 10.7 (separate build)
|
||||
* Ubuntu 12.04 - Ubuntu 18.04
|
||||
* Fedora 22 - Fedora 28
|
||||
* Ubuntu 12.04 - Ubuntu 18.10
|
||||
* Fedora 22 - Fedora 29
|
||||
* [Snappy](https://snapcraft.io/telegram-desktop)
|
||||
|
||||
## Third-party
|
||||
@@ -45,7 +45,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
|
||||
## Build instructions
|
||||
|
||||
* [Visual Studio 2017][msvc]
|
||||
* [Xcode 9][xcode]
|
||||
* [Xcode 10][xcode]
|
||||
* [GYP/CMake on GNU/Linux][cmake]
|
||||
|
||||
[//]: # (LINKS)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/src/build/common.gypi b/src/build/common.gypi
|
||||
index 29990c6..53e99d4 100644
|
||||
index 29990c65..53e99d44 100644
|
||||
--- a/src/build/common.gypi
|
||||
+++ b/src/build/common.gypi
|
||||
@@ -330,6 +330,7 @@
|
||||
@@ -11,7 +11,7 @@ index 29990c6..53e99d4 100644
|
||||
},
|
||||
}],
|
||||
diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
|
||||
index 1a93ce6..1c1d643 100644
|
||||
index 1a93ce6d..b5986e33 100644
|
||||
--- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj
|
||||
+++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
|
||||
@@ -35,6 +35,19 @@
|
||||
@@ -34,7 +34,15 @@ index 1a93ce6..1c1d643 100644
|
||||
162F64F2161C577500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; };
|
||||
162F64F3161C577500CD68D5 /* arch_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 162F64F1161C577500CD68D5 /* arch_utilities.h */; };
|
||||
162F64F4161C579B00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; };
|
||||
@@ -170,11 +183,8 @@
|
||||
@@ -67,6 +80,7 @@
|
||||
4DBE49A7134A4F280072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
|
||||
4DBE49A8134A4F380072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
|
||||
4DBE49A9134A4F460072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
|
||||
+ 5A8B220921E0C5740045F83C /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
|
||||
8B3101C611F0CD9F00FCF3E4 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D6A5FE840307C02AAC07 /* AppKit.framework */; };
|
||||
8B3101C711F0CD9F00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; };
|
||||
8B3101CA11F0CDB000FCF3E4 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D6A5FE840307C02AAC07 /* AppKit.framework */; };
|
||||
@@ -170,11 +184,8 @@
|
||||
F92C564A0ECD10CA009BE4BA /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; };
|
||||
F92C564C0ECD10DD009BE4BA /* breakpadUtilities.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; };
|
||||
F92C56570ECD113E009BE4BA /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C554A0ECCF530009BE4BA /* Carbon.framework */; };
|
||||
@@ -46,7 +54,7 @@ index 1a93ce6..1c1d643 100644
|
||||
F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */; };
|
||||
F93803CD0F8083B7004D428B /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536B0ECCE3FD009BE4BA /* dynamic_images.cc */; };
|
||||
F93803CE0F8083B7004D428B /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536D0ECCE3FD009BE4BA /* exception_handler.cc */; };
|
||||
@@ -213,7 +223,6 @@
|
||||
@@ -213,7 +224,6 @@
|
||||
F9C44DBD0EF072A0003AEBAA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DBA0EF072A0003AEBAA /* MainMenu.xib */; };
|
||||
F9C44E000EF077CD003AEBAA /* Breakpad.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
|
||||
F9C44E3C0EF08B12003AEBAA /* Breakpad.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
|
||||
@@ -54,7 +62,7 @@ index 1a93ce6..1c1d643 100644
|
||||
F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C53770ECCE635009BE4BA /* HTTPMultipartUpload.m */; };
|
||||
F9C44EE50EF0A006003AEBAA /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9C44EE40EF0A006003AEBAA /* SystemConfiguration.framework */; };
|
||||
F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C44EE80EF0A3C1003AEBAA /* GTMLogger.m */; };
|
||||
@@ -410,20 +419,6 @@
|
||||
@@ -410,20 +420,6 @@
|
||||
remoteGlobalIDString = F92C563B0ECD10B3009BE4BA;
|
||||
remoteInfo = breakpadUtilities;
|
||||
};
|
||||
@@ -75,7 +83,7 @@ index 1a93ce6..1c1d643 100644
|
||||
F93DE2FB0F82C3C600608B94 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
|
||||
@@ -536,13 +531,6 @@
|
||||
@@ -536,13 +532,6 @@
|
||||
remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
|
||||
remoteInfo = Breakpad;
|
||||
};
|
||||
@@ -89,7 +97,7 @@ index 1a93ce6..1c1d643 100644
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -714,7 +702,6 @@
|
||||
@@ -714,7 +703,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -97,7 +105,7 @@ index 1a93ce6..1c1d643 100644
|
||||
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1181,18 +1168,13 @@
|
||||
@@ -1181,18 +1169,13 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */;
|
||||
buildPhases = (
|
||||
@@ -116,7 +124,7 @@ index 1a93ce6..1c1d643 100644
|
||||
);
|
||||
name = Breakpad;
|
||||
productInstallPath = "$(HOME)/Library/Frameworks";
|
||||
@@ -1399,6 +1381,8 @@
|
||||
@@ -1399,6 +1382,8 @@
|
||||
/* Begin PBXProject section */
|
||||
0867D690FE84028FC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
@@ -125,7 +133,7 @@ index 1a93ce6..1c1d643 100644
|
||||
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Breakpad" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
developmentRegion = English;
|
||||
@@ -1583,16 +1567,6 @@
|
||||
@@ -1583,16 +1568,6 @@
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
@@ -142,7 +150,7 @@ index 1a93ce6..1c1d643 100644
|
||||
F92C569C0ECE04A7009BE4BA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1640,20 +1614,6 @@
|
||||
@@ -1640,20 +1615,6 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "install_name_tool -id \"@executable_path/../Resources/breakpadUtilities.dylib\" \"${BUILT_PRODUCTS_DIR}/breakpadUtilities.dylib\"\n";
|
||||
};
|
||||
@@ -163,10 +171,11 @@ index 1a93ce6..1c1d643 100644
|
||||
F9C77DD80F7DD5CF0045F7DB /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1674,6 +1634,19 @@
|
||||
@@ -1674,6 +1635,20 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
+ 5A8B220921E0C5740045F83C /* breakpad_nlist_64.cc in Sources */,
|
||||
+ 0748C0501C63C52D004489BF /* bootstrap_compat.cc in Sources */,
|
||||
+ 0748C04F1C63C523004489BF /* macho_walker.cc in Sources */,
|
||||
+ 0748C04E1C63C51C004489BF /* md5.cc in Sources */,
|
||||
@@ -183,7 +192,7 @@ index 1a93ce6..1c1d643 100644
|
||||
F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */,
|
||||
F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */,
|
||||
F92C55D10ECD0064009BE4BA /* Breakpad.mm in Sources */,
|
||||
@@ -1955,16 +1928,6 @@
|
||||
@@ -1955,16 +1930,6 @@
|
||||
target = F92C563B0ECD10B3009BE4BA /* breakpadUtilities */;
|
||||
targetProxy = F92C564D0ECD10E5009BE4BA /* PBXContainerItemProxy */;
|
||||
};
|
||||
@@ -200,7 +209,7 @@ index 1a93ce6..1c1d643 100644
|
||||
F93DE2FC0F82C3C600608B94 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = F93803BD0F80820F004D428B /* generator_test */;
|
||||
@@ -2025,11 +1988,6 @@
|
||||
@@ -2025,11 +1990,6 @@
|
||||
target = 8DC2EF4F0486A6940098B216 /* Breakpad */;
|
||||
targetProxy = F9C44E190EF0790F003AEBAA /* PBXContainerItemProxy */;
|
||||
};
|
||||
@@ -212,7 +221,7 @@ index 1a93ce6..1c1d643 100644
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
@@ -2126,8 +2084,12 @@
|
||||
@@ -2126,8 +2086,12 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */;
|
||||
buildSettings = {
|
||||
@@ -226,7 +235,7 @@ index 1a93ce6..1c1d643 100644
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -2135,7 +2097,12 @@
|
||||
@@ -2135,7 +2099,12 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8B31027811F0D3AF00FCF3E4 /* BreakpadRelease.xcconfig */;
|
||||
buildSettings = {
|
||||
@@ -239,7 +248,7 @@ index 1a93ce6..1c1d643 100644
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -2454,7 +2421,12 @@
|
||||
@@ -2454,7 +2423,12 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */;
|
||||
buildSettings = {
|
||||
@@ -253,7 +262,7 @@ index 1a93ce6..1c1d643 100644
|
||||
name = "Debug With Code Coverage";
|
||||
};
|
||||
diff --git a/src/client/mac/Framework/Breakpad.mm b/src/client/mac/Framework/Breakpad.mm
|
||||
index 1d2e519..943310f 100644
|
||||
index 1d2e519b..943310fa 100644
|
||||
--- a/src/client/mac/Framework/Breakpad.mm
|
||||
+++ b/src/client/mac/Framework/Breakpad.mm
|
||||
@@ -355,10 +355,10 @@ bool Breakpad::Initialize(NSDictionary *parameters) {
|
||||
@@ -480,7 +489,7 @@ index 1d2e519..943310f 100644
|
||||
}
|
||||
|
||||
diff --git a/src/common/language.cc b/src/common/language.cc
|
||||
index 978fb85..a95ae5f 100644
|
||||
index 978fb855..a95ae5f7 100644
|
||||
--- a/src/common/language.cc
|
||||
+++ b/src/common/language.cc
|
||||
@@ -46,8 +46,27 @@
|
||||
@@ -552,7 +561,7 @@ index 978fb85..a95ae5f 100644
|
||||
#endif
|
||||
}
|
||||
diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc
|
||||
index 562875e..4367851 100644
|
||||
index 562875e1..43678510 100644
|
||||
--- a/src/common/linux/elf_symbols_to_module.cc
|
||||
+++ b/src/common/linux/elf_symbols_to_module.cc
|
||||
@@ -39,6 +39,29 @@
|
||||
@@ -615,7 +624,7 @@ index 562875e..4367851 100644
|
||||
module->AddExtern(ext);
|
||||
}
|
||||
diff --git a/src/tools/linux/tools_linux.gypi b/src/tools/linux/tools_linux.gypi
|
||||
index 1c15992..020e4c1 100644
|
||||
index 1c15992e..020e4c1c 100644
|
||||
--- a/src/tools/linux/tools_linux.gypi
|
||||
+++ b/src/tools/linux/tools_linux.gypi
|
||||
@@ -58,7 +58,7 @@
|
||||
@@ -627,3 +636,16 @@ index 1c15992..020e4c1 100644
|
||||
],
|
||||
'dependencies': [
|
||||
'../common/common.gyp:common',
|
||||
diff --git a/src/tools/mac/dump_syms/macho_dump.cc b/src/tools/mac/dump_syms/macho_dump.cc
|
||||
index d882bbe8..3432bb45 100644
|
||||
--- a/src/tools/mac/dump_syms/macho_dump.cc
|
||||
+++ b/src/tools/mac/dump_syms/macho_dump.cc
|
||||
@@ -140,7 +140,7 @@ void DumpFile(const char *filename) {
|
||||
size_t object_files_size;
|
||||
const SuperFatArch* super_fat_object_files =
|
||||
fat_reader.object_files(&object_files_size);
|
||||
- struct fat_arch *object_files;
|
||||
+ struct fat_arch *object_files = 0;
|
||||
if (!super_fat_object_files->ConvertToFatArch(object_files)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,108 @@ pacman --noconfirm -S pkg-config
|
||||
|
||||
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
./configure --toolchain=msvc --disable-programs --disable-doc --disable-everything --enable-protocol=file --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --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=wavpack --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=pcm_zork --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_d3d11va --enable-hwaccel=h264_dxva2 --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --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=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release"
|
||||
./configure --toolchain=msvc \
|
||||
--extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release" \
|
||||
--disable-programs \
|
||||
--disable-doc \
|
||||
--disable-network \
|
||||
--disable-everything \
|
||||
--enable-hwaccel=h264_d3d11va \
|
||||
--enable-hwaccel=h264_d3d11va2 \
|
||||
--enable-hwaccel=h264_dxva2 \
|
||||
--enable-hwaccel=hevc_d3d11va \
|
||||
--enable-hwaccel=hevc_d3d11va2 \
|
||||
--enable-hwaccel=hevc_dxva2 \
|
||||
--enable-hwaccel=mpeg2_d3d11va \
|
||||
--enable-hwaccel=mpeg2_d3d11va2 \
|
||||
--enable-hwaccel=mpeg2_dxva2 \
|
||||
--enable-protocol=file --enable-libopus \
|
||||
--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=pcm_zork \
|
||||
--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 -j4
|
||||
make -j4 install
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/build/common.gypi b/build/common.gypi
|
||||
index 1affc70..c0d2f6a 100644
|
||||
index 1affc70..0677e4b 100644
|
||||
--- a/build/common.gypi
|
||||
+++ b/build/common.gypi
|
||||
@@ -66,6 +66,11 @@
|
||||
@@ -66,6 +66,13 @@
|
||||
'conditions': [
|
||||
['clang!=0', {
|
||||
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', # -std=c++11
|
||||
@@ -10,11 +10,13 @@ index 1affc70..c0d2f6a 100644
|
||||
+ 'OTHER_LDFLAGS': [
|
||||
+ '/usr/local/macold/lib/libc++.a',
|
||||
+ '/usr/local/macold/lib/libc++abi.a',
|
||||
+ '-isysroot/',
|
||||
+ '-L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/',
|
||||
+ ],
|
||||
|
||||
# Don't link in libarclite_macosx.a, see http://crbug.com/156530.
|
||||
'CLANG_LINK_OBJC_RUNTIME': 'NO', # -fno-objc-link-runtime
|
||||
@@ -116,6 +121,9 @@
|
||||
@@ -116,6 +123,9 @@
|
||||
],
|
||||
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf
|
||||
index eec9e1f..7ae53c7 100644
|
||||
index eec9e1f688..7ae53c7a1e 100644
|
||||
--- a/mkspecs/common/msvc-desktop.conf
|
||||
+++ b/mkspecs/common/msvc-desktop.conf
|
||||
@@ -30,9 +30,10 @@ QMAKE_YACCFLAGS = -d
|
||||
@@ -17,7 +17,7 @@ index eec9e1f..7ae53c7 100644
|
||||
QMAKE_CFLAGS_LTCG = -GL
|
||||
QMAKE_CFLAGS_SSE2 = -arch:SSE2
|
||||
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
|
||||
index 391fbcc..d07802b 100644
|
||||
index 391fbcc519..d07802bb7a 100644
|
||||
--- a/src/corelib/io/qfsfileengine_win.cpp
|
||||
+++ b/src/corelib/io/qfsfileengine_win.cpp
|
||||
@@ -427,11 +427,12 @@ qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
|
||||
@@ -36,7 +36,7 @@ index 391fbcc..d07802b 100644
|
||||
// Note: Only return error if the first WriteFile failed.
|
||||
q->setError(QFile::WriteError, qt_error_string());
|
||||
diff --git a/src/corelib/tools/qunicodetables.cpp b/src/corelib/tools/qunicodetables.cpp
|
||||
index 14e4fd1..0619a17 100644
|
||||
index 14e4fd10aa..0619a176a7 100644
|
||||
--- a/src/corelib/tools/qunicodetables.cpp
|
||||
+++ b/src/corelib/tools/qunicodetables.cpp
|
||||
@@ -6227,7 +6227,8 @@ static const Properties uc_properties[] = {
|
||||
@@ -50,7 +50,7 @@ index 14e4fd1..0619a17 100644
|
||||
{ 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
|
||||
{ 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
|
||||
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
|
||||
index 2d00b9d..eeba86e 100644
|
||||
index 2d00b9dce9..eeba86e936 100644
|
||||
--- a/src/gui/kernel/qhighdpiscaling.cpp
|
||||
+++ b/src/gui/kernel/qhighdpiscaling.cpp
|
||||
@@ -51,6 +51,9 @@ static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS";
|
||||
@@ -64,7 +64,7 @@ index 2d00b9d..eeba86e 100644
|
||||
qreal result = 1;
|
||||
if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) {
|
||||
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
|
||||
index 5b2f4ec..790db46 100644
|
||||
index 5b2f4ece77..790db46d25 100644
|
||||
--- a/src/gui/kernel/qplatformdialoghelper.h
|
||||
+++ b/src/gui/kernel/qplatformdialoghelper.h
|
||||
@@ -386,6 +386,10 @@ public:
|
||||
@@ -79,7 +79,7 @@ index 5b2f4ec..790db46 100644
|
||||
virtual void selectNameFilter(const QString &filter) = 0;
|
||||
virtual QString selectedNameFilter() const = 0;
|
||||
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
|
||||
index bcd29b6..bcb0672 100644
|
||||
index bcd29b6fe1..bcb0672f69 100644
|
||||
--- a/src/gui/kernel/qwindow.cpp
|
||||
+++ b/src/gui/kernel/qwindow.cpp
|
||||
@@ -2525,7 +2525,8 @@ void QWindowPrivate::setCursor(const QCursor *newCursor)
|
||||
@@ -93,7 +93,7 @@ index bcd29b6..bcb0672 100644
|
||||
QCursor *c = QGuiApplication::overrideCursor();
|
||||
if (!c && hasCursor)
|
||||
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
|
||||
index 918c989..4158259 100644
|
||||
index 918c98997b..4158259743 100644
|
||||
--- a/src/gui/painting/qpaintengine_p.h
|
||||
+++ b/src/gui/painting/qpaintengine_p.h
|
||||
@@ -80,8 +80,18 @@ public:
|
||||
@@ -117,7 +117,7 @@ index 918c989..4158259 100644
|
||||
|
||||
// Make sure we're inside the viewport.
|
||||
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
|
||||
index 7e507bb..936e7a9 100644
|
||||
index 7e507bba2d..936e7a92cb 100644
|
||||
--- a/src/gui/text/qtextengine_p.h
|
||||
+++ b/src/gui/text/qtextengine_p.h
|
||||
@@ -283,7 +283,8 @@ private:
|
||||
@@ -131,7 +131,7 @@ index 7e507bb..936e7a9 100644
|
||||
public:
|
||||
inline QTextItemInt()
|
||||
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
|
||||
index aca475a..5fa0be2 100644
|
||||
index aca475a581..5fa0be2c45 100644
|
||||
--- a/src/gui/text/qtextlayout.cpp
|
||||
+++ b/src/gui/text/qtextlayout.cpp
|
||||
@@ -694,6 +694,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
|
||||
@@ -208,7 +208,7 @@ index aca475a..5fa0be2 100644
|
||||
|
||||
static const QFixed RightBearingNotCalculated;
|
||||
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
|
||||
index f74d4d4..8ad672c 100644
|
||||
index f74d4d4229..8ad672c9fe 100644
|
||||
--- a/src/gui/text/qtextlayout.h
|
||||
+++ b/src/gui/text/qtextlayout.h
|
||||
@@ -196,6 +196,9 @@ private:
|
||||
@@ -222,7 +222,7 @@ index f74d4d4..8ad672c 100644
|
||||
|
||||
|
||||
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
|
||||
index c4cb8e6..45793e3 100644
|
||||
index c4cb8e65c0..45793e364f 100644
|
||||
--- a/src/network/access/qhttpnetworkconnection.cpp
|
||||
+++ b/src/network/access/qhttpnetworkconnection.cpp
|
||||
@@ -110,6 +110,8 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
|
||||
@@ -235,7 +235,7 @@ index c4cb8e6..45793e3 100644
|
||||
delete channels[i].socket;
|
||||
}
|
||||
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
|
||||
index 41834b2..8cdf4ab 100644
|
||||
index 41834b21ae..8cdf4ab145 100644
|
||||
--- a/src/network/socket/qnativesocketengine_win.cpp
|
||||
+++ b/src/network/socket/qnativesocketengine_win.cpp
|
||||
@@ -675,6 +675,13 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
|
||||
@@ -253,7 +253,7 @@ index 41834b2..8cdf4ab 100644
|
||||
setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
|
||||
socketState = QAbstractSocket::UnconnectedState;
|
||||
diff --git a/src/platformsupport/dbustray/qdbustrayicon.cpp b/src/platformsupport/dbustray/qdbustrayicon.cpp
|
||||
index 4d6e707..9bdb0be 100644
|
||||
index 4d6e70720d..9bdb0beb67 100644
|
||||
--- a/src/platformsupport/dbustray/qdbustrayicon.cpp
|
||||
+++ b/src/platformsupport/dbustray/qdbustrayicon.cpp
|
||||
@@ -58,9 +58,18 @@ QT_BEGIN_NAMESPACE
|
||||
@@ -290,7 +290,7 @@ index 4d6e707..9bdb0be 100644
|
||||
}
|
||||
if (!necessary)
|
||||
diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
|
||||
index 728b166..1dc6459 100644
|
||||
index 728b166b71..1dc64593e1 100644
|
||||
--- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
|
||||
+++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
|
||||
@@ -172,6 +172,79 @@ void QBasicFontDatabase::releaseHandle(void *handle)
|
||||
@@ -388,7 +388,7 @@ index 728b166..1dc6459 100644
|
||||
if (error != FT_Err_Ok) {
|
||||
qDebug() << "FT_New_Face failed with index" << index << ':' << hex << error;
|
||||
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
|
||||
index 8ebabf3..7bb8abd 100644
|
||||
index 8ebabf3419..7bb8abd0d0 100644
|
||||
--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
|
||||
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
|
||||
@@ -375,6 +375,17 @@ static void populateFromPattern(FcPattern *pattern)
|
||||
@@ -450,7 +450,7 @@ index 8ebabf3..7bb8abd 100644
|
||||
}
|
||||
populateFromPattern(pattern);
|
||||
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
index 566abf2..5c5fde9 100644
|
||||
index 566abf2126..5c5fde9813 100644
|
||||
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
@@ -265,6 +265,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
|
||||
@@ -482,7 +482,7 @@ index 566abf2..5c5fde9 100644
|
||||
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
|
||||
double d;
|
||||
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
index 7b45958..2ed2fd9 100644
|
||||
index 7b459584ea..2ed2fd9b3b 100644
|
||||
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
@@ -764,7 +764,8 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gl
|
||||
@@ -496,7 +496,7 @@ index 7b45958..2ed2fd9 100644
|
||||
|
||||
QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const
|
||||
diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro
|
||||
index 86bdd47..9b9c8de 100644
|
||||
index 86bdd4729b..9b9c8ded08 100644
|
||||
--- a/src/plugins/platforminputcontexts/compose/compose.pro
|
||||
+++ b/src/plugins/platforminputcontexts/compose/compose.pro
|
||||
@@ -15,7 +15,8 @@ HEADERS += $$PWD/qcomposeplatforminputcontext.h \
|
||||
@@ -510,7 +510,7 @@ index 86bdd47..9b9c8de 100644
|
||||
LIBS += $$QMAKE_LIBS_XKBCOMMON
|
||||
QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON
|
||||
diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
|
||||
index d1bea9a..36a15a6 100644
|
||||
index d1bea9af23..36a15a6473 100644
|
||||
--- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
|
||||
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
|
||||
@@ -232,6 +232,12 @@ bool QComposeInputContext::checkComposeTable()
|
||||
@@ -527,7 +527,7 @@ index d1bea9a..36a15a6 100644
|
||||
event.setCommitString(QChar(character));
|
||||
QCoreApplication::sendEvent(m_focusObject, &event);
|
||||
diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro
|
||||
index faea54b..fe4a837 100644
|
||||
index faea54b874..fe4a837511 100644
|
||||
--- a/src/plugins/platforminputcontexts/platforminputcontexts.pro
|
||||
+++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro
|
||||
@@ -1,7 +1,8 @@
|
||||
@@ -541,7 +541,7 @@ index faea54b..fe4a837 100644
|
||||
|
||||
contains(QT_CONFIG, xcb-plugin): SUBDIRS += compose
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
index caa8884..9dc3bc1 100644
|
||||
index caa8884661..9dc3bc1661 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
@@ -210,7 +210,8 @@ QT_END_NAMESPACE
|
||||
@@ -572,7 +572,7 @@ index caa8884..9dc3bc1 100644
|
||||
}
|
||||
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
|
||||
index 934f68a..3ece698 100644
|
||||
index 934f68ad18..3ece6984ac 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
|
||||
@@ -64,6 +64,9 @@ public:
|
||||
@@ -586,7 +586,7 @@ index 934f68a..3ece698 100644
|
||||
|
||||
QT_END_NAMESPACE
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
|
||||
index ca92103..f27ea15 100644
|
||||
index ca92103826..f27ea15bad 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
|
||||
@@ -38,7 +38,8 @@
|
||||
@@ -624,7 +624,7 @@ index ca92103..f27ea15 100644
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
const QVector<QRect> rects = region.rects();
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
|
||||
index 058209d..6af61e7 100644
|
||||
index 058209da7e..6af61e7dab 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
|
||||
@@ -546,9 +546,9 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm
|
||||
@@ -654,7 +654,7 @@ index 058209d..6af61e7 100644
|
||||
}
|
||||
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
index c2d206f..9b97398 100644
|
||||
index c2d206fb45..9b9739862d 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
@@ -384,6 +384,12 @@ bool QCocoaKeyMapper::updateKeyboard()
|
||||
@@ -681,7 +681,7 @@ index c2d206f..9b97398 100644
|
||||
}
|
||||
return ret;
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
index 8152c57..87ba2f3 100644
|
||||
index 8152c57ffd..87ba2f3f72 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
@@ -94,6 +94,8 @@ QT_USE_NAMESPACE
|
||||
@@ -821,7 +821,7 @@ index 8152c57..87ba2f3 100644
|
||||
}
|
||||
}
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
index c0d5904..f3c2047 100644
|
||||
index c0d5904367..f3c2047196 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
@@ -141,7 +141,8 @@ static bool isMouseEvent(NSEvent *ev)
|
||||
@@ -883,7 +883,7 @@ index c0d5904..f3c2047 100644
|
||||
[iconButton setImage:image];
|
||||
[image release];
|
||||
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
|
||||
index c67bcfd..2616f42 100644
|
||||
index c67bcfd23b..6a60670aee 100644
|
||||
--- a/src/plugins/platforms/cocoa/qnsview.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qnsview.mm
|
||||
@@ -647,6 +647,12 @@ QT_WARNING_POP
|
||||
@@ -957,8 +957,19 @@ index c67bcfd..2616f42 100644
|
||||
- (void)cancelOperation:(id)sender
|
||||
{
|
||||
Q_UNUSED(sender);
|
||||
@@ -1981,6 +2006,10 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
// change the cursor
|
||||
[nativeCursor set];
|
||||
|
||||
+ // Patch: Backport a fix from cd08753d3e. Starting with macOS Mojave this requires accessibility access.
|
||||
+ if (QSysInfo::macVersion() >= Q_MV_OSX(10, 14))
|
||||
+ return;
|
||||
+
|
||||
// Make sure the cursor is updated correctly if the mouse does not move and window is under cursor
|
||||
// by creating a fake move event
|
||||
if (m_updatingDrag)
|
||||
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
|
||||
index 94bb71e..16ab51e 100644
|
||||
index 94bb71e429..16ab51e166 100644
|
||||
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
|
||||
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
|
||||
@@ -716,12 +716,20 @@ public:
|
||||
@@ -1163,7 +1174,7 @@ index 94bb71e..16ab51e 100644
|
||||
{
|
||||
m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time.
|
||||
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
|
||||
index 1e58b9b..1741c21 100644
|
||||
index 1e58b9b3d4..1741c21a1c 100644
|
||||
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
|
||||
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
|
||||
@@ -1268,6 +1268,10 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
|
||||
@@ -1178,7 +1189,7 @@ index 1e58b9b..1741c21 100644
|
||||
if (!kbItem.exists)
|
||||
return result;
|
||||
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
|
||||
index 1d23a9d..640cd42 100644
|
||||
index 1d23a9d9b9..640cd426ed 100644
|
||||
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
|
||||
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
|
||||
@@ -127,6 +127,10 @@ static inline bool launchMail(const QUrl &url)
|
||||
@@ -1193,7 +1204,7 @@ index 1d23a9d..640cd42 100644
|
||||
// but that cannot handle a Windows command line [yet].
|
||||
command.replace(QStringLiteral("%1"), url.toString(QUrl::FullyEncoded));
|
||||
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
|
||||
index b38d7c2..34f19c4 100644
|
||||
index b38d7c29ae..34f19c4efa 100644
|
||||
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
|
||||
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
|
||||
@@ -1020,7 +1020,8 @@ void QWindowsWindow::destroyWindow()
|
||||
@@ -1247,7 +1258,7 @@ index b38d7c2..34f19c4 100644
|
||||
break;
|
||||
}
|
||||
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
|
||||
index 6fffa1e..cb1c9c1 100644
|
||||
index 6fffa1e6e9..cb1c9c1161 100644
|
||||
--- a/src/plugins/platforms/windows/qwindowswindow.h
|
||||
+++ b/src/plugins/platforms/windows/qwindowswindow.h
|
||||
@@ -265,6 +265,10 @@ private:
|
||||
@@ -1262,7 +1273,7 @@ index 6fffa1e..cb1c9c1 100644
|
||||
inline bool isDropSiteEnabled() const { return m_dropTarget != 0; }
|
||||
void setDropSiteEnabled(bool enabled);
|
||||
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
|
||||
index 09e7ecf..c0f15a4 100644
|
||||
index 09e7ecf3a3..c0f15a4242 100644
|
||||
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
|
||||
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
|
||||
@@ -79,7 +79,10 @@ static int resourceType(const QByteArray &key)
|
||||
@@ -1292,7 +1303,7 @@ index 09e7ecf..c0f15a4 100644
|
||||
break;
|
||||
}
|
||||
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
|
||||
index f88b710..6f818a5 100644
|
||||
index f88b710864..6f818a5a72 100644
|
||||
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
|
||||
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
|
||||
@@ -68,7 +68,10 @@ public:
|
||||
@@ -1308,7 +1319,7 @@ index f88b710..6f818a5 100644
|
||||
|
||||
QXcbNativeInterface();
|
||||
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
|
||||
index bc2de89..aa8f8df 100644
|
||||
index bc2de899f5..aa8f8df4ad 100644
|
||||
--- a/src/widgets/dialogs/qfiledialog.cpp
|
||||
+++ b/src/widgets/dialogs/qfiledialog.cpp
|
||||
@@ -1200,6 +1200,15 @@ QList<QUrl> QFileDialogPrivate::userSelectedFiles() const
|
||||
@@ -1343,7 +1354,7 @@ index bc2de89..aa8f8df 100644
|
||||
Returns a list of urls containing the selected files in the dialog.
|
||||
If no files are selected, or the mode is not ExistingFiles or
|
||||
diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h
|
||||
index ffe49a2..42dc563 100644
|
||||
index ffe49a2dd2..42dc563c8a 100644
|
||||
--- a/src/widgets/dialogs/qfiledialog.h
|
||||
+++ b/src/widgets/dialogs/qfiledialog.h
|
||||
@@ -108,6 +108,9 @@ public:
|
||||
@@ -1357,7 +1368,7 @@ index ffe49a2..42dc563 100644
|
||||
QList<QUrl> selectedUrls() const;
|
||||
|
||||
diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h
|
||||
index f610e46..547a646 100644
|
||||
index f610e46f83..547a64695a 100644
|
||||
--- a/src/widgets/dialogs/qfiledialog_p.h
|
||||
+++ b/src/widgets/dialogs/qfiledialog_p.h
|
||||
@@ -123,6 +123,10 @@ public:
|
||||
@@ -1398,7 +1409,7 @@ index f610e46..547a646 100644
|
||||
{
|
||||
if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
|
||||
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
|
||||
index b1d80d7..42e32fd 100644
|
||||
index b1d80d7b8f..42e32fd404 100644
|
||||
--- a/src/widgets/kernel/qwidget.cpp
|
||||
+++ b/src/widgets/kernel/qwidget.cpp
|
||||
@@ -5138,6 +5138,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
|
||||
@@ -1451,7 +1462,7 @@ index b1d80d7..42e32fd 100644
|
||||
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
|
||||
res = focusNextPrevChild(false);
|
||||
diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp
|
||||
index 704142f..7c4340e 100644
|
||||
index 704142fe5c..7c4340e459 100644
|
||||
--- a/src/widgets/util/qsystemtrayicon.cpp
|
||||
+++ b/src/widgets/util/qsystemtrayicon.cpp
|
||||
@@ -709,6 +709,10 @@ void QSystemTrayIconPrivate::updateMenu_sys_qpa()
|
||||
@@ -1466,7 +1477,7 @@ index 704142f..7c4340e 100644
|
||||
}
|
||||
|
||||
diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp
|
||||
index 2e2a042..472e377 100644
|
||||
index 2e2a042bf1..472e37722b 100644
|
||||
--- a/src/widgets/widgets/qabstractscrollarea.cpp
|
||||
+++ b/src/widgets/widgets/qabstractscrollarea.cpp
|
||||
@@ -640,15 +640,22 @@ scrolling range.
|
||||
@@ -1497,7 +1508,7 @@ index 2e2a042..472e377 100644
|
||||
}
|
||||
|
||||
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
index daf9f00..57499dc 100644
|
||||
index daf9f00c46..57499dc4a4 100644
|
||||
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
@@ -40,6 +40,11 @@
|
||||
@@ -1539,7 +1550,7 @@ index daf9f00..57499dc 100644
|
||||
#ifndef QT_NO_COMPLETER
|
||||
complete(event->key());
|
||||
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
index deca002..8a2023f 100644
|
||||
index deca002bf5..8a2023f503 100644
|
||||
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
@@ -71,6 +71,11 @@
|
||||
|
||||
@@ -92,7 +92,7 @@ msgServiceFont: semiboldFont;
|
||||
msgServiceNameFont: semiboldFont;
|
||||
msgServicePhotoWidth: 100px;
|
||||
msgDateFont: font(13px);
|
||||
msgMinWidth: 190px;
|
||||
msgMinWidth: 160px;
|
||||
msgPhotoSize: 33px;
|
||||
msgPhotoSkip: 40px;
|
||||
msgPadding: margins(13px, 7px, 13px, 8px);
|
||||
@@ -258,19 +258,6 @@ videoIcon: icon {
|
||||
};
|
||||
locationSize: size(320px, 240px);
|
||||
|
||||
webPageLeft: 10px;
|
||||
webPageBar: 2px;
|
||||
webPageTitleFont: semiboldFont;
|
||||
webPageTitleStyle: semiboldTextStyle;
|
||||
webPageTitleOutFg: historyTextOutFg;
|
||||
webPageTitleInFg: historyTextInFg;
|
||||
webPageDescriptionOutFg: historyTextOutFg;
|
||||
webPageDescriptionInFg: historyTextInFg;
|
||||
webPageDescriptionFont: normalFont;
|
||||
webPageDescriptionStyle: defaultTextStyle;
|
||||
webPagePhotoSize: 100px;
|
||||
webPagePhotoDelta: 8px;
|
||||
|
||||
mediaPlayerSuppressDuration: 150;
|
||||
|
||||
botDescSkip: 8px;
|
||||
|
||||
BIN
Telegram/Resources/emoji/set0_preview.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
Telegram/Resources/emoji/set1_preview.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Telegram/Resources/emoji/set2_preview.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
Telegram/Resources/emoji/set3_preview.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
@@ -311,7 +311,8 @@ div.selected {
|
||||
background-position: 12px 12px;
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
.default .media .title {
|
||||
.default .media .title,
|
||||
.default .media_poll .question {
|
||||
padding-top: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
BIN
Telegram/Resources/icons/dialogs_bot.png
Normal file
|
After Width: | Height: | Size: 277 B |
BIN
Telegram/Resources/icons/dialogs_bot@2x.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
Telegram/Resources/icons/dialogs_bot@3x.png
Normal file
|
After Width: | Height: | Size: 715 B |
BIN
Telegram/Resources/icons/history_audio_cancel.png
Normal file
|
After Width: | Height: | Size: 153 B |
BIN
Telegram/Resources/icons/history_audio_cancel@2x.png
Normal file
|
After Width: | Height: | Size: 251 B |
BIN
Telegram/Resources/icons/history_audio_cancel@3x.png
Normal file
|
After Width: | Height: | Size: 487 B |
BIN
Telegram/Resources/icons/history_audio_download.png
Normal file
|
After Width: | Height: | Size: 160 B |
BIN
Telegram/Resources/icons/history_audio_download@2x.png
Normal file
|
After Width: | Height: | Size: 221 B |
BIN
Telegram/Resources/icons/history_audio_download@3x.png
Normal file
|
After Width: | Height: | Size: 453 B |
BIN
Telegram/Resources/icons/info_permissions.png
Normal file
|
After Width: | Height: | Size: 672 B |
BIN
Telegram/Resources/icons/info_permissions@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/info_permissions@3x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 354 B |
|
Before Width: | Height: | Size: 737 B |
|
Before Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/info_rights_lock.png
Normal file
|
After Width: | Height: | Size: 280 B |
BIN
Telegram/Resources/icons/info_rights_lock@2x.png
Normal file
|
After Width: | Height: | Size: 519 B |
BIN
Telegram/Resources/icons/info_rights_lock@3x.png
Normal file
|
After Width: | Height: | Size: 721 B |
BIN
Telegram/Resources/icons/overview_video_download.png
Normal file
|
After Width: | Height: | Size: 156 B |
BIN
Telegram/Resources/icons/overview_video_download@2x.png
Normal file
|
After Width: | Height: | Size: 221 B |
BIN
Telegram/Resources/icons/overview_video_download@3x.png
Normal file
|
After Width: | Height: | Size: 438 B |
BIN
Telegram/Resources/icons/overview_video_play.png
Normal file
|
After Width: | Height: | Size: 175 B |
BIN
Telegram/Resources/icons/overview_video_play@2x.png
Normal file
|
After Width: | Height: | Size: 321 B |
BIN
Telegram/Resources/icons/overview_video_play@3x.png
Normal file
|
After Width: | Height: | Size: 422 B |
BIN
Telegram/Resources/icons/settings_emoji.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/settings_emoji@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Telegram/Resources/icons/settings_emoji@3x.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
@@ -128,6 +128,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gif_error" = "An error has occurred while reading GIF animation :(";
|
||||
"lng_edit_error" = "You cannot edit this message";
|
||||
"lng_join_channel_error" = "Sorry, you have joined too many channels and supergroups. Please leave some before joining this one.";
|
||||
"lng_migrate_error" = "This action will convert the group to a supergroup. Unfortunately, you are a member of too many supergroups and channels. Please leave some of the channels or groups you don't need before proceeding.";
|
||||
"lng_error_phone_flood" = "Sorry, you have deleted and re-created your account too many times recently. Please wait for a few days before signing up again.";
|
||||
"lng_error_start_minimized_passcoded" = "You have set a local passcode, so Telegram Desktop can't be launched minimised; it will ask you to enter your passcode before it can start working.";
|
||||
"lng_error_pinned_max#one" = "Sorry, you can pin no more than {count} chat to the top.";
|
||||
@@ -142,10 +143,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_error_admin_limit_channel" = "Sorry, you've reached the maximum number of admins for this channel.";
|
||||
"lng_sure_add_admin_invite" = "This user is not a member of this group. Add them to the group and promote them to admin?";
|
||||
"lng_sure_add_admin_invite_channel" = "This user is not a subscriber of this channel. Add them to the channel and promote them to admin?";
|
||||
"lng_sure_add_admin_unban" = "This user is currently restricted or banned. Are you sure you want to unban and promote them?";
|
||||
"lng_sure_add_admin_unremove" = "This user is currently restricted or removed. Are you sure you want to promote them?";
|
||||
"lng_sure_ban_admin" = "This user is an admin. Are you sure you want to go ahead and restrict them?";
|
||||
"lng_sure_ban_user_group" = "Ban {user} in the group?";
|
||||
"lng_sure_ban_user_channel" = "Ban {user} in the channel?";
|
||||
"lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in the Settings (Connection Type).";
|
||||
"lng_sure_enable" = "Enable";
|
||||
|
||||
@@ -156,6 +155,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_deleted" = "Deleted Account";
|
||||
"lng_deleted_message" = "Deleted message";
|
||||
"lng_pinned_message" = "Pinned message";
|
||||
"lng_pinned_poll" = "Pinned poll";
|
||||
"lng_pinned_unpin_sure" = "Would you like to unpin this message?";
|
||||
"lng_pinned_pin_sure" = "Would you like to pin this message?";
|
||||
"lng_pinned_pin" = "Pin";
|
||||
@@ -274,16 +274,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_empty_bio" = "None";
|
||||
|
||||
"lng_settings_section_notify" = "Notifications";
|
||||
"lng_settings_notify_title" = "Notifications for chats";
|
||||
"lng_settings_desktop_notify" = "Desktop notifications";
|
||||
"lng_settings_show_name" = "Show sender's name";
|
||||
"lng_settings_show_preview" = "Show message preview";
|
||||
"lng_settings_native_title" = "Native notifications";
|
||||
"lng_settings_use_windows" = "Use Windows notifications";
|
||||
"lng_settings_use_native_notifications" = "Use native notifications";
|
||||
"lng_settings_notifications_position" = "Location on the screen";
|
||||
"lng_settings_notifications_count" = "Notifications count";
|
||||
"lng_settings_sound_notify" = "Play sound";
|
||||
"lng_settings_badge_title" = "Badge counter";
|
||||
"lng_settings_include_muted" = "Include muted chats in unread count";
|
||||
"lng_settings_count_unread" = "Count unread messages";
|
||||
"lng_settings_events_title" = "Events";
|
||||
"lng_settings_events_joined" = "Contact joined Telegram";
|
||||
|
||||
"lng_notification_preview" = "You have a new message";
|
||||
"lng_notification_reply" = "Reply";
|
||||
@@ -330,6 +335,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_bg_tile" = "Tile background";
|
||||
"lng_settings_adaptive_wide" = "Adaptive layout for wide screens";
|
||||
|
||||
"lng_settings_section_call_settings" = "Calls Settings";
|
||||
"lng_settings_call_section_output" = "Speakers and headphones";
|
||||
"lng_settings_call_section_input" = "Microphone";
|
||||
"lng_settings_call_input_device" = "Input device";
|
||||
"lng_settings_call_output_device" = "Output device";
|
||||
"lng_settings_call_input_volume" = "Input volume: {percent}%";
|
||||
"lng_settings_call_output_volume" = "Output volume: {percent}%";
|
||||
"lng_settings_call_test_mic" = "Test microphone";
|
||||
"lng_settings_call_stop_mic_test" = "Stop test";
|
||||
"lng_settings_call_section_other" = "Other settings";
|
||||
"lng_settings_call_open_system_prefs" = "Open system sound preferences";
|
||||
"lng_settings_call_device_default" = "Default";
|
||||
"lng_settings_call_audio_ducking" = "Mute other sounds during calls";
|
||||
|
||||
"lng_settings_language" = "Language";
|
||||
"lng_settings_default_scale" = "Default interface scale";
|
||||
"lng_settings_connection_type" = "Connection type";
|
||||
@@ -340,6 +359,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_calls_peer_to_peer" = "Peer-to-peer in calls";
|
||||
"lng_settings_groups_invite" = "Groups";
|
||||
"lng_settings_group_privacy_about" = "Change who can add you to groups and channels.";
|
||||
"lng_settings_forwards_privacy" = "Forwarded messages";
|
||||
"lng_settings_profile_photo_privacy" = "Profile photo";
|
||||
"lng_settings_sessions_about" = "Control your sessions on other devices.";
|
||||
"lng_settings_passcode_disable" = "Disable passcode";
|
||||
"lng_settings_password_disable" = "Disable cloud password";
|
||||
@@ -376,6 +397,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_theme_reverting#other" = "Reverting to the old theme in {count} seconds.";
|
||||
"lng_theme_keep_changes" = "Keep changes";
|
||||
"lng_theme_revert" = "Revert";
|
||||
"lng_background_header" = "Background preview";
|
||||
"lng_background_text1" = "Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff!";
|
||||
"lng_background_text2" = "I can't even take you seriously right now.";
|
||||
"lng_background_bad_link" = "This background link appears to be invalid.";
|
||||
"lng_background_apply" = "Apply";
|
||||
"lng_background_share" = "Share";
|
||||
"lng_background_link_copied" = "Link copied to clipboard";
|
||||
"lng_background_blur" = "Blurred";
|
||||
"lng_background_sure_delete" = "Are you sure you want to delete this background?";
|
||||
|
||||
"lng_download_path_ask" = "Ask download path for each file";
|
||||
"lng_download_path" = "Download path";
|
||||
@@ -408,7 +438,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_local_storage_round#other" = "{count} video messages";
|
||||
"lng_local_storage_animation#one" = "{count} animation";
|
||||
"lng_local_storage_animation#other" = "{count} animations";
|
||||
"lng_local_storage_media" = "Media cache";
|
||||
"lng_local_storage_size_limit" = "Total size limit: {size}";
|
||||
"lng_local_storage_media_limit" = "Media cache limit: {size}";
|
||||
"lng_local_storage_time_limit" = "Clear files older than: {limit}";
|
||||
"lng_local_storage_limit_weeks#one" = "{count} week";
|
||||
"lng_local_storage_limit_weeks#other" = "{count} weeks";
|
||||
@@ -610,6 +642,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_privacy_calls_p2p_contacts" = "My contacts";
|
||||
"lng_edit_privacy_calls_p2p_nobody" = "Nobody";
|
||||
|
||||
"lng_edit_privacy_forwards_title" = "Forwarded messages privacy";
|
||||
"lng_edit_privacy_forwards_header" = "Who can add link to my account when forwarding my messages";
|
||||
"lng_edit_privacy_forwards_warning" = "When forwarded to other chats, messages you send will not link back to your account.";
|
||||
"lng_edit_privacy_forwards_always_empty" = "Always allow";
|
||||
"lng_edit_privacy_forwards_never_empty" = "Never allow";
|
||||
"lng_edit_privacy_forwards_exceptions" = "These settings will override the values above.";
|
||||
"lng_edit_privacy_forwards_always_title" = "Always allow";
|
||||
"lng_edit_privacy_forwards_never_title" = "Never allow";
|
||||
"lng_edit_privacy_forwards_sample_message" = "Reinhardt, we need to find you some new tunes 🎶";
|
||||
"lng_edit_privacy_forwards_sample_everyone" = "Link to your account.";
|
||||
"lng_edit_privacy_forwards_sample_contacts" = "Link if allowed by settings below.";
|
||||
"lng_edit_privacy_forwards_sample_nobody" = "Not a link to your account.";
|
||||
|
||||
"lng_edit_privacy_profile_photo_title" = "Profile photo privacy";
|
||||
"lng_edit_privacy_profile_photo_header" = "Who can see my profile photo";
|
||||
"lng_edit_privacy_profile_photo_always_empty" = "Always allow";
|
||||
"lng_edit_privacy_profile_photo_never_empty" = "Never allow";
|
||||
"lng_edit_privacy_profile_photo_exceptions" = "These settings will override the values above.";
|
||||
"lng_edit_privacy_profile_photo_always_title" = "Always allow";
|
||||
"lng_edit_privacy_profile_photo_never_title" = "Never allow";
|
||||
|
||||
"lng_self_destruct_title" = "Account self-destruction";
|
||||
"lng_self_destruct_description" = "If you don't come online at least once within this period, your account will be deleted along with all groups, messages and contacts.";
|
||||
"lng_self_destruct_months#one" = "{count} month";
|
||||
@@ -647,10 +700,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_create_public_link" = "Create public link";
|
||||
"lng_profile_edit_public_link" = "Edit public link";
|
||||
"lng_profile_search_members" = "Search members";
|
||||
"lng_profile_manage_admins" = "Manage administrators";
|
||||
"lng_profile_manage_blocklist" = "Manage banned users";
|
||||
"lng_profile_manage_restrictedlist" = "Manage restricted users";
|
||||
"lng_profile_recent_actions" = "Recent actions";
|
||||
"lng_profile_common_groups#one" = "{count} group in common";
|
||||
"lng_profile_common_groups#other" = "{count} groups in common";
|
||||
"lng_profile_participants_section" = "Members";
|
||||
@@ -678,6 +727,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_join_group" = "Join Group";
|
||||
"lng_profile_delete_and_exit" = "Leave";
|
||||
"lng_profile_kick" = "Remove";
|
||||
"lng_profile_delete_removed" = "Delete";
|
||||
"lng_profile_sure_kick" = "Remove {user} from the group?";
|
||||
"lng_profile_sure_kick_channel" = "Remove {user} from the channel?";
|
||||
"lng_profile_sure_remove_admin" = "Remove {user} from admins?";
|
||||
@@ -773,13 +823,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_manage_peer_recent_actions" = "Recent Actions";
|
||||
"lng_manage_peer_members" = "Members";
|
||||
"lng_manage_peer_administrators" = "Administrators";
|
||||
"lng_manage_peer_banned_users" = "Banned users";
|
||||
"lng_manage_peer_restricted_users" = "Restricted users";
|
||||
"lng_manage_peer_exceptions" = "Exceptions";
|
||||
"lng_manage_peer_removed_users" = "Removed users";
|
||||
"lng_manage_peer_permissions" = "Permissions";
|
||||
|
||||
"lng_manage_peer_group_type" = "Group type";
|
||||
"lng_manage_peer_channel_type" = "Channel type";
|
||||
"lng_manage_private_peer_title" = "Private";
|
||||
"lng_manage_public_peer_title" = "Public";
|
||||
|
||||
"lng_manage_history_visibility_title" = "Chat history for new members";
|
||||
"lng_manage_history_visibility_shown" = "Visible";
|
||||
"lng_manage_history_visibility_shown_about" = "New members will see messages that were sent before they joined.";
|
||||
"lng_manage_history_visibility_hidden" = "Hidden";
|
||||
"lng_manage_history_visibility_hidden_about" = "New members won't see earlier messages.";
|
||||
"lng_manage_history_visibility_hidden_legacy" = "New members won't see more than 100 previous messages.";
|
||||
|
||||
"lng_report_title" = "Report channel";
|
||||
"lng_report_group_title" = "Report group";
|
||||
@@ -794,17 +852,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_report_thanks" = "Thank you! Your report will be reviewed by our team very soon.";
|
||||
|
||||
"lng_channel_add_members" = "Add members";
|
||||
"lng_channel_add_banned" = "Ban user";
|
||||
"lng_channel_add_restricted" = "Restrict user";
|
||||
"lng_channel_add_users" = "Add users";
|
||||
"lng_channel_add_removed" = "Remove user";
|
||||
"lng_channel_add_exception" = "Add exception";
|
||||
"lng_channel_admins" = "Administrators";
|
||||
"lng_channel_add_admin" = "Add Administrator";
|
||||
"lng_channel_admin_status_creator" = "Creator";
|
||||
"lng_channel_admin_status_promoted_by" = "Promoted by {user}";
|
||||
"lng_channel_admin_status_not_admin" = "Not administrator";
|
||||
"lng_channel_banned_status_restricted_by" = "Restricted by {user}";
|
||||
"lng_channel_banned_status_removed_by" = "Removed by {user}";
|
||||
|
||||
"lng_group_blocked_list_about" = "Banned users are removed from the group and can only come back if invited by an admin.\nInvite links don't work for them.";
|
||||
"lng_channel_blocked_list_about" = "Banned users are removed from the channel.\nInvite links don't work for them.";
|
||||
"lng_channel_removed_list_about" = "Users removed from the channel by admins cannot rejoin it via invite links.";
|
||||
"lng_group_removed_list_about" = "Users removed from the group by admins cannot rejoin it via invite links.";
|
||||
|
||||
"lng_chat_all_members_admins" = "All Members Are Admins";
|
||||
"lng_chat_about_all_admins" = "Group members can add new members, edit name and photo of the group.";
|
||||
@@ -829,6 +889,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_create_private_group_about" = "People can only join if they were invited or have an invite link";
|
||||
"lng_create_group_skip" = "Skip";
|
||||
|
||||
"lng_create_channel_link_about" = "You can use a-z, 0-9 and underscores.\nMinimum length is 5 characters.";
|
||||
|
||||
"lng_create_channel_link_invalid" = "This link is invalid";
|
||||
"lng_create_channel_link_occupied" = "Sorry, this link is already occupied";
|
||||
"lng_create_channel_link_too_short" = "Sorry, this link is too short";
|
||||
@@ -884,7 +946,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_changed_title_channel" = "Channel name was changed to «{title}»";
|
||||
"lng_action_created_chat" = "{from} created group «{title}»";
|
||||
"lng_action_created_channel" = "Channel created";
|
||||
"lng_action_group_migrate" = "The group was upgraded to a supergroup";
|
||||
"lng_action_pinned_message" = "{from} pinned «{text}»";
|
||||
"lng_action_pinned_media" = "{from} pinned {media}";
|
||||
"lng_action_pinned_media_photo" = "a photo";
|
||||
@@ -939,8 +1000,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_convert_feature4" = "— Creator can set a public link for the group";
|
||||
"lng_profile_convert_warning" = "{bold_start}Note:{bold_end} This action can not be undone";
|
||||
"lng_profile_convert_confirm" = "Convert";
|
||||
"lng_profile_add_more_after_upgrade#one" = "You will be able to add up to {count} member after you upgrade your group to a supergroup.";
|
||||
"lng_profile_add_more_after_upgrade#other" = "You will be able to add up to {count} members after you upgrade your group to a supergroup.";
|
||||
"lng_profile_add_more_after_create" = "You will be able to add more members after you create the group.";
|
||||
|
||||
"lng_channel_not_accessible" = "Sorry, this channel is not accessible.";
|
||||
"lng_group_not_accessible" = "Sorry, this group is not accessible.";
|
||||
@@ -973,6 +1033,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_forwarded_via" = "Forwarded from {user} via {inline_bot}";
|
||||
"lng_forwarded_channel_via" = "Forwarded from {channel} via {inline_bot}";
|
||||
"lng_forwarded_signed" = "{channel} ({user})";
|
||||
"lng_forwarded_hidden" = "The account was hidden by the user.";
|
||||
"lng_signed_author" = "Author: {user}";
|
||||
"lng_in_reply_to" = "In reply to";
|
||||
"lng_edited" = "edited";
|
||||
"lng_edited_date" = "Edited: {date}";
|
||||
@@ -997,13 +1059,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_media_audio" = "Voice message";
|
||||
|
||||
"lng_media_auto_settings" = "Automatic media download";
|
||||
"lng_media_auto_in_private" = "In private chats";
|
||||
"lng_media_auto_in_groups" = "In groups";
|
||||
"lng_media_auto_in_channels" = "In channels";
|
||||
"lng_media_auto_title" = "Automatically download";
|
||||
"lng_media_photo_title" = "Photos";
|
||||
"lng_media_video_title" = "Video files";
|
||||
"lng_media_audio_title" = "Voice messages";
|
||||
"lng_media_gif_title" = "GIFs and animations";
|
||||
"lng_media_auto_private_chats" = "Private chats";
|
||||
"lng_media_auto_groups" = "Groups and channels";
|
||||
"lng_media_auto_play" = "Autoplay";
|
||||
"lng_media_video_messages_title" = "Round video messages";
|
||||
"lng_media_file_title" = "Files";
|
||||
"lng_media_music_title" = "Music";
|
||||
"lng_media_animation_title" = "Animated GIFs";
|
||||
"lng_media_size_limit" = "Limit by size";
|
||||
"lng_media_size_up_to" = "up to {size}";
|
||||
"lng_media_chat_background" = "Chat background";
|
||||
|
||||
"lng_emoji_category1" = "People";
|
||||
"lng_emoji_category2" = "Nature";
|
||||
@@ -1013,6 +1082,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_emoji_category6" = "Objects";
|
||||
"lng_emoji_category7" = "Symbols & Flags";
|
||||
"lng_emoji_hide_panel" = "Click here to hide the emoji sidebar";
|
||||
"lng_emoji_manage_sets" = "Choose emoji set";
|
||||
"lng_emoji_set_ready" = "Downloaded";
|
||||
"lng_emoji_set_active" = "Current set";
|
||||
"lng_emoji_set_download" = "Download {size}";
|
||||
"lng_emoji_set_loading" = "{percent}, {progress}";
|
||||
|
||||
"lng_recent_stickers" = "Frequently used";
|
||||
"lng_faved_stickers_add" = "Add to Favorites";
|
||||
@@ -1021,6 +1095,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_stickers_description" = "You can choose a sticker set which will be available for every member while in the group chat.";
|
||||
"lng_group_stickers_add" = "Choose sticker set";
|
||||
|
||||
"lng_group_about_header" = "You have created a group.";
|
||||
"lng_group_about_text" = "Groups can have:";
|
||||
"lng_group_about1" = "Up to 100,000 members";
|
||||
"lng_group_about2" = "Persistent chat history";
|
||||
"lng_group_about3" = "Public links such as t.me/title";
|
||||
"lng_group_about4" = "Admins with different rights";
|
||||
|
||||
"lng_switch_stickers" = "Stickers";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
"lng_switch_gifs" = "GIFs";
|
||||
@@ -1048,6 +1129,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stickers_count#one" = "{count} sticker";
|
||||
"lng_stickers_count#other" = "{count} stickers";
|
||||
"lng_stickers_masks_pack" = "This is a pack of mask stickers. You can use them in the photo editor on our mobile apps.";
|
||||
"lng_stickers_attached_sets" = "Sets of attached stickers";
|
||||
"lng_stickers_group_set" = "Group sticker set";
|
||||
"lng_stickers_remove_group_set" = "Remove group sticker set?";
|
||||
"lng_stickers_group_from_your" = "Choose from your stickers";
|
||||
@@ -1066,6 +1148,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_in_dlg_file" = "File";
|
||||
"lng_in_dlg_sticker" = "Sticker";
|
||||
"lng_in_dlg_sticker_emoji" = "{emoji} Sticker";
|
||||
"lng_in_dlg_poll" = "Poll";
|
||||
|
||||
"lng_ban_user" = "Ban User";
|
||||
"lng_delete_all_from" = "Delete all from this user";
|
||||
@@ -1082,7 +1165,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_cant_invite_banned" = "Sorry, only admin can add this user.";
|
||||
"lng_cant_invite_privacy" = "Sorry, you cannot add this user to groups because of their privacy settings.";
|
||||
"lng_cant_invite_privacy_channel" = "Sorry, you cannot add this user to channels because of their privacy settings.";
|
||||
"lng_cant_invite_bot_to_channel" = "Sorry, bots can only be added to channels as administrators.";
|
||||
"lng_cant_do_this" = "Sorry, this action is unavailable.";
|
||||
"lng_cant_invite_offer_admin" = "Bots can only be added as administrators.";
|
||||
"lng_cant_invite_make_admin" = "Make admin";
|
||||
|
||||
"lng_send_button" = "Send";
|
||||
"lng_message_ph" = "Write a message...";
|
||||
@@ -1184,6 +1270,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_edit_permissions" = "Edit permissions";
|
||||
"lng_context_restrict_user" = "Restrict user";
|
||||
"lng_context_remove_from_group" = "Remove from group";
|
||||
"lng_context_add_to_group" = "Add to group";
|
||||
|
||||
"lng_context_copy_link" = "Copy Link";
|
||||
"lng_context_copy_post_link" = "Copy Post Link";
|
||||
@@ -1204,6 +1291,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_copy_text" = "Copy Text";
|
||||
"lng_context_open_gif" = "Open GIF";
|
||||
"lng_context_save_gif" = "Save GIF";
|
||||
"lng_context_attached_stickers" = "Attached Stickers";
|
||||
"lng_context_to_msg" = "Go To Message";
|
||||
"lng_context_reply_msg" = "Reply";
|
||||
"lng_context_edit_msg" = "Edit";
|
||||
@@ -1267,9 +1355,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_contact_title" = "Edit contact name";
|
||||
"lng_edit_channel_title" = "Edit channel";
|
||||
"lng_edit_sign_messages" = "Sign messages";
|
||||
"lng_edit_group_who_invites" = "Who can add members";
|
||||
"lng_edit_group_invites_everybody" = "All members";
|
||||
"lng_edit_group_invites_only_admins" = "Only admins";
|
||||
"lng_edit_group" = "Edit group";
|
||||
"lng_edit_self_title" = "Edit your name";
|
||||
"lng_confirm_contact_data" = "New Contact";
|
||||
@@ -1305,8 +1390,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_delete_for_me_chat_hint#other" = "This will delete them just for you, not for other participants of the chat.";
|
||||
"lng_delete_for_me_hint#one" = "This will delete it just for you.";
|
||||
"lng_delete_for_me_hint#other" = "This will delete them just for you.";
|
||||
"lng_selected_unsend_about_user_one" = "You can also delete the message you sent from {user}'s inbox by checking \"Unsend my messages\".";
|
||||
"lng_selected_unsend_about_user#one" = "You can also delete the {count} message you sent from {user}'s inbox by checking \"Unsend my messages\".";
|
||||
"lng_selected_unsend_about_user#other" = "You can also delete the {count} messages you sent from {user}'s inbox by checking \"Unsend my messages\".";
|
||||
"lng_selected_unsend_about_group_one" = "You can also delete the message you sent from the inboxes of other group members by checking \"Unsend my messages\".";
|
||||
"lng_selected_unsend_about_group#one" = "You can also delete the {count} message you sent from the inboxes of other group members by checking \"Unsend my messages\".";
|
||||
"lng_selected_unsend_about_group#other" = "You can also delete the {count} messages you sent from the inboxes of other group members by checking \"Unsend my messages\".";
|
||||
"lng_delete_for_everyone_check" = "Delete for everyone";
|
||||
"lng_delete_for_other_check" = "Delete for {user}";
|
||||
"lng_delete_for_other_check" = "Also delete for {user}";
|
||||
"lng_delete_for_other_my" = "Unsend my messages";
|
||||
"lng_box_delete" = "Delete";
|
||||
"lng_box_leave" = "Leave";
|
||||
|
||||
@@ -1361,7 +1453,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_menu_formatting_link_edit" = "Edit link";
|
||||
"lng_menu_formatting_clear" = "Plain text";
|
||||
"lng_formatting_link_create_title" = "Create link";
|
||||
"lng_formatting_link_edit_title" = "Create link";
|
||||
"lng_formatting_link_edit_title" = "Edit link";
|
||||
"lng_formatting_link_text" = "Text";
|
||||
"lng_formatting_link_url" = "URL";
|
||||
"lng_formatting_link_create" = "Create";
|
||||
@@ -1439,14 +1531,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_player_message_today" = "Today at {time}";
|
||||
"lng_player_message_yesterday" = "Yesterday at {time}";
|
||||
"lng_player_message_date" = "{date} at {time}";
|
||||
//"lng_player_cant_stream" = "This file can't be played before it is fully downloaded.\n\nWould you like to download it?";
|
||||
"lng_player_download" = "Download";
|
||||
|
||||
"lng_rights_edit_admin" = "Manage permissions";
|
||||
"lng_rights_edit_admin_header" = "What can this admin do?";
|
||||
"lng_rights_about_add_admins_yes" = "This admin will be able to add new admins with the same (or more limited) permissions.";
|
||||
"lng_rights_about_add_admins_no" = "This admin will not be able to add new admins.";
|
||||
"lng_rights_about_admin_cant_edit" = "You cannot edit rights of this admin.";
|
||||
|
||||
"lng_rights_about_admin_cant_edit" = "You are not allowed to edit the rights of this admin.";
|
||||
"lng_rights_about_restriction_cant_edit" = "You cannot change the restrictions for this user.";
|
||||
"lng_rights_restriction_for_all" = "This option is disabled for all members in Group Permissions. You can either enable the permission for everyone or make this user an admin.";
|
||||
"lng_rights_permission_for_all" = "This option is enabled for all members in Group Permissions.";
|
||||
"lng_rights_permission_unavailable" = "This permission is not available in public groups.";
|
||||
"lng_rights_permission_cant_edit" = "You cannot edit this permission.";
|
||||
"lng_rights_user_restrictions" = "User restrictions";
|
||||
"lng_rights_user_restrictions_header" = "What can this user do?";
|
||||
"lng_rights_user_restrictions_header" = "What can this member do?";
|
||||
"lng_rights_default_restrictions_header" = "What can members of this group do?";
|
||||
|
||||
"lng_rights_channel_info" = "Change channel info";
|
||||
"lng_rights_channel_post" = "Post messages";
|
||||
@@ -1464,6 +1565,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_rights_chat_send_media" = "Send media";
|
||||
"lng_rights_chat_send_stickers" = "Send stickers & GIFs";
|
||||
"lng_rights_chat_send_links" = "Embed links";
|
||||
"lng_rights_chat_send_polls" = "Send polls";
|
||||
"lng_rights_chat_add_members" = "Add members";
|
||||
"lng_rights_chat_banned_until_header" = "Restricted until";
|
||||
"lng_rights_chat_banned_forever" = "Forever";
|
||||
"lng_rights_chat_banned_day#one" = "For {count} day";
|
||||
@@ -1478,9 +1581,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_restricted_send_stickers" = "The admins of this group restricted you from posting stickers here.";
|
||||
"lng_restricted_send_gifs" = "The admins of this group restricted you from posting GIFs here.";
|
||||
"lng_restricted_send_inline" = "The admins of this group restricted you from posting inline content here.";
|
||||
"lng_restricted_send_polls" = "The admins of this group restricted you from posting polls here.";
|
||||
|
||||
"lng_restricted_list_title" = "Restricted users";
|
||||
"lng_banned_list_title" = "Banned users";
|
||||
"lng_restricted_send_message_all" = "Writing messages isn't allowed in this group.";
|
||||
"lng_restricted_send_media_all" = "Posting media content isn't allowed in this group.";
|
||||
"lng_restricted_send_stickers_all" = "Posting stickers isn't allowed in this group.";
|
||||
"lng_restricted_send_gifs_all" = "Posting GIFs isn't allowed in this group.";
|
||||
"lng_restricted_send_inline_all" = "Posting inline content isn't allowed in this group.";
|
||||
"lng_restricted_send_polls_all" = "Posting polls isn't allowed in this group.";
|
||||
|
||||
"lng_exceptions_list_title" = "Exceptions";
|
||||
"lng_removed_list_title" = "Removed users";
|
||||
|
||||
"lng_admin_log_title_all" = "All actions";
|
||||
"lng_admin_log_title_selected" = "Selected actions";
|
||||
@@ -1540,10 +1651,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_participant_joined_channel" = "{from} joined the channel";
|
||||
"lng_admin_log_participant_left" = "{from} left the group";
|
||||
"lng_admin_log_participant_left_channel" = "{from} left the channel";
|
||||
"lng_admin_log_stopped_poll" = "{from} stopped poll:";
|
||||
"lng_admin_log_invited" = "invited {user}";
|
||||
"lng_admin_log_banned" = "banned {user}";
|
||||
"lng_admin_log_restricted" = "changed restrictions for {user} {until}";
|
||||
"lng_admin_log_promoted" = "changed privileges for {user}";
|
||||
"lng_admin_log_changed_default_permissions" = "changed default permissions";
|
||||
"lng_admin_log_changed_stickers_group" = "{from} changed the group's {sticker_set}";
|
||||
"lng_admin_log_changed_stickers_set" = "sticker set";
|
||||
"lng_admin_log_removed_stickers_group" = "{from} removed the group's sticker set";
|
||||
@@ -1555,12 +1668,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_banned_send_media" = "Send media";
|
||||
"lng_admin_log_banned_send_stickers" = "Send stickers & GIFs";
|
||||
"lng_admin_log_banned_embed_links" = "Embed links";
|
||||
"lng_admin_log_banned_send_polls" = "Send polls";
|
||||
"lng_admin_log_admin_change_info" = "Change info";
|
||||
"lng_admin_log_admin_post_messages" = "Post messages";
|
||||
"lng_admin_log_admin_edit_messages" = "Edit messages";
|
||||
"lng_admin_log_admin_delete_messages" = "Delete messages";
|
||||
"lng_admin_log_admin_ban_users" = "Ban users";
|
||||
"lng_admin_log_admin_invite_users" = "Add users";
|
||||
"lng_admin_log_admin_invite_users" = "Add members";
|
||||
"lng_admin_log_admin_invite_link" = "Invite users via link";
|
||||
"lng_admin_log_admin_pin_messages" = "Pin messages";
|
||||
"lng_admin_log_admin_add_admins" = "Add new admins";
|
||||
@@ -1829,6 +1943,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_launch_exe_sure" = "Run";
|
||||
"lng_launch_exe_dont_ask" = "Don't ask me again";
|
||||
|
||||
"lng_polls_anonymous" = "Anonymous Poll";
|
||||
"lng_polls_closed" = "Final results";
|
||||
"lng_polls_votes_count#one" = "{count} vote";
|
||||
"lng_polls_votes_count#other" = "{count} votes";
|
||||
"lng_polls_votes_none" = "No votes";
|
||||
"lng_polls_retract" = "Retract vote";
|
||||
"lng_polls_stop" = "Stop poll";
|
||||
"lng_polls_stop_warning" = "If you stop this poll now, nobody will be able to vote in it anymore. This action cannot be undone.";
|
||||
"lng_polls_stop_sure" = "Stop";
|
||||
"lng_polls_create" = "Create poll";
|
||||
"lng_polls_create_title" = "New poll";
|
||||
"lng_polls_create_question" = "Question";
|
||||
"lng_polls_create_question_placeholder" = "Ask a question";
|
||||
"lng_polls_create_options" = "Poll options";
|
||||
"lng_polls_create_option_add" = "Add an option...";
|
||||
"lng_polls_create_limit#one" = "You can add {count} more option.";
|
||||
"lng_polls_create_limit#other" = "You can add {count} more options.";
|
||||
"lng_polls_create_maximum" = "You have added the maximum number of options.";
|
||||
"lng_polls_create_button" = "Create";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
||||
@@ -1841,6 +1975,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_linux_menu_undo" = "Undo";
|
||||
"lng_linux_menu_redo" = "Redo";
|
||||
|
||||
"lng_linux_no_audio_prefs" = "You don't have any audio configuration applications installed.";
|
||||
|
||||
// Mac specific
|
||||
|
||||
"lng_mac_choose_program_menu" = "Other...";
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
52;MX;Mexico;
|
||||
51;PE;Peru;51 XXX XXX XXX;11;
|
||||
49;DE;Germany;49 XXX XXXXXXXX;13;
|
||||
48;PL;Poland;48 XX XXX XXXX;11;
|
||||
48;PL;Poland;48 XXX XXX XXX;11;
|
||||
47;NO;Norway;47 XXXX XXXX;10;
|
||||
46;SE;Sweden;46 XX XXX XXXX;11;
|
||||
45;DK;Denmark;45 XXXX XXXX;10;
|
||||
|
||||
8
Telegram/Resources/qrc/telegram_emoji_preview.qrc
Normal file
@@ -0,0 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/set0_preview.webp">../emoji/set0_preview.webp</file>
|
||||
<file alias="emoji/set1_preview.webp">../emoji/set1_preview.webp</file>
|
||||
<file alias="emoji/set2_preview.webp">../emoji/set2_preview.webp</file>
|
||||
<file alias="emoji/set3_preview.webp">../emoji/set3_preview.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -176,7 +176,8 @@ inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = In
|
||||
inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
|
||||
inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
|
||||
inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia;
|
||||
inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
|
||||
inputMediaPoll#6b3765b poll:Poll = InputMedia;
|
||||
|
||||
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
|
||||
inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
|
||||
@@ -194,8 +195,6 @@ inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes
|
||||
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
|
||||
inputTakeoutFileLocation#29be5899 = InputFileLocation;
|
||||
|
||||
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
|
||||
|
||||
peerUser#9db1bc6d user_id:int = Peer;
|
||||
peerChat#bad0e5bb chat_id:int = Peer;
|
||||
peerChannel#bddde532 channel_id:int = Peer;
|
||||
@@ -215,7 +214,7 @@ fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileL
|
||||
fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation;
|
||||
|
||||
userEmpty#200250ba id:int = User;
|
||||
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
|
||||
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
|
||||
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
|
||||
@@ -228,13 +227,13 @@ userStatusLastWeek#7bf09fc = UserStatus;
|
||||
userStatusLastMonth#77ebc742 = UserStatus;
|
||||
|
||||
chatEmpty#9ba2d800 id:int = Chat;
|
||||
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
|
||||
chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
||||
chatForbidden#7328bdb id:int title:string = Chat;
|
||||
channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
|
||||
channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
|
||||
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
|
||||
|
||||
chatFull#edd2a791 flags:# id:int participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int = ChatFull;
|
||||
channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
|
||||
chatFull#22a235da flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int = ChatFull;
|
||||
channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
|
||||
|
||||
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
|
||||
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
|
||||
@@ -261,6 +260,7 @@ messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:str
|
||||
messageMediaGame#fdb19008 game:Game = MessageMedia;
|
||||
messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
|
||||
messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
|
||||
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
|
||||
|
||||
messageActionEmpty#b6aef7b0 = MessageAction;
|
||||
messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
|
||||
@@ -284,6 +284,7 @@ messageActionCustomAction#fae69f56 message:string = MessageAction;
|
||||
messageActionBotAllowed#abe9affe domain:string = MessageAction;
|
||||
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
|
||||
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
|
||||
messageActionContactSignUp#f3f25f76 = MessageAction;
|
||||
|
||||
dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
|
||||
|
||||
@@ -293,6 +294,7 @@ photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_r
|
||||
photoSizeEmpty#e17e23c type:string = PhotoSize;
|
||||
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
|
||||
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
|
||||
photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
|
||||
|
||||
geoPointEmpty#1117dd5f = GeoPoint;
|
||||
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
|
||||
@@ -316,12 +318,12 @@ peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bo
|
||||
|
||||
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
|
||||
|
||||
wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper;
|
||||
wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper;
|
||||
wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
|
||||
|
||||
inputReportReasonSpam#58dbcab8 = ReportReason;
|
||||
inputReportReasonViolence#1e22c78d = ReportReason;
|
||||
inputReportReasonPornography#2e59d922 = ReportReason;
|
||||
inputReportReasonChildAbuse#adf44ee3 = ReportReason;
|
||||
inputReportReasonOther#e1746d0a text:string = ReportReason;
|
||||
inputReportReasonCopyright#9b89f93a = ReportReason;
|
||||
|
||||
@@ -350,8 +352,8 @@ messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<
|
||||
messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs;
|
||||
|
||||
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.messagesSlice#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.messagesNotModified#74535f21 count:int = messages.Messages;
|
||||
|
||||
messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats;
|
||||
@@ -387,7 +389,6 @@ updateChatParticipants#7761198 participants:ChatParticipants = Update;
|
||||
updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
|
||||
updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update;
|
||||
updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update;
|
||||
updateContactRegistered#2575bbb9 user_id:int date:int = Update;
|
||||
updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update;
|
||||
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
|
||||
updateEncryptedChatTyping#1710f156 chat_id:int = Update;
|
||||
@@ -411,7 +412,6 @@ updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
|
||||
updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update;
|
||||
updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update;
|
||||
updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
|
||||
updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update;
|
||||
updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
|
||||
updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
|
||||
updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update;
|
||||
@@ -446,7 +446,9 @@ updateContactsReset#7084a7be = Update;
|
||||
updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
|
||||
updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update;
|
||||
updateUserPinnedMessage#4c43da18 user_id:int id:int = Update;
|
||||
updateChatPinnedMessage#22893b26 chat_id:int id:int = Update;
|
||||
updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update;
|
||||
updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update;
|
||||
updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@@ -473,7 +475,7 @@ upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes
|
||||
|
||||
dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
|
||||
|
||||
config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
|
||||
config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
|
||||
|
||||
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
|
||||
|
||||
@@ -511,7 +513,7 @@ inputDocumentEmpty#72f0eaae = InputDocument;
|
||||
inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument;
|
||||
|
||||
documentEmpty#36f8c871 id:long = Document;
|
||||
document#59534e4c id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = Document;
|
||||
document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;
|
||||
|
||||
help.support#17c6b5f6 phone_number:string user:User = help.Support;
|
||||
|
||||
@@ -540,11 +542,15 @@ inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
|
||||
inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey;
|
||||
inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey;
|
||||
inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey;
|
||||
inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey;
|
||||
inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey;
|
||||
|
||||
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
|
||||
privacyKeyChatInvite#500e6dfa = PrivacyKey;
|
||||
privacyKeyPhoneCall#3d662b7b = PrivacyKey;
|
||||
privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
|
||||
privacyKeyForwards#69ec56a3 = PrivacyKey;
|
||||
privacyKeyProfilePhoto#96151fed = PrivacyKey;
|
||||
|
||||
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
|
||||
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
|
||||
@@ -616,7 +622,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
|
||||
|
||||
stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
|
||||
stickerSet#6a90bcb7 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize count:int hash:int = StickerSet;
|
||||
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
|
||||
@@ -673,8 +679,8 @@ channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:
|
||||
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
|
||||
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
|
||||
channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant;
|
||||
channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant;
|
||||
channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant;
|
||||
channelParticipantAdmin#5daa6e23 flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights = ChannelParticipant;
|
||||
channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
|
||||
|
||||
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
|
||||
channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter;
|
||||
@@ -682,6 +688,7 @@ channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter;
|
||||
channelParticipantsBots#b0d1865b = ChannelParticipantsFilter;
|
||||
channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter;
|
||||
channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter;
|
||||
channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter;
|
||||
|
||||
channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants;
|
||||
channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;
|
||||
@@ -723,7 +730,7 @@ messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_off
|
||||
|
||||
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
|
||||
|
||||
messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
|
||||
messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
|
||||
|
||||
auth.codeTypeSms#72a3158c = auth.CodeType;
|
||||
auth.codeTypeCall#741cd3e3 = auth.CodeType;
|
||||
@@ -916,11 +923,7 @@ langPackStringDeleted#2979eeb2 key:string = LangPackString;
|
||||
|
||||
langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector<LangPackString> = LangPackDifference;
|
||||
|
||||
langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage;
|
||||
|
||||
channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights;
|
||||
|
||||
channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights;
|
||||
langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage;
|
||||
|
||||
channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction;
|
||||
@@ -938,6 +941,8 @@ channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:Channel
|
||||
channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
|
||||
|
||||
channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
|
||||
|
||||
@@ -1057,6 +1062,17 @@ secureRequiredTypeOneOf#27477b4 types:Vector<SecureRequiredType> = SecureRequire
|
||||
help.passportConfigNotModified#bfb9f457 = help.PassportConfig;
|
||||
help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig;
|
||||
|
||||
inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent;
|
||||
|
||||
jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue;
|
||||
|
||||
jsonNull#3f6d7b68 = JSONValue;
|
||||
jsonBool#c7345e6a value:Bool = JSONValue;
|
||||
jsonNumber#2be0dfa4 value:double = JSONValue;
|
||||
jsonString#b71e767a value:string = JSONValue;
|
||||
jsonArray#f7444763 value:Vector<JSONValue> = JSONValue;
|
||||
jsonObject#99c1d49d value:Vector<JSONObjectValue> = JSONValue;
|
||||
|
||||
pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell;
|
||||
|
||||
pageTableRow#e0c0c5e5 cells:Vector<PageTableCell> = PageTableRow;
|
||||
@@ -1071,13 +1087,50 @@ pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector<PageBlock> = PageLis
|
||||
|
||||
pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle;
|
||||
|
||||
page#ae891bec flags:# part:flags.0?true rtl:flags.1?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page;
|
||||
page#ae891bec flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page;
|
||||
|
||||
help.supportName#8c05f1c9 name:string = help.SupportName;
|
||||
|
||||
help.userInfoEmpty#f3ae2eed = help.UserInfo;
|
||||
help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:string date:int = help.UserInfo;
|
||||
|
||||
pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer;
|
||||
|
||||
poll#d5529d06 id:long flags:# closed:flags.0?true question:string answers:Vector<PollAnswer> = Poll;
|
||||
|
||||
pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true option:bytes voters:int = PollAnswerVoters;
|
||||
|
||||
pollResults#5755785a flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int = PollResults;
|
||||
|
||||
chatOnlines#f041e250 onlines:int = ChatOnlines;
|
||||
|
||||
statsURL#47a971e0 url:string = StatsURL;
|
||||
|
||||
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights;
|
||||
|
||||
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
|
||||
|
||||
inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
|
||||
inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
|
||||
|
||||
account.wallPapersNotModified#1c199183 = account.WallPapers;
|
||||
account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
|
||||
|
||||
codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings;
|
||||
|
||||
wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings;
|
||||
|
||||
autoDownloadSettings#d246fd47 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_max:int = AutoDownloadSettings;
|
||||
|
||||
account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings;
|
||||
|
||||
emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector<string> = EmojiKeyword;
|
||||
emojiKeywordDeleted#236df622 keyword:string emoticons:Vector<string> = EmojiKeyword;
|
||||
|
||||
emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector<EmojiKeyword> = EmojiKeywordsDifference;
|
||||
|
||||
emojiURL#a575739d url:string = EmojiURL;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@@ -1088,7 +1141,7 @@ invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
|
||||
invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
|
||||
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
|
||||
|
||||
auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode;
|
||||
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
|
||||
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
|
||||
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
|
||||
auth.logOut#5717da40 = Bool;
|
||||
@@ -1111,7 +1164,7 @@ account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
|
||||
account.resetNotifySettings#db7e1747 = Bool;
|
||||
account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
|
||||
account.updateStatus#6628562c offline:Bool = Bool;
|
||||
account.getWallPapers#c04cfac2 = Vector<WallPaper>;
|
||||
account.getWallPapers#aabb1763 hash:int = account.WallPapers;
|
||||
account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool;
|
||||
account.checkUsername#2714d86c username:string = Bool;
|
||||
account.updateUsername#3e0bdd7c username:string = User;
|
||||
@@ -1120,7 +1173,7 @@ account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> =
|
||||
account.deleteAccount#418d4e0b reason:string = Bool;
|
||||
account.getAccountTTL#8fc711d = AccountDaysTTL;
|
||||
account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;
|
||||
account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
|
||||
account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode;
|
||||
account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User;
|
||||
account.updateDeviceLocked#38df3532 period:int = Bool;
|
||||
account.getAuthorizations#e320c158 = account.Authorizations;
|
||||
@@ -1128,7 +1181,7 @@ account.resetAuthorization#df77f3bc hash:long = Bool;
|
||||
account.getPassword#548a30f5 = account.Password;
|
||||
account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings;
|
||||
account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool;
|
||||
account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode;
|
||||
account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode;
|
||||
account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
|
||||
account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword;
|
||||
account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
|
||||
@@ -1140,7 +1193,7 @@ account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long =
|
||||
account.deleteSecureValue#b880bc4b types:Vector<SecureValueType> = Bool;
|
||||
account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm;
|
||||
account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector<SecureValueHash> credentials:SecureCredentialsEncrypted = Bool;
|
||||
account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
|
||||
account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode;
|
||||
account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool;
|
||||
account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode;
|
||||
account.verifyEmail#ecba39db email:string code:string = Bool;
|
||||
@@ -1149,6 +1202,16 @@ account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool;
|
||||
account.confirmPasswordEmail#8fdf1920 code:string = Bool;
|
||||
account.resendPasswordEmail#7a7f2a15 = Bool;
|
||||
account.cancelPasswordEmail#c1cbd5b6 = Bool;
|
||||
account.getContactSignUpNotification#9f07c728 = Bool;
|
||||
account.setContactSignUpNotification#cff43f61 silent:Bool = Bool;
|
||||
account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates;
|
||||
account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper;
|
||||
account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
|
||||
account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool;
|
||||
account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool;
|
||||
account.resetWallPapers#bb3b9804 = Bool;
|
||||
account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings;
|
||||
account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
@@ -1160,11 +1223,10 @@ contacts.getContacts#c023849f hash:int = contacts.Contacts;
|
||||
contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts;
|
||||
contacts.deleteContact#8e953744 id:InputUser = contacts.Link;
|
||||
contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool;
|
||||
contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool;
|
||||
contacts.block#332b49fc id:InputUser = Bool;
|
||||
contacts.unblock#e54100bd id:InputUser = Bool;
|
||||
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
|
||||
contacts.exportCard#84e53737 = Vector<int>;
|
||||
contacts.importCard#4fe196fe export_card:Vector<int> = User;
|
||||
contacts.search#11f812d8 q:string limit:int = contacts.Found;
|
||||
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
|
||||
contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers;
|
||||
@@ -1178,7 +1240,7 @@ messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int
|
||||
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
|
||||
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory;
|
||||
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
|
||||
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
|
||||
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
||||
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
|
||||
@@ -1211,7 +1273,7 @@ messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages
|
||||
messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers;
|
||||
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
|
||||
messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
|
||||
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
|
||||
messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite;
|
||||
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
|
||||
messages.importChatInvite#6c50051c hash:string = Updates;
|
||||
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
|
||||
@@ -1219,7 +1281,6 @@ messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = m
|
||||
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
|
||||
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
|
||||
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
|
||||
messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates;
|
||||
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
|
||||
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
|
||||
messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
@@ -1230,10 +1291,10 @@ messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
|
||||
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
||||
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
|
||||
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
|
||||
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
|
||||
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
|
||||
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
||||
messages.editMessage#c000e4c8 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Updates;
|
||||
messages.editInlineBotMessage#adc3e828 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Bool;
|
||||
messages.editMessage#d116f31e flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
|
||||
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
|
||||
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
|
||||
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
|
||||
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
|
||||
@@ -1274,6 +1335,15 @@ messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogP
|
||||
messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>;
|
||||
messages.clearAllDrafts#7e58ee9c = Bool;
|
||||
messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates;
|
||||
messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector<bytes> = Updates;
|
||||
messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates;
|
||||
messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines;
|
||||
messages.getStatsURL#812c2ae6 flags:# dark:flags.0?true peer:InputPeer params:string = StatsURL;
|
||||
messages.editChatAbout#def60797 peer:InputPeer about:string = Bool;
|
||||
messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates;
|
||||
messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference;
|
||||
messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference;
|
||||
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@@ -1296,7 +1366,6 @@ upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector<Fil
|
||||
help.getConfig#c4f9186b = Config;
|
||||
help.getNearestDc#1fb33026 = NearestDc;
|
||||
help.getAppUpdate#522d5a7d source:string = help.AppUpdate;
|
||||
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
|
||||
help.getInviteText#4d392343 = help.InviteText;
|
||||
help.getSupport#9cdf08cd = help.Support;
|
||||
help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
|
||||
@@ -1307,6 +1376,8 @@ help.getProxyData#3d7758e1 = help.ProxyData;
|
||||
help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
|
||||
help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
|
||||
help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
|
||||
help.getAppConfig#98914110 = JSONValue;
|
||||
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
|
||||
help.getPassportConfig#c661ad08 hash:int = help.PassportConfig;
|
||||
help.getSupportName#d360e72c = help.SupportName;
|
||||
help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo;
|
||||
@@ -1322,8 +1393,7 @@ channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channe
|
||||
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
|
||||
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
|
||||
channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates;
|
||||
channels.editAbout#13e27f1e channel:InputChannel about:string = Bool;
|
||||
channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates;
|
||||
channels.editAdmin#70f893ba channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights = Updates;
|
||||
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
|
||||
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
|
||||
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
|
||||
@@ -1331,14 +1401,11 @@ channels.updateUsername#3514b3de channel:InputChannel username:string = Bool;
|
||||
channels.joinChannel#24b524c5 channel:InputChannel = Updates;
|
||||
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
|
||||
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
|
||||
channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite;
|
||||
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
|
||||
channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
|
||||
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates;
|
||||
channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats;
|
||||
channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates;
|
||||
channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates;
|
||||
channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
|
||||
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
|
||||
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
|
||||
@@ -1367,13 +1434,13 @@ phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtoc
|
||||
phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||
phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool;
|
||||
phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates;
|
||||
phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates;
|
||||
phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
|
||||
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
|
||||
|
||||
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
|
||||
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
|
||||
langpack.getDifference#9d51e814 lang_code:string from_version:int = LangPackDifference;
|
||||
langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference;
|
||||
langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>;
|
||||
langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage;
|
||||
|
||||
// LAYER 89
|
||||
// LAYER 97
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="1.5.2.0" />
|
||||
Version="1.6.2.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,5,2,0
|
||||
PRODUCTVERSION 1,5,2,0
|
||||
FILEVERSION 1,6,2,0
|
||||
PRODUCTVERSION 1,6,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -52,10 +52,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "1.5.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
|
||||
VALUE "FileVersion", "1.6.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2019"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.5.2.0"
|
||||
VALUE "ProductVersion", "1.6.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,5,2,0
|
||||
PRODUCTVERSION 1,5,2,0
|
||||
FILEVERSION 1,6,2,0
|
||||
PRODUCTVERSION 1,6,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -43,10 +43,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "1.5.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
|
||||
VALUE "FileVersion", "1.6.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2019"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.5.2.0"
|
||||
VALUE "ProductVersion", "1.6.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -7,9 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
#ifdef small
|
||||
#undef small
|
||||
#endif // small
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4091)
|
||||
#include <DbgHelp.h>
|
||||
|
||||
@@ -6,6 +6,7 @@ For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
NSString *appName = @"Telegram.app";
|
||||
NSString *appDir = nil;
|
||||
@@ -44,6 +45,20 @@ void writeLog(NSString *msg) {
|
||||
[_logFile synchronizeFile];
|
||||
}
|
||||
|
||||
void RemoveQuarantineAttribute(NSString *path) {
|
||||
const char *kQuarantineAttribute = "com.apple.quarantine";
|
||||
|
||||
writeLog([@"Removing quarantine: " stringByAppendingString:path]);
|
||||
removexattr([path fileSystemRepresentation], kQuarantineAttribute, 0);
|
||||
}
|
||||
|
||||
void RemoveQuarantineFromBundle(NSString *path) {
|
||||
RemoveQuarantineAttribute(path);
|
||||
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/MacOS/Telegram"]);
|
||||
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/Helpers/crashpad_handler"]);
|
||||
RemoveQuarantineAttribute([path stringByAppendingString:@"/Contents/Frameworks/Updater"]);
|
||||
}
|
||||
|
||||
void delFolder() {
|
||||
writeLog([@"Fully clearing old path: " stringByAppendingString:[workDir stringByAppendingString:@"tupdates/ready"]]);
|
||||
if (![[NSFileManager defaultManager] removeItemAtPath:[workDir stringByAppendingString:@"tupdates/ready"] error:nil]) {
|
||||
@@ -232,6 +247,9 @@ int main(int argc, const char * argv[]) {
|
||||
}
|
||||
|
||||
NSString *appPath = [[NSArray arrayWithObjects:appDir, appRealName, nil] componentsJoinedByString:@""];
|
||||
|
||||
RemoveQuarantineFromBundle(appPath);
|
||||
|
||||
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects: @"-noupdate", nil];
|
||||
if (toSettings) [args addObject:@"-tosettings"];
|
||||
if (_debug) [args addObject:@"-debug"];
|
||||
@@ -248,18 +266,24 @@ int main(int argc, const char * argv[]) {
|
||||
[args addObject:workDir];
|
||||
}
|
||||
writeLog([[NSArray arrayWithObjects:@"Running application '", appPath, @"' with args '", [args componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]);
|
||||
NSError *error = nil;
|
||||
NSRunningApplication *result = [[NSWorkspace sharedWorkspace]
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
NSError *error = nil;
|
||||
NSRunningApplication *result = [[NSWorkspace sharedWorkspace]
|
||||
launchApplicationAtURL:[NSURL fileURLWithPath:appPath]
|
||||
options:NSWorkspaceLaunchDefault
|
||||
configuration:[NSDictionary
|
||||
dictionaryWithObject:args
|
||||
forKey:NSWorkspaceLaunchConfigurationArguments]
|
||||
error:&error];
|
||||
if (!result) {
|
||||
if (result) {
|
||||
closeLog();
|
||||
return 0;
|
||||
}
|
||||
writeLog([[NSString stringWithFormat:@"Could not run application, error %ld: ", (long)[error code]] stringByAppendingString: error ? [error localizedDescription] : @"(nil)"]);
|
||||
usleep(200000);
|
||||
}
|
||||
closeLog();
|
||||
return result ? 0 : -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/timer.h"
|
||||
#include "base/flat_map.h"
|
||||
#include "base/flat_set.h"
|
||||
#include "core/single_timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
#include "data/data_messages.h"
|
||||
@@ -24,6 +23,11 @@ enum class SendMediaType;
|
||||
struct FileLoadTo;
|
||||
class mtpFileLoader;
|
||||
|
||||
namespace Data {
|
||||
struct UpdatedFileReferences;
|
||||
class WallPaper;
|
||||
} // namespace Data
|
||||
|
||||
namespace InlineBots {
|
||||
class Result;
|
||||
} // namespace InlineBots
|
||||
@@ -43,14 +47,6 @@ struct CloudPasswordState;
|
||||
|
||||
namespace Api {
|
||||
|
||||
inline const MTPVector<MTPChat> *getChatsFromMessagesChats(const MTPmessages_Chats &chats) {
|
||||
switch (chats.type()) {
|
||||
case mtpc_messages_chats: return &chats.c_messages_chats().vchats;
|
||||
case mtpc_messages_chatsSlice: return &chats.c_messages_chatsSlice().vchats;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename IntRange>
|
||||
inline int32 CountHash(IntRange &&range) {
|
||||
uint32 acc = 0;
|
||||
@@ -62,7 +58,7 @@ inline int32 CountHash(IntRange &&range) {
|
||||
|
||||
} // namespace Api
|
||||
|
||||
class ApiWrap : private MTP::Sender, private base::Subscriber {
|
||||
class ApiWrap : public MTP::Sender, private base::Subscriber {
|
||||
public:
|
||||
ApiWrap(not_null<AuthSession*> session);
|
||||
|
||||
@@ -87,16 +83,22 @@ public:
|
||||
void requestDialogEntry(
|
||||
not_null<History*> history,
|
||||
Fn<void()> callback = nullptr);
|
||||
void requestDialogEntries(std::vector<not_null<History*>> histories);
|
||||
void dialogEntryApplied(not_null<History*> history);
|
||||
//void applyFeedSources(const MTPDchannels_feedSources &data); // #feed
|
||||
//void setFeedChannels(
|
||||
// not_null<Data::Feed*> feed,
|
||||
// const std::vector<not_null<ChannelData*>> &channels);
|
||||
void changeDialogUnreadMark(not_null<History*> history, bool unread);
|
||||
//void changeDialogUnreadMark(not_null<Data::Feed*> feed, bool unread); // #feed
|
||||
void requestFakeChatListMessage(not_null<History*> history);
|
||||
|
||||
void requestFullPeer(PeerData *peer);
|
||||
void requestPeer(PeerData *peer);
|
||||
void requestWallPaper(
|
||||
const QString &slug,
|
||||
Fn<void(const Data::WallPaper &)> done,
|
||||
Fn<void(const RPCError &)> fail);
|
||||
|
||||
void requestFullPeer(not_null<PeerData*> peer);
|
||||
void requestPeer(not_null<PeerData*> peer);
|
||||
void requestPeers(const QList<PeerData*> &peers);
|
||||
void requestLastParticipants(not_null<ChannelData*> channel);
|
||||
void requestBots(not_null<ChannelData*> channel);
|
||||
@@ -134,29 +136,43 @@ public:
|
||||
void requestChannelMembersForAdd(
|
||||
not_null<ChannelData*> channel,
|
||||
Fn<void(const MTPchannels_ChannelParticipants&)> callback);
|
||||
void processFullPeer(PeerData *peer, const MTPmessages_ChatFull &result);
|
||||
void processFullPeer(UserData *user, const MTPUserFull &result);
|
||||
void processFullPeer(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPmessages_ChatFull &result);
|
||||
void processFullPeer(
|
||||
not_null<UserData*> user,
|
||||
const MTPUserFull &result);
|
||||
|
||||
void migrateChat(
|
||||
not_null<ChatData*> chat,
|
||||
FnMut<void(not_null<ChannelData*>)> done,
|
||||
FnMut<void(const RPCError &)> fail = nullptr);
|
||||
|
||||
void markMediaRead(const base::flat_set<not_null<HistoryItem*>> &items);
|
||||
void markMediaRead(not_null<HistoryItem*> item);
|
||||
|
||||
void requestSelfParticipant(ChannelData *channel);
|
||||
void requestSelfParticipant(not_null<ChannelData*> channel);
|
||||
void kickParticipant(not_null<ChatData*> chat, not_null<UserData*> user);
|
||||
void kickParticipant(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> user,
|
||||
const MTPChannelBannedRights ¤tRights);
|
||||
const MTPChatBannedRights ¤tRights);
|
||||
void unblockParticipant(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> user);
|
||||
void deleteAllFromUser(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> from);
|
||||
void saveDefaultRestrictions(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPChatBannedRights &rights,
|
||||
Fn<void(bool)> callback = nullptr);
|
||||
|
||||
void requestWebPageDelayed(WebPageData *page);
|
||||
void clearWebPageRequest(WebPageData *page);
|
||||
void clearWebPageRequests();
|
||||
|
||||
void requestAttachedStickerSets(not_null<PhotoData*> photo);
|
||||
void scheduleStickerSetRequest(uint64 setId, uint64 access);
|
||||
void requestStickerSets();
|
||||
void saveStickerSets(
|
||||
@@ -195,7 +211,12 @@ public:
|
||||
const MTPUserStatus &status,
|
||||
int currentOnlineTill);
|
||||
|
||||
void clearHistory(not_null<PeerData*> peer);
|
||||
void clearHistory(not_null<PeerData*> peer, bool revoke);
|
||||
void deleteConversation(not_null<PeerData*> peer, bool revoke);
|
||||
void deleteMessages(
|
||||
not_null<PeerData*> peer,
|
||||
const QVector<MTPint> &ids,
|
||||
bool revoke);
|
||||
|
||||
base::Observable<PeerData*> &fullPeerUpdated() {
|
||||
return _fullPeerUpdated;
|
||||
@@ -209,12 +230,9 @@ public:
|
||||
void jumpToDate(Dialogs::Key chat, const QDate &date);
|
||||
|
||||
void preloadEnoughUnreadMentions(not_null<History*> history);
|
||||
void checkForUnreadMentions(const base::flat_set<MsgId> &possiblyReadMentions, ChannelData *channel = nullptr);
|
||||
|
||||
void editChatAdmins(
|
||||
not_null<ChatData*> chat,
|
||||
bool adminsEnabled,
|
||||
base::flat_set<not_null<UserData*>> &&admins);
|
||||
void checkForUnreadMentions(
|
||||
const base::flat_set<MsgId> &possiblyReadMentions,
|
||||
ChannelData *channel = nullptr);
|
||||
|
||||
using SliceType = Data::LoadDirection;
|
||||
void requestSharedMedia(
|
||||
@@ -260,6 +278,9 @@ public:
|
||||
int availableCount,
|
||||
const QVector<MTPChannelParticipant> &list)> callbackList,
|
||||
Fn<void()> callbackNotModified = nullptr);
|
||||
void addChatParticipants(
|
||||
not_null<PeerData*> peer,
|
||||
const std::vector<not_null<UserData*>> &users);
|
||||
|
||||
struct SendOptions {
|
||||
SendOptions(not_null<History*> history);
|
||||
@@ -329,7 +350,7 @@ public:
|
||||
bool handleSupportSwitch = false;
|
||||
};
|
||||
void sendMessage(MessageToSend &&message);
|
||||
void sendBotStart(not_null<UserData*> bot);
|
||||
void sendBotStart(not_null<UserData*> bot, PeerData *chat = nullptr);
|
||||
void sendInlineResult(
|
||||
not_null<UserData*> bot,
|
||||
not_null<InlineBots::Result*> data,
|
||||
@@ -350,6 +371,11 @@ public:
|
||||
rpl::producer<Core::CloudPasswordState> passwordState() const;
|
||||
std::optional<Core::CloudPasswordState> passwordStateCurrent() const;
|
||||
|
||||
void reloadContactSignupSilent();
|
||||
rpl::producer<bool> contactSignupSilent() const;
|
||||
std::optional<bool> contactSignupSilentCurrent() const;
|
||||
void saveContactSignupSilent(bool silent);
|
||||
|
||||
void saveSelfBio(const QString &text, FnMut<void()> done);
|
||||
|
||||
struct Privacy {
|
||||
@@ -358,6 +384,8 @@ public:
|
||||
Calls,
|
||||
Invites,
|
||||
CallsPeer2Peer,
|
||||
Forwards,
|
||||
ProfilePhoto,
|
||||
};
|
||||
enum class Option {
|
||||
Everyone,
|
||||
@@ -377,6 +405,17 @@ public:
|
||||
rpl::producer<int> selfDestructValue() const;
|
||||
void saveSelfDestruct(int days);
|
||||
|
||||
void createPoll(
|
||||
const PollData &data,
|
||||
const SendOptions &options,
|
||||
FnMut<void()> done,
|
||||
FnMut<void(const RPCError &error)> fail);
|
||||
void sendPollVotes(
|
||||
FullMsgId itemId,
|
||||
const std::vector<QByteArray> &options);
|
||||
void closePoll(FullMsgId itemId);
|
||||
void reloadPollResults(not_null<HistoryItem*> item);
|
||||
|
||||
~ApiWrap();
|
||||
|
||||
private:
|
||||
@@ -391,13 +430,9 @@ private:
|
||||
struct StickersByEmoji {
|
||||
std::vector<not_null<DocumentData*>> list;
|
||||
int32 hash = 0;
|
||||
TimeMs received = 0;
|
||||
crl::time received = 0;
|
||||
};
|
||||
|
||||
using SimpleFileLocationId = Data::SimpleFileLocationId;
|
||||
using DocumentFileLocationId = Data::DocumentFileLocationId;
|
||||
using FileLocationId = Data::FileLocationId;
|
||||
|
||||
void updatesReceived(const MTPUpdates &updates);
|
||||
void checkQuitPreventFinished();
|
||||
|
||||
@@ -412,13 +447,18 @@ private:
|
||||
QVector<MTPInputMessage> collectMessageIds(const MessageDataRequests &requests);
|
||||
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
|
||||
void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
|
||||
void historyDialogEntryApplied(not_null<History*> history);
|
||||
void applyFeedDialogs(
|
||||
not_null<Data::Feed*> feed,
|
||||
const MTPmessages_Dialogs &dialogs);
|
||||
|
||||
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req);
|
||||
void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req);
|
||||
void gotChatFull(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPmessages_ChatFull &result,
|
||||
mtpRequestId req);
|
||||
void gotUserFull(
|
||||
not_null<UserData*> user,
|
||||
const MTPUserFull &result,
|
||||
mtpRequestId req);
|
||||
void applyLastParticipantsList(
|
||||
not_null<ChannelData*> channel,
|
||||
int availableCount,
|
||||
@@ -462,9 +502,6 @@ private:
|
||||
void requestSavedGifs(TimeId now);
|
||||
void readFeaturedSets();
|
||||
|
||||
void cancelEditChatAdmins(not_null<ChatData*> chat);
|
||||
void saveChatAdmins(not_null<ChatData*> chat);
|
||||
void sendSaveChatAdminsRequests(not_null<ChatData*> chat);
|
||||
void refreshChannelAdmins(
|
||||
not_null<ChannelData*> channel,
|
||||
const QVector<MTPChannelParticipant> &participants);
|
||||
@@ -508,6 +545,10 @@ private:
|
||||
UserId userId,
|
||||
const SendOptions &options);
|
||||
|
||||
void deleteHistory(
|
||||
not_null<PeerData*> peer,
|
||||
bool justClear,
|
||||
bool revoke);
|
||||
void sendReadRequest(not_null<PeerData*> peer, MsgId upTo);
|
||||
int applyAffectedHistory(
|
||||
not_null<PeerData*> peer,
|
||||
@@ -568,6 +609,13 @@ private:
|
||||
|
||||
void setSelfDestructDays(int days);
|
||||
|
||||
void migrateDone(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<ChannelData*> channel);
|
||||
void migrateFail(not_null<PeerData*> peer, const RPCError &error);
|
||||
|
||||
void sendDialogRequests();
|
||||
|
||||
not_null<AuthSession*> _session;
|
||||
|
||||
MessageDataRequests _messageDataRequests;
|
||||
@@ -596,7 +644,11 @@ private:
|
||||
not_null<UserData*>>;
|
||||
base::flat_map<KickRequest, mtpRequestId> _kickRequests;
|
||||
|
||||
QMap<ChannelData*, mtpRequestId> _selfParticipantRequests;
|
||||
base::flat_map<
|
||||
not_null<PeerData*>,
|
||||
mtpRequestId> _defaultRestrictionsRequests;
|
||||
|
||||
base::flat_set<not_null<ChannelData*>> _selfParticipantRequests;
|
||||
|
||||
base::flat_map<
|
||||
not_null<ChannelData*>,
|
||||
@@ -638,19 +690,13 @@ private:
|
||||
base::flat_map<
|
||||
not_null<History*>,
|
||||
std::vector<Fn<void()>>> _dialogRequests;
|
||||
base::flat_map<
|
||||
not_null<History*>,
|
||||
std::vector<Fn<void()>>> _dialogRequestsPending;
|
||||
base::flat_set<not_null<History*>> _fakeChatListRequests;
|
||||
|
||||
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;
|
||||
|
||||
base::flat_map<
|
||||
not_null<ChatData*>,
|
||||
mtpRequestId> _chatAdminsEnabledRequests;
|
||||
base::flat_map<
|
||||
not_null<ChatData*>,
|
||||
base::flat_set<not_null<UserData*>>> _chatAdminsToSave;
|
||||
base::flat_map<
|
||||
not_null<ChatData*>,
|
||||
base::flat_set<mtpRequestId>> _chatAdminsSaveRequests;
|
||||
|
||||
base::flat_map<std::tuple<
|
||||
not_null<PeerData*>,
|
||||
SharedMediaType,
|
||||
@@ -694,7 +740,7 @@ private:
|
||||
|
||||
rpl::event_stream<uint64> _stickerSetInstalled;
|
||||
|
||||
base::flat_map<not_null<Data::Feed*>, TimeMs> _feedReadsDelayed;
|
||||
base::flat_map<not_null<Data::Feed*>, crl::time> _feedReadsDelayed;
|
||||
base::flat_map<not_null<Data::Feed*>, mtpRequestId> _feedReadRequests;
|
||||
base::Timer _feedReadTimer;
|
||||
|
||||
@@ -712,13 +758,21 @@ private:
|
||||
|
||||
mtpRequestId _deepLinkInfoRequestId = 0;
|
||||
|
||||
TimeMs _termsUpdateSendAt = 0;
|
||||
crl::time _termsUpdateSendAt = 0;
|
||||
mtpRequestId _termsUpdateRequestId = 0;
|
||||
|
||||
mtpRequestId _checkInviteRequestId = 0;
|
||||
FnMut<void(const MTPChatInvite &result)> _checkInviteDone;
|
||||
FnMut<void(const RPCError &error)> _checkInviteFail;
|
||||
|
||||
struct MigrateCallbacks {
|
||||
FnMut<void(not_null<ChannelData*>)> done;
|
||||
FnMut<void(const RPCError&)> fail;
|
||||
};
|
||||
base::flat_map<
|
||||
not_null<PeerData*>,
|
||||
std::vector<MigrateCallbacks>> _migrateCallbacks;
|
||||
|
||||
std::vector<FnMut<void(const MTPUser &)>> _supportContactCallbacks;
|
||||
|
||||
base::flat_map<FullMsgId, not_null<PeerData*>> _peerPhotoUploads;
|
||||
@@ -739,4 +793,19 @@ private:
|
||||
std::optional<int> _selfDestructDays;
|
||||
rpl::event_stream<int> _selfDestructChanges;
|
||||
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollVotesRequestIds;
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollCloseRequestIds;
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollReloadRequestIds;
|
||||
|
||||
mtpRequestId _wallPaperRequestId = 0;
|
||||
QString _wallPaperSlug;
|
||||
Fn<void(const Data::WallPaper &)> _wallPaperDone;
|
||||
Fn<void(const RPCError &)> _wallPaperFail;
|
||||
|
||||
mtpRequestId _contactSignupSilentRequestId = 0;
|
||||
std::optional<bool> _contactSignupSilent;
|
||||
rpl::event_stream<bool> _contactSignupSilentChanges;
|
||||
|
||||
mtpRequestId _attachedStickerSetsRequestId = 0;
|
||||
|
||||
};
|
||||
|
||||
@@ -8,16 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "data/data_types.h"
|
||||
#include "data/data_peer.h"
|
||||
|
||||
enum NewMessageType : char;
|
||||
enum class ImageRoundRadius;
|
||||
class Messenger;
|
||||
class MainWindow;
|
||||
class MainWidget;
|
||||
class HistoryItem;
|
||||
class History;
|
||||
class Histories;
|
||||
namespace HistoryView {
|
||||
class Element;
|
||||
} // namespace HistoryView
|
||||
@@ -38,6 +35,8 @@ enum RoundCorners {
|
||||
SelectedOverlayLargeCorners,
|
||||
DateCorners,
|
||||
DateSelectedCorners,
|
||||
OverviewVideoCorners,
|
||||
OverviewVideoSelectedCorners,
|
||||
ForwardCorners,
|
||||
MediaviewSaveCorners,
|
||||
EmojiHoverCorners,
|
||||
@@ -67,16 +66,6 @@ namespace App {
|
||||
|
||||
QString formatPhone(QString phone);
|
||||
|
||||
UserData *feedUser(const MTPUser &user);
|
||||
UserData *feedUsers(const MTPVector<MTPUser> &users); // returns last user
|
||||
PeerData *feedChat(const MTPChat &chat);
|
||||
PeerData *feedChats(const MTPVector<MTPChat> &chats); // returns last chat
|
||||
|
||||
void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos);
|
||||
void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d);
|
||||
void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d);
|
||||
void feedChatAdmins(const MTPDupdateChatAdmins &d);
|
||||
void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d);
|
||||
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached
|
||||
void updateEditedMessage(const MTPMessage &m);
|
||||
void addSavedGif(DocumentData *doc);
|
||||
@@ -90,68 +79,13 @@ namespace App {
|
||||
|
||||
ImagePtr image(const MTPPhotoSize &size);
|
||||
|
||||
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded);
|
||||
inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
|
||||
return asUser(peer(id, restriction));
|
||||
}
|
||||
inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
|
||||
return asChat(peer(id, restriction));
|
||||
}
|
||||
inline ChannelData *channel(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
|
||||
return asChannel(peer(id, restriction));
|
||||
}
|
||||
inline UserData *user(UserId userId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
|
||||
return asUser(peer(peerFromUser(userId), restriction));
|
||||
}
|
||||
inline ChatData *chat(ChatId chatId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
|
||||
return asChat(peer(peerFromChat(chatId), restriction));
|
||||
}
|
||||
inline ChannelData *channel(ChannelId channelId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
|
||||
return asChannel(peer(peerFromChannel(channelId), restriction));
|
||||
}
|
||||
inline PeerData *peerLoaded(const PeerId &id) {
|
||||
return peer(id, PeerData::FullLoaded);
|
||||
}
|
||||
inline UserData *userLoaded(const PeerId &id) {
|
||||
return user(id, PeerData::FullLoaded);
|
||||
}
|
||||
inline ChatData *chatLoaded(const PeerId &id) {
|
||||
return chat(id, PeerData::FullLoaded);
|
||||
}
|
||||
inline ChannelData *channelLoaded(const PeerId &id) {
|
||||
return channel(id, PeerData::FullLoaded);
|
||||
}
|
||||
inline UserData *userLoaded(UserId userId) {
|
||||
return user(userId, PeerData::FullLoaded);
|
||||
}
|
||||
inline ChatData *chatLoaded(ChatId chatId) {
|
||||
return chat(chatId, PeerData::FullLoaded);
|
||||
}
|
||||
inline ChannelData *channelLoaded(ChannelId channelId) {
|
||||
return channel(channelId, PeerData::FullLoaded);
|
||||
}
|
||||
void enumerateUsers(Fn<void(not_null<UserData*>)> action);
|
||||
void enumerateGroups(Fn<void(not_null<PeerData*>)> action);
|
||||
void enumerateChannels(Fn<void(not_null<ChannelData*>)> action);
|
||||
[[nodiscard]] QString peerName(const PeerData *peer, bool forDialogs = false);
|
||||
|
||||
PeerData *peerByName(const QString &username);
|
||||
QString peerName(const PeerData *peer, bool forDialogs = false);
|
||||
|
||||
Histories &histories();
|
||||
not_null<History*> history(const PeerId &peer);
|
||||
History *historyLoaded(const PeerId &peer);
|
||||
HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
|
||||
inline not_null<History*> history(const PeerData *peer) {
|
||||
Assert(peer != nullptr);
|
||||
return history(peer->id);
|
||||
}
|
||||
inline History *historyLoaded(const PeerData *peer) {
|
||||
return peer ? historyLoaded(peer->id) : nullptr;
|
||||
}
|
||||
inline HistoryItem *histItemById(const ChannelData *channel, MsgId itemId) {
|
||||
return histItemById(channel ? peerToChannel(channel->id) : 0, itemId);
|
||||
}
|
||||
inline HistoryItem *histItemById(const FullMsgId &msgId) {
|
||||
[[nodiscard]] HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
|
||||
[[nodiscard]] HistoryItem *histItemById(
|
||||
const ChannelData *channel,
|
||||
MsgId itemId);
|
||||
[[nodiscard]] inline HistoryItem *histItemById(const FullMsgId &msgId) {
|
||||
return histItemById(msgId.channel, msgId.msg);
|
||||
}
|
||||
void historyRegItem(not_null<HistoryItem*> item);
|
||||
@@ -183,8 +117,6 @@ namespace App {
|
||||
|
||||
const style::font &monofont();
|
||||
|
||||
void clearHistories();
|
||||
|
||||
void initMedia();
|
||||
void deinitMedia();
|
||||
|
||||
@@ -222,14 +154,4 @@ namespace App {
|
||||
return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts);
|
||||
}
|
||||
|
||||
struct WallPaper {
|
||||
WallPaper(int32 id, ImagePtr thumb, ImagePtr full) : id(id), thumb(thumb), full(full) {
|
||||
}
|
||||
int32 id;
|
||||
ImagePtr thumb;
|
||||
ImagePtr full;
|
||||
};
|
||||
typedef QList<WallPaper> WallPapers;
|
||||
DeclareSetting(WallPapers, ServerBackgrounds);
|
||||
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "auth_session.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "messenger.h"
|
||||
#include "core/application.h"
|
||||
#include "core/changelogs.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "storage/file_upload.h"
|
||||
@@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "storage/storage_facade.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "platform/platform_specific.h"
|
||||
@@ -30,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kAutoLockTimeoutLateMs = TimeMs(3000);
|
||||
constexpr auto kAutoLockTimeoutLateMs = crl::time(3000);
|
||||
constexpr auto kLegacyCallsPeerToPeerNobody = 4;
|
||||
|
||||
} // namespace
|
||||
@@ -45,11 +46,13 @@ AuthSessionSettings::Variables::Variables()
|
||||
}
|
||||
|
||||
QByteArray AuthSessionSettings::serialize() const {
|
||||
const auto autoDownload = _variables.autoDownload.serialize();
|
||||
auto size = sizeof(qint32) * 23;
|
||||
for (auto i = _variables.soundOverrides.cbegin(), e = _variables.soundOverrides.cend(); i != e; ++i) {
|
||||
size += Serialize::stringSize(i.key()) + Serialize::stringSize(i.value());
|
||||
}
|
||||
size += _variables.groupStickersSectionHidden.size() * sizeof(quint64);
|
||||
size += Serialize::bytearraySize(autoDownload);
|
||||
|
||||
auto result = QByteArray();
|
||||
result.reserve(size);
|
||||
@@ -88,6 +91,8 @@ QByteArray AuthSessionSettings::serialize() const {
|
||||
stream << qint32(_variables.includeMutedCounter ? 1 : 0);
|
||||
stream << qint32(_variables.countUnreadMessages ? 1 : 0);
|
||||
stream << qint32(_variables.exeLaunchWarning ? 1 : 0);
|
||||
stream << autoDownload;
|
||||
stream << qint32(_variables.supportAllSearchResults.current() ? 1 : 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -122,6 +127,8 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
|
||||
qint32 includeMutedCounter = _variables.includeMutedCounter ? 1 : 0;
|
||||
qint32 countUnreadMessages = _variables.countUnreadMessages ? 1 : 0;
|
||||
qint32 exeLaunchWarning = _variables.exeLaunchWarning ? 1 : 0;
|
||||
QByteArray autoDownload;
|
||||
qint32 supportAllSearchResults = _variables.supportAllSearchResults.current() ? 1 : 0;
|
||||
|
||||
stream >> selectorTab;
|
||||
stream >> lastSeenWarningSeen;
|
||||
@@ -195,11 +202,21 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
|
||||
if (!stream.atEnd()) {
|
||||
stream >> exeLaunchWarning;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
stream >> autoDownload;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
stream >> supportAllSearchResults;
|
||||
}
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for AuthSessionSettings::constructFromSerialized()"));
|
||||
return;
|
||||
}
|
||||
if (!autoDownload.isEmpty()
|
||||
&& !_variables.autoDownload.setFromSerialized(autoDownload)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto uncheckedTab = static_cast<ChatHelpers::SelectorTab>(selectorTab);
|
||||
switch (uncheckedTab) {
|
||||
@@ -259,6 +276,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
|
||||
_variables.includeMutedCounter = (includeMutedCounter == 1);
|
||||
_variables.countUnreadMessages = (countUnreadMessages == 1);
|
||||
_variables.exeLaunchWarning = (exeLaunchWarning == 1);
|
||||
_variables.supportAllSearchResults = (supportAllSearchResults == 1);
|
||||
}
|
||||
|
||||
void AuthSessionSettings::setSupportChatsTimeSlice(int slice) {
|
||||
@@ -273,6 +291,18 @@ rpl::producer<int> AuthSessionSettings::supportChatsTimeSliceValue() const {
|
||||
return _variables.supportChatsTimeSlice.value();
|
||||
}
|
||||
|
||||
void AuthSessionSettings::setSupportAllSearchResults(bool all) {
|
||||
_variables.supportAllSearchResults = all;
|
||||
}
|
||||
|
||||
bool AuthSessionSettings::supportAllSearchResults() const {
|
||||
return _variables.supportAllSearchResults.current();
|
||||
}
|
||||
|
||||
rpl::producer<bool> AuthSessionSettings::supportAllSearchResultsValue() const {
|
||||
return _variables.supportAllSearchResults.value();
|
||||
}
|
||||
|
||||
void AuthSessionSettings::setTabbedSelectorSectionEnabled(bool enabled) {
|
||||
_variables.tabbedSelectorSectionEnabled = enabled;
|
||||
if (enabled) {
|
||||
@@ -342,14 +372,13 @@ rpl::producer<int> AuthSessionSettings::thirdColumnWidthChanges() const {
|
||||
}
|
||||
|
||||
AuthSession &Auth() {
|
||||
auto result = Messenger::Instance().authSession();
|
||||
auto result = Core::App().authSession();
|
||||
Assert(result != nullptr);
|
||||
return *result;
|
||||
}
|
||||
|
||||
AuthSession::AuthSession(const MTPUser &user)
|
||||
: _user(App::user(user.match([](const auto &data) { return data.vid.v; })))
|
||||
, _autoLockTimer([this] { checkAutoLock(); })
|
||||
: _autoLockTimer([this] { checkAutoLock(); })
|
||||
, _api(std::make_unique<ApiWrap>(this))
|
||||
, _calls(std::make_unique<Calls::Instance>())
|
||||
, _downloader(std::make_unique<Storage::Downloader>())
|
||||
@@ -357,21 +386,17 @@ AuthSession::AuthSession(const MTPUser &user)
|
||||
, _storage(std::make_unique<Storage::Facade>())
|
||||
, _notifications(std::make_unique<Window::Notifications::System>(this))
|
||||
, _data(std::make_unique<Data::Session>(this))
|
||||
, _user(_data->processUser(user))
|
||||
, _changelogs(Core::Changelogs::Create(this))
|
||||
, _supportHelper(
|
||||
(Support::ValidateAccount(user)
|
||||
? std::make_unique<Support::Helper>(this)
|
||||
: nullptr)) {
|
||||
App::feedUser(user);
|
||||
|
||||
, _supportHelper(Support::Helper::Create(this)) {
|
||||
_saveDataTimer.setCallback([=] {
|
||||
Local::writeUserSettings();
|
||||
});
|
||||
Messenger::Instance().passcodeLockChanges(
|
||||
Core::App().passcodeLockChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
_shouldLockAt = 0;
|
||||
}, _lifetime);
|
||||
Messenger::Instance().lockChanges(
|
||||
Core::App().lockChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
notifications().updateAll();
|
||||
}, _lifetime);
|
||||
@@ -404,23 +429,28 @@ AuthSession::AuthSession(const MTPUser &user)
|
||||
}
|
||||
|
||||
bool AuthSession::Exists() {
|
||||
if (const auto messenger = Messenger::InstancePointer()) {
|
||||
return (messenger->authSession() != nullptr);
|
||||
}
|
||||
return false;
|
||||
return Core::IsAppLaunched() && (Core::App().authSession() != nullptr);
|
||||
}
|
||||
|
||||
base::Observable<void> &AuthSession::downloaderTaskFinished() {
|
||||
return downloader().taskFinished();
|
||||
}
|
||||
|
||||
UserId AuthSession::userId() const {
|
||||
return _user->bareId();
|
||||
}
|
||||
|
||||
PeerId AuthSession::userPeerId() const {
|
||||
return _user->id;
|
||||
}
|
||||
|
||||
bool AuthSession::validateSelf(const MTPUser &user) {
|
||||
if (user.type() != mtpc_user || !user.c_user().is_self()) {
|
||||
LOG(("API Error: bad self user received."));
|
||||
return false;
|
||||
} else if (user.c_user().vid.v != userId()) {
|
||||
LOG(("Auth Error: wrong self user received."));
|
||||
crl::on_main(this, [] { Messenger::Instance().logOut(); });
|
||||
crl::on_main(this, [] { Core::App().logOut(); });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -438,33 +468,41 @@ void AuthSession::moveSettingsFrom(AuthSessionSettings &&other) {
|
||||
}
|
||||
}
|
||||
|
||||
void AuthSession::saveSettingsDelayed(TimeMs delay) {
|
||||
void AuthSession::saveSettingsDelayed(crl::time delay) {
|
||||
Expects(this == &Auth());
|
||||
|
||||
_saveDataTimer.callOnce(delay);
|
||||
}
|
||||
|
||||
void AuthSession::localPasscodeChanged() {
|
||||
_shouldLockAt = 0;
|
||||
_autoLockTimer.cancel();
|
||||
checkAutoLock();
|
||||
}
|
||||
|
||||
void AuthSession::checkAutoLock() {
|
||||
if (!Global::LocalPasscode()
|
||||
|| Messenger::Instance().passcodeLocked()) {
|
||||
|| Core::App().passcodeLocked()) {
|
||||
_shouldLockAt = 0;
|
||||
_autoLockTimer.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
Messenger::Instance().checkLocalTime();
|
||||
auto now = getms(true);
|
||||
auto shouldLockInMs = Global::AutoLock() * 1000LL;
|
||||
auto idleForMs = psIdleTime();
|
||||
auto notPlayingVideoForMs = now - settings().lastTimeVideoPlayedAt();
|
||||
auto checkTimeMs = qMin(idleForMs, notPlayingVideoForMs);
|
||||
Core::App().checkLocalTime();
|
||||
const auto now = crl::now();
|
||||
const auto shouldLockInMs = Global::AutoLock() * 1000LL;
|
||||
const auto checkTimeMs = now - Core::App().lastNonIdleTime();
|
||||
if (checkTimeMs >= shouldLockInMs || (_shouldLockAt > 0 && now > _shouldLockAt + kAutoLockTimeoutLateMs)) {
|
||||
Messenger::Instance().lockByPasscode();
|
||||
_shouldLockAt = 0;
|
||||
_autoLockTimer.cancel();
|
||||
Core::App().lockByPasscode();
|
||||
} else {
|
||||
_shouldLockAt = now + (shouldLockInMs - checkTimeMs);
|
||||
_autoLockTimer.callOnce(shouldLockInMs - checkTimeMs);
|
||||
}
|
||||
}
|
||||
|
||||
void AuthSession::checkAutoLockIn(TimeMs time) {
|
||||
void AuthSession::checkAutoLockIn(crl::time time) {
|
||||
if (_autoLockTimer.isActive()) {
|
||||
auto remain = _autoLockTimer.remainingTime();
|
||||
if (remain > 0 && remain <= time) return;
|
||||
@@ -486,4 +524,7 @@ Support::Templates& AuthSession::supportTemplates() const {
|
||||
return supportHelper().templates();
|
||||
}
|
||||
|
||||
AuthSession::~AuthSession() = default;
|
||||
AuthSession::~AuthSession() {
|
||||
ClickHandler::clearActive();
|
||||
ClickHandler::unpressed();
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <rpl/filter.h>
|
||||
#include <rpl/variable.h>
|
||||
#include "base/timer.h"
|
||||
#include "data/data_auto_download.h"
|
||||
|
||||
class ApiWrap;
|
||||
enum class SendFilesWay;
|
||||
@@ -102,6 +103,9 @@ public:
|
||||
void setSupportChatsTimeSlice(int slice);
|
||||
int supportChatsTimeSlice() const;
|
||||
rpl::producer<int> supportChatsTimeSliceValue() const;
|
||||
void setSupportAllSearchResults(bool all);
|
||||
bool supportAllSearchResults() const;
|
||||
rpl::producer<bool> supportAllSearchResultsValue() const;
|
||||
|
||||
ChatHelpers::SelectorTab selectorTab() const {
|
||||
return _variables.selectorTab;
|
||||
@@ -135,12 +139,6 @@ public:
|
||||
bool smallDialogsList() const {
|
||||
return _variables.smallDialogsList;
|
||||
}
|
||||
void setLastTimeVideoPlayedAt(TimeMs time) {
|
||||
_lastTimeVideoPlayedAt = time;
|
||||
}
|
||||
TimeMs lastTimeVideoPlayedAt() const {
|
||||
return _lastTimeVideoPlayedAt;
|
||||
}
|
||||
void setSoundOverride(const QString &key, const QString &path) {
|
||||
_variables.soundOverrides.insert(key, path);
|
||||
}
|
||||
@@ -183,6 +181,13 @@ public:
|
||||
_variables.groupStickersSectionHidden.remove(peerId);
|
||||
}
|
||||
|
||||
Data::AutoDownload::Full &autoDownload() {
|
||||
return _variables.autoDownload;
|
||||
}
|
||||
const Data::AutoDownload::Full &autoDownload() const {
|
||||
return _variables.autoDownload;
|
||||
}
|
||||
|
||||
bool hadLegacyCallsPeerToPeerNobody() const {
|
||||
return _variables.hadLegacyCallsPeerToPeerNobody;
|
||||
}
|
||||
@@ -234,6 +239,7 @@ private:
|
||||
bool includeMutedCounter = true;
|
||||
bool countUnreadMessages = true;
|
||||
bool exeLaunchWarning = true;
|
||||
Data::AutoDownload::Full autoDownload;
|
||||
|
||||
static constexpr auto kDefaultSupportChatsLimitSlice
|
||||
= 7 * 24 * 60 * 60;
|
||||
@@ -243,6 +249,7 @@ private:
|
||||
bool supportTemplatesAutocomplete = true;
|
||||
rpl::variable<int> supportChatsTimeSlice
|
||||
= kDefaultSupportChatsLimitSlice;
|
||||
rpl::variable<bool> supportAllSearchResults = false;
|
||||
};
|
||||
|
||||
rpl::event_stream<bool> _thirdSectionInfoEnabledValue;
|
||||
@@ -250,11 +257,9 @@ private:
|
||||
rpl::event_stream<bool> _tabbedReplacedWithInfoValue;
|
||||
|
||||
Variables _variables;
|
||||
TimeMs _lastTimeVideoPlayedAt = 0;
|
||||
|
||||
};
|
||||
|
||||
// One per Messenger.
|
||||
class AuthSession;
|
||||
AuthSession &Auth();
|
||||
|
||||
@@ -269,12 +274,8 @@ public:
|
||||
|
||||
static bool Exists();
|
||||
|
||||
UserId userId() const {
|
||||
return _user->bareId();
|
||||
}
|
||||
PeerId userPeerId() const {
|
||||
return _user->id;
|
||||
}
|
||||
UserId userId() const;
|
||||
PeerId userPeerId() const;
|
||||
not_null<UserData*> user() const {
|
||||
return _user;
|
||||
}
|
||||
@@ -303,7 +304,7 @@ public:
|
||||
return _settings;
|
||||
}
|
||||
void moveSettingsFrom(AuthSessionSettings &&other);
|
||||
void saveSettingsDelayed(TimeMs delay = kDefaultSaveDelay);
|
||||
void saveSettingsDelayed(crl::time delay = kDefaultSaveDelay);
|
||||
|
||||
ApiWrap &api() {
|
||||
return *_api;
|
||||
@@ -314,7 +315,8 @@ public:
|
||||
}
|
||||
|
||||
void checkAutoLock();
|
||||
void checkAutoLockIn(TimeMs time);
|
||||
void checkAutoLockIn(crl::time time);
|
||||
void localPasscodeChanged();
|
||||
|
||||
rpl::lifetime &lifetime() {
|
||||
return _lifetime;
|
||||
@@ -330,13 +332,12 @@ public:
|
||||
~AuthSession();
|
||||
|
||||
private:
|
||||
static constexpr auto kDefaultSaveDelay = TimeMs(1000);
|
||||
static constexpr auto kDefaultSaveDelay = crl::time(1000);
|
||||
|
||||
const not_null<UserData*> _user;
|
||||
AuthSessionSettings _settings;
|
||||
base::Timer _saveDataTimer;
|
||||
|
||||
TimeMs _shouldLockAt = 0;
|
||||
crl::time _shouldLockAt = 0;
|
||||
base::Timer _autoLockTimer;
|
||||
|
||||
const std::unique_ptr<ApiWrap> _api;
|
||||
@@ -346,8 +347,9 @@ private:
|
||||
const std::unique_ptr<Storage::Facade> _storage;
|
||||
const std::unique_ptr<Window::Notifications::System> _notifications;
|
||||
|
||||
// _data depends on _downloader / _uploader, including destructor.
|
||||
// _data depends on _downloader / _uploader / _notifications.
|
||||
const std::unique_ptr<Data::Session> _data;
|
||||
const not_null<UserData*> _user;
|
||||
|
||||
// _changelogs depends on _data, subscribes on chats loading event.
|
||||
const std::unique_ptr<Core::Changelogs> _changelogs;
|
||||
|
||||
@@ -24,6 +24,12 @@ inline constexpr size_t array_size(const Type(&)[Size]) {
|
||||
return Size;
|
||||
}
|
||||
|
||||
template <typename Container, typename T>
|
||||
inline bool contains(const Container &container, const T &value) {
|
||||
const auto end = std::end(container);
|
||||
return std::find(std::begin(container), end, value) != end;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -19,7 +19,10 @@ void log(const char *message, const char *file, int line);
|
||||
inline constexpr void noop() {
|
||||
}
|
||||
|
||||
[[noreturn]] inline void fail(const char *message, const char *file, int line) {
|
||||
[[noreturn]] inline void fail(
|
||||
const char *message,
|
||||
const char *file,
|
||||
int line) {
|
||||
log(message, file, line);
|
||||
|
||||
// Crash with access violation and generate crash report.
|
||||
@@ -30,24 +33,36 @@ inline constexpr void noop() {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
#ifndef GSL_UNLIKELY
|
||||
#define DEFINED_GSL_UNLIKELY_
|
||||
#define GSL_UNLIKELY(expression) (expression)
|
||||
#endif // GSL_UNLIKELY
|
||||
|
||||
inline constexpr void validate(bool condition, const char *message, const char *file, int line) {
|
||||
(GSL_UNLIKELY(!(condition))) ? fail(message, file, line) : noop();
|
||||
constexpr const char* extract_basename(const char* path, size_t size) {
|
||||
while (size != 0 && path[size - 1] != '/' && path[size - 1] != '\\') {
|
||||
--size;
|
||||
}
|
||||
return path + size;
|
||||
}
|
||||
|
||||
#ifdef DEFINED_GSL_UNLIKELY_
|
||||
#undef GSL_UNLIKELY
|
||||
#undef DEFINED_GSL_UNLIKELY_
|
||||
#endif // DEFINED_GSL_UNLIKELY_
|
||||
|
||||
} // namespace assertion
|
||||
} // namespace base
|
||||
|
||||
#define AssertCustom(condition, message) (::base::assertion::validate(condition, message, __FILE__, __LINE__))
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define AssertUnlikelyHelper(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define AssertUnlikelyHelper(x) (!!(x))
|
||||
#endif
|
||||
|
||||
#define AssertValidationCondition(condition, message, file, line)\
|
||||
((AssertUnlikelyHelper(!(condition)))\
|
||||
? ::base::assertion::fail(message, file, line)\
|
||||
: ::base::assertion::noop())
|
||||
|
||||
#define SOURCE_FILE_BASENAME (::base::assertion::extract_basename(\
|
||||
__FILE__,\
|
||||
sizeof(__FILE__)))
|
||||
|
||||
#define AssertCustom(condition, message) (AssertValidationCondition(\
|
||||
condition,\
|
||||
message,\
|
||||
SOURCE_FILE_BASENAME,\
|
||||
__LINE__))
|
||||
#define Assert(condition) AssertCustom(condition, "\"" #condition "\"")
|
||||
|
||||
// Define our own versions of Expects() and Ensures().
|
||||
@@ -55,17 +70,28 @@ inline constexpr void validate(bool condition, const char *message, const char *
|
||||
#ifdef Expects
|
||||
#undef Expects
|
||||
#endif // Expects
|
||||
#define Expects(condition) (::base::assertion::validate(condition, "\"" #condition "\"", __FILE__, __LINE__))
|
||||
#define Expects(condition) (AssertValidationCondition(\
|
||||
condition,\
|
||||
"\"" #condition "\"",\
|
||||
SOURCE_FILE_BASENAME,\
|
||||
__LINE__))
|
||||
|
||||
#ifdef Ensures
|
||||
#undef Ensures
|
||||
#endif // Ensures
|
||||
#define Ensures(condition) (::base::assertion::validate(condition, "\"" #condition "\"", __FILE__, __LINE__))
|
||||
#define Ensures(condition) (AssertValidationCondition(\
|
||||
condition,\
|
||||
"\"" #condition "\"",\
|
||||
SOURCE_FILE_BASENAME,\
|
||||
__LINE__))
|
||||
|
||||
#ifdef Unexpected
|
||||
#undef Unexpected
|
||||
#endif // Unexpected
|
||||
#define Unexpected(message) (::base::assertion::fail("Unexpected: " message, __FILE__, __LINE__))
|
||||
#define Unexpected(message) (::base::assertion::fail(\
|
||||
"Unexpected: " message,\
|
||||
SOURCE_FILE_BASENAME,\
|
||||
__LINE__))
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define AssertIsDebug(...)
|
||||
|
||||
@@ -46,7 +46,6 @@ using uint64 = quint64;
|
||||
using float32 = float;
|
||||
using float64 = double;
|
||||
|
||||
using TimeMs = int64;
|
||||
using TimeId = int32;
|
||||
|
||||
// Define specializations for QByteArray for Qt 5.3.2, because
|
||||
|
||||
@@ -21,7 +21,9 @@ public:
|
||||
~binary_guard();
|
||||
|
||||
bool alive() const;
|
||||
void kill();
|
||||
|
||||
binary_guard &operator=(std::nullptr_t);
|
||||
explicit operator bool() const;
|
||||
|
||||
private:
|
||||
void destroy();
|
||||
@@ -44,15 +46,20 @@ inline binary_guard &binary_guard::operator=(binary_guard &&other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline binary_guard::~binary_guard() {
|
||||
inline binary_guard &binary_guard::operator=(std::nullptr_t) {
|
||||
destroy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline binary_guard::operator bool() const {
|
||||
return alive();
|
||||
}
|
||||
|
||||
inline bool binary_guard::alive() const {
|
||||
return _bothAlive && _bothAlive->load();
|
||||
}
|
||||
|
||||
inline void binary_guard::kill() {
|
||||
inline binary_guard::~binary_guard() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
@@ -74,3 +81,21 @@ inline std::pair<binary_guard, binary_guard> make_binary_guard() {
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
namespace crl {
|
||||
|
||||
template <typename T, typename Enable>
|
||||
struct guard_traits;
|
||||
|
||||
template <>
|
||||
struct guard_traits<base::binary_guard, void> {
|
||||
static base::binary_guard create(base::binary_guard value) {
|
||||
return value;
|
||||
}
|
||||
static bool check(const base::binary_guard &guard) {
|
||||
return guard.alive();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace crl
|
||||
|
||||
@@ -26,16 +26,16 @@ QMutex EnvironmentMutex;
|
||||
class CallDelayedEvent : public QEvent {
|
||||
public:
|
||||
CallDelayedEvent(
|
||||
crl::time_type timeout,
|
||||
crl::time timeout,
|
||||
Qt::TimerType type,
|
||||
FnMut<void()> method);
|
||||
|
||||
crl::time_type timeout() const;
|
||||
crl::time timeout() const;
|
||||
Qt::TimerType type() const;
|
||||
FnMut<void()> takeMethod();
|
||||
|
||||
private:
|
||||
crl::time_type _timeout = 0;
|
||||
crl::time _timeout = 0;
|
||||
Qt::TimerType _type = Qt::PreciseTimer;
|
||||
FnMut<void()> _method;
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
};
|
||||
|
||||
CallDelayedEvent::CallDelayedEvent(
|
||||
crl::time_type timeout,
|
||||
crl::time timeout,
|
||||
Qt::TimerType type,
|
||||
FnMut<void()> method)
|
||||
: QEvent(kCallDelayedEvent)
|
||||
@@ -58,7 +58,7 @@ CallDelayedEvent::CallDelayedEvent(
|
||||
Expects(_timeout >= 0 && _timeout < std::numeric_limits<int>::max());
|
||||
}
|
||||
|
||||
crl::time_type CallDelayedEvent::timeout() const {
|
||||
crl::time CallDelayedEvent::timeout() const {
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ TimerObjectWrap::~TimerObjectWrap() {
|
||||
}
|
||||
|
||||
void TimerObjectWrap::call(
|
||||
crl::time_type timeout,
|
||||
crl::time timeout,
|
||||
Qt::TimerType type,
|
||||
FnMut<void()> method) {
|
||||
sendEvent(std::make_unique<CallDelayedEvent>(
|
||||
@@ -281,7 +281,7 @@ Fn<void()> ConcurrentTimer::createAdjuster() {
|
||||
}
|
||||
|
||||
void ConcurrentTimer::start(
|
||||
TimeMs timeout,
|
||||
crl::time timeout,
|
||||
Qt::TimerType type,
|
||||
Repeat repeat) {
|
||||
_type = type;
|
||||
@@ -290,7 +290,7 @@ void ConcurrentTimer::start(
|
||||
setTimeout(timeout);
|
||||
|
||||
cancelAndSchedule(_timeout);
|
||||
_next = crl::time() + _timeout;
|
||||
_next = crl::now() + _timeout;
|
||||
}
|
||||
|
||||
void ConcurrentTimer::cancelAndSchedule(int timeout) {
|
||||
@@ -301,11 +301,11 @@ void ConcurrentTimer::cancelAndSchedule(int timeout) {
|
||||
runner = _runner,
|
||||
guard = std::move(guards.second)
|
||||
]() mutable {
|
||||
if (!guard.alive()) {
|
||||
if (!guard) {
|
||||
return;
|
||||
}
|
||||
runner([=, guard = std::move(guard)] {
|
||||
if (!guard.alive()) {
|
||||
if (!guard) {
|
||||
return;
|
||||
}
|
||||
timerEvent();
|
||||
@@ -319,7 +319,7 @@ void ConcurrentTimer::timerEvent() {
|
||||
if (_adjusted) {
|
||||
start(_timeout, _type, repeat());
|
||||
} else {
|
||||
_next = crl::time() + _timeout;
|
||||
_next = crl::now() + _timeout;
|
||||
}
|
||||
} else {
|
||||
cancel();
|
||||
@@ -338,12 +338,12 @@ void ConcurrentTimer::cancel() {
|
||||
}
|
||||
}
|
||||
|
||||
TimeMs ConcurrentTimer::remainingTime() const {
|
||||
crl::time ConcurrentTimer::remainingTime() const {
|
||||
if (!isActive()) {
|
||||
return -1;
|
||||
}
|
||||
const auto now = crl::time();
|
||||
return (_next > now) ? (_next - now) : TimeMs(0);
|
||||
const auto now = crl::now();
|
||||
return (_next > now) ? (_next - now) : crl::time(0);
|
||||
}
|
||||
|
||||
void ConcurrentTimer::adjust() {
|
||||
@@ -354,7 +354,7 @@ void ConcurrentTimer::adjust() {
|
||||
}
|
||||
}
|
||||
|
||||
void ConcurrentTimer::setTimeout(TimeMs timeout) {
|
||||
void ConcurrentTimer::setTimeout(crl::time timeout) {
|
||||
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
|
||||
|
||||
_timeout = static_cast<unsigned int>(timeout);
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
~TimerObjectWrap();
|
||||
|
||||
void call(
|
||||
crl::time_type timeout,
|
||||
crl::time timeout,
|
||||
Qt::TimerType type,
|
||||
FnMut<void()> method);
|
||||
void cancel();
|
||||
@@ -67,8 +67,8 @@ public:
|
||||
crl::weak_on_queue<Object> weak,
|
||||
Fn<void()> callback = nullptr);
|
||||
|
||||
static Qt::TimerType DefaultType(TimeMs timeout) {
|
||||
constexpr auto kThreshold = TimeMs(1000);
|
||||
static Qt::TimerType DefaultType(crl::time timeout) {
|
||||
constexpr auto kThreshold = crl::time(1000);
|
||||
return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer;
|
||||
}
|
||||
|
||||
@@ -76,19 +76,19 @@ public:
|
||||
_callback = std::move(callback);
|
||||
}
|
||||
|
||||
void callOnce(TimeMs timeout) {
|
||||
void callOnce(crl::time timeout) {
|
||||
callOnce(timeout, DefaultType(timeout));
|
||||
}
|
||||
|
||||
void callEach(TimeMs timeout) {
|
||||
void callEach(crl::time timeout) {
|
||||
callEach(timeout, DefaultType(timeout));
|
||||
}
|
||||
|
||||
void callOnce(TimeMs timeout, Qt::TimerType type) {
|
||||
void callOnce(crl::time timeout, Qt::TimerType type) {
|
||||
start(timeout, type, Repeat::SingleShot);
|
||||
}
|
||||
|
||||
void callEach(TimeMs timeout, Qt::TimerType type) {
|
||||
void callEach(crl::time timeout, Qt::TimerType type) {
|
||||
start(timeout, type, Repeat::Interval);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
}
|
||||
|
||||
void cancel();
|
||||
TimeMs remainingTime() const;
|
||||
crl::time remainingTime() const;
|
||||
|
||||
private:
|
||||
enum class Repeat : unsigned {
|
||||
@@ -105,12 +105,12 @@ private:
|
||||
SingleShot = 1,
|
||||
};
|
||||
Fn<void()> createAdjuster();
|
||||
void start(TimeMs timeout, Qt::TimerType type, Repeat repeat);
|
||||
void start(crl::time timeout, Qt::TimerType type, Repeat repeat);
|
||||
void adjust();
|
||||
|
||||
void cancelAndSchedule(int timeout);
|
||||
|
||||
void setTimeout(TimeMs timeout);
|
||||
void setTimeout(crl::time timeout);
|
||||
int timeout() const;
|
||||
|
||||
void timerEvent();
|
||||
@@ -127,7 +127,7 @@ private:
|
||||
details::TimerObjectWrap _object;
|
||||
Fn<void()> _callback;
|
||||
base::binary_guard _running;
|
||||
TimeMs _next = 0;
|
||||
crl::time _next = 0;
|
||||
int _timeout = 0;
|
||||
|
||||
Qt::TimerType _type : 2;
|
||||
|
||||
@@ -602,36 +602,38 @@ public:
|
||||
using parent::contains;
|
||||
using parent::erase;
|
||||
|
||||
iterator insert(const Type &value) {
|
||||
std::pair<iterator, bool> insert(const Type &value) {
|
||||
if (this->empty() || this->compare()(value, this->front())) {
|
||||
this->impl().push_front(value);
|
||||
return this->begin();
|
||||
return std::make_pair(this->begin(), true);
|
||||
} else if (this->compare()(this->back(), value)) {
|
||||
this->impl().push_back(value);
|
||||
return (this->end() - 1);
|
||||
return std::make_pair(this->end() - 1, true);
|
||||
}
|
||||
auto where = this->getLowerBound(value);
|
||||
if (this->compare()(value, *where)) {
|
||||
return this->impl().insert(where, value);
|
||||
return std::make_pair(this->impl().insert(where, value), true);
|
||||
}
|
||||
return this->end();
|
||||
return std::make_pair(where, false);
|
||||
}
|
||||
iterator insert(Type &&value) {
|
||||
std::pair<iterator, bool> insert(Type &&value) {
|
||||
if (this->empty() || this->compare()(value, this->front())) {
|
||||
this->impl().push_front(std::move(value));
|
||||
return this->begin();
|
||||
return std::make_pair(this->begin(), true);
|
||||
} else if (this->compare()(this->back(), value)) {
|
||||
this->impl().push_back(std::move(value));
|
||||
return (this->end() - 1);
|
||||
return std::make_pair(this->end() - 1, true);
|
||||
}
|
||||
auto where = this->getLowerBound(value);
|
||||
if (this->compare()(value, *where)) {
|
||||
return this->impl().insert(where, std::move(value));
|
||||
return std::make_pair(
|
||||
this->impl().insert(where, std::move(value)),
|
||||
true);
|
||||
}
|
||||
return this->end();
|
||||
return std::make_pair(where, false);
|
||||
}
|
||||
template <typename... Args>
|
||||
iterator emplace(Args&&... args) {
|
||||
std::pair<iterator, bool> emplace(Args&&... args) {
|
||||
return this->insert(Type(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,20 @@ public:
|
||||
|
||||
using value_type = typename Container::value_type;
|
||||
using difference_type = typename Container::difference_type;
|
||||
using pointer = typename Container::pointer;
|
||||
using reference = typename Container::reference;
|
||||
using pointer = std::conditional_t<
|
||||
std::is_const_v<Container>,
|
||||
typename Container::const_pointer,
|
||||
typename Container::pointer>;
|
||||
using reference = std::conditional_t<
|
||||
std::is_const_v<Container>,
|
||||
typename Container::const_reference,
|
||||
typename Container::reference>;
|
||||
using base_type = std::conditional_t<
|
||||
std::is_const_v<Container>,
|
||||
typename Container::const_iterator,
|
||||
typename Container::iterator>;
|
||||
|
||||
index_based_iterator(
|
||||
Container *container,
|
||||
typename Container::iterator impl)
|
||||
index_based_iterator(Container *container, base_type impl)
|
||||
: _container(container)
|
||||
, _index(impl - _container->begin()) {
|
||||
}
|
||||
@@ -99,7 +107,7 @@ public:
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
typename Container::iterator base() const {
|
||||
base_type base() const {
|
||||
return _container->begin() + _index;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,10 @@ extern "C" {
|
||||
#include <openssl/evp.h>
|
||||
} // extern "C"
|
||||
|
||||
#ifdef small
|
||||
#undef small
|
||||
#endif // small
|
||||
|
||||
namespace openssl {
|
||||
|
||||
class Context {
|
||||
|
||||
@@ -40,7 +40,7 @@ Timer::Timer(Fn<void()> callback)
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
|
||||
void Timer::start(crl::time timeout, Qt::TimerType type, Repeat repeat) {
|
||||
cancel();
|
||||
|
||||
_type = type;
|
||||
@@ -49,7 +49,7 @@ void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
|
||||
setTimeout(timeout);
|
||||
_timerId = startTimer(_timeout, _type);
|
||||
if (_timerId) {
|
||||
_next = crl::time() + _timeout;
|
||||
_next = crl::now() + _timeout;
|
||||
} else {
|
||||
_next = 0;
|
||||
}
|
||||
@@ -61,12 +61,12 @@ void Timer::cancel() {
|
||||
}
|
||||
}
|
||||
|
||||
TimeMs Timer::remainingTime() const {
|
||||
crl::time Timer::remainingTime() const {
|
||||
if (!isActive()) {
|
||||
return -1;
|
||||
}
|
||||
auto now = crl::time();
|
||||
return (_next > now) ? (_next - now) : TimeMs(0);
|
||||
const auto now = crl::now();
|
||||
return (_next > now) ? (_next - now) : crl::time(0);
|
||||
}
|
||||
|
||||
void Timer::Adjust() {
|
||||
@@ -87,7 +87,7 @@ void Timer::adjust() {
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::setTimeout(TimeMs timeout) {
|
||||
void Timer::setTimeout(crl::time timeout) {
|
||||
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
|
||||
|
||||
_timeout = static_cast<unsigned int>(timeout);
|
||||
@@ -102,7 +102,7 @@ void Timer::timerEvent(QTimerEvent *e) {
|
||||
if (_adjusted) {
|
||||
start(_timeout, _type, repeat());
|
||||
} else {
|
||||
_next = crl::time() + _timeout;
|
||||
_next = crl::now() + _timeout;
|
||||
}
|
||||
} else {
|
||||
cancel();
|
||||
@@ -114,7 +114,7 @@ void Timer::timerEvent(QTimerEvent *e) {
|
||||
}
|
||||
|
||||
int DelayedCallTimer::call(
|
||||
TimeMs timeout,
|
||||
crl::time timeout,
|
||||
FnMut<void()> callback,
|
||||
Qt::TimerType type) {
|
||||
Expects(timeout >= 0);
|
||||
|
||||
@@ -21,8 +21,8 @@ public:
|
||||
Fn<void()> callback = nullptr);
|
||||
explicit Timer(Fn<void()> callback = nullptr);
|
||||
|
||||
static Qt::TimerType DefaultType(TimeMs timeout) {
|
||||
constexpr auto kThreshold = TimeMs(1000);
|
||||
static Qt::TimerType DefaultType(crl::time timeout) {
|
||||
constexpr auto kThreshold = crl::time(1000);
|
||||
return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer;
|
||||
}
|
||||
|
||||
@@ -30,19 +30,19 @@ public:
|
||||
_callback = std::move(callback);
|
||||
}
|
||||
|
||||
void callOnce(TimeMs timeout) {
|
||||
void callOnce(crl::time timeout) {
|
||||
callOnce(timeout, DefaultType(timeout));
|
||||
}
|
||||
|
||||
void callEach(TimeMs timeout) {
|
||||
void callEach(crl::time timeout) {
|
||||
callEach(timeout, DefaultType(timeout));
|
||||
}
|
||||
|
||||
void callOnce(TimeMs timeout, Qt::TimerType type) {
|
||||
void callOnce(crl::time timeout, Qt::TimerType type) {
|
||||
start(timeout, type, Repeat::SingleShot);
|
||||
}
|
||||
|
||||
void callEach(TimeMs timeout, Qt::TimerType type) {
|
||||
void callEach(crl::time timeout, Qt::TimerType type) {
|
||||
start(timeout, type, Repeat::Interval);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
}
|
||||
|
||||
void cancel();
|
||||
TimeMs remainingTime() const;
|
||||
crl::time remainingTime() const;
|
||||
|
||||
static void Adjust();
|
||||
|
||||
@@ -63,10 +63,10 @@ private:
|
||||
Interval = 0,
|
||||
SingleShot = 1,
|
||||
};
|
||||
void start(TimeMs timeout, Qt::TimerType type, Repeat repeat);
|
||||
void start(crl::time timeout, Qt::TimerType type, Repeat repeat);
|
||||
void adjust();
|
||||
|
||||
void setTimeout(TimeMs timeout);
|
||||
void setTimeout(crl::time timeout);
|
||||
int timeout() const;
|
||||
|
||||
void setRepeat(Repeat repeat) {
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
}
|
||||
|
||||
Fn<void()> _callback;
|
||||
TimeMs _next = 0;
|
||||
crl::time _next = 0;
|
||||
int _timeout = 0;
|
||||
int _timerId = 0;
|
||||
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
|
||||
class DelayedCallTimer final : private QObject {
|
||||
public:
|
||||
int call(TimeMs timeout, FnMut<void()> callback) {
|
||||
int call(crl::time timeout, FnMut<void()> callback) {
|
||||
return call(
|
||||
timeout,
|
||||
std::move(callback),
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
}
|
||||
|
||||
int call(
|
||||
TimeMs timeout,
|
||||
crl::time timeout,
|
||||
FnMut<void()> callback,
|
||||
Qt::TimerType type);
|
||||
void cancel(int callId);
|
||||
|
||||
@@ -57,12 +57,21 @@ public:
|
||||
}
|
||||
|
||||
~has_weak_ptr() {
|
||||
if (auto alive = _alive.load()) {
|
||||
if (const auto alive = _alive.load()) {
|
||||
alive->value.store(nullptr);
|
||||
details::decrement(alive);
|
||||
}
|
||||
}
|
||||
|
||||
friend inline void invalidate_weak_ptrs(has_weak_ptr *object) {
|
||||
if (auto alive = object->_alive.load()) {
|
||||
if (object->_alive.compare_exchange_strong(alive, nullptr)) {
|
||||
alive->value.store(nullptr);
|
||||
details::decrement(alive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Child>
|
||||
friend class weak_ptr;
|
||||
|
||||
@@ -13,6 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "zip.h"
|
||||
#include "unzip.h"
|
||||
|
||||
#ifdef small
|
||||
#undef small
|
||||
#endif // small
|
||||
|
||||
namespace zlib {
|
||||
namespace internal {
|
||||
|
||||
@@ -172,15 +176,28 @@ public:
|
||||
return error();
|
||||
}
|
||||
|
||||
int goToFirstFile() {
|
||||
if (error() == UNZ_OK) {
|
||||
_error = _handle ? unzGoToFirstFile(_handle) : -1;
|
||||
}
|
||||
return error();
|
||||
}
|
||||
|
||||
int goToNextFile() {
|
||||
if (error() == UNZ_OK) {
|
||||
_error = _handle ? unzGoToNextFile(_handle) : -1;
|
||||
}
|
||||
return error();
|
||||
}
|
||||
|
||||
int getCurrentFileInfo(
|
||||
unz_file_info *pfile_info,
|
||||
char *szFileName,
|
||||
uLong fileNameBufferSize,
|
||||
void *extraField,
|
||||
uLong extraFieldBufferSize,
|
||||
char *szComment,
|
||||
uLong commentBufferSize
|
||||
) {
|
||||
unz_file_info *pfile_info,
|
||||
char *szFileName,
|
||||
uLong fileNameBufferSize,
|
||||
void *extraField,
|
||||
uLong extraFieldBufferSize,
|
||||
char *szComment,
|
||||
uLong commentBufferSize) {
|
||||
if (error() == UNZ_OK) {
|
||||
_error = _handle ? unzGetCurrentFileInfo(
|
||||
_handle,
|
||||
@@ -196,6 +213,21 @@ public:
|
||||
return error();
|
||||
}
|
||||
|
||||
QString getCurrentFileName() {
|
||||
unz_file_info info = { 0 };
|
||||
constexpr auto kMaxName = 128;
|
||||
char name[kMaxName + 1] = { 0 };
|
||||
const auto result = getCurrentFileInfo(
|
||||
&info,
|
||||
name,
|
||||
kMaxName,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
0);
|
||||
return (result == UNZ_OK) ? QString::fromUtf8(name) : QString();
|
||||
}
|
||||
|
||||
int openCurrentFile() {
|
||||
if (error() == UNZ_OK) {
|
||||
_error = _handle ? unzOpenCurrentFile(_handle) : -1;
|
||||
|
||||
@@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "application.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -70,7 +69,7 @@ void AboutBox::showVersionHistory() {
|
||||
}
|
||||
url = url.arg(qsl("talpha%1_%2").arg(cRealAlphaVersion()).arg(Core::countAlphaVersionSignature(cRealAlphaVersion())));
|
||||
|
||||
Application::clipboard()->setText(url);
|
||||
QApplication::clipboard()->setText(url);
|
||||
|
||||
Ui::show(Box<InformBox>("The link to the current private alpha version of Telegram Desktop was copied to the clipboard."));
|
||||
} else {
|
||||
@@ -87,13 +86,19 @@ void AboutBox::keyPressEvent(QKeyEvent *e) {
|
||||
}
|
||||
|
||||
QString telegramFaqLink() {
|
||||
auto result = qsl("https://telegram.org/faq");
|
||||
auto language = Lang::Current().id();
|
||||
for (auto faqLanguage : { "de", "es", "it", "ko", "br" }) {
|
||||
if (language.startsWith(QLatin1String(faqLanguage))) {
|
||||
result.append('/').append(faqLanguage);
|
||||
const auto result = qsl("https://telegram.org/faq");
|
||||
const auto langpacked = [&](const char *language) {
|
||||
return result + '/' + language;
|
||||
};
|
||||
const auto current = Lang::Current().id();
|
||||
for (const auto language : { "de", "es", "it", "ko" }) {
|
||||
if (current.startsWith(QLatin1String(language))) {
|
||||
return langpacked(language);
|
||||
}
|
||||
}
|
||||
if (current.startsWith(qstr("pt-br"))) {
|
||||
return langpacked("br");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -378,11 +378,14 @@ void AbstractBox::updateButtonsPositions() {
|
||||
if (_leftButton) {
|
||||
_leftButton->moveToLeft(right, top);
|
||||
}
|
||||
for_const (auto &button, _buttons) {
|
||||
for (const auto &button : _buttons) {
|
||||
button->moveToRight(right, top);
|
||||
right += button->width() + padding.left();
|
||||
}
|
||||
}
|
||||
if (_topButton) {
|
||||
_topButton->moveToRight(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
QPointer<QWidget> AbstractBox::outerContainer() {
|
||||
@@ -403,6 +406,7 @@ void AbstractBox::clearButtons() {
|
||||
button.destroy();
|
||||
}
|
||||
_leftButton.destroy();
|
||||
_topButton = nullptr;
|
||||
}
|
||||
|
||||
QPointer<Ui::RoundButton> AbstractBox::addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) {
|
||||
@@ -423,6 +427,15 @@ QPointer<Ui::RoundButton> AbstractBox::addLeftButton(Fn<QString()> textFactory,
|
||||
return result;
|
||||
}
|
||||
|
||||
QPointer<Ui::IconButton> AbstractBox::addTopButton(const style::IconButton &st, Fn<void()> clickCallback) {
|
||||
_topButton = base::make_unique_q<Ui::IconButton>(this, st);
|
||||
auto result = QPointer<Ui::IconButton>(_topButton.get());
|
||||
result->setClickedCallback(std::move(clickCallback));
|
||||
result->show();
|
||||
updateButtonsPositions();
|
||||
return result;
|
||||
}
|
||||
|
||||
void AbstractBox::setDimensions(int newWidth, int maxHeight) {
|
||||
_maxContentHeight = maxHeight;
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "window/layer_widget.h"
|
||||
#include "base/unique_qptr.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace style {
|
||||
struct RoundButton;
|
||||
struct IconButton;
|
||||
struct ScrollArea;
|
||||
} // namespace style
|
||||
|
||||
@@ -35,6 +37,7 @@ public:
|
||||
virtual void clearButtons() = 0;
|
||||
virtual QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) = 0;
|
||||
virtual QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) = 0;
|
||||
virtual QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback) = 0;
|
||||
virtual void updateButtonsPositions() = 0;
|
||||
|
||||
virtual void showBox(
|
||||
@@ -100,8 +103,14 @@ public:
|
||||
void clearButtons() {
|
||||
getDelegate()->clearButtons();
|
||||
}
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback);
|
||||
QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback);
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback = nullptr);
|
||||
QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback = nullptr);
|
||||
QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback = nullptr) {
|
||||
return getDelegate()->addTopButton(st, std::move(clickCallback));
|
||||
}
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, const style::RoundButton &st) {
|
||||
return getDelegate()->addButton(std::move(textFactory), nullptr, st);
|
||||
}
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) {
|
||||
return getDelegate()->addButton(std::move(textFactory), std::move(clickCallback), st);
|
||||
}
|
||||
@@ -251,6 +260,7 @@ public:
|
||||
void clearButtons() override;
|
||||
QPointer<Ui::RoundButton> addButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) override;
|
||||
QPointer<Ui::RoundButton> addLeftButton(Fn<QString()> textFactory, Fn<void()> clickCallback, const style::RoundButton &st) override;
|
||||
QPointer<Ui::IconButton> addTopButton(const style::IconButton &st, Fn<void()> clickCallback) override;
|
||||
void updateButtonsPositions() override;
|
||||
QPointer<QWidget> outerContainer() override;
|
||||
|
||||
@@ -319,6 +329,7 @@ private:
|
||||
|
||||
std::vector<object_ptr<Ui::RoundButton>> _buttons;
|
||||
object_ptr<Ui::RoundButton> _leftButton = { nullptr };
|
||||
base::unique_qptr<Ui::IconButton> _topButton = { nullptr };
|
||||
|
||||
};
|
||||
|
||||
@@ -337,3 +348,45 @@ enum CreatingGroupType {
|
||||
CreatingGroupGroup,
|
||||
CreatingGroupChannel,
|
||||
};
|
||||
|
||||
class BoxPointer {
|
||||
public:
|
||||
BoxPointer() = default;
|
||||
BoxPointer(const BoxPointer &other) = default;
|
||||
BoxPointer(BoxPointer &&other) : _value(base::take(other._value)) {
|
||||
}
|
||||
BoxPointer &operator=(const BoxPointer &other) {
|
||||
if (_value != other._value) {
|
||||
destroy();
|
||||
_value = other._value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BoxPointer &operator=(BoxPointer &&other) {
|
||||
if (_value != other._value) {
|
||||
destroy();
|
||||
_value = base::take(other._value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BoxPointer &operator=(BoxContent *other) {
|
||||
if (_value != other) {
|
||||
destroy();
|
||||
_value = other;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~BoxPointer() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
void destroy() {
|
||||
if (const auto value = base::take(_value)) {
|
||||
value->closeBox();
|
||||
}
|
||||
}
|
||||
|
||||
QPointer<BoxContent> _value;
|
||||
|
||||
};
|
||||
|
||||
@@ -10,13 +10,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "messenger.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "base/flat_set.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/photo_crop_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/add_participants_box.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 "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
@@ -25,6 +28,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
@@ -59,7 +66,7 @@ style::InputField CreateBioFieldStyle() {
|
||||
|
||||
QString PeerFloodErrorText(PeerFloodType type) {
|
||||
auto link = textcmdLink(
|
||||
Messenger::Instance().createInternalLinkFull(qsl("spambot")),
|
||||
Core::App().createInternalLinkFull(qsl("spambot")),
|
||||
lang(lng_cant_more_info));
|
||||
if (type == PeerFloodType::InviteGroup) {
|
||||
return lng_cant_invite_not_contact(lt_more_info, link);
|
||||
@@ -67,6 +74,77 @@ QString PeerFloodErrorText(PeerFloodType type) {
|
||||
return lng_cant_send_to_not_contact(lt_more_info, link);
|
||||
}
|
||||
|
||||
void ShowAddParticipantsError(
|
||||
const QString &error,
|
||||
not_null<PeerData*> chat,
|
||||
const std::vector<not_null<UserData*>> &users) {
|
||||
if (error == qstr("USER_BOT")) {
|
||||
const auto channel = chat->asChannel();
|
||||
if ((users.size() == 1)
|
||||
&& (users.front()->botInfo != nullptr)
|
||||
&& channel
|
||||
&& !channel->isMegagroup()
|
||||
&& channel->canAddAdmins()) {
|
||||
const auto makeAdmin = [=] {
|
||||
const auto user = users.front();
|
||||
const auto weak = std::make_shared<QPointer<EditAdminBox>>();
|
||||
const auto close = [=](auto&&...) {
|
||||
if (*weak) {
|
||||
(*weak)->closeBox();
|
||||
}
|
||||
};
|
||||
const auto saveCallback = SaveAdminCallback(
|
||||
channel,
|
||||
user,
|
||||
close,
|
||||
close);
|
||||
auto box = Box<EditAdminBox>(
|
||||
channel,
|
||||
user,
|
||||
MTP_chatAdminRights(MTP_flags(0)));
|
||||
box->setSaveCallback(saveCallback);
|
||||
*weak = Ui::show(std::move(box));
|
||||
};
|
||||
Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
lang(lng_cant_invite_offer_admin),
|
||||
lang(lng_cant_invite_make_admin),
|
||||
lang(lng_cancel),
|
||||
makeAdmin),
|
||||
LayerOption::KeepOther);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto bot = ranges::find_if(users, [](not_null<UserData*> user) {
|
||||
return user->botInfo != nullptr;
|
||||
});
|
||||
const auto hasBot = (bot != end(users));
|
||||
const auto text = [&] {
|
||||
if (error == qstr("USER_BOT")) {
|
||||
return lang(lng_cant_invite_bot_to_channel);
|
||||
} else if (error == qstr("USER_LEFT_CHAT")) {
|
||||
// Trying to return a user who has left.
|
||||
} else if (error == qstr("USER_KICKED")) {
|
||||
// Trying to return a user who was kicked by admin.
|
||||
return lang(lng_cant_invite_banned);
|
||||
} else if (error == qstr("USER_PRIVACY_RESTRICTED")) {
|
||||
return lang(lng_cant_invite_privacy);
|
||||
} else if (error == qstr("USER_NOT_MUTUAL_CONTACT")) {
|
||||
// Trying to return user who does not have me in contacts.
|
||||
return lang(lng_failed_add_not_mutual);
|
||||
} else if (error == qstr("USER_ALREADY_PARTICIPANT") && hasBot) {
|
||||
return lang(lng_bot_already_in_group);
|
||||
} else if (error == qstr("PEER_FLOOD")) {
|
||||
const auto isGroup = (chat->isChat() || chat->isMegagroup());
|
||||
return PeerFloodErrorText(isGroup
|
||||
? PeerFloodType::InviteGroup
|
||||
: PeerFloodType::InviteChannel);
|
||||
}
|
||||
return lang(lng_failed_add_participant);
|
||||
}();
|
||||
Ui::show(Box<InformBox>(text), LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
class RevokePublicLinkBox::Inner : public TWidget, private MTP::Sender {
|
||||
public:
|
||||
Inner(QWidget *parent, Fn<void()> revokeCallback);
|
||||
@@ -244,8 +322,9 @@ bool AddContactBox::onSaveUserFail(const RPCError &error) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
_addRequest = 0;
|
||||
QString err(error.type());
|
||||
QString firstName = _first->getLastText().trimmed(), lastName = _last->getLastText().trimmed();
|
||||
const auto &err = error.type();
|
||||
const auto firstName = _first->getLastText().trimmed();
|
||||
const auto lastName = _last->getLastText().trimmed();
|
||||
if (err == "CHAT_TITLE_NOT_MODIFIED") {
|
||||
_user->setName(firstName, lastName, _user->nameOrPhone, _user->username);
|
||||
closeBox();
|
||||
@@ -263,21 +342,21 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
|
||||
if (!isBoxShown() || !App::main()) return;
|
||||
|
||||
const auto &d = res.c_contacts_importedContacts();
|
||||
App::feedUsers(d.vusers);
|
||||
Auth().data().processUsers(d.vusers);
|
||||
|
||||
const auto &v = d.vimported.v;
|
||||
const auto user = [&]() -> UserData* {
|
||||
if (!v.isEmpty()) {
|
||||
auto &c = v.front().c_importedContact();
|
||||
if (c.vclient_id.v == _contactId) {
|
||||
return App::userLoaded(c.vuser_id.v);
|
||||
return Auth().data().userLoaded(c.vuser_id.v);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
if (user) {
|
||||
if (user->contactStatus() == UserData::ContactStatus::Contact
|
||||
|| Auth().supportMode()) {
|
||||
|| user->session().supportMode()) {
|
||||
Ui::showPeerHistory(user, ShowAtTheEndMsgId);
|
||||
}
|
||||
Ui::hideLayer();
|
||||
@@ -291,7 +370,7 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
|
||||
|
||||
void AddContactBox::onSaveUserDone(const MTPcontacts_ImportedContacts &res) {
|
||||
auto &d = res.c_contacts_importedContacts();
|
||||
App::feedUsers(d.vusers);
|
||||
Auth().data().processUsers(d.vusers);
|
||||
closeBox();
|
||||
}
|
||||
|
||||
@@ -329,9 +408,9 @@ void GroupInfoBox::prepare() {
|
||||
|
||||
_photo.create(
|
||||
this,
|
||||
(_creating == CreatingGroupChannel)
|
||||
? peerFromChannel(0)
|
||||
: peerFromChat(0),
|
||||
lang((_creating == CreatingGroupChannel)
|
||||
? lng_create_channel_crop
|
||||
: lng_create_group_crop),
|
||||
Ui::UserpicButton::Role::ChangePhoto,
|
||||
st::defaultUserpicButton);
|
||||
_title.create(
|
||||
@@ -458,11 +537,13 @@ void GroupInfoBox::createGroup(
|
||||
: std::nullopt;
|
||||
}
|
||||
| [](auto chats) {
|
||||
return App::chat(chats->front().c_chat().vid.v);
|
||||
return Auth().data().chat(chats->front().c_chat().vid.v);
|
||||
}
|
||||
| [&](not_null<ChatData*> chat) {
|
||||
if (!image.isNull()) {
|
||||
Auth().api().uploadPeerPhoto(chat, std::move(image));
|
||||
chat->session().api().uploadPeerPhoto(
|
||||
chat,
|
||||
std::move(image));
|
||||
}
|
||||
Ui::showPeerHistory(chat, ShowAtUnreadMsgId);
|
||||
};
|
||||
@@ -531,8 +612,7 @@ void GroupInfoBox::submit() {
|
||||
};
|
||||
Ui::show(
|
||||
Box<PeerListBox>(
|
||||
std::make_unique<AddParticipantsBoxController>(
|
||||
nullptr),
|
||||
std::make_unique<AddParticipantsBoxController>(),
|
||||
std::move(initBox)),
|
||||
LayerOption::KeepOther);
|
||||
}
|
||||
@@ -541,7 +621,11 @@ void GroupInfoBox::submit() {
|
||||
void GroupInfoBox::createChannel(const QString &title, const QString &description) {
|
||||
bool mega = false;
|
||||
auto flags = mega ? MTPchannels_CreateChannel::Flag::f_megagroup : MTPchannels_CreateChannel::Flag::f_broadcast;
|
||||
_creationRequestId = request(MTPchannels_CreateChannel(MTP_flags(flags), MTP_string(title), MTP_string(description))).done([this](const MTPUpdates &result) {
|
||||
_creationRequestId = request(MTPchannels_CreateChannel(
|
||||
MTP_flags(flags),
|
||||
MTP_string(title),
|
||||
MTP_string(description)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
Auth().api().applyUpdates(result);
|
||||
|
||||
auto success = base::make_optional(&result)
|
||||
@@ -561,17 +645,19 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
|
||||
: std::nullopt;
|
||||
}
|
||||
| [](auto chats) {
|
||||
return App::channel(chats->front().c_channel().vid.v);
|
||||
return Auth().data().channel(chats->front().c_channel().vid.v);
|
||||
}
|
||||
| [this](not_null<ChannelData*> channel) {
|
||||
| [&](not_null<ChannelData*> channel) {
|
||||
auto image = _photo->takeResultImage();
|
||||
if (!image.isNull()) {
|
||||
Auth().api().uploadPeerPhoto(channel, std::move(image));
|
||||
channel->session().api().uploadPeerPhoto(
|
||||
channel,
|
||||
std::move(image));
|
||||
}
|
||||
_createdChannel = channel;
|
||||
_creationRequestId = request(
|
||||
MTPchannels_ExportInvite(_createdChannel->inputChannel)
|
||||
).done([this](const MTPExportedChatInvite &result) {
|
||||
_creationRequestId = request(MTPmessages_ExportChatInvite(
|
||||
_createdChannel->input
|
||||
)).done([=](const MTPExportedChatInvite &result) {
|
||||
_creationRequestId = 0;
|
||||
if (result.type() == mtpc_chatInviteExported) {
|
||||
auto link = qs(result.c_chatInviteExported().vlink);
|
||||
@@ -749,7 +835,7 @@ void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) {
|
||||
void SetupChannelBox::mousePressEvent(QMouseEvent *e) {
|
||||
if (_linkOver) {
|
||||
if (_channel->inviteLink().isEmpty()) {
|
||||
Auth().api().exportInviteLink(_channel);
|
||||
_channel->session().api().exportInviteLink(_channel);
|
||||
} else {
|
||||
QGuiApplication::clipboard()->setText(_channel->inviteLink());
|
||||
Ui::Toast::Show(lang(lng_create_channel_link_copied));
|
||||
@@ -1069,7 +1155,7 @@ void EditNameBox::save() {
|
||||
}
|
||||
|
||||
void EditNameBox::saveSelfDone(const MTPUser &user) {
|
||||
App::feedUsers(MTP_vector<MTPUser>(1, user));
|
||||
_user->owner().processUsers(MTP_vector<MTPUser>(1, user));
|
||||
closeBox();
|
||||
}
|
||||
|
||||
@@ -1096,261 +1182,6 @@ bool EditNameBox::saveSelfFail(const RPCError &error) {
|
||||
return true;
|
||||
}
|
||||
|
||||
EditChannelBox::EditChannelBox(QWidget*, not_null<ChannelData*> channel)
|
||||
: _channel(channel)
|
||||
, _title(this, st::defaultInputField, langFactory(_channel->isMegagroup() ? lng_dlg_new_group_name : lng_dlg_new_channel_name), _channel->name)
|
||||
, _description(
|
||||
this,
|
||||
st::newGroupDescription,
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
langFactory(lng_create_group_description),
|
||||
_channel->about())
|
||||
, _sign(this, lang(lng_edit_sign_messages), channel->addsSignature(), st::defaultBoxCheckbox)
|
||||
, _inviteGroup(std::make_shared<Ui::RadioenumGroup<Invites>>(channel->anyoneCanAddMembers() ? Invites::Everybody : Invites::OnlyAdmins))
|
||||
, _inviteEverybody(this, _inviteGroup, Invites::Everybody, lang(lng_edit_group_invites_everybody))
|
||||
, _inviteOnlyAdmins(this, _inviteGroup, Invites::OnlyAdmins, lang(lng_edit_group_invites_only_admins))
|
||||
, _publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), st::boxLinkButton) {
|
||||
}
|
||||
|
||||
void EditChannelBox::prepare() {
|
||||
setTitle(langFactory(_channel->isMegagroup() ? lng_edit_group : lng_edit_channel_title));
|
||||
|
||||
addButton(langFactory(lng_settings_save), [this] { save(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
|
||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::NameChanged, [this](const Notify::PeerUpdate &update) {
|
||||
if (update.peer == _channel) {
|
||||
handleChannelNameChange();
|
||||
}
|
||||
}));
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
_title->setMaxLength(kMaxGroupChannelTitle);
|
||||
_title->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
_title->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
Ui::Emoji::SuggestionsController::Init(
|
||||
getDelegate()->outerContainer(),
|
||||
_title);
|
||||
|
||||
_description->setMaxLength(kMaxChannelDescription);
|
||||
_description->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
_description->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
|
||||
connect(_description, &Ui::InputField::resized, [=] { descriptionResized(); });
|
||||
connect(_description, &Ui::InputField::submitted, [=] { save(); });
|
||||
connect(_description, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
Ui::Emoji::SuggestionsController::Init(
|
||||
getDelegate()->outerContainer(),
|
||||
_description);
|
||||
|
||||
_publicLink->addClickHandler([=] { setupPublicLink(); });
|
||||
_publicLink->setVisible(_channel->canEditUsername());
|
||||
_sign->setVisible(canEditSignatures());
|
||||
_inviteEverybody->setVisible(canEditInvites());
|
||||
_inviteOnlyAdmins->setVisible(canEditInvites());
|
||||
|
||||
updateMaxHeight();
|
||||
}
|
||||
|
||||
void EditChannelBox::setInnerFocus() {
|
||||
_title->setFocusFast();
|
||||
}
|
||||
|
||||
void EditChannelBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
if (_title->hasFocus()) {
|
||||
save();
|
||||
}
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void EditChannelBox::handleChannelNameChange() {
|
||||
_publicLink->setText(lang(_channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link));
|
||||
_sign->setChecked(_channel->addsSignature());
|
||||
}
|
||||
|
||||
void EditChannelBox::descriptionResized() {
|
||||
updateMaxHeight();
|
||||
update();
|
||||
}
|
||||
|
||||
bool EditChannelBox::canEditSignatures() const {
|
||||
return _channel->canEditInformation() && !_channel->isMegagroup();
|
||||
}
|
||||
|
||||
bool EditChannelBox::canEditInvites() const {
|
||||
return _channel->canEditInformation() && _channel->isMegagroup();
|
||||
}
|
||||
|
||||
void EditChannelBox::updateMaxHeight() {
|
||||
auto newHeight = st::newGroupInfoPadding.top() + _title->height();
|
||||
newHeight += st::newGroupDescriptionPadding.top() + _description->height() + st::newGroupDescriptionPadding.bottom();
|
||||
if (canEditSignatures()) {
|
||||
newHeight += st::newGroupPublicLinkPadding.top() + _sign->heightNoMargins() + st::newGroupPublicLinkPadding.bottom();
|
||||
}
|
||||
if (canEditInvites()) {
|
||||
newHeight += st::boxTitleHeight + _inviteEverybody->heightNoMargins();
|
||||
newHeight += st::boxLittleSkip + _inviteOnlyAdmins->heightNoMargins();
|
||||
}
|
||||
if (_channel->canEditUsername()) {
|
||||
newHeight += st::newGroupPublicLinkPadding.top() + _publicLink->height() + st::newGroupPublicLinkPadding.bottom();
|
||||
}
|
||||
newHeight += st::boxPadding.bottom() + st::newGroupInfoPadding.bottom();
|
||||
setDimensions(st::boxWideWidth, newHeight);
|
||||
}
|
||||
|
||||
void EditChannelBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _title->height());
|
||||
_title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::newGroupInfoPadding.top() + st::newGroupNamePosition.y());
|
||||
|
||||
_description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description->height());
|
||||
_description->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _title->y() + _title->height() + st::newGroupDescriptionPadding.top());
|
||||
|
||||
_sign->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
|
||||
|
||||
_inviteEverybody->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::boxTitleHeight);
|
||||
_inviteOnlyAdmins->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _inviteEverybody->bottomNoMargins() + st::boxLittleSkip);
|
||||
|
||||
if (canEditSignatures()) {
|
||||
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _sign->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
|
||||
} else if (canEditInvites()) {
|
||||
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _inviteOnlyAdmins->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
|
||||
} else {
|
||||
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
|
||||
}
|
||||
}
|
||||
|
||||
void EditChannelBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
if (canEditInvites()) {
|
||||
Painter p(this);
|
||||
p.setPen(st::boxTitleFg);
|
||||
p.setFont(st::autoDownloadTitleFont);
|
||||
p.drawTextLeft(st::boxTitlePosition.x(), _description->y() + _description->height() + st::boxTitlePosition.y(), width(), lang(lng_edit_group_who_invites));
|
||||
}
|
||||
}
|
||||
|
||||
void EditChannelBox::save() {
|
||||
if (_saveTitleRequestId || _saveDescriptionRequestId || _saveSignRequestId || _saveInvitesRequestId) return;
|
||||
|
||||
auto title = TextUtilities::PrepareForSending(_title->getLastText());
|
||||
auto description = TextUtilities::PrepareForSending(_description->getLastText(), TextUtilities::PrepareTextOption::CheckLinks);
|
||||
if (title.isEmpty()) {
|
||||
_title->setFocus();
|
||||
_title->showError();
|
||||
return;
|
||||
}
|
||||
_sentTitle = title;
|
||||
_sentDescription = description;
|
||||
if (_sentTitle == _channel->name) {
|
||||
saveDescription();
|
||||
} else {
|
||||
_saveTitleRequestId = MTP::send(MTPchannels_EditTitle(_channel->inputChannel, MTP_string(_sentTitle)), rpcDone(&EditChannelBox::onSaveTitleDone), rpcFail(&EditChannelBox::onSaveFail));
|
||||
}
|
||||
}
|
||||
|
||||
void EditChannelBox::setupPublicLink() {
|
||||
Ui::show(
|
||||
Box<SetupChannelBox>(_channel, true),
|
||||
LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void EditChannelBox::saveDescription() {
|
||||
if (_sentDescription == _channel->about()) {
|
||||
saveSign();
|
||||
} else {
|
||||
_saveDescriptionRequestId = MTP::send(MTPchannels_EditAbout(_channel->inputChannel, MTP_string(_sentDescription)), rpcDone(&EditChannelBox::onSaveDescriptionDone), rpcFail(&EditChannelBox::onSaveFail));
|
||||
}
|
||||
}
|
||||
|
||||
void EditChannelBox::saveSign() {
|
||||
if (!canEditSignatures() || _channel->addsSignature() == _sign->checked()) {
|
||||
saveInvites();
|
||||
} else {
|
||||
_saveSignRequestId = MTP::send(MTPchannels_ToggleSignatures(_channel->inputChannel, MTP_bool(_sign->checked())), rpcDone(&EditChannelBox::onSaveSignDone), rpcFail(&EditChannelBox::onSaveFail));
|
||||
}
|
||||
}
|
||||
|
||||
void EditChannelBox::saveInvites() {
|
||||
if (!canEditInvites() || _channel->anyoneCanAddMembers() == (_inviteGroup->value() == Invites::Everybody)) {
|
||||
closeBox();
|
||||
} else {
|
||||
_saveInvitesRequestId = MTP::send(MTPchannels_ToggleInvites(_channel->inputChannel, MTP_bool(_inviteGroup->value() == Invites::Everybody)), rpcDone(&EditChannelBox::onSaveInvitesDone), rpcFail(&EditChannelBox::onSaveFail));
|
||||
}
|
||||
}
|
||||
|
||||
bool EditChannelBox::onSaveFail(const RPCError &error, mtpRequestId req) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
QString err(error.type());
|
||||
if (req == _saveTitleRequestId) {
|
||||
_saveTitleRequestId = 0;
|
||||
if (err == qstr("CHAT_NOT_MODIFIED") || err == qstr("CHAT_TITLE_NOT_MODIFIED")) {
|
||||
_channel->setName(_sentTitle, _channel->username);
|
||||
saveDescription();
|
||||
return true;
|
||||
} else if (err == qstr("NO_CHAT_TITLE")) {
|
||||
_title->setFocus();
|
||||
_title->showError();
|
||||
return true;
|
||||
} else {
|
||||
_title->setFocus();
|
||||
}
|
||||
} else if (req == _saveDescriptionRequestId) {
|
||||
_saveDescriptionRequestId = 0;
|
||||
if (err == qstr("CHAT_ABOUT_NOT_MODIFIED")) {
|
||||
_channel->setAbout(_sentDescription);
|
||||
saveSign();
|
||||
return true;
|
||||
} else {
|
||||
_description->setFocus();
|
||||
}
|
||||
} else if (req == _saveSignRequestId) {
|
||||
_saveSignRequestId = 0;
|
||||
if (err == qstr("CHAT_NOT_MODIFIED")) {
|
||||
saveInvites();
|
||||
return true;
|
||||
}
|
||||
} else if (req == _saveInvitesRequestId) {
|
||||
_saveInvitesRequestId = 0;
|
||||
if (err == qstr("CHAT_NOT_MODIFIED")) {
|
||||
closeBox();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditChannelBox::onSaveTitleDone(const MTPUpdates &result) {
|
||||
_saveTitleRequestId = 0;
|
||||
Auth().api().applyUpdates(result);
|
||||
saveDescription();
|
||||
}
|
||||
|
||||
void EditChannelBox::onSaveDescriptionDone(const MTPBool &result) {
|
||||
_saveDescriptionRequestId = 0;
|
||||
_channel->setAbout(_sentDescription);
|
||||
saveSign();
|
||||
}
|
||||
|
||||
void EditChannelBox::onSaveSignDone(const MTPUpdates &result) {
|
||||
_saveSignRequestId = 0;
|
||||
Auth().api().applyUpdates(result);
|
||||
saveInvites();
|
||||
}
|
||||
|
||||
void EditChannelBox::onSaveInvitesDone(const MTPUpdates &result) {
|
||||
_saveSignRequestId = 0;
|
||||
Auth().api().applyUpdates(result);
|
||||
closeBox();
|
||||
}
|
||||
|
||||
RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn<void()> revokeCallback) : TWidget(parent)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
, _revokeWidth(st::normalFont->width(lang(lng_channels_too_much_public_revoke)))
|
||||
@@ -1359,27 +1190,29 @@ RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn<void()> revokeCallback) :
|
||||
|
||||
resize(width(), 5 * _rowHeight);
|
||||
|
||||
request(MTPchannels_GetAdminedPublicChannels()).done([this](const MTPmessages_Chats &result) {
|
||||
if (auto chats = Api::getChatsFromMessagesChats(result)) {
|
||||
for_const (auto &chat, chats->v) {
|
||||
if (auto peer = App::feedChat(chat)) {
|
||||
if (!peer->isChannel() || peer->userName().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto row = ChatRow(peer);
|
||||
row.peer = peer;
|
||||
row.name.setText(
|
||||
st::contactsNameStyle,
|
||||
peer->name,
|
||||
Ui::NameTextOptions());
|
||||
row.status.setText(
|
||||
st::defaultTextStyle,
|
||||
Messenger::Instance().createInternalLink(
|
||||
textcmdLink(1, peer->userName())),
|
||||
Ui::DialogTextOptions());
|
||||
_rows.push_back(std::move(row));
|
||||
request(MTPchannels_GetAdminedPublicChannels(
|
||||
)).done([=](const MTPmessages_Chats &result) {
|
||||
const auto &chats = result.match([](const auto &data) {
|
||||
return data.vchats.v;
|
||||
});
|
||||
for (const auto &chat : chats) {
|
||||
if (const auto peer = Auth().data().processChat(chat)) {
|
||||
if (!peer->isChannel() || peer->userName().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto row = ChatRow(peer);
|
||||
row.peer = peer;
|
||||
row.name.setText(
|
||||
st::contactsNameStyle,
|
||||
peer->name,
|
||||
Ui::NameTextOptions());
|
||||
row.status.setText(
|
||||
st::defaultTextStyle,
|
||||
Core::App().createInternalLink(
|
||||
textcmdLink(1, peer->userName())),
|
||||
Ui::DialogTextOptions());
|
||||
_rows.push_back(std::move(row));
|
||||
}
|
||||
}
|
||||
resize(width(), _rows.size() * _rowHeight);
|
||||
@@ -1387,23 +1220,30 @@ RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn<void()> revokeCallback) :
|
||||
}).send();
|
||||
}
|
||||
|
||||
RevokePublicLinkBox::RevokePublicLinkBox(QWidget*, Fn<void()> revokeCallback)
|
||||
: _aboutRevoke(this, lang(lng_channels_too_much_public_about), Ui::FlatLabel::InitType::Simple, st::aboutRevokePublicLabel)
|
||||
RevokePublicLinkBox::RevokePublicLinkBox(
|
||||
QWidget*,
|
||||
Fn<void()> revokeCallback)
|
||||
: _aboutRevoke(
|
||||
this,
|
||||
lang(lng_channels_too_much_public_about),
|
||||
Ui::FlatLabel::InitType::Simple,
|
||||
st::aboutRevokePublicLabel)
|
||||
, _revokeCallback(std::move(revokeCallback)) {
|
||||
}
|
||||
|
||||
void RevokePublicLinkBox::prepare() {
|
||||
_innerTop = st::boxPadding.top() + _aboutRevoke->height() + st::boxPadding.top();
|
||||
_inner = setInnerWidget(object_ptr<Inner>(this, [this] {
|
||||
_inner = setInnerWidget(object_ptr<Inner>(this, [=] {
|
||||
const auto callback = _revokeCallback;
|
||||
closeBox();
|
||||
if (_revokeCallback) {
|
||||
_revokeCallback();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}), st::boxLayerScroll, _innerTop);
|
||||
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
|
||||
subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
|
||||
|
||||
_inner->resizeToWidth(st::boxWideWidth);
|
||||
setDimensions(st::boxWideWidth, _innerTop + _inner->height());
|
||||
@@ -1444,16 +1284,20 @@ void RevokePublicLinkBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default);
|
||||
if (pressed && pressed == _selected) {
|
||||
auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel;
|
||||
auto text = text_method(lt_link, Messenger::Instance().createInternalLink(pressed->userName()), lt_group, pressed->name);
|
||||
auto text = text_method(lt_link, Core::App().createInternalLink(pressed->userName()), lt_group, pressed->name);
|
||||
auto confirmText = lang(lng_channels_too_much_public_revoke);
|
||||
_weakRevokeConfirmBox = Ui::show(Box<ConfirmBox>(text, confirmText, crl::guard(this, [this, pressed]() {
|
||||
if (_revokeRequestId) return;
|
||||
_revokeRequestId = request(MTPchannels_UpdateUsername(pressed->asChannel()->inputChannel, MTP_string(""))).done([this](const MTPBool &result) {
|
||||
_revokeRequestId = request(MTPchannels_UpdateUsername(
|
||||
pressed->asChannel()->inputChannel,
|
||||
MTP_string("")
|
||||
)).done([=](const MTPBool &result) {
|
||||
const auto callback = _revokeCallback;
|
||||
if (_weakRevokeConfirmBox) {
|
||||
_weakRevokeConfirmBox->closeBox();
|
||||
}
|
||||
if (_revokeCallback) {
|
||||
_revokeCallback();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}).send();
|
||||
})), LayerOption::KeepOther);
|
||||
|
||||
@@ -38,6 +38,10 @@ enum class PeerFloodType {
|
||||
InviteChannel,
|
||||
};
|
||||
QString PeerFloodErrorText(PeerFloodType type);
|
||||
void ShowAddParticipantsError(
|
||||
const QString &error,
|
||||
not_null<PeerData*> chat,
|
||||
const std::vector<not_null<UserData*>> &users);
|
||||
|
||||
class AddContactBox : public BoxContent, public RPCSender {
|
||||
public:
|
||||
@@ -96,7 +100,6 @@ private:
|
||||
|
||||
void descriptionResized();
|
||||
void updateMaxHeight();
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
|
||||
CreatingGroupType _creating;
|
||||
bool _fromTypeChoose = false;
|
||||
@@ -134,7 +137,6 @@ private:
|
||||
};
|
||||
void privacyChanged(Privacy value);
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
void showAddContactsToChannelBox() const;
|
||||
void handleChange();
|
||||
void check();
|
||||
void save();
|
||||
@@ -201,62 +203,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class EditChannelBox : public BoxContent, public RPCSender {
|
||||
public:
|
||||
EditChannelBox(QWidget*, not_null<ChannelData*> channel);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
void setInnerFocus() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
void updateMaxHeight();
|
||||
bool canEditSignatures() const;
|
||||
bool canEditInvites() const;
|
||||
void handleChannelNameChange();
|
||||
void descriptionResized();
|
||||
void setupPublicLink();
|
||||
void save();
|
||||
|
||||
void onSaveTitleDone(const MTPUpdates &result);
|
||||
void onSaveDescriptionDone(const MTPBool &result);
|
||||
void onSaveSignDone(const MTPUpdates &result);
|
||||
void onSaveInvitesDone(const MTPUpdates &result);
|
||||
bool onSaveFail(const RPCError &error, mtpRequestId req);
|
||||
|
||||
void saveDescription();
|
||||
void saveSign();
|
||||
void saveInvites();
|
||||
|
||||
not_null<ChannelData*> _channel;
|
||||
|
||||
object_ptr<Ui::InputField> _title;
|
||||
object_ptr<Ui::InputField> _description;
|
||||
object_ptr<Ui::Checkbox> _sign;
|
||||
|
||||
enum class Invites {
|
||||
Everybody,
|
||||
OnlyAdmins,
|
||||
};
|
||||
std::shared_ptr<Ui::RadioenumGroup<Invites>> _inviteGroup;
|
||||
object_ptr<Ui::Radioenum<Invites>> _inviteEverybody;
|
||||
object_ptr<Ui::Radioenum<Invites>> _inviteOnlyAdmins;
|
||||
|
||||
object_ptr<Ui::LinkButton> _publicLink;
|
||||
|
||||
mtpRequestId _saveTitleRequestId = 0;
|
||||
mtpRequestId _saveDescriptionRequestId = 0;
|
||||
mtpRequestId _saveSignRequestId = 0;
|
||||
mtpRequestId _saveInvitesRequestId = 0;
|
||||
|
||||
QString _sentTitle, _sentDescription;
|
||||
|
||||
};
|
||||
|
||||
class RevokePublicLinkBox : public BoxContent, public RPCSender {
|
||||
public:
|
||||
RevokePublicLinkBox(QWidget*, Fn<void()> revokeCallback);
|
||||
|
||||
179
Telegram/SourceFiles/boxes/auto_download_box.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
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/auto_download_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "auth_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "info/profile/info_profile_button.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/wrap.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "export/view/export_view_settings.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMegabyte = 1024 * 1024;
|
||||
constexpr auto kDefaultLimit = 10 * kMegabyte;
|
||||
|
||||
} // namespace
|
||||
|
||||
AutoDownloadBox::AutoDownloadBox(
|
||||
QWidget*,
|
||||
Data::AutoDownload::Source source)
|
||||
: _source(source) {
|
||||
}
|
||||
|
||||
void AutoDownloadBox::prepare() {
|
||||
setupContent();
|
||||
}
|
||||
|
||||
void AutoDownloadBox::setupContent() {
|
||||
using namespace Settings;
|
||||
using namespace Data::AutoDownload;
|
||||
using namespace rpl::mappers;
|
||||
using Type = Data::AutoDownload::Type;
|
||||
|
||||
setTitle(langFactory(lng_media_auto_title));
|
||||
|
||||
const auto settings = &Auth().settings().autoDownload();
|
||||
const auto checked = [=](Source source, Type type) {
|
||||
return (settings->bytesLimit(source, type) > 0);
|
||||
};
|
||||
|
||||
auto wrap = object_ptr<Ui::VerticalLayout>(this);
|
||||
const auto content = wrap.data();
|
||||
setInnerWidget(object_ptr<Ui::OverrideMargins>(
|
||||
this,
|
||||
std::move(wrap)));
|
||||
|
||||
static const auto kHidden = {
|
||||
Type::Video,
|
||||
Type::Music,
|
||||
Type::VoiceMessage
|
||||
};
|
||||
|
||||
const auto values = Ui::CreateChild<base::flat_map<Type, int>>(content);
|
||||
const auto add = [&](Type type, LangKey label) {
|
||||
if (ranges::find(kHidden, type) != end(kHidden)) {
|
||||
return;
|
||||
}
|
||||
const auto value = settings->bytesLimit(_source, type);
|
||||
AddButton(
|
||||
content,
|
||||
label,
|
||||
st::settingsButton
|
||||
)->toggleOn(
|
||||
rpl::single(value > 0)
|
||||
)->toggledChanges(
|
||||
) | rpl::start_with_next([=](bool enabled) {
|
||||
(*values)[type] = enabled ? 1 : 0;
|
||||
}, content->lifetime());
|
||||
values->emplace(type, value);
|
||||
};
|
||||
add(Type::Photo, lng_media_photo_title);
|
||||
add(Type::VoiceMessage, lng_media_audio_title);
|
||||
add(Type::VideoMessage, lng_media_video_messages_title);
|
||||
add(Type::Video, lng_media_video_title);
|
||||
add(Type::File, lng_media_file_title);
|
||||
add(Type::Music, lng_media_music_title);
|
||||
add(Type::GIF, lng_media_animation_title);
|
||||
|
||||
const auto limits = Ui::CreateChild<rpl::event_stream<int>>(content);
|
||||
using Pair = base::flat_map<Type, int>::value_type;
|
||||
const auto settingsLimit = ranges::max_element(
|
||||
*values,
|
||||
std::less<>(),
|
||||
[](Pair pair) { return pair.second; })->second;
|
||||
const auto initialLimit = settingsLimit ? settingsLimit : kDefaultLimit;
|
||||
const auto limit = Ui::CreateChild<int>(content, initialLimit);
|
||||
AddButtonWithLabel(
|
||||
content,
|
||||
lng_media_size_limit,
|
||||
limits->events_starting_with_copy(
|
||||
initialLimit
|
||||
) | rpl::map([](int value) {
|
||||
return lng_media_size_up_to(
|
||||
lt_size,
|
||||
QString::number(value / kMegabyte) + " MB");
|
||||
}),
|
||||
st::autoDownloadLimitButton
|
||||
)->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
const auto slider = content->add(
|
||||
object_ptr<Ui::MediaSlider>(content, st::autoDownloadLimitSlider),
|
||||
st::autoDownloadLimitPadding);
|
||||
slider->resize(st::autoDownloadLimitSlider.seekSize);
|
||||
slider->setPseudoDiscrete(
|
||||
Export::View::kSizeValueCount,
|
||||
Export::View::SizeLimitByIndex,
|
||||
*limit,
|
||||
[=](int value) {
|
||||
*limit = value;
|
||||
limits->fire_copy(value);
|
||||
});
|
||||
|
||||
addButton(langFactory(lng_connection_save), [=] {
|
||||
auto allowMore = ranges::view::all(
|
||||
*values
|
||||
) | ranges::view::filter([&](Pair pair) {
|
||||
const auto [type, enabled] = pair;
|
||||
const auto value = enabled ? *limit : 0;
|
||||
const auto old = settings->bytesLimit(_source, type);
|
||||
return (old < value);
|
||||
}) | ranges::view::transform([](Pair pair) {
|
||||
return pair.first;
|
||||
});
|
||||
const auto allowMoreTypes = base::flat_set<Type>(
|
||||
allowMore.begin(),
|
||||
allowMore.end());
|
||||
|
||||
const auto changed = ranges::find_if(*values, [&](Pair pair) {
|
||||
const auto [type, enabled] = pair;
|
||||
const auto value = enabled ? *limit : 0;
|
||||
return settings->bytesLimit(_source, type) != value;
|
||||
}) != end(*values);
|
||||
|
||||
const auto hiddenChanged = ranges::find_if(kHidden, [&](Type type) {
|
||||
const auto now = settings->bytesLimit(_source, type);
|
||||
return (now > 0) && (now != *limit);
|
||||
}) != end(kHidden);
|
||||
|
||||
if (changed) {
|
||||
for (const auto [type, enabled] : *values) {
|
||||
const auto value = enabled ? *limit : 0;
|
||||
settings->setBytesLimit(_source, type, value);
|
||||
}
|
||||
}
|
||||
if (hiddenChanged) {
|
||||
for (const auto type : kHidden) {
|
||||
const auto now = settings->bytesLimit(_source, type);
|
||||
if (now > 0) {
|
||||
settings->setBytesLimit(_source, type, *limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed || hiddenChanged) {
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
if (allowMoreTypes.contains(Type::Photo)) {
|
||||
Auth().data().photoLoadSettingsChanged();
|
||||
}
|
||||
if (ranges::find_if(allowMoreTypes, _1 != Type::Photo)
|
||||
!= allowMoreTypes.end()) {
|
||||
Auth().data().documentLoadSettingsChanged();
|
||||
}
|
||||
closeBox();
|
||||
});
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
setDimensionsToContent(st::boxWidth, content);
|
||||
}
|
||||
30
Telegram/SourceFiles/boxes/auto_download_box.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
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 Data {
|
||||
namespace AutoDownload {
|
||||
enum class Source;
|
||||
} // namespace AutoDownload
|
||||
} // namespace Data
|
||||
|
||||
class AutoDownloadBox : public BoxContent {
|
||||
public:
|
||||
AutoDownloadBox(QWidget*, Data::AutoDownload::Source source);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
void setupContent();
|
||||
|
||||
Data::AutoDownload::Source _source;
|
||||
|
||||
};
|
||||
@@ -5,7 +5,7 @@ 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/autolock_box.h"
|
||||
#include "boxes/auto_lock_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "storage/localstorage.h"
|
||||
@@ -8,22 +8,58 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/background_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "ui/effects/round_checkbox.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "auth_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "data/data_session.h"
|
||||
#include "boxes/background_preview_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "styles/style_overview.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
||||
class BackgroundBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||
namespace {
|
||||
|
||||
constexpr auto kBackgroundsInRow = 3;
|
||||
|
||||
QImage TakeMiddleSample(QImage original, QSize size) {
|
||||
size *= cIntRetinaFactor();
|
||||
const auto from = original.size();
|
||||
if (from.isEmpty()) {
|
||||
auto result = original.scaled(size);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto take = (from.width() * size.height()
|
||||
> from.height() * size.width())
|
||||
? QSize(size.width() * from.height() / size.height(), from.height())
|
||||
: QSize(from.width(), size.height() * from.width() / size.width());
|
||||
auto result = original.copy(
|
||||
(from.width() - take.width()) / 2,
|
||||
(from.height() - take.height()) / 2,
|
||||
take.width(),
|
||||
take.height()
|
||||
).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class BackgroundBox::Inner
|
||||
: public Ui::RpWidget
|
||||
, private MTP::Sender
|
||||
, private base::Subscriber {
|
||||
public:
|
||||
Inner(QWidget *parent);
|
||||
|
||||
void setBackgroundChosenCallback(Fn<void(int index)> callback) {
|
||||
_backgroundChosenCallback = std::move(callback);
|
||||
}
|
||||
rpl::producer<Data::WallPaper> chooseEvents() const;
|
||||
rpl::producer<Data::WallPaper> removeRequests() const;
|
||||
|
||||
void removePaper(const Data::WallPaper &data);
|
||||
|
||||
~Inner();
|
||||
|
||||
@@ -34,16 +70,51 @@ protected:
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
void gotWallpapers(const MTPVector<MTPWallPaper> &result);
|
||||
void updateWallpapers();
|
||||
struct Paper {
|
||||
Data::WallPaper data;
|
||||
mutable QPixmap thumbnail;
|
||||
};
|
||||
struct Selected {
|
||||
int index = 0;
|
||||
inline bool operator==(const Selected &other) const {
|
||||
return index == other.index;
|
||||
}
|
||||
inline bool operator!=(const Selected &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
struct DeleteSelected {
|
||||
int index = 0;
|
||||
inline bool operator==(const DeleteSelected &other) const {
|
||||
return index == other.index;
|
||||
}
|
||||
inline bool operator!=(const DeleteSelected &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
using Selection = base::optional_variant<Selected, DeleteSelected>;
|
||||
|
||||
Fn<void(int index)> _backgroundChosenCallback;
|
||||
int getSelectionIndex(const Selection &selection) const;
|
||||
void repaintPaper(int index);
|
||||
void resizeToContentAndPreload();
|
||||
void updatePapers();
|
||||
void requestPapers();
|
||||
void sortPapers();
|
||||
void paintPaper(
|
||||
Painter &p,
|
||||
const Paper &paper,
|
||||
int column,
|
||||
int row) const;
|
||||
void validatePaperThumbnail(const Paper &paper) const;
|
||||
|
||||
std::vector<Paper> _papers;
|
||||
|
||||
Selection _over;
|
||||
Selection _overDown;
|
||||
|
||||
int _bgCount = 0;
|
||||
int _rows = 0;
|
||||
int _over = -1;
|
||||
int _overDown = -1;
|
||||
std::unique_ptr<Ui::RoundCheckbox> _check; // this is not a widget
|
||||
rpl::event_stream<Data::WallPaper> _backgroundChosen;
|
||||
rpl::event_stream<Data::WallPaper> _backgroundRemove;
|
||||
|
||||
};
|
||||
|
||||
@@ -53,180 +124,320 @@ BackgroundBox::BackgroundBox(QWidget*) {
|
||||
void BackgroundBox::prepare() {
|
||||
setTitle(langFactory(lng_backgrounds_header));
|
||||
|
||||
addButton(langFactory(lng_close), [this] { closeBox(); });
|
||||
addButton(langFactory(lng_close), [=] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWideWidth, st::boxMaxListHeight);
|
||||
|
||||
_inner = setInnerWidget(object_ptr<Inner>(this), st::backgroundScroll);
|
||||
_inner->setBackgroundChosenCallback([this](int index) { backgroundChosen(index); });
|
||||
|
||||
_inner->chooseEvents(
|
||||
) | rpl::start_with_next([](const Data::WallPaper &paper) {
|
||||
Ui::show(Box<BackgroundPreviewBox>(paper), LayerOption::KeepOther);
|
||||
}, _inner->lifetime());
|
||||
|
||||
_inner->removeRequests(
|
||||
) | rpl::start_with_next([=](const Data::WallPaper &paper) {
|
||||
removePaper(paper);
|
||||
}, _inner->lifetime());
|
||||
}
|
||||
|
||||
void BackgroundBox::backgroundChosen(int index) {
|
||||
if (index >= 0 && index < App::cServerBackgrounds().size()) {
|
||||
auto &paper = App::cServerBackgrounds()[index];
|
||||
if (App::main()) App::main()->setChatBackground(paper);
|
||||
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
Window::Theme::Background()->notify(Update(Update::Type::Start, !paper.id));
|
||||
}
|
||||
closeBox();
|
||||
void BackgroundBox::removePaper(const Data::WallPaper &paper) {
|
||||
const auto box = std::make_shared<QPointer<BoxContent>>();
|
||||
const auto remove = [=, weak = make_weak(this)]{
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
if (weak) {
|
||||
weak->_inner->removePaper(paper);
|
||||
}
|
||||
Auth().data().removeWallpaper(paper);
|
||||
Auth().api().request(MTPaccount_SaveWallPaper(
|
||||
paper.mtpInput(),
|
||||
MTP_bool(true),
|
||||
paper.mtpSettings()
|
||||
)).send();
|
||||
};
|
||||
*box = Ui::show(
|
||||
Box<ConfirmBox>(
|
||||
lang(lng_background_sure_delete),
|
||||
lang(lng_selected_delete),
|
||||
lang(lng_cancel),
|
||||
remove),
|
||||
LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent)
|
||||
, _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [this] { update(); })) {
|
||||
BackgroundBox::Inner::Inner(QWidget *parent) : RpWidget(parent)
|
||||
, _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [=] { update(); })) {
|
||||
_check->setChecked(true, Ui::RoundCheckbox::SetStyle::Fast);
|
||||
if (App::cServerBackgrounds().isEmpty()) {
|
||||
resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
MTP::send(MTPaccount_GetWallPapers(), rpcDone(&Inner::gotWallpapers));
|
||||
if (Auth().data().wallpapers().empty()) {
|
||||
resize(st::boxWideWidth, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
} else {
|
||||
updateWallpapers();
|
||||
updatePapers();
|
||||
}
|
||||
requestPapers();
|
||||
|
||||
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
|
||||
subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
subscribe(Window::Theme::Background(), [=](const Update &update) {
|
||||
if (update.paletteChanged()) {
|
||||
_check->invalidateCache();
|
||||
} else if (update.type == Update::Type::New) {
|
||||
sortPapers();
|
||||
requestPapers();
|
||||
this->update();
|
||||
}
|
||||
});
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::gotWallpapers(const MTPVector<MTPWallPaper> &result) {
|
||||
App::WallPapers wallpapers;
|
||||
|
||||
auto oldBackground = Images::Create(qsl(":/gui/art/bg_initial.jpg"), "JPG");
|
||||
wallpapers.push_back(App::WallPaper(Window::Theme::kInitialBackground, oldBackground, oldBackground));
|
||||
auto &v = result.v;
|
||||
for_const (auto &w, v) {
|
||||
switch (w.type()) {
|
||||
case mtpc_wallPaper: {
|
||||
auto &d = w.c_wallPaper();
|
||||
auto &sizes = d.vsizes.v;
|
||||
const MTPPhotoSize *thumb = 0, *full = 0;
|
||||
int32 thumbLevel = -1, fullLevel = -1;
|
||||
for (QVector<MTPPhotoSize>::const_iterator j = sizes.cbegin(), e = sizes.cend(); j != e; ++j) {
|
||||
char size = 0;
|
||||
int32 w = 0, h = 0;
|
||||
switch (j->type()) {
|
||||
case mtpc_photoSize: {
|
||||
auto &s = j->c_photoSize().vtype.v;
|
||||
if (s.size()) size = s[0];
|
||||
w = j->c_photoSize().vw.v;
|
||||
h = j->c_photoSize().vh.v;
|
||||
} break;
|
||||
|
||||
case mtpc_photoCachedSize: {
|
||||
auto &s = j->c_photoCachedSize().vtype.v;
|
||||
if (s.size()) size = s[0];
|
||||
w = j->c_photoCachedSize().vw.v;
|
||||
h = j->c_photoCachedSize().vh.v;
|
||||
} break;
|
||||
}
|
||||
if (!size || !w || !h) continue;
|
||||
|
||||
int32 newThumbLevel = qAbs((st::backgroundSize.width() * cIntRetinaFactor()) - w), newFullLevel = qAbs(2560 - w);
|
||||
if (thumbLevel < 0 || newThumbLevel < thumbLevel) {
|
||||
thumbLevel = newThumbLevel;
|
||||
thumb = &(*j);
|
||||
}
|
||||
if (fullLevel < 0 || newFullLevel < fullLevel) {
|
||||
fullLevel = newFullLevel;
|
||||
full = &(*j);
|
||||
}
|
||||
}
|
||||
if (thumb && full && full->type() != mtpc_photoSizeEmpty) {
|
||||
wallpapers.push_back(App::WallPaper(d.vid.v ? d.vid.v : INT_MAX, App::image(*thumb), App::image(*full)));
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_wallPaperSolid: {
|
||||
auto &d = w.c_wallPaperSolid();
|
||||
} break;
|
||||
void BackgroundBox::Inner::requestPapers() {
|
||||
request(MTPaccount_GetWallPapers(
|
||||
MTP_int(Auth().data().wallpapersHash())
|
||||
)).done([=](const MTPaccount_WallPapers &result) {
|
||||
if (Auth().data().updateWallpapers(result)) {
|
||||
updatePapers();
|
||||
}
|
||||
}
|
||||
|
||||
App::cSetServerBackgrounds(wallpapers);
|
||||
updateWallpapers();
|
||||
}).send();
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::updateWallpapers() {
|
||||
_bgCount = App::cServerBackgrounds().size();
|
||||
_rows = _bgCount / BackgroundsInRow;
|
||||
if (_bgCount % BackgroundsInRow) ++_rows;
|
||||
|
||||
resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, _rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
for (int i = 0; i < BackgroundsInRow * 3; ++i) {
|
||||
if (i >= _bgCount) break;
|
||||
|
||||
App::cServerBackgrounds()[i].thumb->load(Data::FileOrigin());
|
||||
void BackgroundBox::Inner::sortPapers() {
|
||||
const auto current = Window::Theme::Background()->id();
|
||||
const auto night = Window::Theme::IsNightMode();
|
||||
ranges::stable_sort(_papers, std::greater<>(), [&](const Paper &paper) {
|
||||
const auto &data = paper.data;
|
||||
return std::make_tuple(
|
||||
data.id() == current,
|
||||
night ? data.isDark() : !data.isDark(),
|
||||
!data.isDefault() && !data.isLocal(),
|
||||
!data.isDefault() && data.isLocal());
|
||||
});
|
||||
if (!_papers.empty() && _papers.front().data.id() == current) {
|
||||
_papers.front().data = _papers.front().data.withParamsFrom(
|
||||
Window::Theme::Background()->paper());
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::updatePapers() {
|
||||
_over = _overDown = Selection();
|
||||
|
||||
_papers = Auth().data().wallpapers(
|
||||
) | ranges::view::filter([](const Data::WallPaper &paper) {
|
||||
return !paper.isPattern() || paper.backgroundColor().has_value();
|
||||
}) | ranges::view::transform([](const Data::WallPaper &paper) {
|
||||
return Paper{ paper };
|
||||
}) | ranges::to_vector;
|
||||
sortPapers();
|
||||
resizeToContentAndPreload();
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::resizeToContentAndPreload() {
|
||||
const auto count = _papers.size();
|
||||
const auto rows = (count / kBackgroundsInRow)
|
||||
+ (count % kBackgroundsInRow ? 1 : 0);
|
||||
|
||||
resize(st::boxWideWidth, rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
|
||||
const auto preload = kBackgroundsInRow * 3;
|
||||
for (const auto &paper : _papers | ranges::view::take(preload)) {
|
||||
paper.data.loadThumbnail();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
if (_rows) {
|
||||
for (int i = 0; i < _rows; ++i) {
|
||||
if ((st::backgroundSize.height() + st::backgroundPadding) * (i + 1) <= r.top()) continue;
|
||||
for (int j = 0; j < BackgroundsInRow; ++j) {
|
||||
int index = i * BackgroundsInRow + j;
|
||||
if (index >= _bgCount) break;
|
||||
|
||||
const auto &paper = App::cServerBackgrounds()[index];
|
||||
paper.thumb->load(Data::FileOrigin());
|
||||
|
||||
int x = st::backgroundPadding + j * (st::backgroundSize.width() + st::backgroundPadding);
|
||||
int y = st::backgroundPadding + i * (st::backgroundSize.height() + st::backgroundPadding);
|
||||
|
||||
const auto &pix = paper.thumb->pix(
|
||||
Data::FileOrigin(),
|
||||
st::backgroundSize.width(),
|
||||
st::backgroundSize.height());
|
||||
p.drawPixmap(x, y, pix);
|
||||
|
||||
if (paper.id == Window::Theme::Background()->id()) {
|
||||
auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
|
||||
auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
|
||||
_check->paint(p, getms(), checkLeft, checkTop, width());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_papers.empty()) {
|
||||
p.setFont(st::noContactsFont);
|
||||
p.setPen(st::noContactsColor);
|
||||
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
|
||||
return;
|
||||
}
|
||||
auto row = 0;
|
||||
auto column = 0;
|
||||
for (const auto &paper : _papers) {
|
||||
const auto increment = gsl::finally([&] {
|
||||
++column;
|
||||
if (column == kBackgroundsInRow) {
|
||||
column = 0;
|
||||
++row;
|
||||
}
|
||||
});
|
||||
if ((st::backgroundSize.height() + st::backgroundPadding) * (row + 1) <= r.top()) {
|
||||
continue;
|
||||
} else if ((st::backgroundSize.height() + st::backgroundPadding) * row >= r.top() + r.height()) {
|
||||
break;
|
||||
}
|
||||
paintPaper(p, paper, column, row);
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::validatePaperThumbnail(
|
||||
const Paper &paper) const {
|
||||
Expects(paper.data.thumbnail() != nullptr);
|
||||
|
||||
const auto thumbnail = paper.data.thumbnail();
|
||||
if (!paper.thumbnail.isNull()) {
|
||||
return;
|
||||
} else if (!thumbnail->loaded()) {
|
||||
thumbnail->load(paper.data.fileOrigin());
|
||||
return;
|
||||
}
|
||||
auto original = thumbnail->original();
|
||||
if (paper.data.isPattern()) {
|
||||
const auto color = *paper.data.backgroundColor();
|
||||
original = Data::PreparePatternImage(
|
||||
std::move(original),
|
||||
color,
|
||||
Data::PatternColor(color),
|
||||
paper.data.patternIntensity());
|
||||
}
|
||||
paper.thumbnail = App::pixmapFromImageInPlace(TakeMiddleSample(
|
||||
original,
|
||||
st::backgroundSize));
|
||||
paper.thumbnail.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::paintPaper(
|
||||
Painter &p,
|
||||
const Paper &paper,
|
||||
int column,
|
||||
int row) const {
|
||||
const auto x = st::backgroundPadding + column * (st::backgroundSize.width() + st::backgroundPadding);
|
||||
const auto y = st::backgroundPadding + row * (st::backgroundSize.height() + st::backgroundPadding);
|
||||
validatePaperThumbnail(paper);
|
||||
if (!paper.thumbnail.isNull()) {
|
||||
p.drawPixmap(x, y, paper.thumbnail);
|
||||
}
|
||||
|
||||
const auto over = _overDown ? _overDown : _over;
|
||||
if (paper.data.id() == Window::Theme::Background()->id()) {
|
||||
const auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
|
||||
const auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
|
||||
_check->paint(p, crl::now(), checkLeft, checkTop, width());
|
||||
} else if (Data::IsCloudWallPaper(paper.data)
|
||||
&& !Data::IsDefaultWallPaper(paper.data)
|
||||
&& over.has_value()
|
||||
&& (&paper == &_papers[getSelectionIndex(over)])) {
|
||||
const auto deleteSelected = over.is<DeleteSelected>();
|
||||
const auto deletePos = QPoint(x + st::backgroundSize.width() - st::stickerPanDeleteIconBg.width(), y);
|
||||
p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityBgOver : st::stickerPanDeleteOpacityBg);
|
||||
st::stickerPanDeleteIconBg.paint(p, deletePos, width());
|
||||
p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityFgOver : st::stickerPanDeleteOpacityFg);
|
||||
st::stickerPanDeleteIconFg.paint(p, deletePos, width());
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
int x = e->pos().x(), y = e->pos().y();
|
||||
int row = int((y - st::backgroundPadding) / (st::backgroundSize.height() + st::backgroundPadding));
|
||||
if (y - row * (st::backgroundSize.height() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.height()) row = _rows + 1;
|
||||
|
||||
int col = int((x - st::backgroundPadding) / (st::backgroundSize.width() + st::backgroundPadding));
|
||||
if (x - col * (st::backgroundSize.width() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.width()) row = _rows + 1;
|
||||
|
||||
int newOver = row * BackgroundsInRow + col;
|
||||
if (newOver >= _bgCount) newOver = -1;
|
||||
if (newOver != _over) {
|
||||
const auto newOver = [&] {
|
||||
const auto x = e->pos().x();
|
||||
const auto y = e->pos().y();
|
||||
const auto width = st::backgroundSize.width();
|
||||
const auto height = st::backgroundSize.height();
|
||||
const auto skip = st::backgroundPadding;
|
||||
const auto row = int((y - skip) / (height + skip));
|
||||
const auto column = int((x - skip) / (width + skip));
|
||||
const auto result = row * kBackgroundsInRow + column;
|
||||
if (y - row * (height + skip) > skip + height) {
|
||||
return Selection();
|
||||
} else if (x - column * (width + skip) > skip + width) {
|
||||
return Selection();
|
||||
} else if (result >= _papers.size()) {
|
||||
return Selection();
|
||||
}
|
||||
const auto deleteLeft = (column + 1) * (width + skip)
|
||||
- st::stickerPanDeleteIconBg.width();
|
||||
const auto deleteBottom = row * (height + skip) + skip
|
||||
+ st::stickerPanDeleteIconBg.height();
|
||||
const auto currentId = Window::Theme::Background()->id();
|
||||
const auto inDelete = (x >= deleteLeft)
|
||||
&& (y < deleteBottom)
|
||||
&& Data::IsCloudWallPaper(_papers[result].data)
|
||||
&& !Data::IsDefaultWallPaper(_papers[result].data)
|
||||
&& (currentId != _papers[result].data.id());
|
||||
return (result >= _papers.size())
|
||||
? Selection()
|
||||
: inDelete
|
||||
? Selection(DeleteSelected{ result })
|
||||
: Selection(Selected{ result });
|
||||
}();
|
||||
if (_over != newOver) {
|
||||
repaintPaper(getSelectionIndex(_over));
|
||||
_over = newOver;
|
||||
setCursor((_over >= 0 || _overDown >= 0) ? style::cur_pointer : style::cur_default);
|
||||
repaintPaper(getSelectionIndex(_over));
|
||||
setCursor((_over.has_value() || _overDown.has_value())
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::repaintPaper(int index) {
|
||||
if (index < 0 || index >= _papers.size()) {
|
||||
return;
|
||||
}
|
||||
const auto row = (index / kBackgroundsInRow);
|
||||
const auto column = (index % kBackgroundsInRow);
|
||||
const auto width = st::backgroundSize.width();
|
||||
const auto height = st::backgroundSize.height();
|
||||
const auto skip = st::backgroundPadding;
|
||||
update(
|
||||
(width + skip) * column + skip,
|
||||
(height + skip) * row + skip,
|
||||
width,
|
||||
height);
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
_overDown = _over;
|
||||
}
|
||||
|
||||
int BackgroundBox::Inner::getSelectionIndex(
|
||||
const Selection &selection) const {
|
||||
return selection.match([](const Selected &data) {
|
||||
return data.index;
|
||||
}, [](const DeleteSelected &data) {
|
||||
return data.index;
|
||||
}, [](std::nullopt_t) {
|
||||
return -1;
|
||||
});
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (_overDown == _over && _over >= 0) {
|
||||
if (_backgroundChosenCallback) {
|
||||
_backgroundChosenCallback(_over);
|
||||
if (base::take(_overDown) == _over && _over.has_value()) {
|
||||
const auto index = getSelectionIndex(_over);
|
||||
if (index >= 0 && index < _papers.size()) {
|
||||
if (base::get_if<DeleteSelected>(&_over)) {
|
||||
_backgroundRemove.fire_copy(_papers[index].data);
|
||||
} else if (base::get_if<Selected>(&_over)) {
|
||||
_backgroundChosen.fire_copy(_papers[index].data);
|
||||
}
|
||||
}
|
||||
} else if (_over < 0) {
|
||||
} else if (!_over.has_value()) {
|
||||
setCursor(style::cur_default);
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<Data::WallPaper> BackgroundBox::Inner::chooseEvents() const {
|
||||
return _backgroundChosen.events();
|
||||
}
|
||||
|
||||
auto BackgroundBox::Inner::removeRequests() const
|
||||
-> rpl::producer<Data::WallPaper> {
|
||||
return _backgroundRemove.events();
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::removePaper(const Data::WallPaper &data) {
|
||||
const auto i = ranges::find(
|
||||
_papers,
|
||||
data.id(),
|
||||
[](const Paper &paper) { return paper.data.id(); });
|
||||
if (i != end(_papers)) {
|
||||
_papers.erase(i);
|
||||
_over = _overDown = Selection();
|
||||
resizeToContentAndPreload();
|
||||
}
|
||||
}
|
||||
|
||||
BackgroundBox::Inner::~Inner() = default;
|
||||
|
||||
@@ -9,9 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
|
||||
namespace Ui {
|
||||
class RoundCheckbox;
|
||||
} // namespace Ui
|
||||
namespace Data {
|
||||
class WallPaper;
|
||||
} // namespace Data
|
||||
|
||||
class BackgroundBox : public BoxContent {
|
||||
public:
|
||||
@@ -21,9 +21,10 @@ protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
void backgroundChosen(int index);
|
||||
|
||||
class Inner;
|
||||
|
||||
void removePaper(const Data::WallPaper &paper);
|
||||
|
||||
QPointer<Inner> _inner;
|
||||
|
||||
};
|
||||
|
||||
796
Telegram/SourceFiles/boxes/background_preview_box.cpp
Normal file
@@ -0,0 +1,796 @@
|
||||
/*
|
||||
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/background_preview_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_message.h"
|
||||
#include "history/view/history_view_message.h"
|
||||
#include "auth_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_document.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/background_preview_box.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxWallPaperSlugLength = 255;
|
||||
|
||||
class ServiceCheck : public Ui::AbstractCheckView {
|
||||
public:
|
||||
ServiceCheck(const style::ServiceCheck &st, bool checked);
|
||||
|
||||
QSize getSize() const override;
|
||||
void paint(
|
||||
Painter &p,
|
||||
int left,
|
||||
int top,
|
||||
int outerWidth,
|
||||
crl::time ms) override;
|
||||
QImage prepareRippleMask() const override;
|
||||
bool checkRippleStartPosition(QPoint position) const override;
|
||||
|
||||
private:
|
||||
class Generator {
|
||||
public:
|
||||
Generator();
|
||||
|
||||
void paintFrame(
|
||||
Painter &p,
|
||||
int left,
|
||||
int top,
|
||||
not_null<const style::ServiceCheck*> st,
|
||||
float64 toggled);
|
||||
void invalidate();
|
||||
|
||||
private:
|
||||
struct Frames {
|
||||
QImage image;
|
||||
std::vector<bool> ready;
|
||||
};
|
||||
|
||||
not_null<Frames*> framesForStyle(
|
||||
not_null<const style::ServiceCheck*> st);
|
||||
static void FillFrame(
|
||||
QImage &image,
|
||||
not_null<const style::ServiceCheck*> st,
|
||||
int index,
|
||||
int count);
|
||||
static void PaintFillingFrame(
|
||||
Painter &p,
|
||||
not_null<const style::ServiceCheck*> st,
|
||||
float64 progress);
|
||||
static void PaintCheckingFrame(
|
||||
Painter &p,
|
||||
not_null<const style::ServiceCheck*> st,
|
||||
float64 progress);
|
||||
|
||||
base::flat_map<not_null<const style::ServiceCheck*>, Frames> _data;
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
static Generator &Frames();
|
||||
|
||||
const style::ServiceCheck &_st;
|
||||
|
||||
};
|
||||
|
||||
ServiceCheck::Generator::Generator() {
|
||||
*_lifetime.make_state<base::Subscription>() = Window::Theme::Background(
|
||||
)->add_subscription([=](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto ServiceCheck::Generator::framesForStyle(
|
||||
not_null<const style::ServiceCheck*> st) -> not_null<Frames*> {
|
||||
if (const auto i = _data.find(st); i != _data.end()) {
|
||||
return &i->second;
|
||||
}
|
||||
const auto result = &_data.emplace(st, Frames()).first->second;
|
||||
const auto size = st->diameter;
|
||||
const auto count = (st->duration / AnimationTimerDelta) + 2;
|
||||
result->image = QImage(
|
||||
QSize(count * size, size) * cIntRetinaFactor(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
result->image.fill(Qt::transparent);
|
||||
result->image.setDevicePixelRatio(cRetinaFactor());
|
||||
result->ready.resize(count);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ServiceCheck::Generator::FillFrame(
|
||||
QImage &image,
|
||||
not_null<const style::ServiceCheck*> st,
|
||||
int index,
|
||||
int count) {
|
||||
Expects(count > 1);
|
||||
Expects(index >= 0 && index < count);
|
||||
|
||||
Painter p(&image);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
|
||||
p.translate(index * st->diameter, 0);
|
||||
const auto progress = index / float64(count - 1);
|
||||
if (progress > 0.5) {
|
||||
PaintCheckingFrame(p, st, (progress - 0.5) * 2);
|
||||
} else {
|
||||
PaintFillingFrame(p, st, progress * 2);
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceCheck::Generator::PaintFillingFrame(
|
||||
Painter &p,
|
||||
not_null<const style::ServiceCheck*> st,
|
||||
float64 progress) {
|
||||
const auto shift = progress * st->shift;
|
||||
p.setBrush(st->color);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawEllipse(QRectF(
|
||||
shift,
|
||||
shift,
|
||||
st->diameter - 2 * shift,
|
||||
st->diameter - 2 * shift));
|
||||
if (progress < 1.) {
|
||||
const auto remove = progress * (st->diameter / 2. - st->thickness);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(Qt::transparent);
|
||||
p.drawEllipse(QRectF(
|
||||
st->thickness + remove,
|
||||
st->thickness + remove,
|
||||
st->diameter - 2 * (st->thickness + remove),
|
||||
st->diameter - 2 * (st->thickness + remove)));
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceCheck::Generator::PaintCheckingFrame(
|
||||
Painter &p,
|
||||
not_null<const style::ServiceCheck*> st,
|
||||
float64 progress) {
|
||||
const auto shift = (1. - progress) * st->shift;
|
||||
p.setBrush(st->color);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawEllipse(QRectF(
|
||||
shift,
|
||||
shift,
|
||||
st->diameter - 2 * shift,
|
||||
st->diameter - 2 * shift));
|
||||
if (progress > 0.) {
|
||||
const auto tip = QPointF(st->tip.x(), st->tip.y());
|
||||
const auto left = tip - QPointF(st->small, st->small) * progress;
|
||||
const auto right = tip - QPointF(-st->large, st->large) * progress;
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.setBrush(Qt::NoBrush);
|
||||
auto pen = QPen(Qt::transparent);
|
||||
pen.setWidth(st->stroke);
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
pen.setJoinStyle(Qt::RoundJoin);
|
||||
p.setPen(pen);
|
||||
auto path = QPainterPath();
|
||||
path.moveTo(left);
|
||||
path.lineTo(tip);
|
||||
path.lineTo(right);
|
||||
p.drawPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceCheck::Generator::paintFrame(
|
||||
Painter &p,
|
||||
int left,
|
||||
int top,
|
||||
not_null<const style::ServiceCheck*> st,
|
||||
float64 toggled) {
|
||||
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)));
|
||||
Assert(index >= 0 && index < count);
|
||||
if (!frames->ready[index]) {
|
||||
frames->ready[index] = true;
|
||||
FillFrame(image, st, index, count);
|
||||
}
|
||||
const auto size = st->diameter;
|
||||
const auto part = size * cIntRetinaFactor();
|
||||
p.drawImage(
|
||||
QPoint(left, top),
|
||||
image,
|
||||
QRect(index * part, 0, part, part));
|
||||
}
|
||||
|
||||
void ServiceCheck::Generator::invalidate() {
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
ServiceCheck::Generator &ServiceCheck::Frames() {
|
||||
static const auto Instance = Ui::CreateChild<Generator>(
|
||||
QApplication::instance());
|
||||
return *Instance;
|
||||
}
|
||||
|
||||
ServiceCheck::ServiceCheck(
|
||||
const style::ServiceCheck &st,
|
||||
bool checked)
|
||||
: AbstractCheckView(st.duration, checked, nullptr)
|
||||
, _st(st) {
|
||||
}
|
||||
|
||||
QSize ServiceCheck::getSize() const {
|
||||
const auto inner = QRect(0, 0, _st.diameter, _st.diameter);
|
||||
return inner.marginsAdded(_st.margin).size();
|
||||
}
|
||||
|
||||
void ServiceCheck::paint(
|
||||
Painter &p,
|
||||
int left,
|
||||
int top,
|
||||
int outerWidth,
|
||||
crl::time ms) {
|
||||
Frames().paintFrame(
|
||||
p,
|
||||
left + _st.margin.left(),
|
||||
top + _st.margin.top(),
|
||||
&_st,
|
||||
currentAnimationValue(ms));
|
||||
}
|
||||
|
||||
QImage ServiceCheck::prepareRippleMask() const {
|
||||
return QImage();
|
||||
}
|
||||
|
||||
bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsValidWallPaperSlug(const QString &slug) {
|
||||
if (slug.isEmpty() || slug.size() > kMaxWallPaperSlugLength) {
|
||||
return false;
|
||||
}
|
||||
return ranges::find_if(slug, [](QChar ch) {
|
||||
return (ch != '.')
|
||||
&& (ch != '_')
|
||||
&& (ch != '-')
|
||||
&& (ch < '0' || ch > '9')
|
||||
&& (ch < 'a' || ch > 'z')
|
||||
&& (ch < 'A' || ch > 'Z');
|
||||
}) == slug.end();
|
||||
}
|
||||
|
||||
AdminLog::OwnedItem GenerateTextItem(
|
||||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
not_null<History*> history,
|
||||
const QString &text,
|
||||
bool out) {
|
||||
Expects(history->peer->isUser());
|
||||
|
||||
using Flag = MTPDmessage::Flag;
|
||||
static auto id = ServerMaxMsgId + (ServerMaxMsgId / 3);
|
||||
const auto flags = Flag::f_entities
|
||||
| Flag::f_from_id
|
||||
| (out ? Flag::f_out : Flag(0));
|
||||
const auto replyTo = 0;
|
||||
const auto viaBotId = 0;
|
||||
const auto item = new HistoryMessage(
|
||||
history,
|
||||
++id,
|
||||
flags,
|
||||
replyTo,
|
||||
viaBotId,
|
||||
unixtime(),
|
||||
out ? history->session().userId() : peerToUser(history->peer->id),
|
||||
QString(),
|
||||
TextWithEntities{ TextUtilities::Clean(text) });
|
||||
return AdminLog::OwnedItem(delegate, item);
|
||||
}
|
||||
|
||||
QImage PrepareScaledNonPattern(
|
||||
const QImage &image,
|
||||
Images::Option blur) {
|
||||
const auto size = st::boxWideWidth;
|
||||
const auto width = std::max(image.width(), 1);
|
||||
const auto height = std::max(image.height(), 1);
|
||||
const auto takeWidth = (width > height)
|
||||
? (width * size / height)
|
||||
: size;
|
||||
const auto takeHeight = (width > height)
|
||||
? size
|
||||
: (height * size / width);
|
||||
return Images::prepare(
|
||||
image,
|
||||
takeWidth * cIntRetinaFactor(),
|
||||
takeHeight * cIntRetinaFactor(),
|
||||
Images::Option::Smooth
|
||||
| Images::Option::TransparentBackground
|
||||
| blur,
|
||||
size,
|
||||
size);
|
||||
}
|
||||
|
||||
QImage ColorizePattern(QImage image, QColor color) {
|
||||
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
image = std::move(image).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
// Similar to style::colorizeImage.
|
||||
// But style::colorizeImage takes pattern with all pixels having the
|
||||
// same components value, from (0, 0, 0, 0) to (255, 255, 255, 255).
|
||||
//
|
||||
// While in patterns we have different value ranges, usually they are
|
||||
// from (0, 0, 0, 0) to (0, 0, 0, 255), so we should use only 'alpha'.
|
||||
|
||||
const auto width = image.width();
|
||||
const auto height = image.height();
|
||||
const auto pattern = anim::shifted(color);
|
||||
|
||||
const auto resultBytesPerPixel = (image.depth() >> 3);
|
||||
constexpr auto resultIntsPerPixel = 1;
|
||||
const auto resultIntsPerLine = (image.bytesPerLine() >> 2);
|
||||
const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel;
|
||||
auto resultInts = reinterpret_cast<uint32*>(image.bits());
|
||||
Assert(resultIntsAdded >= 0);
|
||||
Assert(image.depth() == static_cast<int>((resultIntsPerPixel * sizeof(uint32)) << 3));
|
||||
Assert(image.bytesPerLine() == (resultIntsPerLine << 2));
|
||||
|
||||
const auto maskBytesPerPixel = (image.depth() >> 3);
|
||||
const auto maskBytesPerLine = image.bytesPerLine();
|
||||
const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel;
|
||||
|
||||
// We want to read the last byte of four available.
|
||||
// This is the difference with style::colorizeImage.
|
||||
auto maskBytes = image.constBits() + (maskBytesPerPixel - 1);
|
||||
Assert(maskBytesAdded >= 0);
|
||||
Assert(image.depth() == (maskBytesPerPixel << 3));
|
||||
for (auto y = 0; y != height; ++y) {
|
||||
for (auto x = 0; x != width; ++x) {
|
||||
auto maskOpacity = static_cast<anim::ShiftedMultiplier>(*maskBytes) + 1;
|
||||
*resultInts = anim::unshifted(pattern * maskOpacity);
|
||||
maskBytes += maskBytesPerPixel;
|
||||
resultInts += resultIntsPerPixel;
|
||||
}
|
||||
maskBytes += maskBytesAdded;
|
||||
resultInts += resultIntsAdded;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
QImage PrepareScaledFromFull(
|
||||
const QImage &image,
|
||||
std::optional<QColor> patternBackground,
|
||||
Images::Option blur = Images::Option(0)) {
|
||||
auto result = PrepareScaledNonPattern(image, blur);
|
||||
if (patternBackground) {
|
||||
result = ColorizePattern(
|
||||
std::move(result),
|
||||
Data::PatternColor(*patternBackground));
|
||||
}
|
||||
return std::move(result).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BackgroundPreviewBox::BackgroundPreviewBox(
|
||||
QWidget*,
|
||||
const Data::WallPaper &paper)
|
||||
: _text1(GenerateTextItem(
|
||||
delegate(),
|
||||
Auth().data().history(peerFromUser(PeerData::kServiceNotificationsId)),
|
||||
lang(lng_background_text1),
|
||||
false))
|
||||
, _text2(GenerateTextItem(
|
||||
delegate(),
|
||||
Auth().data().history(peerFromUser(PeerData::kServiceNotificationsId)),
|
||||
lang(lng_background_text2),
|
||||
true))
|
||||
, _paper(paper)
|
||||
, _radial(animation(this, &BackgroundPreviewBox::step_radial)) {
|
||||
subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
|
||||
}
|
||||
|
||||
not_null<HistoryView::ElementDelegate*> BackgroundPreviewBox::delegate() {
|
||||
return static_cast<HistoryView::ElementDelegate*>(this);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::prepare() {
|
||||
setTitle(langFactory(lng_background_header));
|
||||
|
||||
addButton(langFactory(lng_background_apply), [=] { apply(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
if (_paper.hasShareUrl()) {
|
||||
addLeftButton(langFactory(lng_background_share), [=] { share(); });
|
||||
}
|
||||
updateServiceBg(_paper.backgroundColor());
|
||||
|
||||
_paper.loadThumbnail();
|
||||
_paper.loadDocument();
|
||||
if (_paper.document() && _paper.document()->loading()) {
|
||||
_radial.start(_paper.document()->progress());
|
||||
}
|
||||
if (_paper.thumbnail() && !_paper.isPattern()) {
|
||||
createBlurCheckbox();
|
||||
}
|
||||
setScaledFromThumb();
|
||||
checkLoadedDocument();
|
||||
|
||||
_text1->setDisplayDate(true);
|
||||
_text1->initDimensions();
|
||||
_text1->resizeGetHeight(st::boxWideWidth);
|
||||
_text2->initDimensions();
|
||||
_text2->resizeGetHeight(st::boxWideWidth);
|
||||
|
||||
setDimensions(st::boxWideWidth, st::boxWideWidth);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::createBlurCheckbox() {
|
||||
_blur.create(
|
||||
this,
|
||||
lang(lng_background_blur),
|
||||
st::backgroundCheckbox,
|
||||
std::make_unique<ServiceCheck>(
|
||||
st::backgroundCheck,
|
||||
_paper.isBlurred()));
|
||||
|
||||
rpl::combine(
|
||||
sizeValue(),
|
||||
_blur->sizeValue()
|
||||
) | rpl::start_with_next([=](QSize outer, QSize inner) {
|
||||
_blur->move(
|
||||
(outer.width() - inner.width()) / 2,
|
||||
outer.height() - st::historyPaddingBottom - inner.height());
|
||||
}, _blur->lifetime());
|
||||
|
||||
_blur->paintRequest(
|
||||
) | rpl::filter([=] {
|
||||
return _serviceBg.has_value();
|
||||
}) | rpl::start_with_next([=] {
|
||||
Painter p(_blur.data());
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(*_serviceBg);
|
||||
p.drawRoundedRect(
|
||||
_blur->rect(),
|
||||
st::historyMessageRadius,
|
||||
st::historyMessageRadius);
|
||||
}, _blur->lifetime());
|
||||
|
||||
_blur->checkedChanges(
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
checkBlurAnimationStart();
|
||||
update();
|
||||
}, lifetime());
|
||||
|
||||
_blur->setDisabled(true);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::apply() {
|
||||
const auto install = (_paper.id() != Window::Theme::Background()->id())
|
||||
&& Data::IsCloudWallPaper(_paper);
|
||||
App::main()->setChatBackground(_paper, std::move(_full));
|
||||
if (install) {
|
||||
Auth().api().request(MTPaccount_InstallWallPaper(
|
||||
_paper.mtpInput(),
|
||||
_paper.mtpSettings()
|
||||
)).send();
|
||||
}
|
||||
closeBox();
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::share() {
|
||||
QApplication::clipboard()->setText(_paper.shareUrl());
|
||||
Ui::Toast::Show(lang(lng_background_link_copied));
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
const auto ms = crl::now();
|
||||
const auto color = _paper.backgroundColor();
|
||||
if (color) {
|
||||
p.fillRect(e->rect(), *color);
|
||||
}
|
||||
if (!color || _paper.isPattern()) {
|
||||
if (!_scaled.isNull() || setScaledFromThumb()) {
|
||||
paintImage(p, ms);
|
||||
paintRadial(p, ms);
|
||||
} else if (!color) {
|
||||
p.fillRect(e->rect(), st::boxBg);
|
||||
return;
|
||||
} else {
|
||||
// Progress of pattern loading.
|
||||
paintRadial(p, ms);
|
||||
}
|
||||
}
|
||||
paintTexts(p, ms);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::paintImage(Painter &p, crl::time ms) {
|
||||
Expects(!_scaled.isNull());
|
||||
|
||||
const auto master = _paper.isPattern()
|
||||
? std::clamp(_paper.patternIntensity() / 100., 0., 1.)
|
||||
: 1.;
|
||||
|
||||
const auto factor = cIntRetinaFactor();
|
||||
const auto size = st::boxWideWidth;
|
||||
const auto from = QRect(
|
||||
0,
|
||||
(size - height()) / 2 * factor,
|
||||
size * factor,
|
||||
height() * factor);
|
||||
const auto guard = gsl::finally([&] { p.setOpacity(1.); });
|
||||
|
||||
const auto fade = _fadeIn.current(ms, 1.);
|
||||
if (fade < 1. && !_fadeOutThumbnail.isNull()) {
|
||||
p.drawPixmap(rect(), _fadeOutThumbnail, from);
|
||||
}
|
||||
const auto &pixmap = (!_blurred.isNull() && _paper.isBlurred())
|
||||
? _blurred
|
||||
: _scaled;
|
||||
p.setOpacity(master * fade);
|
||||
p.drawPixmap(rect(), pixmap, from);
|
||||
checkBlurAnimationStart();
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::paintRadial(Painter &p, crl::time ms) {
|
||||
bool radial = false;
|
||||
float64 radialOpacity = 0;
|
||||
if (_radial.animating()) {
|
||||
_radial.step(ms);
|
||||
radial = _radial.animating();
|
||||
radialOpacity = _radial.opacity();
|
||||
}
|
||||
if (!radial) {
|
||||
return;
|
||||
}
|
||||
auto inner = radialRect();
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setOpacity(radialOpacity);
|
||||
p.setBrush(st::radialBg);
|
||||
|
||||
{
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawEllipse(inner);
|
||||
}
|
||||
|
||||
p.setOpacity(1);
|
||||
QRect arc(inner.marginsRemoved(QMargins(st::radialLine, st::radialLine, st::radialLine, st::radialLine)));
|
||||
_radial.draw(p, arc, st::radialLine, st::radialFg);
|
||||
}
|
||||
|
||||
int BackgroundPreviewBox::textsTop() const {
|
||||
const auto bottom = _blur ? _blur->y() : height();
|
||||
return bottom
|
||||
- st::historyPaddingBottom
|
||||
- _text1->height()
|
||||
- _text2->height();
|
||||
}
|
||||
|
||||
QRect BackgroundPreviewBox::radialRect() const {
|
||||
const auto available = textsTop() - st::historyPaddingBottom;
|
||||
return QRect(
|
||||
QPoint(
|
||||
(width() - st::radialSize.width()) / 2,
|
||||
(available - st::radialSize.height()) / 2),
|
||||
st::radialSize);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::paintTexts(Painter &p, crl::time ms) {
|
||||
const auto height1 = _text1->height();
|
||||
const auto height2 = _text2->height();
|
||||
p.translate(0, textsTop());
|
||||
paintDate(p);
|
||||
_text1->draw(p, rect(), TextSelection(), ms);
|
||||
p.translate(0, height1);
|
||||
_text2->draw(p, rect(), TextSelection(), ms);
|
||||
p.translate(0, height2);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::paintDate(Painter &p) {
|
||||
const auto date = _text1->Get<HistoryView::DateBadge>();
|
||||
if (!date || !_serviceBg) {
|
||||
return;
|
||||
}
|
||||
const auto text = date->text;
|
||||
const auto bubbleHeight = st::msgServicePadding.top() + st::msgServiceFont->height + st::msgServicePadding.bottom();
|
||||
const auto bubbleTop = st::msgServiceMargin.top();
|
||||
const auto textWidth = st::msgServiceFont->width(text);
|
||||
const auto bubbleWidth = st::msgServicePadding.left() + textWidth + st::msgServicePadding.right();
|
||||
const auto bubbleLeft = (width() - bubbleWidth) / 2;
|
||||
const auto radius = bubbleHeight / 2;
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(*_serviceBg);
|
||||
p.drawRoundedRect(bubbleLeft, bubbleTop, bubbleWidth, bubbleHeight, radius, radius);
|
||||
p.setPen(st::msgServiceFg);
|
||||
p.setFont(st::msgServiceFont);
|
||||
p.drawText(bubbleLeft + st::msgServicePadding.left(), bubbleTop + st::msgServicePadding.top() + st::msgServiceFont->ascent, text);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::step_radial(crl::time ms, bool timer) {
|
||||
Expects(_paper.document() != nullptr);
|
||||
|
||||
const auto document = _paper.document();
|
||||
const auto wasAnimating = _radial.animating();
|
||||
const auto updated = _radial.update(
|
||||
document->progress(),
|
||||
!document->loading(),
|
||||
ms);
|
||||
if (timer
|
||||
&& (wasAnimating || _radial.animating())
|
||||
&& (!anim::Disabled() || updated)) {
|
||||
update(radialRect());
|
||||
}
|
||||
checkLoadedDocument();
|
||||
}
|
||||
|
||||
bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||
const auto thumbnail = _paper.thumbnail();
|
||||
if (!thumbnail || !thumbnail->loaded()) {
|
||||
return false;
|
||||
} else if (_paper.isPattern() && _paper.document() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto scaled = PrepareScaledFromFull(
|
||||
thumbnail->original(),
|
||||
patternBackgroundColor(),
|
||||
_paper.document() ? Images::Option::Blurred : Images::Option(0));
|
||||
auto blurred = (_paper.document() || _paper.isPattern())
|
||||
? QImage()
|
||||
: PrepareScaledNonPattern(
|
||||
Data::PrepareBlurredBackground(thumbnail->original()),
|
||||
Images::Option(0));
|
||||
setScaledFromImage(std::move(scaled), std::move(blurred));
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::setScaledFromImage(
|
||||
QImage &&image,
|
||||
QImage &&blurred) {
|
||||
updateServiceBg(Window::Theme::CountAverageColor(image));
|
||||
if (!_full.isNull()) {
|
||||
startFadeInFrom(std::move(_scaled));
|
||||
}
|
||||
_scaled = App::pixmapFromImageInPlace(std::move(image));
|
||||
_blurred = App::pixmapFromImageInPlace(std::move(blurred));
|
||||
if (_blur && (!_paper.document() || !_full.isNull())) {
|
||||
_blur->setDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::startFadeInFrom(QPixmap previous) {
|
||||
_fadeOutThumbnail = std::move(previous);
|
||||
_fadeIn.start([=] { update(); }, 0., 1., st::backgroundCheck.duration);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::checkBlurAnimationStart() {
|
||||
if (_fadeIn.animating()
|
||||
|| _blurred.isNull()
|
||||
|| !_blur
|
||||
|| _paper.isBlurred() == _blur->checked()) {
|
||||
return;
|
||||
}
|
||||
_paper = _paper.withBlurred(_blur->checked());
|
||||
startFadeInFrom(_paper.isBlurred() ? _scaled : _blurred);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::updateServiceBg(std::optional<QColor> background) {
|
||||
if (background) {
|
||||
_serviceBg = Window::Theme::AdjustedColor(
|
||||
st::msgServiceBg->c,
|
||||
*background);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<QColor> BackgroundPreviewBox::patternBackgroundColor() const {
|
||||
return _paper.isPattern() ? _paper.backgroundColor() : std::nullopt;
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::checkLoadedDocument() {
|
||||
const auto document = _paper.document();
|
||||
if (!_full.isNull()
|
||||
|| !document
|
||||
|| !document->loaded(DocumentData::FilePathResolve::Checked)
|
||||
|| _generating) {
|
||||
return;
|
||||
}
|
||||
const auto generateCallback = [=](QImage &&image) {
|
||||
auto [left, right] = base::make_binary_guard();
|
||||
_generating = std::move(left);
|
||||
crl::async([
|
||||
this,
|
||||
image = std::move(image),
|
||||
patternBackground = patternBackgroundColor(),
|
||||
guard = std::move(right)
|
||||
]() mutable {
|
||||
auto scaled = PrepareScaledFromFull(image, patternBackground);
|
||||
const auto ms = crl::now();
|
||||
auto blurred = patternBackground
|
||||
? QImage()
|
||||
: PrepareScaledNonPattern(
|
||||
Data::PrepareBlurredBackground(image),
|
||||
Images::Option(0));
|
||||
crl::on_main(std::move(guard), [
|
||||
this,
|
||||
image = std::move(image),
|
||||
scaled = std::move(scaled),
|
||||
blurred = std::move(blurred)
|
||||
]() mutable {
|
||||
_full = std::move(image);
|
||||
setScaledFromImage(std::move(scaled), std::move(blurred));
|
||||
update();
|
||||
});
|
||||
});
|
||||
};
|
||||
_generating = Data::ReadImageAsync(
|
||||
document,
|
||||
Window::Theme::ProcessBackgroundImage,
|
||||
generateCallback);
|
||||
}
|
||||
|
||||
bool BackgroundPreviewBox::Start(
|
||||
const QString &slug,
|
||||
const QMap<QString, QString> ¶ms) {
|
||||
if (const auto paper = Data::WallPaper::FromColorSlug(slug)) {
|
||||
Ui::show(Box<BackgroundPreviewBox>(paper->withUrlParams(params)));
|
||||
return true;
|
||||
}
|
||||
if (!IsValidWallPaperSlug(slug)) {
|
||||
Ui::show(Box<InformBox>(lang(lng_background_bad_link)));
|
||||
return false;
|
||||
}
|
||||
Auth().api().requestWallPaper(slug, [=](const Data::WallPaper &result) {
|
||||
Ui::show(Box<BackgroundPreviewBox>(result.withUrlParams(params)));
|
||||
}, [](const RPCError &error) {
|
||||
Ui::show(Box<InformBox>(lang(lng_background_bad_link)));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
HistoryView::Context BackgroundPreviewBox::elementContext() {
|
||||
return HistoryView::Context::ContactPreview;
|
||||
}
|
||||
|
||||
std::unique_ptr<HistoryView::Element> BackgroundPreviewBox::elementCreate(
|
||||
not_null<HistoryMessage*> message) {
|
||||
return std::make_unique<HistoryView::Message>(delegate(), message);
|
||||
}
|
||||
|
||||
std::unique_ptr<HistoryView::Element> BackgroundPreviewBox::elementCreate(
|
||||
not_null<HistoryService*> message) {
|
||||
Unexpected("Service message in BackgroundPreviewBox.");
|
||||
}
|
||||
|
||||
bool BackgroundPreviewBox::elementUnderCursor(
|
||||
not_null<const Element*> view) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::elementAnimationAutoplayAsync(
|
||||
not_null<const Element*> element) {
|
||||
}
|
||||
|
||||
crl::time BackgroundPreviewBox::elementHighlightTime(
|
||||
not_null<const Element*> element) {
|
||||
return crl::time(0);
|
||||
}
|
||||
|
||||
bool BackgroundPreviewBox::elementInSelectionMode() {
|
||||
return false;
|
||||
}
|
||||
81
Telegram/SourceFiles/boxes/background_preview_box.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
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/binary_guard.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "history/admin_log/history_admin_log_item.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
|
||||
namespace Ui {
|
||||
class Checkbox;
|
||||
} // namespace Ui
|
||||
|
||||
class BackgroundPreviewBox
|
||||
: public BoxContent
|
||||
, private HistoryView::ElementDelegate {
|
||||
public:
|
||||
BackgroundPreviewBox(QWidget*, const Data::WallPaper &paper);
|
||||
|
||||
static bool Start(
|
||||
const QString &slug,
|
||||
const QMap<QString, QString> ¶ms);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
using Element = HistoryView::Element;
|
||||
not_null<HistoryView::ElementDelegate*> delegate();
|
||||
HistoryView::Context elementContext() override;
|
||||
std::unique_ptr<Element> elementCreate(
|
||||
not_null<HistoryMessage*> message) override;
|
||||
std::unique_ptr<Element> elementCreate(
|
||||
not_null<HistoryService*> message) override;
|
||||
bool elementUnderCursor(not_null<const Element*> view) override;
|
||||
void elementAnimationAutoplayAsync(
|
||||
not_null<const Element*> element) override;
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const Element*> element) override;
|
||||
bool elementInSelectionMode() override;
|
||||
|
||||
void apply();
|
||||
void share();
|
||||
void step_radial(crl::time ms, bool timer);
|
||||
QRect radialRect() const;
|
||||
|
||||
void checkLoadedDocument();
|
||||
bool setScaledFromThumb();
|
||||
void setScaledFromImage(QImage &&image, QImage &&blurred);
|
||||
void updateServiceBg(std::optional<QColor> background);
|
||||
std::optional<QColor> patternBackgroundColor() const;
|
||||
void paintImage(Painter &p, crl::time ms);
|
||||
void paintRadial(Painter &p, crl::time ms);
|
||||
void paintTexts(Painter &p, crl::time ms);
|
||||
void paintDate(Painter &p);
|
||||
void createBlurCheckbox();
|
||||
int textsTop() const;
|
||||
void startFadeInFrom(QPixmap previous);
|
||||
void checkBlurAnimationStart();
|
||||
|
||||
AdminLog::OwnedItem _text1;
|
||||
AdminLog::OwnedItem _text2;
|
||||
Data::WallPaper _paper;
|
||||
QImage _full;
|
||||
QPixmap _scaled, _blurred, _fadeOutThumbnail;
|
||||
Animation _fadeIn;
|
||||
Ui::RadialAnimation _radial;
|
||||
base::binary_guard _generating;
|
||||
std::optional<QColor> _serviceBg;
|
||||
object_ptr<Ui::Checkbox> _blur = { nullptr };
|
||||
|
||||
};
|
||||
@@ -13,6 +13,19 @@ using "intro/intro.style";
|
||||
boxDuration: 200;
|
||||
boxRadius: 3px;
|
||||
|
||||
ServiceCheck {
|
||||
margin: margins;
|
||||
diameter: pixels;
|
||||
shift: pixels;
|
||||
thickness: pixels;
|
||||
tip: point;
|
||||
small: pixels;
|
||||
large: pixels;
|
||||
stroke: pixels;
|
||||
color: color;
|
||||
duration: int;
|
||||
}
|
||||
|
||||
boxButtonFont: font(boxFontSize semibold);
|
||||
defaultBoxButton: RoundButton(defaultLightButton) {
|
||||
width: -24px;
|
||||
@@ -69,7 +82,7 @@ boxTitle: FlatLabel(defaultFlatLabel) {
|
||||
linkFontOver: font(17px semibold underline);
|
||||
}
|
||||
}
|
||||
boxTitlePosition: point(23px, 20px);
|
||||
boxTitlePosition: point(23px, 16px);
|
||||
boxTitleHeight: 56px;
|
||||
boxLayerTitlePosition: point(23px, 16px);
|
||||
boxLayerTitleHeight: 56px;
|
||||
@@ -533,6 +546,10 @@ aboutLabel: FlatLabel(defaultFlatLabel) {
|
||||
autoDownloadTopDelta: 10px;
|
||||
autoDownloadTitlePosition: point(23px, 18px);
|
||||
autoDownloadTitleFont: font(15px semibold);
|
||||
autoDownloadLimitSlider: MediaSlider(defaultContinuousSlider) {
|
||||
seekSize: size(15px, 15px);
|
||||
}
|
||||
autoDownloadLimitPadding: margins(22px, 8px, 22px, 8px);
|
||||
|
||||
confirmCaptionArea: InputField(defaultInputField) {
|
||||
textMargins: margins(1px, 26px, 31px, 4px);
|
||||
@@ -688,6 +705,7 @@ rightsCheckbox: Checkbox(defaultBoxCheckbox) {
|
||||
rightsToggle: Toggle(defaultToggle) {
|
||||
toggledFg: windowBgActive;
|
||||
untoggledFg: attentionButtonFg;
|
||||
lockIcon: icon {{ "info_rights_lock", windowBgActive }};
|
||||
xsize: 8px;
|
||||
vsize: 5px;
|
||||
vshift: 1px;
|
||||
@@ -695,7 +713,8 @@ rightsToggle: Toggle(defaultToggle) {
|
||||
duration: 120;
|
||||
}
|
||||
rightsDividerHeight: 10px;
|
||||
rightsHeaderMargin: margins(23px, 20px, 23px, 8px);
|
||||
rightsDividerMargin: margins(0px, 0px, 0px, 20px);
|
||||
rightsHeaderMargin: margins(23px, 0px, 23px, 8px);
|
||||
rightsToggleMargin: margins(23px, 8px, 23px, 8px);
|
||||
rightsAboutMargin: margins(23px, 8px, 23px, 8px);
|
||||
rightsPhotoButton: UserpicButton(defaultUserpicButton) {
|
||||
@@ -718,7 +737,7 @@ rightsHeaderLabel: FlatLabel(boxLabel) {
|
||||
}
|
||||
textFg: windowActiveTextFg;
|
||||
}
|
||||
rightsUntilMargin: margins(0px, 8px, 0px, 0px);
|
||||
rightsUntilMargin: margins(0px, 8px, 0px, 20px);
|
||||
|
||||
mutePhotoButton: UserpicButton(defaultUserpicButton) {
|
||||
size: size(40px, 40px);
|
||||
@@ -834,3 +853,100 @@ themesScroll: ScrollArea(defaultScrollArea) {
|
||||
bottomsh: 0px;
|
||||
topsh: 0px;
|
||||
}
|
||||
|
||||
createPollField: InputField(defaultInputField) {
|
||||
font: boxTextFont;
|
||||
textMargins: margins(0px, 0px, 0px, 0px);
|
||||
textAlign: align(left);
|
||||
heightMin: 36px;
|
||||
heightMax: 86px;
|
||||
placeholderFg: placeholderFg;
|
||||
placeholderFgActive: placeholderFgActive;
|
||||
placeholderFgError: placeholderFgActive;
|
||||
placeholderMargins: margins(2px, 0px, 2px, 0px);
|
||||
placeholderAlign: align(topleft);
|
||||
placeholderScale: 0.;
|
||||
placeholderFont: boxTextFont;
|
||||
placeholderShift: -50px;
|
||||
border: 0px;
|
||||
borderActive: 0px;
|
||||
duration: 100;
|
||||
}
|
||||
createPollFieldPadding: margins(22px, 5px, 22px, 5px);
|
||||
createPollOptionField: InputField(createPollField) {
|
||||
textMargins: margins(22px, 8px, 40px, 8px);
|
||||
placeholderMargins: margins(2px, 0px, 2px, 0px);
|
||||
heightMax: 64px;
|
||||
}
|
||||
createPollLimitLabel: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 274px;
|
||||
align: align(topleft);
|
||||
}
|
||||
createPollLimitPadding: margins(22px, 10px, 22px, 5px);
|
||||
createPollOptionRemove: CrossButton {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
|
||||
cross: CrossAnimation {
|
||||
size: 22px;
|
||||
skip: 6px;
|
||||
stroke: 1px;
|
||||
minScale: 0.3;
|
||||
}
|
||||
crossFg: boxTitleCloseFg;
|
||||
crossFgOver: boxTitleCloseFgOver;
|
||||
crossPosition: point(0px, 0px);
|
||||
|
||||
duration: 150;
|
||||
loadingPeriod: 1000;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
}
|
||||
createPollOptionRemovePosition: point(10px, 7px);
|
||||
createPollWarning: FlatLabel(defaultFlatLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
palette: TextPalette(defaultTextPalette) {
|
||||
linkFg: boxTextFgError;
|
||||
}
|
||||
}
|
||||
createPollWarningPosition: point(16px, 6px);
|
||||
|
||||
callSettingsButton: IconButton {
|
||||
width: 50px;
|
||||
height: boxLayerTitleHeight;
|
||||
icon: icon {{ "menu_settings", boxTitleCloseFg }};
|
||||
iconOver: icon {{ "menu_settings", boxTitleCloseFgOver }};
|
||||
iconPosition: point(8px, -1px);
|
||||
rippleAreaSize: 44px;
|
||||
rippleAreaPosition: point(0px, 6px);
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
}
|
||||
|
||||
backgroundCheckbox: Checkbox(defaultCheckbox) {
|
||||
textFg: msgServiceFg;
|
||||
textFgActive: msgServiceFg;
|
||||
|
||||
width: -50px;
|
||||
margin: margins(0px, 0px, 0px, 0px);
|
||||
|
||||
textPosition: point(0px, 8px);
|
||||
checkPosition: point(0px, 0px);
|
||||
|
||||
style: semiboldTextStyle;
|
||||
}
|
||||
|
||||
backgroundCheck: ServiceCheck {
|
||||
margin: margins(12px, 8px, 8px, 8px);
|
||||
diameter: 18px;
|
||||
shift: 2px;
|
||||
thickness: 2px;
|
||||
tip: point(7px, 13px);
|
||||
small: 3px;
|
||||
large: 6px;
|
||||
stroke: 2px;
|
||||
color: msgServiceFg;
|
||||
duration: 200;
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ int CalendarBox::Inner::rowsTop() const {
|
||||
|
||||
void CalendarBox::Inner::paintRows(Painter &p, QRect clip) {
|
||||
p.setFont(st::calendarDaysFont);
|
||||
auto ms = getms();
|
||||
auto ms = crl::now();
|
||||
auto y = rowsTop();
|
||||
auto index = -_context->daysShift();
|
||||
auto highlightedIndex = _context->highlightedIndex();
|
||||
@@ -495,16 +495,8 @@ void CalendarBox::setMaxDate(QDate date) {
|
||||
}
|
||||
|
||||
void CalendarBox::prepare() {
|
||||
_previous->setClickedCallback([this] {
|
||||
if (isPreviousEnabled()) {
|
||||
_context->skipMonth(-1);
|
||||
}
|
||||
});
|
||||
_next->setClickedCallback([this] {
|
||||
if (isNextEnabled()) {
|
||||
_context->skipMonth(1);
|
||||
}
|
||||
});
|
||||
_previous->setClickedCallback([this] { goPreviousMonth(); });
|
||||
_next->setClickedCallback([this] { goNextMonth(); });
|
||||
|
||||
// _inner = setInnerWidget(object_ptr<Inner>(this, _context.get()), st::calendarScroll, st::calendarTitleHeight);
|
||||
_inner->setDateChosenCallback(std::move(_callback));
|
||||
@@ -528,6 +520,18 @@ bool CalendarBox::isNextEnabled() const {
|
||||
return (_context->maxDayIndex() >= _context->daysCount());
|
||||
}
|
||||
|
||||
void CalendarBox::goPreviousMonth() {
|
||||
if (isPreviousEnabled()) {
|
||||
_context->skipMonth(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void CalendarBox::goNextMonth() {
|
||||
if (isNextEnabled()) {
|
||||
_context->skipMonth(1);
|
||||
}
|
||||
}
|
||||
|
||||
void CalendarBox::monthChanged(QDate month) {
|
||||
setDimensions(_st.width, st::calendarTitleHeight + _inner->countHeight());
|
||||
auto previousEnabled = isPreviousEnabled();
|
||||
@@ -548,4 +552,14 @@ void CalendarBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
}
|
||||
|
||||
void CalendarBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
e->ignore();
|
||||
} else if (e->key() == Qt::Key_Left) {
|
||||
goPreviousMonth();
|
||||
} else if (e->key() == Qt::Key_Right) {
|
||||
goNextMonth();
|
||||
}
|
||||
}
|
||||
|
||||
CalendarBox::~CalendarBox() = default;
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
@@ -50,6 +51,9 @@ private:
|
||||
bool isPreviousEnabled() const;
|
||||
bool isNextEnabled() const;
|
||||
|
||||
void goPreviousMonth();
|
||||
void goNextMonth();
|
||||
|
||||
const style::CalendarSizes &_st;
|
||||
|
||||
class Context;
|
||||
|
||||
@@ -8,13 +8,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/change_phone_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "boxes/confirm_phone_box.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "auth_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -144,11 +146,19 @@ void ChangePhoneBox::EnterPhone::submit() {
|
||||
hideError();
|
||||
|
||||
auto phoneNumber = _phone->getLastText().trimmed();
|
||||
_requestId = MTP::send(MTPaccount_SendChangePhoneCode(MTP_flags(0), MTP_string(phoneNumber), MTP_bool(false)), rpcDone(crl::guard(this, [this, phoneNumber](const MTPauth_SentCode &result) {
|
||||
return sendPhoneDone(phoneNumber, result);
|
||||
})), rpcFail(crl::guard(this, [this, phoneNumber](const RPCError &error) {
|
||||
return sendPhoneFail(phoneNumber, error);
|
||||
})));
|
||||
_requestId = MTP::send(
|
||||
MTPaccount_SendChangePhoneCode(
|
||||
MTP_string(phoneNumber),
|
||||
MTP_codeSettings(
|
||||
MTP_flags(0),
|
||||
MTPstring())),
|
||||
rpcDone(crl::guard(this, [=](
|
||||
const MTPauth_SentCode &result) {
|
||||
return sendPhoneDone(phoneNumber, result);
|
||||
})), rpcFail(crl::guard(this, [=](
|
||||
const RPCError &error) {
|
||||
return sendPhoneFail(phoneNumber, error);
|
||||
})));
|
||||
}
|
||||
|
||||
void ChangePhoneBox::EnterPhone::sendPhoneDone(const QString &phoneNumber, const MTPauth_SentCode &result) {
|
||||
@@ -260,7 +270,7 @@ void ChangePhoneBox::EnterCode::submit() {
|
||||
MTP_string(_hash),
|
||||
MTP_string(code)
|
||||
), rpcDone([weak = make_weak(this)](const MTPUser &result) {
|
||||
App::feedUser(result);
|
||||
Auth().data().processUser(result);
|
||||
if (weak) {
|
||||
Ui::hideLayer();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "application.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
@@ -23,42 +22,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
#include "auth_session.h"
|
||||
#include "observer_peer.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void ConvertToSupergroupDone(const MTPUpdates &updates) {
|
||||
Auth().api().applyUpdates(updates);
|
||||
|
||||
auto handleChats = [](const MTPVector<MTPChat> &chats) {
|
||||
for (const auto &chat : chats.v) {
|
||||
if (chat.type() == mtpc_channel) {
|
||||
const auto channel = App::channel(chat.c_channel().vid.v);
|
||||
Ui::showPeerHistory(channel, ShowAtUnreadMsgId);
|
||||
Auth().api().requestParticipantsCountDelayed(channel);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch (updates.type()) {
|
||||
case mtpc_updates:
|
||||
handleChats(updates.c_updates().vchats);
|
||||
break;
|
||||
case mtpc_updatesCombined:
|
||||
handleChats(updates.c_updatesCombined().vchats);
|
||||
break;
|
||||
default:
|
||||
LOG(("API Error: unexpected update cons %1 "
|
||||
"(ConvertToSupergroupBox::convertDone)").arg(updates.type()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TextParseOptions _confirmBoxTextOptions = {
|
||||
TextParseLinks | TextParseMultiline | TextParseRichText, // flags
|
||||
0, // maxw
|
||||
@@ -66,7 +38,11 @@ TextParseOptions _confirmBoxTextOptions = {
|
||||
Qt::LayoutDirectionAuto, // dir
|
||||
};
|
||||
|
||||
ConfirmBox::ConfirmBox(QWidget*, const QString &text, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
FnMut<void()> confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(lang(lng_box_ok))
|
||||
, _cancelText(lang(lng_cancel))
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
@@ -76,7 +52,12 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, FnMut<void()> confirmedCal
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
FnMut<void()> confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(lang(lng_cancel))
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
@@ -86,7 +67,12 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(QWidget*, const TextWithEntities &text, const QString &confirmText, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const TextWithEntities &text,
|
||||
const QString &confirmText,
|
||||
FnMut<void()> confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(lang(lng_cancel))
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
@@ -96,7 +82,13 @@ ConfirmBox::ConfirmBox(QWidget*, const TextWithEntities &text, const QString &co
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const style::RoundButton &confirmStyle,
|
||||
FnMut<void()> confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(lang(lng_cancel))
|
||||
, _confirmStyle(confirmStyle)
|
||||
@@ -106,7 +98,13 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const QString &cancelText, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const QString &cancelText,
|
||||
FnMut<void()> confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(cancelText)
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
@@ -116,7 +114,14 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText, const style::RoundButton &confirmStyle, const QString &cancelText, FnMut<void()> confirmedCallback, FnMut<void()> cancelledCallback)
|
||||
ConfirmBox::ConfirmBox(
|
||||
QWidget*,
|
||||
const QString &text,
|
||||
const QString &confirmText,
|
||||
const style::RoundButton &confirmStyle,
|
||||
const QString &cancelText,
|
||||
FnMut<void()> confirmedCallback,
|
||||
FnMut<void()> cancelledCallback)
|
||||
: _confirmText(confirmText)
|
||||
, _cancelText(cancelText)
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
@@ -126,7 +131,11 @@ ConfirmBox::ConfirmBox(QWidget*, const QString &text, const QString &confirmText
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(const InformBoxTag &, const QString &text, const QString &doneText, Fn<void()> closedCallback)
|
||||
ConfirmBox::ConfirmBox(
|
||||
const InformBoxTag &,
|
||||
const QString &text,
|
||||
const QString &doneText,
|
||||
Fn<void()> closedCallback)
|
||||
: _confirmText(doneText)
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _informative(true)
|
||||
@@ -136,7 +145,11 @@ ConfirmBox::ConfirmBox(const InformBoxTag &, const QString &text, const QString
|
||||
init(text);
|
||||
}
|
||||
|
||||
ConfirmBox::ConfirmBox(const InformBoxTag &, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback)
|
||||
ConfirmBox::ConfirmBox(
|
||||
const InformBoxTag &,
|
||||
const TextWithEntities &text,
|
||||
const QString &doneText,
|
||||
Fn<void()> closedCallback)
|
||||
: _confirmText(doneText)
|
||||
, _confirmStyle(st::defaultBoxButton)
|
||||
, _informative(true)
|
||||
@@ -146,8 +159,9 @@ ConfirmBox::ConfirmBox(const InformBoxTag &, const TextWithEntities &text, const
|
||||
init(text);
|
||||
}
|
||||
|
||||
FnMut<void()> ConfirmBox::generateInformCallback(Fn<void()> closedCallback) {
|
||||
return crl::guard(this, [this, closedCallback] {
|
||||
FnMut<void()> ConfirmBox::generateInformCallback(
|
||||
Fn<void()> closedCallback) {
|
||||
return crl::guard(this, [=] {
|
||||
closeBox();
|
||||
if (closedCallback) {
|
||||
closedCallback();
|
||||
@@ -156,7 +170,10 @@ FnMut<void()> ConfirmBox::generateInformCallback(Fn<void()> closedCallback) {
|
||||
}
|
||||
|
||||
void ConfirmBox::init(const QString &text) {
|
||||
_text.setText(st::boxLabelStyle, text, _informative ? _confirmBoxTextOptions : _textPlainOptions);
|
||||
_text.setText(
|
||||
st::boxLabelStyle,
|
||||
text,
|
||||
_informative ? _confirmBoxTextOptions : _textPlainOptions);
|
||||
}
|
||||
|
||||
void ConfirmBox::init(const TextWithEntities &text) {
|
||||
@@ -164,9 +181,14 @@ void ConfirmBox::init(const TextWithEntities &text) {
|
||||
}
|
||||
|
||||
void ConfirmBox::prepare() {
|
||||
addButton([this] { return _confirmText; }, [this] { confirmed(); }, _confirmStyle);
|
||||
addButton(
|
||||
[=] { return _confirmText; },
|
||||
[=] { confirmed(); },
|
||||
_confirmStyle);
|
||||
if (!_informative) {
|
||||
addButton([this] { return _cancelText; }, [this] { _cancelled = true; closeBox(); });
|
||||
addButton(
|
||||
[=] { return _cancelText; },
|
||||
[=] { _cancelled = true; closeBox(); });
|
||||
}
|
||||
|
||||
boxClosing() | rpl::start_with_next([=] {
|
||||
@@ -318,7 +340,7 @@ void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
|
||||
mouseMoveEvent(e);
|
||||
if (_linkOver) {
|
||||
if (_channel->inviteLink().isEmpty()) {
|
||||
Auth().api().exportInviteLink(_channel);
|
||||
_channel->session().api().exportInviteLink(_channel);
|
||||
} else {
|
||||
QGuiApplication::clipboard()->setText(_channel->inviteLink());
|
||||
Ui::Toast::Show(lang(lng_create_channel_link_copied));
|
||||
@@ -363,65 +385,6 @@ void MaxInviteBox::resizeEvent(QResizeEvent *e) {
|
||||
_invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height);
|
||||
}
|
||||
|
||||
ConvertToSupergroupBox::ConvertToSupergroupBox(QWidget*, ChatData *chat)
|
||||
: _chat(chat)
|
||||
, _text(100)
|
||||
, _note(100) {
|
||||
}
|
||||
|
||||
void ConvertToSupergroupBox::prepare() {
|
||||
QStringList text;
|
||||
text.push_back(lang(lng_profile_convert_feature1));
|
||||
text.push_back(lang(lng_profile_convert_feature2));
|
||||
text.push_back(lang(lng_profile_convert_feature3));
|
||||
text.push_back(lang(lng_profile_convert_feature4));
|
||||
|
||||
setTitle(langFactory(lng_profile_convert_title));
|
||||
|
||||
addButton(langFactory(lng_profile_convert_confirm), [this] { convertToSupergroup(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
|
||||
_text.setText(st::boxLabelStyle, text.join('\n'), _confirmBoxTextOptions);
|
||||
_note.setText(st::boxLabelStyle, lng_profile_convert_warning(lt_bold_start, textcmdStartSemibold(), lt_bold_end, textcmdStopSemibold()), _confirmBoxTextOptions);
|
||||
_textWidth = st::boxWideWidth - st::boxPadding.left() - st::boxButtonPadding.right();
|
||||
_textHeight = _text.countHeight(_textWidth);
|
||||
setDimensions(st::boxWideWidth, _textHeight + st::boxPadding.bottom() + _note.countHeight(_textWidth));
|
||||
}
|
||||
|
||||
void ConvertToSupergroupBox::convertToSupergroup() {
|
||||
MTP::send(MTPmessages_MigrateChat(_chat->inputChat), rpcDone(&ConvertToSupergroupBox::convertDone), rpcFail(&ConvertToSupergroupBox::convertFail));
|
||||
}
|
||||
|
||||
void ConvertToSupergroupBox::convertDone(const MTPUpdates &updates) {
|
||||
Ui::hideLayer();
|
||||
ConvertToSupergroupDone(updates);
|
||||
}
|
||||
|
||||
bool ConvertToSupergroupBox::convertFail(const RPCError &error) {
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
Ui::hideLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConvertToSupergroupBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
convertToSupergroup();
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertToSupergroupBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::boxTextFg);
|
||||
_text.drawLeft(p, st::boxPadding.left(), 0, _textWidth, width());
|
||||
_note.drawLeft(p, st::boxPadding.left(), _textHeight + st::boxPadding.bottom(), _textWidth, width());
|
||||
}
|
||||
|
||||
PinMessageBox::PinMessageBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
@@ -479,7 +442,7 @@ void PinMessageBox::pinMessage() {
|
||||
}
|
||||
|
||||
void PinMessageBox::pinDone(const MTPUpdates &updates) {
|
||||
Auth().api().applyUpdates(updates);
|
||||
_peer->session().api().applyUpdates(updates);
|
||||
Ui::hideLayer();
|
||||
}
|
||||
|
||||
@@ -493,8 +456,7 @@ DeleteMessagesBox::DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<HistoryItem*> item,
|
||||
bool suggestModerateActions)
|
||||
: _ids(1, item->fullId())
|
||||
, _singleItem(true) {
|
||||
: _ids(1, item->fullId()) {
|
||||
if (suggestModerateActions) {
|
||||
_moderateBan = item->suggestBanReport();
|
||||
_moderateDeleteAll = item->suggestDeleteAllReport();
|
||||
@@ -512,11 +474,54 @@ DeleteMessagesBox::DeleteMessagesBox(
|
||||
Expects(!_ids.empty());
|
||||
}
|
||||
|
||||
DeleteMessagesBox::DeleteMessagesBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
bool justClear)
|
||||
: _wipeHistoryPeer(peer)
|
||||
, _wipeHistoryJustClear(justClear) {
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::prepare() {
|
||||
auto text = QString();
|
||||
if (_moderateFrom) {
|
||||
auto details = TextWithEntities();
|
||||
const auto appendDetails = [&](TextWithEntities &&text) {
|
||||
TextUtilities::Append(details, { "\n\n" });
|
||||
TextUtilities::Append(details, std::move(text));
|
||||
};
|
||||
auto deleteKey = lng_box_delete;
|
||||
auto deleteStyle = &st::defaultBoxButton;
|
||||
if (const auto peer = _wipeHistoryPeer) {
|
||||
if (_wipeHistoryJustClear) {
|
||||
details.text = peer->isSelf()
|
||||
? lang(lng_sure_delete_saved_messages)
|
||||
: peer->isUser()
|
||||
? lng_sure_delete_history(lt_contact, peer->name)
|
||||
: lng_sure_delete_group_history(lt_group, peer->name);
|
||||
deleteStyle = &st::attentionBoxButton;
|
||||
} else {
|
||||
details.text = peer->isSelf()
|
||||
? lang(lng_sure_delete_saved_messages)
|
||||
: peer->isUser()
|
||||
? lng_sure_delete_history(lt_contact, peer->name)
|
||||
: peer->isChat()
|
||||
? lng_sure_delete_and_exit(lt_group, peer->name)
|
||||
: lang(peer->isMegagroup()
|
||||
? lng_sure_leave_group
|
||||
: lng_sure_leave_channel);
|
||||
deleteKey = _wipeHistoryPeer->isUser()
|
||||
? lng_box_delete
|
||||
: lng_box_leave;
|
||||
deleteStyle = &(peer->isChannel()
|
||||
? st::defaultBoxButton
|
||||
: st::attentionBoxButton);
|
||||
}
|
||||
if (auto revoke = revokeText(peer)) {
|
||||
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
|
||||
appendDetails(std::move(revoke->description));
|
||||
}
|
||||
} else if (_moderateFrom) {
|
||||
Assert(_moderateInChannel != nullptr);
|
||||
text = lang(lng_selected_delete_sure_this);
|
||||
details.text = lang(lng_selected_delete_sure_this);
|
||||
if (_moderateBan) {
|
||||
_banUser.create(this, lang(lng_ban_user), false, st::defaultBoxCheckbox);
|
||||
}
|
||||
@@ -525,49 +530,32 @@ void DeleteMessagesBox::prepare() {
|
||||
_deleteAll.create(this, lang(lng_delete_all_from), false, st::defaultBoxCheckbox);
|
||||
}
|
||||
} else {
|
||||
text = _singleItem ? lang(lng_selected_delete_sure_this) : lng_selected_delete_sure(lt_count, _ids.size());
|
||||
auto canDeleteAllForEveryone = true;
|
||||
auto now = unixtime();
|
||||
auto deleteForUser = (UserData*)nullptr;
|
||||
auto peer = (PeerData*)nullptr;
|
||||
auto forEveryoneText = lang(lng_delete_for_everyone_check);
|
||||
for (const auto fullId : std::as_const(_ids)) {
|
||||
if (const auto item = App::histItemById(fullId)) {
|
||||
peer = item->history()->peer;
|
||||
if (!item->canDeleteForEveryone(now)) {
|
||||
canDeleteAllForEveryone = false;
|
||||
break;
|
||||
} else if (auto user = item->history()->peer->asUser()) {
|
||||
if (!deleteForUser || deleteForUser == user) {
|
||||
deleteForUser = user;
|
||||
forEveryoneText = lng_delete_for_other_check(
|
||||
lt_user,
|
||||
user->firstName);
|
||||
} else {
|
||||
forEveryoneText = lang(lng_delete_for_everyone_check);
|
||||
}
|
||||
details.text = (_ids.size() == 1)
|
||||
? lang(lng_selected_delete_sure_this)
|
||||
: lng_selected_delete_sure(lt_count, _ids.size());
|
||||
if (const auto peer = checkFromSinglePeer()) {
|
||||
auto count = int(_ids.size());
|
||||
if (auto revoke = revokeText(peer)) {
|
||||
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
|
||||
appendDetails(std::move(revoke->description));
|
||||
} else if (peer && peer->isChannel()) {
|
||||
if (peer->isMegagroup()) {
|
||||
appendDetails({ lng_delete_for_everyone_hint(lt_count, count) });
|
||||
}
|
||||
} else {
|
||||
canDeleteAllForEveryone = false;
|
||||
} else if (peer->isChat()) {
|
||||
appendDetails({ lng_delete_for_me_chat_hint(lt_count, count) });
|
||||
} else if (!peer->isSelf()) {
|
||||
appendDetails({ lng_delete_for_me_hint(lt_count, count) });
|
||||
}
|
||||
}
|
||||
auto count = int(_ids.size());
|
||||
if (canDeleteAllForEveryone) {
|
||||
_forEveryone.create(this, forEveryoneText, false, st::defaultBoxCheckbox);
|
||||
} else if (peer && peer->isChannel()) {
|
||||
if (peer->isMegagroup()) {
|
||||
text += qsl("\n\n") + lng_delete_for_everyone_hint(lt_count, count);
|
||||
}
|
||||
} else if (peer->isChat()) {
|
||||
text += qsl("\n\n") + lng_delete_for_me_chat_hint(lt_count, count);
|
||||
} else if (!peer->isSelf()) {
|
||||
text += qsl("\n\n") + lng_delete_for_me_hint(lt_count, count);
|
||||
}
|
||||
}
|
||||
_text.create(this, text, Ui::FlatLabel::InitType::Simple, st::boxLabel);
|
||||
_text.create(this, rpl::single(std::move(details)), st::boxLabel);
|
||||
|
||||
addButton(langFactory(lng_box_delete), [this] { deleteAndClear(); });
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
addButton(
|
||||
langFactory(deleteKey),
|
||||
[=] { deleteAndClear(); },
|
||||
*deleteStyle);
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
auto fullHeight = st::boxPadding.top() + _text->height() + st::boxPadding.bottom();
|
||||
if (_moderateFrom) {
|
||||
@@ -579,12 +567,112 @@ void DeleteMessagesBox::prepare() {
|
||||
if (_deleteAll) {
|
||||
fullHeight += st::boxLittleSkip + _deleteAll->heightNoMargins();
|
||||
}
|
||||
} else if (_forEveryone) {
|
||||
fullHeight += st::boxMediumSkip + _forEveryone->heightNoMargins();
|
||||
} else if (_revoke) {
|
||||
fullHeight += st::boxMediumSkip + _revoke->heightNoMargins();
|
||||
}
|
||||
setDimensions(st::boxWidth, fullHeight);
|
||||
}
|
||||
|
||||
PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
|
||||
auto result = (PeerData*)nullptr;
|
||||
for (const auto fullId : std::as_const(_ids)) {
|
||||
if (const auto item = App::histItemById(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 = lng_delete_for_other_check(
|
||||
lt_user,
|
||||
user->firstName);
|
||||
} else {
|
||||
result.checkbox = lang(lng_delete_for_everyone_check);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto items = ranges::view::all(
|
||||
_ids
|
||||
) | ranges::view::transform([](FullMsgId id) {
|
||||
return App::histItemById(id);
|
||||
}) | ranges::view::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 = unixtime();
|
||||
const auto canRevoke = [&](HistoryItem * item) {
|
||||
return item->canDeleteForEveryone(now);
|
||||
};
|
||||
const auto cannotRevoke = [&](HistoryItem *item) {
|
||||
return !item->canDeleteForEveryone(now);
|
||||
};
|
||||
const auto canRevokeAll = ranges::find_if(
|
||||
items,
|
||||
cannotRevoke
|
||||
) == end(items);
|
||||
auto outgoing = items | ranges::view::filter(&HistoryItem::out);
|
||||
const auto canRevokeOutgoingCount = canRevokeAll
|
||||
? -1
|
||||
: ranges::count_if(outgoing, canRevoke);
|
||||
|
||||
if (canRevokeAll) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
result.checkbox = lng_delete_for_other_check(
|
||||
lt_user,
|
||||
user->firstName);
|
||||
} else {
|
||||
result.checkbox = lang(lng_delete_for_everyone_check);
|
||||
}
|
||||
return result;
|
||||
} else if (canRevokeOutgoingCount > 0) {
|
||||
result.checkbox = lang(lng_delete_for_other_my);
|
||||
if (const auto user = peer->asUser()) {
|
||||
auto boldName = TextWithEntities{ user->firstName };
|
||||
boldName.entities.push_back(
|
||||
EntityInText(EntityInTextBold, 0, boldName.text.size()));
|
||||
if (canRevokeOutgoingCount == 1) {
|
||||
result.description = lng_selected_unsend_about_user_one__generic<TextWithEntities>(
|
||||
lt_user,
|
||||
boldName);
|
||||
} else {
|
||||
result.description = lng_selected_unsend_about_user__generic<TextWithEntities>(
|
||||
lt_count,
|
||||
canRevokeOutgoingCount,
|
||||
lt_user,
|
||||
boldName);
|
||||
}
|
||||
} else if (canRevokeOutgoingCount == 1) {
|
||||
result.description = TextWithEntities{
|
||||
lang(lng_selected_unsend_about_group_one) };
|
||||
} else {
|
||||
result.description = TextWithEntities{
|
||||
lng_selected_unsend_about_group(
|
||||
lt_count,
|
||||
canRevokeOutgoingCount) };
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void DeleteMessagesBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
@@ -600,10 +688,10 @@ void DeleteMessagesBox::resizeEvent(QResizeEvent *e) {
|
||||
if (_deleteAll) {
|
||||
_deleteAll->moveToLeft(st::boxPadding.left(), top);
|
||||
}
|
||||
} else if (_forEveryone) {
|
||||
auto availableWidth = width() - 2 * st::boxPadding.left();
|
||||
_forEveryone->resizeToNaturalWidth(availableWidth);
|
||||
_forEveryone->moveToLeft(st::boxPadding.left(), _text->bottomNoMargins() + st::boxMediumSkip);
|
||||
} else if (_revoke) {
|
||||
const auto availableWidth = width() - 2 * st::boxPadding.left();
|
||||
_revoke->resizeToNaturalWidth(availableWidth);
|
||||
_revoke->moveToLeft(st::boxPadding.left(), _text->bottomNoMargins() + st::boxMediumSkip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,22 +704,45 @@ void DeleteMessagesBox::keyPressEvent(QKeyEvent *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 {
|
||||
const auto controller = App::wnd()->controller();
|
||||
if (controller->activeChatCurrent().peer() == peer) {
|
||||
Ui::showChatsList();
|
||||
}
|
||||
// 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()) {
|
||||
Auth().api().kickParticipant(
|
||||
_moderateInChannel->session().api().kickParticipant(
|
||||
_moderateInChannel,
|
||||
_moderateFrom,
|
||||
MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
|
||||
MTP_chatBannedRights(MTP_flags(0), MTP_int(0)));
|
||||
}
|
||||
if (_reportSpam->checked()) {
|
||||
MTP::send(
|
||||
_moderateInChannel->session().api().request(
|
||||
MTPchannels_ReportSpam(
|
||||
_moderateInChannel->inputChannel,
|
||||
_moderateFrom->inputUser,
|
||||
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg))));
|
||||
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg)))
|
||||
).send();
|
||||
}
|
||||
if (_deleteAll && _deleteAll->checked()) {
|
||||
Auth().api().deleteAllFromUser(
|
||||
_moderateInChannel->session().api().deleteAllFromUser(
|
||||
_moderateInChannel,
|
||||
_moderateFrom);
|
||||
}
|
||||
@@ -641,25 +752,25 @@ void DeleteMessagesBox::deleteAndClear() {
|
||||
_deleteConfirmedCallback();
|
||||
}
|
||||
|
||||
QMap<PeerData*, QVector<MTPint>> idsByPeer;
|
||||
base::flat_map<not_null<PeerData*>, QVector<MTPint>> idsByPeer;
|
||||
for (const auto itemId : _ids) {
|
||||
if (auto item = App::histItemById(itemId)) {
|
||||
auto history = item->history();
|
||||
auto wasOnServer = (item->id > 0);
|
||||
auto wasLast = (history->lastMessage() == item);
|
||||
if (const auto item = App::histItemById(itemId)) {
|
||||
const auto history = item->history();
|
||||
const auto wasOnServer = IsServerMsgId(item->id);
|
||||
const auto wasLast = (history->lastMessage() == item);
|
||||
const auto wasInChats = (history->chatListMessage() == item);
|
||||
item->destroy();
|
||||
|
||||
if (wasOnServer) {
|
||||
idsByPeer[history->peer].push_back(MTP_int(itemId.msg));
|
||||
} else if (wasLast && !history->lastMessageKnown()) {
|
||||
Auth().api().requestDialogEntry(history);
|
||||
} else if (wasLast || wasInChats) {
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto forEveryone = _forEveryone ? _forEveryone->checked() : false;
|
||||
for (auto i = idsByPeer.cbegin(), e = idsByPeer.cend(); i != e; ++i) {
|
||||
App::main()->deleteMessages(i.key(), i.value(), forEveryone);
|
||||
for (const auto &[peer, ids] : idsByPeer) {
|
||||
peer->session().api().deleteMessages(peer, ids, revoke);
|
||||
}
|
||||
Ui::hideLayer();
|
||||
Auth().data().sendHistoryChangeNotifications();
|
||||
@@ -724,7 +835,7 @@ std::vector<not_null<UserData*>> ConfirmInviteBox::GetParticipants(
|
||||
auto result = std::vector<not_null<UserData*>>();
|
||||
result.reserve(v.size());
|
||||
for (const auto &participant : v) {
|
||||
if (const auto user = App::feedUser(participant)) {
|
||||
if (const auto user = Auth().data().processUser(participant)) {
|
||||
result.push_back(user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,27 +119,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class ConvertToSupergroupBox : public BoxContent, public RPCSender {
|
||||
public:
|
||||
ConvertToSupergroupBox(QWidget*, ChatData *chat);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
void convertToSupergroup();
|
||||
void convertDone(const MTPUpdates &updates);
|
||||
bool convertFail(const RPCError &error);
|
||||
|
||||
ChatData *_chat;
|
||||
Text _text, _note;
|
||||
int32 _textWidth, _textHeight;
|
||||
|
||||
};
|
||||
|
||||
class PinMessageBox : public BoxContent, public RPCSender {
|
||||
public:
|
||||
PinMessageBox(QWidget*, not_null<PeerData*> peer, MsgId msgId);
|
||||
@@ -172,6 +151,7 @@ public:
|
||||
not_null<HistoryItem*> item,
|
||||
bool suggestModerateActions);
|
||||
DeleteMessagesBox(QWidget*, MessageIdsList &&selected);
|
||||
DeleteMessagesBox(QWidget*, not_null<PeerData*> peer, bool justClear);
|
||||
|
||||
void setDeleteConfirmedCallback(Fn<void()> callback) {
|
||||
_deleteConfirmedCallback = std::move(callback);
|
||||
@@ -184,17 +164,24 @@ protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
struct RevokeConfig {
|
||||
QString checkbox;
|
||||
TextWithEntities description;
|
||||
};
|
||||
void deleteAndClear();
|
||||
PeerData *checkFromSinglePeer() const;
|
||||
std::optional<RevokeConfig> revokeText(not_null<PeerData*> peer) const;
|
||||
|
||||
PeerData * const _wipeHistoryPeer = nullptr;
|
||||
const bool _wipeHistoryJustClear = false;
|
||||
const MessageIdsList _ids;
|
||||
const bool _singleItem = false;
|
||||
UserData *_moderateFrom = nullptr;
|
||||
ChannelData *_moderateInChannel = nullptr;
|
||||
bool _moderateBan = false;
|
||||
bool _moderateDeleteAll = false;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _text = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _forEveryone = { 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 };
|
||||
|
||||
@@ -170,7 +170,14 @@ void ConfirmPhoneBox::checkPhoneAndHash() {
|
||||
if (_sendCodeRequestId) {
|
||||
return;
|
||||
}
|
||||
_sendCodeRequestId = MTP::send(MTPaccount_SendConfirmPhoneCode(MTP_flags(0), MTP_string(_hash), MTPBool()), rpcDone(&ConfirmPhoneBox::sendCodeDone), rpcFail(&ConfirmPhoneBox::sendCodeFail));
|
||||
_sendCodeRequestId = MTP::send(
|
||||
MTPaccount_SendConfirmPhoneCode(
|
||||
MTP_string(_hash),
|
||||
MTP_codeSettings(
|
||||
MTP_flags(0),
|
||||
MTPstring())),
|
||||
rpcDone(&ConfirmPhoneBox::sendCodeDone),
|
||||
rpcFail(&ConfirmPhoneBox::sendCodeFail));
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::sendCodeDone(const MTPauth_SentCode &result) {
|
||||
|
||||
@@ -7,41 +7,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/connection_box.h"
|
||||
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_document.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "mainwidget.h"
|
||||
#include "messenger.h"
|
||||
#include "mainwindow.h"
|
||||
#include "auth_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "mtproto/connection.h"
|
||||
#include "core/application.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "history/history_location_manager.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "application.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kSaveSettingsDelayedTimeout = TimeMs(1000);
|
||||
constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000);
|
||||
|
||||
class ProxyRow : public Ui::RippleButton {
|
||||
public:
|
||||
@@ -65,8 +52,8 @@ protected:
|
||||
private:
|
||||
void setupControls(View &&view);
|
||||
int countAvailableWidth() const;
|
||||
void step_radial(TimeMs ms, bool timer);
|
||||
void paintCheck(Painter &p, TimeMs ms);
|
||||
void step_radial(crl::time ms, bool timer);
|
||||
void paintCheck(Painter &p, crl::time ms);
|
||||
void showMenu();
|
||||
|
||||
View _view;
|
||||
@@ -254,7 +241,7 @@ void ProxyRow::updateFields(View &&view) {
|
||||
update();
|
||||
}
|
||||
|
||||
void ProxyRow::step_radial(TimeMs ms, bool timer) {
|
||||
void ProxyRow::step_radial(crl::time ms, bool timer) {
|
||||
if (timer && !anim::Disabled()) {
|
||||
update();
|
||||
}
|
||||
@@ -281,7 +268,7 @@ int ProxyRow::resizeGetHeight(int newWidth) {
|
||||
void ProxyRow::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
const auto ms = getms();
|
||||
const auto ms = crl::now();
|
||||
if (!_view.deleted) {
|
||||
paintRipple(p, 0, 0, ms);
|
||||
}
|
||||
@@ -354,13 +341,13 @@ void ProxyRow::paintEvent(QPaintEvent *e) {
|
||||
top += st::normalFont->height + st::proxyRowPadding.bottom();
|
||||
}
|
||||
|
||||
void ProxyRow::paintCheck(Painter &p, TimeMs ms) {
|
||||
void ProxyRow::paintCheck(Painter &p, crl::time ms) {
|
||||
if (_progress) {
|
||||
_progress->step(ms);
|
||||
}
|
||||
const auto loading = _progress
|
||||
? _progress->computeState()
|
||||
: Ui::InfiniteRadialAnimation::State{ 0., 0, FullArcLength };
|
||||
: Ui::RadialState{ 0., 0, FullArcLength };
|
||||
const auto toggled = _toggled.current(ms, _view.selected ? 1. : 0.)
|
||||
* (1. - loading.shown);
|
||||
const auto _st = &st::defaultRadio;
|
||||
@@ -374,6 +361,7 @@ void ProxyRow::paintCheck(Painter &p, TimeMs ms) {
|
||||
|
||||
auto pen = anim::pen(_st->untoggledFg, _st->toggledFg, toggled * set);
|
||||
pen.setWidth(_st->thickness);
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
p.setPen(pen);
|
||||
p.setBrush(_st->bg);
|
||||
const auto rect = rtlrect(QRectF(left, top, _st->diameter, _st->diameter).marginsRemoved(QMarginsF(_st->thickness / 2., _st->thickness / 2., _st->thickness / 2., _st->thickness / 2.)), outerWidth);
|
||||
@@ -936,102 +924,6 @@ void ProxyBox::addLabel(
|
||||
|
||||
} // namespace
|
||||
|
||||
AutoDownloadBox::AutoDownloadBox(QWidget *parent) {
|
||||
}
|
||||
|
||||
void AutoDownloadBox::prepare() {
|
||||
setupContent();
|
||||
}
|
||||
|
||||
void AutoDownloadBox::setupContent() {
|
||||
using namespace Settings;
|
||||
|
||||
setTitle(langFactory(lng_media_auto_title));
|
||||
|
||||
auto wrap = object_ptr<Ui::VerticalLayout>(this);
|
||||
const auto content = wrap.data();
|
||||
setInnerWidget(object_ptr<Ui::OverrideMargins>(
|
||||
this,
|
||||
std::move(wrap)));
|
||||
|
||||
using pair = std::pair<Ui::Checkbox*, Ui::Checkbox*>;
|
||||
const auto pairValue = [](pair checkboxes) {
|
||||
return (checkboxes.first->checked() ? 0 : dbiadNoPrivate)
|
||||
| (checkboxes.second->checked() ? 0 : dbiadNoGroups);
|
||||
};
|
||||
const auto enabledSomething = [](int32 oldValue, int32 newValue) {
|
||||
return (uint32(oldValue) & ~uint32(newValue)) != 0;
|
||||
};
|
||||
const auto addCheckbox = [&](int32 value, DBIAutoDownloadFlags flag) {
|
||||
const auto label = (flag == dbiadNoPrivate)
|
||||
? lng_media_auto_private_chats
|
||||
: lng_media_auto_groups;
|
||||
return content->add(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
content,
|
||||
lang(label),
|
||||
!(value & flag),
|
||||
st::settingsSendType),
|
||||
st::settingsSendTypePadding);
|
||||
};
|
||||
const auto addPair = [&](int32 value) {
|
||||
const auto first = addCheckbox(value, dbiadNoPrivate);
|
||||
const auto second = addCheckbox(value, dbiadNoGroups);
|
||||
return pair(first, second);
|
||||
};
|
||||
|
||||
AddSubsectionTitle(content, lng_media_photo_title);
|
||||
const auto photo = addPair(cAutoDownloadPhoto());
|
||||
AddSkip(content);
|
||||
|
||||
AddSkip(content);
|
||||
AddSubsectionTitle(content, lng_media_audio_title);
|
||||
const auto audio = addPair(cAutoDownloadAudio());
|
||||
AddSkip(content);
|
||||
|
||||
AddSkip(content);
|
||||
AddSubsectionTitle(content, lng_media_gif_title);
|
||||
const auto gif = addPair(cAutoDownloadGif());
|
||||
AddSkip(content);
|
||||
|
||||
addButton(langFactory(lng_connection_save), [=] {
|
||||
const auto photoValue = pairValue(photo);
|
||||
const auto audioValue = pairValue(audio);
|
||||
const auto gifValue = pairValue(gif);
|
||||
const auto photosEnabled = enabledSomething(
|
||||
cAutoDownloadPhoto(),
|
||||
photoValue);
|
||||
const auto audioEnabled = enabledSomething(
|
||||
cAutoDownloadAudio(),
|
||||
audioValue);
|
||||
const auto gifEnabled = enabledSomething(
|
||||
cAutoDownloadGif(),
|
||||
gifValue);
|
||||
const auto photosChanged = (cAutoDownloadPhoto() != photoValue);
|
||||
const auto documentsChanged = (cAutoDownloadAudio() != audioValue)
|
||||
|| (cAutoDownloadGif() != gifValue);
|
||||
cSetAutoDownloadAudio(audioValue);
|
||||
cSetAutoDownloadGif(gifValue);
|
||||
cSetAutoDownloadPhoto(photoValue);
|
||||
if (photosChanged || documentsChanged) {
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
if (photosEnabled) {
|
||||
Auth().data().photoLoadSettingsChanged();
|
||||
}
|
||||
if (audioEnabled) {
|
||||
Auth().data().voiceLoadSettingsChanged();
|
||||
}
|
||||
if (gifEnabled) {
|
||||
Auth().data().animationLoadSettingsChanged();
|
||||
}
|
||||
closeBox();
|
||||
});
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
|
||||
setDimensionsToContent(st::boxWideWidth, content);
|
||||
}
|
||||
|
||||
ProxiesBoxController::ProxiesBoxController()
|
||||
: _saveTimer([] { Local::writeSettings(); }) {
|
||||
_list = ranges::view::all(
|
||||
@@ -1083,7 +975,7 @@ void ProxiesBoxController::ShowApplyConfirmation(
|
||||
if (ranges::find(proxies, proxy) == end(proxies)) {
|
||||
proxies.push_back(proxy);
|
||||
}
|
||||
Messenger::Instance().setCurrentProxy(
|
||||
Core::App().setCurrentProxy(
|
||||
proxy,
|
||||
ProxyData::Settings::Enabled);
|
||||
Local::writeSettings();
|
||||
@@ -1106,7 +998,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
|
||||
const auto type = (item.data.type == Type::Http)
|
||||
? Variants::Http
|
||||
: Variants::Tcp;
|
||||
const auto mtproto = Messenger::Instance().mtp();
|
||||
const auto mtproto = Core::App().mtp();
|
||||
const auto dcId = mtproto->mainDcId();
|
||||
|
||||
item.state = ItemState::Checking;
|
||||
@@ -1248,7 +1140,7 @@ void ProxiesBoxController::applyItem(int id) {
|
||||
|
||||
auto j = findByProxy(Global::SelectedProxy());
|
||||
|
||||
Messenger::Instance().setCurrentProxy(
|
||||
Core::App().setCurrentProxy(
|
||||
item->data,
|
||||
ProxyData::Settings::Enabled);
|
||||
saveDelayed();
|
||||
@@ -1271,7 +1163,7 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
|
||||
_lastSelectedProxy = base::take(Global::RefSelectedProxy());
|
||||
if (Global::ProxySettings() == ProxyData::Settings::Enabled) {
|
||||
_lastSelectedProxyUsed = true;
|
||||
Messenger::Instance().setCurrentProxy(
|
||||
Core::App().setCurrentProxy(
|
||||
ProxyData(),
|
||||
ProxyData::Settings::System);
|
||||
saveDelayed();
|
||||
@@ -1296,7 +1188,7 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
|
||||
Assert(Global::ProxySettings() != ProxyData::Settings::Enabled);
|
||||
|
||||
if (base::take(_lastSelectedProxyUsed)) {
|
||||
Messenger::Instance().setCurrentProxy(
|
||||
Core::App().setCurrentProxy(
|
||||
base::take(_lastSelectedProxy),
|
||||
ProxyData::Settings::Enabled);
|
||||
} else {
|
||||
@@ -1401,9 +1293,7 @@ bool ProxiesBoxController::setProxySettings(ProxyData::Settings value) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Messenger::Instance().setCurrentProxy(
|
||||
Global::SelectedProxy(),
|
||||
value);
|
||||
Core::App().setCurrentProxy(Global::SelectedProxy(), value);
|
||||
saveDelayed();
|
||||
return true;
|
||||
}
|
||||
@@ -1491,7 +1381,7 @@ void ProxiesBoxController::share(const ProxyData &proxy) {
|
||||
? "&pass=" + qthelp::url_encode(proxy.password) : "")
|
||||
+ ((proxy.type == Type::Mtproto && !proxy.password.isEmpty())
|
||||
? "&secret=" + proxy.password : "");
|
||||
Application::clipboard()->setText(link);
|
||||
QApplication::clipboard()->setText(link);
|
||||
Ui::Toast::Show(lang(lng_username_copied));
|
||||
}
|
||||
|
||||
|
||||
@@ -22,18 +22,6 @@ template <typename Enum>
|
||||
class Radioenum;
|
||||
} // namespace Ui
|
||||
|
||||
class AutoDownloadBox : public BoxContent {
|
||||
public:
|
||||
AutoDownloadBox(QWidget *parent);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
void setupContent();
|
||||
|
||||
};
|
||||
|
||||
class ProxiesBoxController : public base::Subscriber {
|
||||
public:
|
||||
using Type = ProxyData::Type;
|
||||
|
||||
731
Telegram/SourceFiles/boxes/create_poll_box.cpp
Normal file
@@ -0,0 +1,731 @@
|
||||
/*
|
||||
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/create_poll_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "core/event_filter.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "base/unique_qptr.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kQuestionLimit = 255;
|
||||
constexpr auto kMaxOptionsCount = PollData::kMaxOptions;
|
||||
constexpr auto kOptionLimit = 100;
|
||||
constexpr auto kWarnQuestionLimit = 80;
|
||||
constexpr auto kWarnOptionLimit = 30;
|
||||
constexpr auto kErrorLimit = 99;
|
||||
|
||||
class Options {
|
||||
public:
|
||||
Options(
|
||||
not_null<QWidget*> outer,
|
||||
not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
[[nodiscard]] bool isValid() const;
|
||||
[[nodiscard]] rpl::producer<bool> isValidChanged() const;
|
||||
[[nodiscard]] std::vector<PollAnswer> toPollAnswers() const;
|
||||
void focusFirst();
|
||||
|
||||
[[nodiscard]] rpl::producer<int> usedCount() const;
|
||||
[[nodiscard]] rpl::producer<not_null<QWidget*>> scrollToWidget() const;
|
||||
[[nodiscard]] rpl::producer<> backspaceInFront() const;
|
||||
|
||||
private:
|
||||
class Option {
|
||||
public:
|
||||
static Option Create(
|
||||
not_null<QWidget*> outer,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
int position);
|
||||
|
||||
void toggleRemoveAlways(bool toggled);
|
||||
|
||||
void show(anim::type animated);
|
||||
void destroy(FnMut<void()> done);
|
||||
|
||||
//[[nodisacrd]] bool hasShadow() const;
|
||||
//void destroyShadow();
|
||||
|
||||
[[nodiscard]] bool isEmpty() const;
|
||||
[[nodiscard]] bool isGood() const;
|
||||
[[nodiscard]] bool isTooLong() const;
|
||||
[[nodiscard]] bool hasFocus() const;
|
||||
void setFocus() const;
|
||||
void clearValue();
|
||||
|
||||
void setPlaceholder() const;
|
||||
void removePlaceholder() const;
|
||||
|
||||
not_null<Ui::InputField*> field() const;
|
||||
|
||||
[[nodiscard]] PollAnswer toPollAnswer(int index) const;
|
||||
|
||||
[[nodiscard]] rpl::producer<Qt::MouseButton> removeClicks() const;
|
||||
|
||||
inline bool operator<(const Option &other) const {
|
||||
return field() < other.field();
|
||||
}
|
||||
|
||||
friend inline bool operator<(
|
||||
const Option &option,
|
||||
Ui::InputField *field) {
|
||||
return option.field() < field;
|
||||
}
|
||||
friend inline bool operator<(
|
||||
Ui::InputField *field,
|
||||
const Option &option) {
|
||||
return field < option.field();
|
||||
}
|
||||
|
||||
private:
|
||||
Option() = default;
|
||||
|
||||
void createShadow();
|
||||
void createRemove();
|
||||
void createWarning();
|
||||
|
||||
base::unique_qptr<Ui::SlideWrap<Ui::InputField>> _field;
|
||||
base::unique_qptr<Ui::PlainShadow> _shadow;
|
||||
base::unique_qptr<Ui::CrossButton> _remove;
|
||||
rpl::variable<bool> *_removeAlways = nullptr;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] bool full() const;
|
||||
//[[nodiscard]] bool correctShadows() const;
|
||||
//void fixShadows();
|
||||
void removeEmptyTail();
|
||||
void addEmptyOption();
|
||||
void checkLastOption();
|
||||
void validateState();
|
||||
void fixAfterErase();
|
||||
void destroy(Option &&option);
|
||||
void removeDestroyed(not_null<Ui::InputField*> field);
|
||||
int findField(not_null<Ui::InputField*> field) const;
|
||||
|
||||
not_null<QWidget*> _outer;
|
||||
not_null<Ui::VerticalLayout*> _container;
|
||||
int _position = 0;
|
||||
std::vector<Option> _list;
|
||||
std::set<Option, std::less<>> _destroyed;
|
||||
rpl::variable<bool> _valid = false;
|
||||
rpl::variable<int> _usedCount = 0;
|
||||
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
|
||||
rpl::event_stream<> _backspaceInFront;
|
||||
|
||||
};
|
||||
|
||||
void InitField(
|
||||
not_null<QWidget*> container,
|
||||
not_null<Ui::InputField*> field) {
|
||||
field->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
field->setInstantReplacesEnabled(Global::ReplaceEmojiValue());
|
||||
Ui::Emoji::SuggestionsController::Init(container, field);
|
||||
}
|
||||
|
||||
not_null<Ui::FlatLabel*> CreateWarningLabel(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Ui::InputField*> field,
|
||||
int valueLimit,
|
||||
int warnLimit) {
|
||||
const auto result = Ui::CreateChild<Ui::FlatLabel>(
|
||||
parent.get(),
|
||||
QString(),
|
||||
Ui::FlatLabel::InitType::Simple,
|
||||
st::createPollWarning);
|
||||
result->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
QObject::connect(field, &Ui::InputField::changed, [=] {
|
||||
Ui::PostponeCall(crl::guard(field, [=] {
|
||||
const auto length = field->getLastText().size();
|
||||
const auto value = valueLimit - length;
|
||||
const auto shown = (value < warnLimit)
|
||||
&& (field->height() > st::createPollOptionField.heightMin);
|
||||
result->setRichText((value >= 0)
|
||||
? QString::number(value)
|
||||
: textcmdLink(1, QString::number(value)));
|
||||
result->setVisible(shown);
|
||||
}));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void FocusAtEnd(not_null<Ui::InputField*> field) {
|
||||
field->setFocus();
|
||||
field->setCursorPosition(field->getLastText().size());
|
||||
field->ensureCursorVisible();
|
||||
}
|
||||
|
||||
Options::Option Options::Option::Create(
|
||||
not_null<QWidget*> outer,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
int position) {
|
||||
auto result = Option();
|
||||
const auto field = container->insert(
|
||||
position,
|
||||
object_ptr<Ui::SlideWrap<Ui::InputField>>(
|
||||
container,
|
||||
object_ptr<Ui::InputField>(
|
||||
container,
|
||||
st::createPollOptionField,
|
||||
langFactory(lng_polls_create_option_add))));
|
||||
InitField(outer, field->entity());
|
||||
field->entity()->setMaxLength(kOptionLimit + kErrorLimit);
|
||||
result._field.reset(field);
|
||||
|
||||
result.createShadow();
|
||||
result.createRemove();
|
||||
result.createWarning();
|
||||
return result;
|
||||
}
|
||||
|
||||
//bool Options::Option::hasShadow() const {
|
||||
// return (_shadow != nullptr);
|
||||
//}
|
||||
|
||||
void Options::Option::createShadow() {
|
||||
Expects(_field != nullptr);
|
||||
|
||||
if (_shadow) {
|
||||
return;
|
||||
}
|
||||
const auto value = Ui::CreateChild<Ui::PlainShadow>(field().get());
|
||||
value->show();
|
||||
field()->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
const auto left = st::createPollFieldPadding.left();
|
||||
value->setGeometry(
|
||||
left,
|
||||
size.height() - st::lineWidth,
|
||||
size.width() - left,
|
||||
st::lineWidth);
|
||||
}, value->lifetime());
|
||||
_shadow.reset(value);
|
||||
}
|
||||
|
||||
//void Options::Option::destroyShadow() {
|
||||
// _shadow = nullptr;
|
||||
//}
|
||||
|
||||
void Options::Option::createRemove() {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
const auto field = this->field();
|
||||
auto &lifetime = field->lifetime();
|
||||
|
||||
const auto remove = Ui::CreateChild<Ui::CrossButton>(
|
||||
field.get(),
|
||||
st::createPollOptionRemove);
|
||||
remove->hide(anim::type::instant);
|
||||
|
||||
const auto toggle = lifetime.make_state<rpl::variable<bool>>(false);
|
||||
_removeAlways = lifetime.make_state<rpl::variable<bool>>(false);
|
||||
|
||||
QObject::connect(field, &Ui::InputField::changed, [=] {
|
||||
// Don't capture 'this'! Because Option is a value type.
|
||||
*toggle = !field->getLastText().isEmpty();
|
||||
});
|
||||
rpl::combine(
|
||||
toggle->value(),
|
||||
_removeAlways->value(),
|
||||
_1 || _2
|
||||
) | rpl::start_with_next([=](bool shown) {
|
||||
remove->toggle(shown, anim::type::normal);
|
||||
}, remove->lifetime());
|
||||
|
||||
field->widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
remove->moveToRight(
|
||||
st::createPollOptionRemovePosition.x(),
|
||||
st::createPollOptionRemovePosition.y(),
|
||||
width);
|
||||
}, remove->lifetime());
|
||||
|
||||
_remove.reset(remove);
|
||||
}
|
||||
|
||||
void Options::Option::createWarning() {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
const auto field = this->field();
|
||||
const auto warning = CreateWarningLabel(
|
||||
field,
|
||||
field,
|
||||
kOptionLimit,
|
||||
kWarnOptionLimit);
|
||||
rpl::combine(
|
||||
field->sizeValue(),
|
||||
warning->sizeValue()
|
||||
) | rpl::start_with_next([=](QSize size, QSize label) {
|
||||
warning->moveToLeft(
|
||||
(size.width()
|
||||
- label.width()
|
||||
- st::createPollWarningPosition.x()),
|
||||
(size.height()
|
||||
- label.height()
|
||||
- st::createPollWarningPosition.y()),
|
||||
size.width());
|
||||
}, warning->lifetime());
|
||||
}
|
||||
|
||||
bool Options::Option::isEmpty() const {
|
||||
return field()->getLastText().trimmed().isEmpty();
|
||||
}
|
||||
|
||||
bool Options::Option::isGood() const {
|
||||
return !field()->getLastText().trimmed().isEmpty() && !isTooLong();
|
||||
}
|
||||
|
||||
bool Options::Option::isTooLong() const {
|
||||
return (field()->getLastText().size() > kOptionLimit);
|
||||
}
|
||||
|
||||
bool Options::Option::hasFocus() const {
|
||||
return field()->hasFocus();
|
||||
}
|
||||
|
||||
void Options::Option::setFocus() const {
|
||||
FocusAtEnd(field());
|
||||
}
|
||||
|
||||
void Options::Option::clearValue() {
|
||||
field()->setText(QString());
|
||||
}
|
||||
|
||||
void Options::Option::setPlaceholder() const {
|
||||
field()->setPlaceholder(langFactory(lng_polls_create_option_add));
|
||||
}
|
||||
|
||||
void Options::Option::toggleRemoveAlways(bool toggled) {
|
||||
*_removeAlways = toggled;
|
||||
}
|
||||
|
||||
not_null<Ui::InputField*> Options::Option::field() const {
|
||||
return _field->entity();
|
||||
}
|
||||
|
||||
void Options::Option::removePlaceholder() const {
|
||||
field()->setPlaceholder(nullptr);
|
||||
}
|
||||
|
||||
PollAnswer Options::Option::toPollAnswer(int index) const {
|
||||
Expects(index >= 0 && index < kMaxOptionsCount);
|
||||
|
||||
return PollAnswer{
|
||||
field()->getLastText().trimmed(),
|
||||
QByteArray(1, ('0' + index))
|
||||
};
|
||||
}
|
||||
|
||||
rpl::producer<Qt::MouseButton> Options::Option::removeClicks() const {
|
||||
return _remove->clicks();
|
||||
}
|
||||
|
||||
Options::Options(
|
||||
not_null<QWidget*> outer,
|
||||
not_null<Ui::VerticalLayout*> container)
|
||||
: _outer(outer)
|
||||
, _container(container)
|
||||
, _position(_container->count()) {
|
||||
checkLastOption();
|
||||
}
|
||||
|
||||
bool Options::full() const {
|
||||
return (_list.size() == kMaxOptionsCount);
|
||||
}
|
||||
|
||||
bool Options::isValid() const {
|
||||
return _valid.current();
|
||||
}
|
||||
|
||||
rpl::producer<bool> Options::isValidChanged() const {
|
||||
return _valid.changes();
|
||||
}
|
||||
|
||||
rpl::producer<int> Options::usedCount() const {
|
||||
return _usedCount.value();
|
||||
}
|
||||
|
||||
rpl::producer<not_null<QWidget*>> Options::scrollToWidget() const {
|
||||
return _scrollToWidget.events();
|
||||
}
|
||||
|
||||
rpl::producer<> Options::backspaceInFront() const {
|
||||
return _backspaceInFront.events();
|
||||
}
|
||||
|
||||
void Options::Option::show(anim::type animated) {
|
||||
_field->hide(anim::type::instant);
|
||||
_field->show(animated);
|
||||
}
|
||||
|
||||
void Options::Option::destroy(FnMut<void()> done) {
|
||||
if (anim::Disabled() || _field->isHidden()) {
|
||||
Ui::PostponeCall(std::move(done));
|
||||
return;
|
||||
}
|
||||
_field->hide(anim::type::normal);
|
||||
App::CallDelayed(
|
||||
st::slideWrapDuration * 2,
|
||||
_field.get(),
|
||||
std::move(done));
|
||||
}
|
||||
|
||||
std::vector<PollAnswer> Options::toPollAnswers() const {
|
||||
auto result = std::vector<PollAnswer>();
|
||||
result.reserve(_list.size());
|
||||
auto counter = int(0);
|
||||
const auto makeAnswer = [&](const Option &option) {
|
||||
return option.toPollAnswer(counter++);
|
||||
};
|
||||
ranges::copy(
|
||||
_list
|
||||
| ranges::view::filter(&Option::isGood)
|
||||
| ranges::view::transform(makeAnswer),
|
||||
ranges::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
void Options::focusFirst() {
|
||||
Expects(!_list.empty());
|
||||
|
||||
_list.front().setFocus();
|
||||
}
|
||||
//
|
||||
//bool Options::correctShadows() const {
|
||||
// // Last one should be without shadow if all options were used.
|
||||
// const auto noShadow = ranges::find(
|
||||
// _list,
|
||||
// true,
|
||||
// ranges::not_fn(&Option::hasShadow));
|
||||
// return (noShadow == end(_list) - (full() ? 1 : 0));
|
||||
//}
|
||||
//
|
||||
//void Options::fixShadows() {
|
||||
// if (correctShadows()) {
|
||||
// return;
|
||||
// }
|
||||
// for (auto &option : _list) {
|
||||
// option.createShadow();
|
||||
// }
|
||||
// if (full()) {
|
||||
// _list.back().destroyShadow();
|
||||
// }
|
||||
//}
|
||||
|
||||
void Options::removeEmptyTail() {
|
||||
// Only one option at the end of options list can be empty.
|
||||
// Remove all other trailing empty options.
|
||||
// Only last empty and previous option have non-empty placeholders.
|
||||
const auto focused = ranges::find_if(
|
||||
_list,
|
||||
&Option::hasFocus);
|
||||
const auto end = _list.end();
|
||||
const auto reversed = ranges::view::reverse(_list);
|
||||
const auto emptyItem = ranges::find_if(
|
||||
reversed,
|
||||
ranges::not_fn(&Option::isEmpty)).base();
|
||||
const auto focusLast = (focused > emptyItem) && (focused < end);
|
||||
if (emptyItem == end) {
|
||||
return;
|
||||
}
|
||||
if (focusLast) {
|
||||
emptyItem->setFocus();
|
||||
}
|
||||
for (auto i = emptyItem + 1; i != end; ++i) {
|
||||
destroy(std::move(*i));
|
||||
}
|
||||
_list.erase(emptyItem + 1, end);
|
||||
fixAfterErase();
|
||||
}
|
||||
|
||||
void Options::destroy(Option &&option) {
|
||||
const auto field = option.field();
|
||||
option.destroy([=] { removeDestroyed(field); });
|
||||
_destroyed.emplace(std::move(option));
|
||||
}
|
||||
|
||||
void Options::fixAfterErase() {
|
||||
Expects(!_list.empty());
|
||||
|
||||
const auto last = _list.end() - 1;
|
||||
last->setPlaceholder();
|
||||
last->toggleRemoveAlways(false);
|
||||
if (last != begin(_list)) {
|
||||
(last - 1)->setPlaceholder();
|
||||
(last - 1)->toggleRemoveAlways(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Options::addEmptyOption() {
|
||||
if (full()) {
|
||||
return;
|
||||
} else if (!_list.empty() && _list.back().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (_list.size() > 1) {
|
||||
(_list.end() - 2)->removePlaceholder();
|
||||
(_list.end() - 2)->toggleRemoveAlways(true);
|
||||
}
|
||||
_list.push_back(Option::Create(
|
||||
_outer,
|
||||
_container,
|
||||
_position + _list.size() + _destroyed.size()));
|
||||
const auto field = _list.back().field();
|
||||
QObject::connect(field, &Ui::InputField::submitted, [=] {
|
||||
const auto index = findField(field);
|
||||
if (_list[index].isGood() && index + 1 < _list.size()) {
|
||||
_list[index + 1].setFocus();
|
||||
}
|
||||
});
|
||||
QObject::connect(field, &Ui::InputField::changed, [=] {
|
||||
Ui::PostponeCall(crl::guard(field, [=] {
|
||||
validateState();
|
||||
}));
|
||||
});
|
||||
QObject::connect(field, &Ui::InputField::focused, [=] {
|
||||
_scrollToWidget.fire_copy(field);
|
||||
});
|
||||
Core::InstallEventFilter(field, [=](not_null<QEvent*> event) {
|
||||
if (event->type() != QEvent::KeyPress
|
||||
|| !field->getLastText().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const auto key = static_cast<QKeyEvent*>(event.get())->key();
|
||||
if (key != Qt::Key_Backspace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto index = findField(field);
|
||||
if (index > 0) {
|
||||
_list[index - 1].setFocus();
|
||||
} else {
|
||||
_backspaceInFront.fire({});
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
_list.back().removeClicks(
|
||||
) | rpl::start_with_next([=] {
|
||||
Ui::PostponeCall(crl::guard(field, [=] {
|
||||
Expects(!_list.empty());
|
||||
|
||||
const auto item = begin(_list) + findField(field);
|
||||
if (item == _list.end() - 1) {
|
||||
item->clearValue();
|
||||
return;
|
||||
}
|
||||
if (item->hasFocus()) {
|
||||
(item + 1)->setFocus();
|
||||
}
|
||||
destroy(std::move(*item));
|
||||
_list.erase(item);
|
||||
fixAfterErase();
|
||||
validateState();
|
||||
}));
|
||||
}, field->lifetime());
|
||||
|
||||
_list.back().show((_list.size() == 1)
|
||||
? anim::type::instant
|
||||
: anim::type::normal);
|
||||
//fixShadows();
|
||||
}
|
||||
|
||||
void Options::removeDestroyed(not_null<Ui::InputField*> field) {
|
||||
_destroyed.erase(_destroyed.find(field));
|
||||
}
|
||||
|
||||
void Options::validateState() {
|
||||
checkLastOption();
|
||||
_valid = (ranges::count_if(_list, &Option::isGood) > 1)
|
||||
&& (ranges::find_if(_list, &Option::isTooLong) == end(_list));
|
||||
const auto lastEmpty = !_list.empty() && _list.back().isEmpty();
|
||||
_usedCount = _list.size() - (lastEmpty ? 1 : 0);
|
||||
}
|
||||
|
||||
int Options::findField(not_null<Ui::InputField*> field) const {
|
||||
const auto result = ranges::find(
|
||||
_list,
|
||||
field,
|
||||
&Option::field) - begin(_list);
|
||||
|
||||
Ensures(result >= 0 && result < _list.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
void Options::checkLastOption() {
|
||||
removeEmptyTail();
|
||||
addEmptyOption();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CreatePollBox::CreatePollBox(QWidget*) {
|
||||
}
|
||||
|
||||
rpl::producer<PollData> CreatePollBox::submitRequests() const {
|
||||
return _submitRequests.events();
|
||||
}
|
||||
|
||||
void CreatePollBox::setInnerFocus() {
|
||||
_setInnerFocus();
|
||||
}
|
||||
|
||||
void CreatePollBox::submitFailed(const QString &error) {
|
||||
Ui::Toast::Show(error);
|
||||
}
|
||||
|
||||
not_null<Ui::InputField*> CreatePollBox::setupQuestion(
|
||||
not_null<Ui::VerticalLayout*> container) {
|
||||
using namespace Settings;
|
||||
|
||||
AddSubsectionTitle(container, lng_polls_create_question);
|
||||
const auto question = container->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
container,
|
||||
st::createPollField,
|
||||
Ui::InputField::Mode::MultiLine,
|
||||
langFactory(lng_polls_create_question_placeholder)),
|
||||
st::createPollFieldPadding);
|
||||
InitField(getDelegate()->outerContainer(), question);
|
||||
question->setMaxLength(kQuestionLimit + kErrorLimit);
|
||||
|
||||
const auto warning = CreateWarningLabel(
|
||||
container,
|
||||
question,
|
||||
kQuestionLimit,
|
||||
kWarnQuestionLimit);
|
||||
rpl::combine(
|
||||
question->geometryValue(),
|
||||
warning->sizeValue()
|
||||
) | rpl::start_with_next([=](QRect geometry, QSize label) {
|
||||
warning->moveToLeft(
|
||||
(container->width()
|
||||
- label.width()
|
||||
- st::createPollWarningPosition.x()),
|
||||
(geometry.y()
|
||||
- st::createPollFieldPadding.top()
|
||||
- st::settingsSubsectionTitlePadding.bottom()
|
||||
- st::settingsSubsectionTitle.style.font->height
|
||||
+ st::settingsSubsectionTitle.style.font->ascent
|
||||
- st::createPollWarning.style.font->ascent),
|
||||
geometry.width());
|
||||
}, warning->lifetime());
|
||||
|
||||
return question;
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
||||
using namespace Settings;
|
||||
|
||||
const auto id = rand_value<uint64>();
|
||||
const auto valid = lifetime().make_state<rpl::event_stream<bool>>();
|
||||
|
||||
auto result = object_ptr<Ui::VerticalLayout>(this);
|
||||
const auto container = result.data();
|
||||
|
||||
const auto question = setupQuestion(container);
|
||||
AddDivider(container);
|
||||
AddSkip(container);
|
||||
AddSubsectionTitle(container, lng_polls_create_options);
|
||||
const auto options = lifetime().make_state<Options>(
|
||||
getDelegate()->outerContainer(),
|
||||
container);
|
||||
auto limit = options->usedCount() | rpl::after_next([=](int count) {
|
||||
setCloseByEscape(!count);
|
||||
setCloseByOutsideClick(!count);
|
||||
}) | rpl::map([=](int count) {
|
||||
return (count < kMaxOptionsCount)
|
||||
? lng_polls_create_limit(lt_count, kMaxOptionsCount - count)
|
||||
: lang(lng_polls_create_maximum);
|
||||
}) | rpl::after_next([=] {
|
||||
container->resizeToWidth(container->widthNoMargins());
|
||||
});
|
||||
container->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
std::move(limit),
|
||||
st::createPollLimitLabel),
|
||||
st::createPollLimitPadding);
|
||||
|
||||
const auto isValidQuestion = [=] {
|
||||
const auto text = question->getLastText().trimmed();
|
||||
return !text.isEmpty() && (text.size() <= kQuestionLimit);
|
||||
};
|
||||
|
||||
connect(question, &Ui::InputField::submitted, [=] {
|
||||
if (isValidQuestion()) {
|
||||
options->focusFirst();
|
||||
}
|
||||
});
|
||||
|
||||
_setInnerFocus = [=] {
|
||||
question->setFocusFast();
|
||||
};
|
||||
|
||||
const auto collectResult = [=] {
|
||||
auto result = PollData(id);
|
||||
result.question = question->getLastText().trimmed();
|
||||
result.answers = options->toPollAnswers();
|
||||
return result;
|
||||
};
|
||||
const auto updateValid = [=] {
|
||||
valid->fire(isValidQuestion() && options->isValid());
|
||||
};
|
||||
connect(question, &Ui::InputField::changed, [=] {
|
||||
updateValid();
|
||||
});
|
||||
valid->events_starting_with(
|
||||
false
|
||||
) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool valid) {
|
||||
clearButtons();
|
||||
if (valid) {
|
||||
addButton(
|
||||
langFactory(lng_polls_create_button),
|
||||
[=] { _submitRequests.fire(collectResult()); });
|
||||
}
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
}, lifetime());
|
||||
|
||||
options->isValidChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateValid();
|
||||
}, lifetime());
|
||||
|
||||
options->scrollToWidget(
|
||||
) | rpl::start_with_next([=](not_null<QWidget*> widget) {
|
||||
scrollToWidget(widget);
|
||||
}, lifetime());
|
||||
|
||||
options->backspaceInFront(
|
||||
) | rpl::start_with_next([=] {
|
||||
FocusAtEnd(question);
|
||||
}, lifetime());
|
||||
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
void CreatePollBox::prepare() {
|
||||
setTitle(langFactory(lng_polls_create_title));
|
||||
|
||||
const auto inner = setInnerWidget(setupContent());
|
||||
|
||||
setDimensionsToContent(st::boxWideWidth, inner);
|
||||
}
|
||||
39
Telegram/SourceFiles/boxes/create_poll_box.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
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 Ui {
|
||||
class VerticalLayout;
|
||||
} // namespace Ui
|
||||
|
||||
struct PollData;
|
||||
|
||||
class CreatePollBox : public BoxContent {
|
||||
public:
|
||||
CreatePollBox(QWidget*);
|
||||
|
||||
rpl::producer<PollData> submitRequests() const;
|
||||
void submitFailed(const QString &error);
|
||||
|
||||
void setInnerFocus() override;
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
object_ptr<Ui::RpWidget> setupContent();
|
||||
not_null<Ui::InputField*> setupQuestion(
|
||||
not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
Fn<void()> _setInnerFocus;
|
||||
Fn<rpl::producer<bool>()> _dataIsValidValue;
|
||||
rpl::event_stream<PollData> _submitRequests;
|
||||
|
||||
};
|
||||
@@ -11,12 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "media/media_clip_reader.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "core/event_filter.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
@@ -41,18 +42,22 @@ EditCaptionBox::EditCaptionBox(
|
||||
Expects(item->media()->allowsEditCaption());
|
||||
|
||||
QSize dimensions;
|
||||
ImagePtr image;
|
||||
auto image = (Image*)nullptr;
|
||||
DocumentData *doc = nullptr;
|
||||
|
||||
const auto media = item->media();
|
||||
if (const auto photo = media->photo()) {
|
||||
_photo = true;
|
||||
dimensions = QSize(photo->full->width(), photo->full->height());
|
||||
image = photo->full;
|
||||
dimensions = QSize(photo->width(), photo->height());
|
||||
image = photo->large();
|
||||
} else if (const auto document = media->document()) {
|
||||
dimensions = document->dimensions;
|
||||
image = document->thumb;
|
||||
image = document->thumbnail();
|
||||
dimensions = image
|
||||
? image->size()
|
||||
: document->dimensions;
|
||||
if (document->isAnimation()) {
|
||||
_gifw = document->dimensions.width();
|
||||
_gifh = document->dimensions.height();
|
||||
_animated = true;
|
||||
} else if (document->isVideoFile()) {
|
||||
_animated = true;
|
||||
@@ -67,11 +72,11 @@ EditCaptionBox::EditCaptionBox(
|
||||
ConvertEntitiesToTextTags(original.entities)
|
||||
};
|
||||
|
||||
if (!_animated && (dimensions.isEmpty() || doc || image->isNull())) {
|
||||
if (image->isNull()) {
|
||||
if (!_animated && (dimensions.isEmpty() || doc || !image)) {
|
||||
if (!image) {
|
||||
_thumbw = 0;
|
||||
} else {
|
||||
int32 tw = image->width(), th = image->height();
|
||||
const auto tw = image->width(), th = image->height();
|
||||
if (tw > th) {
|
||||
_thumbw = (tw * st::msgFileThumbSize) / th;
|
||||
} else {
|
||||
@@ -79,7 +84,7 @@ EditCaptionBox::EditCaptionBox(
|
||||
}
|
||||
_thumbnailImage = image;
|
||||
_refreshThumbnail = [=] {
|
||||
auto options = Images::Option::Smooth
|
||||
const auto options = Images::Option::Smooth
|
||||
| Images::Option::RoundedSmall
|
||||
| Images::Option::RoundedTopLeft
|
||||
| Images::Option::RoundedTopRight
|
||||
@@ -96,7 +101,7 @@ EditCaptionBox::EditCaptionBox(
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
auto nameString = doc->isVoiceMessage()
|
||||
const auto nameString = doc->isVoiceMessage()
|
||||
? lang(lng_media_audio)
|
||||
: doc->composeNameString();
|
||||
_name.setText(
|
||||
@@ -104,7 +109,7 @@ EditCaptionBox::EditCaptionBox(
|
||||
nameString,
|
||||
Ui::NameTextOptions());
|
||||
_status = formatSizeText(doc->size);
|
||||
_statusw = qMax(
|
||||
_statusw = std::max(
|
||||
_name.maxWidth(),
|
||||
st::normalFont->width(_status));
|
||||
_isImage = doc->isImage();
|
||||
@@ -114,12 +119,15 @@ EditCaptionBox::EditCaptionBox(
|
||||
_refreshThumbnail();
|
||||
}
|
||||
} else {
|
||||
int32 maxW = 0, maxH = 0;
|
||||
if (!image) {
|
||||
image = Image::BlankMedia();
|
||||
}
|
||||
auto maxW = 0, maxH = 0;
|
||||
const auto limitW = st::sendMediaPreviewSize;
|
||||
auto limitH = std::min(st::confirmMaxHeight, _gifh ? _gifh : INT_MAX);
|
||||
if (_animated) {
|
||||
int32 limitW = st::sendMediaPreviewSize;
|
||||
int32 limitH = st::confirmMaxHeight;
|
||||
maxW = qMax(dimensions.width(), 1);
|
||||
maxH = qMax(dimensions.height(), 1);
|
||||
maxW = std::max(dimensions.width(), 1);
|
||||
maxH = std::max(dimensions.height(), 1);
|
||||
if (maxW * limitH > maxH * limitW) {
|
||||
if (maxW < limitW) {
|
||||
maxH = maxH * limitW / maxW;
|
||||
@@ -160,24 +168,42 @@ EditCaptionBox::EditCaptionBox(
|
||||
}
|
||||
_refreshThumbnail();
|
||||
|
||||
int32 tw = _thumb.width(), th = _thumb.height();
|
||||
if (!tw || !th) {
|
||||
tw = th = 1;
|
||||
}
|
||||
_thumbw = st::sendMediaPreviewSize;
|
||||
if (_thumb.width() < _thumbw) {
|
||||
_thumbw = (_thumb.width() > 20) ? _thumb.width() : 20;
|
||||
}
|
||||
int32 maxthumbh = qMin(qRound(1.5 * _thumbw), int(st::confirmMaxHeight));
|
||||
_thumbh = qRound(th * float64(_thumbw) / tw);
|
||||
if (_thumbh > maxthumbh) {
|
||||
_thumbw = qRound(_thumbw * float64(maxthumbh) / _thumbh);
|
||||
_thumbh = maxthumbh;
|
||||
if (_thumbw < 10) {
|
||||
_thumbw = 10;
|
||||
const auto resizeDimensions = [&](int &thumbWidth, int &thumbHeight, int &thumbX) {
|
||||
auto tw = thumbWidth, th = thumbHeight;
|
||||
if (!tw || !th) {
|
||||
tw = th = 1;
|
||||
}
|
||||
if (thumbWidth < st::sendMediaPreviewSize) {
|
||||
thumbWidth = (thumbWidth > 20) ? thumbWidth : 20;
|
||||
} else {
|
||||
thumbWidth = st::sendMediaPreviewSize;
|
||||
}
|
||||
const auto maxThumbHeight = std::min(int(std::round(1.5 * thumbWidth)), limitH);
|
||||
thumbHeight = int(std::round(th * float64(thumbWidth) / tw));
|
||||
if (thumbHeight > maxThumbHeight) {
|
||||
thumbWidth = int(std::round(thumbWidth * float64(maxThumbHeight) / thumbHeight));
|
||||
thumbHeight = maxThumbHeight;
|
||||
if (thumbWidth < 10) {
|
||||
thumbWidth = 10;
|
||||
}
|
||||
}
|
||||
thumbX = (st::boxWideWidth - thumbWidth) / 2;
|
||||
};
|
||||
|
||||
if (doc && doc->isAnimation()) {
|
||||
resizeDimensions(_gifw, _gifh, _gifx);
|
||||
}
|
||||
limitH = std::min(st::confirmMaxHeight, _gifh ? _gifh : INT_MAX);
|
||||
|
||||
_thumbw = _thumb.width();
|
||||
_thumbh = _thumb.height();
|
||||
// If thumb's and resized gif's sizes are equal,
|
||||
// Then just take made values.
|
||||
if (_thumbw == _gifw && _thumbh == _gifh) {
|
||||
_thumbx = (st::boxWideWidth - _thumbw) / 2;
|
||||
} else {
|
||||
resizeDimensions(_thumbw, _thumbh, _thumbx);
|
||||
}
|
||||
_thumbx = (st::boxWideWidth - _thumbw) / 2;
|
||||
|
||||
const auto prepareBasicThumb = _refreshThumbnail;
|
||||
const auto scaleThumbDown = [=] {
|
||||
@@ -200,7 +226,9 @@ EditCaptionBox::EditCaptionBox(
|
||||
? _thumbnailImage->loaded()
|
||||
: true;
|
||||
subscribe(Auth().downloaderTaskFinished(), [=] {
|
||||
if (!_thumbnailImageLoaded && _thumbnailImage->loaded()) {
|
||||
if (!_thumbnailImageLoaded
|
||||
&& _thumbnailImage
|
||||
&& _thumbnailImage->loaded()) {
|
||||
_thumbnailImageLoaded = true;
|
||||
_refreshThumbnail();
|
||||
update();
|
||||
@@ -263,7 +291,7 @@ void EditCaptionBox::clipCallback(Media::Clip::Notification notification) {
|
||||
}
|
||||
|
||||
if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) {
|
||||
auto s = QSize(_thumbw, _thumbh);
|
||||
const auto s = QSize(_gifw, _gifh);
|
||||
_gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None);
|
||||
}
|
||||
|
||||
@@ -337,7 +365,7 @@ void EditCaptionBox::setupEmojiPanel() {
|
||||
void EditCaptionBox::updateBoxSize() {
|
||||
auto newHeight = st::boxPhotoPadding.top() + st::boxPhotoCaptionSkip + _field->height() + errorTopSkip() + st::normalFont->height;
|
||||
if (_photo || _animated) {
|
||||
newHeight += _thumbh;
|
||||
newHeight += std::max(_thumbh, _gifh);
|
||||
} else if (_thumbw) {
|
||||
newHeight += 0 + st::msgFileThumbSize + 0;
|
||||
} else if (_doc) {
|
||||
@@ -358,22 +386,24 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
if (_photo || _animated) {
|
||||
const auto th = std::max(_gifh, _thumbh);
|
||||
if (_thumbx > st::boxPhotoPadding.left()) {
|
||||
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), _thumbh, st::confirmBg);
|
||||
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), th, st::confirmBg);
|
||||
}
|
||||
if (_thumbx + _thumbw < width() - st::boxPhotoPadding.right()) {
|
||||
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, _thumbh, st::confirmBg);
|
||||
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, th, st::confirmBg);
|
||||
}
|
||||
if (_gifPreview && _gifPreview->started()) {
|
||||
auto s = QSize(_thumbw, _thumbh);
|
||||
auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Layer);
|
||||
auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : getms());
|
||||
p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), frame);
|
||||
const auto s = QSize(_gifw, _gifh);
|
||||
const auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Layer);
|
||||
const auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : crl::now());
|
||||
p.drawPixmap(_gifx, st::boxPhotoPadding.top(), frame);
|
||||
} else {
|
||||
p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), _thumb);
|
||||
const auto offset = _gifh ? ((_gifh - _thumbh) / 2) : 0;
|
||||
p.drawPixmap(_thumbx, st::boxPhotoPadding.top() + offset, _thumb);
|
||||
}
|
||||
if (_animated && !_gifPreview) {
|
||||
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_thumbh - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
||||
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (th - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::msgDateImgBg);
|
||||
|
||||
@@ -382,13 +412,13 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
|
||||
p.drawEllipse(inner);
|
||||
}
|
||||
|
||||
auto icon = &st::historyFileInPlay;
|
||||
const auto icon = &st::historyFileInPlay;
|
||||
icon->paintInCenter(p, inner);
|
||||
}
|
||||
} else if (_doc) {
|
||||
int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||
int32 h = _thumbw ? (0 + st::msgFileThumbSize + 0) : (0 + st::msgFileSize + 0);
|
||||
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0;
|
||||
const auto w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||
const auto h = _thumbw ? (0 + st::msgFileThumbSize + 0) : (0 + st::msgFileSize + 0);
|
||||
auto nameleft = 0, nametop = 0, nameright = 0, statustop = 0;
|
||||
if (_thumbw) {
|
||||
nameleft = 0 + st::msgFileThumbSize + st::msgFileThumbPadding.right();
|
||||
nametop = st::msgFileThumbNameTop - st::msgFileThumbPadding.top();
|
||||
@@ -400,12 +430,12 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
|
||||
nameright = 0;
|
||||
statustop = st::msgFileStatusTop - st::msgFilePadding.top();
|
||||
}
|
||||
int32 namewidth = w - nameleft - 0;
|
||||
const auto namewidth = w - nameleft - 0;
|
||||
if (namewidth > _statusw) {
|
||||
//w -= (namewidth - _statusw);
|
||||
//namewidth = _statusw;
|
||||
}
|
||||
int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top();
|
||||
const auto x = (width() - w) / 2, y = st::boxPhotoPadding.top();
|
||||
|
||||
// App::roundRect(p, x, y, w, h, st::msgInBg, MessageInCorners, &st::msgInShadow);
|
||||
|
||||
@@ -413,7 +443,7 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
|
||||
QRect rthumb(rtlrect(x + 0, y + 0, st::msgFileThumbSize, st::msgFileThumbSize, width()));
|
||||
p.drawPixmap(rthumb.topLeft(), _thumb);
|
||||
} else {
|
||||
QRect inner(rtlrect(x + 0, y + 0, st::msgFileSize, st::msgFileSize, width()));
|
||||
const QRect inner(rtlrect(x + 0, y + 0, st::msgFileSize, st::msgFileSize, width()));
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::msgFileInBg);
|
||||
|
||||
@@ -422,14 +452,14 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
|
||||
p.drawEllipse(inner);
|
||||
}
|
||||
|
||||
auto icon = &(_isAudio ? st::historyFileInPlay : _isImage ? st::historyFileInImage : st::historyFileInDocument);
|
||||
const auto icon = &(_isAudio ? st::historyFileInPlay : _isImage ? st::historyFileInImage : st::historyFileInDocument);
|
||||
icon->paintInCenter(p, inner);
|
||||
}
|
||||
p.setFont(st::semiboldFont);
|
||||
p.setPen(st::historyFileNameInFg);
|
||||
_name.drawLeftElided(p, x + nameleft, y + nametop, namewidth, width());
|
||||
|
||||
auto &status = st::mediaInFg;
|
||||
const auto &status = st::mediaInFg;
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(status);
|
||||
p.drawTextLeft(x + nameleft, y + statustop, width(), _status);
|
||||
@@ -464,7 +494,7 @@ void EditCaptionBox::setInnerFocus() {
|
||||
void EditCaptionBox::save() {
|
||||
if (_saveRequestId) return;
|
||||
|
||||
auto item = App::histItemById(_msgId);
|
||||
const auto item = App::histItemById(_msgId);
|
||||
if (!item) {
|
||||
_error = lang(lng_edit_deleted);
|
||||
update();
|
||||
@@ -499,9 +529,8 @@ void EditCaptionBox::save() {
|
||||
MTP_int(item->id),
|
||||
MTP_string(sending.text),
|
||||
MTPInputMedia(),
|
||||
MTPnullMarkup,
|
||||
sentEntities,
|
||||
MTP_inputGeoPointEmpty()),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities),
|
||||
rpcDone(&EditCaptionBox::saveDone),
|
||||
rpcFail(&EditCaptionBox::saveFail));
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ private:
|
||||
|
||||
not_null<Window::Controller*> _controller;
|
||||
FullMsgId _msgId;
|
||||
ImagePtr _thumbnailImage;
|
||||
Image *_thumbnailImage = nullptr;
|
||||
bool _thumbnailImageLoaded = false;
|
||||
Fn<void()> _refreshThumbnail;
|
||||
bool _animated = false;
|
||||
@@ -87,6 +87,10 @@ private:
|
||||
bool _isAudio = false;
|
||||
bool _isImage = false;
|
||||
|
||||
int _gifw = 0;
|
||||
int _gifh = 0;
|
||||
int _gifx = 0;
|
||||
|
||||
bool _previewCancelled = false;
|
||||
mtpRequestId _saveRequestId = 0;
|
||||
|
||||
|
||||
@@ -442,7 +442,7 @@ public:
|
||||
|
||||
protected:
|
||||
void correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) override;
|
||||
void paintAdditionalPlaceholder(Painter &p, TimeMs ms) override;
|
||||
void paintAdditionalPlaceholder(Painter &p, crl::time ms) override;
|
||||
|
||||
void wheelEvent(QWheelEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
@@ -501,7 +501,7 @@ void EditColorBox::Field::correctValue(const QString &was, int wasCursor, QStrin
|
||||
}
|
||||
}
|
||||
|
||||
void EditColorBox::Field::paintAdditionalPlaceholder(Painter &p, TimeMs ms) {
|
||||
void EditColorBox::Field::paintAdditionalPlaceholder(Painter &p, crl::time ms) {
|
||||
p.setFont(_st.font);
|
||||
p.setPen(_st.placeholderFg);
|
||||
auto inner = QRect(_st.textMargins.right(), _st.textMargins.top(), width() - 2 * _st.textMargins.right(), height() - _st.textMargins.top() - _st.textMargins.bottom());
|
||||
@@ -565,7 +565,7 @@ public:
|
||||
|
||||
protected:
|
||||
void correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) override;
|
||||
void paintAdditionalPlaceholder(Painter &p, TimeMs ms) override;
|
||||
void paintAdditionalPlaceholder(Painter &p, crl::time ms) override;
|
||||
|
||||
};
|
||||
|
||||
@@ -606,7 +606,7 @@ void EditColorBox::ResultField::correctValue(const QString &was, int wasCursor,
|
||||
}
|
||||
}
|
||||
|
||||
void EditColorBox::ResultField::paintAdditionalPlaceholder(Painter &p, TimeMs ms) {
|
||||
void EditColorBox::ResultField::paintAdditionalPlaceholder(Painter &p, crl::time ms) {
|
||||
p.setFont(_st.font);
|
||||
p.setPen(_st.placeholderFg);
|
||||
p.drawText(QRect(_st.textMargins.right(), _st.textMargins.top(), width(), height() - _st.textMargins.top() - _st.textMargins.bottom()), "#", style::al_topleft);
|
||||
|
||||
@@ -1,523 +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/edit_participant_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "boxes/calendar_box.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxRestrictDelayDays = 366;
|
||||
constexpr auto kSecondsInDay = 24 * 60 * 60;
|
||||
constexpr auto kSecondsInWeek = 7 * kSecondsInDay;
|
||||
|
||||
template <typename CheckboxesMap, typename DependenciesMap>
|
||||
void ApplyDependencies(CheckboxesMap &checkboxes, DependenciesMap &dependencies, QPointer<Ui::Checkbox> changed) {
|
||||
auto checkAndApply = [&checkboxes](auto &¤t, auto dependency, bool isChecked) {
|
||||
for (auto &&checkbox : checkboxes) {
|
||||
if ((checkbox.first & dependency) && (checkbox.second->checked() == isChecked)) {
|
||||
current->setChecked(isChecked);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto applySomeDependency = [&checkboxes, &dependencies, &changed, checkAndApply] {
|
||||
auto result = false;
|
||||
for (auto &&entry : checkboxes) {
|
||||
if (entry.second == changed) {
|
||||
continue;
|
||||
}
|
||||
auto isChecked = entry.second->checked();
|
||||
for (auto &&dependency : dependencies) {
|
||||
if (entry.first & (isChecked ? dependency.first : dependency.second)) {
|
||||
if (checkAndApply(entry.second, (isChecked ? dependency.second : dependency.first), !isChecked)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
while (true) {
|
||||
if (!applySomeDependency()) {
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class EditParticipantBox::Inner : public TWidget {
|
||||
public:
|
||||
Inner(
|
||||
QWidget *parent,
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> user,
|
||||
bool hasAdminRights);
|
||||
|
||||
template <typename Widget>
|
||||
QPointer<Widget> addControl(object_ptr<Widget> widget, QMargins margin) {
|
||||
doAddControl(std::move(widget), margin);
|
||||
return static_cast<Widget*>(_rows.back().widget.data());
|
||||
}
|
||||
|
||||
void removeControl(QPointer<TWidget> widget);
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
void doAddControl(object_ptr<TWidget> widget, QMargins margin);
|
||||
|
||||
not_null<ChannelData*> _channel;
|
||||
not_null<UserData*> _user;
|
||||
object_ptr<Ui::UserpicButton> _userPhoto;
|
||||
Text _userName;
|
||||
bool _hasAdminRights = false;
|
||||
struct Control {
|
||||
object_ptr<TWidget> widget;
|
||||
QMargins margin;
|
||||
};
|
||||
std::vector<Control> _rows;
|
||||
|
||||
};
|
||||
|
||||
EditParticipantBox::Inner::Inner(
|
||||
QWidget *parent,
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> user,
|
||||
bool hasAdminRights)
|
||||
: TWidget(parent)
|
||||
, _channel(channel)
|
||||
, _user(user)
|
||||
, _userPhoto(
|
||||
this,
|
||||
_user,
|
||||
Ui::UserpicButton::Role::Custom,
|
||||
st::rightsPhotoButton)
|
||||
, _hasAdminRights(hasAdminRights) {
|
||||
_userPhoto->setPointerCursor(false);
|
||||
_userName.setText(
|
||||
st::rightsNameStyle,
|
||||
App::peerName(_user),
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
void EditParticipantBox::Inner::removeControl(QPointer<TWidget> widget) {
|
||||
auto row = std::find_if(_rows.begin(), _rows.end(), [widget](auto &&row) {
|
||||
return (row.widget == widget);
|
||||
});
|
||||
Assert(row != _rows.end());
|
||||
row->widget.destroy();
|
||||
_rows.erase(row);
|
||||
}
|
||||
|
||||
void EditParticipantBox::Inner::doAddControl(object_ptr<TWidget> widget, QMargins margin) {
|
||||
widget->setParent(this);
|
||||
_rows.push_back({ std::move(widget), margin });
|
||||
_rows.back().widget->show();
|
||||
}
|
||||
|
||||
int EditParticipantBox::Inner::resizeGetHeight(int newWidth) {
|
||||
_userPhoto->moveToLeft(st::rightsPhotoMargin.left(), st::rightsPhotoMargin.top());
|
||||
auto newHeight = st::rightsPhotoMargin.top()
|
||||
+ st::rightsPhotoButton.size.height()
|
||||
+ st::rightsPhotoMargin.bottom();
|
||||
for (auto &&row : _rows) {
|
||||
auto rowWidth = newWidth - row.margin.left() - row.margin.right();
|
||||
newHeight += row.margin.top();
|
||||
row.widget->resizeToNaturalWidth(rowWidth);
|
||||
row.widget->moveToLeft(row.margin.left(), newHeight);
|
||||
newHeight += row.widget->heightNoMargins() + row.margin.bottom();
|
||||
}
|
||||
return newHeight;
|
||||
}
|
||||
|
||||
void EditParticipantBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
p.fillRect(e->rect(), st::boxBg);
|
||||
|
||||
p.setPen(st::contactsNameFg);
|
||||
auto namex = st::rightsPhotoMargin.left()
|
||||
+ st::rightsPhotoButton.size .width()
|
||||
+ st::rightsPhotoMargin.right();
|
||||
auto namew = width() - namex - st::rightsPhotoMargin.right();
|
||||
_userName.drawLeftElided(p, namex, st::rightsPhotoMargin.top() + st::rightsNameTop, namew, width());
|
||||
auto statusText = [this] {
|
||||
if (_user->botInfo) {
|
||||
auto seesAllMessages = (_user->botInfo->readsAllHistory || _hasAdminRights);
|
||||
return lang(seesAllMessages ? lng_status_bot_reads_all : lng_status_bot_not_reads_all);
|
||||
}
|
||||
return Data::OnlineText(_user->onlineTill, unixtime());
|
||||
};
|
||||
p.setFont(st::contactsStatusFont);
|
||||
p.setPen(st::contactsStatusFg);
|
||||
p.drawTextLeft(namex, st::rightsPhotoMargin.top() + st::rightsStatusTop, width(), statusText());
|
||||
}
|
||||
|
||||
EditParticipantBox::EditParticipantBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, bool hasAdminRights) : BoxContent()
|
||||
, _channel(channel)
|
||||
, _user(user)
|
||||
, _hasAdminRights(hasAdminRights) {
|
||||
}
|
||||
|
||||
void EditParticipantBox::prepare() {
|
||||
_inner = setInnerWidget(object_ptr<Inner>(
|
||||
this,
|
||||
_channel,
|
||||
_user,
|
||||
hasAdminRights()));
|
||||
}
|
||||
|
||||
template <typename Widget>
|
||||
QPointer<Widget> EditParticipantBox::addControl(object_ptr<Widget> widget, QMargins margin) {
|
||||
Expects(_inner != nullptr);
|
||||
return _inner->addControl(std::move(widget), margin);
|
||||
}
|
||||
|
||||
void EditParticipantBox::removeControl(QPointer<TWidget> widget) {
|
||||
Expects(_inner != nullptr);
|
||||
return _inner->removeControl(widget);
|
||||
}
|
||||
|
||||
void EditParticipantBox::resizeToContent() {
|
||||
_inner->resizeToWidth(st::boxWideWidth);
|
||||
setDimensions(_inner->width(), qMin(_inner->height(), st::boxMaxListHeight));
|
||||
}
|
||||
|
||||
EditAdminBox::EditAdminBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, const MTPChannelAdminRights &rights) : EditParticipantBox(nullptr, channel, user, (rights.c_channelAdminRights().vflags.v != 0))
|
||||
, _oldRights(rights) {
|
||||
auto dependency = [this](Flag dependent, Flag dependency) {
|
||||
_dependencies.push_back(std::make_pair(dependent, dependency));
|
||||
};
|
||||
dependency(Flag::f_invite_link, Flag::f_invite_users); // invite_link <-> invite_users
|
||||
dependency(Flag::f_invite_users, Flag::f_invite_link);
|
||||
}
|
||||
|
||||
MTPChannelAdminRights EditAdminBox::DefaultRights(not_null<ChannelData*> channel) {
|
||||
auto defaultRights = channel->isMegagroup()
|
||||
? (Flag::f_change_info | Flag::f_delete_messages | Flag::f_ban_users | Flag::f_invite_users | Flag::f_invite_link | Flag::f_pin_messages)
|
||||
: (Flag::f_change_info | Flag::f_post_messages | Flag::f_edit_messages | Flag::f_delete_messages | Flag::f_invite_users | Flag::f_invite_link);
|
||||
return MTP_channelAdminRights(MTP_flags(defaultRights));
|
||||
}
|
||||
|
||||
void EditAdminBox::prepare() {
|
||||
EditParticipantBox::prepare();
|
||||
|
||||
auto hadRights = _oldRights.c_channelAdminRights().vflags.v;
|
||||
setTitle(langFactory(hadRights ? lng_rights_edit_admin : lng_channel_add_admin));
|
||||
|
||||
addControl(object_ptr<BoxContentDivider>(this), QMargins());
|
||||
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
|
||||
|
||||
const auto prepareRights = hadRights ? _oldRights : DefaultRights(channel());
|
||||
const auto filterByMyRights = canSave()
|
||||
&& !hadRights
|
||||
&& !channel()->amCreator();
|
||||
const auto prepareFlags = prepareRights.c_channelAdminRights().vflags.v
|
||||
& (filterByMyRights ? channel()->adminRights() : ~Flag(0));
|
||||
auto addCheckbox = [&](Flags flags, const QString &text) {
|
||||
const auto checked = (prepareFlags & flags) != 0;
|
||||
auto control = addControl(object_ptr<Ui::Checkbox>(this, text, checked, st::rightsCheckbox, st::rightsToggle), st::rightsToggleMargin);
|
||||
control->checkedChanges(
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
InvokeQueued(this, [=] {
|
||||
applyDependencies(control);
|
||||
});
|
||||
}, control->lifetime());
|
||||
if (!channel()->amCreator()) {
|
||||
if (!(channel()->adminRights() & flags)) {
|
||||
control->setDisabled(true); // Grey out options that we don't have ourselves.
|
||||
}
|
||||
}
|
||||
if (!canSave()) {
|
||||
control->setDisabled(true);
|
||||
}
|
||||
_checkboxes.emplace(flags, control);
|
||||
};
|
||||
if (channel()->isMegagroup()) {
|
||||
addCheckbox(Flag::f_change_info, lang(lng_rights_group_info));
|
||||
addCheckbox(Flag::f_delete_messages, lang(lng_rights_group_delete));
|
||||
addCheckbox(Flag::f_ban_users, lang(lng_rights_group_ban));
|
||||
addCheckbox(Flag::f_invite_users | Flag::f_invite_link, lang(channel()->anyoneCanAddMembers() ? lng_rights_group_invite_link : lng_rights_group_invite));
|
||||
addCheckbox(Flag::f_pin_messages, lang(lng_rights_group_pin));
|
||||
addCheckbox(Flag::f_add_admins, lang(lng_rights_add_admins));
|
||||
} else {
|
||||
addCheckbox(Flag::f_change_info, lang(lng_rights_channel_info));
|
||||
addCheckbox(Flag::f_post_messages, lang(lng_rights_channel_post));
|
||||
addCheckbox(Flag::f_edit_messages, lang(lng_rights_channel_edit));
|
||||
addCheckbox(Flag::f_delete_messages, lang(lng_rights_channel_delete));
|
||||
addCheckbox(Flag::f_invite_users | Flag::f_invite_link, lang(lng_rights_group_invite));
|
||||
addCheckbox(Flag::f_add_admins, lang(lng_rights_add_admins));
|
||||
}
|
||||
|
||||
auto addAdmins = _checkboxes.find(Flag::f_add_admins);
|
||||
if (addAdmins != _checkboxes.end()) {
|
||||
_aboutAddAdmins = addControl(
|
||||
object_ptr<Ui::FlatLabel>(this, st::boxLabel),
|
||||
st::rightsAboutMargin);
|
||||
Assert(addAdmins != _checkboxes.end());
|
||||
addAdmins->second->checkedChanges(
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
refreshAboutAddAdminsText();
|
||||
}, addAdmins->second->lifetime());
|
||||
refreshAboutAddAdminsText();
|
||||
}
|
||||
|
||||
if (canSave()) {
|
||||
addButton(langFactory(lng_settings_save), [this] {
|
||||
if (!_saveCallback) {
|
||||
return;
|
||||
}
|
||||
auto newFlags = MTPDchannelAdminRights::Flags(0);
|
||||
for (auto &&checkbox : _checkboxes) {
|
||||
if (checkbox.second->checked()) {
|
||||
newFlags |= checkbox.first;
|
||||
} else {
|
||||
newFlags &= ~checkbox.first;
|
||||
}
|
||||
}
|
||||
if (!channel()->amCreator()) {
|
||||
// Leave only rights that we have so we could save them.
|
||||
newFlags &= channel()->adminRights();
|
||||
}
|
||||
_saveCallback(_oldRights, MTP_channelAdminRights(MTP_flags(newFlags)));
|
||||
});
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
} else {
|
||||
addButton(langFactory(lng_box_ok), [this] { closeBox(); });
|
||||
}
|
||||
|
||||
applyDependencies(nullptr);
|
||||
for (auto &&checkbox : _checkboxes) {
|
||||
checkbox.second->finishAnimating();
|
||||
}
|
||||
|
||||
resizeToContent();
|
||||
}
|
||||
|
||||
void EditAdminBox::applyDependencies(QPointer<Ui::Checkbox> changed) {
|
||||
ApplyDependencies(_checkboxes, _dependencies, changed);
|
||||
}
|
||||
|
||||
void EditAdminBox::refreshAboutAddAdminsText() {
|
||||
auto addAdmins = _checkboxes.find(Flag::f_add_admins);
|
||||
Assert(addAdmins != _checkboxes.end());
|
||||
auto text = [this, addAdmins] {
|
||||
if (!canSave()) {
|
||||
return lang(lng_rights_about_admin_cant_edit);
|
||||
} else if (addAdmins->second->checked()) {
|
||||
return lang(lng_rights_about_add_admins_yes);
|
||||
}
|
||||
return lang(lng_rights_about_add_admins_no);
|
||||
};
|
||||
_aboutAddAdmins->setText(text());
|
||||
resizeToContent();
|
||||
}
|
||||
|
||||
EditRestrictedBox::EditRestrictedBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, bool hasAdminRights, const MTPChannelBannedRights &rights) : EditParticipantBox(nullptr, channel, user, hasAdminRights)
|
||||
, _oldRights(rights) {
|
||||
auto dependency = [this](Flag dependent, Flag dependency) {
|
||||
_dependencies.push_back(std::make_pair(dependent, dependency));
|
||||
};
|
||||
dependency(Flag::f_send_gifs, Flag::f_send_stickers); // stickers <-> gifs
|
||||
dependency(Flag::f_send_stickers, Flag::f_send_gifs);
|
||||
dependency(Flag::f_send_games, Flag::f_send_stickers); // stickers <-> games
|
||||
dependency(Flag::f_send_stickers, Flag::f_send_games);
|
||||
dependency(Flag::f_send_inline, Flag::f_send_stickers); // stickers <-> inline
|
||||
dependency(Flag::f_send_stickers, Flag::f_send_inline);
|
||||
dependency(Flag::f_send_stickers, Flag::f_send_media); // stickers -> send_media
|
||||
dependency(Flag::f_embed_links, Flag::f_send_media); // embed_links -> send_media
|
||||
dependency(Flag::f_send_media, Flag::f_send_messages); // send_media- > send_messages
|
||||
dependency(Flag::f_send_messages, Flag::f_view_messages); // send_messages -> view_messages
|
||||
}
|
||||
|
||||
void EditRestrictedBox::prepare() {
|
||||
EditParticipantBox::prepare();
|
||||
|
||||
setTitle(langFactory(lng_rights_user_restrictions));
|
||||
|
||||
addControl(object_ptr<BoxContentDivider>(this), QMargins());
|
||||
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_user_restrictions_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
|
||||
|
||||
auto prepareRights = (_oldRights.c_channelBannedRights().vflags.v ? _oldRights : DefaultRights(channel()));
|
||||
_until = prepareRights.c_channelBannedRights().vuntil_date.v;
|
||||
|
||||
auto addCheckbox = [&](Flags flags, const QString &text) {
|
||||
auto checked = (prepareRights.c_channelBannedRights().vflags.v & flags) == 0;
|
||||
auto control = addControl(object_ptr<Ui::Checkbox>(this, text, checked, st::rightsCheckbox, st::rightsToggle), st::rightsToggleMargin);
|
||||
control->checkedChanges(
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
InvokeQueued(this, [=] {
|
||||
applyDependencies(control);
|
||||
});
|
||||
}, control->lifetime());
|
||||
if (!canSave()) {
|
||||
control->setDisabled(true);
|
||||
}
|
||||
_checkboxes.emplace(flags, control);
|
||||
};
|
||||
addCheckbox(Flag::f_view_messages, lang(lng_rights_chat_read));
|
||||
addCheckbox(Flag::f_send_messages, lang(lng_rights_chat_send_text));
|
||||
addCheckbox(Flag::f_send_media, lang(lng_rights_chat_send_media));
|
||||
addCheckbox(Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline, lang(lng_rights_chat_send_stickers));
|
||||
addCheckbox(Flag::f_embed_links, lang(lng_rights_chat_send_links));
|
||||
|
||||
addControl(object_ptr<BoxContentDivider>(this), st::rightsUntilMargin);
|
||||
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_chat_banned_until_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
|
||||
setRestrictUntil(_until);
|
||||
|
||||
//addControl(object_ptr<Ui::LinkButton>(this, lang(lng_rights_chat_banned_block), st::boxLinkButton));
|
||||
|
||||
if (canSave()) {
|
||||
addButton(langFactory(lng_settings_save), [this] {
|
||||
if (!_saveCallback) {
|
||||
return;
|
||||
}
|
||||
auto newFlags = MTPDchannelBannedRights::Flags(0);
|
||||
for (auto &&checkbox : _checkboxes) {
|
||||
if (checkbox.second->checked()) {
|
||||
newFlags &= ~checkbox.first;
|
||||
} else {
|
||||
newFlags |= checkbox.first;
|
||||
}
|
||||
}
|
||||
_saveCallback(_oldRights, MTP_channelBannedRights(MTP_flags(newFlags), MTP_int(getRealUntilValue())));
|
||||
});
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
} else {
|
||||
addButton(langFactory(lng_box_ok), [this] { closeBox(); });
|
||||
}
|
||||
|
||||
applyDependencies(nullptr);
|
||||
for (auto &&checkbox : _checkboxes) {
|
||||
checkbox.second->finishAnimating();
|
||||
}
|
||||
|
||||
resizeToContent();
|
||||
}
|
||||
|
||||
void EditRestrictedBox::applyDependencies(QPointer<Ui::Checkbox> changed) {
|
||||
ApplyDependencies(_checkboxes, _dependencies, changed);
|
||||
}
|
||||
|
||||
MTPChannelBannedRights EditRestrictedBox::DefaultRights(not_null<ChannelData*> channel) {
|
||||
auto defaultRights = Flag::f_send_messages | Flag::f_send_media | Flag::f_embed_links | Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline;
|
||||
return MTP_channelBannedRights(MTP_flags(defaultRights), MTP_int(0));
|
||||
}
|
||||
|
||||
void EditRestrictedBox::showRestrictUntil() {
|
||||
auto tomorrow = QDate::currentDate().addDays(1);
|
||||
auto highlighted = isUntilForever() ? tomorrow : ParseDateTime(getRealUntilValue()).date();
|
||||
auto month = highlighted;
|
||||
_restrictUntilBox = Ui::show(
|
||||
Box<CalendarBox>(
|
||||
month,
|
||||
highlighted,
|
||||
[this](const QDate &date) {
|
||||
setRestrictUntil(static_cast<int>(QDateTime(date).toTime_t()));
|
||||
}),
|
||||
LayerOption::KeepOther);
|
||||
_restrictUntilBox->setMaxDate(QDate::currentDate().addDays(kMaxRestrictDelayDays));
|
||||
_restrictUntilBox->setMinDate(tomorrow);
|
||||
_restrictUntilBox->addLeftButton(langFactory(lng_rights_chat_banned_forever), [this] { setRestrictUntil(0); });
|
||||
}
|
||||
|
||||
void EditRestrictedBox::setRestrictUntil(TimeId until) {
|
||||
_until = until;
|
||||
if (_restrictUntilBox) {
|
||||
_restrictUntilBox->closeBox();
|
||||
}
|
||||
clearVariants();
|
||||
createUntilGroup();
|
||||
createUntilVariants();
|
||||
resizeToContent();
|
||||
}
|
||||
|
||||
void EditRestrictedBox::clearVariants() {
|
||||
for (auto &&widget : base::take(_untilVariants)) {
|
||||
removeControl(widget.data());
|
||||
}
|
||||
}
|
||||
|
||||
void EditRestrictedBox::createUntilGroup() {
|
||||
_untilGroup = std::make_shared<Ui::RadiobuttonGroup>(isUntilForever() ? 0 : _until);
|
||||
_untilGroup->setChangedCallback([this](int value) {
|
||||
if (value == kUntilCustom) {
|
||||
_untilGroup->setValue(_until);
|
||||
showRestrictUntil();
|
||||
} else if (_until != value) {
|
||||
_until = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void EditRestrictedBox::createUntilVariants() {
|
||||
auto addVariant = [this](int value, const QString &text) {
|
||||
if (!canSave() && _untilGroup->value() != value) {
|
||||
return;
|
||||
}
|
||||
_untilVariants.push_back(addControl(object_ptr<Ui::Radiobutton>(this, _untilGroup, value, text, st::defaultBoxCheckbox), st::rightsToggleMargin));
|
||||
if (!canSave()) {
|
||||
_untilVariants.back()->setDisabled(true);
|
||||
}
|
||||
};
|
||||
auto addCustomVariant = [addVariant](TimeId until, TimeId from, TimeId to) {
|
||||
if (!ChannelData::IsRestrictedForever(until) && until > from && until <= to) {
|
||||
addVariant(
|
||||
until,
|
||||
lng_rights_chat_banned_custom_date(
|
||||
lt_date,
|
||||
langDayOfMonthFull(ParseDateTime(until).date())));
|
||||
}
|
||||
};
|
||||
auto addCurrentVariant = [this, addCustomVariant](TimeId from, TimeId to) {
|
||||
auto oldUntil = _oldRights.c_channelBannedRights().vuntil_date.v;
|
||||
if (oldUntil < _until) {
|
||||
addCustomVariant(oldUntil, from, to);
|
||||
}
|
||||
addCustomVariant(_until, from, to);
|
||||
if (oldUntil > _until) {
|
||||
addCustomVariant(oldUntil, from, to);
|
||||
}
|
||||
};
|
||||
addVariant(0, lang(lng_rights_chat_banned_forever));
|
||||
|
||||
auto now = unixtime();
|
||||
auto nextDay = now + kSecondsInDay;
|
||||
auto nextWeek = now + kSecondsInWeek;
|
||||
addCurrentVariant(0, nextDay);
|
||||
addVariant(kUntilOneDay, lng_rights_chat_banned_day(lt_count, 1));
|
||||
addCurrentVariant(nextDay, nextWeek);
|
||||
addVariant(kUntilOneWeek, lng_rights_chat_banned_week(lt_count, 1));
|
||||
addCurrentVariant(nextWeek, INT_MAX);
|
||||
addVariant(kUntilCustom, lang(lng_rights_chat_banned_custom));
|
||||
}
|
||||
|
||||
TimeId EditRestrictedBox::getRealUntilValue() const {
|
||||
Expects(_until != kUntilCustom);
|
||||
if (_until == kUntilOneDay) {
|
||||
return unixtime() + kSecondsInDay;
|
||||
} else if (_until == kUntilOneWeek) {
|
||||
return unixtime() + kSecondsInWeek;
|
||||
}
|
||||
Assert(_until >= 0);
|
||||
return _until;
|
||||
}
|
||||
@@ -1,138 +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"
|
||||
|
||||
namespace Ui {
|
||||
class FlatLabel;
|
||||
class LinkButton;
|
||||
class Checkbox;
|
||||
class Radiobutton;
|
||||
class RadiobuttonGroup;
|
||||
} // namespace Ui
|
||||
|
||||
class CalendarBox;
|
||||
|
||||
class EditParticipantBox : public BoxContent {
|
||||
public:
|
||||
EditParticipantBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, bool hasAdminRights);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeToContent();
|
||||
|
||||
not_null<UserData*> user() const {
|
||||
return _user;
|
||||
}
|
||||
not_null<ChannelData*> channel() const {
|
||||
return _channel;
|
||||
}
|
||||
|
||||
template <typename Widget>
|
||||
QPointer<Widget> addControl(object_ptr<Widget> widget, QMargins margin);
|
||||
|
||||
void removeControl(QPointer<TWidget> widget);
|
||||
|
||||
bool hasAdminRights() const {
|
||||
return _hasAdminRights;
|
||||
}
|
||||
|
||||
private:
|
||||
not_null<ChannelData*> _channel;
|
||||
not_null<UserData*> _user;
|
||||
bool _hasAdminRights = false;
|
||||
|
||||
class Inner;
|
||||
QPointer<Inner> _inner;
|
||||
|
||||
};
|
||||
|
||||
class EditAdminBox : public EditParticipantBox {
|
||||
public:
|
||||
EditAdminBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, const MTPChannelAdminRights &rights);
|
||||
|
||||
void setSaveCallback(Fn<void(MTPChannelAdminRights, MTPChannelAdminRights)> callback) {
|
||||
_saveCallback = std::move(callback);
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
using Flag = MTPDchannelAdminRights::Flag;
|
||||
using Flags = MTPDchannelAdminRights::Flags;
|
||||
|
||||
static MTPChannelAdminRights DefaultRights(not_null<ChannelData*> channel);
|
||||
|
||||
bool canSave() const {
|
||||
return !!_saveCallback;
|
||||
}
|
||||
void applyDependencies(QPointer<Ui::Checkbox> changed);
|
||||
void refreshAboutAddAdminsText();
|
||||
|
||||
const MTPChannelAdminRights _oldRights;
|
||||
std::vector<std::pair<Flag, Flag>> _dependencies;
|
||||
Fn<void(MTPChannelAdminRights, MTPChannelAdminRights)> _saveCallback;
|
||||
|
||||
std::map<Flags, QPointer<Ui::Checkbox>> _checkboxes;
|
||||
QPointer<Ui::FlatLabel> _aboutAddAdmins;
|
||||
|
||||
};
|
||||
|
||||
// Restricted box works with flags in the opposite way.
|
||||
// If some flag is set in the rights then the checkbox is unchecked.
|
||||
|
||||
class EditRestrictedBox : public EditParticipantBox {
|
||||
public:
|
||||
EditRestrictedBox(QWidget*, not_null<ChannelData*> channel, not_null<UserData*> user, bool hasAdminRights, const MTPChannelBannedRights &rights);
|
||||
|
||||
void setSaveCallback(Fn<void(MTPChannelBannedRights, MTPChannelBannedRights)> callback) {
|
||||
_saveCallback = std::move(callback);
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
using Flag = MTPDchannelBannedRights::Flag;
|
||||
using Flags = MTPDchannelBannedRights::Flags;
|
||||
|
||||
static MTPChannelBannedRights DefaultRights(not_null<ChannelData*> channel);
|
||||
|
||||
bool canSave() const {
|
||||
return !!_saveCallback;
|
||||
}
|
||||
void applyDependencies(QPointer<Ui::Checkbox> changed);
|
||||
void showRestrictUntil();
|
||||
void setRestrictUntil(TimeId until);
|
||||
bool isUntilForever() {
|
||||
return ChannelData::IsRestrictedForever(_until);
|
||||
}
|
||||
void clearVariants();
|
||||
void createUntilGroup();
|
||||
void createUntilVariants();
|
||||
TimeId getRealUntilValue() const;
|
||||
|
||||
const MTPChannelBannedRights _oldRights;
|
||||
TimeId _until = 0;
|
||||
std::vector<std::pair<Flag, Flag>> _dependencies;
|
||||
Fn<void(MTPChannelBannedRights, MTPChannelBannedRights)> _saveCallback;
|
||||
|
||||
std::map<Flags, QPointer<Ui::Checkbox>> _checkboxes;
|
||||
|
||||
std::shared_ptr<Ui::RadiobuttonGroup> _untilGroup;
|
||||
QVector<QPointer<Ui::Radiobutton>> _untilVariants;
|
||||
QPointer<CalendarBox> _restrictUntilBox;
|
||||
|
||||
static constexpr auto kUntilOneDay = -1;
|
||||
static constexpr auto kUntilOneWeek = -2;
|
||||
static constexpr auto kUntilCustom = -3;
|
||||
|
||||
};
|
||||
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "apiwrap.h"
|
||||
#include "auth_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
@@ -238,12 +239,12 @@ void EditPrivacyBox::setupContent() {
|
||||
|
||||
const auto group = std::make_shared<Ui::RadioenumGroup<Option>>(
|
||||
_value.option);
|
||||
const auto toggle = Ui::CreateChild<rpl::event_stream<>>(content);
|
||||
|
||||
const auto toggle = Ui::CreateChild<rpl::event_stream<Option>>(content);
|
||||
group->setChangedCallback([=](Option value) {
|
||||
_value.option = value;
|
||||
toggle->fire({});
|
||||
toggle->fire_copy(value);
|
||||
});
|
||||
auto optionValue = toggle->events_starting_with_copy(_value.option);
|
||||
|
||||
const auto addOptionRow = [&](Option option) {
|
||||
return (_controller->hasOption(option) || (_value.option == option))
|
||||
@@ -274,8 +275,8 @@ void EditPrivacyBox::setupContent() {
|
||||
std::move(label),
|
||||
st::settingsButton,
|
||||
text);
|
||||
button->toggleOn(toggle->events_starting_with(
|
||||
rpl::empty_value()
|
||||
button->toggleOn(rpl::duplicate(
|
||||
optionValue
|
||||
) | rpl::map([=] {
|
||||
return showExceptionLink(exception);
|
||||
}))->entity()->addClickHandler([=] {
|
||||
@@ -284,6 +285,13 @@ void EditPrivacyBox::setupContent() {
|
||||
return button;
|
||||
};
|
||||
|
||||
auto above = _controller->setupAboveWidget(
|
||||
content,
|
||||
std::move(optionValue));
|
||||
if (above) {
|
||||
content->add(std::move(above));
|
||||
}
|
||||
|
||||
AddSubsectionTitle(content, _controller->optionsTitleKey());
|
||||
addOptionRow(Option::Everyone);
|
||||
addOptionRow(Option::Contacts);
|
||||
|
||||