Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7351641034 | ||
|
|
e0669e222d | ||
|
|
4c1f83daca | ||
|
|
ced2652deb | ||
|
|
8d1db85a28 | ||
|
|
97305c8cb5 | ||
|
|
1ef5d81270 | ||
|
|
9ff427afad | ||
|
|
1c5eadcd79 | ||
|
|
bc6c01de7f | ||
|
|
41255cab44 | ||
|
|
ccbc63cd6e | ||
|
|
97446ae783 | ||
|
|
5a75dd2b6f | ||
|
|
6559e83e83 | ||
|
|
d679703bbf | ||
|
|
66a3e36024 | ||
|
|
31e38e1690 | ||
|
|
da10059f45 | ||
|
|
cb5863177f | ||
|
|
84399286c1 | ||
|
|
2e92441b3a | ||
|
|
7883f97c94 | ||
|
|
297b5d6a76 | ||
|
|
492dc2568c | ||
|
|
547c657b1a | ||
|
|
c478d96385 | ||
|
|
2ede53e0ee | ||
|
|
6f760d513e | ||
|
|
f4f6550d66 | ||
|
|
c7878f9d21 | ||
|
|
cd75a45673 | ||
|
|
07e3671ca8 | ||
|
|
295aa644bf | ||
|
|
b5b78c0ade | ||
|
|
f5c0e5d31d | ||
|
|
246ed43046 | ||
|
|
701e1d7b4d | ||
|
|
9cbe899688 | ||
|
|
7409d615a3 | ||
|
|
c9553c2d4c | ||
|
|
bedefaee4d | ||
|
|
5d3b8f02fc | ||
|
|
5120d3ef2c | ||
|
|
82a372873f | ||
|
|
d1d1f83881 | ||
|
|
78c3c86fe6 | ||
|
|
447d4e6c47 | ||
|
|
d0e3d15e8e | ||
|
|
0251f58bf2 | ||
|
|
36997f084a | ||
|
|
942fcb9aae | ||
|
|
6232dce1a3 | ||
|
|
0c0fc46b90 | ||
|
|
dcf737bebe | ||
|
|
919834093e | ||
|
|
99ccd49e13 | ||
|
|
29896b2efd |
30
.github/workflows/issue_closer.yml
vendored
@@ -14,6 +14,22 @@ jobs:
|
||||
echo $tag
|
||||
echo ::set-env name=LATEST_TAG::$tag
|
||||
|
||||
- name: Get the latest macOS version.
|
||||
shell: python
|
||||
run: |
|
||||
import subprocess;
|
||||
from xml.dom import minidom;
|
||||
|
||||
url = "https://osx.telegram.org/updates/versions.xml";
|
||||
subprocess.check_call("wget %s" % url, shell=True);
|
||||
|
||||
xmldoc = minidom.parse('versions.xml');
|
||||
itemlist = xmldoc.getElementsByTagName('enclosure');
|
||||
ver = itemlist[0].attributes['sparkle:shortVersionString'].value;
|
||||
print(ver);
|
||||
|
||||
subprocess.check_call("echo ::set-env name=%s::%s" % ("LATEST_MACOS", ver), shell=True);
|
||||
|
||||
- name: Check a version from an issue.
|
||||
uses: actions/github-script@0.4.0
|
||||
with:
|
||||
@@ -75,10 +91,20 @@ jobs:
|
||||
let issueNum = firstNum(issueVer);
|
||||
let latestNum = firstNum(latestVer);
|
||||
|
||||
if (issueNum <= latestNum && issueNum < 5) {
|
||||
let macos_ver = process.env.LATEST_MACOS;
|
||||
console.log("Telegram for MacOS version from website: " + macos_ver);
|
||||
|
||||
if (issueNum <= latestNum && issueNum < macos_ver) {
|
||||
console.log("Seems the version of this issue is fine!");
|
||||
return;
|
||||
}
|
||||
if (issueNum > macos_ver) {
|
||||
let message = `Seems like it's neither the Telegram Desktop\
|
||||
nor the Telegram for macOS version.
|
||||
`;
|
||||
console.log(message);
|
||||
return;
|
||||
}
|
||||
|
||||
let message = `
|
||||
Sorry, but according to the version you specify in this issue, \
|
||||
@@ -87,7 +113,7 @@ jobs:
|
||||
You can report your issue to [the group](https://t.me/macswift) \
|
||||
or to [the repository of Telegram for macOS](https://github.com/overtake/TelegramSwift).
|
||||
|
||||
If I made a mistake and closed your issue wrongly, please reopen it. Thanks!
|
||||
**If I made a mistake and closed your issue wrongly, please reopen it. Thanks!**
|
||||
`;
|
||||
|
||||
let params = {
|
||||
|
||||
17
.github/workflows/linux.yml
vendored
@@ -335,19 +335,6 @@ jobs:
|
||||
|
||||
sudo cp -R ffmpeg-cache/. /
|
||||
|
||||
- name: PortAudio.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
|
||||
git clone https://git.assembla.com/portaudio.git
|
||||
cd portaudio
|
||||
git checkout 396fe4b669
|
||||
./configure
|
||||
make -j$(nproc)
|
||||
sudo make install
|
||||
cd ..
|
||||
rm -rf portaudio
|
||||
|
||||
- name: OpenAL Soft.
|
||||
run: |
|
||||
cd $LibrariesPath
|
||||
@@ -428,8 +415,8 @@ jobs:
|
||||
|
||||
git clone -b v5.12.8 --depth=1 git://code.qt.io/qt/qt5.git qt_${QT}
|
||||
cd qt_${QT}
|
||||
perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg
|
||||
git submodule update qtbase qtwayland qtimageformats qtsvg
|
||||
perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg,qtx11extras
|
||||
git submodule update qtbase qtwayland qtimageformats qtsvg qtx11extras
|
||||
cd qtbase
|
||||
git apply ../../patches/qtbase_${QT}.diff
|
||||
cd ../
|
||||
|
||||
35
.github/workflows/master_updater.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Master branch updater.
|
||||
|
||||
on:
|
||||
release:
|
||||
types: released
|
||||
|
||||
jobs:
|
||||
updater:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SKIP: "0"
|
||||
to_branch: "master"
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
if: env.SKIP == '0'
|
||||
- name: Push the code to the master branch.
|
||||
if: env.SKIP == '0'
|
||||
run: |
|
||||
token=${{ secrets.TOKEN_FOR_MASTER_UPDATER }}
|
||||
if [ -z "${token}" ]; then
|
||||
echo "Token is unset. Nothing to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
url=https://x-access-token:$token@github.com/$GITHUB_REPOSITORY
|
||||
latest_tag=$(git describe --tags --abbrev=0)
|
||||
echo "Latest tag: $latest_tag"
|
||||
|
||||
git remote set-url origin $url
|
||||
git remote -v
|
||||
git checkout master
|
||||
git merge $latest_tag
|
||||
|
||||
git push origin HEAD:refs/heads/$to_branch
|
||||
echo "Done!"
|
||||
3
.gitmodules
vendored
@@ -91,3 +91,6 @@
|
||||
[submodule "Telegram/ThirdParty/libqtxdg"]
|
||||
path = Telegram/ThirdParty/libqtxdg
|
||||
url = https://github.com/lxqt/libqtxdg.git
|
||||
[submodule "Telegram/ThirdParty/fcitx5-qt"]
|
||||
path = Telegram/ThirdParty/fcitx5-qt
|
||||
url = https://github.com/fcitx/fcitx5-qt.git
|
||||
|
||||
28
README.md
@@ -13,18 +13,27 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
|
||||
|
||||
## Supported systems
|
||||
|
||||
* Windows XP - Windows 10 (**not** RT)
|
||||
* Mac OS X 10.8 - Mac OS X 10.15
|
||||
* Mac OS X 10.6 - Mac OS X 10.7 (separate build)
|
||||
* Ubuntu 12.04 - Ubuntu 20.04
|
||||
* Fedora 22 - Fedora 31
|
||||
* [Snappy](https://snapcraft.io/telegram-desktop)
|
||||
* [Flathub](https://flathub.org/apps/details/org.telegram.desktop)
|
||||
The latest version is available for
|
||||
|
||||
* [Windows 7 and above](https://telegram.org/dl/desktop/win) ([portable](https://telegram.org/dl/desktop/win_portable))
|
||||
* [macOS 10.12 and above](https://telegram.org/dl/desktop/mac)
|
||||
* [OS X 10.10 and 10.11](https://telegram.org/dl/desktop/osx)
|
||||
* [Linux static build for 64 bit](https://telegram.org/dl/desktop/linux) ([32 bit](https://telegram.org/dl/desktop/linux32))
|
||||
* [Snap](https://snapcraft.io/telegram-desktop)
|
||||
* [Flatpak](https://flathub.org/apps/details/org.telegram.desktop)
|
||||
|
||||
## Old system versions
|
||||
|
||||
Version **1.8.15** was the last that supports older systems
|
||||
|
||||
* [Windows XP and Vista](https://updates.tdesktop.com/tsetup/tsetup.1.8.15.exe) ([portable](https://updates.tdesktop.com/tsetup/tportable.1.8.15.zip))
|
||||
* [OS X 10.8 and 10.9](https://updates.tdesktop.com/tmac/tsetup.1.8.15.dmg)
|
||||
* [OS X 10.6 and 10.7](https://updates.tdesktop.com/tmac32/tsetup32.1.8.15.dmg)
|
||||
|
||||
## Third-party
|
||||
|
||||
* Qt 5.12.8 and 5.6.2, slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html))
|
||||
* OpenSSL 1.1.1 ([OpenSSL License](https://www.openssl.org/source/license.html))
|
||||
* Qt 5.12.8, 5.6.2 and 5.3.2 slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html))
|
||||
* OpenSSL 1.1.1 and 1.0.1 ([OpenSSL License](https://www.openssl.org/source/license.html))
|
||||
* zlib 1.2.11 ([zlib License](http://www.zlib.net/zlib_license.html))
|
||||
* LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html))
|
||||
* liblzma ([public domain](http://tukaani.org/xz/))
|
||||
@@ -39,6 +48,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
|
||||
* Mapbox Variant ([BSD License](https://github.com/mapbox/variant/blob/master/LICENSE))
|
||||
* Range-v3 ([Boost License](https://github.com/ericniebler/range-v3/blob/master/LICENSE.txt))
|
||||
* Open Sans font ([Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html))
|
||||
* Vazir font ([License](https://github.com/rastikerdar/vazir-font/blob/master/LICENSE))
|
||||
* Emoji alpha codes ([MIT License](https://github.com/emojione/emojione/blob/master/extras/alpha-codes/LICENSE.md))
|
||||
* Catch test framework ([Boost License](https://github.com/philsquared/Catch/blob/master/LICENSE.txt))
|
||||
* xxHash ([BSD License](https://github.com/Cyan4973/xxHash/blob/dev/LICENSE))
|
||||
|
||||
@@ -91,6 +91,7 @@ if (LINUX)
|
||||
desktop-app::external_statusnotifieritem
|
||||
desktop-app::external_dbusmenu_qt
|
||||
desktop-app::external_fcitx_qt5
|
||||
desktop-app::external_fcitx5_qt5
|
||||
desktop-app::external_hime_qt
|
||||
)
|
||||
endif()
|
||||
@@ -138,7 +139,7 @@ endif()
|
||||
|
||||
if (DESKTOP_APP_USE_PACKAGED)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_package(Threads)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
@@ -1042,6 +1043,8 @@ PRIVATE
|
||||
qrc/emoji_3.qrc
|
||||
qrc/emoji_4.qrc
|
||||
qrc/emoji_5.qrc
|
||||
qrc/emoji_6.qrc
|
||||
qrc/emoji_7.qrc
|
||||
qrc/emoji_preview.qrc
|
||||
qrc/telegram/telegram.qrc
|
||||
qrc/telegram/sounds.qrc
|
||||
@@ -1210,6 +1213,10 @@ if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR NOT LINUX) AND NOT build_macstore AND
|
||||
|
||||
set_target_properties(Updater PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
|
||||
|
||||
if (WIN32 AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
target_link_options(Updater PRIVATE -municode)
|
||||
endif()
|
||||
|
||||
if (LINUX)
|
||||
target_link_options(Updater PRIVATE -static-libstdc++)
|
||||
endif()
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 894 KiB After Width: | Height: | Size: 1.4 MiB |
BIN
Telegram/Resources/emoji/emoji_6.webp
Normal file
|
After Width: | Height: | Size: 862 KiB |
BIN
Telegram/Resources/emoji/emoji_7.webp
Normal file
|
After Width: | Height: | Size: 98 KiB |
@@ -300,6 +300,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_notifications_position" = "Location on the screen";
|
||||
"lng_settings_notifications_count" = "Notifications count";
|
||||
"lng_settings_sound_notify" = "Play sound";
|
||||
"lng_settings_alert_windows" = "Flash the taskbar icon";
|
||||
"lng_settings_alert_mac" = "Bounce the dock icon";
|
||||
"lng_settings_alert_linux" = "Draw attention to the window";
|
||||
"lng_settings_badge_title" = "Badge counter";
|
||||
"lng_settings_include_muted" = "Include muted chats in unread count";
|
||||
"lng_settings_count_unread" = "Count unread messages";
|
||||
@@ -1451,6 +1454,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_edit_msg" = "Edit";
|
||||
"lng_context_forward_msg" = "Forward Message";
|
||||
"lng_context_send_now_msg" = "Send now";
|
||||
"lng_context_reschedule" = "Reschedule";
|
||||
"lng_context_delete_msg" = "Delete Message";
|
||||
"lng_context_select_msg" = "Select Message";
|
||||
"lng_context_report_msg" = "Report Message";
|
||||
|
||||
5
Telegram/Resources/qrc/emoji_6.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/emoji_6.webp">../emoji/emoji_6.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
5
Telegram/Resources/qrc/emoji_7.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/emoji_7.webp">../emoji/emoji_7.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.1.2.0" />
|
||||
Version="2.1.7.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>
|
||||
|
||||
@@ -6,7 +6,18 @@
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
#if defined(__MINGW64__) || defined(__MINGW32__)
|
||||
// MinGW-w64, MinGW
|
||||
#if defined(__has_include) && __has_include(<winres.h>)
|
||||
#include <winres.h>
|
||||
#else
|
||||
#include <afxres.h>
|
||||
#include <winresrc.h>
|
||||
#endif
|
||||
#else
|
||||
// MSVC, Windows SDK
|
||||
#include <winres.h>
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
@@ -33,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,1,2,0
|
||||
PRODUCTVERSION 2,1,2,0
|
||||
FILEVERSION 2,1,7,0
|
||||
PRODUCTVERSION 2,1,7,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -51,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "2.1.2.0"
|
||||
VALUE "FileVersion", "2.1.7.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.1.2.0"
|
||||
VALUE "ProductVersion", "2.1.7.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -6,7 +6,18 @@
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
#if defined(__MINGW64__) || defined(__MINGW32__)
|
||||
// MinGW-w64, MinGW
|
||||
#if defined(__has_include) && __has_include(<winres.h>)
|
||||
#include <winres.h>
|
||||
#else
|
||||
#include <afxres.h>
|
||||
#include <winresrc.h>
|
||||
#endif
|
||||
#else
|
||||
// MSVC, Windows SDK
|
||||
#include <winres.h>
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
@@ -24,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,1,2,0
|
||||
PRODUCTVERSION 2,1,2,0
|
||||
FILEVERSION 2,1,7,0
|
||||
PRODUCTVERSION 2,1,7,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -42,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "2.1.2.0"
|
||||
VALUE "FileVersion", "2.1.7.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.1.2.0"
|
||||
VALUE "ProductVersion", "2.1.7.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -268,7 +268,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Compression start, size: " << resultSize << "\n";
|
||||
|
||||
QByteArray compressed, resultCheck;
|
||||
#ifdef Q_OS_WIN // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
|
||||
|
||||
compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size
|
||||
|
||||
@@ -27,7 +27,7 @@ extern "C" {
|
||||
#include <openssl/evp.h>
|
||||
} // extern "C"
|
||||
|
||||
#ifdef Q_OS_WIN // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
#include <LzmaLib.h>
|
||||
#else
|
||||
#include <lzma.h>
|
||||
|
||||
@@ -30,6 +30,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
void InnerFillMessagePostFlags(
|
||||
const Api::SendOptions &options,
|
||||
not_null<PeerData*> peer,
|
||||
MTPDmessage::Flags &flags) {
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
if (!channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_from_id;
|
||||
return;
|
||||
}
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
// Don't display views and author of a new post when it's scheduled.
|
||||
if (options.scheduled) {
|
||||
return;
|
||||
}
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
if (peer->asChannel()->addsSignature()) {
|
||||
flags |= MTPDmessage::Flag::f_post_author;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MediaData>
|
||||
void SendExistingMedia(
|
||||
Api::MessageToSend &&message,
|
||||
@@ -60,15 +80,7 @@ void SendExistingMedia(
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto silentPost = message.action.options.silent
|
||||
|| (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;
|
||||
}
|
||||
InnerFillMessagePostFlags(message.action.options, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
@@ -246,15 +258,7 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto silentPost = message.action.options.silent
|
||||
|| (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;
|
||||
}
|
||||
InnerFillMessagePostFlags(message.action.options, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
}
|
||||
@@ -320,4 +324,11 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FillMessagePostFlags(
|
||||
const Api::SendAction &action,
|
||||
not_null<PeerData*> peer,
|
||||
MTPDmessage::Flags &flags) {
|
||||
InnerFillMessagePostFlags(action.options, peer, flags);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -25,4 +25,9 @@ void SendExistingPhoto(
|
||||
|
||||
bool SendDice(Api::MessageToSend &message);
|
||||
|
||||
void FillMessagePostFlags(
|
||||
const SendAction &action,
|
||||
not_null<PeerData*> peer,
|
||||
MTPDmessage::Flags &flags);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -82,6 +82,7 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
|
||||
if (entity.length() <= 0) continue;
|
||||
if (option == ConvertOption::SkipLocal
|
||||
&& entity.type() != EntityType::Bold
|
||||
//&& entity.type() != EntityType::Semibold // Not in API.
|
||||
&& entity.type() != EntityType::Italic
|
||||
&& entity.type() != EntityType::Underline
|
||||
&& entity.type() != EntityType::StrikeOut
|
||||
|
||||
@@ -4328,15 +4328,7 @@ void ApiWrap::forwardMessages(
|
||||
auto flags = MTPDmessage::Flags(0);
|
||||
auto clientFlags = MTPDmessage_ClientFlags();
|
||||
auto sendFlags = MTPmessages_ForwardMessages::Flags(0);
|
||||
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;
|
||||
}
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_ForwardMessages::Flag::f_silent;
|
||||
}
|
||||
@@ -4489,15 +4481,7 @@ void ApiWrap::sendSharedContact(
|
||||
if (action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
if (channelPost) {
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
if (peer->asChannel()->addsSignature()) {
|
||||
flags |= MTPDmessage::Flag::f_post_author;
|
||||
}
|
||||
} else {
|
||||
flags |= MTPDmessage::Flag::f_from_id;
|
||||
}
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
} else {
|
||||
@@ -4874,15 +4858,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto silentPost = action.options.silent
|
||||
|| (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;
|
||||
}
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
|
||||
}
|
||||
@@ -5019,15 +4995,7 @@ void ApiWrap::sendInlineResult(
|
||||
bool channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
bool silentPost = action.options.silent
|
||||
|| (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;
|
||||
}
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
|
||||
}
|
||||
@@ -5857,6 +5825,43 @@ void ApiWrap::closePoll(not_null<HistoryItem*> item) {
|
||||
_pollCloseRequestIds.emplace(itemId, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::rescheduleMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
Api::SendOptions options) {
|
||||
const auto text = item->originalText().text;
|
||||
const auto sentEntities = Api::EntitiesToMTP(
|
||||
item->originalText().entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
const auto media = item->media();
|
||||
|
||||
const auto emptyFlag = MTPmessages_EditMessage::Flag(0);
|
||||
const auto flags = MTPmessages_EditMessage::Flag::f_schedule_date
|
||||
| (!text.isEmpty()
|
||||
? MTPmessages_EditMessage::Flag::f_message
|
||||
: emptyFlag)
|
||||
| ((!media || !media->webpage())
|
||||
? MTPmessages_EditMessage::Flag::f_no_webpage
|
||||
: emptyFlag)
|
||||
| (!sentEntities.v.isEmpty()
|
||||
? MTPmessages_EditMessage::Flag::f_entities
|
||||
: emptyFlag);
|
||||
|
||||
const auto id = _session->data().scheduledMessages().lookupId(item);
|
||||
request(MTPmessages_EditMessage(
|
||||
MTP_flags(flags),
|
||||
item->history()->peer->input,
|
||||
MTP_int(id),
|
||||
MTP_string(text),
|
||||
MTPInputMedia(),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(options.scheduled)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
}).fail([](const RPCError &error) {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::reloadPollResults(not_null<HistoryItem*> item) {
|
||||
const auto itemId = item->fullId();
|
||||
if (!IsServerMsgId(item->id)
|
||||
|
||||
@@ -476,6 +476,10 @@ public:
|
||||
void closePoll(not_null<HistoryItem*> item);
|
||||
void reloadPollResults(not_null<HistoryItem*> item);
|
||||
|
||||
void rescheduleMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
Api::SendOptions options);
|
||||
|
||||
private:
|
||||
struct MessageDataRequest {
|
||||
using Callbacks = QList<RequestMessageDataCallback>;
|
||||
|
||||
@@ -915,7 +915,7 @@ blockUserConfirmation: FlatLabel(boxLabel) {
|
||||
minWidth: 240px;
|
||||
}
|
||||
|
||||
transferCheckWidth: 300px;
|
||||
transferCheckWidth: 320px;
|
||||
|
||||
slowmodeLabelsMargin: margins(0px, 5px, 0px, 0px);
|
||||
slowmodeLabel: LabelSimple(defaultLabelSimple) {
|
||||
|
||||
@@ -599,4 +599,19 @@ void CalendarBox::keyPressEvent(QKeyEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void CalendarBox::wheelEvent(QWheelEvent *e) {
|
||||
// Only a mouse wheel is accepted.
|
||||
constexpr auto step = static_cast<int>(QWheelEvent::DefaultDeltasPerStep);
|
||||
const auto delta = e->angleDelta().y();
|
||||
if (std::abs(delta) != step) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (delta < 0) {
|
||||
goPreviousMonth();
|
||||
} else {
|
||||
goNextMonth();
|
||||
}
|
||||
}
|
||||
|
||||
CalendarBox::~CalendarBox() = default;
|
||||
|
||||
@@ -46,6 +46,7 @@ protected:
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void wheelEvent(QWheelEvent *e) override;
|
||||
|
||||
private:
|
||||
void monthChanged(QDate month);
|
||||
|
||||
@@ -83,7 +83,7 @@ private:
|
||||
void show(anim::type animated);
|
||||
void destroy(FnMut<void()> done);
|
||||
|
||||
[[nodisacrd]] bool hasShadow() const;
|
||||
[[nodiscard]] bool hasShadow() const;
|
||||
void createShadow();
|
||||
void destroyShadow();
|
||||
|
||||
|
||||
@@ -551,10 +551,7 @@ void EditCaptionBox::prepare() {
|
||||
} else if (data->hasImage()) {
|
||||
return true;
|
||||
} else if (const auto urls = data->urls(); !urls.empty()) {
|
||||
if (ranges::find_if(
|
||||
urls,
|
||||
[](const QUrl &url) { return !url.isLocalFile(); }
|
||||
) == urls.end()) {
|
||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,5 +584,9 @@ void ChooseRecipientBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
|
||||
auto ChooseRecipientBoxController::createRow(
|
||||
not_null<History*> history) -> std::unique_ptr<Row> {
|
||||
return std::make_unique<Row>(history);
|
||||
const auto peer = history->peer;
|
||||
const auto skip = peer->isChannel()
|
||||
&& !peer->isMegagroup()
|
||||
&& !peer->canWrite();
|
||||
return skip ? nullptr : std::make_unique<Row>(history);
|
||||
}
|
||||
|
||||
@@ -463,6 +463,8 @@ void Panel::toggleOpacityAnimation(bool visible) {
|
||||
_visible ? 1. : 0.,
|
||||
st::callPanelDuration,
|
||||
_visible ? anim::easeOutCirc : anim::easeInCirc);
|
||||
} else if (!isHidden() && !_visible) {
|
||||
hide();
|
||||
}
|
||||
if (isHidden() && _visible) {
|
||||
show();
|
||||
|
||||
@@ -40,15 +40,15 @@ inline auto PreviewPath(int i) {
|
||||
|
||||
const auto kSets = {
|
||||
Set{ {0, 0, 0, "Mac"}, PreviewPath(0) },
|
||||
Set{ {1, 246, 7'336'383, "Android"}, PreviewPath(1) },
|
||||
Set{ {2, 206, 5'038'738, "Twemoji"}, PreviewPath(2) },
|
||||
Set{ {3, 238, 6'992'260, "JoyPixels"}, PreviewPath(3) },
|
||||
Set{ {1, 713, 7'313'166, "Android"}, PreviewPath(1) },
|
||||
Set{ {2, 714, 4'690'333, "Twemoji"}, PreviewPath(2) },
|
||||
Set{ {3, 716, 5'968'021, "JoyPixels"}, PreviewPath(3) },
|
||||
};
|
||||
|
||||
using Loading = MTP::DedicatedLoader::Progress;
|
||||
using SetState = BlobState;
|
||||
|
||||
class Loader : public BlobLoader {
|
||||
class Loader final : public BlobLoader {
|
||||
public:
|
||||
Loader(
|
||||
QObject *parent,
|
||||
@@ -60,6 +60,9 @@ public:
|
||||
void destroy() override;
|
||||
void unpack(const QString &path) override;
|
||||
|
||||
private:
|
||||
void fail() override;
|
||||
|
||||
};
|
||||
|
||||
class Inner : public Ui::RpWidget {
|
||||
@@ -155,12 +158,14 @@ bool UnpackSet(const QString &path, const QString &folder) {
|
||||
return UnpackBlob(path, folder, GoodSetPartName);
|
||||
}
|
||||
|
||||
|
||||
Loader::Loader(
|
||||
QObject *parent,
|
||||
int id,
|
||||
MTP::DedicatedLoader::Location location,
|
||||
const QString &folder,
|
||||
int size) : BlobLoader(parent, id, location, folder, size) {
|
||||
int size)
|
||||
: BlobLoader(parent, id, location, folder, size) {
|
||||
}
|
||||
|
||||
void Loader::unpack(const QString &path) {
|
||||
@@ -190,6 +195,11 @@ void Loader::destroy() {
|
||||
SetGlobalLoader(nullptr);
|
||||
}
|
||||
|
||||
void Loader::fail() {
|
||||
ClearNeedSwitchToId();
|
||||
BlobLoader::fail();
|
||||
}
|
||||
|
||||
Inner::Inner(QWidget *parent) : RpWidget(parent) {
|
||||
setupContent();
|
||||
}
|
||||
@@ -401,12 +411,7 @@ void Row::setupHandler() {
|
||||
}
|
||||
|
||||
void Row::load() {
|
||||
SetGlobalLoader(base::make_unique_q<Loader>(
|
||||
App::main(),
|
||||
_id,
|
||||
GetDownloadLocation(_id),
|
||||
internal::SetDataPath(_id),
|
||||
GetDownloadSize(_id)));
|
||||
LoadAndSwitchTo(_id);
|
||||
}
|
||||
|
||||
void Row::setupLabels(const Set &set) {
|
||||
@@ -538,5 +543,20 @@ void ManageSetsBox::prepare() {
|
||||
setDimensionsToContent(st::boxWidth, inner);
|
||||
}
|
||||
|
||||
void LoadAndSwitchTo(int id) {
|
||||
Expects(App::main() != nullptr);
|
||||
|
||||
if (!ranges::contains(kSets, id, &Set::id)) {
|
||||
ClearNeedSwitchToId();
|
||||
return;
|
||||
}
|
||||
SetGlobalLoader(base::make_unique_q<Loader>(
|
||||
App::main(),
|
||||
id,
|
||||
GetDownloadLocation(id),
|
||||
internal::SetDataPath(id),
|
||||
GetDownloadSize(id)));
|
||||
}
|
||||
|
||||
} // namespace Emoji
|
||||
} // namespace Ui
|
||||
|
||||
@@ -21,5 +21,7 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
void LoadAndSwitchTo(int id);
|
||||
|
||||
} // namespace Emoji
|
||||
} // namespace Ui
|
||||
|
||||
@@ -20,9 +20,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "main/main_session.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "facades.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_history.h"
|
||||
@@ -33,14 +33,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
FieldAutocomplete::FieldAutocomplete(
|
||||
QWidget *parent,
|
||||
not_null<Main::Session*> session)
|
||||
not_null<Window::SessionController*> controller)
|
||||
: RpWidget(parent)
|
||||
, _session(session)
|
||||
, _controller(controller)
|
||||
, _scroll(this, st::mentionScroll) {
|
||||
_scroll->setGeometry(rect());
|
||||
|
||||
_inner = _scroll->setOwnedWidget(
|
||||
object_ptr<internal::FieldAutocompleteInner>(
|
||||
_controller,
|
||||
this,
|
||||
&_mrows,
|
||||
&_hrows,
|
||||
@@ -169,7 +170,7 @@ inline int indexOfInFirstN(const T &v, const U &elem, int last) {
|
||||
|
||||
internal::StickerRows FieldAutocomplete::getStickerSuggestions() {
|
||||
const auto list = Stickers::GetListByEmoji(
|
||||
_session,
|
||||
&_controller->session(),
|
||||
_emoji,
|
||||
_stickersSeed
|
||||
);
|
||||
@@ -584,12 +585,14 @@ bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) {
|
||||
namespace internal {
|
||||
|
||||
FieldAutocompleteInner::FieldAutocompleteInner(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<FieldAutocomplete*> parent,
|
||||
not_null<MentionRows*> mrows,
|
||||
not_null<HashtagRows*> hrows,
|
||||
not_null<BotCommandRows*> brows,
|
||||
not_null<StickerRows*> srows)
|
||||
: _parent(parent)
|
||||
: _controller(controller)
|
||||
, _parent(parent)
|
||||
, _mrows(mrows)
|
||||
, _hrows(hrows)
|
||||
, _brows(brows)
|
||||
@@ -665,7 +668,6 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
if (sticker.animated && sticker.animated->ready()) {
|
||||
const auto frame = sticker.animated->frame();
|
||||
sticker.animated->markFrameShown();
|
||||
const auto size = frame.size() / cIntRetinaFactor();
|
||||
const auto ppos = pos + QPoint(
|
||||
(st::stickerPanSize.width() - size.width()) / 2,
|
||||
@@ -673,6 +675,11 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
||||
p.drawImage(
|
||||
QRect(ppos, size),
|
||||
frame);
|
||||
const auto paused = _controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::SavedGifs);
|
||||
if (!paused) {
|
||||
sticker.animated->markFrameShown();
|
||||
}
|
||||
} else if (const auto image = document->getStickerSmall()) {
|
||||
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
|
||||
p.drawPixmapLeft(ppos, width(), image->pix(document->stickerSetOrigin(), w, h));
|
||||
|
||||
@@ -22,9 +22,9 @@ class SinglePlayer;
|
||||
class FrameRenderer;
|
||||
} // namespace Lottie;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace internal {
|
||||
|
||||
@@ -46,7 +46,9 @@ class FieldAutocomplete final : public Ui::RpWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FieldAutocomplete(QWidget *parent, not_null<Main::Session*> session);
|
||||
FieldAutocomplete(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller);
|
||||
~FieldAutocomplete();
|
||||
|
||||
bool clearFilteredBotCommands();
|
||||
@@ -109,7 +111,7 @@ private:
|
||||
void recount(bool resetScroll = false);
|
||||
internal::StickerRows getStickerSuggestions();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
QPixmap _cache;
|
||||
internal::MentionRows _mrows;
|
||||
internal::HashtagRows _hrows;
|
||||
@@ -160,6 +162,7 @@ class FieldAutocompleteInner final
|
||||
|
||||
public:
|
||||
FieldAutocompleteInner(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<FieldAutocomplete*> parent,
|
||||
not_null<MentionRows*> mrows,
|
||||
not_null<HashtagRows*> hrows,
|
||||
@@ -204,11 +207,12 @@ private:
|
||||
void repaintSticker(not_null<DocumentData*> document);
|
||||
std::shared_ptr<Lottie::FrameRenderer> getLottieRenderer();
|
||||
|
||||
not_null<FieldAutocomplete*> _parent;
|
||||
not_null<MentionRows*> _mrows;
|
||||
not_null<HashtagRows*> _hrows;
|
||||
not_null<BotCommandRows*> _brows;
|
||||
not_null<StickerRows*> _srows;
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<FieldAutocomplete*> _parent;
|
||||
const not_null<MentionRows*> _mrows;
|
||||
const not_null<HashtagRows*> _hrows;
|
||||
const not_null<BotCommandRows*> _brows;
|
||||
const not_null<StickerRows*> _srows;
|
||||
rpl::lifetime _stickersLifetime;
|
||||
std::weak_ptr<Lottie::FrameRenderer> _lottieRenderer;
|
||||
int _stickersPerRow = 1;
|
||||
|
||||
@@ -518,6 +518,21 @@ void Application::switchTestMode() {
|
||||
App::restart();
|
||||
}
|
||||
|
||||
void Application::switchFreeType() {
|
||||
if (cUseFreeType()) {
|
||||
QFile(cWorkingDir() + qsl("tdata/withfreetype")).remove();
|
||||
cSetUseFreeType(false);
|
||||
} else {
|
||||
QFile f(cWorkingDir() + qsl("tdata/withfreetype"));
|
||||
if (f.open(QIODevice::WriteOnly)) {
|
||||
f.write("1");
|
||||
f.close();
|
||||
}
|
||||
cSetUseFreeType(true);
|
||||
}
|
||||
App::restart();
|
||||
}
|
||||
|
||||
void Application::writeInstallBetaVersionsSetting() {
|
||||
_launcher->writeInstallBetaVersionsSetting();
|
||||
}
|
||||
|
||||
@@ -215,6 +215,7 @@ public:
|
||||
|
||||
void switchDebugMode();
|
||||
void switchTestMode();
|
||||
void switchFreeType();
|
||||
void writeInstallBetaVersionsSetting();
|
||||
|
||||
void call_handleUnreadCounterUpdate();
|
||||
|
||||
@@ -34,26 +34,47 @@ private:
|
||||
static constexpr auto kForwardArgumentCount = 1;
|
||||
|
||||
int _count = 0;
|
||||
char *_arguments[kForwardArgumentCount + 1] = { nullptr };
|
||||
std::vector<QByteArray> _owned;
|
||||
std::vector<char*> _arguments;
|
||||
|
||||
void pushArgument(const char *text);
|
||||
|
||||
};
|
||||
|
||||
FilteredCommandLineArguments::FilteredCommandLineArguments(
|
||||
int argc,
|
||||
char **argv)
|
||||
: _count(std::clamp(argc, 0, kForwardArgumentCount)) {
|
||||
char **argv) {
|
||||
// For now just pass only the first argument, the executable path.
|
||||
for (auto i = 0; i != _count; ++i) {
|
||||
_arguments[i] = argv[i];
|
||||
for (auto i = 0; i != kForwardArgumentCount; ++i) {
|
||||
pushArgument(argv[i]);
|
||||
}
|
||||
|
||||
#if defined Q_OS_WIN || defined Q_OS_MAC
|
||||
if (cUseFreeType()) {
|
||||
pushArgument("-platform");
|
||||
#ifdef Q_OS_WIN
|
||||
pushArgument("windows:fontengine=freetype");
|
||||
#else // Q_OS_WIN
|
||||
pushArgument("cocoa:fontengine=freetype");
|
||||
#endif // !Q_OS_WIN
|
||||
}
|
||||
#endif // Q_OS_WIN || Q_OS_MAC
|
||||
|
||||
pushArgument(nullptr);
|
||||
}
|
||||
|
||||
int &FilteredCommandLineArguments::count() {
|
||||
_count = _arguments.size() - 1;
|
||||
return _count;
|
||||
}
|
||||
|
||||
char **FilteredCommandLineArguments::values() {
|
||||
return _arguments;
|
||||
return _arguments.data();
|
||||
}
|
||||
|
||||
void FilteredCommandLineArguments::pushArgument(const char *text) {
|
||||
_owned.emplace_back(text);
|
||||
_arguments.push_back(_owned.back().data());
|
||||
}
|
||||
|
||||
QString DebugModeSettingPath() {
|
||||
@@ -82,6 +103,12 @@ void ComputeTestMode() {
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeFreeType() {
|
||||
if (QFile(cWorkingDir() + qsl("tdata/withfreetype")).exists()) {
|
||||
cSetUseFreeType(true);
|
||||
}
|
||||
}
|
||||
|
||||
QString InstallBetaVersionsSettingPath() {
|
||||
return cWorkingDir() + qsl("tdata/devversion");
|
||||
}
|
||||
@@ -301,6 +328,7 @@ void Launcher::workingFolderReady() {
|
||||
|
||||
ComputeTestMode();
|
||||
ComputeDebugMode();
|
||||
ComputeFreeType();
|
||||
ComputeInstallBetaVersions();
|
||||
ComputeInstallationTag();
|
||||
}
|
||||
@@ -382,6 +410,7 @@ void Launcher::processArguments() {
|
||||
auto parseMap = std::map<QByteArray, KeyFormat> {
|
||||
{ "-testmode" , KeyFormat::NoValues },
|
||||
{ "-debug" , KeyFormat::NoValues },
|
||||
{ "-freetype" , KeyFormat::NoValues },
|
||||
{ "-many" , KeyFormat::NoValues },
|
||||
{ "-key" , KeyFormat::OneValue },
|
||||
{ "-autostart" , KeyFormat::NoValues },
|
||||
@@ -423,6 +452,7 @@ void Launcher::processArguments() {
|
||||
SetUpdaterDisabledAtStartup();
|
||||
}
|
||||
gTestMode = parseResult.contains("-testmode");
|
||||
gUseFreeType = parseResult.contains("-freetype");
|
||||
Logs::SetDebugEnabled(parseResult.contains("-debug"));
|
||||
gManyInstance = parseResult.contains("-many");
|
||||
gKeyFile = parseResult.value("-key", {}).join(QString()).toLower();
|
||||
|
||||
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/connection_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "boxes/sessions_box.h"
|
||||
#include "boxes/language_box.h"
|
||||
#include "passport/passport_form_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "data/data_session.h"
|
||||
@@ -101,12 +102,21 @@ bool ShowTheme(
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowLanguagesBox() {
|
||||
static auto Guard = base::binary_guard();
|
||||
Guard = LanguageBox::Show();
|
||||
}
|
||||
|
||||
bool SetLanguage(
|
||||
Main::Session *session,
|
||||
const Match &match,
|
||||
const QVariant &context) {
|
||||
const auto languageId = match->captured(1);
|
||||
Lang::CurrentCloudManager().switchWithWarning(languageId);
|
||||
if (match->capturedRef(1).isEmpty()) {
|
||||
ShowLanguagesBox();
|
||||
} else {
|
||||
const auto languageId = match->captured(2);
|
||||
Lang::CurrentCloudManager().switchWithWarning(languageId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -351,6 +361,9 @@ bool ResolveSettings(
|
||||
if (section == qstr("devices")) {
|
||||
Ui::show(Box<SessionsBox>(session));
|
||||
return true;
|
||||
} else if (section == qstr("language")) {
|
||||
ShowLanguagesBox();
|
||||
return true;
|
||||
}
|
||||
const auto type = (section == qstr("folders"))
|
||||
? ::Settings::Type::Folders
|
||||
@@ -441,7 +454,7 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
||||
ShowTheme
|
||||
},
|
||||
{
|
||||
qsl("^setlanguage/?\\?lang=([a-zA-Z0-9\\.\\_\\-]+)(&|$)"),
|
||||
qsl("^setlanguage/?(\\?lang=([a-zA-Z0-9\\.\\_\\-]+))?(&|$)"),
|
||||
SetLanguage
|
||||
},
|
||||
{
|
||||
@@ -481,7 +494,7 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
||||
ResolvePrivatePost
|
||||
},
|
||||
{
|
||||
qsl("^settings(/folders|/devices)?$"),
|
||||
qsl("^settings(/folders|/devices|/language)?$"),
|
||||
ResolveSettings
|
||||
},
|
||||
{
|
||||
|
||||
@@ -373,11 +373,8 @@ void Sandbox::readClients() {
|
||||
toSend.append(_escapeFrom7bit(cmds.mid(from + 5, to - from - 5)));
|
||||
}
|
||||
} else if (cmd.startsWith(qsl("OPEN:"))) {
|
||||
auto activateRequired = true;
|
||||
if (cStartUrl().isEmpty()) {
|
||||
startUrl = _escapeFrom7bit(cmds.mid(from + 5, to - from - 5)).mid(0, 8192);
|
||||
activateRequired = StartUrlRequiresActivate(startUrl);
|
||||
}
|
||||
startUrl = _escapeFrom7bit(cmds.mid(from + 5, to - from - 5)).mid(0, 8192);
|
||||
auto activateRequired = StartUrlRequiresActivate(startUrl);
|
||||
if (activateRequired) {
|
||||
execExternal("show");
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ extern "C" {
|
||||
#include <openssl/err.h>
|
||||
} // extern "C"
|
||||
|
||||
#ifdef Q_OS_WIN // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
#include <LzmaLib.h>
|
||||
#else // Q_OS_WIN
|
||||
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
#include <lzma.h>
|
||||
#endif // else of Q_OS_WIN
|
||||
#endif // else of Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
@@ -252,11 +252,11 @@ bool UnpackUpdate(const QString &filepath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
|
||||
#else // Q_OS_WIN
|
||||
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header
|
||||
#endif // Q_OS_WIN
|
||||
#endif // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
|
||||
QByteArray compressed = input.readAll();
|
||||
int32 compressedLen = compressed.size() - hSize;
|
||||
@@ -311,14 +311,14 @@ bool UnpackUpdate(const QString &filepath) {
|
||||
uncompressed.resize(uncompressedLen);
|
||||
|
||||
size_t resultLen = uncompressed.size();
|
||||
#ifdef Q_OS_WIN // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
SizeT srcLen = compressedLen;
|
||||
int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
|
||||
if (uncompressRes != SZ_OK) {
|
||||
LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
|
||||
return false;
|
||||
}
|
||||
#else // Q_OS_WIN
|
||||
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
lzma_stream stream = LZMA_STREAM_INIT;
|
||||
|
||||
lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED);
|
||||
@@ -361,7 +361,7 @@ bool UnpackUpdate(const QString &filepath) {
|
||||
LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res));
|
||||
return false;
|
||||
}
|
||||
#endif // Q_OS_WIN
|
||||
#endif // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
|
||||
tempDir.mkdir(tempDir.absolutePath());
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 2001002;
|
||||
constexpr auto AppVersionStr = "2.1.2";
|
||||
constexpr auto AppVersion = 2001007;
|
||||
constexpr auto AppVersionStr = "2.1.7";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -66,23 +66,32 @@ void Histories::clearAll() {
|
||||
}
|
||||
|
||||
void Histories::readInbox(not_null<History*> history) {
|
||||
DEBUG_LOG(("Reading: readInbox called."));
|
||||
if (history->lastServerMessageKnown()) {
|
||||
const auto last = history->lastServerMessage();
|
||||
DEBUG_LOG(("Reading: last known, reading till %1."
|
||||
).arg(last ? last->id : 0));
|
||||
readInboxTill(history, last ? last->id : 0);
|
||||
return;
|
||||
} else if (history->loadedAtBottom()) {
|
||||
if (const auto lastId = history->maxMsgId()) {
|
||||
DEBUG_LOG(("Reading: loaded at bottom, maxMsgId %1."
|
||||
).arg(lastId));
|
||||
readInboxTill(history, lastId);
|
||||
return;
|
||||
} else if (history->loadedAtTop()) {
|
||||
DEBUG_LOG(("Reading: loaded at bottom, loaded at top."));
|
||||
readInboxTill(history, 0);
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(("Reading: loaded at bottom, but requesting entry."));
|
||||
}
|
||||
requestDialogEntry(history, [=] {
|
||||
Expects(history->lastServerMessageKnown());
|
||||
|
||||
const auto last = history->lastServerMessage();
|
||||
DEBUG_LOG(("Reading: got entry, reading till %1."
|
||||
).arg(last ? last->id : 0));
|
||||
readInboxTill(history, last ? last->id : 0);
|
||||
});
|
||||
}
|
||||
@@ -135,10 +144,20 @@ void Histories::readInboxTill(
|
||||
bool force) {
|
||||
Expects(IsServerMsgId(tillId) || (!tillId && !force));
|
||||
|
||||
DEBUG_LOG(("Reading: readInboxTill %1, force %2."
|
||||
).arg(tillId
|
||||
).arg(Logs::b(force)));
|
||||
|
||||
const auto syncGuard = gsl::finally([&] {
|
||||
DEBUG_LOG(("Reading: in guard, unread %1."
|
||||
).arg(history->unreadCount()));
|
||||
if (history->unreadCount() > 0) {
|
||||
if (const auto last = history->lastServerMessage()) {
|
||||
DEBUG_LOG(("Reading: checking last %1 and %2."
|
||||
).arg(last->id
|
||||
).arg(tillId));
|
||||
if (last->id == tillId) {
|
||||
DEBUG_LOG(("Reading: locally marked as read."));
|
||||
history->setUnreadCount(0);
|
||||
history->updateChatListEntry();
|
||||
}
|
||||
@@ -150,14 +169,21 @@ void Histories::readInboxTill(
|
||||
|
||||
const auto needsRequest = history->readInboxTillNeedsRequest(tillId);
|
||||
if (!needsRequest && !force) {
|
||||
DEBUG_LOG(("Reading: readInboxTill finish 1."));
|
||||
return;
|
||||
} else if (!history->trackUnreadMessages()) {
|
||||
DEBUG_LOG(("Reading: readInboxTill finish 2."));
|
||||
return;
|
||||
}
|
||||
const auto maybeState = lookup(history);
|
||||
if (maybeState && maybeState->sentReadTill >= tillId) {
|
||||
DEBUG_LOG(("Reading: readInboxTill finish 3 with %1."
|
||||
).arg(maybeState->sentReadTill));
|
||||
return;
|
||||
} else if (maybeState && maybeState->willReadTill >= tillId) {
|
||||
DEBUG_LOG(("Reading: readInboxTill finish 4 with %1 and force %2."
|
||||
).arg(maybeState->sentReadTill
|
||||
).arg(Logs::b(force)));
|
||||
if (force) {
|
||||
sendPendingReadInbox(history);
|
||||
}
|
||||
@@ -171,23 +197,35 @@ void Histories::readInboxTill(
|
||||
&& stillUnread
|
||||
&& history->unreadCountKnown()
|
||||
&& *stillUnread == history->unreadCount()) {
|
||||
DEBUG_LOG(("Reading: count didn't change so just update till %1"
|
||||
).arg(tillId));
|
||||
history->setInboxReadTill(tillId);
|
||||
return;
|
||||
}
|
||||
auto &state = maybeState ? *maybeState : _states[history];
|
||||
state.willReadTill = tillId;
|
||||
if (force || !stillUnread || !*stillUnread) {
|
||||
DEBUG_LOG(("Reading: will read till %1 with still unread %2"
|
||||
).arg(tillId
|
||||
).arg(stillUnread.value_or(-666)));
|
||||
state.willReadWhen = 0;
|
||||
sendReadRequests();
|
||||
if (!stillUnread) {
|
||||
return;
|
||||
}
|
||||
} else if (!state.willReadWhen) {
|
||||
DEBUG_LOG(("Reading: will read till %1 with postponed").arg(tillId));
|
||||
state.willReadWhen = crl::now() + kReadRequestTimeout;
|
||||
if (!_readRequestsTimer.isActive()) {
|
||||
_readRequestsTimer.callOnce(kReadRequestTimeout);
|
||||
}
|
||||
} else {
|
||||
DEBUG_LOG(("Reading: will read till %1 postponed already"
|
||||
).arg(tillId));
|
||||
}
|
||||
DEBUG_LOG(("Reading: marking now with till %1 and still %2"
|
||||
).arg(tillId
|
||||
).arg(*stillUnread));
|
||||
history->setInboxReadTill(tillId);
|
||||
history->setUnreadCount(*stillUnread);
|
||||
history->updateChatListEntry();
|
||||
@@ -399,6 +437,9 @@ void Histories::requestFakeChatListMessage(
|
||||
|
||||
void Histories::sendPendingReadInbox(not_null<History*> history) {
|
||||
if (const auto state = lookup(history)) {
|
||||
DEBUG_LOG(("Reading: send pending now with till %1 and when %2"
|
||||
).arg(state->willReadTill
|
||||
).arg(state->willReadWhen));
|
||||
if (state->willReadTill && state->willReadWhen) {
|
||||
state->willReadWhen = 0;
|
||||
sendReadRequests();
|
||||
@@ -407,6 +448,7 @@ void Histories::sendPendingReadInbox(not_null<History*> history) {
|
||||
}
|
||||
|
||||
void Histories::sendReadRequests() {
|
||||
DEBUG_LOG(("Reading: send requests with count %1.").arg(_states.size()));
|
||||
if (_states.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -414,10 +456,14 @@ void Histories::sendReadRequests() {
|
||||
auto next = std::optional<crl::time>();
|
||||
for (auto &[history, state] : _states) {
|
||||
if (!state.willReadTill) {
|
||||
DEBUG_LOG(("Reading: skipping zero till."));
|
||||
continue;
|
||||
} else if (state.willReadWhen <= now) {
|
||||
DEBUG_LOG(("Reading: sending with till %1."
|
||||
).arg(state.willReadTill));
|
||||
sendReadRequest(history, state);
|
||||
} else if (!next || *next > state.willReadWhen) {
|
||||
DEBUG_LOG(("Reading: scheduling for later send."));
|
||||
next = state.willReadWhen;
|
||||
}
|
||||
}
|
||||
@@ -434,7 +480,11 @@ void Histories::sendReadRequest(not_null<History*> history, State &state) {
|
||||
const auto tillId = state.sentReadTill = base::take(state.willReadTill);
|
||||
state.willReadWhen = 0;
|
||||
state.sentReadDone = false;
|
||||
DEBUG_LOG(("Reading: sending request now with till %1."
|
||||
).arg(tillId));
|
||||
sendRequest(history, RequestType::ReadInbox, [=](Fn<void()> finish) {
|
||||
DEBUG_LOG(("Reading: sending request invoked with till %1."
|
||||
).arg(tillId));
|
||||
const auto finished = [=] {
|
||||
const auto state = lookup(history);
|
||||
Assert(state != nullptr);
|
||||
|
||||
@@ -770,7 +770,7 @@ int PeerData::slowmodeSecondsLeft() const {
|
||||
|
||||
bool PeerData::canSendPolls() const {
|
||||
if (const auto user = asUser()) {
|
||||
return user->isBot();
|
||||
return user->isBot() && !user->isSupport();
|
||||
} else if (const auto chat = asChat()) {
|
||||
return chat->canSendPolls();
|
||||
} else if (const auto channel = asChannel()) {
|
||||
|
||||
@@ -414,6 +414,7 @@ HistoryItem *ScheduledMessages::append(
|
||||
}, data.vmedia());
|
||||
existing->updateReplyMarkup(data.vreply_markup());
|
||||
existing->updateForwardedInfo(data.vfwd_from());
|
||||
existing->updateDate(data.vdate().v);
|
||||
history->owner().requestItemTextRefresh(existing);
|
||||
}, [&](const auto &data) {});
|
||||
return existing;
|
||||
|
||||
@@ -1549,6 +1549,17 @@ void InnerWidget::repaintDialogRow(RowDescriptor row) {
|
||||
updateDialogRow(row);
|
||||
}
|
||||
|
||||
void InnerWidget::refreshDialogRow(RowDescriptor row) {
|
||||
if (row.fullId) {
|
||||
for (const auto &result : _searchResults) {
|
||||
if (result->item()->fullId() == row.fullId) {
|
||||
result->invalidateCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
repaintDialogRow(row);
|
||||
}
|
||||
|
||||
void InnerWidget::updateSearchResult(not_null<PeerData*> peer) {
|
||||
if (_state == WidgetState::Filtered) {
|
||||
if (!_peerSearchResults.empty()) {
|
||||
|
||||
@@ -92,6 +92,7 @@ public:
|
||||
void removeDialog(Key key);
|
||||
void repaintDialogRow(FilterId filterId, not_null<Row*> row);
|
||||
void repaintDialogRow(RowDescriptor row);
|
||||
void refreshDialogRow(RowDescriptor row);
|
||||
|
||||
void dragLeft();
|
||||
|
||||
|
||||
@@ -121,6 +121,11 @@ public:
|
||||
return _item;
|
||||
}
|
||||
|
||||
void invalidateCache() {
|
||||
_cacheFor = nullptr;
|
||||
_cache = Ui::Text::String();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Layout::RowPainter;
|
||||
|
||||
|
||||
@@ -549,6 +549,10 @@ void Widget::repaintDialogRow(RowDescriptor row) {
|
||||
_inner->repaintDialogRow(row);
|
||||
}
|
||||
|
||||
void Widget::refreshDialogRow(RowDescriptor row) {
|
||||
_inner->refreshDialogRow(row);
|
||||
}
|
||||
|
||||
void Widget::jumpToTop() {
|
||||
if (session().supportMode()) {
|
||||
return;
|
||||
@@ -674,7 +678,6 @@ void Widget::animationCallback() {
|
||||
|
||||
updateControlsVisibility(true);
|
||||
|
||||
applyFilterUpdate();
|
||||
if (!_filter->hasFocus()) {
|
||||
if (App::wnd()) App::wnd()->setInnerFocus();
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
void removeDialog(Key key);
|
||||
void repaintDialogRow(FilterId filterId, not_null<Row*> row);
|
||||
void repaintDialogRow(RowDescriptor row);
|
||||
void refreshDialogRow(RowDescriptor row);
|
||||
|
||||
void jumpToTop();
|
||||
|
||||
|
||||
@@ -381,7 +381,9 @@ struct Data {
|
||||
bool VoiceMsgPlaybackDoubled = false;
|
||||
bool SoundNotify = true;
|
||||
bool DesktopNotify = true;
|
||||
bool FlashBounceNotify = true;
|
||||
bool RestoreSoundNotifyFromTray = false;
|
||||
bool RestoreFlashBounceNotifyFromTray = false;
|
||||
DBINotifyView NotifyView = dbinvShowPreview;
|
||||
bool NativeNotifications = false;
|
||||
int NotificationsCount = 3;
|
||||
@@ -508,7 +510,9 @@ DefineRefVar(Global, base::Observable<void>, DownloadPathChanged);
|
||||
DefineVar(Global, bool, VoiceMsgPlaybackDoubled);
|
||||
DefineVar(Global, bool, SoundNotify);
|
||||
DefineVar(Global, bool, DesktopNotify);
|
||||
DefineVar(Global, bool, FlashBounceNotify);
|
||||
DefineVar(Global, bool, RestoreSoundNotifyFromTray);
|
||||
DefineVar(Global, bool, RestoreFlashBounceNotifyFromTray);
|
||||
DefineVar(Global, DBINotifyView, NotifyView);
|
||||
DefineVar(Global, bool, NativeNotifications);
|
||||
DefineVar(Global, int, NotificationsCount);
|
||||
|
||||
@@ -210,7 +210,9 @@ DeclareRefVar(base::Observable<void>, DownloadPathChanged);
|
||||
DeclareVar(bool, VoiceMsgPlaybackDoubled);
|
||||
DeclareVar(bool, SoundNotify);
|
||||
DeclareVar(bool, DesktopNotify);
|
||||
DeclareVar(bool, FlashBounceNotify);
|
||||
DeclareVar(bool, RestoreSoundNotifyFromTray);
|
||||
DeclareVar(bool, RestoreFlashBounceNotifyFromTray);
|
||||
DeclareVar(DBINotifyView, NotifyView);
|
||||
DeclareVar(bool, NativeNotifications);
|
||||
DeclareVar(int, NotificationsCount);
|
||||
|
||||
@@ -478,7 +478,7 @@ void InnerWidget::updateEmptyText() {
|
||||
options.flags |= TextParseMarkdown;
|
||||
auto hasSearch = !_searchQuery.isEmpty();
|
||||
auto hasFilter = (_filter.flags != 0) || !_filter.allUsers;
|
||||
auto text = Ui::Text::Bold((hasSearch || hasFilter)
|
||||
auto text = Ui::Text::Semibold((hasSearch || hasFilter)
|
||||
? tr::lng_admin_log_no_results_title(tr::now)
|
||||
: tr::lng_admin_log_no_events_title(tr::now));
|
||||
auto description = hasSearch
|
||||
|
||||
@@ -1622,6 +1622,9 @@ bool History::readInboxTillNeedsRequest(MsgId tillId) {
|
||||
if (unreadMark()) {
|
||||
owner().histories().changeDialogUnreadMark(this, false);
|
||||
}
|
||||
DEBUG_LOG(("Reading: readInboxTillNeedsRequest is_server %1, before %2."
|
||||
).arg(Logs::b(IsServerMsgId(tillId))
|
||||
).arg(_inboxReadBefore.value_or(-666)));
|
||||
return IsServerMsgId(tillId) && (_inboxReadBefore.value_or(1) <= tillId);
|
||||
}
|
||||
|
||||
@@ -1639,10 +1642,17 @@ bool History::unreadCountRefreshNeeded(MsgId readTillId) const {
|
||||
|
||||
std::optional<int> History::countStillUnreadLocal(MsgId readTillId) const {
|
||||
if (isEmpty() || !folderKnown()) {
|
||||
DEBUG_LOG(("Reading: countStillUnreadLocal unknown %1 and %2."
|
||||
).arg(Logs::b(isEmpty())
|
||||
).arg(Logs::b(folderKnown())));
|
||||
return std::nullopt;
|
||||
}
|
||||
if (_inboxReadBefore) {
|
||||
const auto before = *_inboxReadBefore;
|
||||
DEBUG_LOG(("Reading: check before %1 with min %2 and max %3."
|
||||
).arg(before
|
||||
).arg(minMsgId()
|
||||
).arg(maxMsgId()));
|
||||
if (minMsgId() <= before && maxMsgId() >= readTillId) {
|
||||
auto result = 0;
|
||||
for (const auto &block : blocks) {
|
||||
@@ -1658,12 +1668,19 @@ std::optional<int> History::countStillUnreadLocal(MsgId readTillId) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(("Reading: check before result %1 with existing %2"
|
||||
).arg(result
|
||||
).arg(_unreadCount.value_or(-666)));
|
||||
if (_unreadCount) {
|
||||
return std::max(*_unreadCount - result, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto minimalServerId = minMsgId();
|
||||
DEBUG_LOG(("Reading: check at end loaded from %1 loaded %2 - %3"
|
||||
).arg(minimalServerId
|
||||
).arg(Logs::b(loadedAtBottom())
|
||||
).arg(Logs::b(loadedAtTop())));
|
||||
if (!loadedAtBottom()
|
||||
|| (!loadedAtTop() && !minimalServerId)
|
||||
|| minimalServerId > readTillId) {
|
||||
@@ -1682,6 +1699,7 @@ std::optional<int> History::countStillUnreadLocal(MsgId readTillId) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(("Reading: check at end counted %1").arg(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ PeerData *HistoryItem::displayFrom() const {
|
||||
void HistoryItem::invalidateChatListEntry() {
|
||||
if (const auto main = App::main()) {
|
||||
// #TODO feeds search results
|
||||
main->repaintDialogRow({ history(), fullId() });
|
||||
main->refreshDialogRow({ history(), fullId() });
|
||||
}
|
||||
|
||||
// invalidate cache for drawInDialog
|
||||
@@ -708,6 +708,17 @@ MsgId HistoryItem::idOriginal() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
void HistoryItem::updateDate(TimeId newDate) {
|
||||
if (canUpdateDate() && _date != newDate) {
|
||||
_date = newDate;
|
||||
_history->owner().requestItemViewRefresh(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool HistoryItem::canUpdateDate() const {
|
||||
return isScheduled();
|
||||
}
|
||||
|
||||
void HistoryItem::sendFailed() {
|
||||
Expects(_clientFlags & MTPDmessage_ClientFlag::f_sending);
|
||||
Expects(!(_clientFlags & MTPDmessage_ClientFlag::f_failed));
|
||||
|
||||
@@ -328,6 +328,9 @@ public:
|
||||
[[nodiscard]] virtual std::unique_ptr<HistoryView::Element> createView(
|
||||
not_null<HistoryView::ElementDelegate*> delegate) = 0;
|
||||
|
||||
void updateDate(TimeId newDate);
|
||||
[[nodiscard]] bool canUpdateDate() const;
|
||||
|
||||
virtual ~HistoryItem();
|
||||
|
||||
MsgId id;
|
||||
|
||||
@@ -695,7 +695,7 @@ void HistoryMessage::createComponentsHelper(
|
||||
if (flags & MTPDmessage::Flag::f_reply_to_msg_id) config.replyTo = replyTo;
|
||||
if (flags & MTPDmessage::Flag::f_reply_markup) config.mtpMarkup = &markup;
|
||||
if (flags & MTPDmessage::Flag::f_post_author) config.author = postAuthor;
|
||||
if (isPost()) config.viewsCount = 1;
|
||||
if (flags & MTPDmessage::Flag::f_views) config.viewsCount = 1;
|
||||
|
||||
createComponents(config);
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ HistoryWidget::HistoryWidget(
|
||||
, _scroll(this, st::historyScroll, false)
|
||||
, _historyDown(_scroll, st::historyToDown)
|
||||
, _unreadMentions(_scroll, st::historyUnreadMentions)
|
||||
, _fieldAutocomplete(this, &session())
|
||||
, _fieldAutocomplete(this, controller)
|
||||
, _supportAutocomplete(session().supportMode()
|
||||
? object_ptr<Support::Autocomplete>(this, &session())
|
||||
: nullptr)
|
||||
@@ -1433,8 +1433,7 @@ bool HistoryWidget::notify_switchInlineBotButtonReceived(const QString &query, U
|
||||
if (_history) {
|
||||
TextWithTags textWithTags = { '@' + samePeerBot->username + ' ' + query, TextWithTags::Tags() };
|
||||
MessageCursor cursor = { textWithTags.text.size(), textWithTags.text.size(), QFIXED_MAX };
|
||||
auto replyTo = _history->peer->isUser() ? 0 : samePeerReplyTo;
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(textWithTags, replyTo, cursor, false));
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(textWithTags, 0, cursor, false));
|
||||
applyDraft();
|
||||
return true;
|
||||
}
|
||||
@@ -4476,10 +4475,7 @@ bool HistoryWidget::canSendFiles(not_null<const QMimeData*> data) const {
|
||||
} else if (data->hasImage()) {
|
||||
return true;
|
||||
} else if (const auto urls = data->urls(); !urls.empty()) {
|
||||
if (ranges::find_if(
|
||||
urls,
|
||||
[](const QUrl &url) { return !url.isLocalFile(); }
|
||||
) == urls.end()) {
|
||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4681,15 +4677,7 @@ void HistoryWidget::sendFileConfirmed(
|
||||
}
|
||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||
const auto silentPost = file->to.options.silent;
|
||||
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;
|
||||
}
|
||||
Api::FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
flags |= MTPDmessage::Flag::f_silent;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,9 @@ class HistoryWidget final
|
||||
public:
|
||||
using FieldHistoryAction = Ui::InputField::HistoryAction;
|
||||
|
||||
HistoryWidget(QWidget *parent, not_null<Window::SessionController*> controller);
|
||||
HistoryWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller);
|
||||
|
||||
void start();
|
||||
|
||||
|
||||
@@ -110,6 +110,10 @@ rpl::producer<> ComposeControls::attachRequests() const {
|
||||
});
|
||||
}
|
||||
|
||||
void ComposeControls::setMimeDataHook(MimeDataHook hook) {
|
||||
_field->setMimeDataHook(std::move(hook));
|
||||
}
|
||||
|
||||
rpl::producer<not_null<DocumentData*>> ComposeControls::fileChosen() const {
|
||||
return _fileChosen.events();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/unique_qptr.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
|
||||
class History;
|
||||
@@ -31,7 +32,6 @@ namespace Ui {
|
||||
class SendButton;
|
||||
class IconButton;
|
||||
class EmojiButton;
|
||||
class InputField;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Main {
|
||||
@@ -76,6 +76,11 @@ public:
|
||||
[[nodiscard]] auto inlineResultChosen() const
|
||||
-> rpl::producer<ChatHelpers::TabbedSelector::InlineChosen>;
|
||||
|
||||
using MimeDataHook = Fn<bool(
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action)>;
|
||||
void setMimeDataHook(MimeDataHook hook);
|
||||
|
||||
bool pushTabbedSelectorToThirdSection(
|
||||
not_null<PeerData*> peer,
|
||||
const Window::SectionShow ¶ms);
|
||||
|
||||
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_message.h"
|
||||
#include "history/history_item_text.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "history/view/media/history_view_media.h"
|
||||
#include "history/view/media/history_view_web_page.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
@@ -29,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_groups.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
@@ -61,6 +63,14 @@ constexpr auto kExportLocalTimeout = crl::time(1000);
|
||||
// }
|
||||
//}
|
||||
|
||||
MsgId ItemIdAcrossData(not_null<HistoryItem*> item) {
|
||||
if (!item->isScheduled()) {
|
||||
return item->id;
|
||||
}
|
||||
const auto session = &item->history()->session();
|
||||
return session->data().scheduledMessages().lookupId(item);
|
||||
}
|
||||
|
||||
void SavePhotoToFile(not_null<PhotoData*> photo) {
|
||||
if (photo->isNull() || !photo->loaded()) {
|
||||
return;
|
||||
@@ -385,6 +395,49 @@ bool AddSendNowMessageAction(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddRescheduleMessageAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
const ContextMenuRequest &request) {
|
||||
const auto item = request.item;
|
||||
if (!item || item->isSending() || !request.selectedItems.empty()) {
|
||||
return false;
|
||||
}
|
||||
const auto peer = item->history()->peer;
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
if (!channel->canEditMessages()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const auto owner = &item->history()->owner();
|
||||
const auto itemId = item->fullId();
|
||||
menu->addAction(tr::lng_context_reschedule(tr::now), [=] {
|
||||
const auto item = owner->message(itemId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const auto callback = [=](Api::SendOptions options) {
|
||||
item->history()->session().api().rescheduleMessage(item, options);
|
||||
};
|
||||
|
||||
const auto sendMenuType = !peer
|
||||
? SendMenuType::Disabled
|
||||
: peer->isSelf()
|
||||
? SendMenuType::Reminder
|
||||
: HistoryView::CanScheduleUntilOnline(peer)
|
||||
? SendMenuType::ScheduledToUser
|
||||
: SendMenuType::Scheduled;
|
||||
|
||||
Ui::show(
|
||||
HistoryView::PrepareScheduleBox(
|
||||
&request.navigation->session(),
|
||||
sendMenuType,
|
||||
callback,
|
||||
item->date() + 600),
|
||||
Ui::LayerOption::KeepOther);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddSendNowAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
const ContextMenuRequest &request,
|
||||
@@ -436,7 +489,8 @@ bool AddDeleteMessageAction(
|
||||
if (asGroup) {
|
||||
if (const auto group = owner->groups().find(item)) {
|
||||
if (ranges::find_if(group->items, [](auto item) {
|
||||
return !IsServerMsgId(item->id) || !item->canDelete();
|
||||
const auto id = ItemIdAcrossData(item);
|
||||
return !IsServerMsgId(id) || !item->canDelete();
|
||||
}) != end(group->items)) {
|
||||
return false;
|
||||
}
|
||||
@@ -495,7 +549,9 @@ bool AddSelectMessageAction(
|
||||
const auto item = request.item;
|
||||
if (request.overSelection && !request.selectedItems.empty()) {
|
||||
return false;
|
||||
} else if (!item || !IsServerMsgId(item->id) || item->serviceMsg()) {
|
||||
} else if (!item
|
||||
|| !IsServerMsgId(ItemIdAcrossData(item))
|
||||
|| item->serviceMsg()) {
|
||||
return false;
|
||||
}
|
||||
const auto owner = &item->history()->owner();
|
||||
@@ -531,6 +587,7 @@ void AddMessageActions(
|
||||
AddSendNowAction(menu, request, list);
|
||||
AddDeleteAction(menu, request, list);
|
||||
AddSelectionAction(menu, request, list);
|
||||
AddRescheduleMessageAction(menu, request);
|
||||
}
|
||||
|
||||
void AddCopyLinkAction(
|
||||
|
||||
@@ -937,6 +937,7 @@ void ListWidget::selectItemAsGroup(not_null<HistoryItem*> item) {
|
||||
item,
|
||||
SelectAction::Select);
|
||||
pushSelectedItems();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1464,6 +1464,12 @@ int Message::plainMaxWidth() const {
|
||||
+ st::msgPadding.right();
|
||||
}
|
||||
|
||||
int Message::monospaceMaxWidth() const {
|
||||
return st::msgPadding.left()
|
||||
+ (hasVisibleText() ? message()->_text.countMaxMonospaceWidth() : 0)
|
||||
+ st::msgPadding.right();
|
||||
}
|
||||
|
||||
void Message::initLogEntryOriginal() {
|
||||
if (const auto log = message()->Get<HistoryMessageLogEntryOriginal>()) {
|
||||
AddComponents(LogEntryOriginal::Bit());
|
||||
@@ -1757,6 +1763,9 @@ void Message::fromNameUpdated(int width) const {
|
||||
}
|
||||
|
||||
TextSelection Message::skipTextSelection(TextSelection selection) const {
|
||||
if (selection.from == 0xFFFF) {
|
||||
return selection;
|
||||
}
|
||||
return HistoryView::UnshiftItemSelection(selection, message()->_text);
|
||||
}
|
||||
|
||||
@@ -1787,7 +1796,7 @@ QRect Message::countGeometry() const {
|
||||
// contentLeft += st::msgPhotoSkip - (hmaxwidth - hwidth);
|
||||
}
|
||||
accumulate_min(contentWidth, maxWidth());
|
||||
accumulate_min(contentWidth, st::msgMaxWidth);
|
||||
accumulate_min(contentWidth, _bubbleWidthLimit);
|
||||
if (mediaWidth < contentWidth) {
|
||||
const auto textualWidth = plainMaxWidth();
|
||||
if (mediaWidth < textualWidth
|
||||
@@ -1829,7 +1838,8 @@ int Message::resizeContentGetHeight(int newWidth) {
|
||||
contentWidth -= st::msgPhotoSkip;
|
||||
}
|
||||
accumulate_min(contentWidth, maxWidth());
|
||||
accumulate_min(contentWidth, st::msgMaxWidth);
|
||||
_bubbleWidthLimit = std::max(st::msgMaxWidth, monospaceMaxWidth());
|
||||
accumulate_min(contentWidth, _bubbleWidthLimit);
|
||||
if (mediaDisplayed) {
|
||||
media->resizeGetHeight(contentWidth);
|
||||
if (media->width() < contentWidth) {
|
||||
|
||||
@@ -157,8 +157,9 @@ private:
|
||||
const HistoryMessageEdited *displayedEditBadge() const;
|
||||
HistoryMessageEdited *displayedEditBadge();
|
||||
void initTime();
|
||||
int timeLeft() const;
|
||||
int plainMaxWidth() const;
|
||||
[[nodiscard]] int timeLeft() const;
|
||||
[[nodiscard]] int plainMaxWidth() const;
|
||||
[[nodiscard]] int monospaceMaxWidth() const;
|
||||
|
||||
WebPage *logEntryOriginal() const;
|
||||
|
||||
@@ -167,6 +168,7 @@ private:
|
||||
|
||||
mutable ClickHandlerPtr _rightActionLink;
|
||||
mutable ClickHandlerPtr _fastReplyLink;
|
||||
int _bubbleWidthLimit = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -29,12 +29,13 @@ template <typename Guard, typename Submit>
|
||||
[[nodiscard]] object_ptr<Ui::GenericBox> PrepareScheduleBox(
|
||||
Guard &&guard,
|
||||
SendMenuType type,
|
||||
Submit &&submit) {
|
||||
Submit &&submit,
|
||||
TimeId scheduleTime = DefaultScheduleTime()) {
|
||||
return Box(
|
||||
ScheduleBox,
|
||||
type,
|
||||
crl::guard(std::forward<Guard>(guard), std::forward<Submit>(submit)),
|
||||
DefaultScheduleTime());
|
||||
scheduleTime);
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
||||
@@ -44,6 +44,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
@@ -55,6 +57,17 @@ void ShowErrorToast(const QString &text) {
|
||||
});
|
||||
}
|
||||
|
||||
bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||
if (data->hasImage()) {
|
||||
return true;
|
||||
} else if (const auto urls = data->urls(); !urls.empty()) {
|
||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
object_ptr<Window::SectionWidget> ScheduledMemento::createWidget(
|
||||
@@ -165,6 +178,20 @@ void ScheduledWidget::setupComposeControls() {
|
||||
ChatHelpers::TabbedSelector::InlineChosen chosen) {
|
||||
sendInlineResult(chosen.result, chosen.bot);
|
||||
}, lifetime());
|
||||
|
||||
_composeControls->setMimeDataHook([=](
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return CanSendFiles(data);
|
||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||
return confirmSendingFiles(
|
||||
data,
|
||||
CompressConfirm::Auto,
|
||||
data->text());
|
||||
}
|
||||
Unexpected("action in MimeData hook.");
|
||||
});
|
||||
}
|
||||
|
||||
void ScheduledWidget::chooseAttach() {
|
||||
@@ -214,6 +241,43 @@ void ScheduledWidget::chooseAttach() {
|
||||
}), nullptr);
|
||||
}
|
||||
|
||||
bool ScheduledWidget::confirmSendingFiles(
|
||||
not_null<const QMimeData*> data,
|
||||
CompressConfirm compressed,
|
||||
const QString &insertTextOnCancel) {
|
||||
const auto hasImage = data->hasImage();
|
||||
|
||||
if (const auto urls = data->urls(); !urls.empty()) {
|
||||
auto list = Storage::PrepareMediaList(
|
||||
urls,
|
||||
st::sendMediaPreviewSize);
|
||||
if (list.error != Storage::PreparedList::Error::NonLocalUrl) {
|
||||
if (list.error == Storage::PreparedList::Error::None
|
||||
|| !hasImage) {
|
||||
const auto emptyTextOnCancel = QString();
|
||||
confirmSendingFiles(
|
||||
std::move(list),
|
||||
compressed,
|
||||
emptyTextOnCancel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasImage) {
|
||||
auto image = qvariant_cast<QImage>(data->imageData());
|
||||
if (!image.isNull()) {
|
||||
confirmSendingFiles(
|
||||
std::move(image),
|
||||
QByteArray(),
|
||||
compressed,
|
||||
insertTextOnCancel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScheduledWidget::confirmSendingFiles(
|
||||
Storage::PreparedList &&list,
|
||||
CompressConfirm compressed,
|
||||
@@ -834,6 +898,10 @@ void ScheduledWidget::listScrollTo(int top) {
|
||||
}
|
||||
|
||||
void ScheduledWidget::listCancelRequest() {
|
||||
if (_inner && !_inner->getSelectedItems().empty()) {
|
||||
clearSelected();
|
||||
return;
|
||||
}
|
||||
controller()->showBackFromStack();
|
||||
}
|
||||
|
||||
|
||||
@@ -159,6 +159,10 @@ private:
|
||||
Storage::PreparedList &&list,
|
||||
CompressConfirm compressed,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool confirmSendingFiles(
|
||||
not_null<const QMimeData*> data,
|
||||
CompressConfirm compressed,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool showSendingFilesError(const Storage::PreparedList &list) const;
|
||||
void uploadFilesAfterConfirmation(
|
||||
Storage::PreparedList &&list,
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace {
|
||||
auto link = Ui::Text::Link(
|
||||
tr::lng_about_random_send(tr::now).toUpper());
|
||||
link.entities.push_back(
|
||||
EntityInText(EntityType::Bold, 0, link.text.size()));
|
||||
EntityInText(EntityType::Semibold, 0, link.text.size()));
|
||||
config.text.append(' ').append(std::move(link));
|
||||
config.filter = crl::guard(&history->session(), [=](
|
||||
const ClickHandlerPtr &handler,
|
||||
|
||||
@@ -269,7 +269,7 @@ void QrWidget::setupControls() {
|
||||
st::introQrStepMargins);
|
||||
const auto number = Ui::CreateChild<Ui::FlatLabel>(
|
||||
steps,
|
||||
rpl::single(Ui::Text::Bold(QString::number(++index) + ".")),
|
||||
rpl::single(Ui::Text::Semibold(QString::number(++index) + ".")),
|
||||
st::defaultFlatLabel);
|
||||
rpl::combine(
|
||||
number->widthValue(),
|
||||
|
||||
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/effects/slide_animation.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_auto_download.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "facades.h"
|
||||
#include "app.h"
|
||||
@@ -39,6 +40,7 @@ void PrepareSupportMode() {
|
||||
|
||||
Global::SetDesktopNotify(false);
|
||||
Global::SetSoundNotify(false);
|
||||
Global::SetFlashBounceNotify(false);
|
||||
Auth().settings().autoDownload() = Full::FullDisabled();
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
@@ -140,7 +142,7 @@ void Step::finish(const MTPUser &user, QImage &&photo) {
|
||||
const auto weak = base::make_weak(account.get());
|
||||
account->createSession(user);
|
||||
Local::writeMtpData();
|
||||
App::wnd()->setupMain();
|
||||
App::wnd()->controller().setupMain();
|
||||
|
||||
// "this" is already deleted here by creating the main widget.
|
||||
if (weak && account->sessionExists()) {
|
||||
|
||||
@@ -2190,6 +2190,10 @@ void MainWidget::repaintDialogRow(Dialogs::RowDescriptor row) {
|
||||
_dialogs->repaintDialogRow(row);
|
||||
}
|
||||
|
||||
void MainWidget::refreshDialogRow(Dialogs::RowDescriptor row) {
|
||||
_dialogs->refreshDialogRow(row);
|
||||
}
|
||||
|
||||
void MainWidget::windowShown() {
|
||||
_history->windowShown();
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ public:
|
||||
void removeDialog(Dialogs::Key key);
|
||||
void repaintDialogRow(FilterId filterId, not_null<Dialogs::Row*> row);
|
||||
void repaintDialogRow(Dialogs::RowDescriptor row);
|
||||
void refreshDialogRow(Dialogs::RowDescriptor row);
|
||||
|
||||
void windowShown();
|
||||
|
||||
|
||||
@@ -757,7 +757,8 @@ void MainWindow::toggleDisplayNotifyFromTray() {
|
||||
return;
|
||||
}
|
||||
|
||||
bool soundNotifyChanged = false;
|
||||
auto soundNotifyChanged = false;
|
||||
auto flashBounceNotifyChanged = false;
|
||||
Global::SetDesktopNotify(!Global::DesktopNotify());
|
||||
if (Global::DesktopNotify()) {
|
||||
if (Global::RestoreSoundNotifyFromTray() && !Global::SoundNotify()) {
|
||||
@@ -765,6 +766,12 @@ void MainWindow::toggleDisplayNotifyFromTray() {
|
||||
Global::SetRestoreSoundNotifyFromTray(false);
|
||||
soundNotifyChanged = true;
|
||||
}
|
||||
if (Global::RestoreFlashBounceNotifyFromTray()
|
||||
&& !Global::FlashBounceNotify()) {
|
||||
Global::SetFlashBounceNotify(true);
|
||||
Global::SetRestoreFlashBounceNotifyFromTray(false);
|
||||
flashBounceNotifyChanged = true;
|
||||
}
|
||||
} else {
|
||||
if (Global::SoundNotify()) {
|
||||
Global::SetSoundNotify(false);
|
||||
@@ -773,13 +780,23 @@ void MainWindow::toggleDisplayNotifyFromTray() {
|
||||
} else {
|
||||
Global::SetRestoreSoundNotifyFromTray(false);
|
||||
}
|
||||
if (Global::FlashBounceNotify()) {
|
||||
Global::SetFlashBounceNotify(false);
|
||||
Global::SetRestoreFlashBounceNotifyFromTray(true);
|
||||
flashBounceNotifyChanged = true;
|
||||
} else {
|
||||
Global::SetRestoreFlashBounceNotifyFromTray(false);
|
||||
}
|
||||
}
|
||||
Local::writeUserSettings();
|
||||
account().session().notifications().settingsChanged().notify(
|
||||
Window::Notifications::ChangeType::DesktopEnabled);
|
||||
using Change = Window::Notifications::ChangeType;
|
||||
auto &changes = account().session().notifications().settingsChanged();
|
||||
changes.notify(Change::DesktopEnabled);
|
||||
if (soundNotifyChanged) {
|
||||
account().session().notifications().settingsChanged().notify(
|
||||
Window::Notifications::ChangeType::SoundEnabled);
|
||||
changes.notify(Change::SoundEnabled);
|
||||
}
|
||||
if (flashBounceNotifyChanged) {
|
||||
changes.notify(Change::FlashBounceEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,14 +86,14 @@ void EnumeratePlaybackDevices() {
|
||||
Assert(devices != nullptr);
|
||||
while (*devices != 0) {
|
||||
auto deviceName8Bit = QByteArray(devices);
|
||||
auto deviceName = QString::fromLocal8Bit(deviceName8Bit);
|
||||
auto deviceName = QString::fromUtf8(deviceName8Bit);
|
||||
deviceNames.append(deviceName);
|
||||
devices += deviceName8Bit.size() + 1;
|
||||
}
|
||||
LOG(("Audio Playback Devices: %1").arg(deviceNames.join(';')));
|
||||
|
||||
if (auto device = alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER)) {
|
||||
LOG(("Audio Playback Default Device: %1").arg(QString::fromLocal8Bit(device)));
|
||||
LOG(("Audio Playback Default Device: %1").arg(QString::fromUtf8(device)));
|
||||
} else {
|
||||
LOG(("Audio Playback Default Device: (null)"));
|
||||
}
|
||||
@@ -105,14 +105,14 @@ void EnumerateCaptureDevices() {
|
||||
Assert(devices != nullptr);
|
||||
while (*devices != 0) {
|
||||
auto deviceName8Bit = QByteArray(devices);
|
||||
auto deviceName = QString::fromLocal8Bit(deviceName8Bit);
|
||||
auto deviceName = QString::fromUtf8(deviceName8Bit);
|
||||
deviceNames.append(deviceName);
|
||||
devices += deviceName8Bit.size() + 1;
|
||||
}
|
||||
LOG(("Audio Capture Devices: %1").arg(deviceNames.join(';')));
|
||||
|
||||
if (auto device = alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)) {
|
||||
LOG(("Audio Capture Default Device: %1").arg(QString::fromLocal8Bit(device)));
|
||||
LOG(("Audio Capture Default Device: %1").arg(QString::fromUtf8(device)));
|
||||
} else {
|
||||
LOG(("Audio Capture Default Device: (null)"));
|
||||
}
|
||||
|
||||
@@ -62,13 +62,13 @@ Instance::Instance() : _inner(new Inner(&_thread)) {
|
||||
|
||||
void Instance::check() {
|
||||
_available = false;
|
||||
if (auto device = alcCaptureOpenDevice(nullptr, kCaptureFrequency, AL_FORMAT_MONO16, kCaptureFrequency / 5)) {
|
||||
auto error = ErrorHappened(device);
|
||||
alcCaptureCloseDevice(device);
|
||||
_available = !error;
|
||||
} else {
|
||||
LOG(("Audio Error: Could not open capture device!"));
|
||||
if (auto device = alcGetString(0, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)) {
|
||||
if (!QString::fromUtf8(device).isEmpty()) {
|
||||
_available = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG(("Audio Error: No capture device found!"));
|
||||
}
|
||||
|
||||
Instance::~Instance() {
|
||||
|
||||
@@ -544,7 +544,7 @@ void Widget::handleSongChange() {
|
||||
|
||||
textWithEntities.text = name + ' ' + date();
|
||||
textWithEntities.entities.append(EntityInText(
|
||||
EntityType::Bold,
|
||||
EntityType::Semibold,
|
||||
0,
|
||||
name.size(),
|
||||
QString()));
|
||||
@@ -565,7 +565,12 @@ void Widget::handleSongChange() {
|
||||
: TextUtilities::Clean(song->title);
|
||||
auto dash = QString::fromUtf8(" \xe2\x80\x93 ");
|
||||
textWithEntities.text = song->performer + dash + title;
|
||||
textWithEntities.entities.append({ EntityType::Bold, 0, song->performer.size(), QString() });
|
||||
textWithEntities.entities.append({
|
||||
EntityType::Semibold,
|
||||
0,
|
||||
song->performer.size(),
|
||||
QString()
|
||||
});
|
||||
}
|
||||
}
|
||||
_nameLabel->setMarkedText(textWithEntities);
|
||||
|
||||
@@ -37,8 +37,8 @@ public:
|
||||
|
||||
void process(std::vector<FFmpeg::Packet> &&packets);
|
||||
|
||||
[[nodisacrd]] rpl::producer<> checkNextFrame() const;
|
||||
[[nodisacrd]] rpl::producer<> waitingForData() const;
|
||||
[[nodiscard]] rpl::producer<> checkNextFrame() const;
|
||||
[[nodiscard]] rpl::producer<> waitingForData() const;
|
||||
|
||||
void pause(crl::time time);
|
||||
void resume(crl::time time);
|
||||
|
||||
@@ -40,6 +40,7 @@ constexpr auto kTestModeDcIdShift = 10000;
|
||||
constexpr auto kCheckSentRequestsEach = 1 * crl::time(1000);
|
||||
constexpr auto kKeyOldEnoughForDestroy = 60 * crl::time(1000);
|
||||
constexpr auto kSentContainerLives = 600 * crl::time(1000);
|
||||
constexpr auto kFastRequestDuration = crl::time(500);
|
||||
|
||||
// If we can't connect for this time we will ask _instance to update config.
|
||||
constexpr auto kRequestConfigTimeout = 8 * crl::time(1000);
|
||||
@@ -57,6 +58,8 @@ constexpr auto kSendStateRequestWaiting = crl::time(1000);
|
||||
// How much time to wait for some more requests, when sending msg acks.
|
||||
constexpr auto kAckSendWaiting = 10 * crl::time(1000);
|
||||
|
||||
auto SyncTimeRequestDuration = kFastRequestDuration;
|
||||
|
||||
using namespace details;
|
||||
|
||||
[[nodiscard]] QString LogIdsVector(const QVector<MTPlong> &ids) {
|
||||
@@ -1467,8 +1470,12 @@ SessionPrivate::HandleResult SessionPrivate::handleOneReceived(
|
||||
return badTime ? HandleResult::Ignored : HandleResult::Success;
|
||||
}
|
||||
|
||||
if (badTime && !requestsFixTimeSalt(ids, serverTime, serverSalt)) {
|
||||
return HandleResult::Ignored;
|
||||
if (badTime) {
|
||||
if (!requestsFixTimeSalt(ids, serverTime, serverSalt)) {
|
||||
return HandleResult::Ignored;
|
||||
}
|
||||
} else {
|
||||
correctUnixtimeByFastRequest(ids, serverTime);
|
||||
}
|
||||
requestsAcked(ids);
|
||||
} return HandleResult::Success;
|
||||
@@ -1520,7 +1527,8 @@ SessionPrivate::HandleResult SessionPrivate::handleOneReceived(
|
||||
if (serverSalt) {
|
||||
_sessionSalt = serverSalt;
|
||||
}
|
||||
base::unixtime::update(serverTime, true);
|
||||
|
||||
correctUnixtimeWithBadLocal(serverTime);
|
||||
|
||||
DEBUG_LOG(("Message Info: unixtime updated, now %1, resending in container...").arg(serverTime));
|
||||
|
||||
@@ -1530,7 +1538,7 @@ SessionPrivate::HandleResult SessionPrivate::handleOneReceived(
|
||||
if (serverSalt) {
|
||||
_sessionSalt = serverSalt;
|
||||
}
|
||||
base::unixtime::update(serverTime, true);
|
||||
correctUnixtimeWithBadLocal(serverTime);
|
||||
badTime = false;
|
||||
}
|
||||
LOG(("Message Info: bad message notification received, msgId %1, error_code %2").arg(data.vbad_msg_id().v).arg(errorCode));
|
||||
@@ -1580,7 +1588,7 @@ SessionPrivate::HandleResult SessionPrivate::handleOneReceived(
|
||||
}
|
||||
|
||||
_sessionSalt = data.vnew_server_salt().v;
|
||||
base::unixtime::update(serverTime);
|
||||
correctUnixtimeWithBadLocal(serverTime);
|
||||
|
||||
if (setState(ConnectedState, ConnectingState)) {
|
||||
resendAll();
|
||||
@@ -1612,7 +1620,7 @@ SessionPrivate::HandleResult SessionPrivate::handleOneReceived(
|
||||
if (serverSalt) {
|
||||
_sessionSalt = serverSalt; // requestsFixTimeSalt with no lookup
|
||||
}
|
||||
base::unixtime::update(serverTime, true);
|
||||
correctUnixtimeWithBadLocal(serverTime);
|
||||
|
||||
DEBUG_LOG(("Message Info: unixtime updated from mtpc_msgs_state_info, now %1").arg(serverTime));
|
||||
|
||||
@@ -1956,20 +1964,48 @@ mtpBuffer SessionPrivate::ungzip(const mtpPrime *from, const mtpPrime *end) cons
|
||||
}
|
||||
|
||||
bool SessionPrivate::requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt) {
|
||||
uint32 idsCount = ids.size();
|
||||
|
||||
for (uint32 i = 0; i < idsCount; ++i) {
|
||||
if (wasSent(ids[i].v)) {// found such msg_id in recent acked requests or in recent sent requests
|
||||
for (const auto &id : ids) {
|
||||
if (wasSent(id.v)) {
|
||||
// Found such msg_id in recent acked or in recent sent requests.
|
||||
if (serverSalt) {
|
||||
_sessionSalt = serverSalt;
|
||||
}
|
||||
base::unixtime::update(serverTime, true);
|
||||
correctUnixtimeWithBadLocal(serverTime);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SessionPrivate::correctUnixtimeByFastRequest(
|
||||
const QVector<MTPlong> &ids,
|
||||
TimeId serverTime) {
|
||||
const auto now = crl::now();
|
||||
|
||||
QReadLocker locker(_sessionData->haveSentMutex());
|
||||
const auto &haveSent = _sessionData->haveSentMap();
|
||||
for (const auto &id : ids) {
|
||||
const auto i = haveSent.find(id.v);
|
||||
if (i == haveSent.end()) {
|
||||
continue;
|
||||
}
|
||||
const auto duration = (now - i->second->lastSentTime);
|
||||
if (duration < 0 || duration > SyncTimeRequestDuration) {
|
||||
continue;
|
||||
}
|
||||
locker.unlock();
|
||||
|
||||
SyncTimeRequestDuration = duration;
|
||||
base::unixtime::update(serverTime, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SessionPrivate::correctUnixtimeWithBadLocal(TimeId serverTime) {
|
||||
SyncTimeRequestDuration = kFastRequestDuration;
|
||||
base::unixtime::update(serverTime, true);
|
||||
}
|
||||
|
||||
void SessionPrivate::requestsAcked(const QVector<MTPlong> &ids, bool byResponse) {
|
||||
uint32 idsCount = ids.size();
|
||||
|
||||
|
||||
@@ -139,6 +139,12 @@ private:
|
||||
// if badTime received - search for ids in sessionData->haveSent and sessionData->wereAcked and sync time/salt, return true if found
|
||||
bool requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt);
|
||||
|
||||
// if we had a confirmed fast request use its unixtime as a correct one.
|
||||
void correctUnixtimeByFastRequest(
|
||||
const QVector<MTPlong> &ids,
|
||||
TimeId serverTime);
|
||||
void correctUnixtimeWithBadLocal(TimeId serverTime);
|
||||
|
||||
// remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked
|
||||
void requestsAcked(const QVector<MTPlong> &ids, bool byResponse = false);
|
||||
|
||||
|
||||
@@ -55,13 +55,27 @@ TextWithEntities ComposeNameWithEntities(DocumentData *document) {
|
||||
result.text = document->filename().isEmpty()
|
||||
? qsl("Unknown File")
|
||||
: document->filename();
|
||||
result.entities.push_back({ EntityType::Bold, 0, result.text.size() });
|
||||
result.entities.push_back({
|
||||
EntityType::Semibold,
|
||||
0,
|
||||
result.text.size()
|
||||
});
|
||||
} else if (song->performer.isEmpty()) {
|
||||
result.text = song->title;
|
||||
result.entities.push_back({ EntityType::Bold, 0, result.text.size() });
|
||||
result.entities.push_back({
|
||||
EntityType::Semibold,
|
||||
0,
|
||||
result.text.size()
|
||||
});
|
||||
} else {
|
||||
result.text = song->performer + QString::fromUtf8(" \xe2\x80\x93 ") + (song->title.isEmpty() ? qsl("Unknown Track") : song->title);
|
||||
result.entities.push_back({ EntityType::Bold, 0, song->performer.size() });
|
||||
result.text = song->performer
|
||||
+ QString::fromUtf8(" \xe2\x80\x93 ")
|
||||
+ (song->title.isEmpty() ? qsl("Unknown Track") : song->title);
|
||||
result.entities.push_back({
|
||||
EntityType::Semibold,
|
||||
0,
|
||||
song->performer.size()
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -457,15 +457,11 @@ bool SkipAudio() {
|
||||
}
|
||||
|
||||
bool SkipToast() {
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
if (Supported()
|
||||
&& GetCapabilities().contains(qsl("inhibitions"))
|
||||
&& !InhibitedNotSupported) {
|
||||
return Inhibited();
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
return SkipAudio();
|
||||
}
|
||||
|
||||
return false;
|
||||
bool SkipFlashBounce() {
|
||||
return SkipAudio();
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
|
||||
@@ -19,9 +19,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
inline void FlashBounce() {
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
class NotificationData : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -271,6 +271,14 @@ bool IsGtkFileDialogForced() {
|
||||
#endif // !TDESKTOP_FORCE_GTK_FILE_DIALOG
|
||||
}
|
||||
|
||||
bool IsQtPluginsBundled() {
|
||||
#ifdef DESKTOP_APP_USE_PACKAGED_LAZY
|
||||
return true;
|
||||
#else // DESKTOP_APP_USE_PACKAGED_LAZY
|
||||
return false;
|
||||
#endif // !DESKTOP_APP_USE_PACKAGED_LAZY
|
||||
}
|
||||
|
||||
bool IsXDGDesktopPortalPresent() {
|
||||
#ifdef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
static const auto XDGDesktopPortalPresent = false;
|
||||
@@ -623,10 +631,6 @@ namespace Platform {
|
||||
void start() {
|
||||
LOG(("Launcher filename: %1").arg(GetLauncherFilename()));
|
||||
|
||||
if (InAppImage()) {
|
||||
qputenv("LIBGL_ALWAYS_INDIRECT", "1");
|
||||
}
|
||||
|
||||
#ifdef TDESKTOP_USE_FONTCONFIG_FALLBACK
|
||||
FallbackFontConfig();
|
||||
#endif // TDESKTOP_USE_FONTCONFIG_FALLBACK
|
||||
@@ -637,14 +641,16 @@ void start() {
|
||||
if(IsStaticBinary()
|
||||
|| InAppImage()
|
||||
|| InSandbox()
|
||||
|| InSnap()) {
|
||||
|| InSnap()
|
||||
|| IsQtPluginsBundled()) {
|
||||
qputenv("QT_WAYLAND_DECORATION", "material");
|
||||
}
|
||||
|
||||
if(IsStaticBinary()
|
||||
|| InAppImage()
|
||||
|| InSnap()
|
||||
|| IsGtkFileDialogForced()) {
|
||||
|| IsGtkFileDialogForced()
|
||||
|| IsQtPluginsBundled()) {
|
||||
LOG(("Checking for XDG Desktop Portal..."));
|
||||
// this can give us a chance to use a proper file dialog for current session
|
||||
if (IsXDGDesktopPortalPresent()) {
|
||||
|
||||
@@ -25,6 +25,7 @@ bool InSnap();
|
||||
bool InAppImage();
|
||||
bool IsStaticBinary();
|
||||
bool IsGtkFileDialogForced();
|
||||
bool IsQtPluginsBundled();
|
||||
|
||||
bool IsXDGDesktopPortalPresent();
|
||||
bool UseXDGDesktopPortal();
|
||||
|
||||
@@ -13,9 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
bool SkipAudio();
|
||||
bool SkipToast();
|
||||
|
||||
class Manager : public Window::Notifications::NativeManager, public base::has_weak_ptr {
|
||||
public:
|
||||
Manager(Window::Notifications::System *system);
|
||||
|
||||
@@ -34,7 +34,7 @@ void queryDoNotDisturbState() {
|
||||
|
||||
auto userDefaults = [NSUserDefaults alloc];
|
||||
if ([userDefaults respondsToSelector:@selector(initWithSuiteName:)]) {
|
||||
id userDefaultsValue = [[[NSUserDefaults alloc] initWithSuiteName:@"com.apple.notificationcenterui_test"] objectForKey:@"doNotDisturb"];
|
||||
id userDefaultsValue = [[[NSUserDefaults alloc] initWithSuiteName:@"com.apple.notificationcenterui"] objectForKey:@"doNotDisturb"];
|
||||
DoNotDisturbEnabled = ([userDefaultsValue boolValue] == YES);
|
||||
} else {
|
||||
DoNotDisturbEnabled = false;
|
||||
@@ -143,6 +143,10 @@ bool SkipToast() {
|
||||
return DoNotDisturbEnabled;
|
||||
}
|
||||
|
||||
bool SkipFlashBounce() {
|
||||
return SkipAudio();
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
return Platform::IsMac10_8OrGreater();
|
||||
}
|
||||
@@ -154,10 +158,6 @@ std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::Sy
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FlashBounce() {
|
||||
[NSApp requestUserAttention:NSInformationalRequest];
|
||||
}
|
||||
|
||||
class Manager::Private : public QObject, private base::Subscriber {
|
||||
public:
|
||||
Private(Manager *manager);
|
||||
|
||||
@@ -12,12 +12,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
bool SkipAudio();
|
||||
bool SkipToast();
|
||||
[[nodiscard]] bool SkipAudio();
|
||||
[[nodiscard]] bool SkipToast();
|
||||
[[nodiscard]] bool SkipFlashBounce();
|
||||
|
||||
bool Supported();
|
||||
std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system);
|
||||
void FlashBounce();
|
||||
[[nodiscard]] bool Supported();
|
||||
[[nodiscard]] std::unique_ptr<Window::Notifications::Manager> Create(
|
||||
Window::Notifications::System *system);
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "platform/win/windows_dlls.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
|
||||
#include <initguid.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
|
||||
@@ -117,7 +117,13 @@ void UnsafeOpenEmailLink(const QString &email) {
|
||||
auto wstringUrl = url.toString(QUrl::FullyEncoded).toStdWString();
|
||||
if (Dlls::SHOpenWithDialog) {
|
||||
OPENASINFO info;
|
||||
info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC | OAIF_FILE_IS_URI | OAIF_URL_PROTOCOL;
|
||||
info.oaifInFlags = OAIF_ALLOW_REGISTRATION
|
||||
| OAIF_REGISTER_EXT
|
||||
| OAIF_EXEC
|
||||
#if WINVER >= 0x0602
|
||||
| OAIF_FILE_IS_URI
|
||||
#endif // WINVER >= 0x602
|
||||
| OAIF_URL_PROTOCOL;
|
||||
info.pcszClass = NULL;
|
||||
info.pcszFile = wstringUrl.c_str();
|
||||
Dlls::SHOpenWithDialog(0, &info);
|
||||
|
||||
@@ -35,8 +35,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include <roapi.h>
|
||||
#include <wrl/client.h>
|
||||
#include "platform/win/wrapper_wrl_implements_h.h"
|
||||
#include <windows.ui.notifications.h>
|
||||
|
||||
#include <Windowsx.h>
|
||||
#include <VersionHelpers.h>
|
||||
@@ -47,10 +45,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
// WM_POINTER support from Windows 8 onwards (WINVER >= 0x0602)
|
||||
#ifndef WM_POINTERUPDATE
|
||||
# define WM_NCPOINTERUPDATE 0x0241
|
||||
# define WM_NCPOINTERDOWN 0x0242
|
||||
# define WM_NCPOINTERUP 0x0243
|
||||
# define WM_POINTERUPDATE 0x0245
|
||||
# define WM_POINTERDOWN 0x0246
|
||||
# define WM_POINTERUP 0x0247
|
||||
# define WM_POINTERENTER 0x0249
|
||||
# define WM_POINTERLEAVE 0x024A
|
||||
# define WM_POINTERACTIVATE 0x024B
|
||||
# define WM_POINTERCAPTURECHANGED 0x024C
|
||||
# define WM_POINTERWHEEL 0x024E
|
||||
# define WM_POINTERHWHEEL 0x024F
|
||||
#endif // WM_POINTERUPDATE
|
||||
|
||||
HICON qt_pixmapToWinHICON(const QPixmap &);
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
Q_DECLARE_METATYPE(QMargins);
|
||||
|
||||
namespace Platform {
|
||||
namespace {
|
||||
|
||||
@@ -226,7 +242,7 @@ public:
|
||||
destroy();
|
||||
return false;
|
||||
}
|
||||
SetWindowLong(hwnds[i], GWL_HWNDPARENT, (LONG)hwnd);
|
||||
SetWindowLongPtr(hwnds[i], GWLP_HWNDPARENT, (LONG)hwnd);
|
||||
|
||||
dcs[i] = CreateCompatibleDC(screenDC);
|
||||
if (!dcs[i]) {
|
||||
@@ -712,18 +728,18 @@ void MainWindow::workmodeUpdated(DBIWorkMode mode) {
|
||||
switch (mode) {
|
||||
case dbiwmWindowAndTray: {
|
||||
psSetupTrayIcon();
|
||||
HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT);
|
||||
HWND psOwner = (HWND)GetWindowLongPtr(ps_hWnd, GWLP_HWNDPARENT);
|
||||
if (psOwner) {
|
||||
SetWindowLong(ps_hWnd, GWL_HWNDPARENT, 0);
|
||||
SetWindowLongPtr(ps_hWnd, GWLP_HWNDPARENT, 0);
|
||||
psRefreshTaskbarIcon();
|
||||
}
|
||||
} break;
|
||||
|
||||
case dbiwmTrayOnly: {
|
||||
psSetupTrayIcon();
|
||||
HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT);
|
||||
HWND psOwner = (HWND)GetWindowLongPtr(ps_hWnd, GWLP_HWNDPARENT);
|
||||
if (!psOwner) {
|
||||
SetWindowLong(ps_hWnd, GWL_HWNDPARENT, (LONG)ps_tbHider_hWnd);
|
||||
SetWindowLongPtr(ps_hWnd, GWLP_HWNDPARENT, (LONG)ps_tbHider_hWnd);
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -734,9 +750,9 @@ void MainWindow::workmodeUpdated(DBIWorkMode mode) {
|
||||
}
|
||||
trayIcon = 0;
|
||||
|
||||
HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT);
|
||||
HWND psOwner = (HWND)GetWindowLongPtr(ps_hWnd, GWLP_HWNDPARENT);
|
||||
if (psOwner) {
|
||||
SetWindowLong(ps_hWnd, GWL_HWNDPARENT, 0);
|
||||
SetWindowLongPtr(ps_hWnd, GWLP_HWNDPARENT, 0);
|
||||
psRefreshTaskbarIcon();
|
||||
}
|
||||
} break;
|
||||
@@ -874,7 +890,6 @@ void MainWindow::updateSystemMenu(Qt::WindowState state) {
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QMargins);
|
||||
void MainWindow::psUpdateMargins() {
|
||||
if (!ps_hWnd || _inUpdateMargins) return;
|
||||
|
||||
@@ -885,7 +900,7 @@ void MainWindow::psUpdateMargins() {
|
||||
GetClientRect(ps_hWnd, &r);
|
||||
a = r;
|
||||
|
||||
LONG style = GetWindowLong(ps_hWnd, GWL_STYLE), styleEx = GetWindowLong(ps_hWnd, GWL_EXSTYLE);
|
||||
LONG style = GetWindowLongPtr(ps_hWnd, GWL_STYLE), styleEx = GetWindowLongPtr(ps_hWnd, GWL_EXSTYLE);
|
||||
AdjustWindowRectEx(&a, style, false, styleEx);
|
||||
QMargins margins = QMargins(a.left - r.left, a.top - r.top, r.right - a.right, r.bottom - a.bottom);
|
||||
if (style & WS_MAXIMIZE) {
|
||||
|
||||
@@ -20,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include <roapi.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
#ifndef __MINGW32__
|
||||
#include "platform/win/wrapper_wrl_implements_h.h"
|
||||
#include <windows.ui.notifications.h>
|
||||
|
||||
@@ -32,9 +34,12 @@ using namespace Microsoft::WRL;
|
||||
using namespace ABI::Windows::UI::Notifications;
|
||||
using namespace ABI::Windows::Data::Xml::Dom;
|
||||
using namespace Windows::Foundation;
|
||||
#endif // !__MINGW32__
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
#ifndef __MINGW32__
|
||||
namespace {
|
||||
|
||||
class StringReferenceWrapper {
|
||||
@@ -302,40 +307,33 @@ void Check() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif // !__MINGW32__
|
||||
|
||||
bool Supported() {
|
||||
#ifndef __MINGW32__
|
||||
if (!Checked) {
|
||||
Checked = true;
|
||||
Check();
|
||||
}
|
||||
return InitSucceeded;
|
||||
#endif // !__MINGW32__
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system) {
|
||||
#ifndef __MINGW32__
|
||||
if (Global::NativeNotifications() && Supported()) {
|
||||
auto result = std::make_unique<Manager>(system);
|
||||
if (result->init()) {
|
||||
return std::move(result);
|
||||
}
|
||||
}
|
||||
#endif // !__MINGW32__
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FlashBounce() {
|
||||
auto window = App::wnd();
|
||||
if (!window || GetForegroundWindow() == window->psHwnd()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FLASHWINFO info;
|
||||
info.cbSize = sizeof(info);
|
||||
info.hwnd = window->psHwnd();
|
||||
info.dwFlags = FLASHW_ALL;
|
||||
info.dwTimeout = 0;
|
||||
info.uCount = 1;
|
||||
FlashWindowEx(&info);
|
||||
}
|
||||
|
||||
#ifndef __MINGW32__
|
||||
class Manager::Private {
|
||||
public:
|
||||
using Type = Window::Notifications::CachedUserpics::Type;
|
||||
@@ -612,6 +610,7 @@ void Manager::onBeforeNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
void Manager::onAfterNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
_private->afterNotificationActivated(peerId, msgId);
|
||||
}
|
||||
#endif // !__MINGW32__
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -723,5 +722,9 @@ bool SkipToast() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipFlashBounce() {
|
||||
return SkipToast();
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
||||
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
#ifndef __MINGW32__
|
||||
class Manager : public Window::Notifications::NativeManager {
|
||||
public:
|
||||
Manager(Window::Notifications::System *system);
|
||||
@@ -41,6 +42,7 @@ private:
|
||||
const std::unique_ptr<Private> _private;
|
||||
|
||||
};
|
||||
#endif // !__MINGW32__
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
||||
@@ -29,8 +29,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include <roapi.h>
|
||||
#include <wrl/client.h>
|
||||
#include "platform/win/wrapper_wrl_implements_h.h"
|
||||
#include <windows.ui.notifications.h>
|
||||
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/engine.h>
|
||||
@@ -65,9 +63,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#endif
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace ABI::Windows::UI::Notifications;
|
||||
using namespace ABI::Windows::Data::Xml::Dom;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Platform;
|
||||
|
||||
namespace {
|
||||
@@ -435,7 +430,7 @@ namespace {
|
||||
WCHAR defaultStr[bufSize] = { 0 };
|
||||
if (RegQueryValueEx(rkey, value, 0, &defaultType, (BYTE*)defaultStr, &defaultSize) != ERROR_SUCCESS || defaultType != REG_SZ || defaultSize != (v.size() + 1) * 2 || QString::fromStdWString(defaultStr) != v) {
|
||||
WCHAR tmp[bufSize] = { 0 };
|
||||
if (!v.isEmpty()) wsprintf(tmp, v.replace(QChar('%'), qsl("%%")).toStdWString().c_str());
|
||||
if (!v.isEmpty()) StringCbPrintf(tmp, bufSize, v.replace(QChar('%'), qsl("%%")).toStdWString().c_str());
|
||||
LSTATUS status = RegSetValueEx(rkey, value, 0, REG_SZ, (BYTE*)tmp, (wcslen(tmp) + 1) * sizeof(WCHAR));
|
||||
if (status != ERROR_SUCCESS) {
|
||||
QString msg = qsl("App Error: could not set %1, error %2").arg(value ? ('\'' + QString::fromStdWString(value) + '\'') : qsl("(Default)")).arg("%1: %2");
|
||||
|
||||
@@ -13,8 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include <roapi.h>
|
||||
#include <wrl/client.h>
|
||||
#include "platform/win/wrapper_wrl_implements_h.h"
|
||||
#include <windows.ui.notifications.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
@@ -288,6 +286,7 @@ bool validateShortcut() {
|
||||
PropVariantClear(&appIdPropVar);
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
|
||||
#if WINVER >= 0x602
|
||||
PROPVARIANT startPinPropVar;
|
||||
hr = InitPropVariantFromUInt32(APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL, &startPinPropVar);
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
@@ -295,6 +294,7 @@ bool validateShortcut() {
|
||||
hr = propertyStore->SetValue(pkey_AppUserModel_StartPinOption, startPinPropVar);
|
||||
PropVariantClear(&startPinPropVar);
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
#endif // WINVER >= 0x602
|
||||
|
||||
hr = propertyStore->Commit();
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
|
||||
@@ -15,6 +15,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <RestartManager.h>
|
||||
#include <psapi.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define __in
|
||||
#endif
|
||||
|
||||
namespace Platform {
|
||||
namespace Dlls {
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ bool EventFilter::mainWindowEvent(
|
||||
} return false;
|
||||
|
||||
case WM_SHOWWINDOW: {
|
||||
LONG style = GetWindowLong(hWnd, GWL_STYLE);
|
||||
LONG style = GetWindowLongPtr(hWnd, GWL_STYLE);
|
||||
auto changes = ShadowsChange::Resized | ((wParam && !(style & (WS_MAXIMIZE | WS_MINIMIZE))) ? ShadowsChange::Shown : ShadowsChange::Hidden);
|
||||
_window->shadowsUpdate(changes);
|
||||
} return false;
|
||||
|
||||
@@ -53,6 +53,7 @@ Q_IMPORT_PLUGIN(QWaylandMaterialDecorationPlugin)
|
||||
Q_IMPORT_PLUGIN(NimfInputContextPlugin)
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
Q_IMPORT_PLUGIN(QFcitxPlatformInputContextPlugin)
|
||||
Q_IMPORT_PLUGIN(QFcitx5PlatformInputContextPlugin)
|
||||
Q_IMPORT_PLUGIN(QHimePlatformInputContextPlugin)
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
#endif // !DESKTOP_APP_USE_PACKAGED || DESKTOP_APP_USE_PACKAGED_LAZY
|
||||
|
||||