Compare commits
195 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a76658ba46 | ||
|
|
6796204126 | ||
|
|
1c5e91c9a8 | ||
|
|
7f16675d2f | ||
|
|
6c7c442ad2 | ||
|
|
82fb2151a0 | ||
|
|
36b7c1c720 | ||
|
|
06bf67c146 | ||
|
|
8cc0fbc687 | ||
|
|
c846a14118 | ||
|
|
097424c535 | ||
|
|
c7ed36d558 | ||
|
|
95eab45108 | ||
|
|
f852813734 | ||
|
|
ca6a331a26 | ||
|
|
bfae205fbe | ||
|
|
aaa1245430 | ||
|
|
a99ae76ad4 | ||
|
|
6429e8b532 | ||
|
|
cb338e330f | ||
|
|
d12bd0824d | ||
|
|
4c0551ebb1 | ||
|
|
06fc23fc59 | ||
|
|
41977bf515 | ||
|
|
ffd2817d18 | ||
|
|
c48937a2f5 | ||
|
|
091d1157da | ||
|
|
be043a4437 | ||
|
|
fae0bccc9c | ||
|
|
b44cf4a094 | ||
|
|
90f4187ca9 | ||
|
|
ae272074b9 | ||
|
|
9972f7b90e | ||
|
|
f68cefbdc1 | ||
|
|
08841ed895 | ||
|
|
a919737f6e | ||
|
|
8f3510b3c4 | ||
|
|
6c588a8f2f | ||
|
|
4c9ef606f3 | ||
|
|
0b7bb806b7 | ||
|
|
78558e513c | ||
|
|
52e7ddf079 | ||
|
|
e2bc6990c7 | ||
|
|
06c3082fdf | ||
|
|
54cd55523b | ||
|
|
556f75ef6c | ||
|
|
951634a717 | ||
|
|
51d7e177a6 | ||
|
|
81e074115d | ||
|
|
9eb34e496f | ||
|
|
da60739893 | ||
|
|
7be1f16313 | ||
|
|
39b0d9e46f | ||
|
|
7be9e0fb94 | ||
|
|
e3e8d083ea | ||
|
|
9929bfb281 | ||
|
|
effa277a3b | ||
|
|
2661f81fd1 | ||
|
|
661de0c326 | ||
|
|
e1fd43b2a4 | ||
|
|
b697824540 | ||
|
|
eb3eef4b80 | ||
|
|
c3736c6fa3 | ||
|
|
0ef7503917 | ||
|
|
cef50e5f52 | ||
|
|
cb8ff398a5 | ||
|
|
eeb1a6b769 | ||
|
|
66822f7333 | ||
|
|
e466dc9fc7 | ||
|
|
947204bb9d | ||
|
|
f37f097dec | ||
|
|
a8d35b67aa | ||
|
|
4e0d94f347 | ||
|
|
c7e773dd9a | ||
|
|
e64d102efd | ||
|
|
49ea9434f2 | ||
|
|
e21c354428 | ||
|
|
d0614efd65 | ||
|
|
b0baf75fdd | ||
|
|
efb3e92525 | ||
|
|
5cdc563c9e | ||
|
|
a43dfc567c | ||
|
|
ea6e4c6006 | ||
|
|
98930792c3 | ||
|
|
165d1aacae | ||
|
|
831f1b6aee | ||
|
|
2f5fb3688a | ||
|
|
d8897a0cc8 | ||
|
|
3b956c598b | ||
|
|
1ee71bbd5c | ||
|
|
b7ab4fd086 | ||
|
|
44c6050bf2 | ||
|
|
35c759c6bc | ||
|
|
372cf275e0 | ||
|
|
33095966af | ||
|
|
ff53404d5b | ||
|
|
941288b58e | ||
|
|
22441ef80c | ||
|
|
8c2f11de7d | ||
|
|
c7a4d67cfb | ||
|
|
688275ea81 | ||
|
|
266102df2f | ||
|
|
f7aadc352b | ||
|
|
1ae3af0e80 | ||
|
|
97d27fe869 | ||
|
|
fcd2e28abb | ||
|
|
2522e66969 | ||
|
|
b9250edb33 | ||
|
|
54cab2c5a5 | ||
|
|
6231db1411 | ||
|
|
ef5a395c60 | ||
|
|
a200771868 | ||
|
|
914e043abe | ||
|
|
9d66f9cc03 | ||
|
|
e708065446 | ||
|
|
9c64cdb9c4 | ||
|
|
9f8d61ab2f | ||
|
|
0143fd28af | ||
|
|
844d030332 | ||
|
|
ae18ece549 | ||
|
|
10a0c6a086 | ||
|
|
51189fd244 | ||
|
|
1e10529f20 | ||
|
|
8d701ebb4f | ||
|
|
269bb94138 | ||
|
|
9b98ff52ea | ||
|
|
52f2f96f36 | ||
|
|
b53e40f1bf | ||
|
|
4e0d11f517 | ||
|
|
1a24ba857c | ||
|
|
1e254b958e | ||
|
|
23140b3d6a | ||
|
|
8c901d8f71 | ||
|
|
856356ce75 | ||
|
|
b5a65a4519 | ||
|
|
d056c00c67 | ||
|
|
36fb6dac89 | ||
|
|
fcda883878 | ||
|
|
40c0286942 | ||
|
|
59df447fed | ||
|
|
a253d34c00 | ||
|
|
0a5eac50be | ||
|
|
156c3d288c | ||
|
|
154e5660de | ||
|
|
13e6b91ac7 | ||
|
|
a89ad5d0fb | ||
|
|
e11c27048b | ||
|
|
e8dd277a00 | ||
|
|
329db0d8e9 | ||
|
|
eaf3ea9289 | ||
|
|
4156beaa3c | ||
|
|
4115d3d13d | ||
|
|
5f01751660 | ||
|
|
7d4e23448e | ||
|
|
c7aa5ed544 | ||
|
|
1bfe409c93 | ||
|
|
e8d619c740 | ||
|
|
2dc3ec955a | ||
|
|
07ff7c6cb0 | ||
|
|
8d52ca6be6 | ||
|
|
df91b2bfeb | ||
|
|
9d02e539c8 | ||
|
|
241fee80a7 | ||
|
|
83786ddeaf | ||
|
|
0e9793b845 | ||
|
|
2b36dd660b | ||
|
|
35ffc03988 | ||
|
|
5a9d1a3fce | ||
|
|
6776d88688 | ||
|
|
affe9defb5 | ||
|
|
d3fdf433cd | ||
|
|
cec8114b99 | ||
|
|
0a1a5ed70e | ||
|
|
c587c011d2 | ||
|
|
c2fa149ffd | ||
|
|
c63c75018d | ||
|
|
b0077d98f0 | ||
|
|
b5bc7a22af | ||
|
|
e60311811b | ||
|
|
8700c1b08f | ||
|
|
d8b51670e7 | ||
|
|
68c2f563c6 | ||
|
|
bf775cb4ca | ||
|
|
5c4b81434e | ||
|
|
cd1c7c56d3 | ||
|
|
427ceb9a9a | ||
|
|
2a110f0d3e | ||
|
|
d0ed75f3b5 | ||
|
|
be2abd594f | ||
|
|
75a40b83ae | ||
|
|
472a677bca | ||
|
|
dca6e10beb | ||
|
|
122ab94f3d | ||
|
|
2ab40de8b9 | ||
|
|
35659536c5 |
@@ -56,10 +56,6 @@ GOTO:EOF
|
||||
call:logInfo "Build version: %BUILD_VERSION%"
|
||||
set TDESKTOP_BUILD_DEFINES=
|
||||
|
||||
echo %BUILD_VERSION% | findstr /C:"disable_autoupdate">nul && (
|
||||
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_AUTOUPDATE
|
||||
)
|
||||
|
||||
echo %BUILD_VERSION% | findstr /C:"disable_register_custom_scheme">nul && (
|
||||
set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
|
||||
)
|
||||
|
||||
9
.gitignore
vendored
@@ -50,6 +50,15 @@ ipch/
|
||||
project.xcworkspace
|
||||
xcuserdata
|
||||
|
||||
parts
|
||||
prime
|
||||
stage
|
||||
*.snap
|
||||
.snapcraft
|
||||
/snap/gui/*.png
|
||||
/snap/gui/*.desktop
|
||||
/snap/plugins/__pycache__
|
||||
|
||||
/Telegram/*.user.*
|
||||
*.pro.user
|
||||
/Linux/
|
||||
|
||||
@@ -10,7 +10,6 @@ cache:
|
||||
env:
|
||||
matrix:
|
||||
- BUILD_VERSION=""
|
||||
- BUILD_VERSION="disable_autoupdate"
|
||||
- BUILD_VERSION="disable_register_custom_scheme"
|
||||
- BUILD_VERSION="disable_crash_reports"
|
||||
- BUILD_VERSION="disable_network_proxy"
|
||||
|
||||
@@ -100,10 +100,6 @@ build() {
|
||||
fi
|
||||
|
||||
# Configure the build
|
||||
if [[ $BUILD_VERSION == *"disable_autoupdate"* ]]; then
|
||||
GYP_DEFINES+=",TDESKTOP_DISABLE_AUTOUPDATE"
|
||||
fi
|
||||
|
||||
if [[ $BUILD_VERSION == *"disable_register_custom_scheme"* ]]; then
|
||||
GYP_DEFINES+=",TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME"
|
||||
fi
|
||||
|
||||
@@ -16,7 +16,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
|
||||
* 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 24
|
||||
* Fedora 22 - Fedora 28
|
||||
|
||||
## Third-party
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/pylib/gyp/generator/cmake.py b/pylib/gyp/generator/cmake.py
|
||||
index a2b9629..68d7020 100644
|
||||
index a2b9629..ac59461 100644
|
||||
--- a/pylib/gyp/generator/cmake.py
|
||||
+++ b/pylib/gyp/generator/cmake.py
|
||||
@@ -1070,6 +1070,23 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
|
||||
@@ -26,6 +26,43 @@ index a2b9629..68d7020 100644
|
||||
UnsetVariable(output, 'TOOLSET')
|
||||
UnsetVariable(output, 'TARGET')
|
||||
|
||||
@@ -1112,6 +1129,8 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
|
||||
SetVariable(output, 'configuration', config_to_use)
|
||||
|
||||
ar = None
|
||||
+ ranlib = None
|
||||
+ nm = None
|
||||
cc = None
|
||||
cxx = None
|
||||
|
||||
@@ -1121,17 +1140,27 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
|
||||
for key, value in make_global_settings:
|
||||
if key == 'AR':
|
||||
ar = os.path.join(build_to_top, value)
|
||||
+ if key == 'RANLIB':
|
||||
+ ranlib = os.path.join(build_to_top, value)
|
||||
+ if key == 'NM':
|
||||
+ nm = os.path.join(build_to_top, value)
|
||||
if key == 'CC':
|
||||
cc = os.path.join(build_to_top, value)
|
||||
if key == 'CXX':
|
||||
cxx = os.path.join(build_to_top, value)
|
||||
|
||||
ar = gyp.common.GetEnvironFallback(['AR_target', 'AR'], ar)
|
||||
+ ranlib = gyp.common.GetEnvironFallback(['RANLIB_target', 'RANLIB'], ranlib)
|
||||
+ nm = gyp.common.GetEnvironFallback(['NM_target', 'NM'], nm)
|
||||
cc = gyp.common.GetEnvironFallback(['CC_target', 'CC'], cc)
|
||||
cxx = gyp.common.GetEnvironFallback(['CXX_target', 'CXX'], cxx)
|
||||
|
||||
if ar:
|
||||
SetVariable(output, 'CMAKE_AR', ar)
|
||||
+ if ranlib:
|
||||
+ SetVariable(output, 'CMAKE_RANLIB', ranlib)
|
||||
+ if nm:
|
||||
+ SetVariable(output, 'CMAKE_NM', nm)
|
||||
if cc:
|
||||
SetVariable(output, 'CMAKE_C_COMPILER', cc)
|
||||
if cxx:
|
||||
diff --git a/pylib/gyp/generator/xcode.py b/pylib/gyp/generator/xcode.py
|
||||
index db99d6a..8d56baf 100644
|
||||
--- a/pylib/gyp/generator/xcode.py
|
||||
|
||||
@@ -252,6 +252,43 @@ index 41834b21ae..8cdf4ab145 100644
|
||||
if (value == WSAEADDRNOTAVAIL) {
|
||||
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
|
||||
--- a/src/platformsupport/dbustray/qdbustrayicon.cpp
|
||||
+++ b/src/platformsupport/dbustray/qdbustrayicon.cpp
|
||||
@@ -58,9 +58,18 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(qLcTray, "qt.qpa.tray")
|
||||
|
||||
+static QString cachePath()
|
||||
+{
|
||||
+ QString xdgCache = QString::fromUtf8(getenv("XDG_CACHE_HOME"));
|
||||
+ if (xdgCache.isEmpty()) {
|
||||
+ xdgCache = QDir::cleanPath(QDir::homePath() + QStringLiteral("/.cache"));
|
||||
+ }
|
||||
+ return xdgCache;
|
||||
+}
|
||||
+
|
||||
static const QString KDEItemFormat = QStringLiteral("org.kde.StatusNotifierItem-%1-%2");
|
||||
static const QString KDEWatcherService = QStringLiteral("org.kde.StatusNotifierWatcher");
|
||||
-static const QString TempFileTemplate = QDir::tempPath() + QStringLiteral("/qt-trayicon-XXXXXX.png");
|
||||
+static const QString TempFileTemplate = cachePath() + QStringLiteral("/qt-trayicon-XXXXXX.png");
|
||||
static const QString XdgNotificationService = QStringLiteral("org.freedesktop.Notifications");
|
||||
static const QString XdgNotificationPath = QStringLiteral("/org/freedesktop/Notifications");
|
||||
static const QString DefaultAction = QStringLiteral("default");
|
||||
@@ -151,6 +160,12 @@ QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon)
|
||||
uint pid = session.interface()->servicePid(KDEWatcherService).value();
|
||||
QString processName = QLockFilePrivate::processNameByPid(pid);
|
||||
necessary = processName.endsWith(QStringLiteral("indicator-application-service"));
|
||||
+ if (!necessary) {
|
||||
+ QString xdgDesktop = QString::fromUtf8(getenv("XDG_CURRENT_DESKTOP"));
|
||||
+ QStringList desktops = xdgDesktop.toLower().split(QLatin1Char(':'));
|
||||
+ necessary = desktops.contains(QStringLiteral("unity")) ||
|
||||
+ desktops.contains(QStringLiteral("ubuntu"));
|
||||
+ }
|
||||
necessity_checked = true;
|
||||
}
|
||||
if (!necessary)
|
||||
diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
|
||||
index 728b166b71..1dc64593e1 100644
|
||||
--- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
|
||||
|
||||
530
Telegram/Resources/export_html/css/style.css
Normal file
@@ -0,0 +1,530 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font: 12px/18px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;
|
||||
}
|
||||
strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
code, kbd, pre, samp {
|
||||
font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
|
||||
}
|
||||
code {
|
||||
padding: 2px 4px;
|
||||
font-size: 90%;
|
||||
color: #c7254e;
|
||||
background-color: #f9f2f4;
|
||||
border-radius: 4px;
|
||||
}
|
||||
pre {
|
||||
display: block;
|
||||
margin: 0;
|
||||
line-height: 1.42857143;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
color: #333;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
padding: 3px;
|
||||
border: 1px solid #eee;
|
||||
max-height: none;
|
||||
font-size: inherit;
|
||||
}
|
||||
.clearfix:after {
|
||||
content: " ";
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
}
|
||||
.pull_left {
|
||||
float: left;
|
||||
}
|
||||
.pull_right {
|
||||
float: right;
|
||||
}
|
||||
.page_wrap {
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
.page_wrap a {
|
||||
color: #168acd;
|
||||
text-decoration: none;
|
||||
}
|
||||
.page_wrap a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.page_header {
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
background-color: #ffffff;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #e3e6e8;
|
||||
}
|
||||
.page_header .content {
|
||||
width: 480px;
|
||||
margin: 0 auto;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
.page_header a.content {
|
||||
background-repeat: no-repeat;
|
||||
background-position: 24px 21px;
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
.bold {
|
||||
color: #212121;
|
||||
font-weight: 700;
|
||||
}
|
||||
.details {
|
||||
color: #70777b;
|
||||
}
|
||||
.page_header .content .text {
|
||||
padding: 24px 24px 22px 24px;
|
||||
font-size: 22px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.page_header a.content .text {
|
||||
padding: 24px 24px 22px 82px;
|
||||
}
|
||||
.page_body {
|
||||
padding-top: 64px;
|
||||
width: 480px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.page_about {
|
||||
padding: 24px 24px;
|
||||
}
|
||||
.with_divider {
|
||||
border-top: 1px solid #e3e6e8;
|
||||
}
|
||||
.userpic_link {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
.userpic_link:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.userpic {
|
||||
display: block;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.userpic .initials {
|
||||
display: block;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
user-select: none;
|
||||
}
|
||||
.color_red,
|
||||
.userpic1,
|
||||
.media_call .fill,
|
||||
.media_file .fill,
|
||||
.media_live_location .fill {
|
||||
background-color: #ff5555;
|
||||
}
|
||||
.color_green,
|
||||
.userpic2,
|
||||
.media_call.success .fill,
|
||||
.media_photo .fill {
|
||||
background-color: #64bf47;
|
||||
}
|
||||
.color_yellow,
|
||||
.userpic3,
|
||||
.media_venue .fill {
|
||||
background-color: #ffab00;
|
||||
}
|
||||
.color_blue,
|
||||
.userpic4,
|
||||
.media_audio_file .fill,
|
||||
.media_voice_message .fill {
|
||||
background-color: #4f9cd9;
|
||||
}
|
||||
.color_purple,
|
||||
.userpic5,
|
||||
.media_game .fill {
|
||||
background-color: #9884e8;
|
||||
}
|
||||
.color_pink,
|
||||
.userpic6,
|
||||
.media_invoice .fill {
|
||||
background-color: #e671a5;
|
||||
}
|
||||
.color_sea,
|
||||
.userpic7,
|
||||
.media_location .fill,
|
||||
.media_video .fill {
|
||||
background-color: #47bcd1;
|
||||
}
|
||||
.color_orange,
|
||||
.userpic8,
|
||||
.media_contact .fill {
|
||||
background-color: #ff8c44;
|
||||
}
|
||||
.personal_info {
|
||||
padding: 24px;
|
||||
}
|
||||
.personal_info .userpic .initials {
|
||||
font-size: 30px;
|
||||
}
|
||||
.personal_info .rows {
|
||||
float: left;
|
||||
padding-right: 24px;
|
||||
}
|
||||
.personal_info .names {
|
||||
width: 164px;
|
||||
}
|
||||
.personal_info .info {
|
||||
width: 124px;
|
||||
}
|
||||
.personal_info .bio {
|
||||
width: 400px;
|
||||
}
|
||||
.personal_info .row {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
a.block_link {
|
||||
display: block;
|
||||
text-decoration: none !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
a.block_link:hover {
|
||||
text-decoration: none !important;
|
||||
background-color: #f5f7f8;
|
||||
}
|
||||
.sections {
|
||||
padding: 11px 0;
|
||||
}
|
||||
.section {
|
||||
height: 48px;
|
||||
background-position: 24px 12px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
.section .counter {
|
||||
float: right;
|
||||
padding: 14px 24px 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
.section .label {
|
||||
padding: 15px 0 0 82px;
|
||||
font-size: 15px;
|
||||
}
|
||||
.list_page .page_about {
|
||||
padding: 16px 24px 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
.list_page .entry_list {
|
||||
padding: 16px 0;
|
||||
}
|
||||
.list_page .entry {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
.list_page .entry .userpic .initials {
|
||||
font-size: 18px;
|
||||
}
|
||||
.list_page .entry .body {
|
||||
margin-left: 66px;
|
||||
}
|
||||
.list_page .entry .name {
|
||||
padding: 4px 0 2px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.list_page .entry .subname {
|
||||
padding-top: 4px;
|
||||
}
|
||||
.list_page .entry .details_entry {
|
||||
padding-top: 4px;
|
||||
}
|
||||
.list_page .entry .info {
|
||||
font-size: 11px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.history {
|
||||
padding: 16px 0;
|
||||
}
|
||||
.message {
|
||||
margin: 0 -10px;
|
||||
transition: background-color 2.0s ease;
|
||||
}
|
||||
div.selected {
|
||||
background-color: rgba(242,246,250,255);
|
||||
transition: background-color 0.5s ease;
|
||||
}
|
||||
.service {
|
||||
padding: 10px 24px;
|
||||
}
|
||||
.service .body {
|
||||
text-align: center;
|
||||
}
|
||||
.service .userpic_wrap {
|
||||
padding-top: 10px;
|
||||
}
|
||||
.service .userpic {
|
||||
margin: 0 auto;
|
||||
}
|
||||
.service .userpic .initials {
|
||||
font-size: 24px;
|
||||
}
|
||||
.message .userpic .initials {
|
||||
font-size: 16px;
|
||||
}
|
||||
.default {
|
||||
padding: 10px;
|
||||
}
|
||||
.default.joined {
|
||||
margin-top: -10px;
|
||||
}
|
||||
.default .from_name {
|
||||
color: #3892db;
|
||||
font-weight: 700;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.default .from_name .details {
|
||||
font-weight: normal;
|
||||
}
|
||||
.default .body {
|
||||
margin-left: 60px;
|
||||
}
|
||||
.default .text {
|
||||
word-wrap: break-word;
|
||||
line-height: 150%;
|
||||
}
|
||||
.default .reply_to,
|
||||
.default .media_wrap {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.default .media {
|
||||
margin: 0 -10px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.default .media .fill,
|
||||
.default .media .thumb {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.default .media .fill {
|
||||
background-repeat: no-repeat;
|
||||
background-position: 12px 12px;
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
.default .media .title {
|
||||
padding-top: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.default .media .description {
|
||||
color: #000000;
|
||||
padding-top: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.default .media .status {
|
||||
padding-top: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.default .video_file_wrap,
|
||||
.default .animated_wrap {
|
||||
position: relative;
|
||||
}
|
||||
.default .video_file,
|
||||
.default .animated,
|
||||
.default .photo,
|
||||
.default .sticker {
|
||||
display: block;
|
||||
}
|
||||
.video_duration {
|
||||
background: rgba(0, 0, 0, .4);
|
||||
padding: 0px 5px;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
border-radius: 2px;
|
||||
right: 3px;
|
||||
bottom: 3px;
|
||||
color: #ffffff;
|
||||
font-size: 11px;
|
||||
}
|
||||
.video_play_bg {
|
||||
background: rgba(0, 0, 0, .4);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 0;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin: -20px auto 0 -20px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
.video_play {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
margin-top: -9px;
|
||||
z-index: 1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 9px 0 9px 14px;
|
||||
border-color: transparent transparent transparent #fff;
|
||||
}
|
||||
.gif_play {
|
||||
font-weight: 700;
|
||||
color: #FFF;
|
||||
display: block;
|
||||
line-height: 40px;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
}
|
||||
.pagination {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.toast_container {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
opacity: 0;
|
||||
transition: opacity 3.0s ease;
|
||||
}
|
||||
.toast_body {
|
||||
margin: 0 -50%;
|
||||
float: left;
|
||||
border-radius: 15px;
|
||||
padding: 10px 20px;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
color: #ffffff;
|
||||
}
|
||||
div.toast_shown {
|
||||
opacity: 1;
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
|
||||
.section.calls {
|
||||
background-image: url(../images/section_calls.png);
|
||||
}
|
||||
.section.chats {
|
||||
background-image: url(../images/section_chats.png);
|
||||
}
|
||||
.section.contacts {
|
||||
background-image: url(../images/section_contacts.png);
|
||||
}
|
||||
.section.frequent {
|
||||
background-image: url(../images/section_frequent.png);
|
||||
}
|
||||
.section.photos {
|
||||
background-image: url(../images/section_photos.png);
|
||||
}
|
||||
.section.sessions {
|
||||
background-image: url(../images/section_sessions.png);
|
||||
}
|
||||
.section.web {
|
||||
background-image: url(../images/section_web.png);
|
||||
}
|
||||
.section.other {
|
||||
background-image: url(../images/section_other.png)
|
||||
}
|
||||
.page_header a.content {
|
||||
background-image: url(../images/back.png);
|
||||
}
|
||||
.media_call .fill {
|
||||
background-image: url(../images/media_call.png)
|
||||
}
|
||||
.media_contact .fill {
|
||||
background-image: url(../images/media_contact.png)
|
||||
}
|
||||
.media_file .fill {
|
||||
background-image: url(../images/media_file.png)
|
||||
}
|
||||
.media_game .fill {
|
||||
background-image: url(../images/media_game.png)
|
||||
}
|
||||
.media_live_location .fill,
|
||||
.media_location .fill,
|
||||
.media_venue .fill {
|
||||
background-image: url(../images/media_location.png)
|
||||
}
|
||||
.media_audio_file .fill {
|
||||
background-image: url(../images/media_music.png)
|
||||
}
|
||||
.media_invoice .fill {
|
||||
background-image: url(../images/media_shop.png)
|
||||
}
|
||||
.media_voice_message .fill {
|
||||
background-image: url(../images/media_voice.png)
|
||||
}
|
||||
.media_photo .fill {
|
||||
background-image: url(../images/media_photo.png)
|
||||
}
|
||||
.media_video .fill {
|
||||
background-image: url(../images/media_video.png)
|
||||
}
|
||||
|
||||
@media only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) {
|
||||
.section.calls {
|
||||
background-image: url(../images/section_calls@2x.png);
|
||||
}
|
||||
.section.chats {
|
||||
background-image: url(../images/section_chats@2x.png);
|
||||
}
|
||||
.section.contacts {
|
||||
background-image: url(../images/section_contacts@2x.png);
|
||||
}
|
||||
.section.frequent {
|
||||
background-image: url(../images/section_frequent@2x.png);
|
||||
}
|
||||
.section.photos {
|
||||
background-image: url(../images/section_photos@2x.png);
|
||||
}
|
||||
.section.sessions {
|
||||
background-image: url(../images/section_sessions@2x.png);
|
||||
}
|
||||
.section.web {
|
||||
background-image: url(../images/section_web@2x.png);
|
||||
}
|
||||
.section.other {
|
||||
background-image: url(../images/section_other@2x.png);
|
||||
}
|
||||
.page_header a.content {
|
||||
background-image: url(../images/back@2x.png);
|
||||
}
|
||||
.media_call .fill {
|
||||
background-image: url(../images/media_call@2x.png)
|
||||
}
|
||||
.media_contact .fill {
|
||||
background-image: url(../images/media_contact@2x.png)
|
||||
}
|
||||
.media_file .fill {
|
||||
background-image: url(../images/media_file@2x.png)
|
||||
}
|
||||
.media_game .fill {
|
||||
background-image: url(../images/media_game@2x.png)
|
||||
}
|
||||
.media_live_location .fill,
|
||||
.media_location .fill,
|
||||
.media_venue .fill {
|
||||
background-image: url(../images/media_location@2x.png)
|
||||
}
|
||||
.media_audio_file .fill {
|
||||
background-image: url(../images/media_music@2x.png)
|
||||
}
|
||||
.media_invoice .fill {
|
||||
background-image: url(../images/media_shop@2x.png)
|
||||
}
|
||||
.media_voice_message .fill {
|
||||
background-image: url(../images/media_voice@2x.png)
|
||||
}
|
||||
.media_photo .fill {
|
||||
background-image: url(../images/media_photo@2x.png)
|
||||
}
|
||||
.media_video .fill {
|
||||
background-image: url(../images/media_video@2x.png)
|
||||
}
|
||||
}
|
||||
BIN
Telegram/Resources/export_html/images/back.png
Normal file
|
After Width: | Height: | Size: 312 B |
BIN
Telegram/Resources/export_html/images/back@2x.png
Normal file
|
After Width: | Height: | Size: 518 B |
BIN
Telegram/Resources/export_html/images/media_call.png
Normal file
|
After Width: | Height: | Size: 417 B |
BIN
Telegram/Resources/export_html/images/media_call@2x.png
Normal file
|
After Width: | Height: | Size: 815 B |
BIN
Telegram/Resources/export_html/images/media_contact.png
Normal file
|
After Width: | Height: | Size: 323 B |
BIN
Telegram/Resources/export_html/images/media_contact@2x.png
Normal file
|
After Width: | Height: | Size: 600 B |
BIN
Telegram/Resources/export_html/images/media_file.png
Normal file
|
After Width: | Height: | Size: 236 B |
BIN
Telegram/Resources/export_html/images/media_file@2x.png
Normal file
|
After Width: | Height: | Size: 408 B |
BIN
Telegram/Resources/export_html/images/media_game.png
Normal file
|
After Width: | Height: | Size: 271 B |
BIN
Telegram/Resources/export_html/images/media_game@2x.png
Normal file
|
After Width: | Height: | Size: 510 B |
BIN
Telegram/Resources/export_html/images/media_location.png
Normal file
|
After Width: | Height: | Size: 480 B |
BIN
Telegram/Resources/export_html/images/media_location@2x.png
Normal file
|
After Width: | Height: | Size: 991 B |
BIN
Telegram/Resources/export_html/images/media_music.png
Normal file
|
After Width: | Height: | Size: 275 B |
BIN
Telegram/Resources/export_html/images/media_music@2x.png
Normal file
|
After Width: | Height: | Size: 464 B |
BIN
Telegram/Resources/export_html/images/media_photo.png
Normal file
|
After Width: | Height: | Size: 243 B |
BIN
Telegram/Resources/export_html/images/media_photo@2x.png
Normal file
|
After Width: | Height: | Size: 458 B |
BIN
Telegram/Resources/export_html/images/media_shop.png
Normal file
|
After Width: | Height: | Size: 377 B |
BIN
Telegram/Resources/export_html/images/media_shop@2x.png
Normal file
|
After Width: | Height: | Size: 790 B |
BIN
Telegram/Resources/export_html/images/media_video.png
Normal file
|
After Width: | Height: | Size: 235 B |
BIN
Telegram/Resources/export_html/images/media_video@2x.png
Normal file
|
After Width: | Height: | Size: 411 B |
BIN
Telegram/Resources/export_html/images/media_voice.png
Normal file
|
After Width: | Height: | Size: 328 B |
BIN
Telegram/Resources/export_html/images/media_voice@2x.png
Normal file
|
After Width: | Height: | Size: 660 B |
BIN
Telegram/Resources/export_html/images/section_calls.png
Normal file
|
After Width: | Height: | Size: 656 B |
BIN
Telegram/Resources/export_html/images/section_calls@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/export_html/images/section_chats.png
Normal file
|
After Width: | Height: | Size: 283 B |
BIN
Telegram/Resources/export_html/images/section_chats@2x.png
Normal file
|
After Width: | Height: | Size: 454 B |
BIN
Telegram/Resources/export_html/images/section_contacts.png
Normal file
|
After Width: | Height: | Size: 508 B |
BIN
Telegram/Resources/export_html/images/section_contacts@2x.png
Normal file
|
After Width: | Height: | Size: 1023 B |
BIN
Telegram/Resources/export_html/images/section_frequent.png
Normal file
|
After Width: | Height: | Size: 771 B |
BIN
Telegram/Resources/export_html/images/section_frequent@2x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/export_html/images/section_leftchats.png
Normal file
|
After Width: | Height: | Size: 402 B |
BIN
Telegram/Resources/export_html/images/section_leftchats@2x.png
Normal file
|
After Width: | Height: | Size: 619 B |
BIN
Telegram/Resources/export_html/images/section_other.png
Normal file
|
After Width: | Height: | Size: 155 B |
BIN
Telegram/Resources/export_html/images/section_other@2x.png
Normal file
|
After Width: | Height: | Size: 269 B |
BIN
Telegram/Resources/export_html/images/section_photos.png
Normal file
|
After Width: | Height: | Size: 415 B |
BIN
Telegram/Resources/export_html/images/section_photos@2x.png
Normal file
|
After Width: | Height: | Size: 750 B |
BIN
Telegram/Resources/export_html/images/section_sessions.png
Normal file
|
After Width: | Height: | Size: 134 B |
BIN
Telegram/Resources/export_html/images/section_sessions@2x.png
Normal file
|
After Width: | Height: | Size: 216 B |
BIN
Telegram/Resources/export_html/images/section_web.png
Normal file
|
After Width: | Height: | Size: 266 B |
BIN
Telegram/Resources/export_html/images/section_web@2x.png
Normal file
|
After Width: | Height: | Size: 447 B |
189
Telegram/Resources/export_html/js/script.js
Normal file
@@ -0,0 +1,189 @@
|
||||
"use strict";
|
||||
|
||||
window.AllowBackFromHistory = false;
|
||||
function CheckLocation() {
|
||||
var start = "#go_to_message";
|
||||
var hash = location.hash;
|
||||
if (hash.substr(0, start.length) == start) {
|
||||
var messageId = parseInt(hash.substr(start.length));
|
||||
if (messageId) {
|
||||
GoToMessage(messageId);
|
||||
}
|
||||
} else if (hash == "#allow_back") {
|
||||
window.AllowBackFromHistory = true;
|
||||
}
|
||||
}
|
||||
|
||||
function ShowToast(text) {
|
||||
var container = document.createElement("div");
|
||||
container.className = "toast_container";
|
||||
var inner = container.appendChild(document.createElement("div"));
|
||||
inner.className = "toast_body";
|
||||
inner.appendChild(document.createTextNode(text));
|
||||
var appended = document.body.appendChild(container);
|
||||
setTimeout(function () {
|
||||
AddClass(appended, "toast_shown");
|
||||
setTimeout(function () {
|
||||
RemoveClass(appended, "toast_shown");
|
||||
setTimeout(function () {
|
||||
document.body.removeChild(appended);
|
||||
}, 3000);
|
||||
}, 3000);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function ShowHashtag(tag) {
|
||||
ShowToast("This is a hashtag '#" + tag + "' link.");
|
||||
return false;
|
||||
}
|
||||
|
||||
function ShowCashtag(tag) {
|
||||
ShowToast("This is a cashtag '$" + tag + "' link.");
|
||||
return false;
|
||||
}
|
||||
|
||||
function ShowBotCommand(command) {
|
||||
ShowToast("This is a bot command '/" + command + "' link.");
|
||||
return false;
|
||||
}
|
||||
|
||||
function ShowMentionName() {
|
||||
ShowToast("This is a link to a user mentioned by name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
function AddClass(element, name) {
|
||||
var current = element.className;
|
||||
var expression = new RegExp('(^|\\s)' + name + '(\\s|$)', 'g');
|
||||
if (expression.test(current)) {
|
||||
return;
|
||||
}
|
||||
element.className = current + ' ' + name;
|
||||
}
|
||||
|
||||
function RemoveClass(element, name) {
|
||||
var current = element.className;
|
||||
var expression = new RegExp('(^|\\s)' + name + '(\\s|$)', '');
|
||||
var match = expression.exec(current);
|
||||
while ((match = expression.exec(current)) != null) {
|
||||
if (match[1].length > 0 && match[2].length > 0) {
|
||||
current = current.substr(0, match.index + match[1].length)
|
||||
+ current.substr(match.index + match[0].length);
|
||||
} else {
|
||||
current = current.substr(0, match.index)
|
||||
+ current.substr(match.index + match[0].length);
|
||||
}
|
||||
}
|
||||
element.className = current;
|
||||
}
|
||||
|
||||
function EaseOutQuad(t) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
function EaseInOutQuad(t) {
|
||||
return (t < 0.5) ? (2 * t * t) : ((4 - 2 * t) * t - 1);
|
||||
}
|
||||
|
||||
function ScrollHeight() {
|
||||
if ("innerHeight" in window) {
|
||||
return window.innerHeight;
|
||||
} else if (document.documentElement) {
|
||||
return document.documentElement.clientHeight;
|
||||
}
|
||||
return document.body.clientHeight;
|
||||
}
|
||||
|
||||
function ScrollTo(top, callback) {
|
||||
var html = document.documentElement;
|
||||
var current = html.scrollTop;
|
||||
var delta = top - current;
|
||||
var finish = function () {
|
||||
html.scrollTop = top;
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
if (!window.performance.now || delta == 0) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
var transition = EaseOutQuad;
|
||||
var max = 300;
|
||||
if (delta < -max) {
|
||||
current = top + max;
|
||||
delta = -max;
|
||||
} else if (delta > max) {
|
||||
current = top - max;
|
||||
delta = max;
|
||||
} else {
|
||||
transition = EaseInOutQuad;
|
||||
}
|
||||
var duration = 150;
|
||||
var interval = 7;
|
||||
var time = window.performance.now();
|
||||
var animate = function () {
|
||||
var now = window.performance.now();
|
||||
if (now >= time + duration) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
var dt = (now - time) / duration;
|
||||
html.scrollTop = Math.round(current + delta * transition(dt));
|
||||
setTimeout(animate, interval);
|
||||
};
|
||||
setTimeout(animate, interval);
|
||||
}
|
||||
|
||||
function ScrollToElement(element, callback) {
|
||||
var header = document.getElementsByClassName("page_header")[0];
|
||||
var headerHeight = header.offsetHeight;
|
||||
var html = document.documentElement;
|
||||
var scrollHeight = ScrollHeight();
|
||||
var available = scrollHeight - headerHeight;
|
||||
var padding = 10;
|
||||
var top = element.offsetTop;
|
||||
var height = element.offsetHeight;
|
||||
var desired = top
|
||||
- Math.max((available - height) / 2, padding)
|
||||
- headerHeight;
|
||||
var scrollTopMax = html.offsetHeight - scrollHeight;
|
||||
ScrollTo(Math.min(desired, scrollTopMax), callback);
|
||||
}
|
||||
|
||||
function GoToMessage(messageId) {
|
||||
var element = document.getElementById("message" + messageId);
|
||||
if (element) {
|
||||
var hash = "#go_to_message" + messageId;
|
||||
if (location.hash != hash) {
|
||||
location.hash = hash;
|
||||
}
|
||||
ScrollToElement(element, function () {
|
||||
AddClass(element, "selected");
|
||||
setTimeout(function () {
|
||||
RemoveClass(element, "selected");
|
||||
}, 1000);
|
||||
});
|
||||
} else {
|
||||
ShowToast("This message was not exported. Maybe it was deleted.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function GoBack(anchor) {
|
||||
if (!window.AllowBackFromHistory) {
|
||||
return true;
|
||||
}
|
||||
history.back();
|
||||
if (!anchor || !anchor.getAttribute) {
|
||||
return true;
|
||||
}
|
||||
var destination = anchor.getAttribute("href");
|
||||
if (!destination) {
|
||||
return true;
|
||||
}
|
||||
setTimeout(function () {
|
||||
location.href = destination;
|
||||
}, 100);
|
||||
return false;
|
||||
}
|
||||
@@ -469,6 +469,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_calls_privacy" = "Phone calls privacy";
|
||||
"lng_settings_groups_invite_privacy" = "Group invite settings";
|
||||
"lng_settings_show_sessions" = "Show all sessions";
|
||||
"lng_settings_export_data" = "Export Telegram data";
|
||||
"lng_settings_self_destruct" = "Account self-destruct settings";
|
||||
"lng_settings_change_phone" = "Change phone number";
|
||||
|
||||
@@ -671,6 +672,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_delete_conversation" = "Delete conversation";
|
||||
"lng_profile_block_user" = "Block user";
|
||||
"lng_profile_unblock_user" = "Unblock user";
|
||||
"lng_profile_export_chat" = "Export chat history";
|
||||
"lng_profile_export_channel" = "Export channel history";
|
||||
"lng_media_selected_photo#one" = "{count} Photo";
|
||||
"lng_media_selected_photo#other" = "{count} Photos";
|
||||
"lng_media_selected_video#one" = "{count} Video";
|
||||
@@ -1040,6 +1043,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_open_this_link" = "Open this link?";
|
||||
"lng_open_link" = "Open";
|
||||
"lng_open_passport_link" = "Open this Telegram Passport authorization?";
|
||||
"lng_allow_bot_pass" = "Allow {bot_name} to pass your Telegram name and ID to the web pages you open via this bot?";
|
||||
"lng_allow_bot" = "Allow";
|
||||
|
||||
@@ -1105,6 +1109,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_view_feed_info" = "View feed info";
|
||||
"lng_context_pin_to_top" = "Pin to top";
|
||||
"lng_context_unpin_from_top" = "Unpin from top";
|
||||
"lng_context_mark_unread" = "Mark as unread";
|
||||
"lng_context_mark_read" = "Mark as read";
|
||||
|
||||
"lng_context_promote_admin" = "Promote to admin";
|
||||
"lng_context_edit_permissions" = "Edit permissions";
|
||||
@@ -1558,6 +1564,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_identity_internal" = "Internal passport";
|
||||
"lng_passport_identity_internal_upload" = "Upload a scan of your internal passport";
|
||||
"lng_passport_identity_about" = "The document must contain your photograph, first and last name, date of birth, document number, country of issue, and expiry date.";
|
||||
"lng_passport_identity_selfie" = "Take a selfie with your document";
|
||||
"lng_passport_address_title" = "Residential address";
|
||||
"lng_passport_address_description" = "Upload a proof of your address";
|
||||
"lng_passport_address_bill" = "Utility bill";
|
||||
@@ -1567,7 +1574,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_address_agreement" = "Tenancy agreement";
|
||||
"lng_passport_address_agreement_upload" = "Upload a scan of your tenancy agreement";
|
||||
"lng_passport_address_registration" = "Passport registration";
|
||||
"lng_passport_address_registration_upload" = "Upload a scan of your passport registration";
|
||||
"lng_passport_address_registration_upload" = "Upload a scan of your passport registration page";
|
||||
"lng_passport_address_temporary" = "Temporary registration";
|
||||
"lng_passport_address_temporary_upload" = "Upload a scan of your temporary registration";
|
||||
"lng_passport_address_about" = "To confirm your address, please upload a scan or photo of the selected document (all pages).";
|
||||
@@ -1592,14 +1599,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_selfie_name" = "Photo";
|
||||
"lng_passport_selfie_description" = "Upload a photo of yourself holding your document. Make sure the ID and your face are clearly visible.";
|
||||
"lng_passport_upload_selfie" = "Upload selfie";
|
||||
"lng_passport_reupload_selfie" = "Reupload selfie";
|
||||
"lng_passport_front_side_title" = "Front side";
|
||||
"lng_passport_front_side_name" = "Scan";
|
||||
"lng_passport_front_side_description" = "Upload front side of your document.";
|
||||
"lng_passport_upload_front_side" = "Upload front side scan";
|
||||
"lng_passport_front_side_description" = "Upload the front side of your document.";
|
||||
"lng_passport_upload_front_side" = "Upload a scan of the front side";
|
||||
"lng_passport_reupload_front_side" = "Reupload a scan of the front side";
|
||||
"lng_passport_reverse_side_title" = "Reverse side";
|
||||
"lng_passport_reverse_side_name" = "Scan";
|
||||
"lng_passport_reverse_side_description" = "Upload reverse side of your document.";
|
||||
"lng_passport_upload_reverse_side" = "Upload reverse side scan";
|
||||
"lng_passport_reverse_side_description" = "Upload the reverse side of your document.";
|
||||
"lng_passport_upload_reverse_side" = "Upload a scan of the reverse side";
|
||||
"lng_passport_reupload_reverse_side" = "Reupload a scan of the reverse side";
|
||||
"lng_passport_main_page_title" = "Main page";
|
||||
"lng_passport_main_page_name" = "Scan";
|
||||
"lng_passport_main_page_description" = "Upload the main page of your document.";
|
||||
"lng_passport_upload_main_page" = "Upload a scan of the main page";
|
||||
"lng_passport_reupload_main_page" = "Reupload a scan of the main page";
|
||||
"lng_passport_personal_details" = "Personal details";
|
||||
"lng_passport_personal_details_enter" = "Enter your personal details";
|
||||
"lng_passport_choose_image" = "Choose scan image";
|
||||
@@ -1614,7 +1629,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_country" = "Country";
|
||||
"lng_passport_residence_country" = "Residence";
|
||||
"lng_passport_country_choose" = "Choose country";
|
||||
"lng_passport_document_number" = "Card Number";
|
||||
"lng_passport_document_number" = "Document Number";
|
||||
"lng_passport_expiry_date" = "Expiry date";
|
||||
"lng_passport_address" = "Address";
|
||||
"lng_passport_address_enter" = "Enter your address";
|
||||
@@ -1643,15 +1658,87 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_delete_email_sure" = "Are you sure you want to delete your email address?";
|
||||
"lng_passport_delete_phone" = "Delete phone number";
|
||||
"lng_passport_delete_phone_sure" = "Are you sure you want to delete your phone number?";
|
||||
"lng_passport_success" = "Authorization successfull!";
|
||||
"lng_passport_success" = "Authorization successful!";
|
||||
"lng_passport_stop_sure" = "Are you sure you want to stop this authorization?";
|
||||
"lng_passport_stop" = "Stop";
|
||||
"lng_passport_restart_sure" = "An unexpected error has occurred. Perhaps some changes were made from a different Telegram application. Would you like to restart this authorization?";
|
||||
"lng_passport_restart" = "Restart";
|
||||
"lng_passport_error_too_large" = "This file is too large.";
|
||||
"lng_passport_error_bad_size" = "This image has bad dimensions.";
|
||||
"lng_passport_error_too_large" = "Sorry, this file is too large.";
|
||||
"lng_passport_error_bad_size" = "Sorry, this image has wrong dimensions.";
|
||||
"lng_passport_error_cant_read" = "Can't read this file. Please choose an image.";
|
||||
"lng_passport_bad_name" = "Use latin characters only.";
|
||||
"lng_passport_bad_name" = "Please use latin characters only.";
|
||||
"lng_passport_wait_upload" = "Please wait while upload is finished.";
|
||||
"lng_passport_fix_errors" = "Please correct errors.";
|
||||
"lng_passport_app_out_of_date" = "Sorry, your Telegram app is out of date and can't handle this request. Please update Telegram.";
|
||||
|
||||
"lng_export_title" = "Export Personal Data";
|
||||
"lng_export_progress_title" = "Exporting personal data";
|
||||
"lng_export_option_info" = "Account information";
|
||||
"lng_export_option_info_about" = "Your chosen screen name, username, phone number and profile pictures.";
|
||||
"lng_export_option_contacts" = "Contacts list";
|
||||
"lng_export_option_contacts_about" = "If you allow access, contacts are continuously synced with Telegram. You can adjust this in Settings > Privacy & Security on mobile devices.";
|
||||
"lng_export_option_sessions" = "Active sessions";
|
||||
"lng_export_option_sessions_about" = "We store this to display your connected devices in Settings > Privacy & Security > Active Sessions.";
|
||||
"lng_export_header_other" = "Other";
|
||||
"lng_export_option_other" = "Miscellaneous data";
|
||||
"lng_export_option_other_about" = "Other types of data not mentioned above (beta).";
|
||||
"lng_export_header_chats" = "Chat export settings";
|
||||
"lng_export_option_personal_chats" = "Personal chats";
|
||||
"lng_export_option_bot_chats" = "Bot chats";
|
||||
"lng_export_option_private_groups" = "Private groups";
|
||||
"lng_export_option_private_channels" = "Private channels";
|
||||
"lng_export_option_public_groups" = "Public groups";
|
||||
"lng_export_option_public_channels" = "Public channels";
|
||||
"lng_export_option_only_my" = "Only my messages";
|
||||
"lng_export_header_media" = "Media export settings";
|
||||
"lng_export_option_photos" = "Photos";
|
||||
"lng_export_option_video_files" = "Video files";
|
||||
"lng_export_option_voice_messages" = "Voice messages";
|
||||
"lng_export_option_video_messages" = "Round video messages";
|
||||
"lng_export_option_stickers" = "Stickers";
|
||||
"lng_export_option_gifs" = "Animated GIFs";
|
||||
"lng_export_option_files" = "Files";
|
||||
"lng_export_option_size_limit" = "Size limit: {size}";
|
||||
"lng_export_header_format" = "Location and format";
|
||||
"lng_export_option_location" = "Download path: {path}";
|
||||
"lng_export_option_html" = "Human-readable HTML";
|
||||
"lng_export_option_json" = "Machine-readable JSON";
|
||||
"lng_export_start" = "Export";
|
||||
"lng_export_state_initializing" = "Initializing...";
|
||||
"lng_export_state_userpics" = "Profile pictures";
|
||||
"lng_export_state_chats_list" = "Processing chats...";
|
||||
"lng_export_state_chats" = "Chats";
|
||||
"lng_export_state_progress" = "{count} / {total}";
|
||||
"lng_export_state_photo" = "Photo";
|
||||
"lng_export_state_video_file" = "Video file";
|
||||
"lng_export_state_voice_message" = "Voice message";
|
||||
"lng_export_state_video_message" = "Round video message";
|
||||
"lng_export_state_sticker" = "Sticker";
|
||||
"lng_export_state_gif" = "Animated GIF";
|
||||
"lng_export_progress" = "You can close this window now. Please don't quit Telegram until the data export is completed.";
|
||||
"lng_export_stop" = "Stop";
|
||||
"lng_export_sure_stop" = "Are you sure you want to stop exporting your data?\n\nIf you do, you'll need to start over.";
|
||||
"lng_export_about_done" = "Your data was successfully exported.";
|
||||
"lng_export_done" = "Show my data";
|
||||
"lng_export_finished" = "Data export completed.";
|
||||
"lng_export_total_files" = "Total files: {count}.";
|
||||
"lng_export_total_size" = "Total size: {size}.";
|
||||
"lng_export_folder" = "Choose export folder";
|
||||
"lng_export_invalid" = "Sorry, you have started a new data export, so this data export is now cancelled.";
|
||||
"lng_export_delay" = "Sorry, for security reasons, you will be able to begin downloading your data in {hours}. We have notified all your devices about the export request to make sure it's authorized and to give you time to react if it's not.\n\nPlease come back on {date} and repeat the request using the same device.";
|
||||
"lng_export_delay_less_than_hour" = "less than an hour";
|
||||
"lng_export_delay_hours#one" = "{count} hour";
|
||||
"lng_export_delay_hours#other" = "{count} hours";
|
||||
"lng_export_suggest_title" = "Data export ready";
|
||||
"lng_export_suggest_text" = "You can now download the data you requested. Start exporting data?";
|
||||
"lng_export_suggest_cancel" = "Not now";
|
||||
"lng_export_about_telegram" = "Here is all the data you requested. Remember: we don’t use your data for ad targeting, we don’t sell it to others, and we’re not part of any “family of companies.”\n\nTelegram only keeps the information it needs to function as a feature-rich cloud service – for example, your cloud chats so that you can access them from any devices without using third-party backups, or your contacts so that you can rely on your existing social graph when messaging people on Telegram.\n\nCheck out Settings > Privacy & Security on Telegram's mobile apps for relevant settings.";
|
||||
"lng_export_about_contacts" = "If you allow access, your contacts are continuously synced with Telegram. Thanks to this, you can easily switch to Telegram without losing your existing social graph – and connect with friends across all your devices. We use data about your contacts to let you know when they join Telegram. We also use it to make sure that you see the names you have in your phone book instead of the screen names people choose for themselves.\n\nYou can disable contact syncing or delete your stored contacts in Settings > Privacy & Security on Telegram's mobile apps.";
|
||||
"lng_export_about_frequent" = "This rating shows which people you are likelier to message frequently. Telegram uses this data to populate the 'People' box at the top of the Search section. This rating is also calculated for inline bots so that the app can suggest the bots you are most likely to use in the attachment menu (or when you start a new message with \"@\").\n\nTo delete this data, go to Settings > Privacy & Security and disable 'Suggest Frequent Contacts' (requires Telegram for iOS v.4.8.3 or Telegram for Android v.4.8.10 or higher).";
|
||||
"lng_export_about_sessions" = "We store session info to display your connected devices in Settings > Privacy & Security > Active Sessions.";
|
||||
"lng_export_about_web_sessions" = "We store this to display the websites where you logged in using authentication via Telegram. This information is shown in Settings > Privacy & Security > Active Sessions.";
|
||||
"lng_export_about_chats" = "This page lists all chats from this export and where to look for their data.";
|
||||
"lng_export_about_left_chats" = "Below are the supergroups and channels from this export that you've left or where you were banned.\n\nNote that when you leave a channel or supergroup you've created, you have the option to either delete it, or simply leave (in case you want to rejoin later, or keep the community alive despite not being a member).";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
|
||||
@@ -1,4 +1,46 @@
|
||||
<RCC>
|
||||
<qresource prefix="/export">
|
||||
<file alias="css/style.css">../export_html/css/style.css</file>
|
||||
<file alias="images/back.png">../export_html/images/back.png</file>
|
||||
<file alias="images/back@2x.png">../export_html/images/back@2x.png</file>
|
||||
<file alias="images/media_call.png">../export_html/images/media_call.png</file>
|
||||
<file alias="images/media_call@2x.png">../export_html/images/media_call@2x.png</file>
|
||||
<file alias="images/media_contact.png">../export_html/images/media_contact.png</file>
|
||||
<file alias="images/media_contact@2x.png">../export_html/images/media_contact@2x.png</file>
|
||||
<file alias="images/media_file.png">../export_html/images/media_file.png</file>
|
||||
<file alias="images/media_file@2x.png">../export_html/images/media_file@2x.png</file>
|
||||
<file alias="images/media_game.png">../export_html/images/media_game.png</file>
|
||||
<file alias="images/media_game@2x.png">../export_html/images/media_game@2x.png</file>
|
||||
<file alias="images/media_location.png">../export_html/images/media_location.png</file>
|
||||
<file alias="images/media_location@2x.png">../export_html/images/media_location@2x.png</file>
|
||||
<file alias="images/media_music.png">../export_html/images/media_music.png</file>
|
||||
<file alias="images/media_music@2x.png">../export_html/images/media_music@2x.png</file>
|
||||
<file alias="images/media_photo.png">../export_html/images/media_photo.png</file>
|
||||
<file alias="images/media_photo@2x.png">../export_html/images/media_photo@2x.png</file>
|
||||
<file alias="images/media_shop.png">../export_html/images/media_shop.png</file>
|
||||
<file alias="images/media_shop@2x.png">../export_html/images/media_shop@2x.png</file>
|
||||
<file alias="images/media_video.png">../export_html/images/media_video.png</file>
|
||||
<file alias="images/media_video@2x.png">../export_html/images/media_video@2x.png</file>
|
||||
<file alias="images/media_voice.png">../export_html/images/media_voice.png</file>
|
||||
<file alias="images/media_voice@2x.png">../export_html/images/media_voice@2x.png</file>
|
||||
<file alias="images/section_calls.png">../export_html/images/section_calls.png</file>
|
||||
<file alias="images/section_calls@2x.png">../export_html/images/section_calls@2x.png</file>
|
||||
<file alias="images/section_chats.png">../export_html/images/section_chats.png</file>
|
||||
<file alias="images/section_chats@2x.png">../export_html/images/section_chats@2x.png</file>
|
||||
<file alias="images/section_contacts.png">../export_html/images/section_contacts.png</file>
|
||||
<file alias="images/section_contacts@2x.png">../export_html/images/section_contacts@2x.png</file>
|
||||
<file alias="images/section_frequent.png">../export_html/images/section_frequent.png</file>
|
||||
<file alias="images/section_frequent@2x.png">../export_html/images/section_frequent@2x.png</file>
|
||||
<file alias="images/section_other.png">../export_html/images/section_other.png</file>
|
||||
<file alias="images/section_other@2x.png">../export_html/images/section_other@2x.png</file>
|
||||
<file alias="images/section_photos.png">../export_html/images/section_photos.png</file>
|
||||
<file alias="images/section_photos@2x.png">../export_html/images/section_photos@2x.png</file>
|
||||
<file alias="images/section_sessions.png">../export_html/images/section_sessions.png</file>
|
||||
<file alias="images/section_sessions@2x.png">../export_html/images/section_sessions@2x.png</file>
|
||||
<file alias="images/section_web.png">../export_html/images/section_web.png</file>
|
||||
<file alias="images/section_web@2x.png">../export_html/images/section_web@2x.png</file>
|
||||
<file alias="js/script.js">../export_html/js/script.js</file>
|
||||
</qresource>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="fonts/OpenSans-Regular.ttf">../fonts/OpenSans-Regular.ttf</file>
|
||||
<file alias="fonts/OpenSans-Bold.ttf">../fonts/OpenSans-Bold.ttf</file>
|
||||
|
||||
@@ -167,7 +167,7 @@ inputMediaEmpty#9664f57f = InputMedia;
|
||||
inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
|
||||
inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
|
||||
inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia;
|
||||
inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
|
||||
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
|
||||
inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
|
||||
@@ -192,6 +192,7 @@ inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLo
|
||||
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
|
||||
inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation;
|
||||
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
|
||||
inputTakeoutFileLocation#29be5899 = InputFileLocation;
|
||||
|
||||
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
|
||||
|
||||
@@ -252,7 +253,7 @@ messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_un
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
|
||||
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
|
||||
messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia;
|
||||
messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia;
|
||||
messageMediaUnsupported#9f84f49e = MessageMedia;
|
||||
messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia;
|
||||
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
|
||||
@@ -284,7 +285,7 @@ messageActionBotAllowed#abe9affe domain:string = MessageAction;
|
||||
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
|
||||
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
|
||||
|
||||
dialog#e4def5db flags:# pinned:flags.2?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;
|
||||
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;
|
||||
|
||||
photoEmpty#2331b22d id:long = Photo;
|
||||
photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo;
|
||||
@@ -294,7 +295,7 @@ photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = Phot
|
||||
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
|
||||
|
||||
geoPointEmpty#1117dd5f = GeoPoint;
|
||||
geoPoint#2049d70c long:double lat:double = GeoPoint;
|
||||
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
|
||||
|
||||
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
|
||||
|
||||
@@ -344,6 +345,7 @@ contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Ve
|
||||
|
||||
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
|
||||
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
|
||||
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;
|
||||
@@ -440,6 +442,7 @@ updateFavedStickers#e511996d = Update;
|
||||
updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector<int> = Update;
|
||||
updateContactsReset#7084a7be = Update;
|
||||
updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
|
||||
updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@@ -466,7 +469,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#eb7bb160 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> 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 suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config;
|
||||
config#3213dbba 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 = Config;
|
||||
|
||||
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
|
||||
|
||||
@@ -693,7 +696,7 @@ inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?
|
||||
inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
|
||||
|
||||
inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult;
|
||||
@@ -705,7 +708,7 @@ botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vecto
|
||||
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||
|
||||
botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
|
||||
botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult;
|
||||
@@ -748,8 +751,9 @@ topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<To
|
||||
|
||||
contacts.topPeersNotModified#de266ef5 = contacts.TopPeers;
|
||||
contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers;
|
||||
contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
|
||||
|
||||
draftMessageEmpty#ba4baec5 = DraftMessage;
|
||||
draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
|
||||
draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
|
||||
|
||||
messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
|
||||
@@ -837,14 +841,13 @@ paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string e
|
||||
|
||||
paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials;
|
||||
|
||||
webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> dc_id:int = WebDocument;
|
||||
webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
|
||||
webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
|
||||
|
||||
inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument;
|
||||
|
||||
inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation;
|
||||
inputWebFileGeoPointLocation#66275a62 geo_point:InputGeoPoint w:int h:int zoom:int scale:int = InputWebFileLocation;
|
||||
inputWebFileGeoMessageLocation#553f32eb peer:InputPeer msg_id:int w:int h:int zoom:int scale:int = InputWebFileLocation;
|
||||
inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation;
|
||||
|
||||
upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;
|
||||
|
||||
@@ -1014,6 +1017,10 @@ account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEma
|
||||
help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo;
|
||||
help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = help.DeepLinkInfo;
|
||||
|
||||
savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact;
|
||||
|
||||
account.takeout#4dba4501 id:long = account.Takeout;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@@ -1021,13 +1028,14 @@ invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
|
||||
initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X;
|
||||
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
|
||||
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.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;
|
||||
auth.resetAuthorizations#9fab0d1a = Bool;
|
||||
auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool;
|
||||
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
|
||||
auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
|
||||
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
|
||||
@@ -1079,6 +1087,8 @@ account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_
|
||||
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;
|
||||
account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout;
|
||||
account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
@@ -1099,9 +1109,11 @@ 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;
|
||||
contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
|
||||
contacts.resetSaved#879537f1 = Bool;
|
||||
contacts.getSaved#82f1e39f = Vector<SavedContact>;
|
||||
contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
|
||||
|
||||
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
|
||||
messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;
|
||||
messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
|
||||
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
|
||||
@@ -1196,6 +1208,9 @@ messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = message
|
||||
messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates;
|
||||
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
|
||||
messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
|
||||
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
|
||||
messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool;
|
||||
messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@@ -1262,6 +1277,7 @@ channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet =
|
||||
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
|
||||
channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
|
||||
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
|
||||
channels.getLeftChannels#8341ecc0 offset:int = messages.Chats;
|
||||
|
||||
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
||||
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||
@@ -1292,4 +1308,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangP
|
||||
langpack.getDifference#b2e4d7d from_version:int = LangPackDifference;
|
||||
langpack.getLanguages#800fd57d = Vector<LangPackLanguage>;
|
||||
|
||||
// LAYER 81
|
||||
// LAYER 82
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="1.3.2.0" />
|
||||
Version="1.3.11.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,3,2,0
|
||||
PRODUCTVERSION 1,3,2,0
|
||||
FILEVERSION 1,3,11,0
|
||||
PRODUCTVERSION 1,3,11,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.3.2.0"
|
||||
VALUE "FileVersion", "1.3.11.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.3.2.0"
|
||||
VALUE "ProductVersion", "1.3.11.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,3,2,0
|
||||
PRODUCTVERSION 1,3,2,0
|
||||
FILEVERSION 1,3,11,0
|
||||
PRODUCTVERSION 1,3,11,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.3.2.0"
|
||||
VALUE "FileVersion", "1.3.11.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2018"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.3.2.0"
|
||||
VALUE "ProductVersion", "1.3.11.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -339,7 +339,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
LPWSTR *args;
|
||||
int argsCount;
|
||||
|
||||
bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, testmode = false;
|
||||
bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, testmode = false, externalupdater = false;
|
||||
args = CommandLineToArgvW(GetCommandLine(), &argsCount);
|
||||
if (args) {
|
||||
for (int i = 1; i < argsCount; ++i) {
|
||||
@@ -355,6 +355,8 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
startintray = true;
|
||||
} else if (equal(args[i], L"-testmode")) {
|
||||
testmode = true;
|
||||
} else if (equal(args[i], L"-externalupdater")) {
|
||||
externalupdater = true;
|
||||
} else if (equal(args[i], L"-writeprotected") && ++i < argsCount) {
|
||||
writeLog(std::wstring(L"Argument: ") + args[i]);
|
||||
writeprotected = true;
|
||||
@@ -425,6 +427,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
if (debug) targs += L" -debug";
|
||||
if (startintray) targs += L" -startintray";
|
||||
if (testmode) targs += L" -testmode";
|
||||
if (externalupdater) targs += L" -externalupdater";
|
||||
if (!customWorkingDir.empty()) {
|
||||
targs += L" -workdir \"" + customWorkingDir + L"\"";
|
||||
}
|
||||
|
||||
@@ -337,6 +337,7 @@ int main(int argc, char *argv[]) {
|
||||
bool tosettings = false;
|
||||
bool startintray = false;
|
||||
bool testmode = false;
|
||||
bool externalupdater = false;
|
||||
bool customWorkingDir = false;
|
||||
|
||||
char *key = 0;
|
||||
@@ -352,6 +353,8 @@ int main(int argc, char *argv[]) {
|
||||
startintray = true;
|
||||
} else if (equal(argv[i], "-testmode")) {
|
||||
testmode = true;
|
||||
} else if (equal(argv[i], "-externalupdater")) {
|
||||
externalupdater = true;
|
||||
} else if (equal(argv[i], "-tosettings")) {
|
||||
tosettings = true;
|
||||
} else if (equal(argv[i], "-workdir_custom")) {
|
||||
@@ -450,6 +453,7 @@ int main(int argc, char *argv[]) {
|
||||
char p_key[] = "-key";
|
||||
char p_startintray[] = "-startintray";
|
||||
char p_testmode[] = "-testmode";
|
||||
char p_externalupdater[] = "-externalupdater";
|
||||
char p_workdir[] = "-workdir";
|
||||
int argIndex = 0;
|
||||
args[argIndex++] = path;
|
||||
@@ -458,6 +462,7 @@ int main(int argc, char *argv[]) {
|
||||
if (debug) args[argIndex++] = p_debug;
|
||||
if (startintray) args[argIndex++] = p_startintray;
|
||||
if (testmode) args[argIndex++] = p_testmode;
|
||||
if (externalupdater) args[argIndex++] = p_externalupdater;
|
||||
if (tosettings) args[argIndex++] = p_tosettings;
|
||||
if (key) {
|
||||
args[argIndex++] = p_key;
|
||||
|
||||
@@ -75,7 +75,7 @@ int main(int argc, const char * argv[]) {
|
||||
|
||||
openLog();
|
||||
pid_t procId = 0;
|
||||
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO;
|
||||
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO, externalUpdater = NO;
|
||||
BOOL customWorkingDir = NO;
|
||||
NSString *key = nil;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
@@ -101,6 +101,8 @@ int main(int argc, const char * argv[]) {
|
||||
startInTray = YES;
|
||||
} else if ([@"-testmode" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
testMode = YES;
|
||||
} else if ([@"-externalupdater" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
externalUpdater = YES;
|
||||
} else if ([@"-workdir_custom" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
customWorkingDir = YES;
|
||||
} else if ([@"-key" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
@@ -235,6 +237,7 @@ int main(int argc, const char * argv[]) {
|
||||
if (_debug) [args addObject:@"-debug"];
|
||||
if (startInTray) [args addObject:@"-startintray"];
|
||||
if (testMode) [args addObject:@"-testmode"];
|
||||
if (externalUpdater) [args addObject:@"-externalupdater"];
|
||||
if (autoStart) [args addObject:@"-autostart"];
|
||||
if (key) {
|
||||
[args addObject:@"-key"];
|
||||
|
||||
@@ -37,8 +37,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_lock_widgets.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "inline_bots/inline_bot_result.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/storage_facade.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
@@ -126,15 +128,15 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
|
||||
return MTP_vector<MTPDocumentAttribute>(attributes);
|
||||
}
|
||||
|
||||
FileLoadTo FileLoadTaskOptions(const ApiWrap::SendOptions &options) {
|
||||
const auto peer = options.history->peer;
|
||||
return FileLoadTo(
|
||||
peer->id,
|
||||
Auth().data().notifySilentPosts(peer),
|
||||
options.replyTo);
|
||||
} // namespace
|
||||
|
||||
ApiWrap::SendOptions::SendOptions(not_null<History*> history)
|
||||
: history(history) {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
ApiWrap::MessageToSend::MessageToSend(not_null<History*> history)
|
||||
: history(history) {
|
||||
}
|
||||
|
||||
ApiWrap::ApiWrap(not_null<AuthSession*> session)
|
||||
: _session(session)
|
||||
@@ -230,7 +232,7 @@ void ApiWrap::proxyPromotionDone(const MTPhelp_ProxyData &proxy) {
|
||||
const auto peer = App::peer(peerId);
|
||||
_session->data().setProxyPromoted(peer);
|
||||
if (const auto history = App::historyLoaded(peer)) {
|
||||
_session->api().requestDialogEntry(history);
|
||||
requestDialogEntry(history);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,8 +272,9 @@ void ApiWrap::requestTermsUpdate() {
|
||||
_termsUpdateRequestId = 0;
|
||||
|
||||
const auto requestNext = [&](auto &&data) {
|
||||
const auto timeout = (data.vexpires.v - unixtime());
|
||||
_termsUpdateSendAt = getms(true) + snap(
|
||||
TimeMs(data.vexpires.v - unixtime()),
|
||||
timeout * TimeMs(1000),
|
||||
kTermsUpdateTimeoutMin,
|
||||
kTermsUpdateTimeoutMax);
|
||||
requestTermsUpdate();
|
||||
@@ -565,13 +568,15 @@ void ApiWrap::requestDialogEntry(not_null<Data::Feed*> feed) {
|
||||
// }
|
||||
// _dialogFeedRequests.emplace(feed);
|
||||
//
|
||||
// const auto hash = 0;
|
||||
// request(MTPmessages_GetDialogs(
|
||||
// MTP_flags(MTPmessages_GetDialogs::Flag::f_feed_id),
|
||||
// MTP_int(feed->id()),
|
||||
// MTP_int(0), // offset_date
|
||||
// MTP_int(0), // offset_id
|
||||
// MTP_inputPeerEmpty(), // offset_peer
|
||||
// MTP_int(Data::Feed::kChannelsLimit)
|
||||
// MTP_int(Data::Feed::kChannelsLimit),
|
||||
// MTP_int(hash)
|
||||
// )).done([=](const MTPmessages_Dialogs &result) {
|
||||
// applyFeedDialogs(feed, result);
|
||||
// _dialogFeedRequests.remove(feed);
|
||||
@@ -631,7 +636,7 @@ void ApiWrap::historyDialogEntryApplied(not_null<History*> history) {
|
||||
if (!chat->haveLeft()) {
|
||||
Local::addSavedPeer(
|
||||
history->peer,
|
||||
history->chatsListDate());
|
||||
ParseDateTime(history->chatsListTimeId()));
|
||||
}
|
||||
} else if (const auto channel = history->peer->asChannel()) {
|
||||
const auto inviter = channel->inviter;
|
||||
@@ -648,12 +653,11 @@ void ApiWrap::historyDialogEntryApplied(not_null<History*> history) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!history->chatsListDate().isNull()
|
||||
&& history->loadedAtBottom()) {
|
||||
if (history->chatsListTimeId() != 0 && history->loadedAtBottom()) {
|
||||
if (const auto channel = history->peer->asChannel()) {
|
||||
const auto inviter = channel->inviter;
|
||||
if (inviter != 0
|
||||
&& history->chatsListDate() <= ParseDateTime(channel->inviteDate)
|
||||
&& history->chatsListTimeId() <= channel->inviteDate
|
||||
&& channel->amIn()) {
|
||||
if (const auto from = App::userLoaded(inviter)) {
|
||||
history->insertJoinedMessage(true);
|
||||
@@ -714,6 +718,18 @@ void ApiWrap::applyFeedDialogs(
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
}
|
||||
|
||||
void ApiWrap::changeDialogUnreadMark(
|
||||
not_null<History*> history,
|
||||
bool unread) {
|
||||
history->setUnreadMark(unread);
|
||||
|
||||
using Flag = MTPmessages_MarkDialogUnread::Flag;
|
||||
request(MTPmessages_MarkDialogUnread(
|
||||
MTP_flags(unread ? Flag::f_unread : Flag(0)),
|
||||
MTP_inputDialogPeer(history->peer->input)
|
||||
)).send();
|
||||
}
|
||||
|
||||
void ApiWrap::requestFullPeer(PeerData *peer) {
|
||||
if (!peer || _fullPeerRequests.contains(peer)) return;
|
||||
|
||||
@@ -2055,10 +2071,22 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
if (!textWithTags.tags.isEmpty()) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_entities;
|
||||
}
|
||||
auto entities = TextUtilities::EntitiesToMTP(ConvertTextTagsToEntities(textWithTags.tags), TextUtilities::ConvertOption::SkipLocal);
|
||||
auto entities = TextUtilities::EntitiesToMTP(
|
||||
ConvertTextTagsToEntities(textWithTags.tags),
|
||||
TextUtilities::ConvertOption::SkipLocal);
|
||||
|
||||
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), history->peer->input, MTP_string(textWithTags.text), entities)).done([this, history](const MTPBool &result, mtpRequestId requestId) {
|
||||
if (auto cloudDraft = history->cloudDraft()) {
|
||||
const auto draftText = textWithTags.text;
|
||||
history->setSentDraftText(draftText);
|
||||
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
|
||||
MTP_flags(flags),
|
||||
MTP_int(cloudDraft->msgId),
|
||||
history->peer->input,
|
||||
MTP_string(textWithTags.text),
|
||||
entities
|
||||
)).done([=](const MTPBool &result, mtpRequestId requestId) {
|
||||
history->clearSentDraftText(draftText);
|
||||
|
||||
if (const auto cloudDraft = history->cloudDraft()) {
|
||||
if (cloudDraft->saveRequestId == requestId) {
|
||||
cloudDraft->saveRequestId = 0;
|
||||
history->draftSavedToCloud();
|
||||
@@ -2069,8 +2097,10 @@ void ApiWrap::saveDraftsToCloud() {
|
||||
_draftsSaveRequestIds.erase(history);
|
||||
checkQuitPreventFinished();
|
||||
}
|
||||
}).fail([this, history](const RPCError &error, mtpRequestId requestId) {
|
||||
if (auto cloudDraft = history->cloudDraft()) {
|
||||
}).fail([=](const RPCError &error, mtpRequestId requestId) {
|
||||
history->clearSentDraftText(draftText);
|
||||
|
||||
if (const auto cloudDraft = history->cloudDraft()) {
|
||||
if (cloudDraft->saveRequestId == requestId) {
|
||||
history->clearCloudDraft();
|
||||
}
|
||||
@@ -2470,6 +2500,12 @@ std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji(
|
||||
auto &entry = _stickersByEmoji[emoji];
|
||||
entry.list.clear();
|
||||
entry.list.reserve(data.vstickers.v.size());
|
||||
for (const auto &sticker : data.vstickers.v) {
|
||||
const auto document = _session->data().document(sticker);
|
||||
if (document->sticker()) {
|
||||
entry.list.push_back(document);
|
||||
}
|
||||
}
|
||||
entry.hash = data.vhash.v;
|
||||
entry.received = getms(true);
|
||||
_session->data().notifyStickersUpdated();
|
||||
@@ -3763,6 +3799,8 @@ void ApiWrap::sendSharedContact(
|
||||
const auto messagePostAuthor = channelPost
|
||||
? (_session->user()->firstName + ' ' + _session->user()->lastName)
|
||||
: QString();
|
||||
const auto vcard = QString();
|
||||
const auto views = 1;
|
||||
const auto item = history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
@@ -3778,10 +3816,11 @@ void ApiWrap::sendSharedContact(
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
MTP_string(lastName),
|
||||
MTP_string(vcard),
|
||||
MTP_int(userId)),
|
||||
MTPnullMarkup,
|
||||
MTPnullEntities,
|
||||
MTP_int(1),
|
||||
MTP_int(views),
|
||||
MTPint(),
|
||||
MTP_string(messagePostAuthor),
|
||||
MTPlong()),
|
||||
@@ -3790,7 +3829,8 @@ void ApiWrap::sendSharedContact(
|
||||
const auto media = MTP_inputMediaContact(
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
MTP_string(lastName));
|
||||
MTP_string(lastName),
|
||||
MTP_string(vcard));
|
||||
sendMedia(item, media, _session->data().notifySilentPosts(peer));
|
||||
|
||||
if (const auto main = App::main()) {
|
||||
@@ -3806,7 +3846,7 @@ void ApiWrap::sendVoiceMessage(
|
||||
int duration,
|
||||
const SendOptions &options) {
|
||||
const auto caption = TextWithTags();
|
||||
const auto to = FileLoadTaskOptions(options);
|
||||
const auto to = fileLoadTaskOptions(options);
|
||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||
result,
|
||||
duration,
|
||||
@@ -3822,15 +3862,15 @@ void ApiWrap::sendFiles(
|
||||
std::shared_ptr<SendingAlbum> album,
|
||||
const SendOptions &options) {
|
||||
if (list.files.size() > 1 && !caption.text.isEmpty()) {
|
||||
auto message = MainWidget::MessageToSend(options.history);
|
||||
auto message = MessageToSend(options.history);
|
||||
message.textWithTags = std::move(caption);
|
||||
message.replyTo = options.replyTo;
|
||||
message.clearDraft = false;
|
||||
App::main()->sendMessage(message);
|
||||
sendMessage(std::move(message));
|
||||
caption = TextWithTags();
|
||||
}
|
||||
|
||||
const auto to = FileLoadTaskOptions(options);
|
||||
const auto to = fileLoadTaskOptions(options);
|
||||
if (album) {
|
||||
album->silent = to.silent;
|
||||
}
|
||||
@@ -3871,7 +3911,7 @@ void ApiWrap::sendFile(
|
||||
const QByteArray &fileContent,
|
||||
SendMediaType type,
|
||||
const SendOptions &options) {
|
||||
auto to = FileLoadTaskOptions(options);
|
||||
const auto to = fileLoadTaskOptions(options);
|
||||
auto caption = TextWithTags();
|
||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||
QString(),
|
||||
@@ -3941,6 +3981,212 @@ void ApiWrap::cancelLocalItem(not_null<HistoryItem*> item) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
const auto history = message.history;
|
||||
const auto peer = history->peer;
|
||||
auto &textWithTags = message.textWithTags;
|
||||
|
||||
auto options = ApiWrap::SendOptions(history);
|
||||
options.clearDraft = message.clearDraft;
|
||||
options.replyTo = message.replyTo;
|
||||
options.generateLocal = true;
|
||||
options.webPageId = message.webPageId;
|
||||
sendAction(options);
|
||||
|
||||
if (!peer->canWrite()) {
|
||||
return;
|
||||
}
|
||||
Local::saveRecentSentHashtags(textWithTags.text);
|
||||
|
||||
auto sending = TextWithEntities();
|
||||
auto left = TextWithEntities {
|
||||
textWithTags.text,
|
||||
ConvertTextTagsToEntities(textWithTags.tags)
|
||||
};
|
||||
auto prepareFlags = Ui::ItemTextOptions(
|
||||
history,
|
||||
_session->user()).flags;
|
||||
TextUtilities::PrepareForSending(left, prepareFlags);
|
||||
|
||||
HistoryItem *lastMessage = nullptr;
|
||||
|
||||
while (TextUtilities::CutPart(sending, left, MaxMessageSize)) {
|
||||
auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
|
||||
auto randomId = rand_value<uint64>();
|
||||
|
||||
TextUtilities::Trim(sending);
|
||||
|
||||
App::historyRegRandom(randomId, newId);
|
||||
App::historyRegSentData(randomId, peer->id, sending.text);
|
||||
|
||||
MTPstring msgText(MTP_string(sending.text));
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_entities;
|
||||
auto sendFlags = MTPmessages_SendMessage::Flags(0);
|
||||
if (message.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
MTPMessageMedia media = MTP_messageMediaEmpty();
|
||||
if (message.webPageId == CancelledWebPageId) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage;
|
||||
} else if (message.webPageId) {
|
||||
auto page = _session->data().webpage(message.webPageId);
|
||||
media = MTP_messageMediaWebPage(
|
||||
MTP_webPagePending(
|
||||
MTP_long(page->id),
|
||||
MTP_int(page->pendingTill)));
|
||||
flags |= MTPDmessage::Flag::f_media;
|
||||
}
|
||||
bool channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
bool silentPost = channelPost
|
||||
&& _session->data().notifySilentPosts(peer);
|
||||
if (channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
}
|
||||
if (!channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_from_id;
|
||||
} else if (peer->asChannel()->addsSignature()) {
|
||||
flags |= MTPDmessage::Flag::f_post_author;
|
||||
}
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
|
||||
}
|
||||
auto localEntities = TextUtilities::EntitiesToMTP(sending.entities);
|
||||
auto sentEntities = TextUtilities::EntitiesToMTP(sending.entities, TextUtilities::ConvertOption::SkipLocal);
|
||||
if (!sentEntities.v.isEmpty()) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
|
||||
}
|
||||
if (message.clearDraft) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
|
||||
history->clearCloudDraft();
|
||||
history->setSentDraftText(QString());
|
||||
}
|
||||
auto messageFromId = channelPost ? 0 : _session->userId();
|
||||
auto messagePostAuthor = channelPost
|
||||
? App::peerName(_session->user())
|
||||
: QString();
|
||||
lastMessage = history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
MTP_int(messageFromId),
|
||||
peerToMTP(peer->id),
|
||||
MTPnullFwdHeader,
|
||||
MTPint(),
|
||||
MTP_int(message.replyTo),
|
||||
MTP_int(unixtime()),
|
||||
msgText,
|
||||
media,
|
||||
MTPnullMarkup,
|
||||
localEntities,
|
||||
MTP_int(1),
|
||||
MTPint(),
|
||||
MTP_string(messagePostAuthor),
|
||||
MTPlong()),
|
||||
NewMessageUnread);
|
||||
history->sendRequestId = request(MTPmessages_SendMessage(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(message.replyTo),
|
||||
msgText,
|
||||
MTP_long(randomId),
|
||||
MTPnullMarkup,
|
||||
sentEntities
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result, randomId);
|
||||
history->clearSentDraftText(QString());
|
||||
}).fail([=](const RPCError &error) {
|
||||
sendMessageFail(error);
|
||||
history->clearSentDraftText(QString());
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
}
|
||||
|
||||
if (const auto main = App::main()) {
|
||||
main->finishForwarding(history);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::sendInlineResult(
|
||||
not_null<UserData*> bot,
|
||||
not_null<InlineBots::Result*> data,
|
||||
const SendOptions &options) {
|
||||
Auth().api().sendAction(options);
|
||||
|
||||
const auto history = options.history;
|
||||
const auto peer = history->peer;
|
||||
const auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
|
||||
const auto randomId = rand_value<uint64>();
|
||||
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
|
||||
if (options.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
bool channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
bool silentPost = channelPost && _session->data().notifySilentPosts(peer);
|
||||
if (channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
}
|
||||
if (!channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_from_id;
|
||||
} else if (peer->asChannel()->addsSignature()) {
|
||||
flags |= MTPDmessage::Flag::f_post_author;
|
||||
}
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
|
||||
}
|
||||
if (bot) {
|
||||
flags |= MTPDmessage::Flag::f_via_bot_id;
|
||||
}
|
||||
|
||||
auto messageFromId = channelPost ? 0 : Auth().userId();
|
||||
auto messagePostAuthor = channelPost
|
||||
? App::peerName(Auth().user())
|
||||
: QString();
|
||||
MTPint messageDate = MTP_int(unixtime());
|
||||
UserId messageViaBotId = bot ? peerToUser(bot->id) : 0;
|
||||
MsgId messageId = newId.msg;
|
||||
|
||||
App::historyRegRandom(randomId, newId);
|
||||
|
||||
data->addToHistory(
|
||||
history,
|
||||
flags,
|
||||
messageId,
|
||||
messageFromId,
|
||||
messageDate,
|
||||
messageViaBotId,
|
||||
options.replyTo,
|
||||
messagePostAuthor);
|
||||
|
||||
history->clearCloudDraft();
|
||||
history->setSentDraftText(QString());
|
||||
|
||||
history->sendRequestId = request(MTPmessages_SendInlineBotResult(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(options.replyTo),
|
||||
MTP_long(randomId),
|
||||
MTP_long(data->getQueryId()),
|
||||
MTP_string(data->getId())
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result, randomId);
|
||||
history->clearSentDraftText(QString());
|
||||
}).fail([=](const RPCError &error) {
|
||||
sendMessageFail(error);
|
||||
history->clearSentDraftText(QString());
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
|
||||
if (const auto main = App::main()) {
|
||||
main->finishForwarding(history);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::uploadAlbumMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MessageGroupId &groupId,
|
||||
@@ -4176,10 +4422,21 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||
).send();
|
||||
}
|
||||
|
||||
FileLoadTo ApiWrap::fileLoadTaskOptions(const SendOptions &options) const {
|
||||
const auto peer = options.history->peer;
|
||||
return FileLoadTo(
|
||||
peer->id,
|
||||
_session->data().notifySilentPosts(peer),
|
||||
options.replyTo);
|
||||
}
|
||||
|
||||
void ApiWrap::readServerHistory(not_null<History*> history) {
|
||||
if (history->unreadCount()) {
|
||||
readServerHistoryForce(history);
|
||||
}
|
||||
if (history->unreadMark()) {
|
||||
changeDialogUnreadMark(history, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::readServerHistoryForce(not_null<History*> history) {
|
||||
|
||||
@@ -21,6 +21,11 @@ class AuthSession;
|
||||
struct MessageGroupId;
|
||||
struct SendingAlbum;
|
||||
enum class SendMediaType;
|
||||
struct FileLoadTo;
|
||||
|
||||
namespace InlineBots {
|
||||
class Result;
|
||||
} // namespace InlineBots
|
||||
|
||||
namespace Storage {
|
||||
enum class SharedMediaType : signed char;
|
||||
@@ -80,6 +85,8 @@ public:
|
||||
//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 requestFullPeer(PeerData *peer);
|
||||
void requestPeer(PeerData *peer);
|
||||
@@ -221,8 +228,7 @@ public:
|
||||
Fn<void()> callbackNotModified = nullptr);
|
||||
|
||||
struct SendOptions {
|
||||
SendOptions(not_null<History*> history) : history(history) {
|
||||
}
|
||||
SendOptions(not_null<History*> history);
|
||||
|
||||
not_null<History*> history;
|
||||
MsgId replyTo = 0;
|
||||
@@ -277,6 +283,21 @@ public:
|
||||
bool silent);
|
||||
void cancelLocalItem(not_null<HistoryItem*> item);
|
||||
|
||||
struct MessageToSend {
|
||||
MessageToSend(not_null<History*> history);
|
||||
|
||||
not_null<History*> history;
|
||||
TextWithTags textWithTags;
|
||||
MsgId replyTo = 0;
|
||||
WebPageId webPageId = 0;
|
||||
bool clearDraft = true;
|
||||
};
|
||||
void sendMessage(MessageToSend &&message);
|
||||
void sendInlineResult(
|
||||
not_null<UserData*> bot,
|
||||
not_null<InlineBots::Result*> data,
|
||||
const SendOptions &options);
|
||||
|
||||
~ApiWrap();
|
||||
|
||||
private:
|
||||
@@ -439,6 +460,7 @@ private:
|
||||
const MTPInputMedia &media,
|
||||
bool silent,
|
||||
uint64 randomId);
|
||||
FileLoadTo fileLoadTaskOptions(const SendOptions &options) const;
|
||||
|
||||
void readFeeds();
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_history.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "data/data_abstract_structure.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_session.h"
|
||||
@@ -50,8 +51,7 @@ namespace {
|
||||
|
||||
UserData *self = nullptr;
|
||||
|
||||
using PeersData = QHash<PeerId, PeerData*>;
|
||||
PeersData peersData;
|
||||
std::unordered_map<PeerId, std::unique_ptr<PeerData>> peersData;
|
||||
|
||||
using LocationsData = QHash<LocationCoords, LocationData*>;
|
||||
LocationsData locationsData;
|
||||
@@ -747,7 +747,7 @@ namespace App {
|
||||
} else if (chat->version <= d.vversion.v && chat->count > 0) {
|
||||
chat->version = d.vversion.v;
|
||||
auto canEdit = chat->canEdit();
|
||||
UserData *user = App::userLoaded(d.vuser_id.v);
|
||||
const auto user = App::userLoaded(d.vuser_id.v);
|
||||
if (user) {
|
||||
if (chat->participants.empty()) {
|
||||
if (chat->count > 0) {
|
||||
@@ -1074,40 +1074,43 @@ namespace App {
|
||||
}
|
||||
|
||||
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) {
|
||||
if (!id) return nullptr;
|
||||
if (!id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto i = peersData.constFind(id);
|
||||
auto i = peersData.find(id);
|
||||
if (i == peersData.cend()) {
|
||||
PeerData *newData = nullptr;
|
||||
if (peerIsUser(id)) {
|
||||
newData = new UserData(id);
|
||||
} else if (peerIsChat(id)) {
|
||||
newData = new ChatData(id);
|
||||
} else if (peerIsChannel(id)) {
|
||||
newData = new ChannelData(id);
|
||||
}
|
||||
Assert(newData != nullptr);
|
||||
auto newData = [&]() -> std::unique_ptr<PeerData> {
|
||||
if (peerIsUser(id)) {
|
||||
return std::make_unique<UserData>(id);
|
||||
} else if (peerIsChat(id)) {
|
||||
return std::make_unique<ChatData>(id);
|
||||
} else if (peerIsChannel(id)) {
|
||||
return std::make_unique<ChannelData>(id);
|
||||
}
|
||||
Unexpected("Peer id type.");
|
||||
}();
|
||||
|
||||
newData->input = MTPinputPeer(MTP_inputPeerEmpty());
|
||||
i = peersData.insert(id, newData);
|
||||
i = peersData.emplace(id, std::move(newData)).first;
|
||||
}
|
||||
switch (restriction) {
|
||||
case PeerData::MinimalLoaded: {
|
||||
if (i.value()->loadedStatus == PeerData::NotLoaded) {
|
||||
if (i->second->loadedStatus == PeerData::NotLoaded) {
|
||||
return nullptr;
|
||||
}
|
||||
} break;
|
||||
case PeerData::FullLoaded: {
|
||||
if (i.value()->loadedStatus != PeerData::FullLoaded) {
|
||||
if (i->second->loadedStatus != PeerData::FullLoaded) {
|
||||
return nullptr;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return i.value();
|
||||
return i->second.get();
|
||||
}
|
||||
|
||||
void enumerateUsers(Fn<void(not_null<UserData*>)> action) {
|
||||
for_const (const auto peer, peersData) {
|
||||
for (const auto &[peerId, peer] : peersData) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
action(user);
|
||||
}
|
||||
@@ -1116,9 +1119,9 @@ namespace App {
|
||||
|
||||
void enumerateChatsChannels(
|
||||
Fn<void(not_null<PeerData*>)> action) {
|
||||
for_const (const auto peer, peersData) {
|
||||
for (const auto &[peerId, peer] : peersData) {
|
||||
if (!peer->isUser()) {
|
||||
action(peer);
|
||||
action(peer.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1128,10 +1131,10 @@ namespace App {
|
||||
}
|
||||
|
||||
PeerData *peerByName(const QString &username) {
|
||||
QString uname(username.trimmed());
|
||||
for_const (PeerData *peer, peersData) {
|
||||
const auto uname = username.trimmed();
|
||||
for (const auto &[peerId, peer] : peersData) {
|
||||
if (!peer->userName().compare(uname, Qt::CaseInsensitive)) {
|
||||
return peer;
|
||||
return peer.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -1246,24 +1249,16 @@ namespace App {
|
||||
void historyClearMsgs() {
|
||||
::dependentItems.clear();
|
||||
|
||||
QVector<HistoryItem*> toDelete;
|
||||
for_const (auto item, msgsData) {
|
||||
if (!item->mainView()) {
|
||||
toDelete.push_back(item);
|
||||
}
|
||||
}
|
||||
for_const (auto &chMsgsData, channelMsgsData) {
|
||||
for_const (auto item, chMsgsData) {
|
||||
if (!item->mainView()) {
|
||||
toDelete.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
msgsData.clear();
|
||||
channelMsgsData.clear();
|
||||
for_const (auto item, toDelete) {
|
||||
const auto oldData = base::take(msgsData);
|
||||
const auto oldChannelData = base::take(channelMsgsData);
|
||||
for (const auto item : oldData) {
|
||||
delete item;
|
||||
}
|
||||
for (const auto &data : oldChannelData) {
|
||||
for (const auto item : data) {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
clearMousedItems();
|
||||
}
|
||||
@@ -1275,10 +1270,7 @@ namespace App {
|
||||
cSetSavedPeersByTime(SavedPeersByTime());
|
||||
cSetRecentInlineBots(RecentInlineBots());
|
||||
|
||||
for_const (auto peer, ::peersData) {
|
||||
delete peer;
|
||||
}
|
||||
::peersData.clear();
|
||||
peersData.clear();
|
||||
|
||||
if (AuthSession::Exists()) {
|
||||
Auth().api().clearWebPageRequests();
|
||||
@@ -1598,7 +1590,13 @@ namespace App {
|
||||
}
|
||||
|
||||
void quit() {
|
||||
if (quitting()) return;
|
||||
if (quitting()) {
|
||||
return;
|
||||
} else if (AuthSession::Exists()
|
||||
&& Auth().data().exportInProgress()) {
|
||||
Auth().data().stopExportWithConfirmation([] { App::quit(); });
|
||||
return;
|
||||
}
|
||||
setLaunchState(QuitRequested);
|
||||
|
||||
if (auto window = wnd()) {
|
||||
@@ -1625,11 +1623,9 @@ namespace App {
|
||||
}
|
||||
|
||||
void restart() {
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
bool updateReady = (Core::UpdateChecker().state() == Core::UpdateChecker::State::Ready);
|
||||
#else // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
bool updateReady = false;
|
||||
#endif // else for !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
using namespace Core;
|
||||
const auto updateReady = !UpdaterDisabled()
|
||||
&& (UpdateChecker().state() == UpdateChecker::State::Ready);
|
||||
if (updateReady) {
|
||||
cSetRestartingUpdate(true);
|
||||
} else {
|
||||
|
||||
@@ -64,11 +64,10 @@ QString _escapeFrom7bit(const QString &str) {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool StartUrlRequiresActivate(const QString &url) {
|
||||
bool InternalPassportLink(const QString &url) {
|
||||
const auto urlTrimmed = url.trimmed();
|
||||
if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)
|
||||
|| Messenger::Instance().locked()) {
|
||||
return true;
|
||||
if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)) {
|
||||
return false;
|
||||
}
|
||||
const auto command = urlTrimmed.midRef(qstr("tg://").size());
|
||||
|
||||
@@ -78,11 +77,23 @@ bool StartUrlRequiresActivate(const QString &url) {
|
||||
qsl("^passport/?\\?(.+)(#|$)"),
|
||||
command,
|
||||
matchOptions);
|
||||
const auto authLegacyMatch = regex_match(
|
||||
qsl("^resolve/?\\?domain=telegrampassport&(.+)(#|$)"),
|
||||
const auto usernameMatch = regex_match(
|
||||
qsl("^resolve/?\\?(.+)(#|$)"),
|
||||
command,
|
||||
matchOptions);
|
||||
return !authMatch->hasMatch() && !authLegacyMatch->hasMatch();
|
||||
const auto usernameValue = usernameMatch->hasMatch()
|
||||
? url_parse_params(
|
||||
usernameMatch->captured(1),
|
||||
UrlParamNameTransform::ToLower).value(qsl("domain"))
|
||||
: QString();
|
||||
const auto authLegacy = (usernameValue == qstr("telegrampassport"));
|
||||
return authMatch->hasMatch() || authLegacy;
|
||||
}
|
||||
|
||||
bool StartUrlRequiresActivate(const QString &url) {
|
||||
return Messenger::Instance().locked()
|
||||
? true
|
||||
: !InternalPassportLink(url);
|
||||
}
|
||||
|
||||
Application::Application(
|
||||
@@ -91,10 +102,9 @@ Application::Application(
|
||||
char **argv)
|
||||
: QApplication(argc, argv)
|
||||
, _launcher(launcher)
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
, _updateChecker(std::make_unique<Core::UpdateChecker>())
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
{
|
||||
, _updateChecker(Core::UpdaterDisabled()
|
||||
? nullptr
|
||||
: std::make_unique<Core::UpdateChecker>()) {
|
||||
const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
|
||||
char h[33] = { 0 };
|
||||
hashMd5Hex(d.constData(), d.size(), h);
|
||||
@@ -204,13 +214,13 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
|
||||
}
|
||||
#endif // !Q_OS_WINRT
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if (!cNoStartUpdate() && Core::checkReadyUpdate()) {
|
||||
if (!Core::UpdaterDisabled()
|
||||
&& !cNoStartUpdate()
|
||||
&& Core::checkReadyUpdate()) {
|
||||
cSetRestartingUpdate(true);
|
||||
DEBUG_LOG(("Application Info: installing update instead of starting app..."));
|
||||
return App::quit();
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
singleInstanceChecked();
|
||||
}
|
||||
@@ -384,9 +394,7 @@ void Application::closeApplication() {
|
||||
|
||||
_localSocket.close();
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
_updateChecker = nullptr;
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
}
|
||||
|
||||
inline Application *application() {
|
||||
|
||||
@@ -12,6 +12,7 @@ class Launcher;
|
||||
class UpdateChecker;
|
||||
} // namespace Core
|
||||
|
||||
bool InternalPassportLink(const QString &url);
|
||||
bool StartUrlRequiresActivate(const QString &url);
|
||||
|
||||
class Application : public QApplication {
|
||||
@@ -61,9 +62,7 @@ private:
|
||||
void singleInstanceChecked();
|
||||
|
||||
private:
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
std::unique_ptr<Core::UpdateChecker> _updateChecker;
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <gsl/gsl>
|
||||
#include <gsl/gsl_byte>
|
||||
|
||||
namespace bytes {
|
||||
@@ -134,4 +135,7 @@ vector concatenate(SpanRange args) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Implemented in base/openssl_help.h
|
||||
void set_random(span destination);
|
||||
|
||||
} // namespace bytes
|
||||
|
||||
@@ -417,8 +417,9 @@ public:
|
||||
if (range.first == range.second) {
|
||||
return 0;
|
||||
}
|
||||
const auto result = (range.second - range.first);
|
||||
impl().erase(range.first, range.second);
|
||||
return (range.second - range.first);
|
||||
return result;
|
||||
}
|
||||
|
||||
iterator erase(const_iterator where) {
|
||||
|
||||
@@ -297,8 +297,9 @@ public:
|
||||
if (range.first == range.second) {
|
||||
return 0;
|
||||
}
|
||||
const auto result = (range.second - range.first);
|
||||
impl().erase(range.first, range.second);
|
||||
return (range.second - range.first);
|
||||
return result;
|
||||
}
|
||||
|
||||
iterator erase(const_iterator where) {
|
||||
|
||||
28
Telegram/SourceFiles/base/match_method.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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 <rpl/details/callable.h>
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Data, typename Method, typename ...Methods>
|
||||
inline decltype(auto) match_method(
|
||||
Data &&data,
|
||||
Method &&method,
|
||||
Methods &&...methods) {
|
||||
if constexpr (rpl::details::is_callable_plain_v<Method, Data&&>) {
|
||||
return std::forward<Method>(method)(std::forward<Data>(data));
|
||||
} else {
|
||||
return match_method(
|
||||
std::forward<Data>(data),
|
||||
std::forward<Methods>(methods)...);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
@@ -109,6 +109,15 @@ public:
|
||||
return _impl.template get_unchecked<T>();
|
||||
}
|
||||
|
||||
template <typename ...Methods>
|
||||
decltype(auto) match(Methods &&...methods) {
|
||||
return base::match(_impl, std::forward<Methods>(methods)...);
|
||||
}
|
||||
template <typename ...Methods>
|
||||
decltype(auto) match(Methods &&...methods) const {
|
||||
return base::match(_impl, std::forward<Methods>(methods)...);
|
||||
}
|
||||
|
||||
private:
|
||||
variant<none_type, Types...> _impl;
|
||||
|
||||
@@ -124,6 +133,20 @@ inline const T *get_if(const optional_variant<Types...> *v) {
|
||||
return (v && v->template is<T>()) ? &v->template get_unchecked<T>() : nullptr;
|
||||
}
|
||||
|
||||
template <typename ...Types, typename ...Methods>
|
||||
inline decltype(auto) match(
|
||||
optional_variant<Types...> &value,
|
||||
Methods &&...methods) {
|
||||
return value.match(std::forward<Methods>(methods)...);
|
||||
}
|
||||
|
||||
template <typename ...Types, typename ...Methods>
|
||||
inline decltype(auto) match(
|
||||
const optional_variant<Types...> &value,
|
||||
Methods &&...methods) {
|
||||
return value.match(std::forward<Methods>(methods)...);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
class optional;
|
||||
|
||||
@@ -160,12 +183,17 @@ class optional : public optional_variant<Type> {
|
||||
public:
|
||||
using parent::parent;
|
||||
|
||||
Type &operator*() {
|
||||
Type &operator*() & {
|
||||
Expects(parent::template is<Type>());
|
||||
|
||||
return parent::template get_unchecked<Type>();
|
||||
}
|
||||
const Type &operator*() const {
|
||||
Type &&operator*() && {
|
||||
Expects(parent::template is<Type>());
|
||||
|
||||
return std::move(parent::template get_unchecked<Type>());
|
||||
}
|
||||
const Type &operator*() const & {
|
||||
Expects(parent::template is<Type>());
|
||||
|
||||
return parent::template get_unchecked<Type>();
|
||||
|
||||
@@ -8,6 +8,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/qthelp_url.h"
|
||||
|
||||
namespace qthelp {
|
||||
namespace {
|
||||
|
||||
QRegularExpression RegExpProtocol() {
|
||||
static const auto result = QRegularExpression("^([a-zA-Z]+)://");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsGoodProtocol(const QString &protocol) {
|
||||
const auto equals = [&](QLatin1String string) {
|
||||
return protocol.compare(string, Qt::CaseInsensitive) == 0;
|
||||
};
|
||||
return equals(qstr("http"))
|
||||
|| equals(qstr("https"))
|
||||
|| equals(qstr("tg"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QMap<QString, QString> url_parse_params(
|
||||
const QString ¶ms,
|
||||
@@ -55,4 +72,24 @@ QString url_append_query_or_hash(const QString &url, const QString &add) {
|
||||
+ add;
|
||||
}
|
||||
|
||||
QString validate_url(const QString &value) {
|
||||
const auto trimmed = value.trimmed();
|
||||
if (trimmed.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
const auto match = TextUtilities::RegExpDomainExplicit().match(trimmed);
|
||||
if (!match.hasMatch()) {
|
||||
const auto domain = TextUtilities::RegExpDomain().match(trimmed);
|
||||
if (!domain.hasMatch() || domain.capturedStart() != 0) {
|
||||
return QString();
|
||||
}
|
||||
return qstr("http://") + trimmed;
|
||||
} else if (match.capturedStart() != 0) {
|
||||
return QString();
|
||||
}
|
||||
const auto protocolMatch = RegExpProtocol().match(trimmed);
|
||||
Assert(protocolMatch.hasMatch());
|
||||
return IsGoodProtocol(protocolMatch.captured(1)) ? trimmed : QString();
|
||||
}
|
||||
|
||||
} // namespace qthelp
|
||||
|
||||
@@ -30,4 +30,6 @@ QString url_append_query_or_hash(const QString &url, const QString &add);
|
||||
|
||||
bool is_ipv6(const QString &ip);
|
||||
|
||||
QString validate_url(const QString &value);
|
||||
|
||||
} // namespace qthelp
|
||||
|
||||
@@ -7,7 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QThread>
|
||||
#include "base/observer.h"
|
||||
#include "base/flat_map.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
|
||||
@@ -69,11 +69,11 @@ public:
|
||||
|
||||
unique_any(const unique_any &other) = delete;
|
||||
unique_any &operator=(const unique_any &other) = delete;
|
||||
|
||||
|
||||
unique_any(unique_any &&other) noexcept
|
||||
: _impl(std::move(other._impl)) {
|
||||
}
|
||||
|
||||
|
||||
unique_any &operator=(unique_any &&other) noexcept {
|
||||
_impl = std::move(other._impl);
|
||||
return *this;
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
std::forward<Value>(other),
|
||||
std::is_copy_constructible<std::decay_t<Value>>()) {
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename Value,
|
||||
typename = std::enable_if_t<
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename Value,
|
||||
typename ...Args,
|
||||
@@ -143,7 +143,7 @@ private:
|
||||
unique_any(Value &&other, std::true_type)
|
||||
: _impl(std::forward<Value>(other)) {
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename Value,
|
||||
typename = std::enable_if_t<
|
||||
@@ -177,7 +177,7 @@ inline void swap(unique_any &a, unique_any &b) noexcept {
|
||||
template <
|
||||
typename Value,
|
||||
typename ...Args>
|
||||
inline auto make_any(Args &&...args)
|
||||
inline auto make_any(Args &&...args)
|
||||
-> std::enable_if_t<
|
||||
std::is_copy_constructible_v<std::decay_t<Value>>,
|
||||
unique_any> {
|
||||
@@ -187,7 +187,7 @@ inline auto make_any(Args &&...args)
|
||||
template <
|
||||
typename Value,
|
||||
typename ...Args>
|
||||
inline auto make_any(Args &&...args)
|
||||
inline auto make_any(Args &&...args)
|
||||
-> std::enable_if_t<
|
||||
!std::is_copy_constructible_v<std::decay_t<Value>>
|
||||
&& std::is_move_constructible_v<std::decay_t<Value>>,
|
||||
|
||||
@@ -124,7 +124,10 @@ public:
|
||||
_impl.swap(other._impl);
|
||||
}
|
||||
|
||||
template <typename ...OtherArgs>
|
||||
template <
|
||||
typename ...OtherArgs,
|
||||
typename = decltype(std::declval<std::function<Return(Args...)>>()(
|
||||
std::declval<OtherArgs>()...))>
|
||||
Return operator()(OtherArgs &&...args) {
|
||||
return _impl(std::forward<OtherArgs>(args)...);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace base {
|
||||
namespace details {
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <rpl/details/type_list.h>
|
||||
#include "base/match_method.h"
|
||||
#include "base/assertion.h"
|
||||
|
||||
// We use base::variant<> alias and base::get_if() helper while we don't have std::variant<>.
|
||||
namespace base {
|
||||
@@ -25,20 +28,79 @@ inline const T *get_if(const variant<Types...> *v) {
|
||||
return (v && v->template is<T>()) ? &v->template get_unchecked<T>() : nullptr;
|
||||
}
|
||||
|
||||
// Simplified visit
|
||||
template <typename Method, typename... Types>
|
||||
inline auto visit(Method &&method, const variant<Types...> &value) {
|
||||
return value.match(std::forward<Method>(method));
|
||||
namespace type_list = rpl::details::type_list;
|
||||
|
||||
template <typename ...Types>
|
||||
struct normalized_variant {
|
||||
using list = type_list::list<Types...>;
|
||||
using distinct = type_list::distinct_t<list>;
|
||||
using type = std::conditional_t<
|
||||
type_list::size_v<distinct> == 1,
|
||||
type_list::get_t<0, distinct>,
|
||||
type_list::extract_to_t<distinct, base::variant>>;
|
||||
};
|
||||
|
||||
template <typename ...Types>
|
||||
using normalized_variant_t
|
||||
= typename normalized_variant<Types...>::type;
|
||||
|
||||
template <typename TypeList, typename Variant, typename ...Methods>
|
||||
struct match_helper;
|
||||
|
||||
template <
|
||||
typename Type,
|
||||
typename ...Types,
|
||||
typename Variant,
|
||||
typename ...Methods>
|
||||
struct match_helper<type_list::list<Type, Types...>, Variant, Methods...> {
|
||||
static decltype(auto) call(Variant &value, Methods &&...methods) {
|
||||
if (const auto v = get_if<Type>(&value)) {
|
||||
return match_method(
|
||||
*v,
|
||||
std::forward<Methods>(methods)...);
|
||||
}
|
||||
return match_helper<
|
||||
type_list::list<Types...>,
|
||||
Variant,
|
||||
Methods...>::call(
|
||||
value,
|
||||
std::forward<Methods>(methods)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
typename Type,
|
||||
typename Variant,
|
||||
typename ...Methods>
|
||||
struct match_helper<type_list::list<Type>, Variant, Methods...> {
|
||||
static decltype(auto) call(Variant &value, Methods &&...methods) {
|
||||
if (const auto v = get_if<Type>(&value)) {
|
||||
return match_method(
|
||||
*v,
|
||||
std::forward<Methods>(methods)...);
|
||||
}
|
||||
Unexpected("Valueless variant in base::match().");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ...Types, typename ...Methods>
|
||||
inline decltype(auto) match(
|
||||
variant<Types...> &value,
|
||||
Methods &&...methods) {
|
||||
return match_helper<
|
||||
type_list::list<Types...>,
|
||||
variant<Types...>,
|
||||
Methods...>::call(value, std::forward<Methods>(methods)...);
|
||||
}
|
||||
|
||||
template <typename Method, typename... Types>
|
||||
inline auto visit(Method &&method, variant<Types...> &value) {
|
||||
return value.match(std::forward<Method>(method));
|
||||
}
|
||||
|
||||
template <typename Method, typename... Types>
|
||||
inline auto visit(Method &&method, variant<Types...> &&value) {
|
||||
return value.match(std::forward<Method>(method));
|
||||
template <typename ...Types, typename ...Methods>
|
||||
inline decltype(auto) match(
|
||||
const variant<Types...> &value,
|
||||
Methods &&...methods) {
|
||||
return match_helper<
|
||||
type_list::list<Types...>,
|
||||
const variant<Types...>,
|
||||
Methods...>::call(value, std::forward<Methods>(methods)...);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
namespace base {
|
||||
namespace details {
|
||||
@@ -315,24 +316,3 @@ struct guard_traits<
|
||||
};
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#ifdef QT_VERSION
|
||||
template <typename Lambda>
|
||||
inline void InvokeQueued(const base::has_weak_ptr *context, Lambda &&lambda) {
|
||||
auto callback = [
|
||||
guard = base::make_weak(context),
|
||||
lambda = std::forward<Lambda>(lambda)
|
||||
] {
|
||||
if (guard) {
|
||||
lambda();
|
||||
}
|
||||
};
|
||||
QObject proxy;
|
||||
QObject::connect(
|
||||
&proxy,
|
||||
&QObject::destroyed,
|
||||
QCoreApplication::instance(),
|
||||
std::move(callback),
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
#endif // QT_VERSION
|
||||
|
||||
@@ -31,18 +31,18 @@ void AboutBox::prepare() {
|
||||
|
||||
addButton(langFactory(lng_close), [this] { closeBox(); });
|
||||
|
||||
const auto linkHook = [](const ClickHandlerPtr &link, auto button) {
|
||||
const auto linkFilter = [](const ClickHandlerPtr &link, auto button) {
|
||||
if (const auto url = dynamic_cast<UrlClickHandler*>(link.get())) {
|
||||
url->UrlClickHandler::onClick(button);
|
||||
url->UrlClickHandler::onClick({ button });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
_text3->setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]")));
|
||||
_text1->setClickHandlerHook(linkHook);
|
||||
_text2->setClickHandlerHook(linkHook);
|
||||
_text3->setClickHandlerHook(linkHook);
|
||||
_text1->setClickHandlerFilter(linkFilter);
|
||||
_text2->setClickHandlerFilter(linkFilter);
|
||||
_text3->setClickHandlerFilter(linkFilter);
|
||||
|
||||
_version->setClickedCallback([this] { showVersionHistory(); });
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ boxMediumSkip: 20px;
|
||||
boxButtonPadding: margins(8px, 12px, 13px, 12px);
|
||||
boxLayerButtonPadding: margins(8px, 8px, 8px, 8px);
|
||||
boxLabel: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 285px;
|
||||
minWidth: 274px;
|
||||
align: align(topleft);
|
||||
style: boxLabelStyle;
|
||||
}
|
||||
|
||||
@@ -738,8 +738,7 @@ ProxyData ProxyBox::collectData() {
|
||||
} else if ((result.type == Type::Http || result.type == Type::Socks5)
|
||||
&& !result.password.isEmpty() && result.user.isEmpty()) {
|
||||
_user->showError();
|
||||
} else if (result.type == Type::Mtproto
|
||||
&& result.password.size() != 32) {
|
||||
} else if (result.type == Type::Mtproto && !result.valid()) {
|
||||
_secret->showError();
|
||||
} else if (!result) {
|
||||
_host->showError();
|
||||
@@ -850,7 +849,7 @@ void ProxyBox::setupMtprotoCredentials(const ProxyData &data) {
|
||||
st::connectionUserInputField,
|
||||
langFactory(lng_connection_proxy_secret_ph),
|
||||
(data.type == Type::Mtproto) ? data.password : QString());
|
||||
_secret->setMaxLength(32);
|
||||
_secret->setMaxLength(ProxyData::MaxMtprotoPasswordLength());
|
||||
_secret->move(0, 0);
|
||||
_secret->heightValue(
|
||||
) | rpl::start_with_next([=, wrap = secretWrap.data()](int height) {
|
||||
@@ -1107,7 +1106,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
|
||||
item.checker->connectToServer(
|
||||
item.data.host,
|
||||
item.data.port,
|
||||
MTP::ProtocolSecretFromPassword(item.data.password),
|
||||
item.data.secretFromMtprotoPassword(),
|
||||
dcId);
|
||||
} else {
|
||||
const auto options = mtproto->dcOptions()->lookup(
|
||||
|
||||
@@ -91,7 +91,7 @@ void DownloadPathBox::onEditPath() {
|
||||
}();
|
||||
const auto handleFolder = [=](const QString &result) {
|
||||
if (!result.isEmpty()) {
|
||||
_path = result + '/';
|
||||
_path = result.endsWith('/') ? result : (result + '/');
|
||||
_pathBookmark = psDownloadPathBookmark(_path);
|
||||
setPathText(QDir::toNativeSeparators(_path));
|
||||
_group->setValue(Directory::Custom);
|
||||
|
||||
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/window_controller.h"
|
||||
#include "mainwidget.h"
|
||||
#include "layout.h"
|
||||
#include "auth_session.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
@@ -69,8 +70,22 @@ EditCaptionBox::EditCaptionBox(
|
||||
} else {
|
||||
_thumbw = st::msgFileThumbSize;
|
||||
}
|
||||
auto options = Images::Option::Smooth | Images::Option::RoundedSmall | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::RoundedBottomLeft | Images::Option::RoundedBottomRight;
|
||||
_thumb = Images::pixmap(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize);
|
||||
_thumbnailImage = image;
|
||||
_refreshThumbnail = [=] {
|
||||
auto options = Images::Option::Smooth
|
||||
| Images::Option::RoundedSmall
|
||||
| Images::Option::RoundedTopLeft
|
||||
| Images::Option::RoundedTopRight
|
||||
| Images::Option::RoundedBottomLeft
|
||||
| Images::Option::RoundedBottomRight;
|
||||
_thumb = Images::pixmap(
|
||||
image->pix().toImage(),
|
||||
_thumbw * cIntRetinaFactor(),
|
||||
0,
|
||||
options,
|
||||
st::msgFileThumbSize,
|
||||
st::msgFileThumbSize);
|
||||
};
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
@@ -88,6 +103,9 @@ EditCaptionBox::EditCaptionBox(
|
||||
_isImage = doc->isImage();
|
||||
_isAudio = (doc->isVoiceMessage() || doc->isAudioFile());
|
||||
}
|
||||
if (_refreshThumbnail) {
|
||||
_refreshThumbnail();
|
||||
}
|
||||
} else {
|
||||
int32 maxW = 0, maxH = 0;
|
||||
if (_animated) {
|
||||
@@ -106,13 +124,33 @@ EditCaptionBox::EditCaptionBox(
|
||||
maxH = limitH;
|
||||
}
|
||||
}
|
||||
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth | Images::Option::Blurred, maxW, maxH);
|
||||
_thumbnailImage = image;
|
||||
_refreshThumbnail = [=] {
|
||||
const auto options = Images::Option::Smooth
|
||||
| Images::Option::Blurred;
|
||||
_thumb = image->pixNoCache(
|
||||
maxW * cIntRetinaFactor(),
|
||||
maxH * cIntRetinaFactor(),
|
||||
options,
|
||||
maxW,
|
||||
maxH);
|
||||
};
|
||||
prepareGifPreview(doc);
|
||||
} else {
|
||||
maxW = dimensions.width();
|
||||
maxH = dimensions.height();
|
||||
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth, maxW, maxH);
|
||||
_thumbnailImage = image;
|
||||
_refreshThumbnail = [=] {
|
||||
_thumb = image->pixNoCache(
|
||||
maxW * cIntRetinaFactor(),
|
||||
maxH * cIntRetinaFactor(),
|
||||
Images::Option::Smooth,
|
||||
maxW,
|
||||
maxH);
|
||||
};
|
||||
}
|
||||
_refreshThumbnail();
|
||||
|
||||
int32 tw = _thumb.width(), th = _thumb.height();
|
||||
if (!tw || !th) {
|
||||
tw = th = 1;
|
||||
@@ -132,11 +170,37 @@ EditCaptionBox::EditCaptionBox(
|
||||
}
|
||||
_thumbx = (st::boxWideWidth - _thumbw) / 2;
|
||||
|
||||
_thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
_thumb.setDevicePixelRatio(cRetinaFactor());
|
||||
const auto prepareBasicThumb = _refreshThumbnail;
|
||||
const auto scaleThumbDown = [=] {
|
||||
_thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(
|
||||
_thumbw * cIntRetinaFactor(),
|
||||
_thumbh * cIntRetinaFactor(),
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
_thumb.setDevicePixelRatio(cRetinaFactor());
|
||||
};
|
||||
_refreshThumbnail = [=] {
|
||||
prepareBasicThumb();
|
||||
scaleThumbDown();
|
||||
};
|
||||
scaleThumbDown();
|
||||
}
|
||||
Assert(_animated || _photo || _doc);
|
||||
|
||||
_thumbnailImageLoaded = _thumbnailImage
|
||||
? _thumbnailImage->loaded()
|
||||
: true;
|
||||
subscribe(Auth().downloaderTaskFinished(), [=] {
|
||||
if (!_thumbnailImageLoaded && _thumbnailImage->loaded()) {
|
||||
_thumbnailImageLoaded = true;
|
||||
_refreshThumbnail();
|
||||
update();
|
||||
}
|
||||
if (doc && doc->isAnimation() && doc->loaded() && !_gifPreview) {
|
||||
prepareGifPreview(doc);
|
||||
}
|
||||
});
|
||||
|
||||
_field.create(
|
||||
this,
|
||||
st::confirmCaptionArea,
|
||||
@@ -152,12 +216,10 @@ EditCaptionBox::EditCaptionBox(
|
||||
DefaultEditLinkCallback(_controller, _field));
|
||||
}
|
||||
|
||||
void EditCaptionBox::prepareGifPreview(DocumentData *document) {
|
||||
auto createGifPreview = [document] {
|
||||
return (document && document->isAnimation());
|
||||
};
|
||||
auto createGifPreviewResult = createGifPreview(); // Clang freeze workaround.
|
||||
if (createGifPreviewResult) {
|
||||
void EditCaptionBox::prepareGifPreview(not_null<DocumentData*> document) {
|
||||
if (_gifPreview) {
|
||||
return;
|
||||
} else if (document->isAnimation() && document->loaded()) {
|
||||
_gifPreview = Media::Clip::MakeReader(document, _msgId, [this](Media::Clip::Notification notification) {
|
||||
clipCallback(notification);
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ protected:
|
||||
|
||||
private:
|
||||
void updateBoxSize();
|
||||
void prepareGifPreview(DocumentData *document);
|
||||
void prepareGifPreview(not_null<DocumentData*> document);
|
||||
void clipCallback(Media::Clip::Notification notification);
|
||||
|
||||
void save();
|
||||
@@ -54,6 +54,9 @@ private:
|
||||
|
||||
not_null<Window::Controller*> _controller;
|
||||
FullMsgId _msgId;
|
||||
ImagePtr _thumbnailImage;
|
||||
bool _thumbnailImageLoaded = false;
|
||||
Fn<void()> _refreshThumbnail;
|
||||
bool _animated = false;
|
||||
bool _photo = false;
|
||||
bool _doc = false;
|
||||
|
||||
@@ -669,7 +669,10 @@ void EditColorBox::prepare() {
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
updateFromControls();
|
||||
updateRGBFields();
|
||||
updateHSVFields();
|
||||
updateResultField();
|
||||
update();
|
||||
}
|
||||
|
||||
void EditColorBox::setInnerFocus() {
|
||||
|
||||
@@ -21,6 +21,10 @@ constexpr auto kForeverHours = 24 * 365;
|
||||
|
||||
} // namespace
|
||||
|
||||
MuteSettingsBox::MuteSettingsBox(QWidget *parent, not_null<PeerData*> peer)
|
||||
: _peer(peer) {
|
||||
}
|
||||
|
||||
void MuteSettingsBox::prepare() {
|
||||
setTitle(langFactory(lng_disable_notifications_from_tray));
|
||||
auto y = 0;
|
||||
@@ -67,15 +71,25 @@ void MuteSettingsBox::prepare() {
|
||||
- st::boxOptionListSkip
|
||||
+ st::defaultCheckbox.margin.bottom();
|
||||
|
||||
addButton(langFactory(lng_box_ok), [this, group] {
|
||||
auto muteForSeconds = group->value() * 3600;
|
||||
_save = [=] {
|
||||
const auto muteForSeconds = group->value() * 3600;
|
||||
Auth().data().updateNotifySettings(
|
||||
_peer,
|
||||
muteForSeconds);
|
||||
closeBox();
|
||||
});
|
||||
};
|
||||
addButton(langFactory(lng_box_ok), _save);
|
||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWidth, y);
|
||||
}
|
||||
|
||||
void MuteSettingsBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
if (_save) {
|
||||
_save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vi: ts=4 tw=80
|
||||
|
||||
@@ -13,17 +13,17 @@ Copyright (C) 2017, Nicholas Guriev <guriev-ns@ya.ru>
|
||||
* turning off notifications from a chat. The widget is opened by a context menu
|
||||
* in the left list of dialogues. */
|
||||
class MuteSettingsBox : public BoxContent {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MuteSettingsBox(QWidget *parent, not_null<PeerData*> peer);
|
||||
|
||||
public:
|
||||
MuteSettingsBox(QWidget *parent, not_null<PeerData*> peer)
|
||||
: _peer(peer) {
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
not_null<PeerData*> _peer;
|
||||
Fn<void()> _save;
|
||||
|
||||
};
|
||||
// vi: ts=4 tw=80
|
||||
|
||||
@@ -54,6 +54,14 @@ PasscodeBox::PasscodeBox(
|
||||
if (!hint.isEmpty()) _hintText.setText(st::passcodeTextStyle, lng_signin_hint(lt_password_hint, hint));
|
||||
}
|
||||
|
||||
rpl::producer<QByteArray> PasscodeBox::newPasswordSet() const {
|
||||
return _newPasswordSet.events();
|
||||
}
|
||||
|
||||
rpl::producer<> PasscodeBox::passwordReloadNeeded() const {
|
||||
return _passwordReloadNeeded.events();
|
||||
}
|
||||
|
||||
void PasscodeBox::prepare() {
|
||||
addButton(langFactory(_turningOff ? lng_passcode_remove_button : lng_settings_save), [=] { save(); });
|
||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||
@@ -197,9 +205,9 @@ void PasscodeBox::setInnerFocus() {
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::setPasswordDone() {
|
||||
void PasscodeBox::setPasswordDone(const QByteArray &newPasswordBytes) {
|
||||
_setRequest = 0;
|
||||
emit reloadPassword();
|
||||
_newPasswordSet.fire_copy(newPasswordBytes);
|
||||
auto text = lang(_reenterPasscode->isHidden() ? lng_cloud_password_removed : (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated));
|
||||
getDelegate()->show(Box<InformBox>(text), LayerOption::CloseOther);
|
||||
}
|
||||
@@ -236,7 +244,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) {
|
||||
QString err = error.type();
|
||||
if (err == qstr("PASSWORD_HASH_INVALID")) {
|
||||
if (_oldPasscode->isHidden()) {
|
||||
emit reloadPassword();
|
||||
_passwordReloadNeeded.fire({});
|
||||
closeBox();
|
||||
} else {
|
||||
badOldPasscode();
|
||||
@@ -247,20 +255,36 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) {
|
||||
_newError = lang(lng_cloud_password_bad);
|
||||
update();
|
||||
} else if (err == qstr("NEW_SALT_INVALID")) {
|
||||
emit reloadPassword();
|
||||
_passwordReloadNeeded.fire({});
|
||||
closeBox();
|
||||
} else if (err == qstr("EMAIL_INVALID")) {
|
||||
_emailError = lang(lng_cloud_password_bad_email);
|
||||
_recoverEmail->setFocus();
|
||||
_recoverEmail->showError();
|
||||
update();
|
||||
} else if (err == qstr("EMAIL_UNCONFIRMED")) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PasscodeBox::setPasswordFail(
|
||||
const QByteArray &newPasswordBytes,
|
||||
const RPCError &error) {
|
||||
if (MTP::isFloodError(error)) {
|
||||
return setPasswordFail(error);
|
||||
} else if (MTP::isDefaultHandledError(error)) {
|
||||
return setPasswordFail(error);
|
||||
} else if (error.type() == qstr("EMAIL_UNCONFIRMED")) {
|
||||
closeReplacedBy();
|
||||
_setRequest = 0;
|
||||
|
||||
_newPasswordSet.fire_copy(newPasswordBytes);
|
||||
getDelegate()->show(
|
||||
Box<InformBox>(lang(lng_cloud_password_almost)),
|
||||
LayerOption::CloseOther);
|
||||
emit reloadPassword();
|
||||
return true;
|
||||
} else {
|
||||
return setPasswordFail(error);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PasscodeBox::save(bool force) {
|
||||
@@ -386,14 +410,15 @@ void PasscodeBox::sendClearCloudPassword(const QString &oldPassword) {
|
||||
MTPbytes(), // new_secure_secret
|
||||
MTPlong()) // new_secure_secret_id
|
||||
)).done([=](const MTPBool &result) {
|
||||
setPasswordDone();
|
||||
setPasswordDone({});
|
||||
}).fail([=](const RPCError &error) {
|
||||
setPasswordFail(error);
|
||||
setPasswordFail({}, error);
|
||||
}).send();
|
||||
}
|
||||
|
||||
void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
|
||||
const auto newPasswordData = (_newSalt + newPassword.toUtf8() + _newSalt);
|
||||
const auto newPasswordBytes = newPassword.toUtf8();
|
||||
const auto newPasswordData = (_newSalt + newPasswordBytes + _newSalt);
|
||||
auto newPasswordHash = QByteArray(32, Qt::Uninitialized);
|
||||
hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data());
|
||||
const auto oldPasswordData = QByteArray();
|
||||
@@ -416,9 +441,9 @@ void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
|
||||
MTPbytes(), // new_secure_secret
|
||||
MTPlong()) // new_secure_secret_id
|
||||
)).done([=](const MTPBool &result) {
|
||||
setPasswordDone();
|
||||
setPasswordDone(newPasswordBytes);
|
||||
}).fail([=](const RPCError &error) {
|
||||
setPasswordFail(error);
|
||||
setPasswordFail(newPasswordBytes, error);
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -443,9 +468,10 @@ void PasscodeBox::changeCloudPassword(
|
||||
return;
|
||||
}
|
||||
const auto secret = Passport::DecryptSecureSecret(
|
||||
bytes::make_span(data.vsecure_salt.v),
|
||||
bytes::make_span(data.vsecure_secret.v),
|
||||
bytes::make_span(passwordUtf));
|
||||
Passport::CountPasswordHashForSecret(
|
||||
bytes::make_span(data.vsecure_salt.v),
|
||||
bytes::make_span(passwordUtf)));
|
||||
if (secret.empty()) {
|
||||
LOG(("API Error: Failed to decrypt secure secret."));
|
||||
suggestSecretReset(oldPasswordHash, newPassword);
|
||||
@@ -505,8 +531,8 @@ void PasscodeBox::sendChangeCloudPassword(
|
||||
const QByteArray &oldPasswordHash,
|
||||
const QString &newPassword,
|
||||
const QByteArray &secureSecret) {
|
||||
const auto passwordUtf = newPassword.toUtf8();
|
||||
const auto newPasswordData = (_newSalt + passwordUtf + _newSalt);
|
||||
const auto newPasswordBytes = newPassword.toUtf8();
|
||||
const auto newPasswordData = (_newSalt + newPasswordBytes + _newSalt);
|
||||
auto newPasswordHash = QByteArray(32, Qt::Uninitialized);
|
||||
hashSha256(newPasswordData.constData(), newPasswordData.size(), newPasswordHash.data());
|
||||
const auto hint = _passwordHint->getLastText();
|
||||
@@ -522,9 +548,10 @@ void PasscodeBox::sendChangeCloudPassword(
|
||||
newSecureSecretId = Passport::CountSecureSecretId(
|
||||
bytes::make_span(secureSecret));
|
||||
newSecureSecret = Passport::EncryptSecureSecret(
|
||||
bytes::make_span(_newSecureSecretSalt),
|
||||
bytes::make_span(secureSecret),
|
||||
bytes::make_span(passwordUtf));
|
||||
Passport::CountPasswordHashForSecret(
|
||||
bytes::make_span(_newSecureSecretSalt),
|
||||
bytes::make_span(newPasswordBytes)));
|
||||
}
|
||||
_setRequest = request(MTPaccount_UpdatePasswordSettings(
|
||||
MTP_bytes(oldPasswordHash),
|
||||
@@ -538,9 +565,9 @@ void PasscodeBox::sendChangeCloudPassword(
|
||||
MTP_bytes(newSecureSecret),
|
||||
MTP_long(newSecureSecretId))
|
||||
)).done([=](const MTPBool &result) {
|
||||
setPasswordDone();
|
||||
setPasswordDone(newPasswordBytes);
|
||||
}).fail([=](const RPCError &error) {
|
||||
setPasswordFail(error);
|
||||
setPasswordFail(newPasswordBytes, error);
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -603,8 +630,17 @@ void PasscodeBox::recover() {
|
||||
const auto box = getDelegate()->show(Box<RecoverBox>(
|
||||
_pattern,
|
||||
_notEmptyPassport));
|
||||
connect(box, &RecoverBox::reloadPassword, this, &PasscodeBox::reloadPassword);
|
||||
connect(box, &RecoverBox::recoveryExpired, this, &PasscodeBox::recoverExpired);
|
||||
|
||||
box->passwordCleared(
|
||||
) | rpl::map([] {
|
||||
return QByteArray();
|
||||
}) | rpl::start_to_stream(_newPasswordSet, lifetime());
|
||||
|
||||
box->recoveryExpired(
|
||||
) | rpl::start_with_next([=] {
|
||||
recoverExpired();
|
||||
}, lifetime());
|
||||
|
||||
_replacedBy = box;
|
||||
}
|
||||
|
||||
@@ -630,6 +666,14 @@ RecoverBox::RecoverBox(
|
||||
, _recoverCode(this, st::defaultInputField, langFactory(lng_signin_code)) {
|
||||
}
|
||||
|
||||
rpl::producer<> RecoverBox::passwordCleared() const {
|
||||
return _passwordCleared.events();
|
||||
}
|
||||
|
||||
rpl::producer<> RecoverBox::recoveryExpired() const {
|
||||
return _recoveryExpired.events();
|
||||
}
|
||||
|
||||
void RecoverBox::prepare() {
|
||||
setTitle(langFactory(lng_signin_recover_title));
|
||||
|
||||
@@ -707,10 +751,12 @@ void RecoverBox::codeChanged() {
|
||||
update();
|
||||
}
|
||||
|
||||
void RecoverBox::codeSubmitDone(bool recover, const MTPauth_Authorization &result) {
|
||||
void RecoverBox::codeSubmitDone(
|
||||
bool recover,
|
||||
const MTPauth_Authorization &result) {
|
||||
_submitRequest = 0;
|
||||
|
||||
emit reloadPassword();
|
||||
_passwordCleared.fire({});
|
||||
getDelegate()->show(
|
||||
Box<InformBox>(lang(lng_cloud_password_removed)),
|
||||
LayerOption::CloseOther);
|
||||
@@ -730,7 +776,7 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) {
|
||||
|
||||
const QString &err = error.type();
|
||||
if (err == qstr("PASSWORD_EMPTY")) {
|
||||
emit reloadPassword();
|
||||
_passwordCleared.fire({});
|
||||
getDelegate()->show(
|
||||
Box<InformBox>(lang(lng_cloud_password_removed)),
|
||||
LayerOption::CloseOther);
|
||||
@@ -739,7 +785,7 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) {
|
||||
closeBox();
|
||||
return true;
|
||||
} else if (err == qstr("PASSWORD_RECOVERY_EXPIRED")) {
|
||||
emit recoveryExpired();
|
||||
_recoveryExpired.fire({});
|
||||
closeBox();
|
||||
return true;
|
||||
} else if (err == qstr("CODE_INVALID")) {
|
||||
|
||||
@@ -17,8 +17,6 @@ class LinkButton;
|
||||
} // namespace Ui
|
||||
|
||||
class PasscodeBox : public BoxContent, private MTP::Sender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PasscodeBox(QWidget*, bool turningOff);
|
||||
PasscodeBox(
|
||||
@@ -31,8 +29,8 @@ public:
|
||||
const QByteArray &newSecureSecretSalt,
|
||||
bool turningOff = false);
|
||||
|
||||
signals:
|
||||
void reloadPassword();
|
||||
rpl::producer<QByteArray> newPasswordSet() const;
|
||||
rpl::producer<> passwordReloadNeeded() const;
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@@ -52,8 +50,11 @@ private:
|
||||
void recoverByEmail();
|
||||
void recoverExpired();
|
||||
|
||||
void setPasswordDone();
|
||||
void setPasswordDone(const QByteArray &newPasswordBytes);
|
||||
bool setPasswordFail(const RPCError &error);
|
||||
bool setPasswordFail(
|
||||
const QByteArray &newPasswordBytes,
|
||||
const RPCError &error);
|
||||
|
||||
void recoverStarted(const MTPauth_PasswordRecovery &result);
|
||||
bool recoverStartFail(const RPCError &error);
|
||||
@@ -101,17 +102,20 @@ private:
|
||||
|
||||
QString _oldError, _newError, _emailError;
|
||||
|
||||
rpl::event_stream<QByteArray> _newPasswordSet;
|
||||
rpl::event_stream<> _passwordReloadNeeded;
|
||||
|
||||
};
|
||||
|
||||
class RecoverBox : public BoxContent, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RecoverBox(QWidget*, const QString &pattern, bool notEmptyPassport);
|
||||
|
||||
signals:
|
||||
void reloadPassword();
|
||||
void recoveryExpired();
|
||||
rpl::producer<> passwordCleared() const;
|
||||
rpl::producer<> recoveryExpired() const;
|
||||
|
||||
//void reloadPassword();
|
||||
//void recoveryExpired();
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@@ -135,4 +139,7 @@ private:
|
||||
|
||||
QString _error;
|
||||
|
||||
rpl::event_stream<> _passwordCleared;
|
||||
rpl::event_stream<> _recoveryExpired;
|
||||
|
||||
};
|
||||
|
||||
@@ -251,6 +251,7 @@ void PeerListController::setSearchNoResultsText(const QString &text) {
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> PeerListController::rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1020,7 +1021,7 @@ void PeerListContent::contextMenuEvent(QContextMenuEvent *e) {
|
||||
}
|
||||
|
||||
if (const auto row = getRow(_contexted.index)) {
|
||||
_contextMenu = _controller->rowContextMenu(row);
|
||||
_contextMenu = _controller->rowContextMenu(this, row);
|
||||
if (_contextMenu) {
|
||||
_contextMenu->setDestroyedCallback(crl::guard(
|
||||
this,
|
||||
|
||||
@@ -345,6 +345,7 @@ public:
|
||||
virtual void itemDeselectedHook(not_null<PeerData*> peer) {
|
||||
}
|
||||
virtual base::unique_qptr<Ui::PopupMenu> rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row);
|
||||
bool isSearchLoading() const {
|
||||
return _searchController ? _searchController->isLoading() : false;
|
||||
|
||||
@@ -710,7 +710,7 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkEdit() {
|
||||
_controls.inviteLink->setSelectable(true);
|
||||
_controls.inviteLink->setContextCopyText(QString());
|
||||
_controls.inviteLink->setBreakEverywhere(true);
|
||||
_controls.inviteLink->setClickHandlerHook([this](auto&&...) {
|
||||
_controls.inviteLink->setClickHandlerFilter([=](auto&&...) {
|
||||
Application::clipboard()->setText(inviteLinkText());
|
||||
Ui::Toast::Show(lang(lng_group_invite_copied));
|
||||
return false;
|
||||
|
||||
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_media_types.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/mime_type.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
@@ -801,7 +802,7 @@ void SingleFilePreview::preparePreview(const Storage::PreparedFile &file) {
|
||||
} else {
|
||||
auto fileinfo = QFileInfo(filepath);
|
||||
auto filename = fileinfo.fileName();
|
||||
_fileIsImage = fileIsImage(filename, mimeTypeForFile(fileinfo).name());
|
||||
_fileIsImage = fileIsImage(filename, Core::MimeTypeForFile(fileinfo).name());
|
||||
|
||||
auto songTitle = QString();
|
||||
auto songPerformer = QString();
|
||||
|
||||
@@ -632,7 +632,7 @@ void Call::handleControllerBarCountChange(
|
||||
// Expects(controller == _controller.get());
|
||||
Expects(controller->implData == static_cast<void*>(this));
|
||||
|
||||
InvokeQueued(this, [=] {
|
||||
crl::on_main(this, [=] {
|
||||
setSignalBarCount(count);
|
||||
});
|
||||
}
|
||||
@@ -763,10 +763,17 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
|
||||
auto duration = getDurationMs() / 1000;
|
||||
auto connectionId = _controller ? _controller->GetPreferredRelayID() : 0;
|
||||
_finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); });
|
||||
request(MTPphone_DiscardCall(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_int(duration), reason, MTP_long(connectionId))).done([this, finalState](const MTPUpdates &result) {
|
||||
request(MTPphone_DiscardCall(
|
||||
MTP_inputPhoneCall(
|
||||
MTP_long(_id),
|
||||
MTP_long(_accessHash)),
|
||||
MTP_int(duration),
|
||||
reason,
|
||||
MTP_long(connectionId)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
// This could be destroyed by updates, so we set Ended after
|
||||
// updates being handled, but in a guarded way.
|
||||
InvokeQueued(this, [this, finalState] { setState(finalState); });
|
||||
crl::on_main(this, [=] { setState(finalState); });
|
||||
App::main()->sentUpdatesReceived(result);
|
||||
}).fail([this, finalState](const RPCError &error) {
|
||||
setState(finalState);
|
||||
@@ -774,13 +781,13 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
|
||||
}
|
||||
|
||||
void Call::setStateQueued(State state) {
|
||||
InvokeQueued(this, [=] {
|
||||
crl::on_main(this, [=] {
|
||||
setState(state);
|
||||
});
|
||||
}
|
||||
|
||||
void Call::setFailedQueued(int error) {
|
||||
InvokeQueued(this, [=] {
|
||||
crl::on_main(this, [=] {
|
||||
handleControllerError(error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -415,7 +415,7 @@ void Panel::reinitControls() {
|
||||
}
|
||||
|
||||
void Panel::initLayout() {
|
||||
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Dialog);
|
||||
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::NoDropShadowWindowHint | Qt::Dialog);
|
||||
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
setAttribute(Qt::WA_TranslucentBackground, true);
|
||||
|
||||
@@ -57,7 +57,10 @@ void FieldAutocomplete::paintEvent(QPaintEvent *e) {
|
||||
p.fillRect(rect(), st::mentionBg);
|
||||
}
|
||||
|
||||
void FieldAutocomplete::showFiltered(PeerData *peer, QString query, bool addInlineBots) {
|
||||
void FieldAutocomplete::showFiltered(
|
||||
not_null<PeerData*> peer,
|
||||
QString query,
|
||||
bool addInlineBots) {
|
||||
_chat = peer->asChat();
|
||||
_user = peer->asUser();
|
||||
_channel = peer->asChannel();
|
||||
@@ -105,9 +108,9 @@ void FieldAutocomplete::showStickers(EmojiPtr emoji) {
|
||||
return;
|
||||
}
|
||||
|
||||
_chat = 0;
|
||||
_user = 0;
|
||||
_channel = 0;
|
||||
_chat = nullptr;
|
||||
_user = nullptr;
|
||||
_channel = nullptr;
|
||||
|
||||
updateFiltered(resetScroll);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,10 @@ public:
|
||||
FieldAutocomplete(QWidget *parent);
|
||||
|
||||
bool clearFilteredBotCommands();
|
||||
void showFiltered(PeerData *peer, QString query, bool addInlineBots);
|
||||
void showFiltered(
|
||||
not_null<PeerData*> peer,
|
||||
QString query,
|
||||
bool addInlineBots);
|
||||
void showStickers(EmojiPtr emoji);
|
||||
void setBoundings(QRect boundings);
|
||||
|
||||
|
||||
@@ -860,7 +860,14 @@ void GifsListWidget::sendInlineRequest() {
|
||||
}
|
||||
|
||||
_footer->setLoading(true);
|
||||
_inlineRequestId = request(MTPmessages_GetInlineBotResults(MTP_flags(0), _searchBot->inputUser, _inlineQueryPeer->input, MTPInputGeoPoint(), MTP_string(_inlineQuery), MTP_string(nextOffset))).done([this](const MTPmessages_BotResults &result, mtpRequestId requestId) {
|
||||
_inlineRequestId = request(MTPmessages_GetInlineBotResults(
|
||||
MTP_flags(0),
|
||||
_searchBot->inputUser,
|
||||
_inlineQueryPeer->input,
|
||||
MTPInputGeoPoint(),
|
||||
MTP_string(_inlineQuery),
|
||||
MTP_string(nextOffset)
|
||||
)).done([this](const MTPmessages_BotResults &result) {
|
||||
inlineResultsDone(result);
|
||||
}).fail([this](const RPCError &error) {
|
||||
// show error?
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "history/history_widget.h"
|
||||
#include "base/qthelp_regex.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "window/window_controller.h"
|
||||
@@ -72,40 +73,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
QRegularExpression RegExpProtocol() {
|
||||
static const auto result = QRegularExpression("^([a-zA-Z]+)://");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsGoodProtocol(const QString &protocol) {
|
||||
const auto equals = [&](QLatin1String string) {
|
||||
return protocol.compare(string, Qt::CaseInsensitive) == 0;
|
||||
};
|
||||
return equals(qstr("http"))
|
||||
|| equals(qstr("https"))
|
||||
|| equals(qstr("tg"));
|
||||
}
|
||||
|
||||
QString NormalizeUrl(const QString &value) {
|
||||
const auto trimmed = value.trimmed();
|
||||
if (trimmed.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
const auto match = TextUtilities::RegExpDomainExplicit().match(trimmed);
|
||||
if (!match.hasMatch()) {
|
||||
const auto domain = TextUtilities::RegExpDomain().match(trimmed);
|
||||
if (!domain.hasMatch() || domain.capturedStart() != 0) {
|
||||
return QString();
|
||||
}
|
||||
return qstr("http://") + trimmed;
|
||||
} else if (match.capturedStart() != 0) {
|
||||
return QString();
|
||||
}
|
||||
const auto protocolMatch = RegExpProtocol().match(trimmed);
|
||||
Assert(protocolMatch.hasMatch());
|
||||
return IsGoodProtocol(protocolMatch.captured(1)) ? trimmed : QString();
|
||||
}
|
||||
|
||||
//bool ValidateUrl(const QString &value) {
|
||||
// const auto match = TextUtilities::RegExpDomain().match(value);
|
||||
// if (!match.hasMatch() || match.capturedStart() != 0) {
|
||||
@@ -156,7 +123,7 @@ void EditLinkBox::prepare() {
|
||||
|
||||
const auto submit = [=] {
|
||||
const auto linkText = text->getLastText();
|
||||
const auto linkUrl = NormalizeUrl(url->getLastText());
|
||||
const auto linkUrl = qthelp::validate_url(url->getLastText());
|
||||
if (linkText.isEmpty()) {
|
||||
text->showError();
|
||||
return;
|
||||
@@ -609,19 +576,21 @@ void MessageLinksParser::parse() {
|
||||
const auto markdownTagsEnd = markdownTags.end();
|
||||
const auto markdownTagsAllow = [&](int from, int length) {
|
||||
while (markdownTag != markdownTagsEnd
|
||||
&& (markdownTag->start + markdownTag->length <= from
|
||||
&& (markdownTag->adjustedStart
|
||||
+ markdownTag->adjustedLength <= from
|
||||
|| !markdownTag->closed)) {
|
||||
++markdownTag;
|
||||
continue;
|
||||
}
|
||||
if (markdownTag == markdownTagsEnd
|
||||
|| markdownTag->start >= from + length) {
|
||||
|| markdownTag->adjustedStart >= from + length) {
|
||||
return true;
|
||||
}
|
||||
// Ignore http-links that are completely inside some tags.
|
||||
// This will allow sending http://test.com/__test__/test correctly.
|
||||
return (markdownTag->start > from
|
||||
|| markdownTag->start + markdownTag->length < from + length);
|
||||
return (markdownTag->adjustedStart > from)
|
||||
|| (markdownTag->adjustedStart
|
||||
+ markdownTag->adjustedLength < from + length);
|
||||
};
|
||||
|
||||
const auto len = text.size();
|
||||
|
||||
@@ -1011,39 +1011,4 @@ RecentStickerPack &GetRecentPack() {
|
||||
return cRefRecentStickers();
|
||||
}
|
||||
|
||||
void IncrementRecentHashtag(RecentHashtagPack &recent, const QString &tag) {
|
||||
auto i = recent.begin(), e = recent.end();
|
||||
for (; i != e; ++i) {
|
||||
if (i->first == tag) {
|
||||
++i->second;
|
||||
if (qAbs(i->second) > 0x4000) {
|
||||
for (auto j = recent.begin(); j != e; ++j) {
|
||||
if (j->second > 1) {
|
||||
j->second /= 2;
|
||||
} else if (j->second > 0) {
|
||||
j->second = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i != recent.begin(); --i) {
|
||||
if (qAbs((i - 1)->second) > qAbs(i->second)) {
|
||||
break;
|
||||
}
|
||||
qSwap(*i, *(i - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == e) {
|
||||
while (recent.size() >= 64) recent.pop_back();
|
||||
recent.push_back(qMakePair(tag, 1));
|
||||
for (i = recent.end() - 1; i != recent.begin(); --i) {
|
||||
if ((i - 1)->second > i->second) {
|
||||
break;
|
||||
}
|
||||
qSwap(*i, *(i - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Stickers
|
||||
|
||||
@@ -99,6 +99,4 @@ QString GetSetTitle(const MTPDstickerSet &s);
|
||||
|
||||
RecentStickerPack &GetRecentPack();
|
||||
|
||||
void IncrementRecentHashtag(RecentHashtagPack &recent, const QString &tag);
|
||||
|
||||
} // namespace Stickers
|
||||
|
||||