mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
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:
commit
57b2c69ce6
104 changed files with 1362 additions and 367 deletions
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
4
.github/workflows/docker.yml
vendored
4
.github/workflows/docker.yml
vendored
|
@ -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: |
|
||||||
|
|
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
|
@ -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:
|
||||||
|
|
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
|
@ -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
|
||||||
|
|
8
.github/workflows/mac.yml
vendored
8
.github/workflows/mac.yml
vendored
|
@ -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:
|
||||||
|
|
6
.github/workflows/mac_packaged.yml
vendored
6
.github/workflows/mac_packaged.yml
vendored
|
@ -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:
|
||||||
|
|
2
.github/workflows/master_updater.yml
vendored
2
.github/workflows/master_updater.yml
vendored
|
@ -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'
|
||||||
|
|
6
.github/workflows/snap.yml
vendored
6
.github/workflows/snap.yml
vendored
|
@ -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:
|
||||||
|
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
|
@ -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!
|
||||||
|
|
8
.github/workflows/win.yml
vendored
8
.github/workflows/win.yml
vendored
|
@ -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
1
.gitignore
vendored
|
@ -18,6 +18,7 @@ Release/
|
||||||
*.xcodeproj
|
*.xcodeproj
|
||||||
ipch/
|
ipch/
|
||||||
.vs/
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
/Telegram/log.txt
|
/Telegram/log.txt
|
||||||
/Telegram/data
|
/Telegram/data
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 };
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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 ¶ms) {
|
const Window::SectionShow ¶ms) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ public:
|
||||||
not_null<Data::Forum*> forum,
|
not_null<Data::Forum*> forum,
|
||||||
const Window::SectionShow ¶ms);
|
const Window::SectionShow ¶ms);
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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.");
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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())) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ¶ms);
|
const SectionShow ¶ms);
|
||||||
void dropMainSection(Window::SectionWidget *widget);
|
|
||||||
|
|
||||||
Window::SectionSlideParams prepareThirdSectionAnimation(Window::SectionWidget *section);
|
Window::SectionSlideParams prepareThirdSectionAnimation(Window::SectionWidget *section);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 ¶ms) {
|
||||||
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 ¶ms) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 ¶ms) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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({});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
10
Telegram/build/docker/centos_env/poetry.lock
generated
10
Telegram/build/docker/centos_env/poetry.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -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]
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue