Merge tag 'v5.0.2' into dev

# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/lib_ui
#	snap/snapcraft.yaml
This commit is contained in:
AlexeyZavar 2024-05-25 02:25:40 +03:00
commit 57b2c69ce6
104 changed files with 1362 additions and 367 deletions

6
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View file

@ -20,7 +20,7 @@ jobs:
steps: steps:
- name: Clone. - name: Clone.
uses: actions/checkout@v3.1.0 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
@ -31,7 +31,7 @@ jobs:
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: Free up some disk space. - name: Free up some disk space.
uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8 uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
- name: Docker image build. - name: Docker image build.
run: | run: |

View file

@ -58,7 +58,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone. - name: Clone.
uses: actions/checkout@v3.1.0 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
path: ${{ env.REPO_NAME }} path: ${{ env.REPO_NAME }}
@ -116,7 +116,7 @@ jobs:
cd $REPO_NAME/out/Debug cd $REPO_NAME/out/Debug
sudo mkdir artifact sudo mkdir artifact
sudo mv {Telegram,Updater} artifact/ sudo mv {Telegram,Updater} artifact/
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true' if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact. name: Upload artifact.
with: with:

View file

@ -8,7 +8,7 @@ jobs:
lock: lock:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: dessant/lock-threads@v3 - uses: dessant/lock-threads@v5
with: with:
github-token: ${{ github.token }} github-token: ${{ github.token }}
issue-inactive-days: 45 issue-inactive-days: 45

View file

@ -56,7 +56,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone. - name: Clone.
uses: actions/checkout@v3.1.0 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
path: ${{ env.REPO_NAME }} path: ${{ env.REPO_NAME }}
@ -76,7 +76,7 @@ jobs:
- name: ThirdParty cache. - name: ThirdParty cache.
id: cache-third-party id: cache-third-party
uses: actions/cache@v3.0.11 uses: actions/cache@v4
with: with:
path: ThirdParty path: ThirdParty
key: ${{ runner.OS }}-third-party-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }} key: ${{ runner.OS }}-third-party-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }}
@ -84,7 +84,7 @@ jobs:
- name: Libraries cache. - name: Libraries cache.
id: cache-libs id: cache-libs
uses: actions/cache@v3.0.11 uses: actions/cache@v4
with: with:
path: Libraries path: Libraries
key: ${{ runner.OS }}-libs-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }} key: ${{ runner.OS }}-libs-${{ hashFiles(format('{0}/{1}', env.REPO_NAME, env.PREPARE_PATH)) }}
@ -134,7 +134,7 @@ jobs:
mkdir artifact mkdir artifact
mv Telegram.app artifact/ mv Telegram.app artifact/
mv Updater artifact/ mv Updater artifact/
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true' if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact. name: Upload artifact.
with: with:

View file

@ -60,7 +60,7 @@ jobs:
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
- name: Clone. - name: Clone.
uses: actions/checkout@v3.1.0 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
path: ${{ env.REPO_NAME }} path: ${{ env.REPO_NAME }}
@ -99,7 +99,7 @@ jobs:
- name: WebRTC cache. - name: WebRTC cache.
id: cache-webrtc id: cache-webrtc
uses: actions/cache@v3.0.11 uses: actions/cache@v4
with: with:
path: ${{ env.LibrariesPath }}/tg_owt path: ${{ env.LibrariesPath }}/tg_owt
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }} key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }}
@ -153,7 +153,7 @@ jobs:
cd $REPO_NAME/build cd $REPO_NAME/build
mkdir artifact mkdir artifact
mv Telegram.dmg artifact/ mv Telegram.dmg artifact/
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true' if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact. name: Upload artifact.
with: with:

View file

@ -11,7 +11,7 @@ jobs:
SKIP: "0" SKIP: "0"
to_branch: "master" to_branch: "master"
steps: steps:
- uses: actions/checkout@v4.1.0 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
if: env.SKIP == '0' if: env.SKIP == '0'

View file

@ -47,7 +47,7 @@ jobs:
steps: steps:
- name: Clone. - name: Clone.
uses: actions/checkout@v3.1.0 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: recursive submodules: recursive
@ -61,7 +61,7 @@ jobs:
sudo snap run lxd waitready sudo snap run lxd waitready
- name: Free up some disk space. - name: Free up some disk space.
uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8 uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
- name: Telegram Desktop snap build. - name: Telegram Desktop snap build.
run: sg lxd -c 'snap run snapcraft --verbosity=debug' run: sg lxd -c 'snap run snapcraft --verbosity=debug'
@ -75,7 +75,7 @@ jobs:
mkdir artifact mkdir artifact
mv $artifact_name artifact mv $artifact_name artifact
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@v4
if: env.UPLOAD_ARTIFACT == 'true' if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact. name: Upload artifact.
with: with:

View file

@ -7,7 +7,7 @@ jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v5 - uses: actions/stale@v9
with: with:
stale-issue-message: | stale-issue-message: |
Hey there! Hey there!

View file

@ -69,13 +69,13 @@ jobs:
shell: bash shell: bash
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV 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. name: Native Tools Command Prompt.
with: with:
arch: ${{ matrix.arch }} arch: ${{ matrix.arch }}
- name: Clone. - name: Clone.
uses: actions/checkout@v3.1.0 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
path: ${{ env.TBUILD }}\${{ env.REPO_NAME }} path: ${{ env.TBUILD }}\${{ env.REPO_NAME }}
@ -96,7 +96,7 @@ jobs:
- name: Libraries cache. - name: Libraries cache.
id: cache-libs id: cache-libs
uses: actions/cache@v3.0.11 uses: actions/cache@v4
with: with:
path: ${{ env.TBUILD }}\Libraries path: ${{ env.TBUILD }}\Libraries
key: ${{ runner.OS }}-${{ matrix.arch }}-libs-${{ env.CACHE_KEY }} key: ${{ runner.OS }}-${{ matrix.arch }}-libs-${{ env.CACHE_KEY }}
@ -183,7 +183,7 @@ jobs:
mkdir artifact mkdir artifact
move %OUT%\Telegram.exe artifact/ move %OUT%\Telegram.exe artifact/
move %OUT%\Updater.exe artifact/ move %OUT%\Updater.exe artifact/
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@v4
name: Upload artifact. name: Upload artifact.
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly') if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
with: with:

1
.gitignore vendored
View file

@ -18,6 +18,7 @@ Release/
*.xcodeproj *.xcodeproj
ipch/ ipch/
.vs/ .vs/
.vscode/
/Telegram/log.txt /Telegram/log.txt
/Telegram/data /Telegram/data

View file

@ -757,6 +757,8 @@ PRIVATE
history/view/controls/compose_controls_common.h history/view/controls/compose_controls_common.h
history/view/controls/history_view_compose_controls.cpp history/view/controls/history_view_compose_controls.cpp
history/view/controls/history_view_compose_controls.h 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.cpp
history/view/controls/history_view_compose_search.h history/view/controls/history_view_compose_search.h
history/view/controls/history_view_draft_options.cpp history/view/controls/history_view_draft_options.cpp

View file

@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop" <Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE" ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A" Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="5.0.1.0" /> Version="5.0.2.0" />
<Properties> <Properties>
<DisplayName>Telegram Desktop</DisplayName> <DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName> <PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>

View file

@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,0,1,0 FILEVERSION 5,0,2,0
PRODUCTVERSION 5,0,1,0 PRODUCTVERSION 5,0,2,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -62,10 +62,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Radolyn Labs" VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop" VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "5.0.1.0" VALUE "FileVersion", "5.0.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop" VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "5.0.1.0" VALUE "ProductVersion", "5.0.2.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,0,1,0 FILEVERSION 5,0,2,0
PRODUCTVERSION 5,0,1,0 PRODUCTVERSION 5,0,2,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -53,10 +53,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Radolyn Labs" VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater" VALUE "FileDescription", "AyuGram Desktop Updater"
VALUE "FileVersion", "5.0.1.0" VALUE "FileVersion", "5.0.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop" VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "5.0.1.0" VALUE "ProductVersion", "5.0.2.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "data/business/data_shortcut_messages.h" #include "data/business/data_shortcut_messages.h"
#include "data/components/scheduled_messages.h" #include "data/components/scheduled_messages.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h" #include "data/data_histories.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_web_page.h" #include "data/data_web_page.h"
@ -252,12 +253,100 @@ mtpRequestId EditTextMessage(
Data::WebPageDraft webpage, Data::WebPageDraft webpage,
SendOptions options, SendOptions options,
Fn<void(mtpRequestId requestId)> done, Fn<void(mtpRequestId requestId)> done,
Fn<void(const QString &, mtpRequestId requestId)> fail) { Fn<void(const QString &error, mtpRequestId requestId)> fail,
std::optional<bool> spoilerMediaOverride) {
if (spoilerMediaOverride) {
const auto spoiler = *spoilerMediaOverride;
if (const auto media = item->media()) {
auto takeInputMedia = Fn<std::optional<MTPInputMedia>()>(nullptr);
auto takeFileReference = Fn<QByteArray()>(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<void()> 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<void()> applyUpdates, mtpRequestId id) { const auto callback = [=](Fn<void()> applyUpdates, mtpRequestId id) {
applyUpdates(); applyUpdates();
done(id); done(id);
}; };
return EditMessage(item, caption, webpage, options, callback, fail); return EditMessage(
item,
caption,
webpage,
options,
callback,
fail,
std::nullopt);
} }
} // namespace Api } // namespace Api

View file

@ -55,6 +55,7 @@ mtpRequestId EditTextMessage(
Data::WebPageDraft webpage, Data::WebPageDraft webpage,
SendOptions options, SendOptions options,
Fn<void(mtpRequestId requestId)> done, Fn<void(mtpRequestId requestId)> done,
Fn<void(const QString &error, mtpRequestId requestId)> fail); Fn<void(const QString &error, mtpRequestId requestId)> fail,
std::optional<bool> spoilerMediaOverride);
} // namespace Api } // namespace Api

View file

@ -7,12 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "api/api_text_entities.h" #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_custom_emoji.h"
#include "data/stickers/data_stickers_set.h" #include "data/stickers/data_stickers_set.h"
#include "data/data_session.h" #include "main/main_session.h"
#include "data/data_document.h"
#include "data/data_user.h"
namespace Api { namespace Api {
namespace { namespace {
@ -62,67 +62,163 @@ using namespace TextUtilities;
EntitiesInText EntitiesFromMTP( EntitiesInText EntitiesFromMTP(
Main::Session *session, Main::Session *session,
const QVector<MTPMessageEntity> &entities) { const QVector<MTPMessageEntity> &entities) {
if (entities.isEmpty()) {
return {};
}
auto result = EntitiesInText(); auto result = EntitiesInText();
if (!entities.isEmpty()) { result.reserve(entities.size());
result.reserve(entities.size());
for (const auto &entity : entities) { for (const auto &entity : entities) {
switch (entity.type()) { entity.match([&](const MTPDmessageEntityUnknown &d) {
case mtpc_messageEntityUrl: { auto &d = entity.c_messageEntityUrl(); result.push_back({ EntityType::Url, d.voffset().v, d.vlength().v }); } break; }, [&](const MTPDmessageEntityMention &d) {
case mtpc_messageEntityTextUrl: { auto &d = entity.c_messageEntityTextUrl(); result.push_back({ EntityType::CustomUrl, d.voffset().v, d.vlength().v, qs(d.vurl()) }); } break; result.push_back({
case mtpc_messageEntityEmail: { auto &d = entity.c_messageEntityEmail(); result.push_back({ EntityType::Email, d.voffset().v, d.vlength().v }); } break; EntityType::Mention,
case mtpc_messageEntityHashtag: { auto &d = entity.c_messageEntityHashtag(); result.push_back({ EntityType::Hashtag, d.voffset().v, d.vlength().v }); } break; d.voffset().v,
case mtpc_messageEntityCashtag: { auto &d = entity.c_messageEntityCashtag(); result.push_back({ EntityType::Cashtag, d.voffset().v, d.vlength().v }); } break; d.vlength().v,
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; }, [&](const MTPDmessageEntityHashtag &d) {
case mtpc_messageEntityMentionName: if (session) { result.push_back({
const auto &d = entity.c_messageEntityMentionName(); EntityType::Hashtag,
const auto userId = UserId(d.vuser_id()); d.voffset().v,
const auto user = session->data().userLoaded(userId); d.vlength().v,
const auto data = MentionNameDataFromFields({ });
.selfId = session->userId().bare, }, [&](const MTPDmessageEntityBotCommand &d) {
.userId = userId.bare, result.push_back({
.accessHash = user ? user->accessHash() : 0, EntityType::BotCommand,
}); d.voffset().v,
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data }); d.vlength().v,
} break; });
case mtpc_inputMessageEntityMentionName: if (session) { }, [&](const MTPDmessageEntityUrl &d) {
const auto &d = entity.c_inputMessageEntityMentionName(); result.push_back({
const auto data = d.vuser_id().match([&]( EntityType::Url,
const MTPDinputUserSelf &) { d.voffset().v,
return MentionNameDataFromFields({ d.vlength().v,
.selfId = session->userId().bare, });
.userId = session->userId().bare, }, [&](const MTPDmessageEntityEmail &d) {
.accessHash = session->user()->accessHash(), result.push_back({
}); EntityType::Email,
}, [&](const MTPDinputUser &data) { d.voffset().v,
return MentionNameDataFromFields({ d.vlength().v,
.selfId = session->userId().bare, });
.userId = UserId(data.vuser_id()).bare, }, [&](const MTPDmessageEntityBold &d) {
.accessHash = data.vaccess_hash().v, result.push_back({
}); EntityType::Bold,
}, [&](const auto &) { d.voffset().v,
return QString(); d.vlength().v,
}); });
if (!data.isEmpty()) { }, [&](const MTPDmessageEntityItalic &d) {
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data }); result.push_back({
} EntityType::Italic,
} break; d.voffset().v,
case mtpc_messageEntityBotCommand: { auto &d = entity.c_messageEntityBotCommand(); result.push_back({ EntityType::BotCommand, d.voffset().v, d.vlength().v }); } break; d.vlength().v,
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; }, [&](const MTPDmessageEntityCode &d) {
case mtpc_messageEntityUnderline: { auto &d = entity.c_messageEntityUnderline(); result.push_back({ EntityType::Underline, d.voffset().v, d.vlength().v }); } break; result.push_back({
case mtpc_messageEntityStrike: { auto &d = entity.c_messageEntityStrike(); result.push_back({ EntityType::StrikeOut, d.voffset().v, d.vlength().v }); } break; EntityType::Code,
case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset().v, d.vlength().v }); } break; d.voffset().v,
case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset().v, d.vlength().v, qs(d.vlanguage()) }); } break; d.vlength().v,
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 }, [&](const MTPDmessageEntityPre &d) {
case mtpc_messageEntitySpoiler: { auto &d = entity.c_messageEntitySpoiler(); result.push_back({ EntityType::Spoiler, d.voffset().v, d.vlength().v }); } break; result.push_back({
case mtpc_messageEntityCustomEmoji: { EntityType::Pre,
const auto &d = entity.c_messageEntityCustomEmoji(); d.voffset().v,
result.push_back({ EntityType::CustomEmoji, d.voffset().v, d.vlength().v, CustomEmojiEntityData(d) }); d.vlength().v,
} break; 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; return result;
} }
@ -134,7 +230,9 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
auto v = QVector<MTPMessageEntity>(); auto v = QVector<MTPMessageEntity>();
v.reserve(entities.size()); v.reserve(entities.size());
for (const auto &entity : entities) { for (const auto &entity : entities) {
if (entity.length() <= 0) continue; if (entity.length() <= 0) {
continue;
}
if (option == ConvertOption::SkipLocal if (option == ConvertOption::SkipLocal
&& entity.type() != EntityType::Bold && entity.type() != EntityType::Bold
//&& entity.type() != EntityType::Semibold // Not in API. //&& entity.type() != EntityType::Semibold // Not in API.
@ -154,28 +252,76 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
auto offset = MTP_int(entity.offset()); auto offset = MTP_int(entity.offset());
auto length = MTP_int(entity.length()); auto length = MTP_int(entity.length());
switch (entity.type()) { switch (entity.type()) {
case EntityType::Url: v.push_back(MTP_messageEntityUrl(offset, length)); break; case EntityType::Url: {
case EntityType::CustomUrl: v.push_back(MTP_messageEntityTextUrl(offset, length, MTP_string(entity.data()))); break; v.push_back(MTP_messageEntityUrl(offset, length));
case EntityType::Email: v.push_back(MTP_messageEntityEmail(offset, length)); break; } break;
case EntityType::Hashtag: v.push_back(MTP_messageEntityHashtag(offset, length)); break; case EntityType::CustomUrl: {
case EntityType::Cashtag: v.push_back(MTP_messageEntityCashtag(offset, length)); break; v.push_back(
case EntityType::Mention: v.push_back(MTP_messageEntityMention(offset, length)); break; 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: { 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); v.push_back(*valid);
} }
} break; } break;
case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break; case EntityType::BotCommand: {
case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break; v.push_back(MTP_messageEntityBotCommand(offset, length));
case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break; } break;
case EntityType::Underline: v.push_back(MTP_messageEntityUnderline(offset, length)); break; case EntityType::Bold: {
case EntityType::StrikeOut: v.push_back(MTP_messageEntityStrike(offset, length)); break; v.push_back(MTP_messageEntityBold(offset, length));
case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities } break;
case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break; case EntityType::Italic: {
case EntityType::Blockquote: v.push_back(MTP_messageEntityBlockquote(offset, length)); break; v.push_back(MTP_messageEntityItalic(offset, length));
case EntityType::Spoiler: v.push_back(MTP_messageEntitySpoiler(offset, length)); break; } 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: { 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); v.push_back(*valid);
} }
} break; } break;

View file

@ -206,6 +206,9 @@ void EditPhotoImage(
Storage::UpdateImageDetails(file, previewWidth, sideLimit); Storage::UpdateImageDetails(file, previewWidth, sideLimit);
done(std::move(list)); done(std::move(list));
}; };
if (!large) {
return;
}
const auto fileImage = std::make_shared<Image>(*large); const auto fileImage = std::make_shared<Image>(*large);
auto editor = base::make_unique_q<Editor::PhotoEditor>( auto editor = base::make_unique_q<Editor::PhotoEditor>(
parent, parent,

View file

@ -2125,6 +2125,16 @@ bool PeerListContent::submitted() {
return false; 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( void PeerListContent::visibleTopBottomUpdated(
int visibleTop, int visibleTop,
int visibleBottom) { int visibleBottom) {

View file

@ -625,6 +625,9 @@ public:
void searchQueryChanged(QString query); void searchQueryChanged(QString query);
bool submitted(); bool submitted();
PeerListRowId updateFromParentDrag(QPoint globalPosition);
void dragLeft();
// Interface for the controller. // Interface for the controller.
void appendRow(std::unique_ptr<PeerListRow> row); void appendRow(std::unique_ptr<PeerListRow> row);
void appendSearchRow(std::unique_ptr<PeerListRow> row); void appendSearchRow(std::unique_ptr<PeerListRow> row);

View file

@ -1428,14 +1428,15 @@ void SetupPeerColorSample(
void AddPeerColorButton( void AddPeerColorButton(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
not_null<PeerData*> peer) { not_null<PeerData*> peer,
const style::SettingsButton &st) {
auto label = peer->isSelf() auto label = peer->isSelf()
? tr::lng_settings_theme_name_color() ? tr::lng_settings_theme_name_color()
: tr::lng_edit_channel_color(); : tr::lng_edit_channel_color();
const auto button = AddButtonWithIcon( const auto button = AddButtonWithIcon(
container, container,
rpl::duplicate(label), rpl::duplicate(label),
st::settingsColorButton, st,
{ &st::menuIconChangeColors }); { &st::menuIconChangeColors });
const auto style = std::make_shared<Ui::ChatStyle>( const auto style = std::make_shared<Ui::ChatStyle>(

View file

@ -48,7 +48,8 @@ void EditPeerColorBox(
void AddPeerColorButton( void AddPeerColorButton(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
not_null<PeerData*> peer); not_null<PeerData*> peer,
const style::SettingsButton &st);
void CheckBoostLevel( void CheckBoostLevel(
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,

View file

@ -1016,7 +1016,11 @@ void Controller::fillColorIndexButton() {
Expects(_controls.buttonsLayout != nullptr); Expects(_controls.buttonsLayout != nullptr);
const auto show = _navigation->uiShow(); const auto show = _navigation->uiShow();
AddPeerColorButton(_controls.buttonsLayout, show, _peer); AddPeerColorButton(
_controls.buttonsLayout,
_navigation->uiShow(),
_peer,
st::managePeerColorsButton);
} }
void Controller::fillSignaturesButton() { void Controller::fillSignaturesButton() {

View file

@ -331,6 +331,7 @@ void Panel::Incoming::RendererGL::paint(
shadow.texture.left(), shadow.texture.top(), shadow.texture.left(), shadow.texture.top(),
}; };
_contentBuffer->bind();
_contentBuffer->write(0, coords, sizeof(coords)); _contentBuffer->write(0, coords, sizeof(coords));
const auto bottomShadowArea = QRect( const auto bottomShadowArea = QRect(

View file

@ -783,6 +783,7 @@ void Viewport::RendererGL::paintTile(
: &*_frameProgram.yuv420; : &*_frameProgram.yuv420;
const auto uniformViewport = QSizeF(_viewport) * _factor; const auto uniformViewport = QSizeF(_viewport) * _factor;
program->bind();
program->setUniformValue("viewport", uniformViewport); program->setUniformValue("viewport", uniformViewport);
program->setUniformValue( program->setUniformValue(
"frameBg", "frameBg",
@ -1078,6 +1079,7 @@ void Viewport::RendererGL::drawDownscalePass(
? &*_downscaleProgram.argb32 ? &*_downscaleProgram.argb32
: &*_downscaleProgram.yuv420; : &*_downscaleProgram.yuv420;
program->bind();
FillTexturedRectangle(f, program); FillTexturedRectangle(f, program);
} }

View file

@ -785,6 +785,12 @@ emojiScroll: ScrollArea(defaultSolidScroll) {
reactPanelScroll: ScrollArea(emojiScroll) { reactPanelScroll: ScrollArea(emojiScroll) {
deltab: 7px; deltab: 7px;
} }
reactPanelScrollRounded: ScrollArea(emojiScroll) {
width: 8px;
deltax: 3px;
deltat: 14px;
deltab: 14px;
}
choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }}; choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }};
choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }}; choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }};
@ -983,7 +989,7 @@ historyComposeField: InputField(defaultInputField) {
placeholderFg: placeholderFg; placeholderFg: placeholderFg;
placeholderFgActive: placeholderFgActive; placeholderFgActive: placeholderFgActive;
placeholderFgError: placeholderFgActive; placeholderFgError: placeholderFgActive;
placeholderMargins: margins(7px, 5px, 7px, 5px); placeholderMargins: margins(2px, 0px, 2px, 0px);
placeholderAlign: align(topleft); placeholderAlign: align(topleft);
placeholderScale: 0.; placeholderScale: 0.;
placeholderFont: normalFont; placeholderFont: normalFont;

View file

@ -1134,9 +1134,7 @@ void EmojiListWidget::fillRecentMenu(
not_null<Ui::PopupMenu*> menu, not_null<Ui::PopupMenu*> menu,
int section, int section,
int index) { int index) {
if (section != int(Section::Recent)) { const auto recent = (section == int(Section::Recent));
return;
}
const auto addAction = Ui::Menu::CreateAddActionCallback(menu); const auto addAction = Ui::Menu::CreateAddActionCallback(menu);
const auto over = OverEmoji{ section, index }; const auto over = OverEmoji{ section, index };
const auto emoji = lookupOverEmoji(&over); const auto emoji = lookupOverEmoji(&over);
@ -1157,18 +1155,21 @@ void EmojiListWidget::fillRecentMenu(
TextUtilities::SetClipboardText(data); TextUtilities::SetClipboardText(data);
}, &st::menuIconCopy); }, &st::menuIconCopy);
} }
if (setId && _features.openStickerSets) { if (recent && setId && _features.openStickerSets) {
addAction( addAction(
tr::lng_emoji_view_pack(tr::now), tr::lng_emoji_view_pack(tr::now),
crl::guard(this, [=] { displaySet(setId); }), crl::guard(this, [=] { displaySet(setId); }),
&st::menuIconShowAll); &st::menuIconShowAll);
} }
} else if (emoji) { } else if (recent && emoji) {
addAction(tr::lng_emoji_copy(tr::now), [=] { addAction(tr::lng_emoji_copy(tr::now), [=] {
const auto text = emoji->text(); const auto text = emoji->text();
TextUtilities::SetClipboardText({ text, { text } }); TextUtilities::SetClipboardText({ text, { text } });
}, &st::menuIconCopy); }, &st::menuIconCopy);
} }
if (!recent) {
return;
}
auto id = RecentEmojiId{ emoji }; auto id = RecentEmojiId{ emoji };
if (custom) { if (custom) {
id.data = RecentEmojiDocument{ id.data = RecentEmojiDocument{
@ -1194,7 +1195,7 @@ void EmojiListWidget::fillRecentMenu(
.confirmed = crl::guard(this, sure), .confirmed = crl::guard(this, sure),
.confirmText = tr::lng_emoji_reset_recent_button(tr::now), .confirmText = tr::lng_emoji_reset_recent_button(tr::now),
.labelStyle = &st().boxLabel, .labelStyle = &st().boxLabel,
})); }));
}; };
addAction({ addAction({
.text = tr::lng_emoji_reset_recent(tr::now), .text = tr::lng_emoji_reset_recent(tr::now),

View file

@ -509,7 +509,7 @@ TabbedSelector::TabbedSelector(
_st.categoriesBg); _st.categoriesBg);
}, lifetime()); }, lifetime());
if (hasEmojiTab()) { if (hasEmojiTab() && _mode == Mode::Full) {
session().data().stickers().emojiSetInstalled( session().data().stickers().emojiSetInstalled(
) | rpl::start_with_next([=](uint64 setId) { ) | rpl::start_with_next([=](uint64 setId) {
_tabsSlider->setActiveSection(indexByType(SelectorTab::Emoji)); _tabsSlider->setActiveSection(indexByType(SelectorTab::Emoji));

View file

@ -127,7 +127,8 @@ Settings::Settings()
: _sendSubmitWay(Ui::InputSubmitSettings::Enter) : _sendSubmitWay(Ui::InputSubmitSettings::Enter)
, _floatPlayerColumn(Window::Column::Second) , _floatPlayerColumn(Window::Column::Second)
, _floatPlayerCorner(RectPart::TopRight) , _floatPlayerCorner(RectPart::TopRight)
, _dialogsWidthRatio(DefaultDialogsWidthRatio()) { , _dialogsWithChatWidthRatio(DefaultDialogsWidthRatio())
, _dialogsNoChatWidthRatio(DefaultDialogsWidthRatio()) {
} }
Settings::~Settings() = default; Settings::~Settings() = default;
@ -222,7 +223,8 @@ QByteArray Settings::serialize() const {
+ Serialize::stringSize(_callCaptureDeviceId.current()) + Serialize::stringSize(_callCaptureDeviceId.current())
+ Serialize::bytearraySize(ivPosition) + Serialize::bytearraySize(ivPosition)
+ Serialize::stringSize(noWarningExtensions) + Serialize::stringSize(noWarningExtensions)
+ Serialize::stringSize(_customFontFamily); + Serialize::stringSize(_customFontFamily)
+ sizeof(qint32);
auto result = QByteArray(); auto result = QByteArray();
result.reserve(size); result.reserve(size);
@ -284,7 +286,7 @@ QByteArray Settings::serialize() const {
<< qint32(_floatPlayerCorner) << qint32(_floatPlayerCorner)
<< qint32(_thirdSectionInfoEnabled ? 1 : 0) << qint32(_thirdSectionInfoEnabled ? 1 : 0)
<< qint32(std::clamp( << qint32(std::clamp(
qRound(_dialogsWidthRatio.current() * 1000000), qRound(_dialogsWithChatWidthRatio.current() * 1000000),
0, 0,
1000000)) 1000000))
<< qint32(_thirdColumnWidth.current()) << qint32(_thirdColumnWidth.current())
@ -369,7 +371,11 @@ QByteArray Settings::serialize() const {
<< _callCaptureDeviceId.current() << _callCaptureDeviceId.current()
<< ivPosition << ivPosition
<< noWarningExtensions << noWarningExtensions
<< _customFontFamily; << _customFontFamily
<< qint32(std::clamp(
qRound(_dialogsNoChatWidthRatio.current() * 1000000),
0,
1000000));
} }
Ensures(result.size() == size); Ensures(result.size() == size);
@ -440,7 +446,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 floatPlayerColumn = static_cast<qint32>(Window::Column::Second); qint32 floatPlayerColumn = static_cast<qint32>(Window::Column::Second);
qint32 floatPlayerCorner = static_cast<qint32>(RectPart::TopRight); qint32 floatPlayerCorner = static_cast<qint32>(RectPart::TopRight);
qint32 thirdSectionInfoEnabled = 0; qint32 thirdSectionInfoEnabled = 0;
float64 dialogsWidthRatio = _dialogsWidthRatio.current(); float64 dialogsWithChatWidthRatio = _dialogsWithChatWidthRatio.current();
float64 dialogsNoChatWidthRatio = _dialogsNoChatWidthRatio.current();
qint32 thirdColumnWidth = _thirdColumnWidth.current(); qint32 thirdColumnWidth = _thirdColumnWidth.current();
qint32 thirdSectionExtendedBy = _thirdSectionExtendedBy; qint32 thirdSectionExtendedBy = _thirdSectionExtendedBy;
qint32 notifyFromAll = _notifyFromAll ? 1 : 0; qint32 notifyFromAll = _notifyFromAll ? 1 : 0;
@ -552,18 +559,18 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
>> mainMenuAccountsShown; >> mainMenuAccountsShown;
} }
if (!stream.atEnd()) { if (!stream.atEnd()) {
auto dialogsWidthRatioInt = qint32(); auto dialogsWithChatWidthRatioInt = qint32();
stream stream
>> tabbedSelectorSectionEnabled >> tabbedSelectorSectionEnabled
>> floatPlayerColumn >> floatPlayerColumn
>> floatPlayerCorner >> floatPlayerCorner
>> thirdSectionInfoEnabled >> thirdSectionInfoEnabled
>> dialogsWidthRatioInt >> dialogsWithChatWidthRatioInt
>> thirdColumnWidth >> thirdColumnWidth
>> thirdSectionExtendedBy >> thirdSectionExtendedBy
>> notifyFromAll; >> notifyFromAll;
dialogsWidthRatio = std::clamp( dialogsWithChatWidthRatio = std::clamp(
dialogsWidthRatioInt / 1000000., dialogsWithChatWidthRatioInt / 1000000.,
0., 0.,
1.); 1.);
} }
@ -778,6 +785,15 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) { if (!stream.atEnd()) {
stream >> customFontFamily; stream >> customFontFamily;
} }
if (!stream.atEnd()) {
auto dialogsNoChatWidthRatioInt = qint32();
stream
>> dialogsNoChatWidthRatioInt;
dialogsNoChatWidthRatio = std::clamp(
dialogsNoChatWidthRatioInt / 1000000.,
0.,
1.);
}
if (stream.status() != QDataStream::Ok) { if (stream.status() != QDataStream::Ok) {
LOG(("App Error: " LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()")); "Bad data for Core::Settings::constructFromSerialized()"));
@ -879,7 +895,10 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
case RectPart::BottomRight: _floatPlayerCorner = uncheckedCorner; break; case RectPart::BottomRight: _floatPlayerCorner = uncheckedCorner; break;
} }
_thirdSectionInfoEnabled = thirdSectionInfoEnabled; _thirdSectionInfoEnabled = thirdSectionInfoEnabled;
_dialogsWidthRatio = dialogsWidthRatio; _dialogsWithChatWidthRatio = dialogsWithChatWidthRatio;
_dialogsNoChatWidthRatio = (dialogsWithChatWidthRatio > 0)
? dialogsWithChatWidthRatio
: dialogsNoChatWidthRatio;
_thirdColumnWidth = thirdColumnWidth; _thirdColumnWidth = thirdColumnWidth;
_thirdSectionExtendedBy = thirdSectionExtendedBy; _thirdSectionExtendedBy = thirdSectionExtendedBy;
if (_thirdSectionInfoEnabled) { if (_thirdSectionInfoEnabled) {
@ -1032,16 +1051,46 @@ void Settings::setTabbedReplacedWithInfo(bool enabled) {
} }
} }
void Settings::setDialogsWidthRatio(float64 ratio) { void Settings::updateDialogsWidthRatio(float64 ratio, bool nochat) {
_dialogsWidthRatio = ratio; 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 { float64 Settings::dialogsWidthRatio(bool nochat) const {
return _dialogsWidthRatio.current(); const auto withchat = dialogsWithChatWidthRatio();
return (!nochat || withchat > 0) ? withchat : dialogsNoChatWidthRatio();
} }
rpl::producer<float64> Settings::dialogsWidthRatioChanges() const { float64 Settings::dialogsWithChatWidthRatio() const {
return _dialogsWidthRatio.changes(); return _dialogsWithChatWidthRatio.current();
}
rpl::producer<float64> Settings::dialogsWithChatWidthRatioChanges() const {
return _dialogsWithChatWidthRatio.changes();
}
float64 Settings::dialogsNoChatWidthRatio() const {
return _dialogsNoChatWidthRatio.current();
}
rpl::producer<float64> Settings::dialogsNoChatWidthRatioChanges() const {
return _dialogsNoChatWidthRatio.changes();
} }
void Settings::setThirdColumnWidth(int width) { void Settings::setThirdColumnWidth(int width) {
@ -1333,7 +1382,8 @@ void Settings::resetOnLastLogout() {
_floatPlayerCorner = RectPart::TopRight; // per-window _floatPlayerCorner = RectPart::TopRight; // per-window
_thirdSectionInfoEnabled = true; // per-window _thirdSectionInfoEnabled = true; // per-window
_thirdSectionExtendedBy = -1; // per-window _thirdSectionExtendedBy = -1; // per-window
_dialogsWidthRatio = DefaultDialogsWidthRatio(); // per-window _dialogsWithChatWidthRatio = DefaultDialogsWidthRatio(); // per-window
_dialogsNoChatWidthRatio = DefaultDialogsWidthRatio(); // per-window
_thirdColumnWidth = kDefaultThirdColumnWidth; // p-w _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w
_notifyFromAll = true; _notifyFromAll = true;
_tabbedReplacedWithInfo = false; // per-window _tabbedReplacedWithInfo = false; // per-window

View file

@ -620,9 +620,15 @@ public:
[[nodiscard]] RectPart floatPlayerCorner() const { [[nodiscard]] RectPart floatPlayerCorner() const {
return _floatPlayerCorner; return _floatPlayerCorner;
} }
void setDialogsWidthRatio(float64 ratio);
[[nodiscard]] float64 dialogsWidthRatio() const; void updateDialogsWidthRatio(float64 ratio, bool nochat);
[[nodiscard]] rpl::producer<float64> dialogsWidthRatioChanges() const; [[nodiscard]] float64 dialogsWidthRatio(bool nochat) const;
[[nodiscard]] float64 dialogsWithChatWidthRatio() const;
[[nodiscard]] rpl::producer<float64> dialogsWithChatWidthRatioChanges() const;
[[nodiscard]] float64 dialogsNoChatWidthRatio() const;
[[nodiscard]] rpl::producer<float64> dialogsNoChatWidthRatioChanges() const;
void setThirdColumnWidth(int width); void setThirdColumnWidth(int width);
[[nodiscard]] int thirdColumnWidth() const; [[nodiscard]] int thirdColumnWidth() const;
[[nodiscard]] rpl::producer<int> thirdColumnWidthChanges() const; [[nodiscard]] rpl::producer<int> thirdColumnWidthChanges() const;
@ -975,7 +981,8 @@ private:
bool _thirdSectionInfoEnabled = true; // per-window bool _thirdSectionInfoEnabled = true; // per-window
rpl::event_stream<bool> _thirdSectionInfoEnabledValue; // per-window rpl::event_stream<bool> _thirdSectionInfoEnabledValue; // per-window
int _thirdSectionExtendedBy = -1; // per-window int _thirdSectionExtendedBy = -1; // per-window
rpl::variable<float64> _dialogsWidthRatio; // per-window rpl::variable<float64> _dialogsWithChatWidthRatio; // per-window
rpl::variable<float64> _dialogsNoChatWidthRatio; // per-window
rpl::variable<int> _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w rpl::variable<int> _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w
bool _notifyFromAll = true; bool _notifyFromAll = true;
rpl::variable<bool> _nativeWindowFrame = false; rpl::variable<bool> _nativeWindowFrame = false;
@ -1021,6 +1028,7 @@ private:
float64 _rememberedSongVolume = kDefaultVolume; float64 _rememberedSongVolume = kDefaultVolume;
bool _rememberedSoundNotifyFromTray = false; bool _rememberedSoundNotifyFromTray = false;
bool _rememberedFlashBounceNotifyFromTray = false; bool _rememberedFlashBounceNotifyFromTray = false;
bool _dialogsWidthSetToZeroWithoutChat = false;
QByteArray _photoEditorBrush; QByteArray _photoEditorBrush;

View file

@ -255,7 +255,10 @@ void Sandbox::setupScreenScale() {
Sandbox::~Sandbox() = default; Sandbox::~Sandbox() = default;
bool Sandbox::event(QEvent *e) { 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); Quit(QuitReason::QtQuitEvent);
e->ignore(); e->ignore();
return false; return false;

View file

@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
constexpr auto AppNameOld = "AyuGram for Windows"_cs; constexpr auto AppNameOld = "AyuGram for Windows"_cs;
constexpr auto AppName = "AyuGram Desktop"_cs; constexpr auto AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs; constexpr auto AppFile = "AyuGram"_cs;
constexpr auto AppVersion = 5000001; constexpr auto AppVersion = 5000002;
constexpr auto AppVersionStr = "5.0.1"; constexpr auto AppVersionStr = "5.0.2";
constexpr auto AppBetaVersion = false; constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View file

@ -449,6 +449,22 @@ auto SponsoredMessages::createReportCallback(const FullMsgId &fullId)
return; 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( state->requestId = _session->api().request(
MTPchannels_ReportSponsoredMessage( MTPchannels_ReportSponsoredMessage(
channel->inputChannel, channel->inputChannel,
@ -475,14 +491,7 @@ auto SponsoredMessages::createReportCallback(const FullMsgId &fullId)
}, [](const TLAdsHidden &data) -> Result { }, [](const TLAdsHidden &data) -> Result {
return { .result = Result::FinalStep::Hidden }; return { .result = Result::FinalStep::Hidden };
}, [&](const TLReported &data) -> Result { }, [&](const TLReported &data) -> Result {
const auto it = _data.find(history); erase();
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")) { // I don't like it. if (optionId == Result::Id("1")) { // I don't like it.
return { .result = Result::FinalStep::Silence }; return { .result = Result::FinalStep::Silence };
} }

View file

@ -372,6 +372,16 @@ bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
return viewer->around; return viewer->around;
} else if (const auto item = lookupRoot()) { } else if (const auto item = lookupRoot()) {
return computeInboxReadTillFull(); 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; return viewer->around;
}(); }();

View file

@ -700,7 +700,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
result->setAccessHash(accessHash->v); result->setAccessHash(accessHash->v);
} }
status = data.vstatus(); status = data.vstatus();
{ if (!minimal) {
const auto newUsername = uname; const auto newUsername = uname;
const auto newUsernames = data.vusernames() const auto newUsernames = data.vusernames()
? Api::Usernames::FromTL(*data.vusernames()) ? Api::Usernames::FromTL(*data.vusernames())

View file

@ -82,6 +82,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qt/qt_common_adapters.h" #include "base/qt/qt_common_adapters.h"
#include <QtCore/QMimeData> #include <QtCore/QMimeData>
#include <QtGui/QTextBlock>
#include <QtWidgets/QScrollBar> #include <QtWidgets/QScrollBar>
#include <QtWidgets/QTextEdit> #include <QtWidgets/QTextEdit>
@ -101,6 +102,15 @@ base::options::toggle OptionForumHideChatsList({
.description = "Don't keep a narrow column of chats list.", .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 } // namespace
const char kOptionForumHideChatsList[] = "forum-hide-chats-list"; const char kOptionForumHideChatsList[] = "forum-hide-chats-list";
@ -360,6 +370,14 @@ Widget::Widget(
Ui::PostponeCall(this, [=] { listScrollUpdated(); }); Ui::PostponeCall(this, [=] { listScrollUpdated(); });
}, lifetime()); }, lifetime());
setAttribute(Qt::WA_InputMethodEnabled);
controller->widget()->imeCompositionStarts(
) | rpl::filter([=] {
return redirectImeToSearch();
}) | rpl::start_with_next([=] {
_search->setFocusFast();
}, lifetime());
_search->changes( _search->changes(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
applySearchUpdate(); applySearchUpdate();
@ -449,7 +467,6 @@ Widget::Widget(
loadMoreBlockedByDate(); loadMoreBlockedByDate();
}, lifetime()); }, lifetime());
_search->setFocusPolicy(Qt::StrongFocus);
_search->customUpDown(true); _search->customUpDown(true);
updateJumpToDateVisibility(true); updateJumpToDateVisibility(true);
@ -569,14 +586,6 @@ void Widget::chosenRow(const ChosenRow &row) {
history, history,
ShowAtUnreadMsgId, ShowAtUnreadMsgId,
Window::SectionShow::Way::ClearStack); 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; return;
} else if (history) { } else if (history) {
@ -1018,7 +1027,9 @@ void Widget::setupShortcuts() {
const auto history = forum->history(); const auto history = forum->history();
controller()->searchInChat(history); controller()->searchInChat(history);
return true; return true;
} else if (!_openedFolder && _search->isVisible()) { } else if (!_openedFolder
&& !_childList
&& _search->isVisible()) {
_search->setFocus(); _search->setFocus();
return true; return true;
} }
@ -1175,13 +1186,16 @@ void Widget::updateSuggestions(anim::type animated) {
} else { } else {
_suggestions = nullptr; _suggestions = nullptr;
_hidingSuggestions.clear(); _hidingSuggestions.clear();
storiesExplicitCollapse();
updateStoriesVisibility();
_scroll->show(); _scroll->show();
} }
} else if (suggest && !_suggestions) { } else if (suggest && !_suggestions) {
if (animated == anim::type::normal) { if (animated == anim::type::normal) {
startWidthAnimation(); startWidthAnimation();
updateStoriesVisibility();
} }
// Hides stories and passcode lock.
updateStoriesVisibility();
_suggestions = std::make_unique<Suggestions>( _suggestions = std::make_unique<Suggestions>(
this, this,
controller(), controller(),
@ -1520,16 +1534,17 @@ void Widget::checkUpdateStatus() {
updateControlsGeometry(); updateControlsGeometry();
} }
void Widget::setInnerFocus() { void Widget::setInnerFocus(bool unfocusSearch) {
if (_childList) { if (_childList) {
_childList->setInnerFocus(); _childList->setInnerFocus();
} else if ((_openedFolder || _openedForum) } else if ((_openedFolder || _openedForum)
&& _subsectionTopBar->searchSetFocus()) { && _subsectionTopBar->searchSetFocus()) {
return; return;
} else if (!_search->getLastText().isEmpty() } else if (!unfocusSearch
|| _searchInChat && (!_search->getLastText().isEmpty()
|| _searchHasFocus || _searchInChat
|| _searchSuggestionsLocked) { || _searchHasFocus
|| _searchSuggestionsLocked)) {
_search->setFocus(); _search->setFocus();
} else { } else {
setFocus(); setFocus();
@ -2552,15 +2567,18 @@ void Widget::dragMoveEvent(QDragMoveEvent *e) {
} else { } else {
_chooseByDragTimer.callOnce(ChoosePeerByDragTimeout); _chooseByDragTimer.callOnce(ChoosePeerByDragTimeout);
} }
if (_inner->updateFromParentDrag(mapToGlobal(e->pos()))) { const auto global = mapToGlobal(e->pos());
e->setDropAction(Qt::CopyAction); const auto thread = _suggestions
} else { ? _suggestions->updateFromParentDrag(global)
e->setDropAction(Qt::IgnoreAction); : _inner->updateFromParentDrag(global);
} e->setDropAction(thread ? Qt::CopyAction : Qt::IgnoreAction);
} else { } else {
if (_dragForward) { if (_dragForward) {
updateDragInScroll(false); updateDragInScroll(false);
} }
if (_suggestions) {
_suggestions->dragLeft();
}
_inner->dragLeft(); _inner->dragLeft();
e->setDropAction(Qt::IgnoreAction); e->setDropAction(Qt::IgnoreAction);
} }
@ -2573,6 +2591,9 @@ void Widget::dragLeaveEvent(QDragLeaveEvent *e) {
} else { } else {
_chooseByDragTimer.cancel(); _chooseByDragTimer.cancel();
} }
if (_suggestions) {
_suggestions->dragLeft();
}
_inner->dragLeft(); _inner->dragLeft();
e->accept(); e->accept();
} }
@ -2591,8 +2612,11 @@ void Widget::updateDragInScroll(bool inScroll) {
void Widget::dropEvent(QDropEvent *e) { void Widget::dropEvent(QDropEvent *e) {
_chooseByDragTimer.cancel(); _chooseByDragTimer.cancel();
if (_scroll->geometry().contains(e->pos())) { if (_scroll->geometry().contains(e->pos())) {
const auto point = mapToGlobal(e->pos()); const auto globalPosition = mapToGlobal(e->pos());
if (const auto thread = _inner->updateFromParentDrag(point)) { const auto thread = _suggestions
? _suggestions->updateFromParentDrag(globalPosition)
: _inner->updateFromParentDrag(globalPosition);
if (thread) {
e->setDropAction(Qt::CopyAction); e->setDropAction(Qt::CopyAction);
e->accept(); e->accept();
controller()->content()->filesOrForwardDrop( controller()->content()->filesOrForwardDrop(
@ -2675,8 +2699,9 @@ void Widget::updateForceDisplayWide() {
void Widget::showForum( void Widget::showForum(
not_null<Data::Forum*> forum, not_null<Data::Forum*> forum,
const Window::SectionShow &params) { const Window::SectionShow &params) {
const auto nochat = !controller()->mainSectionShown();
if (!params.childColumn if (!params.childColumn
|| !Core::App().settings().dialogsWidthRatio() || (Core::App().settings().dialogsWidthRatio(nochat) == 0.)
|| (_layout != Layout::Main) || (_layout != Layout::Main)
|| OptionForumHideChatsList.value()) { || OptionForumHideChatsList.value()) {
changeOpenedForum(forum, params.animated); changeOpenedForum(forum, params.animated);
@ -2892,7 +2917,7 @@ bool Widget::setSearchInChat(
if (_searchInChat || !_search->getLastText().isEmpty()) { if (_searchInChat || !_search->getLastText().isEmpty()) {
_search->setFocus(); _search->setFocus();
} else { } else {
setFocus(); setInnerFocus(true);
} }
updateForceDisplayWide(); updateForceDisplayWide();
return true; return true;
@ -3273,6 +3298,10 @@ void Widget::keyPressEvent(QKeyEvent *e) {
//} else { //} else {
// e->ignore(); // 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) { } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
submit(); submit();
} else if (_suggestions } 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 { bool Widget::redirectKeyToSearch(QKeyEvent *e) const {
if (_openedFolder if (!redirectToSearchPossible()) {
|| _openedForum
|| !_search->isVisible()
|| _search->hasFocus()) {
return false; return false;
} }
const auto character = !(e->modifiers() & ~Qt::ShiftModifier) const auto character = !(e->modifiers() & ~Qt::ShiftModifier)
&& (e->key() != Qt::Key_Shift) && (e->key() != Qt::Key_Shift)
&& !e->text().isEmpty(); && RedirectTextToSearch(e->text());
if (character) { if (character) {
return true; return true;
} else if (e != QKeySequence::Paste) { } else if (e != QKeySequence::Paste) {
@ -3338,6 +3398,10 @@ bool Widget::redirectKeyToSearch(QKeyEvent *e) const {
return data && data->hasText(); return data && data->hasText();
} }
bool Widget::redirectImeToSearch() const {
return redirectToSearchPossible();
}
void Widget::paintEvent(QPaintEvent *e) { void Widget::paintEvent(QPaintEvent *e) {
if (controller()->contentOverlapped(this, e)) { if (controller()->contentOverlapped(this, e)) {
return; return;
@ -3446,7 +3510,7 @@ bool Widget::cancelSearch() {
if (!clearingQuery if (!clearingQuery
&& _subsectionTopBar && _subsectionTopBar
&& _subsectionTopBar->toggleSearch(false, anim::type::normal)) { && _subsectionTopBar->toggleSearch(false, anim::type::normal)) {
setFocus(); setInnerFocus(true);
clearingInChat = true; clearingInChat = true;
} }
const auto clearSearchFocus = !_searchInChat const auto clearSearchFocus = !_searchInChat
@ -3457,7 +3521,7 @@ bool Widget::cancelSearch() {
} }
if (!_suggestions && clearSearchFocus) { if (!_suggestions && clearSearchFocus) {
// Don't create suggestions in unfocus case. // Don't create suggestions in unfocus case.
setFocus(); setInnerFocus(true);
} }
_lastSearchPeer = nullptr; _lastSearchPeer = nullptr;
_lastSearchId = _lastSearchMigratedId = 0; _lastSearchId = _lastSearchMigratedId = 0;
@ -3465,7 +3529,7 @@ bool Widget::cancelSearch() {
clearSearchField(); clearSearchField();
applySearchUpdate(); applySearchUpdate();
if (_suggestions && clearSearchFocus) { if (_suggestions && clearSearchFocus) {
setFocus(); setInnerFocus(true);
} }
return clearingQuery || clearingInChat || clearSearchFocus; return clearingQuery || clearingInChat || clearSearchFocus;
} }

View file

@ -99,7 +99,7 @@ public:
not_null<Data::Forum*> forum, not_null<Data::Forum*> forum,
const Window::SectionShow &params); const Window::SectionShow &params);
void searchInChat(Key chat); void searchInChat(Key chat);
void setInnerFocus(); void setInnerFocus(bool unfocusSearch = false);
[[nodiscard]] bool searchHasFocus() const; [[nodiscard]] bool searchHasFocus() const;
void jumpToTop(bool belowPinned = false); void jumpToTop(bool belowPinned = false);
@ -135,6 +135,8 @@ public:
bool cancelSearch(); bool cancelSearch();
bool cancelSearchByMouseBack(); bool cancelSearchByMouseBack();
QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
~Widget(); ~Widget();
protected: protected:
@ -144,6 +146,7 @@ protected:
void dropEvent(QDropEvent *e) override; void dropEvent(QDropEvent *e) override;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override; void keyPressEvent(QKeyEvent *e) override;
void inputMethodEvent(QInputMethodEvent *e) override;
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
private: private:
@ -250,7 +253,9 @@ private:
void updateSuggestions(anim::type animated); void updateSuggestions(anim::type animated);
void processSearchFocusChange(); void processSearchFocusChange();
[[nodiscard]] bool redirectToSearchPossible() const;
[[nodiscard]] bool redirectKeyToSearch(QKeyEvent *e) const; [[nodiscard]] bool redirectKeyToSearch(QKeyEvent *e) const;
[[nodiscard]] bool redirectImeToSearch() const;
MTP::Sender _api; MTP::Sender _api;

View file

@ -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<void()> finish) { void Suggestions::show(anim::type animated, Fn<void()> finish) {
RpWidget::show(); RpWidget::show();
@ -1304,6 +1337,12 @@ object_ptr<Ui::SlideWrap<>> Suggestions::setupRecentPeers(
} }
return JumpResult::NotApplied; return JumpResult::NotApplied;
}; };
_recentUpdateFromParentDrag = [=](QPoint globalPosition) {
return raw->updateFromParentDrag(globalPosition);
};
_recentDragLeft = [=] {
raw->dragLeft();
};
raw->scrollToRequests( raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) { ) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
const auto add = _topPeersWrap->toggled() ? _topPeers->height() : 0; const auto add = _topPeersWrap->toggled() ? _topPeers->height() : 0;
@ -1438,6 +1477,12 @@ object_ptr<Ui::SlideWrap<>> Suggestions::setupMyChannels() {
} }
return JumpResult::NotApplied; return JumpResult::NotApplied;
}; };
_myChannelsUpdateFromParentDrag = [=](QPoint globalPosition) {
return raw->updateFromParentDrag(globalPosition);
};
_myChannelsDragLeft = [=] {
raw->dragLeft();
};
raw->scrollToRequests( raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) { ) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
_channelsScroll->scrollToY(request.ymin, request.ymax); _channelsScroll->scrollToY(request.ymin, request.ymax);
@ -1499,6 +1544,12 @@ object_ptr<Ui::SlideWrap<>> Suggestions::setupRecommendations() {
} }
return JumpResult::NotApplied; return JumpResult::NotApplied;
}; };
_recommendationsUpdateFromParentDrag = [=](QPoint globalPosition) {
return raw->updateFromParentDrag(globalPosition);
};
_recommendationsDragLeft = [=] {
raw->dragLeft();
};
raw->scrollToRequests( raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) { ) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
const auto add = _myChannels->toggled() ? _myChannels->height() : 0; const auto add = _myChannels->toggled() ? _myChannels->height() : 0;

View file

@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
namespace Data {
class Thread;
} // namespace Data
namespace Main { namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
@ -46,6 +50,9 @@ public:
void selectJump(Qt::Key direction, int pageSize = 0); void selectJump(Qt::Key direction, int pageSize = 0);
void chooseRow(); void chooseRow();
[[nodiscard]] Data::Thread *updateFromParentDrag(QPoint globalPosition);
void dragLeft();
void show(anim::type animated, Fn<void()> finish); void show(anim::type animated, Fn<void()> finish);
void hide(anim::type animated, Fn<void()> finish); void hide(anim::type animated, Fn<void()> finish);
[[nodiscard]] float64 shownOpacity() const; [[nodiscard]] float64 shownOpacity() const;
@ -90,6 +97,11 @@ private:
void selectJumpChats(Qt::Key direction, int pageSize); void selectJumpChats(Qt::Key direction, int pageSize);
void selectJumpChannels(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<Ui::SlideWrap<Ui::RpWidget>> setupRecentPeers( [[nodiscard]] object_ptr<Ui::SlideWrap<Ui::RpWidget>> setupRecentPeers(
RecentPeersList recentPeers); RecentPeersList recentPeers);
[[nodiscard]] object_ptr<Ui::SlideWrap<Ui::RpWidget>> setupEmptyRecent(); [[nodiscard]] object_ptr<Ui::SlideWrap<Ui::RpWidget>> setupEmptyRecent();
@ -121,6 +133,8 @@ private:
rpl::variable<int> _recentCount; rpl::variable<int> _recentCount;
Fn<bool()> _recentPeersChoose; Fn<bool()> _recentPeersChoose;
Fn<JumpResult(Qt::Key, int)> _recentSelectJump; Fn<JumpResult(Qt::Key, int)> _recentSelectJump;
Fn<uint64(QPoint)> _recentUpdateFromParentDrag;
Fn<void()> _recentDragLeft;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _recentPeers; const not_null<Ui::SlideWrap<Ui::RpWidget>*> _recentPeers;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _emptyRecent; const not_null<Ui::SlideWrap<Ui::RpWidget>*> _emptyRecent;
@ -130,11 +144,15 @@ private:
rpl::variable<int> _myChannelsCount; rpl::variable<int> _myChannelsCount;
Fn<bool()> _myChannelsChoose; Fn<bool()> _myChannelsChoose;
Fn<JumpResult(Qt::Key, int)> _myChannelsSelectJump; Fn<JumpResult(Qt::Key, int)> _myChannelsSelectJump;
Fn<uint64(QPoint)> _myChannelsUpdateFromParentDrag;
Fn<void()> _myChannelsDragLeft;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _myChannels; const not_null<Ui::SlideWrap<Ui::RpWidget>*> _myChannels;
rpl::variable<int> _recommendationsCount; rpl::variable<int> _recommendationsCount;
Fn<bool()> _recommendationsChoose; Fn<bool()> _recommendationsChoose;
Fn<JumpResult(Qt::Key, int)> _recommendationsSelectJump; Fn<JumpResult(Qt::Key, int)> _recommendationsSelectJump;
Fn<uint64(QPoint)> _recommendationsUpdateFromParentDrag;
Fn<void()> _recommendationsDragLeft;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _recommendations; const not_null<Ui::SlideWrap<Ui::RpWidget>*> _recommendations;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _emptyChannels; const not_null<Ui::SlideWrap<Ui::RpWidget>*> _emptyChannels;

View file

@ -248,7 +248,7 @@ void TopPeersStrip::stripWheelEvent(QWheelEvent *e) {
void TopPeersStrip::stripLeaveEvent(QEvent *e) { void TopPeersStrip::stripLeaveEvent(QEvent *e) {
if (!_selectionByKeyboard) { if (!_selectionByKeyboard) {
setSelected(-1); clearSelection();
} }
if (!_dragging) { if (!_dragging) {
_lastMousePosition = std::nullopt; _lastMousePosition = std::nullopt;
@ -299,9 +299,7 @@ void TopPeersStrip::stripMouseMoveEvent(QMouseEvent *e) {
&& (_lastMousePosition == e->globalPos())) { && (_lastMousePosition == e->globalPos())) {
return; return;
} }
_lastMousePosition = e->globalPos(); selectByMouse(e->globalPos());
_selectionByKeyboard = false;
updateSelected();
if (!_dragging && _mouseDownPosition) { if (!_dragging && _mouseDownPosition) {
if ((*_lastMousePosition - *_mouseDownPosition).manhattanLength() if ((*_lastMousePosition - *_mouseDownPosition).manhattanLength()
@ -315,6 +313,12 @@ void TopPeersStrip::stripMouseMoveEvent(QMouseEvent *e) {
checkDragging(); checkDragging();
} }
void TopPeersStrip::selectByMouse(QPoint globalPosition) {
_lastMousePosition = globalPosition;
_selectionByKeyboard = false;
updateSelected();
}
void TopPeersStrip::checkDragging() { void TopPeersStrip::checkDragging() {
if (_dragging && !_expandAnimation.animating()) { if (_dragging && !_expandAnimation.animating()) {
const auto sign = (style::RightToLeft() ? -1 : 1); const auto sign = (style::RightToLeft() ? -1 : 1);
@ -551,6 +555,20 @@ bool TopPeersStrip::chooseRow() {
return false; 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) { void TopPeersStrip::apply(const TopPeersList &list) {
if (_hiddenLocally) { if (_hiddenLocally) {
return; return;
@ -908,6 +926,10 @@ void TopPeersStrip::setSelected(int selected) {
} }
} }
void TopPeersStrip::clearSelection() {
setSelected(-1);
}
void TopPeersStrip::scrollToSelected() { void TopPeersStrip::scrollToSelected() {
if (_selected < 0) { if (_selected < 0) {
return; return;

View file

@ -62,6 +62,9 @@ public:
void deselectByKeyboard(); void deselectByKeyboard();
bool chooseRow(); bool chooseRow();
uint64 updateFromParentDrag(QPoint globalPosition);
void dragLeft();
[[nodiscard]] auto verticalScrollEvents() const [[nodiscard]] auto verticalScrollEvents() const
-> rpl::producer<not_null<QWheelEvent*>>; -> rpl::producer<not_null<QWheelEvent*>>;
@ -92,6 +95,8 @@ private:
void subscribeUserpic(Entry &entry); void subscribeUserpic(Entry &entry);
void unsubscribeUserpics(bool all = false); void unsubscribeUserpics(bool all = false);
void paintUserpic(Painter &p, int x, int y, int index, bool selected); void paintUserpic(Painter &p, int x, int y, int index, bool selected);
void clearSelection();
void selectByMouse(QPoint globalPosition);
[[nodiscard]] QRect outer() const; [[nodiscard]] QRect outer() const;
[[nodiscard]] QRect innerRounded() const; [[nodiscard]] QRect innerRounded() const;

View file

@ -291,7 +291,11 @@ void FrameGenerator::Impl::jumpToStart() {
void FrameGenerator::Impl::resolveNextFrameTiming() { void FrameGenerator::Impl::resolveNextFrameTiming() {
const auto base = _format->streams[_streamId]->time_base; 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; const auto duration = _next.frame->pkt_duration;
#endif
const auto framePts = _next.frame->pts; const auto framePts = _next.frame->pts;
auto framePosition = (framePts * 1000LL * base.num) / base.den; auto framePosition = (framePts * 1000LL * base.num) / base.den;
_currentFrameDelay = _nextFrameDelay; _currentFrameDelay = _nextFrameDelay;

View file

@ -230,7 +230,11 @@ enum AVPixelFormat GetFormatImplementation(
IOPointer MakeIOPointer( IOPointer MakeIOPointer(
void *opaque, void *opaque,
int(*read)(void *opaque, uint8_t *buffer, int bufferSize), 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), int(*write)(void *opaque, uint8_t *buffer, int bufferSize),
#endif
int64_t(*seek)(void *opaque, int64_t offset, int whence)) { int64_t(*seek)(void *opaque, int64_t offset, int whence)) {
auto buffer = reinterpret_cast<uchar*>(av_malloc(kAvioBlockSize)); auto buffer = reinterpret_cast<uchar*>(av_malloc(kAvioBlockSize));
if (!buffer) { if (!buffer) {
@ -263,7 +267,11 @@ void IODeleter::operator()(AVIOContext *value) {
FormatPointer MakeFormatPointer( FormatPointer MakeFormatPointer(
void *opaque, void *opaque,
int(*read)(void *opaque, uint8_t *buffer, int bufferSize), 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), int(*write)(void *opaque, uint8_t *buffer, int bufferSize),
#endif
int64_t(*seek)(void *opaque, int64_t offset, int whence)) { int64_t(*seek)(void *opaque, int64_t offset, int whence)) {
auto io = MakeIOPointer(opaque, read, write, seek); auto io = MakeIOPointer(opaque, read, write, seek);
if (!io) { if (!io) {

View file

@ -22,8 +22,14 @@ extern "C" {
#include <libavutil/version.h> #include <libavutil/version.h>
} // extern "C" } // extern "C"
#define DA_FFMPEG_NEW_CHANNEL_LAYOUT (LIBAVUTIL_VERSION_MAJOR > 57 \ #define DA_FFMPEG_NEW_CHANNEL_LAYOUT (LIBAVUTIL_VERSION_INT >= \
|| (LIBAVUTIL_VERSION_MAJOR == 57 && LIBAVUTIL_VERSION_MINOR >= 28)) 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; class QImage;
@ -112,7 +118,11 @@ using IOPointer = std::unique_ptr<AVIOContext, IODeleter>;
[[nodiscard]] IOPointer MakeIOPointer( [[nodiscard]] IOPointer MakeIOPointer(
void *opaque, void *opaque,
int(*read)(void *opaque, uint8_t *buffer, int bufferSize), 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), int(*write)(void *opaque, uint8_t *buffer, int bufferSize),
#endif
int64_t(*seek)(void *opaque, int64_t offset, int whence)); int64_t(*seek)(void *opaque, int64_t offset, int whence));
struct FormatDeleter { struct FormatDeleter {
@ -122,7 +132,11 @@ using FormatPointer = std::unique_ptr<AVFormatContext, FormatDeleter>;
[[nodiscard]] FormatPointer MakeFormatPointer( [[nodiscard]] FormatPointer MakeFormatPointer(
void *opaque, void *opaque,
int(*read)(void *opaque, uint8_t *buffer, int bufferSize), 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), int(*write)(void *opaque, uint8_t *buffer, int bufferSize),
#endif
int64_t(*seek)(void *opaque, int64_t offset, int whence)); int64_t(*seek)(void *opaque, int64_t offset, int whence));
struct CodecDeleter { struct CodecDeleter {

View file

@ -3647,7 +3647,8 @@ void HistoryItem::createComponentsHelper(HistoryItemCommonFields &&fields) {
const auto topicPost = config.reply.externalPeerId const auto topicPost = config.reply.externalPeerId
? (replyTo.topicRootId ? (replyTo.topicRootId
&& (replyTo.topicRootId != Data::ForumTopic::kGeneralId)) && (replyTo.topicRootId != Data::ForumTopic::kGeneralId))
: (LookupReplyIsTopicPost(to) : (topic
|| LookupReplyIsTopicPost(to)
|| (to && to->Has<HistoryServiceTopicInfo>()) || (to && to->Has<HistoryServiceTopicInfo>())
|| (forum && forum->creating(config.reply.topMessageId))); || (forum && forum->creating(config.reply.topMessageId)));
config.reply.topicPost = topicPost ? 1 : 0; config.reply.topicPost = topicPost ? 1 : 0;

View file

@ -2681,6 +2681,7 @@ void HistoryWidget::setEditMsgId(MsgId msgId) {
unregisterDraftSources(); unregisterDraftSources();
_editMsgId = msgId; _editMsgId = msgId;
if (!msgId) { if (!msgId) {
_mediaEditSpoiler.setSpoilerOverride(std::nullopt);
_canReplaceMedia = false; _canReplaceMedia = false;
if (_preview) { if (_preview) {
_preview->setDisabled(false); _preview->setDisabled(false);
@ -4071,7 +4072,8 @@ void HistoryWidget::saveEditMsg() {
webPageDraft, webPageDraft,
options, options,
done, done,
fail); fail,
_mediaEditSpoiler.spoilerOverride());
} }
void HistoryWidget::hideChildWidgets() { void HistoryWidget::hideChildWidgets() {
@ -6602,7 +6604,14 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
return; return;
} }
const auto isReadyToForward = readyToForward(); 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( EditCaptionBox::StartPhotoEdit(
controller(), controller(),
_photoEditMedia, _photoEditMedia,
@ -8209,12 +8218,14 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
} }
} }
if (_replyEditMsg) { if (_replyEditMsg) {
const auto media = _replyEditMsg->media(); const auto editMedia = _editMsgId
_canReplaceMedia = media && media->allowsEditMedia(); ? _replyEditMsg->media()
: nullptr;
_canReplaceMedia = editMedia && editMedia->allowsEditMedia();
_photoEditMedia = (_canReplaceMedia _photoEditMedia = (_canReplaceMedia
&& media->photo() && editMedia->photo()
&& !media->photo()->isNull()) && !editMedia->photo()->isNull())
? media->photo()->createMediaView() ? editMedia->photo()->createMediaView()
: nullptr; : nullptr;
if (_photoEditMedia) { if (_photoEditMedia) {
_photoEditMedia->wanted( _photoEditMedia->wanted(
@ -8303,8 +8314,14 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
? drawMsgText->media() ? drawMsgText->media()
: nullptr; : nullptr;
const auto hasPreview = media && media->hasReplyPreview(); const auto hasPreview = media && media->hasReplyPreview();
const auto preview = hasPreview ? media->replyPreview() : nullptr; const auto preview = _mediaEditSpoiler.spoilerOverride()
const auto spoilered = preview && media->hasSpoiler(); ? _mediaEditSpoiler.mediaPreview(drawMsgText)
: hasPreview
? media->replyPreview()
: nullptr;
const auto spoilered = _mediaEditSpoiler.spoilerOverride()
? (*_mediaEditSpoiler.spoilerOverride())
: (preview && media->hasSpoiler());
if (!spoilered) { if (!spoilered) {
_replySpoiler = nullptr; _replySpoiler = nullptr;
} else if (!_replySpoiler) { } else if (!_replySpoiler) {

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "history/view/controls/history_view_compose_media_edit_manager.h"
#include "history/view/history_view_corner_buttons.h" #include "history/view/history_view_corner_buttons.h"
#include "history/history_drag_area.h" #include "history/history_drag_area.h"
#include "history/history_view_highlight_manager.h" #include "history/history_view_highlight_manager.h"
@ -103,6 +104,7 @@ class ForwardPanel;
class TTLButton; class TTLButton;
class WebpageProcessor; class WebpageProcessor;
class CharactersLimitLabel; class CharactersLimitLabel;
class PhotoEditSpoilerManager;
} // namespace HistoryView::Controls } // namespace HistoryView::Controls
class BotKeyboard; class BotKeyboard;
@ -661,6 +663,7 @@ private:
MsgId _editMsgId = 0; MsgId _editMsgId = 0;
std::shared_ptr<Data::PhotoMedia> _photoEditMedia; std::shared_ptr<Data::PhotoMedia> _photoEditMedia;
bool _canReplaceMedia = false; bool _canReplaceMedia = false;
HistoryView::MediaEditSpoilerManager _mediaEditSpoiler;
HistoryItem *_replyEditMsg = nullptr; HistoryItem *_replyEditMsg = nullptr;
Ui::Text::String _replyEditMsgText; Ui::Text::String _replyEditMsgText;

View file

@ -21,6 +21,7 @@ struct MessageToEdit {
FullMsgId fullId; FullMsgId fullId;
Api::SendOptions options; Api::SendOptions options;
TextWithTags textWithTags; TextWithTags textWithTags;
std::optional<bool> spoilerMediaOverride;
}; };
struct VoiceToSend { struct VoiceToSend {
QByteArray bytes; QByteArray bytes;

View file

@ -50,6 +50,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/view/controls/history_view_characters_limit.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_forward_panel.h"
#include "history/view/controls/history_view_draft_options.h" #include "history/view/controls/history_view_draft_options.h"
#include "history/view/controls/history_view_voice_record_bar.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/ui_utility.h"
#include "ui/widgets/fields/input_field.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/dropdown_menu.h" #include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/popup_menu.h"
#include "ui/text/format_values.h" #include "ui/text/format_values.h"
#include "ui/controls/emoji_button.h" #include "ui/controls/emoji_button.h"
#include "ui/controls/send_button.h" #include "ui/controls/send_button.h"
@ -84,6 +86,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h" #include "mainwindow.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
#include "styles/style_chat_helpers.h" #include "styles/style_chat_helpers.h"
#include "styles/style_menu_icons.h"
namespace HistoryView { namespace HistoryView {
namespace { namespace {
@ -210,6 +213,8 @@ private:
bool _repaintScheduled : 1 = false; bool _repaintScheduled : 1 = false;
bool _inClickable : 1 = false; bool _inClickable : 1 = false;
HistoryView::MediaEditSpoilerManager _mediaEditSpoiler;
const not_null<Data::Session*> _data; const not_null<Data::Session*> _data;
const not_null<Ui::IconButton*> _cancel; const not_null<Ui::IconButton*> _cancel;
@ -398,7 +403,12 @@ void FieldHeader::init() {
_editOptionsRequests.fire({}); _editOptionsRequests.fire({});
} }
} else if (!isLeftButton) { } 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); _jumpToItemRequests.fire_copy(reply);
} }
} }
@ -572,10 +582,14 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) {
const auto media = _shownMessage->media(); const auto media = _shownMessage->media();
_shownMessageHasPreview = media && media->hasReplyPreview(); _shownMessageHasPreview = media && media->hasReplyPreview();
const auto preview = _shownMessageHasPreview const auto preview = _mediaEditSpoiler.spoilerOverride()
? _mediaEditSpoiler.mediaPreview(_shownMessage)
: _shownMessageHasPreview
? media->replyPreview() ? media->replyPreview()
: nullptr; : nullptr;
const auto spoilered = preview && media->hasSpoiler(); const auto spoilered = _mediaEditSpoiler.spoilerOverride()
? (*_mediaEditSpoiler.spoilerOverride())
: (preview && media->hasSpoiler());
if (!spoilered) { if (!spoilered) {
_shownPreviewSpoiler = nullptr; _shownPreviewSpoiler = nullptr;
} else if (!_shownPreviewSpoiler) { } else if (!_shownPreviewSpoiler) {
@ -720,6 +734,7 @@ void FieldHeader::editMessage(FullMsgId id, bool photoEditAllowed) {
_photoEditAllowed = photoEditAllowed; _photoEditAllowed = photoEditAllowed;
_editMsgId = id; _editMsgId = id;
if (!photoEditAllowed) { if (!photoEditAllowed) {
_mediaEditSpoiler.setSpoilerOverride(std::nullopt);
_inPhotoEdit = false; _inPhotoEdit = false;
_inPhotoEditOver.stop(); _inPhotoEditOver.stop();
} }
@ -767,6 +782,7 @@ MessageToEdit FieldHeader::queryToEdit() {
.scheduled = item->isScheduled() ? item->date() : 0, .scheduled = item->isScheduled() ? item->date() : 0,
.shortcutId = item->shortcutId(), .shortcutId = item->shortcutId(),
}, },
.spoilerMediaOverride = _mediaEditSpoiler.spoilerOverride(),
}; };
} }
@ -3440,4 +3456,49 @@ rpl::producer<bool> SendDisabledBySlowmode(not_null<PeerData*> peer) {
_1 && _2); _1 && _2);
} }
void ShowPhotoEditSpoilerMenu(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
const std::optional<bool> &override,
Fn<void(bool)> 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<Ui::PopupMenu>(
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<HistoryItem*> 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 } // namespace HistoryView

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History; class History;
class DocumentData; class DocumentData;
class FieldAutocomplete; class FieldAutocomplete;
class Image;
namespace style { namespace style {
struct ComposeControls; struct ComposeControls;
@ -451,4 +452,14 @@ private:
[[nodiscard]] rpl::producer<bool> SendDisabledBySlowmode( [[nodiscard]] rpl::producer<bool> SendDisabledBySlowmode(
not_null<PeerData*> peer); not_null<PeerData*> peer);
void ShowPhotoEditSpoilerMenu(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
const std::optional<bool> &override,
Fn<void(bool)> callback);
[[nodiscard]] Image *MediaPreviewWithOverriddenSpoiler(
not_null<HistoryItem*> item,
bool spoiler);
} // namespace HistoryView } // namespace HistoryView

View file

@ -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<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
Fn<void(bool)> 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<Ui::PopupMenu>(
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<HistoryItem*> 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<bool> spoilerOverride) {
_spoilerOverride = spoilerOverride;
}
std::optional<bool> MediaEditSpoilerManager::spoilerOverride() const {
return _spoilerOverride;
}
} // namespace HistoryView

View file

@ -0,0 +1,39 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Ui {
class RpWidget;
} // namespace Ui
class Image;
class HistoryItem;
namespace HistoryView {
class MediaEditSpoilerManager final {
public:
MediaEditSpoilerManager();
void showMenu(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
Fn<void(bool)> callback);
[[nodiscard]] Image *mediaPreview(not_null<HistoryItem*> item);
void setSpoilerOverride(std::optional<bool> spoilerOverride);
std::optional<bool> spoilerOverride() const;
private:
std::optional<bool> _spoilerOverride;
};
} // namespace HistoryView

View file

@ -3860,7 +3860,7 @@ void Message::fromNameUpdated(int width) const {
const auto nameText = [&]() -> const Ui::Text::String * { const auto nameText = [&]() -> const Ui::Text::String * {
if (from) { if (from) {
return &_fromName; return &_fromName;
} else if (const auto info= item->originalHiddenSenderInfo()) { } else if (const auto info = item->originalHiddenSenderInfo()) {
return &info->nameText(); return &info->nameText();
} else { } else {
Unexpected("Corrupted forwarded information in message."); Unexpected("Corrupted forwarded information in message.");

View file

@ -744,7 +744,8 @@ void RepliesWidget::setupComposeControls() {
_composeControls->editRequests( _composeControls->editRequests(
) | rpl::start_with_next([=](auto data) { ) | rpl::start_with_next([=](auto data) {
if (const auto item = session().data().message(data.fullId)) { 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()); }, lifetime());
@ -1215,7 +1216,8 @@ void RepliesWidget::send(Api::SendOptions options) {
void RepliesWidget::edit( void RepliesWidget::edit(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
Api::SendOptions options, Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId) { mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride) {
if (*saveEditMsgRequestId) { if (*saveEditMsgRequestId) {
return; return;
} }
@ -1283,7 +1285,8 @@ void RepliesWidget::edit(
webpage, webpage,
options, options,
crl::guard(this, done), crl::guard(this, done),
crl::guard(this, fail)); crl::guard(this, fail),
spoilerMediaOverride);
_composeControls->hidePanelsAnimated(); _composeControls->hidePanelsAnimated();
doSetInnerFocus(); doSetInnerFocus();

View file

@ -246,7 +246,8 @@ private:
void edit( void edit(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
Api::SendOptions options, Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId); mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride);
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos); void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Type sendMenuType() const;
[[nodiscard]] FullReplyTo replyTo() const; [[nodiscard]] FullReplyTo replyTo() const;

View file

@ -587,7 +587,7 @@ QSize Reply::countMultilineOptimalSize(
textGeometry(max, previewSkip, &elided)); textGeometry(max, previewSkip, &elided));
_minHeightExpandable = elided ? 1 : 0; _minHeightExpandable = elided ? 1 : 0;
return { return {
result.width, result.width + st::historyReplyPadding.right(),
std::max(result.height, st::normalFont->height), std::max(result.height, st::normalFont->height),
}; };
} }

View file

@ -326,7 +326,8 @@ void ScheduledWidget::setupComposeControls() {
) | rpl::start_with_next([=](auto data) { ) | rpl::start_with_next([=](auto data) {
if (const auto item = session().data().message(data.fullId)) { if (const auto item = session().data().message(data.fullId)) {
if (item->isScheduled()) { if (item->isScheduled()) {
edit(item, data.options, saveEditMsgRequestId); const auto spoiler = data.spoilerMediaOverride;
edit(item, data.options, saveEditMsgRequestId, spoiler);
} }
} }
}, lifetime()); }, lifetime());
@ -734,7 +735,8 @@ void ScheduledWidget::sendVoice(
void ScheduledWidget::edit( void ScheduledWidget::edit(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
Api::SendOptions options, Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId) { mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride) {
if (*saveEditMsgRequestId) { if (*saveEditMsgRequestId) {
return; return;
} }
@ -802,7 +804,8 @@ void ScheduledWidget::edit(
webpage, webpage,
options, options,
crl::guard(this, done), crl::guard(this, done),
crl::guard(this, fail)); crl::guard(this, fail),
spoilerMediaOverride);
_composeControls->hidePanelsAnimated(); _composeControls->hidePanelsAnimated();
_composeControls->focus(); _composeControls->focus();

View file

@ -213,7 +213,8 @@ private:
void edit( void edit(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
Api::SendOptions options, Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId); mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride);
void highlightSingleNewMessage(const Data::MessagesSlice &slice); void highlightSingleNewMessage(const Data::MessagesSlice &slice);
void chooseAttach(); void chooseAttach();
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Type sendMenuType() const;

View file

@ -447,6 +447,7 @@ QSize Document::countOptimalSize() {
const auto session = &history->session(); const auto session = &history->session();
const auto transcribes = &session->api().transcribes(); const auto transcribes = &session->api().transcribes();
if (_parent->data()->media()->ttlSeconds() if (_parent->data()->media()->ttlSeconds()
|| _realParent->isScheduled()
|| (!session->premium() || (!session->premium()
&& !transcribes->freeFor(_realParent) && !transcribes->freeFor(_realParent)
&& !transcribes->trialsSupport())) { && !transcribes->trialsSupport())) {

View file

@ -2076,6 +2076,7 @@ void Gif::ensureTranscribeButton() const {
if (_data->isVideoMessage() if (_data->isVideoMessage()
&& !_parent->data()->media()->ttlSeconds() && !_parent->data()->media()->ttlSeconds()
&& !_parent->data()->isScheduled()
&& (_data->session().premium() && (_data->session().premium()
|| _data->session().api().transcribes().trialsSupport())) { || _data->session().api().transcribes().trialsSupport())) {
if (!_transcribe) { if (!_transcribe) {

View file

@ -445,7 +445,7 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const {
} }
if (recth) { if (recth) {
int rectx = _additionalOnTop 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())); : (rightAligned ? 0 : (inner.width() + st::msgReplyPadding.left()));
int recty = surrounding.height - recth; int recty = surrounding.height - recth;
if (rtl()) rectx = width() - rectx - rectw; if (rtl()) rectx = width() - rectx - rectw;

View file

@ -921,7 +921,9 @@ void Selector::createList() {
&_show->session(), &_show->session(),
_strip ? _reactions.recent : std::vector<Data::Reaction>(), _strip ? _reactions.recent : std::vector<Data::Reaction>(),
_strip.get()); _strip.get());
_scroll = Ui::CreateChild<Ui::ScrollArea>(this, st::reactPanelScroll); _scroll = Ui::CreateChild<Ui::ScrollArea>(this, _reactions.customAllowed
? st::reactPanelScroll
: st::reactPanelScrollRounded);
_scroll->hide(); _scroll->hide();
const auto st = lifetime().make_state<style::EmojiPan>(_st); const auto st = lifetime().make_state<style::EmojiPan>(_st);

View file

@ -665,6 +665,10 @@ manageGroupTopicsButton: SettingsCountButton(manageGroupTopButtonWithText) {
} }
} }
} }
managePeerColorsButton: SettingsButton(infoProfileButton) {
padding: margins(60px, 10px, 48px, 8px);
}
manageGroupNoIconButtonInner: SettingsButton(infoProfileButton) { manageGroupNoIconButtonInner: SettingsButton(infoProfileButton) {
padding: margins(25px, 11px, 24px, 8px); padding: margins(25px, 11px, 24px, 8px);
} }

View file

@ -128,7 +128,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
base::flat_set<PeerId> groupEmojiSectionHidden; base::flat_set<PeerId> groupEmojiSectionHidden;
qint32 appThirdSectionInfoEnabled = 0; qint32 appThirdSectionInfoEnabled = 0;
qint32 legacySmallDialogsList = 0; qint32 legacySmallDialogsList = 0;
float64 appDialogsWidthRatio = app.dialogsWidthRatio(); float64 appDialogsWidthRatio = app.dialogsWidthRatio(false);
int appThirdColumnWidth = app.thirdColumnWidth(); int appThirdColumnWidth = app.thirdColumnWidth();
int appThirdSectionExtendedBy = app.thirdSectionExtendedBy(); int appThirdSectionExtendedBy = app.thirdSectionExtendedBy();
qint32 appSendFilesWay = app.sendFilesWay().serialize(); qint32 appSendFilesWay = app.sendFilesWay().serialize();
@ -535,7 +535,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
case RectPart::BottomRight: app.setFloatPlayerCorner(uncheckedCorner); break; case RectPart::BottomRight: app.setFloatPlayerCorner(uncheckedCorner); break;
} }
app.setThirdSectionInfoEnabled(appThirdSectionInfoEnabled); app.setThirdSectionInfoEnabled(appThirdSectionInfoEnabled);
app.setDialogsWidthRatio(appDialogsWidthRatio); app.updateDialogsWidthRatio(appDialogsWidthRatio, false);
app.setThirdColumnWidth(appThirdColumnWidth); app.setThirdColumnWidth(appThirdColumnWidth);
app.setThirdSectionExtendedBy(appThirdSectionExtendedBy); app.setThirdSectionExtendedBy(appThirdSectionExtendedBy);
} }

View file

@ -303,8 +303,16 @@ MainWidget::MainWidget(
}); });
}, lifetime()); }, lifetime());
const auto filter = [=](bool mainSectionShown) {
return rpl::filter([=] {
return (_controller->mainSectionShown() == mainSectionShown);
});
};
rpl::merge( 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 Core::App().settings().thirdColumnWidthChanges() | rpl::to_empty
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
updateControlsGeometry(); updateControlsGeometry();
@ -1408,6 +1416,7 @@ void MainWidget::showHistory(
auto onlyDialogs = noPeer && isOneColumn(); auto onlyDialogs = noPeer && isOneColumn();
_mainSection.destroy(); _mainSection.destroy();
updateMainSectionShown();
updateControlsGeometry(); updateControlsGeometry();
if (noPeer) { if (noPeer) {
@ -1781,6 +1790,7 @@ void MainWidget::showNewSection(
if (const auto entry = _mainSection->activeChat(); entry.key) { if (const auto entry = _mainSection->activeChat(); entry.key) {
_controller->setActiveChatEntry(entry); _controller->setActiveChatEntry(entry);
} }
updateMainSectionShown();
// Depends on SessionController::activeChatEntry // Depends on SessionController::activeChatEntry
// for tabbed selector showing in the third column. // for tabbed selector showing in the third column.
@ -1815,22 +1825,16 @@ void MainWidget::checkMainSectionToLayer() {
} }
Ui::FocusPersister persister(this); Ui::FocusPersister persister(this);
if (auto layer = _mainSection->moveContentToLayer(rect())) { if (auto layer = _mainSection->moveContentToLayer(rect())) {
dropMainSection(_mainSection); _mainSection.destroy();
_controller->showBackFromStack(
SectionShow(
anim::type::instant,
anim::activation::background));
_controller->showSpecialLayer( _controller->showSpecialLayer(
std::move(layer), std::move(layer),
anim::type::instant); anim::type::instant);
} }
} updateMainSectionShown();
void MainWidget::dropMainSection(Window::SectionWidget *widget) {
if (_mainSection != widget) {
return;
}
_mainSection.destroy();
_controller->showBackFromStack(
SectionShow(
anim::type::instant,
anim::activation::background));
} }
PeerData *MainWidget::singlePeer() const { PeerData *MainWidget::singlePeer() const {
@ -2236,13 +2240,18 @@ void MainWidget::resizeEvent(QResizeEvent *e) {
updateControlsGeometry(); updateControlsGeometry();
} }
void MainWidget::updateMainSectionShown() {
_controller->setMainSectionShown(_mainSection || _history->peer());
}
void MainWidget::updateControlsGeometry() { void MainWidget::updateControlsGeometry() {
if (!width()) { if (!width()) {
return; return;
} }
updateWindowAdaptiveLayout(); updateWindowAdaptiveLayout();
if (_dialogs) { if (_dialogs) {
if (Core::App().settings().dialogsWidthRatio() > 0) { const auto nochat = !_controller->mainSectionShown();
if (Core::App().settings().dialogsWidthRatio(nochat) > 0) {
_a_dialogsWidth.stop(); _a_dialogsWidth.stop();
} }
if (!_a_dialogsWidth.animating()) { if (!_a_dialogsWidth.animating()) {
@ -2444,19 +2453,22 @@ void MainWidget::ensureFirstColumnResizeAreaCreated() {
return; return;
} }
auto moveLeftCallback = [=](int globalLeft) { auto moveLeftCallback = [=](int globalLeft) {
auto newWidth = globalLeft - mapToGlobal(QPoint(0, 0)).x(); const auto newWidth = globalLeft - mapToGlobal(QPoint(0, 0)).x();
auto newRatio = (newWidth < st::columnMinimalWidthLeft / 2) const auto newRatio = (newWidth < st::columnMinimalWidthLeft / 2)
? 0. ? 0.
: float64(newWidth) / width(); : float64(newWidth) / width();
Core::App().settings().setDialogsWidthRatio(newRatio); const auto nochat = !_controller->mainSectionShown();
Core::App().settings().updateDialogsWidthRatio(newRatio, nochat);
}; };
auto moveFinishedCallback = [=] { auto moveFinishedCallback = [=] {
if (isOneColumn()) { if (isOneColumn()) {
return; return;
} }
if (Core::App().settings().dialogsWidthRatio() > 0) { const auto nochat = !_controller->mainSectionShown();
Core::App().settings().setDialogsWidthRatio( if (Core::App().settings().dialogsWidthRatio(nochat) > 0) {
float64(_dialogsWidth) / width()); Core::App().settings().updateDialogsWidthRatio(
float64(_dialogsWidth) / width(),
nochat);
} }
Core::App().saveSettingsDelayed(); Core::App().saveSettingsDelayed();
}; };
@ -2491,12 +2503,13 @@ void MainWidget::ensureThirdColumnResizeAreaCreated() {
} }
void MainWidget::updateDialogsWidthAnimated() { void MainWidget::updateDialogsWidthAnimated() {
if (!_dialogs || Core::App().settings().dialogsWidthRatio() > 0) { const auto nochat = !_controller->mainSectionShown();
if (!_dialogs || Core::App().settings().dialogsWidthRatio(nochat) > 0) {
return; return;
} }
auto dialogsWidth = _dialogsWidth; auto dialogsWidth = _dialogsWidth;
updateWindowAdaptiveLayout(); updateWindowAdaptiveLayout();
if (!Core::App().settings().dialogsWidthRatio() if (Core::App().settings().dialogsWidthRatio(nochat) == 0.
&& (_dialogsWidth != dialogsWidth && (_dialogsWidth != dialogsWidth
|| _a_dialogsWidth.animating())) { || _a_dialogsWidth.animating())) {
_dialogs->startWidthAnimation(); _dialogs->startWidthAnimation();
@ -2709,8 +2722,10 @@ void MainWidget::handleHistoryBack() {
} }
void MainWidget::updateWindowAdaptiveLayout() { void MainWidget::updateWindowAdaptiveLayout() {
const auto nochat = !_controller->mainSectionShown();
auto layout = _controller->computeColumnLayout(); 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 // 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. // 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() auto useSmallColumnWidth = !isOneColumn()
&& !dialogsWidthRatio && !dialogsWidthRatio

View file

@ -250,6 +250,7 @@ private:
void handleAudioUpdate(const Media::Player::TrackState &state); void handleAudioUpdate(const Media::Player::TrackState &state);
void updateMediaPlaylistPosition(int x); void updateMediaPlaylistPosition(int x);
void updateControlsGeometry(); void updateControlsGeometry();
void updateMainSectionShown();
void updateDialogsWidthAnimated(); void updateDialogsWidthAnimated();
void updateThirdColumnToCurrentChat( void updateThirdColumnToCurrentChat(
Dialogs::Key key, Dialogs::Key key,
@ -278,7 +279,6 @@ private:
void showNewSection( void showNewSection(
std::shared_ptr<Window::SectionMemento> memento, std::shared_ptr<Window::SectionMemento> memento,
const SectionShow &params); const SectionShow &params);
void dropMainSection(Window::SectionWidget *widget);
Window::SectionSlideParams prepareThirdSectionAnimation(Window::SectionWidget *section); Window::SectionSlideParams prepareThirdSectionAnimation(Window::SectionWidget *section);

View file

@ -249,7 +249,11 @@ struct Instance::Inner::Private {
return nbytes; 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) { static int WriteData(void *opaque, uint8_t *buf, int buf_size) {
#endif
auto l = reinterpret_cast<Private*>(opaque); auto l = reinterpret_cast<Private*>(opaque);
if (buf_size <= 0) return 0; if (buf_size <= 0) return 0;

View file

@ -144,7 +144,11 @@ ReaderImplementation::ReadResult FFMpegReaderImplementation::readNextFrame() {
} }
void FFMpegReaderImplementation::processReadFrame() { void FFMpegReaderImplementation::processReadFrame() {
#if DA_FFMPEG_HAVE_DURATION
int64 duration = _frame->duration;
#else
int64 duration = _frame->pkt_duration; int64 duration = _frame->pkt_duration;
#endif
int64 framePts = _frame->pts; int64 framePts = _frame->pts;
crl::time frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den; crl::time frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
_currentFrameDelay = _nextFrameDelay; _currentFrameDelay = _nextFrameDelay;

View file

@ -544,6 +544,7 @@ void OverlayWidget::RendererGL::paintTransformedContent(
0.f, 0.f, 0.f, 0.f,
}; };
_contentBuffer->bind();
_contentBuffer->write(0, coords, sizeof(coords)); _contentBuffer->write(0, coords, sizeof(coords));
program->setUniformValue("viewport", _uniformViewport); program->setUniformValue("viewport", _uniformViewport);
@ -712,6 +713,7 @@ void OverlayWidget::RendererGL::paintControl(
}; };
_controlsProgram->bind(); _controlsProgram->bind();
_controlsProgram->setUniformValue("viewport", _uniformViewport); _controlsProgram->setUniformValue("viewport", _uniformViewport);
_contentBuffer->bind();
if (!over.isEmpty() && overOpacity > 0) { if (!over.isEmpty() && overOpacity > 0) {
_contentBuffer->write( _contentBuffer->write(
offset * 4 * sizeof(GLfloat), offset * 4 * sizeof(GLfloat),
@ -915,6 +917,7 @@ void OverlayWidget::RendererGL::paintRoundedCorners(int radius) {
const auto offset = kControlsOffset const auto offset = kControlsOffset
+ (kControlsCount * kControlValues) / 4; + (kControlsCount * kControlValues) / 4;
const auto byteOffset = offset * 4 * sizeof(GLfloat); const auto byteOffset = offset * 4 * sizeof(GLfloat);
_contentBuffer->bind();
_contentBuffer->write(byteOffset, coords, sizeof(coords)); _contentBuffer->write(byteOffset, coords, sizeof(coords));
_roundedCornersProgram->bind(); _roundedCornersProgram->bind();
_roundedCornersProgram->setUniformValue("viewport", _uniformViewport); _roundedCornersProgram->setUniformValue("viewport", _uniformViewport);
@ -981,6 +984,7 @@ void OverlayWidget::RendererGL::paintStoriesSiblingPart(
+ (6 * 2 * 4) / 4 // rounding + (6 * 2 * 4) / 4 // rounding
+ (index * 4); + (index * 4);
const auto byteOffset = offset * 4 * sizeof(GLfloat); const auto byteOffset = offset * 4 * sizeof(GLfloat);
_contentBuffer->bind();
_contentBuffer->write(byteOffset, coords, sizeof(coords)); _contentBuffer->write(byteOffset, coords, sizeof(coords));
_controlsProgram->bind(); _controlsProgram->bind();
@ -1059,6 +1063,7 @@ void OverlayWidget::RendererGL::paintUsingRaster(
geometry.left(), geometry.bottom(), geometry.left(), geometry.bottom(),
textured.texture.left(), textured.texture.top(), textured.texture.left(), textured.texture.top(),
}; };
_contentBuffer->bind();
_contentBuffer->write( _contentBuffer->write(
bufferOffset * 4 * sizeof(GLfloat), bufferOffset * 4 * sizeof(GLfloat),
coords, coords,

View file

@ -427,6 +427,7 @@ void Pip::RendererGL::paintTransformedContent(
(geometry.outer.height() - geometry.inner.y()) * yscale, (geometry.outer.height() - geometry.inner.y()) * yscale,
}; };
_contentBuffer->bind();
_contentBuffer->write(0, coords, sizeof(coords)); _contentBuffer->write(0, coords, sizeof(coords));
const auto rgbaFrame = _chromaSize.isEmpty(); const auto rgbaFrame = _chromaSize.isEmpty();
@ -588,6 +589,7 @@ void Pip::RendererGL::paintButton(
iconOverRect.texture.right(), iconOverRect.texture.top(), iconOverRect.texture.right(), iconOverRect.texture.top(),
iconOverRect.texture.left(), iconOverRect.texture.top(), iconOverRect.texture.left(), iconOverRect.texture.top(),
}; };
_contentBuffer->bind();
_contentBuffer->write( _contentBuffer->write(
offset * 4 * sizeof(GLfloat), offset * 4 * sizeof(GLfloat),
coords, coords,
@ -741,6 +743,7 @@ void Pip::RendererGL::paintUsingRaster(
geometry.left(), geometry.bottom(), geometry.left(), geometry.bottom(),
textured.texture.left(), textured.texture.top(), textured.texture.left(), textured.texture.top(),
}; };
_contentBuffer->bind();
_contentBuffer->write( _contentBuffer->write(
bufferOffset * 4 * sizeof(GLfloat), bufferOffset * 4 * sizeof(GLfloat),
coords, coords,

View file

@ -37,11 +37,13 @@ namespace {
void AboutBox( void AboutBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) { std::shared_ptr<ChatHelpers::Show> show) {
constexpr auto kUrl = "https://promote.telegram.org"_cs; constexpr auto kUrl = "https://promote.telegram.org"_cs;
box->setNoContentMargin(true); box->setNoContentMargin(true);
const auto session = &show->session();
const auto content = box->verticalLayout().get(); const auto content = box->verticalLayout().get();
const auto levels = Data::LevelLimits(session) const auto levels = Data::LevelLimits(session)
.channelRestrictSponsoredLevelMin(); .channelRestrictSponsoredLevelMin();
@ -101,7 +103,7 @@ void AboutBox(
st::channelEarnSemiboldLabel), st::channelEarnSemiboldLabel),
padding); padding);
Ui::AddSkip(content, st::channelEarnHistoryThreeSkip); Ui::AddSkip(content, st::channelEarnHistoryThreeSkip);
content->add( const auto label = content->add(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
content, content,
std::move(about), std::move(about),
@ -121,6 +123,7 @@ void AboutBox(
(g.left() - left->width()) / 2, (g.left() - left->width()) / 2,
g.top() + st::channelEarnHistoryThreeSkip); g.top() + st::channelEarnHistoryThreeSkip);
}, left->lifetime()); }, left->lifetime());
return label;
}; };
addEntry( addEntry(
tr::lng_sponsored_revenued_info1_title(), tr::lng_sponsored_revenued_info1_title(),
@ -144,10 +147,14 @@ void AboutBox(
lt_link, lt_link,
tr::lng_settings_privacy_premium_link( tr::lng_settings_privacy_premium_link(
) | rpl::map([=](QString t) { ) | rpl::map([=](QString t) {
return Ui::Text::Link(t, kUrl.utf16()); return Ui::Text::Link(std::move(t), u"internal:"_q);
}), }),
Ui::Text::RichLangValue), Ui::Text::RichLangValue),
st::sponsoredAboutRemoveIcon); st::sponsoredAboutRemoveIcon)->setClickHandlerFilter([=](
const auto &...) {
ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
return true;
});
Ui::AddSkip(content); Ui::AddSkip(content);
Ui::AddSkip(content); Ui::AddSkip(content);
} }
@ -332,16 +339,14 @@ void ShowSponsored(
not_null<HistoryItem*> item) { not_null<HistoryItem*> item) {
Expects(item->isSponsored()); Expects(item->isSponsored());
struct State final { const auto session = &item->history()->session();
};
const auto state = std::make_shared<State>();
const auto menu = Ui::CreateChild<Ui::PopupMenu>( const auto menu = Ui::CreateChild<Ui::PopupMenu>(
parent.get(), parent.get(),
st::popupMenuWithIcons); st::popupMenuWithIcons);
menu->addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] { menu->addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] {
show->show(Box(AboutBox, &item->history()->session())); show->show(Box(AboutBox, show));
}, &st::menuIconInfo); }, &st::menuIconInfo);
menu->addAction(tr::lng_sponsored_menu_revenued_report(tr::now), [=] { menu->addAction(tr::lng_sponsored_menu_revenued_report(tr::now), [=] {
@ -351,7 +356,13 @@ void ShowSponsored(
menu->addSeparator(&st::expandedMenuSeparator); menu->addSeparator(&st::expandedMenuSeparator);
menu->addAction(tr::lng_sponsored_hide_ads(tr::now), [=] { 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); }, &st::menuIconCancel);
menu->popup(QCursor::pos()); menu->popup(QCursor::pos());
@ -359,7 +370,7 @@ void ShowSponsored(
void ShowSponsoredAbout(std::shared_ptr<ChatHelpers::Show> show) { void ShowSponsoredAbout(std::shared_ptr<ChatHelpers::Show> show) {
show->showBox(Box([=](not_null<Ui::GenericBox*> box) { show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
AboutBox(box, &show->session()); AboutBox(box, show);
})); }));
} }

View file

@ -1020,12 +1020,25 @@ void Instance::Private::sendRequest(
const auto signedDcId = toMainDc ? -realShiftedDcId : realShiftedDcId; const auto signedDcId = toMainDc ? -realShiftedDcId : realShiftedDcId;
registerRequest(requestId, signedDcId); registerRequest(requestId, signedDcId);
if (afterRequestId) {
request->after = getRequest(afterRequestId);
}
request->lastSentTime = crl::now(); request->lastSentTime = crl::now();
request->needsLayer = needsLayer; 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); session->sendPrepared(request, msCanWait);
} }

View file

@ -8,11 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "overview/overview_layout.h" #include "overview/overview_layout.h"
#include "overview/overview_layout_delegate.h" #include "overview/overview_layout_delegate.h"
#include "core/ui_integration.h" // Core::MarkedTextContext.
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_document_resolver.h" #include "data/data_document_resolver.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_web_page.h" #include "data/data_web_page.h"
#include "data/data_media_types.h"
#include "data/data_peer.h" #include "data/data_peer.h"
#include "data/data_photo_media.h" #include "data/data_photo_media.h"
#include "data/data_document_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 "ui/boxes/confirm_box.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "layout/layout_selection.h" #include "layout/layout_selection.h"
#include "mainwidget.h"
#include "storage/file_upload.h" #include "storage/file_upload.h"
#include "mainwindow.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "media/audio/media_audio.h" #include "media/audio/media_audio.h"
#include "media/player/media_player_instance.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); p.drawTextLeft(nameleft, statustop, _width, _status.text(), statusw);
unreadx += statusw; unreadx += statusw;
} }
auto captionLeft = unreadx + st::mediaUnreadSkip;
if (parent()->hasUnreadMediaFlag() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) { if (parent()->hasUnreadMediaFlag() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) {
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(selected ? st::msgFileInBgSelected : st::msgFileInBg); 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); PainterHighQualityEnabler hq(p);
p.drawEllipse(style::rtlrect(unreadx + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width)); 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() { void Voice::updateName() {
if (const auto forwarded = parent()->Get<HistoryMessageForwarded>()) { if (const auto forwarded = parent()->Get<HistoryMessageForwarded>()) {
if (parent()->fromOriginal()->isChannel()) { const auto info = parent()->originalHiddenSenderInfo();
_name.setText( const auto name = info
st::semiboldTextStyle, ? tr::lng_forwarded(tr::now, lt_user, info->nameText().toString())
tr::lng_forwarded_channel( : parent()->fromOriginal()->isChannel()
tr::now, ? tr::lng_forwarded_channel(
lt_channel, tr::now,
parent()->fromOriginal()->name()), lt_channel,
Ui::NameTextOptions()); parent()->fromOriginal()->name())
} else { : tr::lng_forwarded(
_name.setText( tr::now,
st::semiboldTextStyle, lt_user,
tr::lng_forwarded( parent()->fromOriginal()->name());
tr::now, _name.setText(st::semiboldTextStyle, name, Ui::NameTextOptions());
lt_user,
parent()->fromOriginal()->name()),
Ui::NameTextOptions());
}
} else { } else {
_name.setText( _name.setText(
st::semiboldTextStyle, st::semiboldTextStyle,
@ -1005,6 +1016,14 @@ void Voice::updateName() {
Ui::NameTextOptions()); Ui::NameTextOptions());
} }
_nameVersion = parent()->fromOriginal()->nameVersion(); _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() { bool Voice::updateStatusText() {

View file

@ -362,7 +362,9 @@ private:
const style::OverviewFileLayout &_st; const style::OverviewFileLayout &_st;
Ui::Text::String _name, _details; Ui::Text::String _name;
Ui::Text::String _details;
Ui::Text::String _caption;
int _nameVersion = 0; int _nameVersion = 0;
void updateName(); void updateName();

View file

@ -70,8 +70,8 @@ Panel::Progress::Progress(QWidget *parent, Fn<QRect()> rect)
Panel::Panel(not_null<PanelDelegate*> delegate) Panel::Panel(not_null<PanelDelegate*> delegate)
: _delegate(delegate) : _delegate(delegate)
, _widget(std::make_unique<SeparatePanel>()) { , _widget(std::make_unique<SeparatePanel>()) {
_widget->setInnerSize(st::paymentsPanelSize);
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false); _widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
_widget->setInnerSize(st::paymentsPanelSize);
_widget->closeRequests( _widget->closeRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
@ -534,12 +534,15 @@ bool Panel::createWebview(const Webview::ThemeParams &params) {
const auto bottom = _webviewBottom.get(); const auto bottom = _webviewBottom.get();
bottom->show(); bottom->show();
bottom->heightValue( rpl::combine(
) | rpl::start_with_next([=](int height) { container->geometryValue() | rpl::map([=] {
const auto inner = _widget->innerGeometry(); return _widget->innerGeometry();
}),
bottom->heightValue()
) | rpl::start_with_next([=](QRect inner, int height) {
bottom->move(inner.x(), inner.y() + inner.height() - height); bottom->move(inner.x(), inner.y() + inner.height() - height);
container->resize(inner.width(), inner.height() - height);
bottom->resizeToWidth(inner.width()); bottom->resizeToWidth(inner.width());
_footerHeight = bottom->height();
}, bottom->lifetime()); }, bottom->lifetime());
container->show(); container->show();
@ -584,10 +587,12 @@ bool Panel::createWebview(const Webview::ThemeParams &params) {
}); });
}); });
container->geometryValue( rpl::combine(
) | rpl::start_with_next([=](QRect geometry) { container->geometryValue(),
if (raw->widget()) { _footerHeight.value()
raw->widget()->setGeometry(geometry); ) | rpl::start_with_next([=](QRect geometry, int footer) {
if (const auto view = raw->widget()) {
view->setGeometry(geometry.marginsRemoved({ 0, 0, 0, footer }));
} }
}, _webview->lifetime); }, _webview->lifetime);

View file

@ -115,11 +115,13 @@ private:
[[nodiscard]] bool progressWithBackground() const; [[nodiscard]] bool progressWithBackground() const;
[[nodiscard]] QRect progressRect() const; [[nodiscard]] QRect progressRect() const;
void setupProgressGeometry(); void setupProgressGeometry();
void updateFooterHeight();
const not_null<PanelDelegate*> _delegate; const not_null<PanelDelegate*> _delegate;
std::unique_ptr<SeparatePanel> _widget; std::unique_ptr<SeparatePanel> _widget;
std::unique_ptr<WebviewWithLifetime> _webview; std::unique_ptr<WebviewWithLifetime> _webview;
std::unique_ptr<RpWidget> _webviewBottom; std::unique_ptr<RpWidget> _webviewBottom;
rpl::variable<int> _footerHeight;
std::unique_ptr<Progress> _progress; std::unique_ptr<Progress> _progress;
QPointer<Checkbox> _saveWebviewInformation; QPointer<Checkbox> _saveWebviewInformation;
QPointer<FormSummary> _weakFormSummary; QPointer<FormSummary> _weakFormSummary;

View file

@ -17,7 +17,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/random.h" #include "base/random.h"
#include <QtCore/QAbstractEventDispatcher> #include <QtCore/QAbstractEventDispatcher>
#include <qpa/qwindowsysteminterface.h>
#include <gio/gio.hpp> #include <gio/gio.hpp>
#include <xdpinhibit/xdpinhibit.hpp> #include <xdpinhibit/xdpinhibit.hpp>
@ -190,23 +189,24 @@ private:
const gi::ref_ptr<Application> _application; const gi::ref_ptr<Application> _application;
XdpInhibit::InhibitProxy _inhibitProxy; XdpInhibit::InhibitProxy _inhibitProxy;
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
base::Platform::XDP::SettingWatcher _darkModeWatcher; base::Platform::XDP::SettingWatcher _darkModeWatcher;
#endif // Qt < 6.5.0
}; };
LinuxIntegration::LinuxIntegration() LinuxIntegration::LinuxIntegration()
: _application(MakeApplication()) : _application(MakeApplication())
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
, _darkModeWatcher( , _darkModeWatcher(
"org.freedesktop.appearance", "org.freedesktop.appearance",
"color-scheme", "color-scheme",
[](GLib::Variant value) { [](GLib::Variant value) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
QWindowSystemInterface::handleThemeChange();
#else // Qt >= 6.5.0
Core::Sandbox::Instance().customEnterFromEventLoop([&] { Core::Sandbox::Instance().customEnterFromEventLoop([&] {
Core::App().settings().setSystemDarkMode(value.get_uint32() == 1); Core::App().settings().setSystemDarkMode(value.get_uint32() == 1);
}); });
})
#endif // Qt < 6.5.0 #endif // Qt < 6.5.0
}) { {
LOG(("Icon theme: %1").arg(QIcon::themeName())); LOG(("Icon theme: %1").arg(QIcon::themeName()));
LOG(("Fallback icon theme: %1").arg(QIcon::fallbackThemeName())); LOG(("Fallback icon theme: %1").arg(QIcon::fallbackThemeName()));

View file

@ -20,8 +20,6 @@ class MainWindow : public Window::MainWindow {
public: public:
explicit MainWindow(not_null<Window::Controller*> controller); explicit MainWindow(not_null<Window::Controller*> controller);
bool psFilterNativeEvent(void *event);
int getCustomTitleHeight() const { int getCustomTitleHeight() const {
return _customTitleHeight; return _customTitleHeight;
} }
@ -47,6 +45,11 @@ protected:
private: private:
friend class Private; friend class Private;
bool nativeEvent(
const QByteArray &eventType,
void *message,
qintptr *result) override;
void hideAndDeactivate(); void hideAndDeactivate();
void updateDockCounter(); void updateDockCounter();

View file

@ -63,6 +63,26 @@ namespace {
// fullscreen mode, after that we'll hide the window no matter what. // fullscreen mode, after that we'll hide the window no matter what.
constexpr auto kHideAfterFullscreenTimeoutMs = 3000; constexpr auto kHideAfterFullscreenTimeoutMs = 3000;
[[nodiscard]] bool PossiblyTextTypingEvent(NSEvent *e) {
if ([e type] != NSEventTypeKeyDown) {
return false;
}
NSEventModifierFlags flags = [e modifierFlags]
& NSEventModifierFlagDeviceIndependentFlagsMask;
if ((flags & ~NSEventModifierFlagShift) != 0) {
return false;
}
NSString *text = [e characters];
const auto length = int([text length]);
for (auto i = 0; i != length; ++i) {
const auto utf16 = [text characterAtIndex:i];
if (utf16 >= 32) {
return true;
}
}
return false;
}
} // namespace } // namespace
class MainWindow::Private { class MainWindow::Private {
@ -280,6 +300,21 @@ void MainWindow::initHook() {
void MainWindow::updateWindowIcon() { void MainWindow::updateWindowIcon() {
} }
bool MainWindow::nativeEvent(
const QByteArray &eventType,
void *message,
qintptr *result) {
if (message && eventType == "NSEvent") {
const auto event = static_cast<NSEvent*>(message);
if (PossiblyTextTypingEvent(event)) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
imeCompositionStartReceived();
});
}
}
return false;
}
void MainWindow::hideAndDeactivate() { void MainWindow::hideAndDeactivate() {
hide(); hide();
} }

View file

@ -550,6 +550,12 @@ void Manager::Private::checkFocusState() {
} }
Manager::Private::~Private() { Manager::Private::~Private() {
if (_waitingDnd) {
_dnd.kill();
}
if (_waitingFocus) {
_focus.kill();
}
if (_clearingThread.joinable()) { if (_clearingThread.joinable()) {
putClearTask(ClearFinish()); putClearTask(ClearFinish());
_clearingThread.join(); _clearingThread.join();

View file

@ -480,6 +480,21 @@ bool MainWindow::initGeometryFromSystem() {
return true; return true;
} }
bool MainWindow::nativeEvent(
const QByteArray &eventType,
void *message,
long *result) {
if (message) {
const auto msg = static_cast<MSG*>(message);
if (msg->message == WM_IME_STARTCOMPOSITION) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
imeCompositionStartReceived();
});
}
}
return false;
}
void MainWindow::updateWindowIcon() { void MainWindow::updateWindowIcon() {
updateTaskbarAndIconCounters(); updateTaskbarAndIconCounters();
} }

View file

@ -48,6 +48,11 @@ protected:
bool initGeometryFromSystem() override; bool initGeometryFromSystem() override;
bool nativeEvent(
const QByteArray &eventType,
void *message,
long *result) override;
private: private:
struct Private; struct Private;

View file

@ -238,7 +238,8 @@ private:
void edit( void edit(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
Api::SendOptions options, Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId); mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride);
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos); void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Type sendMenuType() const;
[[nodiscard]] FullReplyTo replyTo() const; [[nodiscard]] FullReplyTo replyTo() const;
@ -673,7 +674,8 @@ void ShortcutMessages::setupComposeControls() {
) | rpl::start_with_next([=](auto data) { ) | rpl::start_with_next([=](auto data) {
if (const auto item = _session->data().message(data.fullId)) { if (const auto item = _session->data().message(data.fullId)) {
if (item->isBusinessShortcut()) { if (item->isBusinessShortcut()) {
edit(item, data.options, saveEditMsgRequestId); const auto spoiler = data.spoilerMediaOverride;
edit(item, data.options, saveEditMsgRequestId, spoiler);
} }
} }
}, lifetime()); }, lifetime());
@ -1213,7 +1215,8 @@ void ShortcutMessages::send(Api::SendOptions options) {
void ShortcutMessages::edit( void ShortcutMessages::edit(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
Api::SendOptions options, Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId) { mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride) {
if (*saveEditMsgRequestId) { if (*saveEditMsgRequestId) {
return; return;
} }
@ -1281,7 +1284,8 @@ void ShortcutMessages::edit(
webpage, webpage,
options, options,
crl::guard(this, done), crl::guard(this, done),
crl::guard(this, fail)); crl::guard(this, fail),
spoilerMediaOverride);
_composeControls->hidePanelsAnimated(); _composeControls->hidePanelsAnimated();
doSetInnerFocus(); doSetInnerFocus();

View file

@ -1654,7 +1654,8 @@ void SetupThemeSettings(
AddPeerColorButton( AddPeerColorButton(
container, container,
controller->uiShow(), controller->uiShow(),
controller->session().user()); controller->session().user(),
st::settingsColorButton);
const auto settings = &Core::App().settings(); const auto settings = &Core::App().settings();
if (settings->systemDarkMode().has_value()) { if (settings->systemDarkMode().has_value()) {

View file

@ -400,7 +400,7 @@ bool ReadSetting(
stream >> v; stream >> v;
if (!CheckStreamStatus(stream)) return false; if (!CheckStreamStatus(stream)) return false;
Core::App().settings().setDialogsWidthRatio(v / 1000000.); Core::App().settings().updateDialogsWidthRatio(v / 1000000., false);
context.legacyRead = true; context.legacyRead = true;
} break; } break;

View file

@ -546,15 +546,25 @@ std::vector<Selector::Entry> Selector::FullList(const QString &now) {
result.push_back({ .id = family }); result.push_back({ .id = family });
} }
} }
if (!ranges::contains(result, now, &Entry::id)) { auto nowIt = ranges::find(result, now, &Entry::id);
if (nowIt == end(result)) {
result.push_back({ .id = now }); result.push_back({ .id = now });
nowIt = end(result) - 1;
} }
for (auto i = begin(result) + 2; i != end(result); ++i) { for (auto i = begin(result) + 2; i != end(result); ++i) {
i->key = TextUtilities::RemoveAccents(i->id).toLower(); i->key = TextUtilities::RemoveAccents(i->id).toLower();
i->text = i->id; i->text = i->id;
i->keywords = TextUtilities::PrepareSearchWords(i->id); i->keywords = TextUtilities::PrepareSearchWords(i->id);
} }
ranges::sort(begin(result) + 2, end(result), std::less<>(), &Entry::key); auto skip = 2;
if (nowIt - begin(result) >= skip) {
std::swap(result[2], *nowIt);
++skip;
}
ranges::sort(
begin(result) + skip, end(result),
std::less<>(),
&Entry::key);
return result; return result;
} }

View file

@ -323,8 +323,8 @@ Panel::Panel(
, _menuButtons(menuButtons) , _menuButtons(menuButtons)
, _widget(std::make_unique<SeparatePanel>()) , _widget(std::make_unique<SeparatePanel>())
, _allowClipboardRead(allowClipboardRead) { , _allowClipboardRead(allowClipboardRead) {
_widget->setInnerSize(st::botWebViewPanelSize);
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false); _widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
_widget->setInnerSize(st::botWebViewPanelSize);
_widget->closeRequests( _widget->closeRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
@ -505,7 +505,7 @@ bool Panel::showWebview(
_webview->window.navigate(url); _webview->window.navigate(url);
_widget->setBackAllowed(allowBack); _widget->setBackAllowed(allowBack);
_widget->setMenuAllowed([=](const Ui::Menu::MenuCallback &callback) { _widget->setMenuAllowed([=](const Ui::Menu::MenuCallback &callback) {
if (_hasSettingsButton) { if (_webview && _webview->window.widget() && _hasSettingsButton) {
callback(tr::lng_bot_settings(tr::now), [=] { callback(tr::lng_bot_settings(tr::now), [=] {
postEvent("settings_button_pressed"); postEvent("settings_button_pressed");
}, &st::menuIconSettings); }, &st::menuIconSettings);
@ -570,17 +570,15 @@ void Panel::createWebviewBottom() {
label->show(); label->show();
_webviewBottom->resize(_webviewBottom->width(), height); _webviewBottom->resize(_webviewBottom->width(), height);
bottom->heightValue( rpl::combine(
) | rpl::start_with_next([=](int height) { _webviewParent->geometryValue() | rpl::map([=] {
const auto inner = _widget->innerGeometry(); return _widget->innerGeometry();
if (_mainButton && !_mainButton->isHidden()) { }),
height = _mainButton->height(); bottom->heightValue()
} ) | rpl::start_with_next([=](QRect inner, int height) {
bottom->move(inner.x(), inner.y() + inner.height() - height); bottom->move(inner.x(), inner.y() + inner.height() - height);
if (const auto container = _webviewParent.data()) {
container->setFixedSize(inner.width(), inner.height() - height);
}
bottom->resizeToWidth(inner.width()); bottom->resizeToWidth(inner.width());
updateFooterHeight();
}, bottom->lifetime()); }, bottom->lifetime());
} }
@ -636,10 +634,13 @@ bool Panel::createWebview(const Webview::ThemeParams &params) {
}); });
}); });
container->geometryValue( updateFooterHeight();
) | rpl::start_with_next([=](QRect geometry) { rpl::combine(
if (raw->widget()) { container->geometryValue(),
raw->widget()->setGeometry(geometry); _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); }, _webview->lifetime);
@ -1185,22 +1186,25 @@ void Panel::createMainButton() {
button->hide(); button->hide();
rpl::combine( rpl::combine(
_webviewParent->geometryValue() | rpl::map([=] {
return _widget->innerGeometry();
}),
button->shownValue(), button->shownValue(),
button->heightValue() button->heightValue()
) | rpl::start_with_next([=](bool shown, int height) { ) | rpl::start_with_next([=](QRect inner, bool shown, int height) {
const auto inner = _widget->innerGeometry();
if (!shown) {
height = _webviewBottom->height();
}
button->move(inner.x(), inner.y() + inner.height() - height); button->move(inner.x(), inner.y() + inner.height() - height);
if (const auto raw = _webviewParent.data()) {
raw->setFixedSize(inner.width(), inner.height() - height);
}
button->resizeToWidth(inner.width()); button->resizeToWidth(inner.width());
_webviewBottom->setVisible(!shown); _webviewBottom->setVisible(!shown);
updateFooterHeight();
}, button->lifetime()); }, button->lifetime());
} }
void Panel::updateFooterHeight() {
_footerHeight = (_mainButton && !_mainButton->isHidden())
? _mainButton->height()
: _webviewBottom->height();
}
void Panel::showBox(object_ptr<BoxContent> box) { void Panel::showBox(object_ptr<BoxContent> box) {
if (const auto widget = _webview ? _webview->window.widget() : nullptr) { if (const auto widget = _webview ? _webview->window.widget() : nullptr) {
const auto hideNow = !widget->isHidden(); const auto hideNow = !widget->isHidden();
@ -1290,6 +1294,11 @@ void Panel::postEvent(const QString &event) {
} }
void Panel::postEvent(const QString &event, EventData data) { void Panel::postEvent(const QString &event, EventData data) {
if (!_webview) {
LOG(("BotWebView Error: Post event \"%1\" on crashed webview."
).arg(event));
return;
}
auto written = v::is<QString>(data) auto written = v::is<QString>(data)
? v::get<QString>(data).toUtf8() ? v::get<QString>(data).toUtf8()
: QJsonDocument( : QJsonDocument(

View file

@ -143,6 +143,7 @@ private:
[[nodiscard]] bool progressWithBackground() const; [[nodiscard]] bool progressWithBackground() const;
[[nodiscard]] QRect progressRect() const; [[nodiscard]] QRect progressRect() const;
void setupProgressGeometry(); void setupProgressGeometry();
void updateFooterHeight();
Webview::StorageId _storageId; Webview::StorageId _storageId;
const not_null<Delegate*> _delegate; const not_null<Delegate*> _delegate;
@ -153,9 +154,10 @@ private:
std::unique_ptr<WebviewWithLifetime> _webview; std::unique_ptr<WebviewWithLifetime> _webview;
std::unique_ptr<RpWidget> _webviewBottom; std::unique_ptr<RpWidget> _webviewBottom;
rpl::variable<QString> _bottomText; rpl::variable<QString> _bottomText;
QPointer<QWidget> _webviewParent; QPointer<RpWidget> _webviewParent;
std::unique_ptr<Button> _mainButton; std::unique_ptr<Button> _mainButton;
mutable crl::time _mainButtonLastClick = 0; mutable crl::time _mainButtonLastClick = 0;
rpl::variable<int> _footerHeight = 0;
std::unique_ptr<Progress> _progress; std::unique_ptr<Progress> _progress;
rpl::event_stream<> _themeUpdateForced; rpl::event_stream<> _themeUpdateForced;
rpl::lifetime _headerColorLifetime; rpl::lifetime _headerColorLifetime;

View file

@ -788,10 +788,18 @@ void MainWindow::setPositionInited() {
_positionInited = true; _positionInited = true;
} }
void MainWindow::imeCompositionStartReceived() {
_imeCompositionStartReceived.fire({});
}
rpl::producer<> MainWindow::leaveEvents() const { rpl::producer<> MainWindow::leaveEvents() const {
return _leaveEvents.events(); return _leaveEvents.events();
} }
rpl::producer<> MainWindow::imeCompositionStarts() const {
return _imeCompositionStartReceived.events();
}
void MainWindow::leaveEventHook(QEvent *e) { void MainWindow::leaveEventHook(QEvent *e) {
_leaveEvents.fire({}); _leaveEvents.fire({});
} }

View file

@ -119,7 +119,8 @@ public:
void launchDrag(std::unique_ptr<QMimeData> data, Fn<void()> &&callback); void launchDrag(std::unique_ptr<QMimeData> data, Fn<void()> &&callback);
rpl::producer<> leaveEvents() const; [[nodiscard]] rpl::producer<> leaveEvents() const;
[[nodiscard]] rpl::producer<> imeCompositionStarts() const;
virtual void updateWindowIcon() = 0; virtual void updateWindowIcon() = 0;
void updateTitle(); void updateTitle();
@ -185,6 +186,7 @@ protected:
return false; return false;
} }
void imeCompositionStartReceived();
void setPositionInited(); void setPositionInited();
virtual QRect computeDesktopRect() const; virtual QRect computeDesktopRect() const;
@ -214,6 +216,7 @@ private:
bool _isActive = false; bool _isActive = false;
rpl::event_stream<> _leaveEvents; rpl::event_stream<> _leaveEvents;
rpl::event_stream<> _imeCompositionStartReceived;
bool _maximizedBeforeHide = false; bool _maximizedBeforeHide = false;

View file

@ -1954,7 +1954,10 @@ int SessionController::countDialogsWidthFromRatio(int bodyWidth) const {
if (!_isPrimary) { if (!_isPrimary) {
return 0; return 0;
} }
auto result = qRound(bodyWidth * Core::App().settings().dialogsWidthRatio()); const auto nochat = !mainSectionShown();
const auto width = bodyWidth
* Core::App().settings().dialogsWidthRatio(nochat);
auto result = qRound(width);
accumulate_max(result, st::columnMinimalWidthLeft); accumulate_max(result, st::columnMinimalWidthLeft);
// accumulate_min(result, st::columnMaximalWidthLeft); // accumulate_min(result, st::columnMaximalWidthLeft);
return result; return result;
@ -2043,10 +2046,12 @@ void SessionController::resizeForThirdSection() {
if (extendBy != settings.thirdColumnWidth()) { if (extendBy != settings.thirdColumnWidth()) {
settings.setThirdColumnWidth(extendBy); settings.setThirdColumnWidth(extendBy);
} }
const auto nochat = !mainSectionShown();
auto newBodyWidth = layout.bodyWidth + extendedBy; auto newBodyWidth = layout.bodyWidth + extendedBy;
auto currentRatio = settings.dialogsWidthRatio(); auto currentRatio = settings.dialogsWidthRatio(nochat);
settings.setDialogsWidthRatio( settings.updateDialogsWidthRatio(
(currentRatio * layout.bodyWidth) / newBodyWidth); (currentRatio * layout.bodyWidth) / newBodyWidth,
nochat);
} }
auto savedValue = (extendedBy == extendBy) ? -1 : extendedBy; auto savedValue = (extendedBy == extendBy) ? -1 : extendedBy;
settings.setThirdSectionExtendedBy(savedValue); settings.setThirdSectionExtendedBy(savedValue);
@ -2062,6 +2067,7 @@ void SessionController::closeThirdSection() {
auto newWindowSize = widget()->size(); auto newWindowSize = widget()->size();
auto layout = computeColumnLayout(); auto layout = computeColumnLayout();
if (layout.windowLayout == Adaptive::WindowLayout::ThreeColumn) { if (layout.windowLayout == Adaptive::WindowLayout::ThreeColumn) {
const auto nochat = !mainSectionShown();
auto noResize = widget()->isFullScreen() auto noResize = widget()->isFullScreen()
|| widget()->isMaximized(); || widget()->isMaximized();
auto savedValue = settings.thirdSectionExtendedBy(); auto savedValue = settings.thirdSectionExtendedBy();
@ -2071,9 +2077,10 @@ void SessionController::closeThirdSection() {
auto newBodyWidth = noResize auto newBodyWidth = noResize
? layout.bodyWidth ? layout.bodyWidth
: (layout.bodyWidth - extendedBy); : (layout.bodyWidth - extendedBy);
auto currentRatio = settings.dialogsWidthRatio(); auto currentRatio = settings.dialogsWidthRatio(nochat);
settings.setDialogsWidthRatio( settings.updateDialogsWidthRatio(
(currentRatio * layout.bodyWidth) / newBodyWidth); (currentRatio * layout.bodyWidth) / newBodyWidth,
nochat);
newWindowSize = QSize( newWindowSize = QSize(
widget()->width() + (newBodyWidth - layout.bodyWidth), widget()->width() + (newBodyWidth - layout.bodyWidth),
widget()->height()); widget()->height());

View file

@ -515,6 +515,16 @@ public:
std::optional<bool> show = std::nullopt) const; std::optional<bool> show = std::nullopt) const;
void finishChatThemeEdit(not_null<PeerData*> peer); void finishChatThemeEdit(not_null<PeerData*> peer);
[[nodiscard]] bool mainSectionShown() const {
return _mainSectionShown.current();
}
[[nodiscard]] rpl::producer<bool> mainSectionShownChanges() const {
return _mainSectionShown.changes();
}
void setMainSectionShown(bool value) {
_mainSectionShown = value;
}
[[nodiscard]] bool chatsForceDisplayWide() const { [[nodiscard]] bool chatsForceDisplayWide() const {
return _chatsForceDisplayWide.current(); return _chatsForceDisplayWide.current();
} }
@ -678,6 +688,7 @@ private:
rpl::variable<Dialogs::Key> _searchInChat; rpl::variable<Dialogs::Key> _searchInChat;
rpl::variable<Dialogs::RowDescriptor> _activeChatEntry; rpl::variable<Dialogs::RowDescriptor> _activeChatEntry;
rpl::lifetime _activeHistoryLifetime; rpl::lifetime _activeHistoryLifetime;
rpl::variable<bool> _mainSectionShown = false;
rpl::variable<bool> _chatsForceDisplayWide = false; rpl::variable<bool> _chatsForceDisplayWide = false;
std::deque<Dialogs::RowDescriptor> _chatEntryHistory; std::deque<Dialogs::RowDescriptor> _chatEntryHistory;
int _chatEntryHistoryPosition = -1; int _chatEntryHistoryPosition = -1;

View file

@ -1,6 +1,6 @@
{%- set GIT = "https://github.com" -%} {%- set GIT = "https://github.com" -%}
{%- set GIT_FREEDESKTOP = GIT ~ "/gitlab-freedesktop-mirrors" -%} {%- set GIT_FREEDESKTOP = GIT ~ "/gitlab-freedesktop-mirrors" -%}
{%- set QT = "6.7.0" -%} {%- set QT = "6.7.1" -%}
{%- set QT_TAG = "v" ~ QT -%} {%- set QT_TAG = "v" ~ QT -%}
{%- set CMAKE_VER = "3.27.6" -%} {%- set CMAKE_VER = "3.27.6" -%}
{%- set CMAKE_FILE = "cmake-" ~ CMAKE_VER ~ "-Linux-x86_64.sh" -%} {%- set CMAKE_FILE = "cmake-" ~ CMAKE_VER ~ "-Linux-x86_64.sh" -%}
@ -51,7 +51,7 @@ FROM builder AS patches
RUN git init patches \ RUN git init patches \
&& cd patches \ && cd patches \
&& git remote add origin {{ GIT }}/desktop-app/patches.git \ && git remote add origin {{ GIT }}/desktop-app/patches.git \
&& git fetch --depth=1 origin 44f5103860dfa3f9b9675730231af6fbe28cde93 \ && git fetch --depth=1 origin 803f1c2630f5eb0d3b00ba3f095b3079c0533156 \
&& git reset --hard FETCH_HEAD \ && git reset --hard FETCH_HEAD \
&& rm -rf .git && rm -rf .git

View file

@ -1,14 +1,14 @@
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
[[package]] [[package]]
name = "jinja2" name = "jinja2"
version = "3.1.3" version = "3.1.4"
description = "A very fast and expressive template engine." description = "A very fast and expressive template engine."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
{file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
] ]
[package.dependencies] [package.dependencies]
@ -69,4 +69,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.7" python-versions = "^3.7"
content-hash = "bac9a23a86839c72127e75f2cf181e331f59d96f723403d529e7ea19774ff9c4" content-hash = "dcdc36798334f1f85051cf78d7f8a7242a480509eb34135934d9f092d2da5c33"

View file

@ -6,7 +6,7 @@ authors = []
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.7" python = "^3.7"
Jinja2 = "^3.1.3" Jinja2 = "^3.1.4"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]

View file

@ -435,7 +435,7 @@ if customRunCommand:
stage('patches', """ stage('patches', """
git clone https://github.com/desktop-app/patches.git git clone https://github.com/desktop-app/patches.git
cd patches cd patches
git checkout 5d64e21844 git checkout 25f76cf4d5
""") """)
stage('msys64', """ stage('msys64', """
@ -593,25 +593,25 @@ stage('openssl3', """
git clone -b openssl-3.2.1 https://github.com/openssl/openssl openssl3 git clone -b openssl-3.2.1 https://github.com/openssl/openssl openssl3
cd openssl3 cd openssl3
win32: win32:
perl Configure no-shared no-tests debug-VC-WIN32 perl Configure no-shared no-tests debug-VC-WIN32 /FS
win64: win64:
perl Configure no-shared no-tests debug-VC-WIN64A perl Configure no-shared no-tests debug-VC-WIN64A /FS
win: win:
nmake jom -j%NUMBER_OF_PROCESSORS%
mkdir out.dbg mkdir out.dbg
move libcrypto.lib out.dbg move libcrypto.lib out.dbg
move libssl.lib out.dbg move libssl.lib out.dbg
move ossl_static.pdb out.dbg move ossl_static.pdb out.dbg
release: release:
move out.dbg\\ossl_static.pdb out.dbg\\ossl_static move out.dbg\\ossl_static.pdb out.dbg\\ossl_static
nmake clean jom clean
move out.dbg\\ossl_static out.dbg\\ossl_static.pdb move out.dbg\\ossl_static out.dbg\\ossl_static.pdb
win32: win32:
perl Configure no-shared no-tests VC-WIN32 perl Configure no-shared no-tests VC-WIN32 /FS
win64: win64:
perl Configure no-shared no-tests VC-WIN64A perl Configure no-shared no-tests VC-WIN64A /FS
win: win:
nmake jom -j%NUMBER_OF_PROCESSORS%
mkdir out mkdir out
move libcrypto.lib out move libcrypto.lib out
move libssl.lib out move libssl.lib out

View file

@ -1,7 +1,7 @@
AppVersion 5000001 AppVersion 5000002
AppVersionStrMajor 5.0 AppVersionStrMajor 5.0
AppVersionStrSmall 5.0.1 AppVersionStrSmall 5.0.2
AppVersionStr 5.0.1 AppVersionStr 5.0.2
BetaChannel 0 BetaChannel 0
AlphaVersion 0 AlphaVersion 0
AppVersionOriginal 5.0.1 AppVersionOriginal 5.0.2

@ -1 +1 @@
Subproject commit d4e5c298fc50f0b7cdd90e9998e71f6aa8f1c5e9 Subproject commit e2c62ef0b4581d84e4ff79623a7e5e9ed315bad7

@ -1 +1 @@
Subproject commit 1cbf5fa7d875074c40e76216a3047bd7c59996d7 Subproject commit f701713cd798bd7d5f69d318fdefb125d101aa76

Some files were not shown because too many files have changed in this diff Show more