diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..5ace4600a1
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 7a65b483fb..ac40f3a330 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -20,7 +20,7 @@ jobs:
steps:
- name: Clone.
- uses: actions/checkout@v3.1.0
+ uses: actions/checkout@v4
with:
submodules: recursive
@@ -31,7 +31,7 @@ jobs:
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: Free up some disk space.
- uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8
+ uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
- name: Docker image build.
run: |
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 8020e46c5b..8eb20a2e55 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -58,7 +58,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone.
- uses: actions/checkout@v3.1.0
+ uses: actions/checkout@v4
with:
submodules: recursive
path: ${{ env.REPO_NAME }}
@@ -116,7 +116,7 @@ jobs:
cd $REPO_NAME/out/Debug
sudo mkdir artifact
sudo mv {Telegram,Updater} artifact/
- - uses: actions/upload-artifact@master
+ - uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml
index 562159d0d1..cf3c469896 100644
--- a/.github/workflows/lock.yml
+++ b/.github/workflows/lock.yml
@@ -8,7 +8,7 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- - uses: dessant/lock-threads@v3
+ - uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-inactive-days: 45
diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml
index 8271664c05..e5f5e56206 100644
--- a/.github/workflows/mac.yml
+++ b/.github/workflows/mac.yml
@@ -56,7 +56,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone.
- uses: actions/checkout@v3.1.0
+ uses: actions/checkout@v4
with:
submodules: recursive
path: ${{ env.REPO_NAME }}
@@ -76,7 +76,7 @@ jobs:
- name: ThirdParty cache.
id: cache-third-party
- uses: actions/cache@v3.0.11
+ uses: actions/cache@v4
with:
path: ThirdParty
key: ${{ runner.OS }}-third-party-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }}
@@ -84,7 +84,7 @@ jobs:
- name: Libraries cache.
id: cache-libs
- uses: actions/cache@v3.0.11
+ uses: actions/cache@v4
with:
path: Libraries
key: ${{ runner.OS }}-libs-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }}
@@ -134,7 +134,7 @@ jobs:
mkdir artifact
mv Telegram.app artifact/
mv Updater artifact/
- - uses: actions/upload-artifact@master
+ - uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
diff --git a/.github/workflows/mac_packaged.yml b/.github/workflows/mac_packaged.yml
index d04b284dee..bd51bb74a5 100644
--- a/.github/workflows/mac_packaged.yml
+++ b/.github/workflows/mac_packaged.yml
@@ -60,7 +60,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone.
- uses: actions/checkout@v3.1.0
+ uses: actions/checkout@v4
with:
submodules: recursive
path: ${{ env.REPO_NAME }}
@@ -99,7 +99,7 @@ jobs:
- name: WebRTC cache.
id: cache-webrtc
- uses: actions/cache@v3.0.11
+ uses: actions/cache@v4
with:
path: ${{ env.LibrariesPath }}/tg_owt
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }}
@@ -153,7 +153,7 @@ jobs:
cd $REPO_NAME/build
mkdir artifact
mv Telegram.dmg artifact/
- - uses: actions/upload-artifact@master
+ - uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
diff --git a/.github/workflows/master_updater.yml b/.github/workflows/master_updater.yml
index 284bb844e4..c59f62e29a 100644
--- a/.github/workflows/master_updater.yml
+++ b/.github/workflows/master_updater.yml
@@ -11,7 +11,7 @@ jobs:
SKIP: "0"
to_branch: "master"
steps:
- - uses: actions/checkout@v4.1.0
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
if: env.SKIP == '0'
diff --git a/.github/workflows/snap.yml b/.github/workflows/snap.yml
index badcf6cc9f..93ef6ad36f 100644
--- a/.github/workflows/snap.yml
+++ b/.github/workflows/snap.yml
@@ -47,7 +47,7 @@ jobs:
steps:
- name: Clone.
- uses: actions/checkout@v3.1.0
+ uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
@@ -61,7 +61,7 @@ jobs:
sudo snap run lxd waitready
- name: Free up some disk space.
- uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8
+ uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
- name: Telegram Desktop snap build.
run: sg lxd -c 'snap run snapcraft --verbosity=debug'
@@ -75,7 +75,7 @@ jobs:
mkdir artifact
mv $artifact_name artifact
- - uses: actions/upload-artifact@master
+ - uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 219f95a82a..4148917e71 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v5
+ - uses: actions/stale@v9
with:
stale-issue-message: |
Hey there!
diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml
index f8332c36f1..ca0c7bf097 100644
--- a/.github/workflows/win.yml
+++ b/.github/workflows/win.yml
@@ -69,13 +69,13 @@ jobs:
shell: bash
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- - uses: ilammy/msvc-dev-cmd@v1.12.0
+ - uses: ilammy/msvc-dev-cmd@v1.13.0
name: Native Tools Command Prompt.
with:
arch: ${{ matrix.arch }}
- name: Clone.
- uses: actions/checkout@v3.1.0
+ uses: actions/checkout@v4
with:
submodules: recursive
path: ${{ env.TBUILD }}\${{ env.REPO_NAME }}
@@ -96,7 +96,7 @@ jobs:
- name: Libraries cache.
id: cache-libs
- uses: actions/cache@v3.0.11
+ uses: actions/cache@v4
with:
path: ${{ env.TBUILD }}\Libraries
key: ${{ runner.OS }}-${{ matrix.arch }}-libs-${{ env.CACHE_KEY }}
@@ -183,7 +183,7 @@ jobs:
mkdir artifact
move %OUT%\Telegram.exe artifact/
move %OUT%\Updater.exe artifact/
- - uses: actions/upload-artifact@master
+ - uses: actions/upload-artifact@v4
name: Upload artifact.
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
with:
diff --git a/.gitignore b/.gitignore
index 678ef32e3b..c2896799ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ Release/
*.xcodeproj
ipch/
.vs/
+.vscode/
/Telegram/log.txt
/Telegram/data
diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index 11f1fc9a3a..210c88d0da 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -757,6 +757,8 @@ PRIVATE
history/view/controls/compose_controls_common.h
history/view/controls/history_view_compose_controls.cpp
history/view/controls/history_view_compose_controls.h
+ history/view/controls/history_view_compose_media_edit_manager.cpp
+ history/view/controls/history_view_compose_media_edit_manager.h
history/view/controls/history_view_compose_search.cpp
history/view/controls/history_view_compose_search.h
history/view/controls/history_view_draft_options.cpp
diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml
index 0021dd5de1..e22af137ae 100644
--- a/Telegram/Resources/uwp/AppX/AppxManifest.xml
+++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml
@@ -10,7 +10,7 @@
+ Version="5.0.2.0" />
Telegram Desktop
Telegram Messenger LLP
diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc
index e7d2777da7..22f1064147 100644
--- a/Telegram/Resources/winrc/Telegram.rc
+++ b/Telegram/Resources/winrc/Telegram.rc
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 5,0,1,0
- PRODUCTVERSION 5,0,1,0
+ FILEVERSION 5,0,2,0
+ PRODUCTVERSION 5,0,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
- VALUE "FileVersion", "5.0.1.0"
+ VALUE "FileVersion", "5.0.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "5.0.1.0"
+ VALUE "ProductVersion", "5.0.2.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc
index d3e2f5f5b8..402c438bf9 100644
--- a/Telegram/Resources/winrc/Updater.rc
+++ b/Telegram/Resources/winrc/Updater.rc
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 5,0,1,0
- PRODUCTVERSION 5,0,1,0
+ FILEVERSION 5,0,2,0
+ PRODUCTVERSION 5,0,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
- VALUE "FileVersion", "5.0.1.0"
+ VALUE "FileVersion", "5.0.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "5.0.1.0"
+ VALUE "ProductVersion", "5.0.2.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/SourceFiles/api/api_editing.cpp b/Telegram/SourceFiles/api/api_editing.cpp
index f91a73579b..7dcd768cb4 100644
--- a/Telegram/SourceFiles/api/api_editing.cpp
+++ b/Telegram/SourceFiles/api/api_editing.cpp
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/confirm_box.h"
#include "data/business/data_shortcut_messages.h"
#include "data/components/scheduled_messages.h"
+#include "data/data_file_origin.h"
#include "data/data_histories.h"
#include "data/data_session.h"
#include "data/data_web_page.h"
@@ -252,12 +253,100 @@ mtpRequestId EditTextMessage(
Data::WebPageDraft webpage,
SendOptions options,
Fn done,
- Fn fail) {
+ Fn fail,
+ std::optional spoilerMediaOverride) {
+ if (spoilerMediaOverride) {
+ const auto spoiler = *spoilerMediaOverride;
+ if (const auto media = item->media()) {
+ auto takeInputMedia = Fn()>(nullptr);
+ auto takeFileReference = Fn(nullptr);
+ if (const auto photo = media->photo()) {
+ using Flag = MTPDinputMediaPhoto::Flag;
+ const auto flags = Flag()
+ | (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
+ | (spoiler ? Flag::f_spoiler : Flag());
+ takeInputMedia = [=] {
+ return MTP_inputMediaPhoto(
+ MTP_flags(flags),
+ photo->mtpInput(),
+ MTP_int(media->ttlSeconds()));
+ };
+ takeFileReference = [=] { return photo->fileReference(); };
+ } else if (const auto document = media->document()) {
+ using Flag = MTPDinputMediaDocument::Flag;
+ const auto flags = Flag()
+ | (media->ttlSeconds() ? Flag::f_ttl_seconds : Flag())
+ | (spoiler ? Flag::f_spoiler : Flag());
+ takeInputMedia = [=] {
+ return MTP_inputMediaDocument(
+ MTP_flags(flags),
+ document->mtpInput(),
+ MTP_int(media->ttlSeconds()),
+ MTPstring()); // query
+ };
+ takeFileReference = [=] { return document->fileReference(); };
+ }
+
+ const auto usedFileReference = takeFileReference
+ ? takeFileReference()
+ : QByteArray();
+ const auto origin = item->fullId();
+ const auto api = &item->history()->session().api();
+ const auto performRequest = [=](
+ const auto &repeatRequest,
+ mtpRequestId originalRequestId) -> mtpRequestId {
+ const auto handleReference = [=](
+ const QString &error,
+ mtpRequestId requestId) {
+ if (error.startsWith(u"FILE_REFERENCE_"_q)) {
+ api->refreshFileReference(origin, [=](const auto &) {
+ if (takeFileReference &&
+ (takeFileReference() != usedFileReference)) {
+ repeatRequest(
+ repeatRequest,
+ originalRequestId
+ ? originalRequestId
+ : requestId);
+ } else {
+ fail(error, requestId);
+ }
+ });
+ } else {
+ fail(error, requestId);
+ }
+ };
+ const auto callback = [=](
+ Fn applyUpdates,
+ mtpRequestId requestId) {
+ applyUpdates();
+ done(originalRequestId ? originalRequestId : requestId);
+ };
+ const auto requestId = EditMessage(
+ item,
+ caption,
+ webpage,
+ options,
+ callback,
+ handleReference,
+ takeInputMedia ? takeInputMedia() : std::nullopt);
+ return originalRequestId ? originalRequestId : requestId;
+ };
+ return performRequest(performRequest, 0);
+ }
+ }
+
const auto callback = [=](Fn applyUpdates, mtpRequestId id) {
applyUpdates();
done(id);
};
- return EditMessage(item, caption, webpage, options, callback, fail);
+ return EditMessage(
+ item,
+ caption,
+ webpage,
+ options,
+ callback,
+ fail,
+ std::nullopt);
}
} // namespace Api
diff --git a/Telegram/SourceFiles/api/api_editing.h b/Telegram/SourceFiles/api/api_editing.h
index 86f106f45e..c8d0f6c509 100644
--- a/Telegram/SourceFiles/api/api_editing.h
+++ b/Telegram/SourceFiles/api/api_editing.h
@@ -55,6 +55,7 @@ mtpRequestId EditTextMessage(
Data::WebPageDraft webpage,
SendOptions options,
Fn done,
- Fn fail);
+ Fn fail,
+ std::optional spoilerMediaOverride);
} // namespace Api
diff --git a/Telegram/SourceFiles/api/api_text_entities.cpp b/Telegram/SourceFiles/api/api_text_entities.cpp
index 6c434bc9ba..44a689ff4b 100644
--- a/Telegram/SourceFiles/api/api_text_entities.cpp
+++ b/Telegram/SourceFiles/api/api_text_entities.cpp
@@ -7,12 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_text_entities.h"
-#include "main/main_session.h"
+#include "data/data_document.h"
+#include "data/data_session.h"
+#include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h"
#include "data/stickers/data_stickers_set.h"
-#include "data/data_session.h"
-#include "data/data_document.h"
-#include "data/data_user.h"
+#include "main/main_session.h"
namespace Api {
namespace {
@@ -62,67 +62,163 @@ using namespace TextUtilities;
EntitiesInText EntitiesFromMTP(
Main::Session *session,
const QVector &entities) {
+ if (entities.isEmpty()) {
+ return {};
+ }
auto result = EntitiesInText();
- if (!entities.isEmpty()) {
- result.reserve(entities.size());
- for (const auto &entity : entities) {
- switch (entity.type()) {
- case mtpc_messageEntityUrl: { auto &d = entity.c_messageEntityUrl(); result.push_back({ EntityType::Url, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityTextUrl: { auto &d = entity.c_messageEntityTextUrl(); result.push_back({ EntityType::CustomUrl, d.voffset().v, d.vlength().v, qs(d.vurl()) }); } break;
- case mtpc_messageEntityEmail: { auto &d = entity.c_messageEntityEmail(); result.push_back({ EntityType::Email, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityHashtag: { auto &d = entity.c_messageEntityHashtag(); result.push_back({ EntityType::Hashtag, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityCashtag: { auto &d = entity.c_messageEntityCashtag(); result.push_back({ EntityType::Cashtag, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityPhone: break; // Skipping phones.
- case mtpc_messageEntityMention: { auto &d = entity.c_messageEntityMention(); result.push_back({ EntityType::Mention, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityMentionName: if (session) {
- const auto &d = entity.c_messageEntityMentionName();
- const auto userId = UserId(d.vuser_id());
- const auto user = session->data().userLoaded(userId);
- const auto data = MentionNameDataFromFields({
- .selfId = session->userId().bare,
- .userId = userId.bare,
- .accessHash = user ? user->accessHash() : 0,
- });
- result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
- } break;
- case mtpc_inputMessageEntityMentionName: if (session) {
- const auto &d = entity.c_inputMessageEntityMentionName();
- const auto data = d.vuser_id().match([&](
- const MTPDinputUserSelf &) {
- return MentionNameDataFromFields({
- .selfId = session->userId().bare,
- .userId = session->userId().bare,
- .accessHash = session->user()->accessHash(),
- });
- }, [&](const MTPDinputUser &data) {
- return MentionNameDataFromFields({
- .selfId = session->userId().bare,
- .userId = UserId(data.vuser_id()).bare,
- .accessHash = data.vaccess_hash().v,
- });
- }, [&](const auto &) {
- return QString();
- });
- if (!data.isEmpty()) {
- result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
- }
- } break;
- case mtpc_messageEntityBotCommand: { auto &d = entity.c_messageEntityBotCommand(); result.push_back({ EntityType::BotCommand, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityBold: { auto &d = entity.c_messageEntityBold(); result.push_back({ EntityType::Bold, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityItalic: { auto &d = entity.c_messageEntityItalic(); result.push_back({ EntityType::Italic, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityUnderline: { auto &d = entity.c_messageEntityUnderline(); result.push_back({ EntityType::Underline, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityStrike: { auto &d = entity.c_messageEntityStrike(); result.push_back({ EntityType::StrikeOut, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset().v, d.vlength().v, qs(d.vlanguage()) }); } break;
- case mtpc_messageEntityBlockquote: { auto &d = entity.c_messageEntityBlockquote(); result.push_back({ EntityType::Blockquote, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityBankCard: break; // Skipping cards. // #TODO entities
- case mtpc_messageEntitySpoiler: { auto &d = entity.c_messageEntitySpoiler(); result.push_back({ EntityType::Spoiler, d.voffset().v, d.vlength().v }); } break;
- case mtpc_messageEntityCustomEmoji: {
- const auto &d = entity.c_messageEntityCustomEmoji();
- result.push_back({ EntityType::CustomEmoji, d.voffset().v, d.vlength().v, CustomEmojiEntityData(d) });
- } break;
+ result.reserve(entities.size());
+
+ for (const auto &entity : entities) {
+ entity.match([&](const MTPDmessageEntityUnknown &d) {
+ }, [&](const MTPDmessageEntityMention &d) {
+ result.push_back({
+ EntityType::Mention,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityHashtag &d) {
+ result.push_back({
+ EntityType::Hashtag,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityBotCommand &d) {
+ result.push_back({
+ EntityType::BotCommand,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityUrl &d) {
+ result.push_back({
+ EntityType::Url,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityEmail &d) {
+ result.push_back({
+ EntityType::Email,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityBold &d) {
+ result.push_back({
+ EntityType::Bold,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityItalic &d) {
+ result.push_back({
+ EntityType::Italic,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityCode &d) {
+ result.push_back({
+ EntityType::Code,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityPre &d) {
+ result.push_back({
+ EntityType::Pre,
+ d.voffset().v,
+ d.vlength().v,
+ qs(d.vlanguage()),
+ });
+ }, [&](const MTPDmessageEntityTextUrl &d) {
+ result.push_back({
+ EntityType::CustomUrl,
+ d.voffset().v,
+ d.vlength().v,
+ qs(d.vurl()),
+ });
+ }, [&](const MTPDmessageEntityMentionName &d) {
+ if (!session) {
+ return;
}
- }
+ const auto userId = UserId(d.vuser_id());
+ const auto user = session->data().userLoaded(userId);
+ const auto data = MentionNameDataFromFields({
+ .selfId = session->userId().bare,
+ .userId = userId.bare,
+ .accessHash = user ? user->accessHash() : 0,
+ });
+ result.push_back({
+ EntityType::MentionName,
+ d.voffset().v,
+ d.vlength().v,
+ data,
+ });
+ }, [&](const MTPDinputMessageEntityMentionName &d) {
+ if (!session) {
+ return;
+ }
+ const auto data = d.vuser_id().match([&](
+ const MTPDinputUserSelf &) {
+ return MentionNameDataFromFields({
+ .selfId = session->userId().bare,
+ .userId = session->userId().bare,
+ .accessHash = session->user()->accessHash(),
+ });
+ }, [&](const MTPDinputUser &data) {
+ return MentionNameDataFromFields({
+ .selfId = session->userId().bare,
+ .userId = UserId(data.vuser_id()).bare,
+ .accessHash = data.vaccess_hash().v,
+ });
+ }, [](const auto &) {
+ return QString();
+ });
+ if (!data.isEmpty()) {
+ result.push_back({
+ EntityType::MentionName,
+ d.voffset().v,
+ d.vlength().v,
+ data,
+ });
+ }
+ }, [&](const MTPDmessageEntityPhone &d) {
+ // Skipping phones.
+ }, [&](const MTPDmessageEntityCashtag &d) {
+ result.push_back({
+ EntityType::Cashtag,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityUnderline &d) {
+ result.push_back({
+ EntityType::Underline,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityStrike &d) {
+ result.push_back({
+ EntityType::StrikeOut,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityBankCard &d) {
+ // Skipping cards. // #TODO entities
+ }, [&](const MTPDmessageEntitySpoiler &d) {
+ result.push_back({
+ EntityType::Spoiler,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ }, [&](const MTPDmessageEntityCustomEmoji &d) {
+ result.push_back({
+ EntityType::CustomEmoji,
+ d.voffset().v,
+ d.vlength().v,
+ CustomEmojiEntityData(d),
+ });
+ }, [&](const MTPDmessageEntityBlockquote &d) {
+ result.push_back({
+ EntityType::Blockquote,
+ d.voffset().v,
+ d.vlength().v,
+ });
+ });
}
return result;
}
@@ -134,7 +230,9 @@ MTPVector EntitiesToMTP(
auto v = QVector();
v.reserve(entities.size());
for (const auto &entity : entities) {
- if (entity.length() <= 0) continue;
+ if (entity.length() <= 0) {
+ continue;
+ }
if (option == ConvertOption::SkipLocal
&& entity.type() != EntityType::Bold
//&& entity.type() != EntityType::Semibold // Not in API.
@@ -154,28 +252,76 @@ MTPVector EntitiesToMTP(
auto offset = MTP_int(entity.offset());
auto length = MTP_int(entity.length());
switch (entity.type()) {
- case EntityType::Url: v.push_back(MTP_messageEntityUrl(offset, length)); break;
- case EntityType::CustomUrl: v.push_back(MTP_messageEntityTextUrl(offset, length, MTP_string(entity.data()))); break;
- case EntityType::Email: v.push_back(MTP_messageEntityEmail(offset, length)); break;
- case EntityType::Hashtag: v.push_back(MTP_messageEntityHashtag(offset, length)); break;
- case EntityType::Cashtag: v.push_back(MTP_messageEntityCashtag(offset, length)); break;
- case EntityType::Mention: v.push_back(MTP_messageEntityMention(offset, length)); break;
+ case EntityType::Url: {
+ v.push_back(MTP_messageEntityUrl(offset, length));
+ } break;
+ case EntityType::CustomUrl: {
+ v.push_back(
+ MTP_messageEntityTextUrl(
+ offset,
+ length,
+ MTP_string(entity.data())));
+ } break;
+ case EntityType::Email: {
+ v.push_back(MTP_messageEntityEmail(offset, length));
+ } break;
+ case EntityType::Hashtag: {
+ v.push_back(MTP_messageEntityHashtag(offset, length));
+ } break;
+ case EntityType::Cashtag: {
+ v.push_back(MTP_messageEntityCashtag(offset, length));
+ } break;
+ case EntityType::Mention: {
+ v.push_back(MTP_messageEntityMention(offset, length));
+ } break;
case EntityType::MentionName: {
- if (const auto valid = MentionNameEntity(session, offset, length, entity.data())) {
+ const auto valid = MentionNameEntity(
+ session,
+ offset,
+ length,
+ entity.data());
+ if (valid) {
v.push_back(*valid);
}
} break;
- case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break;
- case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break;
- case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break;
- case EntityType::Underline: v.push_back(MTP_messageEntityUnderline(offset, length)); break;
- case EntityType::StrikeOut: v.push_back(MTP_messageEntityStrike(offset, length)); break;
- case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities
- case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break;
- case EntityType::Blockquote: v.push_back(MTP_messageEntityBlockquote(offset, length)); break;
- case EntityType::Spoiler: v.push_back(MTP_messageEntitySpoiler(offset, length)); break;
+ case EntityType::BotCommand: {
+ v.push_back(MTP_messageEntityBotCommand(offset, length));
+ } break;
+ case EntityType::Bold: {
+ v.push_back(MTP_messageEntityBold(offset, length));
+ } break;
+ case EntityType::Italic: {
+ v.push_back(MTP_messageEntityItalic(offset, length));
+ } break;
+ case EntityType::Underline: {
+ v.push_back(MTP_messageEntityUnderline(offset, length));
+ } break;
+ case EntityType::StrikeOut: {
+ v.push_back(MTP_messageEntityStrike(offset, length));
+ } break;
+ case EntityType::Code: {
+ // #TODO entities.
+ v.push_back(MTP_messageEntityCode(offset, length));
+ } break;
+ case EntityType::Pre: {
+ v.push_back(
+ MTP_messageEntityPre(
+ offset,
+ length,
+ MTP_string(entity.data())));
+ } break;
+ case EntityType::Blockquote: {
+ v.push_back(MTP_messageEntityBlockquote(offset, length));
+ } break;
+ case EntityType::Spoiler: {
+ v.push_back(MTP_messageEntitySpoiler(offset, length));
+ } break;
case EntityType::CustomEmoji: {
- if (const auto valid = CustomEmojiEntity(offset, length, entity.data())) {
+ const auto valid = CustomEmojiEntity(
+ offset,
+ length,
+ entity.data());
+ if (valid) {
v.push_back(*valid);
}
} break;
diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
index 5ffdfb6f36..be4d4e7fad 100644
--- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
@@ -206,6 +206,9 @@ void EditPhotoImage(
Storage::UpdateImageDetails(file, previewWidth, sideLimit);
done(std::move(list));
};
+ if (!large) {
+ return;
+ }
const auto fileImage = std::make_shared(*large);
auto editor = base::make_unique_q(
parent,
diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp
index 7aa48aaa38..dca4a065ba 100644
--- a/Telegram/SourceFiles/boxes/peer_list_box.cpp
+++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp
@@ -2125,6 +2125,16 @@ bool PeerListContent::submitted() {
return false;
}
+PeerListRowId PeerListContent::updateFromParentDrag(QPoint globalPosition) {
+ selectByMouse(globalPosition);
+ const auto row = getRow(_selected.index);
+ return row ? row->id() : 0;
+}
+
+void PeerListContent::dragLeft() {
+ clearSelection();
+}
+
void PeerListContent::visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) {
diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h
index 335001e02c..4349fd8c60 100644
--- a/Telegram/SourceFiles/boxes/peer_list_box.h
+++ b/Telegram/SourceFiles/boxes/peer_list_box.h
@@ -625,6 +625,9 @@ public:
void searchQueryChanged(QString query);
bool submitted();
+ PeerListRowId updateFromParentDrag(QPoint globalPosition);
+ void dragLeft();
+
// Interface for the controller.
void appendRow(std::unique_ptr row);
void appendSearchRow(std::unique_ptr row);
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp
index 09b5d273b8..b2e292a3cb 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp
@@ -1428,14 +1428,15 @@ void SetupPeerColorSample(
void AddPeerColorButton(
not_null container,
std::shared_ptr show,
- not_null peer) {
+ not_null peer,
+ const style::SettingsButton &st) {
auto label = peer->isSelf()
? tr::lng_settings_theme_name_color()
: tr::lng_edit_channel_color();
const auto button = AddButtonWithIcon(
container,
rpl::duplicate(label),
- st::settingsColorButton,
+ st,
{ &st::menuIconChangeColors });
const auto style = std::make_shared(
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.h b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.h
index 2272123a13..394a13aa88 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.h
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.h
@@ -48,7 +48,8 @@ void EditPeerColorBox(
void AddPeerColorButton(
not_null container,
std::shared_ptr show,
- not_null peer);
+ not_null peer,
+ const style::SettingsButton &st);
void CheckBoostLevel(
std::shared_ptr show,
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
index f732c794ee..c79ef325d1 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
@@ -1016,7 +1016,11 @@ void Controller::fillColorIndexButton() {
Expects(_controls.buttonsLayout != nullptr);
const auto show = _navigation->uiShow();
- AddPeerColorButton(_controls.buttonsLayout, show, _peer);
+ AddPeerColorButton(
+ _controls.buttonsLayout,
+ _navigation->uiShow(),
+ _peer,
+ st::managePeerColorsButton);
}
void Controller::fillSignaturesButton() {
diff --git a/Telegram/SourceFiles/calls/calls_video_incoming.cpp b/Telegram/SourceFiles/calls/calls_video_incoming.cpp
index 9ab16d73d4..e1a52ebe90 100644
--- a/Telegram/SourceFiles/calls/calls_video_incoming.cpp
+++ b/Telegram/SourceFiles/calls/calls_video_incoming.cpp
@@ -331,6 +331,7 @@ void Panel::Incoming::RendererGL::paint(
shadow.texture.left(), shadow.texture.top(),
};
+ _contentBuffer->bind();
_contentBuffer->write(0, coords, sizeof(coords));
const auto bottomShadowArea = QRect(
diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp
index 63e5105fa9..6f6b076204 100644
--- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp
+++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp
@@ -783,6 +783,7 @@ void Viewport::RendererGL::paintTile(
: &*_frameProgram.yuv420;
const auto uniformViewport = QSizeF(_viewport) * _factor;
+ program->bind();
program->setUniformValue("viewport", uniformViewport);
program->setUniformValue(
"frameBg",
@@ -1078,6 +1079,7 @@ void Viewport::RendererGL::drawDownscalePass(
? &*_downscaleProgram.argb32
: &*_downscaleProgram.yuv420;
+ program->bind();
FillTexturedRectangle(f, program);
}
diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
index fd8fa4017e..0631332f9f 100644
--- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style
+++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
@@ -785,6 +785,12 @@ emojiScroll: ScrollArea(defaultSolidScroll) {
reactPanelScroll: ScrollArea(emojiScroll) {
deltab: 7px;
}
+reactPanelScrollRounded: ScrollArea(emojiScroll) {
+ width: 8px;
+ deltax: 3px;
+ deltat: 14px;
+ deltab: 14px;
+}
choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }};
choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }};
@@ -983,7 +989,7 @@ historyComposeField: InputField(defaultInputField) {
placeholderFg: placeholderFg;
placeholderFgActive: placeholderFgActive;
placeholderFgError: placeholderFgActive;
- placeholderMargins: margins(7px, 5px, 7px, 5px);
+ placeholderMargins: margins(2px, 0px, 2px, 0px);
placeholderAlign: align(topleft);
placeholderScale: 0.;
placeholderFont: normalFont;
diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
index adc7d889a6..e2b41060e2 100644
--- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
+++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
@@ -1134,9 +1134,7 @@ void EmojiListWidget::fillRecentMenu(
not_null menu,
int section,
int index) {
- if (section != int(Section::Recent)) {
- return;
- }
+ const auto recent = (section == int(Section::Recent));
const auto addAction = Ui::Menu::CreateAddActionCallback(menu);
const auto over = OverEmoji{ section, index };
const auto emoji = lookupOverEmoji(&over);
@@ -1157,18 +1155,21 @@ void EmojiListWidget::fillRecentMenu(
TextUtilities::SetClipboardText(data);
}, &st::menuIconCopy);
}
- if (setId && _features.openStickerSets) {
+ if (recent && setId && _features.openStickerSets) {
addAction(
tr::lng_emoji_view_pack(tr::now),
crl::guard(this, [=] { displaySet(setId); }),
&st::menuIconShowAll);
}
- } else if (emoji) {
+ } else if (recent && emoji) {
addAction(tr::lng_emoji_copy(tr::now), [=] {
const auto text = emoji->text();
TextUtilities::SetClipboardText({ text, { text } });
}, &st::menuIconCopy);
}
+ if (!recent) {
+ return;
+ }
auto id = RecentEmojiId{ emoji };
if (custom) {
id.data = RecentEmojiDocument{
@@ -1194,7 +1195,7 @@ void EmojiListWidget::fillRecentMenu(
.confirmed = crl::guard(this, sure),
.confirmText = tr::lng_emoji_reset_recent_button(tr::now),
.labelStyle = &st().boxLabel,
- }));
+ }));
};
addAction({
.text = tr::lng_emoji_reset_recent(tr::now),
diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp
index 7de254badb..b63ae69677 100644
--- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp
+++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp
@@ -509,7 +509,7 @@ TabbedSelector::TabbedSelector(
_st.categoriesBg);
}, lifetime());
- if (hasEmojiTab()) {
+ if (hasEmojiTab() && _mode == Mode::Full) {
session().data().stickers().emojiSetInstalled(
) | rpl::start_with_next([=](uint64 setId) {
_tabsSlider->setActiveSection(indexByType(SelectorTab::Emoji));
diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp
index da9e7a96b4..5d00cb5404 100644
--- a/Telegram/SourceFiles/core/core_settings.cpp
+++ b/Telegram/SourceFiles/core/core_settings.cpp
@@ -127,7 +127,8 @@ Settings::Settings()
: _sendSubmitWay(Ui::InputSubmitSettings::Enter)
, _floatPlayerColumn(Window::Column::Second)
, _floatPlayerCorner(RectPart::TopRight)
-, _dialogsWidthRatio(DefaultDialogsWidthRatio()) {
+, _dialogsWithChatWidthRatio(DefaultDialogsWidthRatio())
+, _dialogsNoChatWidthRatio(DefaultDialogsWidthRatio()) {
}
Settings::~Settings() = default;
@@ -222,7 +223,8 @@ QByteArray Settings::serialize() const {
+ Serialize::stringSize(_callCaptureDeviceId.current())
+ Serialize::bytearraySize(ivPosition)
+ Serialize::stringSize(noWarningExtensions)
- + Serialize::stringSize(_customFontFamily);
+ + Serialize::stringSize(_customFontFamily)
+ + sizeof(qint32);
auto result = QByteArray();
result.reserve(size);
@@ -284,7 +286,7 @@ QByteArray Settings::serialize() const {
<< qint32(_floatPlayerCorner)
<< qint32(_thirdSectionInfoEnabled ? 1 : 0)
<< qint32(std::clamp(
- qRound(_dialogsWidthRatio.current() * 1000000),
+ qRound(_dialogsWithChatWidthRatio.current() * 1000000),
0,
1000000))
<< qint32(_thirdColumnWidth.current())
@@ -369,7 +371,11 @@ QByteArray Settings::serialize() const {
<< _callCaptureDeviceId.current()
<< ivPosition
<< noWarningExtensions
- << _customFontFamily;
+ << _customFontFamily
+ << qint32(std::clamp(
+ qRound(_dialogsNoChatWidthRatio.current() * 1000000),
+ 0,
+ 1000000));
}
Ensures(result.size() == size);
@@ -440,7 +446,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 floatPlayerColumn = static_cast(Window::Column::Second);
qint32 floatPlayerCorner = static_cast(RectPart::TopRight);
qint32 thirdSectionInfoEnabled = 0;
- float64 dialogsWidthRatio = _dialogsWidthRatio.current();
+ float64 dialogsWithChatWidthRatio = _dialogsWithChatWidthRatio.current();
+ float64 dialogsNoChatWidthRatio = _dialogsNoChatWidthRatio.current();
qint32 thirdColumnWidth = _thirdColumnWidth.current();
qint32 thirdSectionExtendedBy = _thirdSectionExtendedBy;
qint32 notifyFromAll = _notifyFromAll ? 1 : 0;
@@ -552,18 +559,18 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
>> mainMenuAccountsShown;
}
if (!stream.atEnd()) {
- auto dialogsWidthRatioInt = qint32();
+ auto dialogsWithChatWidthRatioInt = qint32();
stream
>> tabbedSelectorSectionEnabled
>> floatPlayerColumn
>> floatPlayerCorner
>> thirdSectionInfoEnabled
- >> dialogsWidthRatioInt
+ >> dialogsWithChatWidthRatioInt
>> thirdColumnWidth
>> thirdSectionExtendedBy
>> notifyFromAll;
- dialogsWidthRatio = std::clamp(
- dialogsWidthRatioInt / 1000000.,
+ dialogsWithChatWidthRatio = std::clamp(
+ dialogsWithChatWidthRatioInt / 1000000.,
0.,
1.);
}
@@ -778,6 +785,15 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> customFontFamily;
}
+ if (!stream.atEnd()) {
+ auto dialogsNoChatWidthRatioInt = qint32();
+ stream
+ >> dialogsNoChatWidthRatioInt;
+ dialogsNoChatWidthRatio = std::clamp(
+ dialogsNoChatWidthRatioInt / 1000000.,
+ 0.,
+ 1.);
+ }
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
@@ -879,7 +895,10 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
case RectPart::BottomRight: _floatPlayerCorner = uncheckedCorner; break;
}
_thirdSectionInfoEnabled = thirdSectionInfoEnabled;
- _dialogsWidthRatio = dialogsWidthRatio;
+ _dialogsWithChatWidthRatio = dialogsWithChatWidthRatio;
+ _dialogsNoChatWidthRatio = (dialogsWithChatWidthRatio > 0)
+ ? dialogsWithChatWidthRatio
+ : dialogsNoChatWidthRatio;
_thirdColumnWidth = thirdColumnWidth;
_thirdSectionExtendedBy = thirdSectionExtendedBy;
if (_thirdSectionInfoEnabled) {
@@ -1032,16 +1051,46 @@ void Settings::setTabbedReplacedWithInfo(bool enabled) {
}
}
-void Settings::setDialogsWidthRatio(float64 ratio) {
- _dialogsWidthRatio = ratio;
+void Settings::updateDialogsWidthRatio(float64 ratio, bool nochat) {
+ const auto changeWithChat = !nochat
+ || (dialogsWithChatWidthRatio() > 0)
+ || _dialogsWidthSetToZeroWithoutChat;
+ const auto changedWithChat = changeWithChat
+ && (dialogsWithChatWidthRatio() != ratio);
+
+ const auto changeNoChat = nochat
+ || (dialogsWithChatWidthRatio() != ratio);
+ const auto changedNoChat = changeNoChat
+ && (dialogsNoChatWidthRatio() != ratio);
+
+ if (changedWithChat) {
+ _dialogsWidthSetToZeroWithoutChat = nochat && !(ratio > 0);
+ _dialogsWithChatWidthRatio = ratio;
+ }
+ if (changedNoChat) {
+ _dialogsNoChatWidthRatio = ratio;
+ }
}
-float64 Settings::dialogsWidthRatio() const {
- return _dialogsWidthRatio.current();
+float64 Settings::dialogsWidthRatio(bool nochat) const {
+ const auto withchat = dialogsWithChatWidthRatio();
+ return (!nochat || withchat > 0) ? withchat : dialogsNoChatWidthRatio();
}
-rpl::producer Settings::dialogsWidthRatioChanges() const {
- return _dialogsWidthRatio.changes();
+float64 Settings::dialogsWithChatWidthRatio() const {
+ return _dialogsWithChatWidthRatio.current();
+}
+
+rpl::producer Settings::dialogsWithChatWidthRatioChanges() const {
+ return _dialogsWithChatWidthRatio.changes();
+}
+
+float64 Settings::dialogsNoChatWidthRatio() const {
+ return _dialogsNoChatWidthRatio.current();
+}
+
+rpl::producer Settings::dialogsNoChatWidthRatioChanges() const {
+ return _dialogsNoChatWidthRatio.changes();
}
void Settings::setThirdColumnWidth(int width) {
@@ -1333,7 +1382,8 @@ void Settings::resetOnLastLogout() {
_floatPlayerCorner = RectPart::TopRight; // per-window
_thirdSectionInfoEnabled = true; // per-window
_thirdSectionExtendedBy = -1; // per-window
- _dialogsWidthRatio = DefaultDialogsWidthRatio(); // per-window
+ _dialogsWithChatWidthRatio = DefaultDialogsWidthRatio(); // per-window
+ _dialogsNoChatWidthRatio = DefaultDialogsWidthRatio(); // per-window
_thirdColumnWidth = kDefaultThirdColumnWidth; // p-w
_notifyFromAll = true;
_tabbedReplacedWithInfo = false; // per-window
diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h
index a8526f9e6c..442d345980 100644
--- a/Telegram/SourceFiles/core/core_settings.h
+++ b/Telegram/SourceFiles/core/core_settings.h
@@ -620,9 +620,15 @@ public:
[[nodiscard]] RectPart floatPlayerCorner() const {
return _floatPlayerCorner;
}
- void setDialogsWidthRatio(float64 ratio);
- [[nodiscard]] float64 dialogsWidthRatio() const;
- [[nodiscard]] rpl::producer dialogsWidthRatioChanges() const;
+
+ void updateDialogsWidthRatio(float64 ratio, bool nochat);
+ [[nodiscard]] float64 dialogsWidthRatio(bool nochat) const;
+
+ [[nodiscard]] float64 dialogsWithChatWidthRatio() const;
+ [[nodiscard]] rpl::producer dialogsWithChatWidthRatioChanges() const;
+ [[nodiscard]] float64 dialogsNoChatWidthRatio() const;
+ [[nodiscard]] rpl::producer dialogsNoChatWidthRatioChanges() const;
+
void setThirdColumnWidth(int width);
[[nodiscard]] int thirdColumnWidth() const;
[[nodiscard]] rpl::producer thirdColumnWidthChanges() const;
@@ -975,7 +981,8 @@ private:
bool _thirdSectionInfoEnabled = true; // per-window
rpl::event_stream _thirdSectionInfoEnabledValue; // per-window
int _thirdSectionExtendedBy = -1; // per-window
- rpl::variable _dialogsWidthRatio; // per-window
+ rpl::variable _dialogsWithChatWidthRatio; // per-window
+ rpl::variable _dialogsNoChatWidthRatio; // per-window
rpl::variable _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w
bool _notifyFromAll = true;
rpl::variable _nativeWindowFrame = false;
@@ -1021,6 +1028,7 @@ private:
float64 _rememberedSongVolume = kDefaultVolume;
bool _rememberedSoundNotifyFromTray = false;
bool _rememberedFlashBounceNotifyFromTray = false;
+ bool _dialogsWidthSetToZeroWithoutChat = false;
QByteArray _photoEditorBrush;
diff --git a/Telegram/SourceFiles/core/sandbox.cpp b/Telegram/SourceFiles/core/sandbox.cpp
index 3daf917841..4110a73a76 100644
--- a/Telegram/SourceFiles/core/sandbox.cpp
+++ b/Telegram/SourceFiles/core/sandbox.cpp
@@ -255,7 +255,10 @@ void Sandbox::setupScreenScale() {
Sandbox::~Sandbox() = default;
bool Sandbox::event(QEvent *e) {
- if (e->type() == QEvent::Quit && !Quitting()) {
+ if (e->type() == QEvent::Quit) {
+ if (Quitting()) {
+ return QCoreApplication::event(e);
+ }
Quit(QuitReason::QtQuitEvent);
e->ignore();
return false;
diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h
index d58a09fa44..3169174b39 100644
--- a/Telegram/SourceFiles/core/version.h
+++ b/Telegram/SourceFiles/core/version.h
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
constexpr auto AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs;
-constexpr auto AppVersion = 5000001;
-constexpr auto AppVersionStr = "5.0.1";
+constexpr auto AppVersion = 5000002;
+constexpr auto AppVersionStr = "5.0.2";
constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
diff --git a/Telegram/SourceFiles/data/components/sponsored_messages.cpp b/Telegram/SourceFiles/data/components/sponsored_messages.cpp
index 8f9a1b334a..b86c3c6216 100644
--- a/Telegram/SourceFiles/data/components/sponsored_messages.cpp
+++ b/Telegram/SourceFiles/data/components/sponsored_messages.cpp
@@ -449,6 +449,22 @@ auto SponsoredMessages::createReportCallback(const FullMsgId &fullId)
return;
}
+ const auto erase = [=] {
+ const auto it = _data.find(history);
+ if (it != end(_data)) {
+ auto &list = it->second.entries;
+ const auto proj = [&](const Entry &e) {
+ return e.itemFullId == fullId;
+ };
+ list.erase(ranges::remove_if(list, proj), end(list));
+ }
+ };
+
+ if (optionId == Result::Id("-1")) {
+ erase();
+ return;
+ }
+
state->requestId = _session->api().request(
MTPchannels_ReportSponsoredMessage(
channel->inputChannel,
@@ -475,14 +491,7 @@ auto SponsoredMessages::createReportCallback(const FullMsgId &fullId)
}, [](const TLAdsHidden &data) -> Result {
return { .result = Result::FinalStep::Hidden };
}, [&](const TLReported &data) -> Result {
- const auto it = _data.find(history);
- if (it != end(_data)) {
- auto &list = it->second.entries;
- const auto proj = [&](const Entry &e) {
- return e.itemFullId == fullId;
- };
- list.erase(ranges::remove_if(list, proj), end(list));
- }
+ erase();
if (optionId == Result::Id("1")) { // I don't like it.
return { .result = Result::FinalStep::Silence };
}
diff --git a/Telegram/SourceFiles/data/data_replies_list.cpp b/Telegram/SourceFiles/data/data_replies_list.cpp
index 0cd53700cb..e12fa8fac6 100644
--- a/Telegram/SourceFiles/data/data_replies_list.cpp
+++ b/Telegram/SourceFiles/data/data_replies_list.cpp
@@ -372,6 +372,16 @@ bool RepliesList::buildFromData(not_null viewer) {
return viewer->around;
} else if (const auto item = lookupRoot()) {
return computeInboxReadTillFull();
+ } else if (_owningTopic) {
+ // Somehow we don't want always to jump to computed inboxReadTill
+ // (this was in the code before, but I don't remember why).
+ // Maybe in case we "View Thread" from a group we don't really
+ // want to jump to unread inside thread, cause it isn't defined.
+ //
+ // But in case of topics we definitely want to support jumping
+ // to the first unread, even if it is General topic without the
+ // actual root message or it is a broken topic without root.
+ return computeInboxReadTillFull();
}
return viewer->around;
}();
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index eb16132096..779c35ca90 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -700,7 +700,7 @@ not_null Session::processUser(const MTPUser &data) {
result->setAccessHash(accessHash->v);
}
status = data.vstatus();
- {
+ if (!minimal) {
const auto newUsername = uname;
const auto newUsernames = data.vusernames()
? Api::Usernames::FromTL(*data.vusernames())
diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
index 897942c8e6..de738708ee 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
@@ -82,6 +82,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qt/qt_common_adapters.h"
#include
+#include
#include
#include
@@ -101,6 +102,15 @@ base::options::toggle OptionForumHideChatsList({
.description = "Don't keep a narrow column of chats list.",
});
+[[nodiscard]] bool RedirectTextToSearch(const QString &text) {
+ for (const auto &ch : text) {
+ if (ch.unicode() >= 32) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace
const char kOptionForumHideChatsList[] = "forum-hide-chats-list";
@@ -360,6 +370,14 @@ Widget::Widget(
Ui::PostponeCall(this, [=] { listScrollUpdated(); });
}, lifetime());
+ setAttribute(Qt::WA_InputMethodEnabled);
+ controller->widget()->imeCompositionStarts(
+ ) | rpl::filter([=] {
+ return redirectImeToSearch();
+ }) | rpl::start_with_next([=] {
+ _search->setFocusFast();
+ }, lifetime());
+
_search->changes(
) | rpl::start_with_next([=] {
applySearchUpdate();
@@ -449,7 +467,6 @@ Widget::Widget(
loadMoreBlockedByDate();
}, lifetime());
- _search->setFocusPolicy(Qt::StrongFocus);
_search->customUpDown(true);
updateJumpToDateVisibility(true);
@@ -569,14 +586,6 @@ void Widget::chosenRow(const ChosenRow &row) {
history,
ShowAtUnreadMsgId,
Window::SectionShow::Way::ClearStack);
- } else if (!controller()->adaptive().isOneColumn()) {
- const auto item = history->chatListMessage();
- if (const auto topic = item ? item->topic() : nullptr) {
- controller()->showThread(
- topic,
- ShowAtUnreadMsgId,
- Window::SectionShow::Way::ClearStack);
- }
}
return;
} else if (history) {
@@ -1018,7 +1027,9 @@ void Widget::setupShortcuts() {
const auto history = forum->history();
controller()->searchInChat(history);
return true;
- } else if (!_openedFolder && _search->isVisible()) {
+ } else if (!_openedFolder
+ && !_childList
+ && _search->isVisible()) {
_search->setFocus();
return true;
}
@@ -1175,13 +1186,16 @@ void Widget::updateSuggestions(anim::type animated) {
} else {
_suggestions = nullptr;
_hidingSuggestions.clear();
+ storiesExplicitCollapse();
+ updateStoriesVisibility();
_scroll->show();
}
} else if (suggest && !_suggestions) {
if (animated == anim::type::normal) {
startWidthAnimation();
- updateStoriesVisibility();
}
+ // Hides stories and passcode lock.
+ updateStoriesVisibility();
_suggestions = std::make_unique(
this,
controller(),
@@ -1520,16 +1534,17 @@ void Widget::checkUpdateStatus() {
updateControlsGeometry();
}
-void Widget::setInnerFocus() {
+void Widget::setInnerFocus(bool unfocusSearch) {
if (_childList) {
_childList->setInnerFocus();
} else if ((_openedFolder || _openedForum)
&& _subsectionTopBar->searchSetFocus()) {
return;
- } else if (!_search->getLastText().isEmpty()
- || _searchInChat
- || _searchHasFocus
- || _searchSuggestionsLocked) {
+ } else if (!unfocusSearch
+ && (!_search->getLastText().isEmpty()
+ || _searchInChat
+ || _searchHasFocus
+ || _searchSuggestionsLocked)) {
_search->setFocus();
} else {
setFocus();
@@ -2552,15 +2567,18 @@ void Widget::dragMoveEvent(QDragMoveEvent *e) {
} else {
_chooseByDragTimer.callOnce(ChoosePeerByDragTimeout);
}
- if (_inner->updateFromParentDrag(mapToGlobal(e->pos()))) {
- e->setDropAction(Qt::CopyAction);
- } else {
- e->setDropAction(Qt::IgnoreAction);
- }
+ const auto global = mapToGlobal(e->pos());
+ const auto thread = _suggestions
+ ? _suggestions->updateFromParentDrag(global)
+ : _inner->updateFromParentDrag(global);
+ e->setDropAction(thread ? Qt::CopyAction : Qt::IgnoreAction);
} else {
if (_dragForward) {
updateDragInScroll(false);
}
+ if (_suggestions) {
+ _suggestions->dragLeft();
+ }
_inner->dragLeft();
e->setDropAction(Qt::IgnoreAction);
}
@@ -2573,6 +2591,9 @@ void Widget::dragLeaveEvent(QDragLeaveEvent *e) {
} else {
_chooseByDragTimer.cancel();
}
+ if (_suggestions) {
+ _suggestions->dragLeft();
+ }
_inner->dragLeft();
e->accept();
}
@@ -2591,8 +2612,11 @@ void Widget::updateDragInScroll(bool inScroll) {
void Widget::dropEvent(QDropEvent *e) {
_chooseByDragTimer.cancel();
if (_scroll->geometry().contains(e->pos())) {
- const auto point = mapToGlobal(e->pos());
- if (const auto thread = _inner->updateFromParentDrag(point)) {
+ const auto globalPosition = mapToGlobal(e->pos());
+ const auto thread = _suggestions
+ ? _suggestions->updateFromParentDrag(globalPosition)
+ : _inner->updateFromParentDrag(globalPosition);
+ if (thread) {
e->setDropAction(Qt::CopyAction);
e->accept();
controller()->content()->filesOrForwardDrop(
@@ -2675,8 +2699,9 @@ void Widget::updateForceDisplayWide() {
void Widget::showForum(
not_null forum,
const Window::SectionShow ¶ms) {
+ const auto nochat = !controller()->mainSectionShown();
if (!params.childColumn
- || !Core::App().settings().dialogsWidthRatio()
+ || (Core::App().settings().dialogsWidthRatio(nochat) == 0.)
|| (_layout != Layout::Main)
|| OptionForumHideChatsList.value()) {
changeOpenedForum(forum, params.animated);
@@ -2892,7 +2917,7 @@ bool Widget::setSearchInChat(
if (_searchInChat || !_search->getLastText().isEmpty()) {
_search->setFocus();
} else {
- setFocus();
+ setInnerFocus(true);
}
updateForceDisplayWide();
return true;
@@ -3273,6 +3298,10 @@ void Widget::keyPressEvent(QKeyEvent *e) {
//} else {
// e->ignore();
//}
+ } else if ((e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Tab)
+ && _searchHasFocus
+ && !_searchInChat) {
+ escape();
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
submit();
} else if (_suggestions
@@ -3313,16 +3342,47 @@ void Widget::keyPressEvent(QKeyEvent *e) {
}
}
+void Widget::inputMethodEvent(QInputMethodEvent *e) {
+ const auto cursor = _search->rawTextEdit()->textCursor();
+ bool isGettingInput = !e->commitString().isEmpty()
+ || e->preeditString() != cursor.block().layout()->preeditAreaText()
+ || e->replacementLength() > 0;
+
+ if (!isGettingInput || _postponeProcessSearchFocusChange) {
+ Window::AbstractSectionWidget::inputMethodEvent(e);
+ return;
+ }
+
+ // This delay in search focus processing allows us not to create
+ // _suggestions in case the event inserts some non-whitespace search
+ // query while still show _suggestions animated, if it is a space.
+ _postponeProcessSearchFocusChange = true;
+ _search->setFocusFast();
+ QCoreApplication::sendEvent(_search->rawTextEdit(), e);
+ _postponeProcessSearchFocusChange = false;
+ processSearchFocusChange();
+}
+
+QVariant Widget::inputMethodQuery(Qt::InputMethodQuery query) const {
+ return _search->rawTextEdit()->inputMethodQuery(query);
+}
+
+bool Widget::redirectToSearchPossible() const {
+ return !_openedFolder
+ && !_openedForum
+ && !_childList
+ && _search->isVisible()
+ && !_search->hasFocus()
+ && hasFocus();
+}
+
bool Widget::redirectKeyToSearch(QKeyEvent *e) const {
- if (_openedFolder
- || _openedForum
- || !_search->isVisible()
- || _search->hasFocus()) {
+ if (!redirectToSearchPossible()) {
return false;
}
const auto character = !(e->modifiers() & ~Qt::ShiftModifier)
&& (e->key() != Qt::Key_Shift)
- && !e->text().isEmpty();
+ && RedirectTextToSearch(e->text());
if (character) {
return true;
} else if (e != QKeySequence::Paste) {
@@ -3338,6 +3398,10 @@ bool Widget::redirectKeyToSearch(QKeyEvent *e) const {
return data && data->hasText();
}
+bool Widget::redirectImeToSearch() const {
+ return redirectToSearchPossible();
+}
+
void Widget::paintEvent(QPaintEvent *e) {
if (controller()->contentOverlapped(this, e)) {
return;
@@ -3446,7 +3510,7 @@ bool Widget::cancelSearch() {
if (!clearingQuery
&& _subsectionTopBar
&& _subsectionTopBar->toggleSearch(false, anim::type::normal)) {
- setFocus();
+ setInnerFocus(true);
clearingInChat = true;
}
const auto clearSearchFocus = !_searchInChat
@@ -3457,7 +3521,7 @@ bool Widget::cancelSearch() {
}
if (!_suggestions && clearSearchFocus) {
// Don't create suggestions in unfocus case.
- setFocus();
+ setInnerFocus(true);
}
_lastSearchPeer = nullptr;
_lastSearchId = _lastSearchMigratedId = 0;
@@ -3465,7 +3529,7 @@ bool Widget::cancelSearch() {
clearSearchField();
applySearchUpdate();
if (_suggestions && clearSearchFocus) {
- setFocus();
+ setInnerFocus(true);
}
return clearingQuery || clearingInChat || clearSearchFocus;
}
diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h
index 7b1beacb3b..903ddfba2d 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_widget.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h
@@ -99,7 +99,7 @@ public:
not_null forum,
const Window::SectionShow ¶ms);
void searchInChat(Key chat);
- void setInnerFocus();
+ void setInnerFocus(bool unfocusSearch = false);
[[nodiscard]] bool searchHasFocus() const;
void jumpToTop(bool belowPinned = false);
@@ -135,6 +135,8 @@ public:
bool cancelSearch();
bool cancelSearchByMouseBack();
+ QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
+
~Widget();
protected:
@@ -144,6 +146,7 @@ protected:
void dropEvent(QDropEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
+ void inputMethodEvent(QInputMethodEvent *e) override;
void paintEvent(QPaintEvent *e) override;
private:
@@ -250,7 +253,9 @@ private:
void updateSuggestions(anim::type animated);
void processSearchFocusChange();
+ [[nodiscard]] bool redirectToSearchPossible() const;
[[nodiscard]] bool redirectKeyToSearch(QKeyEvent *e) const;
+ [[nodiscard]] bool redirectImeToSearch() const;
MTP::Sender _api;
diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp
index 50362e657a..37be201fa9 100644
--- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp
+++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp
@@ -1121,6 +1121,39 @@ void Suggestions::chooseRow() {
}
}
+Data::Thread *Suggestions::updateFromParentDrag(QPoint globalPosition) {
+ return (_tab.current() == Tab::Chats)
+ ? updateFromChatsDrag(globalPosition)
+ : updateFromChannelsDrag(globalPosition);
+}
+
+Data::Thread *Suggestions::updateFromChatsDrag(QPoint globalPosition) {
+ if (const auto top = _topPeers->updateFromParentDrag(globalPosition)) {
+ return _controller->session().data().history(PeerId(top));
+ }
+ return fromListId(_recentUpdateFromParentDrag(globalPosition));
+}
+
+Data::Thread *Suggestions::updateFromChannelsDrag(QPoint globalPosition) {
+ if (const auto id = _myChannelsUpdateFromParentDrag(globalPosition)) {
+ return fromListId(id);
+ }
+ return fromListId(_recommendationsUpdateFromParentDrag(globalPosition));
+}
+
+Data::Thread *Suggestions::fromListId(uint64 peerListRowId) {
+ return peerListRowId
+ ? _controller->session().data().history(PeerId(peerListRowId)).get()
+ : nullptr;
+}
+
+void Suggestions::dragLeft() {
+ _topPeers->dragLeft();
+ _recentDragLeft();
+ _myChannelsDragLeft();
+ _recommendationsDragLeft();
+}
+
void Suggestions::show(anim::type animated, Fn finish) {
RpWidget::show();
@@ -1304,6 +1337,12 @@ object_ptr> Suggestions::setupRecentPeers(
}
return JumpResult::NotApplied;
};
+ _recentUpdateFromParentDrag = [=](QPoint globalPosition) {
+ return raw->updateFromParentDrag(globalPosition);
+ };
+ _recentDragLeft = [=] {
+ raw->dragLeft();
+ };
raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
const auto add = _topPeersWrap->toggled() ? _topPeers->height() : 0;
@@ -1438,6 +1477,12 @@ object_ptr> Suggestions::setupMyChannels() {
}
return JumpResult::NotApplied;
};
+ _myChannelsUpdateFromParentDrag = [=](QPoint globalPosition) {
+ return raw->updateFromParentDrag(globalPosition);
+ };
+ _myChannelsDragLeft = [=] {
+ raw->dragLeft();
+ };
raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
_channelsScroll->scrollToY(request.ymin, request.ymax);
@@ -1499,6 +1544,12 @@ object_ptr> Suggestions::setupRecommendations() {
}
return JumpResult::NotApplied;
};
+ _recommendationsUpdateFromParentDrag = [=](QPoint globalPosition) {
+ return raw->updateFromParentDrag(globalPosition);
+ };
+ _recommendationsDragLeft = [=] {
+ raw->dragLeft();
+ };
raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
const auto add = _myChannels->toggled() ? _myChannels->height() : 0;
diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h
index 49b74fa740..947bf2fa9d 100644
--- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h
+++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h
@@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/animations.h"
#include "ui/rp_widget.h"
+namespace Data {
+class Thread;
+} // namespace Data
+
namespace Main {
class Session;
} // namespace Main
@@ -46,6 +50,9 @@ public:
void selectJump(Qt::Key direction, int pageSize = 0);
void chooseRow();
+ [[nodiscard]] Data::Thread *updateFromParentDrag(QPoint globalPosition);
+ void dragLeft();
+
void show(anim::type animated, Fn finish);
void hide(anim::type animated, Fn finish);
[[nodiscard]] float64 shownOpacity() const;
@@ -90,6 +97,11 @@ private:
void selectJumpChats(Qt::Key direction, int pageSize);
void selectJumpChannels(Qt::Key direction, int pageSize);
+ [[nodiscard]] Data::Thread *updateFromChatsDrag(QPoint globalPosition);
+ [[nodiscard]] Data::Thread *updateFromChannelsDrag(
+ QPoint globalPosition);
+ [[nodiscard]] Data::Thread *fromListId(uint64 peerListRowId);
+
[[nodiscard]] object_ptr> setupRecentPeers(
RecentPeersList recentPeers);
[[nodiscard]] object_ptr> setupEmptyRecent();
@@ -121,6 +133,8 @@ private:
rpl::variable _recentCount;
Fn _recentPeersChoose;
Fn _recentSelectJump;
+ Fn _recentUpdateFromParentDrag;
+ Fn _recentDragLeft;
const not_null*> _recentPeers;
const not_null*> _emptyRecent;
@@ -130,11 +144,15 @@ private:
rpl::variable _myChannelsCount;
Fn _myChannelsChoose;
Fn _myChannelsSelectJump;
+ Fn _myChannelsUpdateFromParentDrag;
+ Fn _myChannelsDragLeft;
const not_null*> _myChannels;
rpl::variable _recommendationsCount;
Fn _recommendationsChoose;
Fn _recommendationsSelectJump;
+ Fn _recommendationsUpdateFromParentDrag;
+ Fn _recommendationsDragLeft;
const not_null*> _recommendations;
const not_null*> _emptyChannels;
diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp
index f793da346c..40e758ad2a 100644
--- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp
+++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp
@@ -248,7 +248,7 @@ void TopPeersStrip::stripWheelEvent(QWheelEvent *e) {
void TopPeersStrip::stripLeaveEvent(QEvent *e) {
if (!_selectionByKeyboard) {
- setSelected(-1);
+ clearSelection();
}
if (!_dragging) {
_lastMousePosition = std::nullopt;
@@ -299,9 +299,7 @@ void TopPeersStrip::stripMouseMoveEvent(QMouseEvent *e) {
&& (_lastMousePosition == e->globalPos())) {
return;
}
- _lastMousePosition = e->globalPos();
- _selectionByKeyboard = false;
- updateSelected();
+ selectByMouse(e->globalPos());
if (!_dragging && _mouseDownPosition) {
if ((*_lastMousePosition - *_mouseDownPosition).manhattanLength()
@@ -315,6 +313,12 @@ void TopPeersStrip::stripMouseMoveEvent(QMouseEvent *e) {
checkDragging();
}
+void TopPeersStrip::selectByMouse(QPoint globalPosition) {
+ _lastMousePosition = globalPosition;
+ _selectionByKeyboard = false;
+ updateSelected();
+}
+
void TopPeersStrip::checkDragging() {
if (_dragging && !_expandAnimation.animating()) {
const auto sign = (style::RightToLeft() ? -1 : 1);
@@ -551,6 +555,20 @@ bool TopPeersStrip::chooseRow() {
return false;
}
+uint64 TopPeersStrip::updateFromParentDrag(QPoint globalPosition) {
+ if (!rect().contains(mapFromGlobal(globalPosition))) {
+ dragLeft();
+ return 0;
+ }
+ selectByMouse(globalPosition);
+
+ return (_selected >= 0) ? _entries[_selected].id : 0;
+}
+
+void TopPeersStrip::dragLeft() {
+ clearSelection();
+}
+
void TopPeersStrip::apply(const TopPeersList &list) {
if (_hiddenLocally) {
return;
@@ -908,6 +926,10 @@ void TopPeersStrip::setSelected(int selected) {
}
}
+void TopPeersStrip::clearSelection() {
+ setSelected(-1);
+}
+
void TopPeersStrip::scrollToSelected() {
if (_selected < 0) {
return;
diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h
index 9894235c69..23db15d1f2 100644
--- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h
+++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h
@@ -62,6 +62,9 @@ public:
void deselectByKeyboard();
bool chooseRow();
+ uint64 updateFromParentDrag(QPoint globalPosition);
+ void dragLeft();
+
[[nodiscard]] auto verticalScrollEvents() const
-> rpl::producer>;
@@ -92,6 +95,8 @@ private:
void subscribeUserpic(Entry &entry);
void unsubscribeUserpics(bool all = false);
void paintUserpic(Painter &p, int x, int y, int index, bool selected);
+ void clearSelection();
+ void selectByMouse(QPoint globalPosition);
[[nodiscard]] QRect outer() const;
[[nodiscard]] QRect innerRounded() const;
diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_frame_generator.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_frame_generator.cpp
index 116d998a2a..de478b784b 100644
--- a/Telegram/SourceFiles/ffmpeg/ffmpeg_frame_generator.cpp
+++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_frame_generator.cpp
@@ -291,7 +291,11 @@ void FrameGenerator::Impl::jumpToStart() {
void FrameGenerator::Impl::resolveNextFrameTiming() {
const auto base = _format->streams[_streamId]->time_base;
+#if DA_FFMPEG_HAVE_DURATION
+ const auto duration = _next.frame->duration;
+#else
const auto duration = _next.frame->pkt_duration;
+#endif
const auto framePts = _next.frame->pts;
auto framePosition = (framePts * 1000LL * base.num) / base.den;
_currentFrameDelay = _nextFrameDelay;
diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp
index 2a42d0034c..0f7083df36 100644
--- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp
+++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp
@@ -230,7 +230,11 @@ enum AVPixelFormat GetFormatImplementation(
IOPointer MakeIOPointer(
void *opaque,
int(*read)(void *opaque, uint8_t *buffer, int bufferSize),
+#if DA_FFMPEG_CONST_WRITE_CALLBACK
+ int(*write)(void *opaque, const uint8_t *buffer, int bufferSize),
+#else
int(*write)(void *opaque, uint8_t *buffer, int bufferSize),
+#endif
int64_t(*seek)(void *opaque, int64_t offset, int whence)) {
auto buffer = reinterpret_cast(av_malloc(kAvioBlockSize));
if (!buffer) {
@@ -263,7 +267,11 @@ void IODeleter::operator()(AVIOContext *value) {
FormatPointer MakeFormatPointer(
void *opaque,
int(*read)(void *opaque, uint8_t *buffer, int bufferSize),
+#if DA_FFMPEG_CONST_WRITE_CALLBACK
+ int(*write)(void *opaque, const uint8_t *buffer, int bufferSize),
+#else
int(*write)(void *opaque, uint8_t *buffer, int bufferSize),
+#endif
int64_t(*seek)(void *opaque, int64_t offset, int whence)) {
auto io = MakeIOPointer(opaque, read, write, seek);
if (!io) {
diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h
index bc9c8764b9..d96daa9c79 100644
--- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h
+++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h
@@ -22,8 +22,14 @@ extern "C" {
#include
} // extern "C"
-#define DA_FFMPEG_NEW_CHANNEL_LAYOUT (LIBAVUTIL_VERSION_MAJOR > 57 \
- || (LIBAVUTIL_VERSION_MAJOR == 57 && LIBAVUTIL_VERSION_MINOR >= 28))
+#define DA_FFMPEG_NEW_CHANNEL_LAYOUT (LIBAVUTIL_VERSION_INT >= \
+ AV_VERSION_INT(57, 28, 100))
+
+#define DA_FFMPEG_CONST_WRITE_CALLBACK (LIBAVFORMAT_VERSION_INT >= \
+ AV_VERSION_INT(61, 01, 100))
+
+#define DA_FFMPEG_HAVE_DURATION (LIBAVUTIL_VERSION_INT >= \
+ AV_VERSION_INT(58, 02, 100))
class QImage;
@@ -112,7 +118,11 @@ using IOPointer = std::unique_ptr;
[[nodiscard]] IOPointer MakeIOPointer(
void *opaque,
int(*read)(void *opaque, uint8_t *buffer, int bufferSize),
+#if DA_FFMPEG_CONST_WRITE_CALLBACK
+ int(*write)(void *opaque, const uint8_t *buffer, int bufferSize),
+#else
int(*write)(void *opaque, uint8_t *buffer, int bufferSize),
+#endif
int64_t(*seek)(void *opaque, int64_t offset, int whence));
struct FormatDeleter {
@@ -122,7 +132,11 @@ using FormatPointer = std::unique_ptr;
[[nodiscard]] FormatPointer MakeFormatPointer(
void *opaque,
int(*read)(void *opaque, uint8_t *buffer, int bufferSize),
+#if DA_FFMPEG_CONST_WRITE_CALLBACK
+ int(*write)(void *opaque, const uint8_t *buffer, int bufferSize),
+#else
int(*write)(void *opaque, uint8_t *buffer, int bufferSize),
+#endif
int64_t(*seek)(void *opaque, int64_t offset, int whence));
struct CodecDeleter {
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index 144a4483a5..9a62d4a349 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -3647,7 +3647,8 @@ void HistoryItem::createComponentsHelper(HistoryItemCommonFields &&fields) {
const auto topicPost = config.reply.externalPeerId
? (replyTo.topicRootId
&& (replyTo.topicRootId != Data::ForumTopic::kGeneralId))
- : (LookupReplyIsTopicPost(to)
+ : (topic
+ || LookupReplyIsTopicPost(to)
|| (to && to->Has())
|| (forum && forum->creating(config.reply.topMessageId)));
config.reply.topicPost = topicPost ? 1 : 0;
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 441a0f8c00..a8ca276ff4 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -2681,6 +2681,7 @@ void HistoryWidget::setEditMsgId(MsgId msgId) {
unregisterDraftSources();
_editMsgId = msgId;
if (!msgId) {
+ _mediaEditSpoiler.setSpoilerOverride(std::nullopt);
_canReplaceMedia = false;
if (_preview) {
_preview->setDisabled(false);
@@ -4071,7 +4072,8 @@ void HistoryWidget::saveEditMsg() {
webPageDraft,
options,
done,
- fail);
+ fail,
+ _mediaEditSpoiler.spoilerOverride());
}
void HistoryWidget::hideChildWidgets() {
@@ -6602,7 +6604,14 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
return;
}
const auto isReadyToForward = readyToForward();
- if (_inPhotoEdit && _photoEditMedia) {
+ if (_editMsgId
+ && (_inDetails || _inPhotoEdit)
+ && (e->button() == Qt::RightButton)) {
+ _mediaEditSpoiler.showMenu(
+ _list,
+ session().data().message(_history->peer, _editMsgId),
+ [=](bool) { mouseMoveEvent(nullptr); });
+ } else if (_inPhotoEdit && _photoEditMedia) {
EditCaptionBox::StartPhotoEdit(
controller(),
_photoEditMedia,
@@ -8209,12 +8218,14 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
}
}
if (_replyEditMsg) {
- const auto media = _replyEditMsg->media();
- _canReplaceMedia = media && media->allowsEditMedia();
+ const auto editMedia = _editMsgId
+ ? _replyEditMsg->media()
+ : nullptr;
+ _canReplaceMedia = editMedia && editMedia->allowsEditMedia();
_photoEditMedia = (_canReplaceMedia
- && media->photo()
- && !media->photo()->isNull())
- ? media->photo()->createMediaView()
+ && editMedia->photo()
+ && !editMedia->photo()->isNull())
+ ? editMedia->photo()->createMediaView()
: nullptr;
if (_photoEditMedia) {
_photoEditMedia->wanted(
@@ -8303,8 +8314,14 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
? drawMsgText->media()
: nullptr;
const auto hasPreview = media && media->hasReplyPreview();
- const auto preview = hasPreview ? media->replyPreview() : nullptr;
- const auto spoilered = preview && media->hasSpoiler();
+ const auto preview = _mediaEditSpoiler.spoilerOverride()
+ ? _mediaEditSpoiler.mediaPreview(drawMsgText)
+ : hasPreview
+ ? media->replyPreview()
+ : nullptr;
+ const auto spoilered = _mediaEditSpoiler.spoilerOverride()
+ ? (*_mediaEditSpoiler.spoilerOverride())
+ : (preview && media->hasSpoiler());
if (!spoilered) {
_replySpoiler = nullptr;
} else if (!_replySpoiler) {
diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h
index 76d3e6940b..47bdaecfa0 100644
--- a/Telegram/SourceFiles/history/history_widget.h
+++ b/Telegram/SourceFiles/history/history_widget.h
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
+#include "history/view/controls/history_view_compose_media_edit_manager.h"
#include "history/view/history_view_corner_buttons.h"
#include "history/history_drag_area.h"
#include "history/history_view_highlight_manager.h"
@@ -103,6 +104,7 @@ class ForwardPanel;
class TTLButton;
class WebpageProcessor;
class CharactersLimitLabel;
+class PhotoEditSpoilerManager;
} // namespace HistoryView::Controls
class BotKeyboard;
@@ -661,6 +663,7 @@ private:
MsgId _editMsgId = 0;
std::shared_ptr _photoEditMedia;
bool _canReplaceMedia = false;
+ HistoryView::MediaEditSpoilerManager _mediaEditSpoiler;
HistoryItem *_replyEditMsg = nullptr;
Ui::Text::String _replyEditMsgText;
diff --git a/Telegram/SourceFiles/history/view/controls/compose_controls_common.h b/Telegram/SourceFiles/history/view/controls/compose_controls_common.h
index e707523ecc..01237072b6 100644
--- a/Telegram/SourceFiles/history/view/controls/compose_controls_common.h
+++ b/Telegram/SourceFiles/history/view/controls/compose_controls_common.h
@@ -21,6 +21,7 @@ struct MessageToEdit {
FullMsgId fullId;
Api::SendOptions options;
TextWithTags textWithTags;
+ std::optional spoilerMediaOverride;
};
struct VoiceToSend {
QByteArray bytes;
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
index 859a4d83a6..5e988e51e6 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
@@ -50,6 +50,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "history/history_item.h"
#include "history/view/controls/history_view_characters_limit.h"
+#include "history/view/controls/history_view_compose_media_edit_manager.h"
#include "history/view/controls/history_view_forward_panel.h"
#include "history/view/controls/history_view_draft_options.h"
#include "history/view/controls/history_view_voice_record_bar.h"
@@ -72,6 +73,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/ui_utility.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/dropdown_menu.h"
+#include "ui/widgets/popup_menu.h"
#include "ui/text/format_values.h"
#include "ui/controls/emoji_button.h"
#include "ui/controls/send_button.h"
@@ -84,6 +86,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h"
#include "styles/style_chat.h"
#include "styles/style_chat_helpers.h"
+#include "styles/style_menu_icons.h"
namespace HistoryView {
namespace {
@@ -210,6 +213,8 @@ private:
bool _repaintScheduled : 1 = false;
bool _inClickable : 1 = false;
+ HistoryView::MediaEditSpoilerManager _mediaEditSpoiler;
+
const not_null _data;
const not_null _cancel;
@@ -398,7 +403,12 @@ void FieldHeader::init() {
_editOptionsRequests.fire({});
}
} else if (!isLeftButton) {
- if (const auto reply = replyingToMessage()) {
+ if (inPreviewRect && isEditingMessage()) {
+ _mediaEditSpoiler.showMenu(
+ this,
+ _data->message(_editMsgId.current()),
+ [=](bool) { update(); });
+ } else if (const auto reply = replyingToMessage()) {
_jumpToItemRequests.fire_copy(reply);
}
}
@@ -572,10 +582,14 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) {
const auto media = _shownMessage->media();
_shownMessageHasPreview = media && media->hasReplyPreview();
- const auto preview = _shownMessageHasPreview
+ const auto preview = _mediaEditSpoiler.spoilerOverride()
+ ? _mediaEditSpoiler.mediaPreview(_shownMessage)
+ : _shownMessageHasPreview
? media->replyPreview()
: nullptr;
- const auto spoilered = preview && media->hasSpoiler();
+ const auto spoilered = _mediaEditSpoiler.spoilerOverride()
+ ? (*_mediaEditSpoiler.spoilerOverride())
+ : (preview && media->hasSpoiler());
if (!spoilered) {
_shownPreviewSpoiler = nullptr;
} else if (!_shownPreviewSpoiler) {
@@ -720,6 +734,7 @@ void FieldHeader::editMessage(FullMsgId id, bool photoEditAllowed) {
_photoEditAllowed = photoEditAllowed;
_editMsgId = id;
if (!photoEditAllowed) {
+ _mediaEditSpoiler.setSpoilerOverride(std::nullopt);
_inPhotoEdit = false;
_inPhotoEditOver.stop();
}
@@ -767,6 +782,7 @@ MessageToEdit FieldHeader::queryToEdit() {
.scheduled = item->isScheduled() ? item->date() : 0,
.shortcutId = item->shortcutId(),
},
+ .spoilerMediaOverride = _mediaEditSpoiler.spoilerOverride(),
};
}
@@ -3440,4 +3456,49 @@ rpl::producer SendDisabledBySlowmode(not_null peer) {
_1 && _2);
}
+void ShowPhotoEditSpoilerMenu(
+ not_null parent,
+ not_null item,
+ const std::optional &override,
+ Fn callback) {
+ const auto media = item->media();
+ const auto hasPreview = media && media->hasReplyPreview();
+ const auto preview = hasPreview ? media->replyPreview() : nullptr;
+ if (!preview) {
+ return;
+ }
+ const auto spoilered = override
+ ? (*override)
+ : (preview && media->hasSpoiler());
+ const auto menu = Ui::CreateChild(
+ parent,
+ st::popupMenuWithIcons);
+ menu->addAction(
+ spoilered
+ ? tr::lng_context_disable_spoiler(tr::now)
+ : tr::lng_context_spoiler_effect(tr::now),
+ [=] { callback(!spoilered); },
+ spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler);
+ menu->popup(QCursor::pos());
+}
+
+Image *MediaPreviewWithOverriddenSpoiler(
+ not_null item,
+ bool spoiler) {
+ if (const auto media = item->media()) {
+ if (const auto photo = media->photo()) {
+ return photo->getReplyPreview(
+ item->fullId(),
+ item->history()->peer,
+ spoiler);
+ } else if (const auto document = media->document()) {
+ return document->getReplyPreview(
+ item->fullId(),
+ item->history()->peer,
+ spoiler);
+ }
+ }
+ return nullptr;
+}
+
} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h
index b24e0213ab..f6c915968c 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History;
class DocumentData;
class FieldAutocomplete;
+class Image;
namespace style {
struct ComposeControls;
@@ -451,4 +452,14 @@ private:
[[nodiscard]] rpl::producer SendDisabledBySlowmode(
not_null peer);
+void ShowPhotoEditSpoilerMenu(
+ not_null parent,
+ not_null item,
+ const std::optional &override,
+ Fn callback);
+
+[[nodiscard]] Image *MediaPreviewWithOverriddenSpoiler(
+ not_null item,
+ bool spoiler);
+
} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_media_edit_manager.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_media_edit_manager.cpp
new file mode 100644
index 0000000000..940ff7ff24
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_media_edit_manager.cpp
@@ -0,0 +1,83 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "history/view/controls/history_view_compose_media_edit_manager.h"
+
+#include "data/data_document.h"
+#include "data/data_file_origin.h"
+#include "data/data_photo.h"
+#include "history/history.h"
+#include "history/history_item.h"
+#include "lang/lang_keys.h"
+#include "ui/widgets/popup_menu.h"
+#include "styles/style_menu_icons.h"
+
+namespace HistoryView {
+
+MediaEditSpoilerManager::MediaEditSpoilerManager() = default;
+
+void MediaEditSpoilerManager::showMenu(
+ not_null parent,
+ not_null item,
+ Fn callback) {
+ const auto media = item->media();
+ const auto hasPreview = media && media->hasReplyPreview();
+ const auto preview = hasPreview ? media->replyPreview() : nullptr;
+ if (!preview) {
+ return;
+ }
+ const auto spoilered = _spoilerOverride
+ ? (*_spoilerOverride)
+ : (preview && media->hasSpoiler());
+ const auto menu = Ui::CreateChild(
+ parent,
+ st::popupMenuWithIcons);
+ menu->addAction(
+ spoilered
+ ? tr::lng_context_disable_spoiler(tr::now)
+ : tr::lng_context_spoiler_effect(tr::now),
+ [=] {
+ _spoilerOverride = (!spoilered);
+ if (callback) {
+ callback(!spoilered);
+ }
+ },
+ spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler);
+ menu->popup(QCursor::pos());
+}
+
+[[nodiscard]] Image *MediaEditSpoilerManager::mediaPreview(
+ not_null item) {
+ if (!_spoilerOverride) {
+ return nullptr;
+ }
+ if (const auto media = item->media()) {
+ if (const auto photo = media->photo()) {
+ return photo->getReplyPreview(
+ item->fullId(),
+ item->history()->peer,
+ *_spoilerOverride);
+ } else if (const auto document = media->document()) {
+ return document->getReplyPreview(
+ item->fullId(),
+ item->history()->peer,
+ *_spoilerOverride);
+ }
+ }
+ return nullptr;
+}
+
+void MediaEditSpoilerManager::setSpoilerOverride(
+ std::optional spoilerOverride) {
+ _spoilerOverride = spoilerOverride;
+}
+
+std::optional MediaEditSpoilerManager::spoilerOverride() const {
+ return _spoilerOverride;
+}
+
+} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_media_edit_manager.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_media_edit_manager.h
new file mode 100644
index 0000000000..8bc34b7c4e
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_media_edit_manager.h
@@ -0,0 +1,39 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+namespace Ui {
+class RpWidget;
+} // namespace Ui
+
+class Image;
+class HistoryItem;
+
+namespace HistoryView {
+
+class MediaEditSpoilerManager final {
+public:
+ MediaEditSpoilerManager();
+
+ void showMenu(
+ not_null parent,
+ not_null item,
+ Fn callback);
+
+ [[nodiscard]] Image *mediaPreview(not_null item);
+
+ void setSpoilerOverride(std::optional spoilerOverride);
+
+ std::optional spoilerOverride() const;
+
+private:
+ std::optional _spoilerOverride;
+
+};
+
+} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp
index b17f1ba4f5..8afeff663c 100644
--- a/Telegram/SourceFiles/history/view/history_view_message.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_message.cpp
@@ -3860,7 +3860,7 @@ void Message::fromNameUpdated(int width) const {
const auto nameText = [&]() -> const Ui::Text::String * {
if (from) {
return &_fromName;
- } else if (const auto info= item->originalHiddenSenderInfo()) {
+ } else if (const auto info = item->originalHiddenSenderInfo()) {
return &info->nameText();
} else {
Unexpected("Corrupted forwarded information in message.");
diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp
index 90241557b7..f0b8d99906 100644
--- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp
@@ -744,7 +744,8 @@ void RepliesWidget::setupComposeControls() {
_composeControls->editRequests(
) | rpl::start_with_next([=](auto data) {
if (const auto item = session().data().message(data.fullId)) {
- edit(item, data.options, saveEditMsgRequestId);
+ const auto spoiler = data.spoilerMediaOverride;
+ edit(item, data.options, saveEditMsgRequestId, spoiler);
}
}, lifetime());
@@ -1215,7 +1216,8 @@ void RepliesWidget::send(Api::SendOptions options) {
void RepliesWidget::edit(
not_null item,
Api::SendOptions options,
- mtpRequestId *const saveEditMsgRequestId) {
+ mtpRequestId *const saveEditMsgRequestId,
+ std::optional spoilerMediaOverride) {
if (*saveEditMsgRequestId) {
return;
}
@@ -1283,7 +1285,8 @@ void RepliesWidget::edit(
webpage,
options,
crl::guard(this, done),
- crl::guard(this, fail));
+ crl::guard(this, fail),
+ spoilerMediaOverride);
_composeControls->hidePanelsAnimated();
doSetInnerFocus();
diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h
index 3da1c44f0a..33b7859b48 100644
--- a/Telegram/SourceFiles/history/view/history_view_replies_section.h
+++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h
@@ -246,7 +246,8 @@ private:
void edit(
not_null item,
Api::SendOptions options,
- mtpRequestId *const saveEditMsgRequestId);
+ mtpRequestId *const saveEditMsgRequestId,
+ std::optional spoilerMediaOverride);
void chooseAttach(std::optional overrideSendImagesAsPhotos);
[[nodiscard]] SendMenu::Type sendMenuType() const;
[[nodiscard]] FullReplyTo replyTo() const;
diff --git a/Telegram/SourceFiles/history/view/history_view_reply.cpp b/Telegram/SourceFiles/history/view/history_view_reply.cpp
index 51ec4f320b..4e7f6c48b8 100644
--- a/Telegram/SourceFiles/history/view/history_view_reply.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_reply.cpp
@@ -587,7 +587,7 @@ QSize Reply::countMultilineOptimalSize(
textGeometry(max, previewSkip, &elided));
_minHeightExpandable = elided ? 1 : 0;
return {
- result.width,
+ result.width + st::historyReplyPadding.right(),
std::max(result.height, st::normalFont->height),
};
}
diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp
index 632132a132..3a02b72fbc 100644
--- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp
@@ -326,7 +326,8 @@ void ScheduledWidget::setupComposeControls() {
) | rpl::start_with_next([=](auto data) {
if (const auto item = session().data().message(data.fullId)) {
if (item->isScheduled()) {
- edit(item, data.options, saveEditMsgRequestId);
+ const auto spoiler = data.spoilerMediaOverride;
+ edit(item, data.options, saveEditMsgRequestId, spoiler);
}
}
}, lifetime());
@@ -734,7 +735,8 @@ void ScheduledWidget::sendVoice(
void ScheduledWidget::edit(
not_null item,
Api::SendOptions options,
- mtpRequestId *const saveEditMsgRequestId) {
+ mtpRequestId *const saveEditMsgRequestId,
+ std::optional spoilerMediaOverride) {
if (*saveEditMsgRequestId) {
return;
}
@@ -802,7 +804,8 @@ void ScheduledWidget::edit(
webpage,
options,
crl::guard(this, done),
- crl::guard(this, fail));
+ crl::guard(this, fail),
+ spoilerMediaOverride);
_composeControls->hidePanelsAnimated();
_composeControls->focus();
diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h
index 43702688fe..6685c113a4 100644
--- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h
+++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h
@@ -213,7 +213,8 @@ private:
void edit(
not_null item,
Api::SendOptions options,
- mtpRequestId *const saveEditMsgRequestId);
+ mtpRequestId *const saveEditMsgRequestId,
+ std::optional spoilerMediaOverride);
void highlightSingleNewMessage(const Data::MessagesSlice &slice);
void chooseAttach();
[[nodiscard]] SendMenu::Type sendMenuType() const;
diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp
index bb5ebf46e4..b00df78b4a 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp
@@ -447,6 +447,7 @@ QSize Document::countOptimalSize() {
const auto session = &history->session();
const auto transcribes = &session->api().transcribes();
if (_parent->data()->media()->ttlSeconds()
+ || _realParent->isScheduled()
|| (!session->premium()
&& !transcribes->freeFor(_realParent)
&& !transcribes->trialsSupport())) {
diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp
index 26c7f48fe3..a89a760838 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp
@@ -2076,6 +2076,7 @@ void Gif::ensureTranscribeButton() const {
if (_data->isVideoMessage()
&& !_parent->data()->media()->ttlSeconds()
+ && !_parent->data()->isScheduled()
&& (_data->session().premium()
|| _data->session().api().transcribes().trialsSupport())) {
if (!_transcribe) {
diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp
index 9a40c97078..905536c903 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp
@@ -445,7 +445,7 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const {
}
if (recth) {
int rectx = _additionalOnTop
- ? (rightAligned ? (inner.width() + st::msgReplyPadding.left() - rectw) : 0)
+ ? (rightAligned ? (inner.x() + inner.width() - rectw) : 0)
: (rightAligned ? 0 : (inner.width() + st::msgReplyPadding.left()));
int recty = surrounding.height - recth;
if (rtl()) rectx = width() - rectx - rectw;
diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp
index a07545d88e..ab401b9fe5 100644
--- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp
+++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp
@@ -921,7 +921,9 @@ void Selector::createList() {
&_show->session(),
_strip ? _reactions.recent : std::vector(),
_strip.get());
- _scroll = Ui::CreateChild(this, st::reactPanelScroll);
+ _scroll = Ui::CreateChild(this, _reactions.customAllowed
+ ? st::reactPanelScroll
+ : st::reactPanelScrollRounded);
_scroll->hide();
const auto st = lifetime().make_state(_st);
diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style
index 1b1924c983..d076cc9494 100644
--- a/Telegram/SourceFiles/info/info.style
+++ b/Telegram/SourceFiles/info/info.style
@@ -665,6 +665,10 @@ manageGroupTopicsButton: SettingsCountButton(manageGroupTopButtonWithText) {
}
}
}
+managePeerColorsButton: SettingsButton(infoProfileButton) {
+ padding: margins(60px, 10px, 48px, 8px);
+}
+
manageGroupNoIconButtonInner: SettingsButton(infoProfileButton) {
padding: margins(25px, 11px, 24px, 8px);
}
diff --git a/Telegram/SourceFiles/main/main_session_settings.cpp b/Telegram/SourceFiles/main/main_session_settings.cpp
index 7806dea9f1..6349f6b6a3 100644
--- a/Telegram/SourceFiles/main/main_session_settings.cpp
+++ b/Telegram/SourceFiles/main/main_session_settings.cpp
@@ -128,7 +128,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
base::flat_set groupEmojiSectionHidden;
qint32 appThirdSectionInfoEnabled = 0;
qint32 legacySmallDialogsList = 0;
- float64 appDialogsWidthRatio = app.dialogsWidthRatio();
+ float64 appDialogsWidthRatio = app.dialogsWidthRatio(false);
int appThirdColumnWidth = app.thirdColumnWidth();
int appThirdSectionExtendedBy = app.thirdSectionExtendedBy();
qint32 appSendFilesWay = app.sendFilesWay().serialize();
@@ -535,7 +535,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
case RectPart::BottomRight: app.setFloatPlayerCorner(uncheckedCorner); break;
}
app.setThirdSectionInfoEnabled(appThirdSectionInfoEnabled);
- app.setDialogsWidthRatio(appDialogsWidthRatio);
+ app.updateDialogsWidthRatio(appDialogsWidthRatio, false);
app.setThirdColumnWidth(appThirdColumnWidth);
app.setThirdSectionExtendedBy(appThirdSectionExtendedBy);
}
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 1a7a16c015..31ce8e064b 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -303,8 +303,16 @@ MainWidget::MainWidget(
});
}, lifetime());
+ const auto filter = [=](bool mainSectionShown) {
+ return rpl::filter([=] {
+ return (_controller->mainSectionShown() == mainSectionShown);
+ });
+ };
rpl::merge(
- Core::App().settings().dialogsWidthRatioChanges() | rpl::to_empty,
+ Core::App().settings().dialogsWithChatWidthRatioChanges(
+ ) | filter(true) | rpl::to_empty,
+ Core::App().settings().dialogsNoChatWidthRatioChanges(
+ ) | filter(false) | rpl::to_empty,
Core::App().settings().thirdColumnWidthChanges() | rpl::to_empty
) | rpl::start_with_next([=] {
updateControlsGeometry();
@@ -1408,6 +1416,7 @@ void MainWidget::showHistory(
auto onlyDialogs = noPeer && isOneColumn();
_mainSection.destroy();
+ updateMainSectionShown();
updateControlsGeometry();
if (noPeer) {
@@ -1781,6 +1790,7 @@ void MainWidget::showNewSection(
if (const auto entry = _mainSection->activeChat(); entry.key) {
_controller->setActiveChatEntry(entry);
}
+ updateMainSectionShown();
// Depends on SessionController::activeChatEntry
// for tabbed selector showing in the third column.
@@ -1815,22 +1825,16 @@ void MainWidget::checkMainSectionToLayer() {
}
Ui::FocusPersister persister(this);
if (auto layer = _mainSection->moveContentToLayer(rect())) {
- dropMainSection(_mainSection);
+ _mainSection.destroy();
+ _controller->showBackFromStack(
+ SectionShow(
+ anim::type::instant,
+ anim::activation::background));
_controller->showSpecialLayer(
std::move(layer),
anim::type::instant);
}
-}
-
-void MainWidget::dropMainSection(Window::SectionWidget *widget) {
- if (_mainSection != widget) {
- return;
- }
- _mainSection.destroy();
- _controller->showBackFromStack(
- SectionShow(
- anim::type::instant,
- anim::activation::background));
+ updateMainSectionShown();
}
PeerData *MainWidget::singlePeer() const {
@@ -2236,13 +2240,18 @@ void MainWidget::resizeEvent(QResizeEvent *e) {
updateControlsGeometry();
}
+void MainWidget::updateMainSectionShown() {
+ _controller->setMainSectionShown(_mainSection || _history->peer());
+}
+
void MainWidget::updateControlsGeometry() {
if (!width()) {
return;
}
updateWindowAdaptiveLayout();
if (_dialogs) {
- if (Core::App().settings().dialogsWidthRatio() > 0) {
+ const auto nochat = !_controller->mainSectionShown();
+ if (Core::App().settings().dialogsWidthRatio(nochat) > 0) {
_a_dialogsWidth.stop();
}
if (!_a_dialogsWidth.animating()) {
@@ -2444,19 +2453,22 @@ void MainWidget::ensureFirstColumnResizeAreaCreated() {
return;
}
auto moveLeftCallback = [=](int globalLeft) {
- auto newWidth = globalLeft - mapToGlobal(QPoint(0, 0)).x();
- auto newRatio = (newWidth < st::columnMinimalWidthLeft / 2)
+ const auto newWidth = globalLeft - mapToGlobal(QPoint(0, 0)).x();
+ const auto newRatio = (newWidth < st::columnMinimalWidthLeft / 2)
? 0.
: float64(newWidth) / width();
- Core::App().settings().setDialogsWidthRatio(newRatio);
+ const auto nochat = !_controller->mainSectionShown();
+ Core::App().settings().updateDialogsWidthRatio(newRatio, nochat);
};
auto moveFinishedCallback = [=] {
if (isOneColumn()) {
return;
}
- if (Core::App().settings().dialogsWidthRatio() > 0) {
- Core::App().settings().setDialogsWidthRatio(
- float64(_dialogsWidth) / width());
+ const auto nochat = !_controller->mainSectionShown();
+ if (Core::App().settings().dialogsWidthRatio(nochat) > 0) {
+ Core::App().settings().updateDialogsWidthRatio(
+ float64(_dialogsWidth) / width(),
+ nochat);
}
Core::App().saveSettingsDelayed();
};
@@ -2491,12 +2503,13 @@ void MainWidget::ensureThirdColumnResizeAreaCreated() {
}
void MainWidget::updateDialogsWidthAnimated() {
- if (!_dialogs || Core::App().settings().dialogsWidthRatio() > 0) {
+ const auto nochat = !_controller->mainSectionShown();
+ if (!_dialogs || Core::App().settings().dialogsWidthRatio(nochat) > 0) {
return;
}
auto dialogsWidth = _dialogsWidth;
updateWindowAdaptiveLayout();
- if (!Core::App().settings().dialogsWidthRatio()
+ if (Core::App().settings().dialogsWidthRatio(nochat) == 0.
&& (_dialogsWidth != dialogsWidth
|| _a_dialogsWidth.animating())) {
_dialogs->startWidthAnimation();
@@ -2709,8 +2722,10 @@ void MainWidget::handleHistoryBack() {
}
void MainWidget::updateWindowAdaptiveLayout() {
+ const auto nochat = !_controller->mainSectionShown();
+
auto layout = _controller->computeColumnLayout();
- auto dialogsWidthRatio = Core::App().settings().dialogsWidthRatio();
+ auto dialogsWidthRatio = Core::App().settings().dialogsWidthRatio(nochat);
// Check if we are in a single-column layout in a wide enough window
// for the normal layout. If so, switch to the normal layout.
@@ -2753,7 +2768,7 @@ void MainWidget::updateWindowAdaptiveLayout() {
//}
}
- Core::App().settings().setDialogsWidthRatio(dialogsWidthRatio);
+ Core::App().settings().updateDialogsWidthRatio(dialogsWidthRatio, nochat);
auto useSmallColumnWidth = !isOneColumn()
&& !dialogsWidthRatio
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 1e0d35d1ca..be26770ce3 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -250,6 +250,7 @@ private:
void handleAudioUpdate(const Media::Player::TrackState &state);
void updateMediaPlaylistPosition(int x);
void updateControlsGeometry();
+ void updateMainSectionShown();
void updateDialogsWidthAnimated();
void updateThirdColumnToCurrentChat(
Dialogs::Key key,
@@ -278,7 +279,6 @@ private:
void showNewSection(
std::shared_ptr memento,
const SectionShow ¶ms);
- void dropMainSection(Window::SectionWidget *widget);
Window::SectionSlideParams prepareThirdSectionAnimation(Window::SectionWidget *section);
diff --git a/Telegram/SourceFiles/media/audio/media_audio_capture.cpp b/Telegram/SourceFiles/media/audio/media_audio_capture.cpp
index b9151db2a0..1bbf9b10c2 100644
--- a/Telegram/SourceFiles/media/audio/media_audio_capture.cpp
+++ b/Telegram/SourceFiles/media/audio/media_audio_capture.cpp
@@ -249,7 +249,11 @@ struct Instance::Inner::Private {
return nbytes;
}
+#if DA_FFMPEG_CONST_WRITE_CALLBACK
+ static int WriteData(void *opaque, const uint8_t *buf, int buf_size) {
+#else
static int WriteData(void *opaque, uint8_t *buf, int buf_size) {
+#endif
auto l = reinterpret_cast(opaque);
if (buf_size <= 0) return 0;
diff --git a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp
index 9f1c7b2349..1188f02324 100644
--- a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp
+++ b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp
@@ -144,7 +144,11 @@ ReaderImplementation::ReadResult FFMpegReaderImplementation::readNextFrame() {
}
void FFMpegReaderImplementation::processReadFrame() {
+#if DA_FFMPEG_HAVE_DURATION
+ int64 duration = _frame->duration;
+#else
int64 duration = _frame->pkt_duration;
+#endif
int64 framePts = _frame->pts;
crl::time frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
_currentFrameDelay = _nextFrameDelay;
diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp
index 31ea352379..99be5557f6 100644
--- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp
+++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp
@@ -544,6 +544,7 @@ void OverlayWidget::RendererGL::paintTransformedContent(
0.f, 0.f,
};
+ _contentBuffer->bind();
_contentBuffer->write(0, coords, sizeof(coords));
program->setUniformValue("viewport", _uniformViewport);
@@ -712,6 +713,7 @@ void OverlayWidget::RendererGL::paintControl(
};
_controlsProgram->bind();
_controlsProgram->setUniformValue("viewport", _uniformViewport);
+ _contentBuffer->bind();
if (!over.isEmpty() && overOpacity > 0) {
_contentBuffer->write(
offset * 4 * sizeof(GLfloat),
@@ -915,6 +917,7 @@ void OverlayWidget::RendererGL::paintRoundedCorners(int radius) {
const auto offset = kControlsOffset
+ (kControlsCount * kControlValues) / 4;
const auto byteOffset = offset * 4 * sizeof(GLfloat);
+ _contentBuffer->bind();
_contentBuffer->write(byteOffset, coords, sizeof(coords));
_roundedCornersProgram->bind();
_roundedCornersProgram->setUniformValue("viewport", _uniformViewport);
@@ -981,6 +984,7 @@ void OverlayWidget::RendererGL::paintStoriesSiblingPart(
+ (6 * 2 * 4) / 4 // rounding
+ (index * 4);
const auto byteOffset = offset * 4 * sizeof(GLfloat);
+ _contentBuffer->bind();
_contentBuffer->write(byteOffset, coords, sizeof(coords));
_controlsProgram->bind();
@@ -1059,6 +1063,7 @@ void OverlayWidget::RendererGL::paintUsingRaster(
geometry.left(), geometry.bottom(),
textured.texture.left(), textured.texture.top(),
};
+ _contentBuffer->bind();
_contentBuffer->write(
bufferOffset * 4 * sizeof(GLfloat),
coords,
diff --git a/Telegram/SourceFiles/media/view/media_view_pip_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_pip_opengl.cpp
index 8e4e8e7c2c..f4be398c20 100644
--- a/Telegram/SourceFiles/media/view/media_view_pip_opengl.cpp
+++ b/Telegram/SourceFiles/media/view/media_view_pip_opengl.cpp
@@ -427,6 +427,7 @@ void Pip::RendererGL::paintTransformedContent(
(geometry.outer.height() - geometry.inner.y()) * yscale,
};
+ _contentBuffer->bind();
_contentBuffer->write(0, coords, sizeof(coords));
const auto rgbaFrame = _chromaSize.isEmpty();
@@ -588,6 +589,7 @@ void Pip::RendererGL::paintButton(
iconOverRect.texture.right(), iconOverRect.texture.top(),
iconOverRect.texture.left(), iconOverRect.texture.top(),
};
+ _contentBuffer->bind();
_contentBuffer->write(
offset * 4 * sizeof(GLfloat),
coords,
@@ -741,6 +743,7 @@ void Pip::RendererGL::paintUsingRaster(
geometry.left(), geometry.bottom(),
textured.texture.left(), textured.texture.top(),
};
+ _contentBuffer->bind();
_contentBuffer->write(
bufferOffset * 4 * sizeof(GLfloat),
coords,
diff --git a/Telegram/SourceFiles/menu/menu_sponsored.cpp b/Telegram/SourceFiles/menu/menu_sponsored.cpp
index e917c3f077..495da6a856 100644
--- a/Telegram/SourceFiles/menu/menu_sponsored.cpp
+++ b/Telegram/SourceFiles/menu/menu_sponsored.cpp
@@ -37,11 +37,13 @@ namespace {
void AboutBox(
not_null box,
- not_null session) {
+ std::shared_ptr show) {
constexpr auto kUrl = "https://promote.telegram.org"_cs;
box->setNoContentMargin(true);
+ const auto session = &show->session();
+
const auto content = box->verticalLayout().get();
const auto levels = Data::LevelLimits(session)
.channelRestrictSponsoredLevelMin();
@@ -101,7 +103,7 @@ void AboutBox(
st::channelEarnSemiboldLabel),
padding);
Ui::AddSkip(content, st::channelEarnHistoryThreeSkip);
- content->add(
+ const auto label = content->add(
object_ptr(
content,
std::move(about),
@@ -121,6 +123,7 @@ void AboutBox(
(g.left() - left->width()) / 2,
g.top() + st::channelEarnHistoryThreeSkip);
}, left->lifetime());
+ return label;
};
addEntry(
tr::lng_sponsored_revenued_info1_title(),
@@ -144,10 +147,14 @@ void AboutBox(
lt_link,
tr::lng_settings_privacy_premium_link(
) | rpl::map([=](QString t) {
- return Ui::Text::Link(t, kUrl.utf16());
+ return Ui::Text::Link(std::move(t), u"internal:"_q);
}),
Ui::Text::RichLangValue),
- st::sponsoredAboutRemoveIcon);
+ st::sponsoredAboutRemoveIcon)->setClickHandlerFilter([=](
+ const auto &...) {
+ ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
+ return true;
+ });
Ui::AddSkip(content);
Ui::AddSkip(content);
}
@@ -332,16 +339,14 @@ void ShowSponsored(
not_null item) {
Expects(item->isSponsored());
- struct State final {
- };
- const auto state = std::make_shared();
+ const auto session = &item->history()->session();
const auto menu = Ui::CreateChild(
parent.get(),
st::popupMenuWithIcons);
menu->addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] {
- show->show(Box(AboutBox, &item->history()->session()));
+ show->show(Box(AboutBox, show));
}, &st::menuIconInfo);
menu->addAction(tr::lng_sponsored_menu_revenued_report(tr::now), [=] {
@@ -351,7 +356,13 @@ void ShowSponsored(
menu->addSeparator(&st::expandedMenuSeparator);
menu->addAction(tr::lng_sponsored_hide_ads(tr::now), [=] {
- ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
+ if (session->premium()) {
+ using Result = Data::SponsoredReportResult;
+ session->sponsoredMessages().createReportCallback(
+ item->fullId())(Result::Id("-1"), [](const auto &) {});
+ } else {
+ ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
+ }
}, &st::menuIconCancel);
menu->popup(QCursor::pos());
@@ -359,7 +370,7 @@ void ShowSponsored(
void ShowSponsoredAbout(std::shared_ptr show) {
show->showBox(Box([=](not_null box) {
- AboutBox(box, &show->session());
+ AboutBox(box, show);
}));
}
diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.cpp b/Telegram/SourceFiles/mtproto/mtp_instance.cpp
index 76c5cb623e..ee10958370 100644
--- a/Telegram/SourceFiles/mtproto/mtp_instance.cpp
+++ b/Telegram/SourceFiles/mtproto/mtp_instance.cpp
@@ -1020,12 +1020,25 @@ void Instance::Private::sendRequest(
const auto signedDcId = toMainDc ? -realShiftedDcId : realShiftedDcId;
registerRequest(requestId, signedDcId);
- if (afterRequestId) {
- request->after = getRequest(afterRequestId);
- }
request->lastSentTime = crl::now();
request->needsLayer = needsLayer;
+ if (afterRequestId) {
+ request->after = getRequest(afterRequestId);
+
+ if (request->after) {
+ // Check if this after request is waiting in _dependentRequests.
+ // This happens if it was after some other request and failed
+ // to wait for it, but that other request is still processed.
+ QMutexLocker locker(&_dependentRequestsLock);
+ const auto i = _dependentRequests.find(afterRequestId);
+ if (i != end(_dependentRequests)) {
+ _dependentRequests.emplace(requestId, afterRequestId);
+ return;
+ }
+ }
+ }
+
session->sendPrepared(request, msCanWait);
}
diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp
index e75af14641..c56582bc42 100644
--- a/Telegram/SourceFiles/overview/overview_layout.cpp
+++ b/Telegram/SourceFiles/overview/overview_layout.cpp
@@ -8,11 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "overview/overview_layout.h"
#include "overview/overview_layout_delegate.h"
+#include "core/ui_integration.h" // Core::MarkedTextContext.
#include "data/data_document.h"
#include "data/data_document_resolver.h"
#include "data/data_session.h"
#include "data/data_web_page.h"
-#include "data/data_media_types.h"
#include "data/data_peer.h"
#include "data/data_photo_media.h"
#include "data/data_document_media.h"
@@ -20,9 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/confirm_box.h"
#include "lang/lang_keys.h"
#include "layout/layout_selection.h"
-#include "mainwidget.h"
#include "storage/file_upload.h"
-#include "mainwindow.h"
#include "main/main_session.h"
#include "media/audio/media_audio.h"
#include "media/player/media_player_instance.h"
@@ -867,6 +865,7 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
p.drawTextLeft(nameleft, statustop, _width, _status.text(), statusw);
unreadx += statusw;
}
+ auto captionLeft = unreadx + st::mediaUnreadSkip;
if (parent()->hasUnreadMediaFlag() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) {
p.setPen(Qt::NoPen);
p.setBrush(selected ? st::msgFileInBgSelected : st::msgFileInBg);
@@ -875,6 +874,22 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
PainterHighQualityEnabler hq(p);
p.drawEllipse(style::rtlrect(unreadx + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width));
}
+ captionLeft += st::mediaUnreadSkip + st::mediaUnreadSize;
+ }
+ if (!_caption.isEmpty()) {
+ p.setPen(st::historyFileNameInFg);
+ const auto w = _width - captionLeft - st::defaultScrollArea.width;
+ _caption.draw(p, Ui::Text::PaintContext{
+ .position = QPoint(captionLeft, statustop),
+ .availableWidth = w,
+ .spoiler = Ui::Text::DefaultSpoilerCache(),
+ .paused = context
+ ? context->paused
+ : On(PowerSaving::kEmojiChat),
+ .pausedEmoji = On(PowerSaving::kEmojiChat),
+ .pausedSpoiler = On(PowerSaving::kChatSpoiler),
+ .elisionLines = 1,
+ });
}
}
@@ -981,23 +996,19 @@ const style::RoundCheckbox &Voice::checkboxStyle() const {
void Voice::updateName() {
if (const auto forwarded = parent()->Get()) {
- if (parent()->fromOriginal()->isChannel()) {
- _name.setText(
- st::semiboldTextStyle,
- tr::lng_forwarded_channel(
- tr::now,
- lt_channel,
- parent()->fromOriginal()->name()),
- Ui::NameTextOptions());
- } else {
- _name.setText(
- st::semiboldTextStyle,
- tr::lng_forwarded(
- tr::now,
- lt_user,
- parent()->fromOriginal()->name()),
- Ui::NameTextOptions());
- }
+ const auto info = parent()->originalHiddenSenderInfo();
+ const auto name = info
+ ? tr::lng_forwarded(tr::now, lt_user, info->nameText().toString())
+ : parent()->fromOriginal()->isChannel()
+ ? tr::lng_forwarded_channel(
+ tr::now,
+ lt_channel,
+ parent()->fromOriginal()->name())
+ : tr::lng_forwarded(
+ tr::now,
+ lt_user,
+ parent()->fromOriginal()->name());
+ _name.setText(st::semiboldTextStyle, name, Ui::NameTextOptions());
} else {
_name.setText(
st::semiboldTextStyle,
@@ -1005,6 +1016,14 @@ void Voice::updateName() {
Ui::NameTextOptions());
}
_nameVersion = parent()->fromOriginal()->nameVersion();
+ _caption.setMarkedText(
+ st::defaultTextStyle,
+ parent()->originalText(),
+ Ui::DialogTextOptions(),
+ Core::MarkedTextContext{
+ .session = &parent()->history()->session(),
+ .customEmojiRepaint = [=] { delegate()->repaintItem(this); },
+ });
}
bool Voice::updateStatusText() {
diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h
index 3526b5e57c..936379e36b 100644
--- a/Telegram/SourceFiles/overview/overview_layout.h
+++ b/Telegram/SourceFiles/overview/overview_layout.h
@@ -362,7 +362,9 @@ private:
const style::OverviewFileLayout &_st;
- Ui::Text::String _name, _details;
+ Ui::Text::String _name;
+ Ui::Text::String _details;
+ Ui::Text::String _caption;
int _nameVersion = 0;
void updateName();
diff --git a/Telegram/SourceFiles/payments/ui/payments_panel.cpp b/Telegram/SourceFiles/payments/ui/payments_panel.cpp
index f509fdb706..d97628285e 100644
--- a/Telegram/SourceFiles/payments/ui/payments_panel.cpp
+++ b/Telegram/SourceFiles/payments/ui/payments_panel.cpp
@@ -70,8 +70,8 @@ Panel::Progress::Progress(QWidget *parent, Fn rect)
Panel::Panel(not_null delegate)
: _delegate(delegate)
, _widget(std::make_unique()) {
- _widget->setInnerSize(st::paymentsPanelSize);
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
+ _widget->setInnerSize(st::paymentsPanelSize);
_widget->closeRequests(
) | rpl::start_with_next([=] {
@@ -534,12 +534,15 @@ bool Panel::createWebview(const Webview::ThemeParams ¶ms) {
const auto bottom = _webviewBottom.get();
bottom->show();
- bottom->heightValue(
- ) | rpl::start_with_next([=](int height) {
- const auto inner = _widget->innerGeometry();
+ rpl::combine(
+ container->geometryValue() | rpl::map([=] {
+ return _widget->innerGeometry();
+ }),
+ bottom->heightValue()
+ ) | rpl::start_with_next([=](QRect inner, int height) {
bottom->move(inner.x(), inner.y() + inner.height() - height);
- container->resize(inner.width(), inner.height() - height);
bottom->resizeToWidth(inner.width());
+ _footerHeight = bottom->height();
}, bottom->lifetime());
container->show();
@@ -584,10 +587,12 @@ bool Panel::createWebview(const Webview::ThemeParams ¶ms) {
});
});
- container->geometryValue(
- ) | rpl::start_with_next([=](QRect geometry) {
- if (raw->widget()) {
- raw->widget()->setGeometry(geometry);
+ rpl::combine(
+ container->geometryValue(),
+ _footerHeight.value()
+ ) | rpl::start_with_next([=](QRect geometry, int footer) {
+ if (const auto view = raw->widget()) {
+ view->setGeometry(geometry.marginsRemoved({ 0, 0, 0, footer }));
}
}, _webview->lifetime);
diff --git a/Telegram/SourceFiles/payments/ui/payments_panel.h b/Telegram/SourceFiles/payments/ui/payments_panel.h
index b65def0156..6c64c661f8 100644
--- a/Telegram/SourceFiles/payments/ui/payments_panel.h
+++ b/Telegram/SourceFiles/payments/ui/payments_panel.h
@@ -115,11 +115,13 @@ private:
[[nodiscard]] bool progressWithBackground() const;
[[nodiscard]] QRect progressRect() const;
void setupProgressGeometry();
+ void updateFooterHeight();
const not_null _delegate;
std::unique_ptr _widget;
std::unique_ptr _webview;
std::unique_ptr _webviewBottom;
+ rpl::variable _footerHeight;
std::unique_ptr