mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 23:12:10 +00:00
Compare commits
132 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5566a8ca0a | |||
| f5470cd235 | |||
| 1c275caf9d | |||
| 39e3fcb553 | |||
| 11abaac7c1 | |||
| b054093899 | |||
| 7d57e52469 | |||
| a0c787468b | |||
| 3f79ccbcaf | |||
| b6c966f18b | |||
| 1c85a81f1f | |||
| b4c5963a1a | |||
| 299833ca3d | |||
| a48534b51a | |||
| daec2545b4 | |||
| 5234c8af1a | |||
| 80cadf8f7d | |||
| 7cc14bda52 | |||
| c55cab3b1a | |||
| 77d20c11a7 | |||
| fe1babe437 | |||
| 60a96bf9d6 | |||
| 78c8d0562b | |||
| bb0280f096 | |||
| 566b53ce9f | |||
| ec95db0945 | |||
| a0d7d07543 | |||
| fe73bf9053 | |||
| 49c9e08b6c | |||
| abcf55c498 | |||
| 849ce310c4 | |||
| a3e593b747 | |||
| 5433f95eda | |||
| 0459196982 | |||
| 6f1457d30d | |||
| ce596e29c4 | |||
| 86b9d16747 | |||
| 06911ae42a | |||
| af2cb9b757 | |||
| 6a28cd1a35 | |||
| f4a09a9ca0 | |||
| a35f020f56 | |||
| 3d48111368 | |||
| 39ed7d7f4c | |||
| abe83ccb8f | |||
| d1be7c1ff7 | |||
| 1c223e570a | |||
| a37cbd7d05 | |||
| 7ffa9844e2 | |||
| bdf5872f04 | |||
| da1909cc1d | |||
| a503197352 | |||
| d9d9a8f49d | |||
| 6a02bd66a9 | |||
| f57e2edf2a | |||
| a1e2e3d011 | |||
| 5e546d1198 | |||
| 90405f3ebc | |||
| 11b57ff7d3 | |||
| fe06cd63ac | |||
| 6c9d5e1499 | |||
| 6ed910de9f | |||
| a506b8b25c | |||
| 170ebb57c6 | |||
| 29dd574e22 | |||
| 72770aa76d | |||
| 7f1c319aee | |||
| 60805bd916 | |||
| 10272ee0cf | |||
| 7c44cda76e | |||
| 0152d2c48e | |||
| c5febce548 | |||
| 129b07c2c0 | |||
| 47bf099b88 | |||
| 94f1d23788 | |||
| 84ce72ec7a | |||
| 3da8351522 | |||
| 542153d950 | |||
| 090fdfb458 | |||
| 77835a43a5 | |||
| 1a2a1f1c17 | |||
| eaaa704fa4 | |||
| 7803f8e670 | |||
| f36e3c213e | |||
| 6fb1e23ed5 | |||
| 86d0c49e44 | |||
| 9251e6faba | |||
| 8f8725e1af | |||
| 0ce6a4cbdb | |||
| ad3f705f50 | |||
| c5847caa91 | |||
| 8df6d9db7e | |||
| a9c1970f41 | |||
| c3f0d2ef31 | |||
| 0dcc439dda | |||
| 5b0cac47ad | |||
| b39e78a4a9 | |||
| 690d52f7bc | |||
| 23883ed4a1 | |||
| ea178862d8 | |||
| 09f07a7a9d | |||
| f6f8eefaa0 | |||
| ede6e18bc9 | |||
| 36cb28d5cf | |||
| 9464f4b095 | |||
| b31d43cbed | |||
| 2a388ae4b2 | |||
| d675e31a51 | |||
| e32de38d04 | |||
| 154753c732 | |||
| 53b75c8ea4 | |||
| 776e80b4d6 | |||
| b09cede008 | |||
| e2a0483b9f | |||
| aaaeea2979 | |||
| 91f8989f70 | |||
| ae36019ba9 | |||
| 1e0002aa74 | |||
| 1061fb6c85 | |||
| 22f504ca21 | |||
| a74c5ee719 | |||
| ef04ed447f | |||
| c678973119 | |||
| 587b07a648 | |||
| 7fa3c6f8e8 | |||
| 9957678fb7 | |||
| 971803803c | |||
| 8ab118a8e9 | |||
| 1da9df690f | |||
| 615ad85d26 | |||
| e02b60d8fa | |||
| 3fc4030ca6 |
@@ -52,7 +52,7 @@ jobs:
|
||||
- "DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION"
|
||||
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
UPLOAD_ARTIFACT: "true"
|
||||
|
||||
steps:
|
||||
- name: Get repository name.
|
||||
@@ -115,8 +115,8 @@ jobs:
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
run: |
|
||||
cd $REPO_NAME/out/Debug
|
||||
mkdir artifact
|
||||
mv {Telegram,Updater} artifact/
|
||||
sudo mkdir artifact
|
||||
sudo mv {Telegram,Updater} artifact/
|
||||
- uses: actions/upload-artifact@master
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
name: Upload artifact.
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
defines:
|
||||
- ""
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
UPLOAD_ARTIFACT: "true"
|
||||
ONLY_CACHE: "false"
|
||||
PREPARE_PATH: "Telegram/build/prepare/prepare.py"
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
env:
|
||||
GIT: "https://github.com"
|
||||
OPENALDIR: "/usr/local/opt/openal-soft"
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
UPLOAD_ARTIFACT: "true"
|
||||
ONLY_CACHE: "false"
|
||||
MANUAL_CACHING: "1"
|
||||
AUTO_CACHING: "1"
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
UPLOAD_ARTIFACT: "true"
|
||||
|
||||
steps:
|
||||
- name: Clone.
|
||||
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
generator: ["", "Ninja Multi-Config"]
|
||||
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
UPLOAD_ARTIFACT: "true"
|
||||
ONLY_CACHE: "false"
|
||||
PREPARE_PATH: "Telegram/build/prepare/prepare.py"
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@
|
||||
[submodule "Telegram/lib_webview"]
|
||||
path = Telegram/lib_webview
|
||||
url = https://github.com/desktop-app/lib_webview.git
|
||||
[submodule "Telegram/ThirdParty/jemalloc"]
|
||||
path = Telegram/ThirdParty/jemalloc
|
||||
url = https://github.com/jemalloc/jemalloc
|
||||
[submodule "Telegram/ThirdParty/dispatch"]
|
||||
path = Telegram/ThirdParty/dispatch
|
||||
url = https://github.com/apple/swift-corelibs-libdispatch
|
||||
|
||||
@@ -132,8 +132,6 @@ set(ayugram_files
|
||||
ayu/ui/sections/edited/edited_log_item.h
|
||||
ayu/ui/sections/edited/edited_log_section.cpp
|
||||
ayu/ui/sections/edited/edited_log_section.h
|
||||
ayu/ui/boxes/server_read_confirmation_box.cpp
|
||||
ayu/ui/boxes/server_read_confirmation_box.h
|
||||
ayu/ui/boxes/edit_deleted_mark.cpp
|
||||
ayu/ui/boxes/edit_deleted_mark.h
|
||||
ayu/ui/boxes/edit_edited_mark.cpp
|
||||
@@ -531,6 +529,10 @@ PRIVATE
|
||||
data/business/data_business_info.h
|
||||
data/business/data_shortcut_messages.cpp
|
||||
data/business/data_shortcut_messages.h
|
||||
data/components/scheduled_messages.cpp
|
||||
data/components/scheduled_messages.h
|
||||
data/components/sponsored_messages.cpp
|
||||
data/components/sponsored_messages.h
|
||||
data/notify/data_notify_settings.cpp
|
||||
data/notify/data_notify_settings.h
|
||||
data/notify/data_peer_notify_settings.cpp
|
||||
@@ -648,14 +650,10 @@ PRIVATE
|
||||
data/data_send_action.h
|
||||
data/data_session.cpp
|
||||
data/data_session.h
|
||||
data/data_scheduled_messages.cpp
|
||||
data/data_scheduled_messages.h
|
||||
data/data_shared_media.cpp
|
||||
data/data_shared_media.h
|
||||
data/data_sparse_ids.cpp
|
||||
data/data_sparse_ids.h
|
||||
data/data_sponsored_messages.cpp
|
||||
data/data_sponsored_messages.h
|
||||
data/data_statistics.h
|
||||
data/data_stories.cpp
|
||||
data/data_stories.h
|
||||
@@ -1530,8 +1528,6 @@ PRIVATE
|
||||
ui/image/image_location.h
|
||||
ui/image/image_location_factory.cpp
|
||||
ui/image/image_location_factory.h
|
||||
ui/widgets/level_meter.cpp
|
||||
ui/widgets/level_meter.h
|
||||
ui/countryinput.cpp
|
||||
ui/countryinput.h
|
||||
ui/dynamic_thumbnails.cpp
|
||||
@@ -1547,6 +1543,8 @@ PRIVATE
|
||||
ui/search_field_controller.h
|
||||
ui/text/format_song_document_name.cpp
|
||||
ui/text/format_song_document_name.h
|
||||
ui/widgets/label_with_custom_emoji.cpp
|
||||
ui/widgets/label_with_custom_emoji.h
|
||||
ui/unread_badge.cpp
|
||||
ui/unread_badge.h
|
||||
window/main_window.cpp
|
||||
@@ -1574,6 +1572,8 @@ PRIVATE
|
||||
window/window_lock_widgets.h
|
||||
window/window_main_menu.cpp
|
||||
window/window_main_menu.h
|
||||
window/window_main_menu_helpers.cpp
|
||||
window/window_main_menu_helpers.h
|
||||
window/window_media_preview.cpp
|
||||
window/window_media_preview.h
|
||||
window/window_peer_menu.cpp
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -19,6 +19,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_menu_set_status" = "Set Emoji Status";
|
||||
"lng_menu_change_status" = "Change Emoji Status";
|
||||
"lng_menu_my_stories" = "My Stories";
|
||||
"lng_menu_my_groups" = "My Groups";
|
||||
"lng_menu_my_channels" = "My Channels";
|
||||
|
||||
"lng_disable_notifications_from_tray" = "Disable notifications";
|
||||
"lng_enable_notifications_from_tray" = "Enable notifications";
|
||||
@@ -307,7 +309,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_limit_reached#one" = "You've reached the message text limit. Please make the text shorter by {count} character.";
|
||||
"lng_edit_limit_reached#other" = "You've reached the message text limit. Please make the text shorter by {count} characters.";
|
||||
"lng_edit_message" = "Edit message";
|
||||
"lng_edit_message_text" = "New message text...";
|
||||
"lng_edit_message_text" = "Caption";
|
||||
"lng_deleted" = "Deleted Account";
|
||||
"lng_deleted_message" = "Deleted message";
|
||||
"lng_deleted_story" = "Deleted story";
|
||||
@@ -469,6 +471,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_bio_placeholder" = "Bio";
|
||||
|
||||
"lng_collectible_username_title" = "{username} is a collectible username that belongs to";
|
||||
"lng_collectible_username_info" = "This username was bought on **Fragment** on {date} for {price}";
|
||||
"lng_collectible_username_copy" = "Copy Link";
|
||||
"lng_collectible_phone_title" = "{phone} is a collectible phone number that belongs to";
|
||||
"lng_collectible_phone_info" = "This phone number was bought on **Fragment** on {date} for {price}";
|
||||
"lng_collectible_phone_copy" = "Copy Phone Number";
|
||||
"lng_collectible_learn_more" = "Learn More";
|
||||
|
||||
"lng_settings_section_info" = "My info";
|
||||
|
||||
"lng_settings_section_notify" = "Notifications";
|
||||
@@ -724,6 +734,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_sensitive_disable_filtering" = "Disable filtering";
|
||||
"lng_settings_sensitive_about" = "Display sensitive media in public channels on all your Telegram devices.";
|
||||
"lng_settings_security_bots" = "Bots and websites";
|
||||
"lng_settings_file_confirmations" = "File open confirmations";
|
||||
"lng_settings_edit_extensions" = "Extensions whitelist";
|
||||
"lng_settings_edit_extensions_about" = "Open files with the following extensions without additional confirmation.";
|
||||
"lng_settings_edit_ip_confirm" = "IP reveal warning";
|
||||
"lng_settings_edit_ip_confirm_about" = "Show confirmation when opening files that may reveal your IP address.";
|
||||
"lng_settings_clear_payment_info" = "Clear Payment and Shipping Info";
|
||||
"lng_settings_logged_in" = "Connected websites";
|
||||
"lng_settings_logged_in_title" = "Logged in with Telegram";
|
||||
@@ -1058,6 +1073,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_faq_button" = "Go to FAQ";
|
||||
"lng_settings_ask_ok" = "Ask a Volunteer";
|
||||
"lng_settings_faq" = "Telegram FAQ";
|
||||
"lng_settings_faq_link" = "https://telegram.org/faq#general-questions";
|
||||
"lng_settings_features" = "Telegram Features";
|
||||
"lng_settings_logout" = "Log Out";
|
||||
"lng_sure_logout" = "Are you sure you want to log out?";
|
||||
@@ -4469,10 +4485,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_translate_settings_about" = "The 'Translate' button will appear when you open a context menu on a text message.";
|
||||
"lng_translate_settings_one" = "Please choose at least one language so that it can be used as the \"Translate to\" language.";
|
||||
|
||||
"lng_launch_exe_warning" = "This file has a {extension} extension.\nAre you sure you want to run it?";
|
||||
"lng_launch_exe_warning" = "This file has {extension} extension.\nAre you sure you want to run it?";
|
||||
"lng_launch_other_warning" = "This file has {extension} extension.\nAre you sure you want to open it?";
|
||||
"lng_launch_svg_warning" = "Opening this file can potentially expose your IP address to its sender. Continue?";
|
||||
"lng_launch_exe_sure" = "Run";
|
||||
"lng_launch_other_sure" = "Open";
|
||||
"lng_launch_exe_dont_ask" = "Don't ask me again";
|
||||
"lng_launch_dont_ask" = "Remember for this file type";
|
||||
"lng_launch_dont_ask_settings" = "You can later edit trusted file types in Settings > Privacy and Security > File open confirmations.";
|
||||
|
||||
"lng_polls_anonymous" = "Anonymous Poll";
|
||||
"lng_polls_public" = "Poll";
|
||||
@@ -5040,6 +5060,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_channel_earn_learn_coin_title" = "What is {emoji} TON?";
|
||||
"lng_channel_earn_learn_coin_about" = "TON is a blockchain platform and cryptocurrency that Telegram uses for its high speed and low commissions on transactions. {link}";
|
||||
"lng_channel_earn_learn_close" = "Got it";
|
||||
"lng_channel_earn_learn_coin_link" = "https://telegram.org/blog/monetization-for-channels";
|
||||
"lng_channel_earn_chart_top_hours" = "Ad impressions";
|
||||
"lng_channel_earn_chart_revenue" = "Ad revenue";
|
||||
"lng_channel_earn_chart_overriden_detail_currency" = "Revenue in TON";
|
||||
|
||||
@@ -22,5 +22,7 @@
|
||||
<file alias="hours.tgs">../../animations/hours.tgs</file>
|
||||
<file alias="phone.tgs">../../animations/phone.tgs</file>
|
||||
<file alias="chat_link.tgs">../../animations/chat_link.tgs</file>
|
||||
<file alias="collectible_username.tgs">../../animations/collectible_username.tgs</file>
|
||||
<file alias="collectible_phone.tgs">../../animations/collectible_phone.tgs</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="4.16.0.0" />
|
||||
Version="4.16.8.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,16,0,0
|
||||
PRODUCTVERSION 4,16,0,0
|
||||
FILEVERSION 4,16,8,0
|
||||
PRODUCTVERSION 4,16,8,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Radolyn Labs"
|
||||
VALUE "FileDescription", "AyuGram Desktop"
|
||||
VALUE "FileVersion", "4.16.0.0"
|
||||
VALUE "FileVersion", "4.16.8.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "4.16.0.0"
|
||||
VALUE "ProductVersion", "4.16.8.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,16,0,0
|
||||
PRODUCTVERSION 4,16,0,0
|
||||
FILEVERSION 4,16,8,0
|
||||
PRODUCTVERSION 4,16,8,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Radolyn Labs"
|
||||
VALUE "FileDescription", "AyuGram Desktop Updater"
|
||||
VALUE "FileVersion", "4.16.0.0"
|
||||
VALUE "FileVersion", "4.16.8.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2024"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "4.16.0.0"
|
||||
VALUE "ProductVersion", "4.16.8.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -236,14 +236,14 @@ void SendBotCallbackDataWithPassword(
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
const auto box = std::make_shared<QPointer<PasscodeBox>>();
|
||||
auto fields = PasscodeBox::CloudFields::From(state);
|
||||
fields.customTitle = tr::lng_bots_password_confirm_title();
|
||||
fields.customDescription
|
||||
= tr::lng_bots_password_confirm_description(tr::now);
|
||||
fields.customSubmitButton = tr::lng_passcode_submit();
|
||||
fields.customCheckCallback = [=](
|
||||
const Core::CloudPasswordResult &result) {
|
||||
const Core::CloudPasswordResult &result,
|
||||
QPointer<PasscodeBox> box) {
|
||||
if (const auto button = getButton()) {
|
||||
if (button->requestId) {
|
||||
return;
|
||||
@@ -257,18 +257,17 @@ void SendBotCallbackDataWithPassword(
|
||||
return;
|
||||
}
|
||||
SendBotCallbackData(strongController, item, row, column, result, [=] {
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
if (box) {
|
||||
box->closeBox();
|
||||
}
|
||||
}, [=](const QString &error) {
|
||||
if (*box) {
|
||||
(*box)->handleCustomCheckError(error);
|
||||
if (box) {
|
||||
box->handleCustomCheckError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
auto object = Box<PasscodeBox>(session, fields);
|
||||
*box = Ui::MakeWeak(object.data());
|
||||
show->showBox(std::move(object), Ui::LayerOption::CloseOther);
|
||||
}, *lifetime);
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ void ApplyLastList(
|
||||
channel->mgInfo->lastAdmins.clear();
|
||||
channel->mgInfo->lastRestricted.clear();
|
||||
channel->mgInfo->lastParticipants.clear();
|
||||
channel->mgInfo->lastParticipantsStatus =
|
||||
MegagroupInfo::LastParticipantsUpToDate
|
||||
channel->mgInfo->lastParticipantsStatus
|
||||
= MegagroupInfo::LastParticipantsUpToDate
|
||||
| MegagroupInfo::LastParticipantsOnceReceived;
|
||||
|
||||
auto botStatus = channel->mgInfo->botStatus;
|
||||
|
||||
@@ -58,25 +58,33 @@ void HandleWithdrawalButton(
|
||||
state->loading = false;
|
||||
|
||||
auto fields = PasscodeBox::CloudFields::From(pass);
|
||||
fields.customTitle =
|
||||
tr::lng_channel_earn_balance_password_title();
|
||||
fields.customDescription =
|
||||
tr::lng_channel_earn_balance_password_description(tr::now);
|
||||
fields.customTitle
|
||||
= tr::lng_channel_earn_balance_password_title();
|
||||
fields.customDescription
|
||||
= tr::lng_channel_earn_balance_password_description(tr::now);
|
||||
fields.customSubmitButton = tr::lng_passcode_submit();
|
||||
fields.customCheckCallback = crl::guard(button, [=](
|
||||
const Core::CloudPasswordResult &result) {
|
||||
const Core::CloudPasswordResult &result,
|
||||
QPointer<PasscodeBox> box) {
|
||||
const auto done = [=](const QString &result) {
|
||||
if (!result.isEmpty()) {
|
||||
UrlClickHandler::Open(result);
|
||||
if (box) {
|
||||
box->closeBox();
|
||||
}
|
||||
}
|
||||
};
|
||||
const auto fail = [=](const QString &error) {
|
||||
show->showToast(error);
|
||||
};
|
||||
session->api().request(
|
||||
MTPstats_GetBroadcastRevenueWithdrawalUrl(
|
||||
channel->inputChannel,
|
||||
result.result
|
||||
)).done([=](const MTPstats_BroadcastRevenueWithdrawalUrl &r) {
|
||||
const auto url = qs(r.data().vurl());
|
||||
|
||||
if (!url.isEmpty()) {
|
||||
UrlClickHandler::Open(url);
|
||||
}
|
||||
done(qs(r.data().vurl()));
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
fail(error.type());
|
||||
}).send();
|
||||
});
|
||||
show->show(Box<PasscodeBox>(session, fields));
|
||||
|
||||
@@ -12,12 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_text_entities.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "data/business/data_shortcut_messages.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/mtproto_response.h"
|
||||
@@ -29,20 +28,20 @@ namespace {
|
||||
using namespace rpl::details;
|
||||
|
||||
template <typename T>
|
||||
constexpr auto WithId =
|
||||
is_callable_plain_v<T, Fn<void()>, mtpRequestId>;
|
||||
constexpr auto WithId
|
||||
= is_callable_plain_v<T, Fn<void()>, mtpRequestId>;
|
||||
template <typename T>
|
||||
constexpr auto WithoutId =
|
||||
is_callable_plain_v<T, Fn<void()>>;
|
||||
constexpr auto WithoutId
|
||||
= is_callable_plain_v<T, Fn<void()>>;
|
||||
template <typename T>
|
||||
constexpr auto WithoutCallback =
|
||||
is_callable_plain_v<T>;
|
||||
constexpr auto WithoutCallback
|
||||
= is_callable_plain_v<T>;
|
||||
template <typename T>
|
||||
constexpr auto ErrorWithId =
|
||||
is_callable_plain_v<T, QString, mtpRequestId>;
|
||||
constexpr auto ErrorWithId
|
||||
= is_callable_plain_v<T, QString, mtpRequestId>;
|
||||
template <typename T>
|
||||
constexpr auto ErrorWithoutId =
|
||||
is_callable_plain_v<T, QString>;
|
||||
constexpr auto ErrorWithoutId
|
||||
= is_callable_plain_v<T, QString>;
|
||||
|
||||
template <typename DoneCallback, typename FailCallback>
|
||||
mtpRequestId EditMessage(
|
||||
@@ -95,7 +94,7 @@ mtpRequestId EditMessage(
|
||||
: emptyFlag);
|
||||
|
||||
const auto id = item->isScheduled()
|
||||
? session->data().scheduledMessages().lookupId(item)
|
||||
? session->scheduledMessages().lookupId(item)
|
||||
: item->isBusinessShortcut()
|
||||
? session->data().shortcutMessages().lookupId(item)
|
||||
: item->id;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace {
|
||||
|
||||
constexpr auto kSharedMediaLimit = 100;
|
||||
|
||||
[[nodiscard]] SendMediaReady PreparePeerPhoto(
|
||||
[[nodiscard]] std::shared_ptr<FilePrepareResult> PreparePeerPhoto(
|
||||
MTP::DcId dcId,
|
||||
PeerId peerId,
|
||||
QImage &&image) {
|
||||
@@ -80,24 +80,17 @@ constexpr auto kSharedMediaLimit = 100;
|
||||
MTPVector<MTPVideoSize>(),
|
||||
MTP_int(dcId));
|
||||
|
||||
QString file, filename;
|
||||
int64 filesize = 0;
|
||||
QByteArray data;
|
||||
|
||||
return SendMediaReady(
|
||||
SendMediaType::Photo,
|
||||
file,
|
||||
filename,
|
||||
filesize,
|
||||
data,
|
||||
id,
|
||||
id,
|
||||
u"jpg"_q,
|
||||
peerId,
|
||||
photo,
|
||||
photoThumbs,
|
||||
MTP_documentEmpty(MTP_long(0)),
|
||||
jpeg);
|
||||
auto result = MakePreparedFile({
|
||||
.id = id,
|
||||
.type = SendMediaType::Photo,
|
||||
});
|
||||
result->type = SendMediaType::Photo;
|
||||
result->setFileData(jpeg);
|
||||
result->thumbId = id;
|
||||
result->thumbname = "thumb.jpg";
|
||||
result->photo = photo;
|
||||
result->photoThumbs = photoThumbs;
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MTPVideoSize> PrepareMtpMarkup(
|
||||
@@ -239,7 +232,7 @@ void PeerPhoto::upload(
|
||||
_api.instance().mainDcId(),
|
||||
peer->id,
|
||||
base::take(photo.image));
|
||||
_session->uploader().uploadMedia(fakeId, ready);
|
||||
_session->uploader().upload(fakeId, ready);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,16 +24,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
SendMediaReady PrepareRingtoneDocument(
|
||||
std::shared_ptr<FilePrepareResult> PrepareRingtoneDocument(
|
||||
MTP::DcId dcId,
|
||||
const QString &filename,
|
||||
const QString &filemime,
|
||||
const QByteArray &content) {
|
||||
const auto id = base::RandomValue<DocumentId>();
|
||||
auto attributes = QVector<MTPDocumentAttribute>(
|
||||
1,
|
||||
MTP_documentAttributeFilename(MTP_string(filename)));
|
||||
const auto id = base::RandomValue<DocumentId>();
|
||||
const auto document = MTP_document(
|
||||
|
||||
auto result = MakePreparedFile({
|
||||
.id = id,
|
||||
.type = SendMediaType::File,
|
||||
});
|
||||
result->filename = filename;
|
||||
result->content = content;
|
||||
result->filesize = content.size();
|
||||
result->setFileData(content);
|
||||
result->document = MTP_document(
|
||||
MTP_flags(0),
|
||||
MTP_long(id),
|
||||
MTP_long(0),
|
||||
@@ -45,21 +54,7 @@ SendMediaReady PrepareRingtoneDocument(
|
||||
MTPVector<MTPVideoSize>(),
|
||||
MTP_int(dcId),
|
||||
MTP_vector<MTPDocumentAttribute>(std::move(attributes)));
|
||||
|
||||
return SendMediaReady(
|
||||
SendMediaType::File,
|
||||
QString(), // filepath
|
||||
filename,
|
||||
content.size(),
|
||||
content,
|
||||
id,
|
||||
0,
|
||||
QString(),
|
||||
PeerId(),
|
||||
MTP_photoEmpty(MTP_long(0)),
|
||||
PreparedPhotoThumbs(),
|
||||
document,
|
||||
QByteArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -102,7 +97,7 @@ void Ringtones::upload(
|
||||
_uploads.erase(already);
|
||||
}
|
||||
_uploads.emplace(fakeId, uploadedData);
|
||||
_session->uploader().uploadMedia(fakeId, ready);
|
||||
_session->uploader().upload(fakeId, ready);
|
||||
}
|
||||
|
||||
void Ringtones::ready(const FullMsgId &msgId, const MTPInputFile &file) {
|
||||
|
||||
@@ -353,7 +353,7 @@ void FillMessagePostFlags(
|
||||
|
||||
void SendConfirmedFile(
|
||||
not_null<Main::Session*> session,
|
||||
const std::shared_ptr<FileLoadResult> &file) {
|
||||
const std::shared_ptr<FilePrepareResult> &file) {
|
||||
const auto isEditing = (file->type != SendMediaType::Audio)
|
||||
&& (file->to.replaceMediaOf != 0);
|
||||
const auto newId = FullMsgId(
|
||||
|
||||
@@ -14,7 +14,7 @@ class Session;
|
||||
class History;
|
||||
class PhotoData;
|
||||
class DocumentData;
|
||||
struct FileLoadResult;
|
||||
struct FilePrepareResult;
|
||||
|
||||
namespace Api {
|
||||
|
||||
@@ -40,6 +40,6 @@ void FillMessagePostFlags(
|
||||
|
||||
void SendConfirmedFile(
|
||||
not_null<Main::Session*> session,
|
||||
const std::shared_ptr<FileLoadResult> &file);
|
||||
const std::shared_ptr<FilePrepareResult> &file);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -860,6 +860,7 @@ void EarnStatistics::requestHistory(
|
||||
.token = Data::EarnHistorySlice::OffsetToken(nextToken),
|
||||
});
|
||||
}).fail([=] {
|
||||
done({});
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "mtproto/mtproto_dc_options.h"
|
||||
#include "data/business/data_shortcut_messages.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_saved_messages.h"
|
||||
@@ -37,7 +38,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_send_action.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
@@ -98,7 +98,7 @@ void ProcessScheduledMessageWithElapsedTime(
|
||||
// Note that when a message is scheduled until online
|
||||
// while the recipient is already online, the server sends
|
||||
// an ordinary new message with skipped "from_scheduled" flag.
|
||||
session->data().scheduledMessages().checkEntitiesAndUpdate(data);
|
||||
session->scheduledMessages().checkEntitiesAndUpdate(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1472,7 +1472,9 @@ void Updates::applyUpdates(
|
||||
if (const auto id = owner.messageIdByRandomId(randomId)) {
|
||||
const auto local = owner.message(id);
|
||||
if (local && local->isScheduled()) {
|
||||
owner.scheduledMessages().sendNowSimpleMessage(d, local);
|
||||
session().scheduledMessages().sendNowSimpleMessage(
|
||||
d,
|
||||
local);
|
||||
}
|
||||
}
|
||||
const auto wasAlready = (lookupMessage() != nullptr);
|
||||
@@ -1569,7 +1571,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
auto &owner = session().data();
|
||||
if (const auto local = owner.message(id)) {
|
||||
if (local->isScheduled()) {
|
||||
session().data().scheduledMessages().apply(d, local);
|
||||
session().scheduledMessages().apply(d, local);
|
||||
} else if (local->isBusinessShortcut()) {
|
||||
session().data().shortcutMessages().apply(d, local);
|
||||
} else {
|
||||
@@ -1779,12 +1781,12 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
case mtpc_updateNewScheduledMessage: {
|
||||
const auto &d = update.c_updateNewScheduledMessage();
|
||||
session().data().scheduledMessages().apply(d);
|
||||
session().scheduledMessages().apply(d);
|
||||
} break;
|
||||
|
||||
case mtpc_updateDeleteScheduledMessages: {
|
||||
const auto &d = update.c_updateDeleteScheduledMessages();
|
||||
session().data().scheduledMessages().apply(d);
|
||||
session().scheduledMessages().apply(d);
|
||||
} break;
|
||||
|
||||
case mtpc_updateQuickReplies: {
|
||||
|
||||
@@ -307,8 +307,8 @@ void UserPrivacy::reload(Key key) {
|
||||
}
|
||||
|
||||
void UserPrivacy::pushPrivacy(Key key, const TLRules &rules) {
|
||||
const auto &saved = (_privacyValues[key] =
|
||||
TLToRules(rules, _session->data()));
|
||||
const auto &saved
|
||||
= (_privacyValues[key] = TLToRules(rules, _session->data()));
|
||||
const auto i = _privacyChanges.find(key);
|
||||
if (i != end(_privacyChanges)) {
|
||||
i->second.fire_copy(saved);
|
||||
|
||||
@@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_user_names.h"
|
||||
#include "api/api_websites.h"
|
||||
#include "data/business/data_shortcut_messages.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_web_page.h"
|
||||
@@ -43,7 +44,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_saved_sublist.h"
|
||||
#include "data/data_search_controller.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
@@ -291,6 +291,12 @@ void ApiWrap::topPromotionDone(const MTPhelp_PromoData &proxy) {
|
||||
base::unixtime::now(),
|
||||
_topPromotionNextRequestTime);
|
||||
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->disableAds) {
|
||||
_session->data().setTopPromoted(nullptr, QString(), QString());
|
||||
return;
|
||||
}
|
||||
|
||||
proxy.match([&](const MTPDhelp_promoDataEmpty &data) {
|
||||
_session->data().setTopPromoted(nullptr, QString(), QString());
|
||||
}, [&](const MTPDhelp_promoData &data) {
|
||||
@@ -559,7 +565,7 @@ void ApiWrap::sendMessageFail(
|
||||
}
|
||||
}
|
||||
} else if (error == u"SCHEDULE_STATUS_PRIVATE"_q) {
|
||||
auto &scheduled = _session->data().scheduledMessages();
|
||||
auto &scheduled = _session->scheduledMessages();
|
||||
Assert(peer->isUser());
|
||||
if (const auto item = scheduled.lookupItem(peer->id, itemId.msg)) {
|
||||
scheduled.removeSending(item);
|
||||
@@ -813,7 +819,7 @@ QString ApiWrap::exportDirectStoryLink(not_null<Data::Story*> story) {
|
||||
const auto storyId = story->fullId();
|
||||
const auto peer = story->peer();
|
||||
const auto fallback = [&] {
|
||||
const auto base = peer->userName();
|
||||
const auto base = peer->username();
|
||||
const auto story = QString::number(storyId.story);
|
||||
const auto query = base + "/s/" + story;
|
||||
return session().createInternalLinkFull(query);
|
||||
@@ -1573,8 +1579,8 @@ void ApiWrap::saveStickerSets(
|
||||
writeRecent = true;
|
||||
}
|
||||
|
||||
const auto isAttached =
|
||||
(removedSetId == Data::Stickers::CloudRecentAttachedSetId);
|
||||
const auto isAttached
|
||||
= (removedSetId == Data::Stickers::CloudRecentAttachedSetId);
|
||||
const auto flags = isAttached
|
||||
? MTPmessages_ClearRecentStickers::Flag::f_attached
|
||||
: MTPmessages_ClearRecentStickers::Flags(0);
|
||||
@@ -2480,8 +2486,8 @@ void ApiWrap::refreshFileReference(
|
||||
_session->data().peer(storyId.peer)->input,
|
||||
MTP_vector<MTPint>(1, MTP_int(storyId.story))));
|
||||
} else if (item->isScheduled()) {
|
||||
const auto &scheduled = _session->data().scheduledMessages();
|
||||
const auto realId = scheduled.lookupId(item);
|
||||
const auto realId = _session->scheduledMessages().lookupId(
|
||||
item);
|
||||
request(MTPmessages_GetScheduledMessages(
|
||||
item->history()->peer->input,
|
||||
MTP_vector<MTPint>(1, MTP_int(realId))));
|
||||
@@ -2527,8 +2533,8 @@ void ApiWrap::refreshFileReference(
|
||||
}, [&](Data::FileOriginPeerPhoto data) {
|
||||
fail();
|
||||
}, [&](Data::FileOriginStickerSet data) {
|
||||
const auto isRecentAttached =
|
||||
(data.setId == Data::Stickers::CloudRecentAttachedSetId);
|
||||
const auto isRecentAttached
|
||||
= (data.setId == Data::Stickers::CloudRecentAttachedSetId);
|
||||
if (data.setId == Data::Stickers::CloudRecentSetId
|
||||
|| data.setId == Data::Stickers::RecentSetId
|
||||
|| isRecentAttached) {
|
||||
|
||||
@@ -195,6 +195,9 @@ AyuGramSettings::AyuGramSettings() {
|
||||
saveDeletedMessages = true;
|
||||
saveMessagesHistory = true;
|
||||
|
||||
// ~ Message filters
|
||||
hideFromBlocked = false;
|
||||
|
||||
// ~ QoL toggles
|
||||
disableAds = true;
|
||||
disableStories = false;
|
||||
@@ -202,8 +205,6 @@ AyuGramSettings::AyuGramSettings() {
|
||||
collapseSimilarChannels = true;
|
||||
hideSimilarChannels = false;
|
||||
|
||||
uploadSpeedBoost = false;
|
||||
|
||||
disableNotificationsDelay = false;
|
||||
localPremium = false;
|
||||
copyUsernameAsLink = true;
|
||||
@@ -243,7 +244,7 @@ AyuGramSettings::AyuGramSettings() {
|
||||
* showPeerId = 0 means no ID shown
|
||||
* showPeerId = 1 means ID shown as for Telegram API devs
|
||||
* showPeerId = 2 means ID shown as for Bot API devs (-100)
|
||||
*/
|
||||
*/
|
||||
showPeerId = 2;
|
||||
showMessageSeconds = false;
|
||||
showMessageShot = true;
|
||||
@@ -309,6 +310,10 @@ void AyuGramSettings::set_saveMessagesHistory(bool val) {
|
||||
saveMessagesHistory = val;
|
||||
}
|
||||
|
||||
void AyuGramSettings::set_hideFromBlocked(bool val) {
|
||||
hideFromBlocked = val;
|
||||
}
|
||||
|
||||
void AyuGramSettings::set_disableAds(bool val) {
|
||||
disableAds = val;
|
||||
}
|
||||
@@ -329,10 +334,6 @@ void AyuGramSettings::set_hideSimilarChannels(bool val) {
|
||||
hideSimilarChannels = val;
|
||||
}
|
||||
|
||||
void AyuGramSettings::set_uploadSpeedBoost(bool val) {
|
||||
uploadSpeedBoost = val;
|
||||
}
|
||||
|
||||
void AyuGramSettings::set_disableNotificationsDelay(bool val) {
|
||||
disableNotificationsDelay = val;
|
||||
}
|
||||
|
||||
@@ -29,14 +29,14 @@ public:
|
||||
bool saveDeletedMessages;
|
||||
bool saveMessagesHistory;
|
||||
|
||||
bool hideFromBlocked;
|
||||
|
||||
bool disableAds;
|
||||
bool disableStories;
|
||||
bool disableCustomBackgrounds;
|
||||
bool collapseSimilarChannels;
|
||||
bool hideSimilarChannels;
|
||||
|
||||
bool uploadSpeedBoost;
|
||||
|
||||
bool disableNotificationsDelay;
|
||||
bool localPremium;
|
||||
bool copyUsernameAsLink;
|
||||
@@ -89,14 +89,14 @@ public:
|
||||
void set_saveDeletedMessages(bool val);
|
||||
void set_saveMessagesHistory(bool val);
|
||||
|
||||
void set_hideFromBlocked(bool val);
|
||||
|
||||
void set_disableAds(bool val);
|
||||
void set_disableStories(bool val);
|
||||
void set_disableCustomBackgrounds(bool val);
|
||||
void set_collapseSimilarChannels(bool val);
|
||||
void set_hideSimilarChannels(bool val);
|
||||
|
||||
void set_uploadSpeedBoost(bool val);
|
||||
|
||||
void set_disableNotificationsDelay(bool val);
|
||||
void set_localPremium(bool val);
|
||||
void set_copyUsernameAsLink(bool val);
|
||||
@@ -147,12 +147,12 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
|
||||
useScheduledMessages,
|
||||
saveDeletedMessages,
|
||||
saveMessagesHistory,
|
||||
hideFromBlocked,
|
||||
disableAds,
|
||||
disableStories,
|
||||
disableCustomBackgrounds,
|
||||
collapseSimilarChannels,
|
||||
hideSimilarChannels,
|
||||
uploadSpeedBoost,
|
||||
disableNotificationsDelay,
|
||||
localPremium,
|
||||
copyUsernameAsLink,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -146,9 +146,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.45.0"
|
||||
#define SQLITE_VERSION_NUMBER 3045000
|
||||
#define SQLITE_SOURCE_ID "2024-01-15 17:01:13 1066602b2b1976fe58b5150777cced894af17c803e068f5918390d6915b46e1d"
|
||||
#define SQLITE_VERSION "3.45.3"
|
||||
#define SQLITE_VERSION_NUMBER 3045003
|
||||
#define SQLITE_SOURCE_ID "2024-04-15 13:34:05 8653b758870e6ef0c98d46b3ace27849054af85da891eb121e9aaa537f1e8355"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@@ -420,6 +420,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
||||
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
|
||||
** <li> The application must not modify the SQL statement text passed into
|
||||
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
|
||||
** <li> The application must not dereference the arrays or string pointers
|
||||
** passed as the 3rd and 4th callback parameters after it returns.
|
||||
** </ul>
|
||||
*/
|
||||
SQLITE_API int sqlite3_exec(
|
||||
@@ -2141,6 +2143,22 @@ struct sqlite3_mem_methods {
|
||||
** configuration setting is never used, then the default maximum is determined
|
||||
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
|
||||
** compile-time option is not set, then the default maximum is 1073741824.
|
||||
**
|
||||
** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
|
||||
** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
|
||||
** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
|
||||
** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
|
||||
** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
|
||||
** defaults to on. This configuration option queries the current setting or
|
||||
** changes the setting to off or on. The argument is a pointer to an integer.
|
||||
** If that integer initially holds a value of 1, then the ability for VIEWs to
|
||||
** have ROWIDs is activated. If the integer initially holds zero, then the
|
||||
** ability is deactivated. Any other initial value for the integer leaves the
|
||||
** setting unchanged. After changes, if any, the integer is written with
|
||||
** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
|
||||
** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
|
||||
** recommended case) then the integer is always filled with zero, regardless
|
||||
** if its initial value.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
|
||||
@@ -2172,6 +2190,7 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
|
||||
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
|
||||
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
|
||||
#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Configuration Options
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2024
|
||||
#include "server_read_confirmation_box.h"
|
||||
|
||||
#include "lang_auto.h"
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/utils/telegram_helpers.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
namespace AyuUi {
|
||||
|
||||
ServerReadConfirmationBox::ServerReadConfirmationBox(
|
||||
QWidget *,
|
||||
not_null<Window::SessionController*> controller)
|
||||
: _controller(controller) {
|
||||
//
|
||||
}
|
||||
|
||||
void ServerReadConfirmationBox::prepare() {
|
||||
_text.create(this, tr::ayu_ReadConfirmationBoxQuestion(), st::boxLabel);
|
||||
|
||||
auto fullHeight = st::boxPadding.top()
|
||||
+ _text->height()
|
||||
+ st::boxPadding.bottom();
|
||||
|
||||
setDimensions(st::boxWidth, fullHeight);
|
||||
|
||||
addButton(tr::ayu_ReadConfirmationBoxActionText(),
|
||||
[=, this]
|
||||
{
|
||||
ReadAllPeers();
|
||||
closeBox();
|
||||
});
|
||||
addButton(tr::lng_cancel(),
|
||||
[=, this]
|
||||
{
|
||||
closeBox();
|
||||
});
|
||||
}
|
||||
|
||||
void ServerReadConfirmationBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
const auto &padding = st::boxPadding;
|
||||
_text->moveToLeft(padding.left(), padding.top());
|
||||
}
|
||||
|
||||
void ServerReadConfirmationBox::ReadAllPeers() {
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
auto prev = settings->sendReadMessages;
|
||||
settings->set_sendReadMessages(true);
|
||||
|
||||
auto chats = _controller->session().data().chatsList();
|
||||
MarkAsReadChatList(chats);
|
||||
|
||||
settings->set_sendReadMessages(prev);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2024
|
||||
#pragma once
|
||||
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "window/window_main_menu.h"
|
||||
|
||||
namespace AyuUi {
|
||||
|
||||
class ServerReadConfirmationBox : public Ui::BoxContent
|
||||
{
|
||||
public:
|
||||
ServerReadConfirmationBox(QWidget *, not_null<Window::SessionController*> controller);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
void ReadAllPeers();
|
||||
|
||||
not_null<Window::SessionController*> _controller;
|
||||
object_ptr<Ui::FlatLabel> _text = {nullptr};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -54,6 +54,10 @@ void AddHideMessageAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->history()->peer->isSelf()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto history = item->history();
|
||||
menu->addAction(tr::ayu_ContextHideMessage(tr::now),
|
||||
[=]()
|
||||
@@ -279,7 +283,11 @@ void AddMessageDetailsAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
|
||||
}
|
||||
|
||||
void AddReadUntilAction(not_null<Ui::PopupMenu*> menu, HistoryItem *item) {
|
||||
if (item->isLocal()) {
|
||||
if (item->isLocal() || item->isService()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->history()->peer->isSelf()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -381,7 +381,7 @@ auto GenerateParticipantString(
|
||||
data,
|
||||
});
|
||||
}
|
||||
const auto username = peer->userName();
|
||||
const auto username = peer->username();
|
||||
if (username.isEmpty()) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -33,18 +33,19 @@ const QVector<QString> icons{
|
||||
|
||||
const auto rows = static_cast<int>(icons.size()) / 4 + std::min(1, static_cast<int>(icons.size()) % 4);
|
||||
|
||||
void drawIcon(QPainter &p, const QImage &icon, int xOffset, int yOffset, bool selected) {
|
||||
void drawIcon(QPainter &p, const QImage &icon, int xOffset, int yOffset, float strokeOpacity) {
|
||||
xOffset += st::cpPadding;
|
||||
|
||||
if (selected) {
|
||||
p.save();
|
||||
p.setPen(QPen(st::iconPreviewStroke, st::cpPenSize));
|
||||
p.drawEllipse(xOffset + st::cpSelectedPadding,
|
||||
yOffset + st::cpSelectedPadding,
|
||||
st::cpIconSize + st::cpSelectedPadding * 2,
|
||||
st::cpIconSize + st::cpSelectedPadding * 2);
|
||||
p.restore();
|
||||
}
|
||||
// stroke
|
||||
p.save();
|
||||
p.setPen(QPen(st::iconPreviewStroke, st::cpPenSize));
|
||||
p.setOpacity(strokeOpacity);
|
||||
p.drawEllipse(xOffset + st::cpSelectedPadding,
|
||||
yOffset + st::cpSelectedPadding,
|
||||
st::cpIconSize + st::cpSelectedPadding * 2,
|
||||
st::cpIconSize + st::cpSelectedPadding * 2);
|
||||
p.restore();
|
||||
// /stroke
|
||||
|
||||
auto rect = QRect(xOffset + st::cpImagePadding, yOffset + st::cpImagePadding, st::cpIconSize, st::cpIconSize);
|
||||
p.drawImage(rect, icon);
|
||||
@@ -81,11 +82,19 @@ void IconPicker::paintEvent(QPaintEvent *e) {
|
||||
const auto &iconName = icons[idx];
|
||||
auto icon = AyuAssets::loadPreview(iconName)
|
||||
.scaled(st::cpIconSize, st::cpIconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
auto opacity = 0.0f;
|
||||
if (iconName == wasSelected) {
|
||||
opacity = 1.0f - animation.value(1.0f);
|
||||
} else if (iconName == AyuAssets::currentAppLogoName()) {
|
||||
opacity = wasSelected.isEmpty() ? 1.0f : animation.value(1.0f);
|
||||
}
|
||||
|
||||
drawIcon(p,
|
||||
icon,
|
||||
(st::cpIconSize + st::cpSpacingX) * i + offset,
|
||||
row * (st::cpIconSize + st::cpSpacingY),
|
||||
AyuAssets::currentAppLogoName() == iconName);
|
||||
opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +115,17 @@ void IconPicker::mousePressEvent(QMouseEvent *e) {
|
||||
&& e->pos().y() <= yOffset + st::cpIconSize) {
|
||||
const auto &iconName = icons[idx];
|
||||
if (settings->appIcon != iconName) {
|
||||
wasSelected = settings->appIcon;
|
||||
animation.start(
|
||||
[=]
|
||||
{
|
||||
update();
|
||||
},
|
||||
0.0,
|
||||
1.0,
|
||||
200,
|
||||
anim::easeOutCubic);
|
||||
|
||||
settings->set_appIcon(iconName);
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/effects/animations.h"
|
||||
|
||||
class IconPicker : public Ui::RpWidget
|
||||
{
|
||||
@@ -16,4 +17,7 @@ public:
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
|
||||
Ui::Animations::Simple animation;
|
||||
QString wasSelected;
|
||||
};
|
||||
|
||||
@@ -563,6 +563,31 @@ void SetupSpyEssentials(not_null<Ui::VerticalLayout*> container) {
|
||||
container->lifetime());
|
||||
}
|
||||
|
||||
void SetupMessageFilters(not_null<Ui::VerticalLayout*> container) {
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
|
||||
AddSubsectionTitle(container, tr::ayu_RegexFilters());
|
||||
|
||||
AddButtonWithIcon(
|
||||
container,
|
||||
tr::ayu_FiltersHideFromBlocked(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->hideFromBlocked)
|
||||
)->toggledValue(
|
||||
) | rpl::filter(
|
||||
[=](bool enabled)
|
||||
{
|
||||
return (enabled != settings->hideFromBlocked);
|
||||
}) | start_with_next(
|
||||
[=](bool enabled)
|
||||
{
|
||||
settings->set_hideFromBlocked(enabled);
|
||||
AyuSettings::save();
|
||||
},
|
||||
container->lifetime());
|
||||
}
|
||||
|
||||
void SetupQoLToggles(not_null<Ui::VerticalLayout*> container) {
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
|
||||
@@ -667,29 +692,6 @@ void SetupQoLToggles(not_null<Ui::VerticalLayout*> container) {
|
||||
AddDivider(container);
|
||||
AddSkip(container);
|
||||
|
||||
AddButtonWithIcon(
|
||||
container,
|
||||
tr::ayu_UploadSpeedBoostPC(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->uploadSpeedBoost)
|
||||
)->toggledValue(
|
||||
) | rpl::filter(
|
||||
[=](bool enabled)
|
||||
{
|
||||
return (enabled != settings->uploadSpeedBoost);
|
||||
}) | start_with_next(
|
||||
[=](bool enabled)
|
||||
{
|
||||
settings->set_uploadSpeedBoost(enabled);
|
||||
AyuSettings::save();
|
||||
},
|
||||
container->lifetime());
|
||||
|
||||
AddSkip(container);
|
||||
AddDivider(container);
|
||||
AddSkip(container);
|
||||
|
||||
AddButtonWithIcon(
|
||||
container,
|
||||
tr::ayu_DisableNotificationsDelay(),
|
||||
@@ -1031,7 +1033,7 @@ void SetupRecentStickersLimitSlider(not_null<Ui::VerticalLayout*> container) {
|
||||
st::autoDownloadLimitSlider,
|
||||
st::settingsScaleLabel,
|
||||
0,
|
||||
st::settingsScaleLabel.style.font->width("30%"));
|
||||
st::settingsScaleLabel.style.font->width("8%%"));
|
||||
container->add(std::move(recentStickersLimitSlider.widget), st::recentStickersLimitPadding);
|
||||
const auto slider = recentStickersLimitSlider.slider;
|
||||
const auto label = recentStickersLimitSlider.label;
|
||||
@@ -1340,6 +1342,12 @@ void SetupAyuGramSettings(not_null<Ui::VerticalLayout*> container,
|
||||
|
||||
AddDivider(container);
|
||||
|
||||
AddSkip(container);
|
||||
SetupMessageFilters(container);
|
||||
AddSkip(container);
|
||||
|
||||
AddDivider(container);
|
||||
|
||||
AddSkip(container);
|
||||
SetupQoLToggles(container);
|
||||
AddSkip(container);
|
||||
@@ -1354,7 +1362,6 @@ void SetupAyuGramSettings(not_null<Ui::VerticalLayout*> container,
|
||||
AddSkip(container);
|
||||
SetupSendConfirmations(container);
|
||||
AddSkip(container);
|
||||
AddDivider(container);
|
||||
|
||||
AddDividerText(container, tr::ayu_SettingsWatermark());
|
||||
}
|
||||
|
||||
@@ -29,12 +29,14 @@
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_unread_things.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/text/format_values.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/ayu_state.h"
|
||||
|
||||
// https://github.com/AyuGram/AyuGram4AX/blob/rewrite/TMessagesProj/src/main/java/com/radolyn/ayugram/AyuConstants.java
|
||||
std::unordered_set<ID> ayugram_channels = {
|
||||
@@ -160,6 +162,31 @@ bool isExteraRelated(ID peerId) {
|
||||
return extera_devs.contains(peerId) || extera_channels.contains(peerId);
|
||||
}
|
||||
|
||||
bool isMessageHidden(const not_null<HistoryItem*> item) {
|
||||
if (AyuState::isHidden(item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->hideFromBlocked) {
|
||||
if (item->from()->isUser() &&
|
||||
item->from()->asUser()->isBlocked()) {
|
||||
// don't hide messages if it's a dialog with blocked user
|
||||
return item->from()->asUser()->id != item->history()->peer->id;
|
||||
}
|
||||
|
||||
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
|
||||
if (forwarded->originalSender &&
|
||||
forwarded->originalSender->isUser() &&
|
||||
forwarded->originalSender->asUser()->isBlocked()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MarkAsReadChatList(not_null<Dialogs::MainList*> list) {
|
||||
auto mark = std::vector<not_null<History*>>();
|
||||
for (const auto &row : list->indexed()->all()) {
|
||||
@@ -223,7 +250,7 @@ void readReactions(base::weak_ptr<Data::Thread> weakThread) {
|
||||
}
|
||||
|
||||
void MarkAsReadThread(not_null<Data::Thread*> thread) {
|
||||
const auto readHistory = [&](not_null<History*> history)
|
||||
const auto readHistoryNative = [&](not_null<History*> history)
|
||||
{
|
||||
history->owner().histories().readInbox(history);
|
||||
};
|
||||
@@ -245,13 +272,13 @@ void MarkAsReadThread(not_null<Data::Thread*> thread) {
|
||||
{
|
||||
MarkAsReadThread(topic);
|
||||
});
|
||||
} else if (const auto history = thread->asHistory()) {
|
||||
readHistory(history);
|
||||
if (const auto migrated = history->migrateSibling()) {
|
||||
readHistory(migrated);
|
||||
}
|
||||
} else if (const auto topic = thread->asTopic()) {
|
||||
topic->readTillEnd();
|
||||
} else if (const auto history = thread->asHistory()) {
|
||||
readHistoryNative(history);
|
||||
if (const auto migrated = history->migrateSibling()) {
|
||||
readHistoryNative(migrated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,11 +519,7 @@ QString getMediaDC(not_null<HistoryItem*> message) {
|
||||
|
||||
int getScheduleTime(int64 sumSize) {
|
||||
auto time = 12;
|
||||
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
const auto multiplier = settings->uploadSpeedBoost ? 0.7 : 4.5;
|
||||
time += (int) std::ceil(std::max(6.0, std::ceil(sumSize / 1024.0 / 1024.0 * multiplier))) + 1;
|
||||
|
||||
time += (int) std::ceil(std::max(6.0, std::ceil(sumSize / 1024.0 / 1024.0 * 0.7))) + 1;
|
||||
return time;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ ID getBareID(not_null<PeerData*> peer);
|
||||
bool isAyuGramRelated(ID peerId);
|
||||
bool isExteraRelated(ID peerId);
|
||||
|
||||
bool isMessageHidden(not_null<HistoryItem*> item);
|
||||
|
||||
void MarkAsReadChatList(not_null<Dialogs::MainList*> list);
|
||||
void MarkAsReadThread(not_null<Data::Thread*> thread);
|
||||
|
||||
|
||||
@@ -605,8 +605,8 @@ void GroupInfoBox::prepare() {
|
||||
_navigation->session().api().selfDestruct().reload();
|
||||
|
||||
const auto top = addTopButton(st::infoTopBarMenu);
|
||||
const auto menu =
|
||||
top->lifetime().make_state<base::unique_qptr<Ui::PopupMenu>>();
|
||||
const auto menu
|
||||
= top->lifetime().make_state<base::unique_qptr<Ui::PopupMenu>>();
|
||||
top->setClickedCallback([=] {
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
top,
|
||||
@@ -1306,8 +1306,8 @@ void SetupChannelBox::handleChange() {
|
||||
&& (ch < 'a' || ch > 'z')
|
||||
&& (ch < '0' || ch > '9')
|
||||
&& ch != '_') {
|
||||
const auto badSymbols =
|
||||
tr::lng_create_channel_link_bad_symbols(tr::now);
|
||||
const auto badSymbols
|
||||
= tr::lng_create_channel_link_bad_symbols(tr::now);
|
||||
if (_errorText != badSymbols) {
|
||||
_errorText = badSymbols;
|
||||
update();
|
||||
@@ -1317,8 +1317,8 @@ void SetupChannelBox::handleChange() {
|
||||
}
|
||||
}
|
||||
if (name.size() < Ui::EditPeer::kMinUsernameLength) {
|
||||
const auto tooShort =
|
||||
tr::lng_create_channel_link_too_short(tr::now);
|
||||
const auto tooShort
|
||||
= tr::lng_create_channel_link_too_short(tr::now);
|
||||
if (_errorText != tooShort) {
|
||||
_errorText = tooShort;
|
||||
update();
|
||||
|
||||
@@ -593,11 +593,11 @@ void BackgroundPreviewBox::uploadForPeer(bool both) {
|
||||
const auto ready = Window::Theme::PrepareWallPaper(
|
||||
session->mainDcId(),
|
||||
_paper.localThumbnail()->original());
|
||||
const auto documentId = ready.id;
|
||||
const auto documentId = ready->id;
|
||||
_uploadId = FullMsgId(
|
||||
session->userPeerId(),
|
||||
session->data().nextLocalMessageId());
|
||||
session->uploader().uploadMedia(_uploadId, ready);
|
||||
session->uploader().upload(_uploadId, ready);
|
||||
if (_uploadLifetime) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1044,3 +1044,33 @@ inviteForbiddenTitle: FlatLabel(boxTitle) {
|
||||
inviteForbiddenTitlePadding: margins(32px, 4px, 32px, 0px);
|
||||
inviteForbiddenLockBg: dialogsUnreadBgMuted;
|
||||
inviteForbiddenLockIcon: icon {{ "emoji/premium_lock", dialogsUnreadFg }};
|
||||
|
||||
collectibleIconDiameter: 72px;
|
||||
collectibleIcon: 64px;
|
||||
collectibleIconPadding: margins(24px, 32px, 24px, 12px);
|
||||
collectibleHeader: FlatLabel(boxTitle) {
|
||||
minWidth: 120px;
|
||||
maxHeight: 0px;
|
||||
align: align(top);
|
||||
}
|
||||
collectibleHeaderPadding: margins(24px, 16px, 24px, 12px);
|
||||
collectibleOwnerPadding: margins(24px, 4px, 24px, 8px);
|
||||
collectibleInfo: inviteForbiddenInfo;
|
||||
collectibleInfoPadding: margins(24px, 12px, 24px, 12px);
|
||||
collectibleInfoTonMargins: margins(0px, 3px, 0px, 0px);
|
||||
collectibleMore: RoundButton(defaultActiveButton) {
|
||||
height: 36px;
|
||||
textTop: 9px;
|
||||
radius: 6px;
|
||||
}
|
||||
collectibleMorePadding: margins(24px, 12px, 24px, 0px);
|
||||
collectibleCopy: RoundButton(defaultLightButton) {
|
||||
height: 36px;
|
||||
textTop: 9px;
|
||||
radius: 6px;
|
||||
}
|
||||
collectibleBox: Box(defaultBox) {
|
||||
buttonPadding: margins(24px, 12px, 24px, 12px);
|
||||
buttonHeight: 36px;
|
||||
button: collectibleCopy;
|
||||
}
|
||||
|
||||
@@ -232,8 +232,8 @@ void DeleteMessagesBox::prepare() {
|
||||
if (hasScheduledMessages()) {
|
||||
} else if (auto revoke = revokeText(peer)) {
|
||||
const auto &settings = Core::App().settings();
|
||||
const auto revokeByDefault =
|
||||
!settings.rememberedDeleteMessageOnlyForYou();
|
||||
const auto revokeByDefault
|
||||
= !settings.rememberedDeleteMessageOnlyForYou();
|
||||
_revoke.create(
|
||||
this,
|
||||
revoke->checkbox,
|
||||
|
||||
@@ -159,10 +159,7 @@ public:
|
||||
-> rpl::producer<RowSelectionChange>;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::unique_ptr<PeerListRow> createRow() const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
bool _premiums = false;
|
||||
|
||||
rpl::event_stream<> _selectionChanged;
|
||||
rpl::event_stream<RowSelectionChange> _rowSelectionChanges;
|
||||
@@ -209,8 +206,7 @@ bool PremiumsRow::useForumLikeUserpic() const {
|
||||
TypesController::TypesController(
|
||||
not_null<Main::Session*> session,
|
||||
bool premiums)
|
||||
: _session(session)
|
||||
, _premiums(premiums) {
|
||||
: _session(session) {
|
||||
}
|
||||
|
||||
Main::Session &TypesController::session() const {
|
||||
@@ -331,6 +327,9 @@ auto PrivacyExceptionsBoxController::preparePremiumsRowList()
|
||||
|
||||
_deselectOption = [=](PeerListRowId itemId) {
|
||||
if (const auto row = _typesDelegate->peerListFindRow(itemId)) {
|
||||
if (itemId == kPremiumsRowId) {
|
||||
_selected.premiums = false;
|
||||
}
|
||||
_typesDelegate->peerListSetRowChecked(row, false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,7 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/peers/prepare_short_info_box.h"
|
||||
#include "boxes/peers/replace_boost_box.h" // BoostsForGift.
|
||||
#include "boxes/premium_preview_box.h" // ShowPremiumPreviewBox.
|
||||
#include "core/ui_integration.h" // Core::MarkedTextContext.
|
||||
#include "data/data_boosts.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
@@ -48,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/gradient_round_button.h"
|
||||
#include "ui/widgets/label_with_custom_emoji.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/table_layout.h"
|
||||
@@ -319,21 +319,20 @@ void GiftBox(
|
||||
std::move(titleLabel)),
|
||||
st::premiumGiftTitlePadding);
|
||||
|
||||
auto textLabel = object_ptr<Ui::FlatLabel>(box, st::premiumPreviewAbout);
|
||||
tr::lng_premium_gift_about(
|
||||
lt_user,
|
||||
user->session().changes().peerFlagsValue(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::Name
|
||||
) | rpl::map([=] { return TextWithEntities{ user->firstName }; }),
|
||||
Ui::Text::RichLangValue
|
||||
) | rpl::map(
|
||||
BoostsForGiftText({ user })
|
||||
) | rpl::start_with_next([
|
||||
raw = textLabel.data(),
|
||||
session = &user->session()](const TextWithEntities &t) {
|
||||
raw->setMarkedText(t, Core::MarkedTextContext{ .session = session });
|
||||
}, textLabel->lifetime());
|
||||
auto textLabel = Ui::CreateLabelWithCustomEmoji(
|
||||
box,
|
||||
tr::lng_premium_gift_about(
|
||||
lt_user,
|
||||
user->session().changes().peerFlagsValue(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::Name
|
||||
) | rpl::map([=] { return TextWithEntities{ user->firstName }; }),
|
||||
Ui::Text::RichLangValue
|
||||
) | rpl::map(
|
||||
BoostsForGiftText({ user })
|
||||
),
|
||||
{ .session = &user->session() },
|
||||
st::premiumPreviewAbout);
|
||||
textLabel->setTextColorOverride(stTitle.textFg->c);
|
||||
textLabel->resizeToWidth(available);
|
||||
box->addRow(
|
||||
@@ -536,14 +535,12 @@ void GiftsBox(
|
||||
const auto label = box->addRow(
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(box, st::premiumPreviewAbout)),
|
||||
Ui::CreateLabelWithCustomEmoji(
|
||||
box,
|
||||
std::move(text),
|
||||
{ .session = session },
|
||||
st::premiumPreviewAbout)),
|
||||
padding)->entity();
|
||||
std::move(
|
||||
text
|
||||
) | rpl::start_with_next([=](const TextWithEntities &t) {
|
||||
using namespace Core;
|
||||
label->setMarkedText(t, MarkedTextContext{ .session = session });
|
||||
}, label->lifetime());
|
||||
label->setTextColorOverride(stTitle.textFg->c);
|
||||
label->resizeToWidth(available);
|
||||
}
|
||||
|
||||
@@ -740,7 +740,7 @@ void PasscodeBox::submitOnlyCheckCloudPassword(const QString &oldPassword) {
|
||||
void PasscodeBox::sendOnlyCheckCloudPassword(const QString &oldPassword) {
|
||||
checkPassword(oldPassword, [=](const Core::CloudPasswordResult &check) {
|
||||
if (const auto onstack = _cloudFields.customCheckCallback) {
|
||||
onstack(check);
|
||||
onstack(check, Ui::MakeWeak(this));
|
||||
} else {
|
||||
Assert(_cloudFields.turningOff);
|
||||
sendClearCloudPassword(check);
|
||||
|
||||
@@ -51,7 +51,10 @@ public:
|
||||
TimeId pendingResetDate = 0;
|
||||
|
||||
// Check cloud password for some action.
|
||||
Fn<void(const Core::CloudPasswordResult &)> customCheckCallback;
|
||||
using CustomCheck = Fn<void(
|
||||
const Core::CloudPasswordResult &,
|
||||
QPointer<PasscodeBox>)>;
|
||||
CustomCheck customCheckCallback;
|
||||
rpl::producer<QString> customTitle;
|
||||
std::optional<QString> customDescription;
|
||||
rpl::producer<QString> customSubmitButton;
|
||||
|
||||
@@ -1039,11 +1039,9 @@ void PeerListContent::changeCheckState(
|
||||
not_null<PeerListRow*> row,
|
||||
bool checked,
|
||||
anim::type animated) {
|
||||
row->setChecked(
|
||||
checked,
|
||||
_st.item.checkbox,
|
||||
animated,
|
||||
[=] { updateRow(row); });
|
||||
row->setChecked(checked, _st.item.checkbox, animated, [=] {
|
||||
updateRow(row);
|
||||
});
|
||||
}
|
||||
|
||||
void PeerListContent::setRowHidden(not_null<PeerListRow*> row, bool hidden) {
|
||||
@@ -1789,10 +1787,10 @@ crl::time PeerListContent::paintRow(
|
||||
if (row->isSearchResult()
|
||||
&& !_mentionHighlight.isEmpty()
|
||||
&& peer
|
||||
&& peer->userName().startsWith(
|
||||
&& peer->username().startsWith(
|
||||
_mentionHighlight,
|
||||
Qt::CaseInsensitive)) {
|
||||
const auto username = peer->userName();
|
||||
const auto username = peer->username();
|
||||
const auto availableWidth = statusw;
|
||||
auto highlightedPart = '@' + username.mid(0, _mentionHighlight.size());
|
||||
auto grayedPart = username.mid(_mentionHighlight.size());
|
||||
|
||||
@@ -100,7 +100,7 @@ void Controller::prepare() {
|
||||
return;
|
||||
}
|
||||
auto row = std::make_unique<PeerListRow>(chat);
|
||||
const auto username = chat->userName();
|
||||
const auto username = chat->username();
|
||||
row->setCustomStatus(!username.isEmpty()
|
||||
? ('@' + username)
|
||||
: (chat->isChannel() && !chat->isMegagroup())
|
||||
|
||||
@@ -598,19 +598,17 @@ void EditAdminBox::requestTransferPassword(not_null<ChannelData*> channel) {
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) {
|
||||
const auto box = std::make_shared<QPointer<PasscodeBox>>();
|
||||
auto fields = PasscodeBox::CloudFields::From(state);
|
||||
fields.customTitle = tr::lng_rights_transfer_password_title();
|
||||
fields.customDescription
|
||||
= tr::lng_rights_transfer_password_description(tr::now);
|
||||
fields.customSubmitButton = tr::lng_passcode_submit();
|
||||
fields.customCheckCallback = crl::guard(this, [=](
|
||||
const Core::CloudPasswordResult &result) {
|
||||
sendTransferRequestFrom(*box, channel, result);
|
||||
const Core::CloudPasswordResult &result,
|
||||
QPointer<PasscodeBox> box) {
|
||||
sendTransferRequestFrom(box, channel, result);
|
||||
});
|
||||
*box = getDelegate()->show(Box<PasscodeBox>(
|
||||
&channel->session(),
|
||||
fields));
|
||||
getDelegate()->show(Box<PasscodeBox>(&channel->session(), fields));
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "styles/style_layers.h"
|
||||
@@ -23,6 +24,17 @@ void EditPeerHistoryVisibilityBox(
|
||||
Ui::RadioenumGroup<HistoryVisibility>
|
||||
>(historyVisibilitySavedValue);
|
||||
|
||||
const auto addButton = [=](
|
||||
not_null<Ui::RpWidget*> inner,
|
||||
HistoryVisibility v) {
|
||||
const auto button = Ui::CreateChild<Ui::AbstractButton>(inner.get());
|
||||
inner->sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &s) {
|
||||
button->resize(s);
|
||||
}, button->lifetime());
|
||||
button->setClickedCallback([=] { historyVisibility->setValue(v); });
|
||||
};
|
||||
|
||||
box->setTitle(tr::lng_manage_history_visibility_title());
|
||||
box->addButton(tr::lng_settings_save(), [=] {
|
||||
savedCallback(historyVisibility->current());
|
||||
@@ -31,32 +43,36 @@ void EditPeerHistoryVisibilityBox(
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
|
||||
box->addSkip(st::editPeerHistoryVisibilityTopSkip);
|
||||
box->addRow(object_ptr<Ui::Radioenum<HistoryVisibility>>(
|
||||
const auto visible = box->addRow(object_ptr<Ui::VerticalLayout>(box));
|
||||
visible->add(object_ptr<Ui::Radioenum<HistoryVisibility>>(
|
||||
box,
|
||||
historyVisibility,
|
||||
HistoryVisibility::Visible,
|
||||
tr::lng_manage_history_visibility_shown(tr::now),
|
||||
st::defaultBoxCheckbox));
|
||||
box->addRow(
|
||||
visible->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_manage_history_visibility_shown_about(),
|
||||
st::editPeerPrivacyLabel),
|
||||
st::editPeerPreHistoryLabelMargins + st::boxRowPadding);
|
||||
st::editPeerPreHistoryLabelMargins);
|
||||
addButton(visible, HistoryVisibility::Visible);
|
||||
|
||||
box->addSkip(st::editPeerHistoryVisibilityTopSkip);
|
||||
box->addRow(object_ptr<Ui::Radioenum<HistoryVisibility>>(
|
||||
const auto hidden = box->addRow(object_ptr<Ui::VerticalLayout>(box));
|
||||
hidden->add(object_ptr<Ui::Radioenum<HistoryVisibility>>(
|
||||
box,
|
||||
historyVisibility,
|
||||
HistoryVisibility::Hidden,
|
||||
tr::lng_manage_history_visibility_hidden(tr::now),
|
||||
st::defaultBoxCheckbox));
|
||||
box->addRow(
|
||||
hidden->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
(isLegacy
|
||||
? tr::lng_manage_history_visibility_hidden_legacy
|
||||
: tr::lng_manage_history_visibility_hidden_about)(),
|
||||
st::editPeerPrivacyLabel),
|
||||
st::editPeerPreHistoryLabelMargins + st::boxRowPadding);
|
||||
st::editPeerPreHistoryLabelMargins);
|
||||
addButton(hidden, HistoryVisibility::Hidden);
|
||||
}
|
||||
|
||||
@@ -983,8 +983,8 @@ void Controller::fillHistoryVisibilityButton() {
|
||||
: HistoryVisibility::Visible;
|
||||
_channelHasLocationOriginalValue = channel && channel->hasLocation();
|
||||
|
||||
const auto updateHistoryVisibility =
|
||||
std::make_shared<rpl::event_stream<HistoryVisibility>>();
|
||||
const auto updateHistoryVisibility
|
||||
= std::make_shared<rpl::event_stream<HistoryVisibility>>();
|
||||
|
||||
const auto boxCallback = crl::guard(this, [=](HistoryVisibility checked) {
|
||||
updateHistoryVisibility->fire(std::move(checked));
|
||||
@@ -1698,8 +1698,8 @@ void Controller::saveUsernamesOrder() {
|
||||
channel->setUsernames(ranges::views::all(
|
||||
newUsernames
|
||||
) | ranges::views::transform([&](QString username) {
|
||||
const auto editable =
|
||||
(channel->editableUsername() == username);
|
||||
const auto editable
|
||||
= (channel->editableUsername() == username);
|
||||
return Data::Username{
|
||||
.username = std::move(username),
|
||||
.active = true,
|
||||
|
||||
@@ -227,9 +227,9 @@ QImage QrExact(const Qr::Data &data, int pixel, QColor color) {
|
||||
p.drawImage(
|
||||
skip,
|
||||
skip,
|
||||
Intro::details::TelegramLogoImage().scaled(
|
||||
logoSize * style::DevicePixelRatio(),
|
||||
logoSize * style::DevicePixelRatio(),
|
||||
Window::LogoNoMargin().scaled(
|
||||
logoSize,
|
||||
logoSize,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ void ProcessFullPhoto(
|
||||
| UpdateFlag::Birthday)
|
||||
) | rpl::map([=] {
|
||||
const auto user = peer->asUser();
|
||||
const auto username = peer->userName();
|
||||
const auto username = peer->username();
|
||||
return PeerShortInfoFields{
|
||||
.name = peer->name(),
|
||||
.phone = user ? Ui::FormatPhone(user->phone()) : QString(),
|
||||
|
||||
@@ -322,7 +322,7 @@ void PublicsController::prepare() {
|
||||
auto &owner = _navigation->session().data();
|
||||
for (const auto &chat : chats) {
|
||||
if (const auto peer = owner.processChat(chat)) {
|
||||
if (!peer->isChannel() || peer->userName().isEmpty()) {
|
||||
if (!peer->isChannel() || peer->username().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
appendRow(peer);
|
||||
@@ -346,7 +346,7 @@ void PublicsController::rowRightActionClicked(not_null<PeerListRow*> row) {
|
||||
const auto text = textMethod(
|
||||
tr::now,
|
||||
lt_link,
|
||||
peer->session().createInternalLink(peer->userName()),
|
||||
peer->session().createInternalLink(peer->username()),
|
||||
lt_group,
|
||||
peer->name());
|
||||
const auto confirmText = tr::lng_channels_too_much_public_revoke(
|
||||
@@ -389,7 +389,7 @@ std::unique_ptr<PeerListRow> PublicsController::createRow(
|
||||
auto result = std::make_unique<PeerListRowWithLink>(peer);
|
||||
result->setActionLink(tr::lng_channels_too_much_public_revoke(tr::now));
|
||||
result->setCustomStatus(
|
||||
_navigation->session().createInternalLink(peer->userName()));
|
||||
_navigation->session().createInternalLink(peer->username()));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1240,8 +1240,8 @@ void DecorateListPromoBox(
|
||||
box->setStyle(st::premiumPreviewDoubledLimitsBox);
|
||||
box->widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
const auto &padding =
|
||||
st::premiumPreviewDoubledLimitsBox.buttonPadding;
|
||||
const auto &padding
|
||||
= st::premiumPreviewDoubledLimitsBox.buttonPadding;
|
||||
button->resizeToWidth(width
|
||||
- padding.left()
|
||||
- padding.right());
|
||||
|
||||
@@ -90,7 +90,7 @@ QString ExtractRingtoneName(not_null<DocumentData*> document) {
|
||||
}
|
||||
const auto name = document->filename();
|
||||
if (!name.isEmpty()) {
|
||||
const auto extension = Data::FileExtension(name);
|
||||
const auto extension = Core::FileExtension(name);
|
||||
if (extension.isEmpty()) {
|
||||
return name;
|
||||
} else if (name.size() > extension.size() + 1) {
|
||||
|
||||
@@ -611,8 +611,8 @@ void StickerSetBox::updateButtons() {
|
||||
|
||||
if (!_inner->shortName().isEmpty()) {
|
||||
const auto top = addTopButton(st::infoTopBarMenu);
|
||||
const auto menu =
|
||||
std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
|
||||
const auto menu
|
||||
= std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
|
||||
top->setClickedCallback([=] {
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
top,
|
||||
@@ -656,8 +656,8 @@ void StickerSetBox::updateButtons() {
|
||||
_show->showBox(std::move(box));
|
||||
}
|
||||
};
|
||||
const auto menu =
|
||||
std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
|
||||
const auto menu
|
||||
= std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
|
||||
top->setClickedCallback([=] {
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
top,
|
||||
|
||||
@@ -652,8 +652,8 @@ void StickersBox::prepare() {
|
||||
}
|
||||
if (const auto featured = _featured.widget()) {
|
||||
featured->setInstallSetCallback([=](uint64 setId) {
|
||||
markAsInstalledCallback(setId);
|
||||
installCallback(setId);
|
||||
markAsInstalledCallback(setId);
|
||||
});
|
||||
featured->setRemoveSetCallback(markAsRemovedCallback);
|
||||
}
|
||||
@@ -1760,8 +1760,11 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
|
||||
const auto &st = installedSet
|
||||
? st::stickersTrendingInstalled
|
||||
: st::stickersTrendingAdd;
|
||||
const auto buttonTextWidth = installedSet
|
||||
? _installedWidth
|
||||
: _addWidth;
|
||||
auto rippleMask = Ui::RippleAnimation::RoundRectMask(
|
||||
QSize(_addWidth - st.width, st.height),
|
||||
QSize(buttonTextWidth - st.width, st.height),
|
||||
st::roundRadiusLarge);
|
||||
ensureRipple(
|
||||
st.ripple,
|
||||
@@ -1902,9 +1905,19 @@ void StickersBox::Inner::updateSelected() {
|
||||
selected = selectedIndex;
|
||||
local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight);
|
||||
const auto row = _rows[selectedIndex].get();
|
||||
if (!_megagroupSet && (_isInstalledTab || (_section == Section::Featured) || !row->isInstalled() || row->isArchived() || row->removed)) {
|
||||
if (!_megagroupSet
|
||||
&& (_isInstalledTab
|
||||
|| (_section == Section::Featured)
|
||||
|| !row->isInstalled()
|
||||
|| row->isArchived()
|
||||
|| row->removed)) {
|
||||
auto removeButton = (_isInstalledTab && !row->removed);
|
||||
auto rect = myrtlrect(relativeButtonRect(removeButton, false));
|
||||
|
||||
const auto installedSetButton = !_isInstalledTab
|
||||
&& row->isInstalled()
|
||||
&& !row->isArchived()
|
||||
&& !row->removed;
|
||||
auto rect = myrtlrect(relativeButtonRect(removeButton, installedSetButton));
|
||||
actionSel = rect.contains(local) ? selectedIndex : -1;
|
||||
} else {
|
||||
actionSel = -1;
|
||||
@@ -1957,12 +1970,19 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
|
||||
_mouse = e->globalPos();
|
||||
updateSelected();
|
||||
if (_actionDown == _actionSel && _actionSel >= 0) {
|
||||
const auto callback = _rows[_actionDown]->removed
|
||||
? _installSetCallback
|
||||
: _removeSetCallback;
|
||||
const auto down = _actionDown;
|
||||
setActionDown(-1);
|
||||
if (down == _actionSel && _actionSel >= 0) {
|
||||
const auto row = _rows[down].get();
|
||||
const auto installedSet = row->isInstalled()
|
||||
&& !row->isArchived()
|
||||
&& !row->removed;
|
||||
const auto callback = installedSet
|
||||
? _removeSetCallback
|
||||
: _installSetCallback;
|
||||
if (callback) {
|
||||
callback(_rows[_actionDown]->set->id);
|
||||
row->ripple.reset();
|
||||
callback(row->set->id);
|
||||
}
|
||||
} else if (_dragging >= 0) {
|
||||
_rows[_dragging]->yadd.start(0.);
|
||||
@@ -1973,7 +1993,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
}
|
||||
|
||||
_dragging = _started = -1;
|
||||
} else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) {
|
||||
} else if (pressed == _selected && _actionSel < 0 && down < 0) {
|
||||
const auto selectedIndex = [&] {
|
||||
if (auto index = std::get_if<int>(&_selected)) {
|
||||
return *index;
|
||||
@@ -1997,7 +2017,6 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
showSetByRow(*_megagroupSelectedSet);
|
||||
}
|
||||
}
|
||||
setActionDown(-1);
|
||||
}
|
||||
|
||||
void StickersBox::Inner::saveGroupSet(Fn<void()> done) {
|
||||
|
||||
@@ -945,8 +945,8 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||
tgcalls::Descriptor descriptor = {
|
||||
.version = versionString,
|
||||
.config = tgcalls::Config{
|
||||
.initializationTimeout =
|
||||
serverConfig.callConnectTimeoutMs / 1000.,
|
||||
.initializationTimeout
|
||||
= serverConfig.callConnectTimeoutMs / 1000.,
|
||||
.receiveTimeout = serverConfig.callPacketTimeoutMs / 1000.,
|
||||
.dataSaving = tgcalls::DataSaving::Never,
|
||||
.enableP2P = call.is_p2p_allowed(),
|
||||
|
||||
@@ -277,11 +277,11 @@ private:
|
||||
MTP::Sender _api;
|
||||
Type _type = Type::Outgoing;
|
||||
rpl::variable<State> _state = State::Starting;
|
||||
rpl::variable<RemoteAudioState> _remoteAudioState =
|
||||
RemoteAudioState::Active;
|
||||
rpl::variable<RemoteAudioState> _remoteAudioState
|
||||
= RemoteAudioState::Active;
|
||||
rpl::variable<Webrtc::VideoState> _remoteVideoState;
|
||||
rpl::variable<RemoteBatteryState> _remoteBatteryState =
|
||||
RemoteBatteryState::Normal;
|
||||
rpl::variable<RemoteBatteryState> _remoteBatteryState
|
||||
= RemoteBatteryState::Normal;
|
||||
rpl::event_stream<Error> _errors;
|
||||
FinishType _finishAfterRequestingCall = FinishType::None;
|
||||
bool _answerAfterDhConfigReceived = false;
|
||||
|
||||
@@ -162,8 +162,8 @@ private:
|
||||
object_ptr<Ui::FlatLabel> _status;
|
||||
object_ptr<Ui::RpWidget> _fingerprint = { nullptr };
|
||||
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteAudioMute = { nullptr };
|
||||
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteLowBattery =
|
||||
{ nullptr };
|
||||
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteLowBattery
|
||||
= { nullptr };
|
||||
std::unique_ptr<Userpic> _userpic;
|
||||
std::unique_ptr<VideoBubble> _outgoingVideoBubble;
|
||||
QPixmap _bottomShadow;
|
||||
|
||||
@@ -612,9 +612,9 @@ void MembersRow::paintComplexStatusText(
|
||||
x += skip;
|
||||
availableWidth -= skip;
|
||||
const auto &font = st::normalFont;
|
||||
const auto useAbout = (style == MembersRowStyle::Video)
|
||||
? false
|
||||
: ((_state == State::RaisedHand && !_raisedHandStatus)
|
||||
const auto useAbout = !_about.isEmpty()
|
||||
&& (style != MembersRowStyle::Video)
|
||||
&& ((_state == State::RaisedHand && !_raisedHandStatus)
|
||||
|| (_state != State::RaisedHand && !_speaking));
|
||||
if (!useAbout
|
||||
&& _state != State::Invited
|
||||
|
||||
@@ -25,8 +25,8 @@ const auto kSpeakerThreshold = std::vector<float>{
|
||||
50.0f / kMaxVolumePercent,
|
||||
150.0f / kMaxVolumePercent };
|
||||
|
||||
constexpr auto kVolumeStickedValues =
|
||||
std::array<std::pair<float64, float64>, 7>{{
|
||||
constexpr auto kVolumeStickedValues
|
||||
= std::array<std::pair<float64, float64>, 7>{{
|
||||
{ 25. / kMaxVolumePercent, 2. / kMaxVolumePercent },
|
||||
{ 50. / kMaxVolumePercent, 2. / kMaxVolumePercent },
|
||||
{ 75. / kMaxVolumePercent, 2. / kMaxVolumePercent },
|
||||
@@ -93,8 +93,8 @@ MenuVolumeItem::MenuVolumeItem(
|
||||
const auto volume = _localMuted
|
||||
? 0
|
||||
: base::SafeRound(_slider->value() * kMaxVolumePercent);
|
||||
const auto muteProgress =
|
||||
_crossLineAnimation.value((!volume) ? 1. : 0.);
|
||||
const auto muteProgress
|
||||
= _crossLineAnimation.value((!volume) ? 1. : 0.);
|
||||
|
||||
const auto selected = isSelected();
|
||||
p.fillRect(clip, selected ? st.itemBgOver : st.itemBg);
|
||||
@@ -174,8 +174,8 @@ MenuVolumeItem::MenuVolumeItem(
|
||||
return;
|
||||
}
|
||||
if (_waitingForUpdateVolume) {
|
||||
const auto localVolume =
|
||||
base::SafeRound(_slider->value() * _maxVolume);
|
||||
const auto localVolume
|
||||
= base::SafeRound(_slider->value() * _maxVolume);
|
||||
if ((localVolume != newVolume)
|
||||
&& (_cloudVolume == newVolume)) {
|
||||
_changeVolumeRequests.fire(int(localVolume));
|
||||
|
||||
@@ -587,11 +587,9 @@ void ChooseSourceProcess::setupGeometryWithParent(
|
||||
not_null<QWidget*> parent) {
|
||||
_window->createWinId();
|
||||
const auto parentScreen = [&] {
|
||||
if (!::Platform::IsWayland()) {
|
||||
if (const auto screen = QGuiApplication::screenAt(
|
||||
if (const auto screen = QGuiApplication::screenAt(
|
||||
parent->geometry().center())) {
|
||||
return screen;
|
||||
}
|
||||
return screen;
|
||||
}
|
||||
return parent->screen();
|
||||
}();
|
||||
|
||||
@@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
@@ -51,10 +52,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
// AyuGram includes
|
||||
#include "data/data_file_origin.h"
|
||||
#include "qapplication.h"
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
namespace ChatHelpers {
|
||||
namespace {
|
||||
@@ -62,6 +60,7 @@ namespace {
|
||||
constexpr auto kCollapsedRows = 3;
|
||||
constexpr auto kAppearDuration = 0.3;
|
||||
constexpr auto kCustomSearchLimit = 256;
|
||||
constexpr auto kColorPickerDelay = crl::time(500);
|
||||
|
||||
using Core::RecentEmojiId;
|
||||
using Core::RecentEmojiDocument;
|
||||
@@ -630,6 +629,15 @@ void EmojiListWidget::applyNextSearchQuery() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::showPreview() {
|
||||
if (const auto over = std::get_if<OverEmoji>(&_pressed)) {
|
||||
if (const auto custom = lookupCustomEmoji(over)) {
|
||||
_show->showMediaPreview(custom->stickerSetOrigin(), custom);
|
||||
_previewShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<EmojiPtr> EmojiListWidget::collectPlainSearchResults() {
|
||||
return SearchEmoji(_searchQuery, _searchEmoji);
|
||||
}
|
||||
@@ -1125,7 +1133,7 @@ void EmojiListWidget::fillRecentMenu(
|
||||
const auto addAction = Ui::Menu::CreateAddActionCallback(menu);
|
||||
const auto over = OverEmoji{ section, index };
|
||||
const auto emoji = lookupOverEmoji(&over);
|
||||
const auto custom = lookupCustomEmoji(index, section);
|
||||
const auto custom = lookupCustomEmoji(&over);
|
||||
if (custom && custom->sticker()) {
|
||||
const auto sticker = custom->sticker();
|
||||
const auto emoji = sticker->alt;
|
||||
@@ -1498,6 +1506,11 @@ bool EmojiListWidget::checkPickerHide() {
|
||||
return false;
|
||||
}
|
||||
|
||||
DocumentData *EmojiListWidget::lookupCustomEmoji(
|
||||
const OverEmoji *over) const {
|
||||
return over ? lookupCustomEmoji(over->index, over->section) : nullptr;
|
||||
}
|
||||
|
||||
DocumentData *EmojiListWidget::lookupCustomEmoji(
|
||||
int index,
|
||||
int section) const {
|
||||
@@ -1600,12 +1613,14 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
||||
if (!Core::App().settings().hasChosenEmojiVariant(emoji)) {
|
||||
showPicker();
|
||||
} else {
|
||||
_showPickerTimer.callOnce(500);
|
||||
_previewTimer.cancel();
|
||||
_showPickerTimer.callOnce(kColorPickerDelay);
|
||||
}
|
||||
} else if (lookupCustomEmoji(over)) {
|
||||
_showPickerTimer.cancel();
|
||||
_previewTimer.callOnce(QApplication::startDragTime());
|
||||
}
|
||||
}
|
||||
|
||||
_previewTimer.callOnce(QApplication::startDragTime());
|
||||
}
|
||||
|
||||
void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
@@ -1613,11 +1628,6 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
|
||||
auto pressed = _pressed;
|
||||
setPressed(v::null);
|
||||
if (_previewShown) {
|
||||
_previewShown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_lastMousePos = e->globalPos();
|
||||
if (!_picker->isHidden()) {
|
||||
if (_picker->rect().contains(_picker->mapFromGlobal(_lastMousePos))) {
|
||||
@@ -1640,7 +1650,10 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_picker->hide();
|
||||
}
|
||||
|
||||
if (v::is_null(_selected) || _selected != pressed) {
|
||||
if (_previewShown) {
|
||||
_previewShown = false;
|
||||
return;
|
||||
} else if (v::is_null(_selected) || _selected != pressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1659,7 +1672,7 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
return;
|
||||
}
|
||||
selectEmoji(lookupChosen(emoji, over));
|
||||
} else if (const auto custom = lookupCustomEmoji(index, section)) {
|
||||
} else if (const auto custom = lookupCustomEmoji(over)) {
|
||||
selectCustom(lookupChosen(custom, over));
|
||||
}
|
||||
} else if (const auto set = std::get_if<OverSet>(&pressed)) {
|
||||
@@ -2492,8 +2505,10 @@ bool EmojiListWidget::eventHook(QEvent *e) {
|
||||
}
|
||||
|
||||
void EmojiListWidget::updateSelected() {
|
||||
if ((!v::is_null(_pressed) || !v::is_null(_pickerSelected)) && !_previewShown) {
|
||||
return;
|
||||
if (!v::is_null(_pressed) || !v::is_null(_pickerSelected)) {
|
||||
if (!_previewShown) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto newSelected = OverState{ v::null };
|
||||
@@ -2552,34 +2567,16 @@ void EmojiListWidget::setSelected(OverState newSelected) {
|
||||
} else {
|
||||
_picker->showAnimated();
|
||||
}
|
||||
}
|
||||
|
||||
if (_previewShown && _pressed != _selected) {
|
||||
} else if (_previewShown && _pressed != _selected) {
|
||||
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
||||
_pressed = _selected;
|
||||
|
||||
const auto section = over ? over->section : -1;
|
||||
const auto index = over ? over->index : -1;
|
||||
|
||||
if (const auto document = lookupCustomEmoji(index, section)) {
|
||||
_show->showMediaPreview(document->stickerSetOrigin(), document);
|
||||
if (const auto custom = lookupCustomEmoji(over)) {
|
||||
_pressed = _selected;
|
||||
_show->showMediaPreview(custom->stickerSetOrigin(), custom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::showPreview() {
|
||||
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
||||
const auto section = over ? over->section : -1;
|
||||
const auto index = over ? over->index : -1;
|
||||
|
||||
if (const auto document = lookupCustomEmoji(index, section)) {
|
||||
_show->showMediaPreview(document->stickerSetOrigin(), document);
|
||||
_previewShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::setPressed(OverState newPressed) {
|
||||
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||
Assert(hasColorButton(button->section)
|
||||
|
||||
@@ -287,6 +287,8 @@ private:
|
||||
int index);
|
||||
|
||||
[[nodiscard]] EmojiPtr lookupOverEmoji(const OverEmoji *over) const;
|
||||
[[nodiscard]] DocumentData *lookupCustomEmoji(
|
||||
const OverEmoji *over) const;
|
||||
[[nodiscard]] DocumentData *lookupCustomEmoji(
|
||||
int index,
|
||||
int section) const;
|
||||
@@ -371,10 +373,10 @@ private:
|
||||
DocumentId documentId,
|
||||
uint64 setId);
|
||||
|
||||
void applyNextSearchQuery();
|
||||
|
||||
void showPreview();
|
||||
|
||||
void applyNextSearchQuery();
|
||||
|
||||
const std::shared_ptr<Show> _show;
|
||||
const ComposeFeatures _features;
|
||||
Mode _mode = Mode::Full;
|
||||
@@ -442,14 +444,13 @@ private:
|
||||
|
||||
object_ptr<EmojiColorPicker> _picker;
|
||||
base::Timer _showPickerTimer;
|
||||
base::Timer _previewTimer;
|
||||
bool _previewShown = false;
|
||||
|
||||
rpl::event_stream<EmojiChosen> _chosen;
|
||||
rpl::event_stream<FileChosen> _customChosen;
|
||||
rpl::event_stream<> _jumpedToPremium;
|
||||
|
||||
base::Timer _previewTimer;
|
||||
bool _previewShown = false;
|
||||
|
||||
};
|
||||
|
||||
tr::phrase<> EmojiCategoryTitle(int index);
|
||||
|
||||
@@ -437,8 +437,8 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
|
||||
|
||||
auto filterNotPassedByUsername = [this](UserData *user) -> bool {
|
||||
if (PrimaryUsername(user).startsWith(_filter, Qt::CaseInsensitive)) {
|
||||
const auto exactUsername =
|
||||
(PrimaryUsername(user).size() == _filter.size());
|
||||
const auto exactUsername
|
||||
= (PrimaryUsername(user).size() == _filter.size());
|
||||
return exactUsername;
|
||||
}
|
||||
return true;
|
||||
@@ -446,8 +446,9 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
|
||||
auto filterNotPassedByName = [&](UserData *user) -> bool {
|
||||
for (const auto &nameWord : user->nameWords()) {
|
||||
if (nameWord.startsWith(_filter, Qt::CaseInsensitive)) {
|
||||
const auto exactUsername =
|
||||
(PrimaryUsername(user).compare(_filter, Qt::CaseInsensitive) == 0);
|
||||
const auto exactUsername = PrimaryUsername(user).compare(
|
||||
_filter,
|
||||
Qt::CaseInsensitive) == 0;
|
||||
return exactUsername;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -933,8 +933,8 @@ void Application::handleAppDeactivated() {
|
||||
}
|
||||
|
||||
rpl::producer<bool> Application::appDeactivatedValue() const {
|
||||
const auto &app =
|
||||
static_cast<QGuiApplication*>(QCoreApplication::instance());
|
||||
const auto &app
|
||||
= static_cast<QGuiApplication*>(QCoreApplication::instance());
|
||||
return rpl::single(
|
||||
app->applicationState()
|
||||
) | rpl::then(
|
||||
|
||||
@@ -46,6 +46,7 @@ struct ClickHandlerContext {
|
||||
bool mayShowConfirmation = false;
|
||||
bool skipBotAutoLogin = false;
|
||||
bool botStartAutoSubmit = false;
|
||||
bool ignoreIv = false;
|
||||
// Is filled from peer info.
|
||||
PeerData *peer = nullptr;
|
||||
};
|
||||
|
||||
@@ -313,8 +313,8 @@ CloudPasswordState ParseCloudPasswordState(
|
||||
ParseCloudPasswordAlgo(data.vnew_algo()));
|
||||
result.mtp.newSecureSecret = ValidateNewSecureSecretAlgo(
|
||||
ParseSecureSecretAlgo(data.vnew_secure_algo()));
|
||||
result.unconfirmedPattern =
|
||||
qs(data.vemail_unconfirmed_pattern().value_or_empty());
|
||||
result.unconfirmedPattern = qs(
|
||||
data.vemail_unconfirmed_pattern().value_or_empty());
|
||||
result.pendingResetDate = data.vpending_reset_date().value_or_empty();
|
||||
|
||||
result.outdatedClient = [&] {
|
||||
|
||||
@@ -160,6 +160,10 @@ QByteArray Settings::serialize() const {
|
||||
const auto &recentEmojiPreloadData = _recentEmojiPreload.empty()
|
||||
? recentEmojiPreloadGenerated
|
||||
: _recentEmojiPreload;
|
||||
const auto noWarningExtensions = QStringList(
|
||||
begin(_noWarningExtensions),
|
||||
end(_noWarningExtensions)
|
||||
).join(' ');
|
||||
|
||||
auto size = Serialize::bytearraySize(themesAccentColors)
|
||||
+ sizeof(qint32) * 5
|
||||
@@ -216,7 +220,8 @@ QByteArray Settings::serialize() const {
|
||||
+ Serialize::stringSize(_captureDeviceId.current())
|
||||
+ Serialize::stringSize(_callPlaybackDeviceId.current())
|
||||
+ Serialize::stringSize(_callCaptureDeviceId.current())
|
||||
+ Serialize::bytearraySize(ivPosition);
|
||||
+ Serialize::bytearraySize(ivPosition)
|
||||
+ Serialize::stringSize(noWarningExtensions);
|
||||
|
||||
auto result = QByteArray();
|
||||
result.reserve(size);
|
||||
@@ -256,7 +261,7 @@ QByteArray Settings::serialize() const {
|
||||
<< qint32(_sendSubmitWay)
|
||||
<< qint32(_includeMutedCounter ? 1 : 0)
|
||||
<< qint32(_countUnreadMessages ? 1 : 0)
|
||||
<< qint32(_exeLaunchWarning ? 1 : 0)
|
||||
<< qint32(1) // legacy exe launch warning
|
||||
<< qint32(_notifyAboutPinned.current() ? 1 : 0)
|
||||
<< qint32(_loopAnimatedStickers ? 1 : 0)
|
||||
<< qint32(_largeEmoji.current() ? 1 : 0)
|
||||
@@ -361,7 +366,8 @@ QByteArray Settings::serialize() const {
|
||||
<< _captureDeviceId.current()
|
||||
<< _callPlaybackDeviceId.current()
|
||||
<< _callCaptureDeviceId.current()
|
||||
<< ivPosition;
|
||||
<< ivPosition
|
||||
<< noWarningExtensions;
|
||||
}
|
||||
|
||||
Ensures(result.size() == size);
|
||||
@@ -412,7 +418,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
qint32 sendSubmitWay = static_cast<qint32>(_sendSubmitWay);
|
||||
qint32 includeMutedCounter = _includeMutedCounter ? 1 : 0;
|
||||
qint32 countUnreadMessages = _countUnreadMessages ? 1 : 0;
|
||||
qint32 exeLaunchWarning = _exeLaunchWarning ? 1 : 0;
|
||||
std::optional<QString> noWarningExtensions;
|
||||
qint32 legacyExeLaunchWarning = 1;
|
||||
qint32 notifyAboutPinned = _notifyAboutPinned.current() ? 1 : 0;
|
||||
qint32 loopAnimatedStickers = _loopAnimatedStickers ? 1 : 0;
|
||||
qint32 largeEmoji = _largeEmoji.current() ? 1 : 0;
|
||||
@@ -519,7 +526,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
>> sendSubmitWay
|
||||
>> includeMutedCounter
|
||||
>> countUnreadMessages
|
||||
>> exeLaunchWarning
|
||||
>> legacyExeLaunchWarning
|
||||
>> notifyAboutPinned
|
||||
>> loopAnimatedStickers
|
||||
>> largeEmoji
|
||||
@@ -761,6 +768,10 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
if (!stream.atEnd()) {
|
||||
stream >> ivPosition;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
noWarningExtensions = QString();
|
||||
stream >> *noWarningExtensions;
|
||||
}
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for Core::Settings::constructFromSerialized()"));
|
||||
@@ -824,7 +835,12 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
}
|
||||
_includeMutedCounter = (includeMutedCounter == 1);
|
||||
_countUnreadMessages = (countUnreadMessages == 1);
|
||||
_exeLaunchWarning = (exeLaunchWarning == 1);
|
||||
if (noWarningExtensions) {
|
||||
const auto list = noWarningExtensions->mid(0, 10240)
|
||||
.split(' ', Qt::SkipEmptyParts)
|
||||
.mid(0, 1024);
|
||||
_noWarningExtensions = base::flat_set<QString>(list.begin(), list.end());
|
||||
}
|
||||
_ipRevealWarning = (ipRevealWarning == 1);
|
||||
_notifyAboutPinned = (notifyAboutPinned == 1);
|
||||
_loopAnimatedStickers = (loopAnimatedStickers == 1);
|
||||
@@ -1290,7 +1306,7 @@ void Settings::resetOnLastLogout() {
|
||||
//_sendSubmitWay = Ui::InputSubmitSettings::Enter;
|
||||
_soundOverrides = {};
|
||||
|
||||
_exeLaunchWarning = true;
|
||||
_noWarningExtensions.clear();
|
||||
_ipRevealWarning = true;
|
||||
_loopAnimatedStickers = true;
|
||||
_largeEmoji = true;
|
||||
|
||||
@@ -404,11 +404,12 @@ public:
|
||||
}
|
||||
[[nodiscard]] QString getSoundPath(const QString &key) const;
|
||||
|
||||
[[nodiscard]] bool exeLaunchWarning() const {
|
||||
return _exeLaunchWarning;
|
||||
[[nodiscard]] auto noWarningExtensions() const
|
||||
-> const base::flat_set<QString> & {
|
||||
return _noWarningExtensions;
|
||||
}
|
||||
void setExeLaunchWarning(bool warning) {
|
||||
_exeLaunchWarning = warning;
|
||||
void setNoWarningExtensions(base::flat_set<QString> extensions) {
|
||||
_noWarningExtensions = std::move(extensions);
|
||||
}
|
||||
[[nodiscard]] bool ipRevealWarning() const {
|
||||
return _ipRevealWarning;
|
||||
@@ -939,7 +940,7 @@ private:
|
||||
Ui::SendFilesWay _sendFilesWay = Ui::SendFilesWay();
|
||||
Ui::InputSubmitSettings _sendSubmitWay = Ui::InputSubmitSettings();
|
||||
base::flat_map<QString, QString> _soundOverrides;
|
||||
bool _exeLaunchWarning = true;
|
||||
base::flat_set<QString> _noWarningExtensions;
|
||||
bool _ipRevealWarning = true;
|
||||
bool _loopAnimatedStickers = true;
|
||||
rpl::variable<bool> _largeEmoji = true;
|
||||
@@ -990,8 +991,8 @@ private:
|
||||
#else // Q_OS_MAC
|
||||
bool _hardwareAcceleratedVideo = false;
|
||||
#endif // Q_OS_MAC
|
||||
HistoryView::DoubleClickQuickAction _chatQuickAction =
|
||||
HistoryView::DoubleClickQuickAction();
|
||||
HistoryView::DoubleClickQuickAction _chatQuickAction
|
||||
= HistoryView::DoubleClickQuickAction();
|
||||
bool _translateButtonEnabled = false;
|
||||
rpl::variable<bool> _translateChatEnabled = true;
|
||||
rpl::variable<int> _translateToRaw = 0;
|
||||
|
||||
@@ -443,7 +443,7 @@ LastCrashedWindow::LastCrashedWindow(
|
||||
});
|
||||
_saveReport.setText(u"SAVE TO FILE"_q);
|
||||
connect(&_saveReport, &QPushButton::clicked, [=] { saveReport(); });
|
||||
_getApp.setText(u"GET THE LATEST OFFICIAL VERSION OF AYUGRAM DESKTOP"_q);
|
||||
_getApp.setText(u"GET THE LATEST VERSION OF AYUGRAM DESKTOP"_q);
|
||||
connect(&_getApp, &QPushButton::clicked, [=] {
|
||||
QDesktopServices::openUrl(u"https://github.com/AyuGram/AyuGramDesktop"_q);
|
||||
});
|
||||
|
||||
@@ -159,7 +159,7 @@ void Launch(const QString &filepath) {
|
||||
void ShowInFolder(const QString &filepath) {
|
||||
crl::on_main([=] {
|
||||
Ui::PreventDelayedActivation();
|
||||
if (Platform::IsLinux()) {
|
||||
if (Platform::IsX11()) {
|
||||
// Hide mediaview to make other apps visible.
|
||||
Core::App().hideMediaView();
|
||||
}
|
||||
|
||||
@@ -567,6 +567,7 @@ bool ResolveUsernameOrPhone(
|
||||
.phone = phone,
|
||||
.messageId = post,
|
||||
.storyId = storyId,
|
||||
.text = params.value(u"text"_q),
|
||||
.repliesInfo = commentId
|
||||
? Window::RepliesByLinkInfo{
|
||||
Window::CommentId{ commentId }
|
||||
@@ -901,6 +902,34 @@ bool ShowEditPersonalChannel(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShowCollectiblePhone(
|
||||
Window::SessionController *controller,
|
||||
const Match &match,
|
||||
const QVariant &context) {
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
const auto phone = match->captured(1);
|
||||
const auto peerId = PeerId(match->captured(2).toULongLong());
|
||||
controller->resolveCollectible(
|
||||
peerId,
|
||||
phone.startsWith('+') ? phone : '+' + phone);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShowCollectibleUsername(
|
||||
Window::SessionController *controller,
|
||||
const Match &match,
|
||||
const QVariant &context) {
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
const auto username = match->captured(1);
|
||||
const auto peerId = PeerId(match->captured(2).toULongLong());
|
||||
controller->resolveCollectible(peerId, username);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExportTestChatTheme(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<const Data::CloudTheme*> theme) {
|
||||
@@ -1311,6 +1340,14 @@ const std::vector<LocalUrlHandler> &InternalUrlHandlers() {
|
||||
u"^edit_personal_channel$"_q,
|
||||
ShowEditPersonalChannel,
|
||||
},
|
||||
{
|
||||
u"^collectible_phone/([\\+0-9\\-\\s]+)@([0-9]+)$"_q,
|
||||
ShowCollectiblePhone,
|
||||
},
|
||||
{
|
||||
u"^collectible_username/([a-zA-Z0-9\\-\\_\\.]+)@([0-9]+)$"_q,
|
||||
ShowCollectibleUsername,
|
||||
},
|
||||
};
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,12 @@ namespace {
|
||||
&& data->hasImage();
|
||||
}
|
||||
|
||||
[[nodiscard]] base::flat_set<QString> SplitExtensions(
|
||||
const QString &joined) {
|
||||
const auto list = joined.split(' ');
|
||||
return base::flat_set<QString>(list.begin(), list.end());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MimeType::MimeType(const QMimeType &type) : _typeStruct(type) {
|
||||
@@ -162,22 +168,9 @@ bool IsMimeAcceptedForPhotoVideoAlbum(const QString &mime) {
|
||||
}
|
||||
|
||||
bool FileIsImage(const QString &name, const QString &mime) {
|
||||
QString lowermime = mime.toLower(), namelower = name.toLower();
|
||||
if (lowermime.startsWith(u"image/"_q)) {
|
||||
return true;
|
||||
} else if (namelower.endsWith(u".bmp"_q)
|
||||
|| namelower.endsWith(u".jpg"_q)
|
||||
|| namelower.endsWith(u".jpeg"_q)
|
||||
|| namelower.endsWith(u".gif"_q)
|
||||
|| namelower.endsWith(u".webp"_q)
|
||||
|| namelower.endsWith(u".tga"_q)
|
||||
|| namelower.endsWith(u".tiff"_q)
|
||||
|| namelower.endsWith(u".tif"_q)
|
||||
|| namelower.endsWith(u".psd"_q)
|
||||
|| namelower.endsWith(u".png"_q)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return name.isEmpty()
|
||||
? mime.toLower().startsWith(u"image/"_q)
|
||||
: (DetectNameType(name) == NameType::Image);
|
||||
}
|
||||
|
||||
std::shared_ptr<QMimeData> ShareMimeMediaData(
|
||||
@@ -194,10 +187,10 @@ std::shared_ptr<QMimeData> ShareMimeMediaData(
|
||||
result->setData(u"application/x-td-use-jpeg"_q, "1");
|
||||
result->setData(u"image/jpeg"_q, original->data(u"image/jpeg"_q));
|
||||
}
|
||||
if (auto list = Core::ReadMimeUrls(original); !list.isEmpty()) {
|
||||
if (auto list = ReadMimeUrls(original); !list.isEmpty()) {
|
||||
result->setUrls(std::move(list));
|
||||
}
|
||||
result->setText(Core::ReadMimeText(original));
|
||||
result->setText(ReadMimeText(original));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -240,4 +233,116 @@ bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString FileExtension(const QString &filepath) {
|
||||
const auto reversed = ranges::views::reverse(filepath);
|
||||
const auto last = ranges::find_first_of(reversed, ".\\/");
|
||||
if (last == reversed.end() || *last != '.') {
|
||||
return QString();
|
||||
}
|
||||
return QString(last.base(), last - reversed.begin());
|
||||
}
|
||||
|
||||
NameType DetectNameType(const QString &filepath) {
|
||||
static const auto kImage = SplitExtensions(u"\
|
||||
afdesign ai avif bmp dng gif heic icns ico jfif jpeg jpg jpg-large nef png \
|
||||
png-large psd raw sketch svg tga tif tiff webp"_q);
|
||||
static const auto kVideo = SplitExtensions(u"\
|
||||
3g2 3gp 3gpp aep avi flv h264 m4s m4v mkv mov mp4 mpeg mpg ogv srt tgs tgv \
|
||||
vob webm wmv"_q);
|
||||
static const auto kAudio = SplitExtensions(u"\
|
||||
aac ac3 aif amr caf cda cue flac m4a m4b mid midi mp3 ogg opus wav wma"_q);
|
||||
static const auto kDocument = SplitExtensions(u"\
|
||||
pdf doc docx ppt pptx pps ppsx xls xlsx txt rtf odt ods odp csv text log tl \
|
||||
tex xspf xml djvu diag ps ost kml pub epub mobi cbr cbz fb2 prc ris pem p7b \
|
||||
m3u m3u8 wpd wpl htm html xhtml key"_q);
|
||||
static const auto kArchive = SplitExtensions(u"\
|
||||
7z arj bz2 gz rar tar xz z zip zst"_q);
|
||||
static const auto kThemeFile = SplitExtensions(u"\
|
||||
tdesktop-theme tdesktop-palette tgios-theme attheme"_q);
|
||||
static const auto kOtherBenign = SplitExtensions(u"\
|
||||
c cc cpp cxx h m mm swift cs ts class java css ninja cmake patch diff plist \
|
||||
gyp gitignore strings asoundrc torrent csr json xaml md keylayout sql \
|
||||
sln xib mk \
|
||||
\
|
||||
dmg img iso vcd \
|
||||
\
|
||||
pdb eot ics ips ipa core mem pcap ovpn part pcapng dmp pkpass dat zxp crash \
|
||||
file bak gbr plain dlc fon fnt otf ttc ttf gpx db rss cur \
|
||||
\
|
||||
tdesktop-endpoints"_q);
|
||||
|
||||
static const auto kExecutable = SplitExtensions(
|
||||
#ifdef Q_OS_WIN
|
||||
u"\
|
||||
ad ade adp ahk app application appref-ms asp aspx asx bas bat bin cab cdxml \
|
||||
cer cfg cgi chi chm cmd cnt com conf cpl crt csh der diagcab dll drv eml \
|
||||
exe fon fxp gadget grp hlp hpj hta htt inf ini ins inx isp isu its jar jnlp \
|
||||
job js jse jsp key ksh lexe library-ms lnk local lua mad maf mag mam \
|
||||
manifest maq mar mas mat mau mav maw mcf mda mdb mde mdt mdw mdz mht mhtml \
|
||||
mjs mmc mof msc msg msh msh1 msh2 msh1xml msh2xml mshxml msi msp mst ops \
|
||||
osd paf pcd phar php php3 php4 php5 php7 phps php-s pht phtml pif pl plg pm \
|
||||
pod prf prg ps1 ps2 ps1xml ps2xml psc1 psc2 psd1 psm1 pssc pst py py3 pyc \
|
||||
pyd pyi pyo pyw pyzw pyz rb reg rgs scf scr sct search-ms settingcontent-ms \
|
||||
sh shb shs slk sys swf t tmp u3p url vb vbe vbp vbs vbscript vdx vsmacros \
|
||||
vsd vsdm vsdx vss vssm vssx vst vstm vstx vsw vsx vtx website wlua ws wsc \
|
||||
wsf wsh xbap xll xlsm xnk xs"_q
|
||||
#elif defined Q_OS_MAC // Q_OS_MAC
|
||||
u"\
|
||||
applescript action app bin command csh osx workflow terminal url caction \
|
||||
mpkg pkg scpt scptd xhtm xhtml webarchive"_q
|
||||
#else // Q_OS_WIN || Q_OS_MAC
|
||||
u"bin csh deb desktop ksh out pet pkg pup rpm run sh shar slp zsh"_q
|
||||
#endif // !Q_OS_WIN && !Q_OS_MAC
|
||||
);
|
||||
|
||||
const auto extension = FileExtension(filepath).toLower();
|
||||
if (kExecutable.contains(extension)) {
|
||||
return NameType::Executable;
|
||||
} else if (kImage.contains(extension)) {
|
||||
return NameType::Image;
|
||||
} else if (kVideo.contains(extension)) {
|
||||
return NameType::Video;
|
||||
} else if (kAudio.contains(extension)) {
|
||||
return NameType::Audio;
|
||||
} else if (kDocument.contains(extension)) {
|
||||
return NameType::Document;
|
||||
} else if (kArchive.contains(extension)) {
|
||||
return NameType::Archive;
|
||||
} else if (kThemeFile.contains(extension)) {
|
||||
return NameType::ThemeFile;
|
||||
} else if (kOtherBenign.contains(extension)) {
|
||||
return NameType::OtherBenign;
|
||||
}
|
||||
return NameType::Unknown;
|
||||
}
|
||||
|
||||
bool NameTypeAllowsThumbnail(NameType type) {
|
||||
return type == NameType::Image
|
||||
|| type == NameType::Video
|
||||
|| type == NameType::Audio
|
||||
|| type == NameType::Document
|
||||
|| type == NameType::ThemeFile;
|
||||
}
|
||||
|
||||
bool IsIpRevealingPath(const QString &filepath) {
|
||||
static const auto kExtensions = [] {
|
||||
const auto joined = u"htm html svg m4v m3u8 xhtml"_q;
|
||||
const auto list = joined.split(' ');
|
||||
return base::flat_set<QString>(list.begin(), list.end());
|
||||
}();
|
||||
static const auto kMimeTypes = [] {
|
||||
const auto joined = u"text/html image/svg+xml"_q;
|
||||
const auto list = joined.split(' ');
|
||||
return base::flat_set<QString>(list.begin(), list.end());
|
||||
}();
|
||||
|
||||
return ranges::binary_search(
|
||||
kExtensions,
|
||||
FileExtension(filepath).toLower()
|
||||
) || ranges::binary_search(
|
||||
kMimeTypes,
|
||||
QMimeDatabase().mimeTypeForFile(QFileInfo(filepath)).name()
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -69,4 +69,21 @@ struct MimeImageData {
|
||||
[[nodiscard]] QList<QUrl> ReadMimeUrls(not_null<const QMimeData*> data);
|
||||
[[nodiscard]] bool CanSendFiles(not_null<const QMimeData*> data);
|
||||
|
||||
enum class NameType : uchar {
|
||||
Unknown,
|
||||
Executable,
|
||||
Image,
|
||||
Video,
|
||||
Audio,
|
||||
Document,
|
||||
Archive,
|
||||
ThemeFile,
|
||||
OtherBenign,
|
||||
};
|
||||
|
||||
[[nodiscard]] QString FileExtension(const QString &filepath);
|
||||
[[nodiscard]] NameType DetectNameType(const QString &filepath);
|
||||
[[nodiscard]] bool NameTypeAllowsThumbnail(NameType type);
|
||||
[[nodiscard]] bool IsIpRevealingPath(const QString &filepath);
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -33,7 +33,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtGui/QSessionManager>
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtGui/qpa/qplatformscreen.h>
|
||||
#include <ksandbox.h>
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
@@ -83,7 +82,6 @@ bool Sandbox::QuitOnStartRequested = false;
|
||||
Sandbox::Sandbox(int &argc, char **argv)
|
||||
: QApplication(argc, argv)
|
||||
, _mainThreadId(QThread::currentThreadId()) {
|
||||
setQuitOnLastWindowClosed(false);
|
||||
}
|
||||
|
||||
int Sandbox::start() {
|
||||
@@ -518,10 +516,8 @@ void Sandbox::refreshGlobalProxy() {
|
||||
|| proxy.type == MTP::ProxyData::Type::Http) {
|
||||
QNetworkProxy::setApplicationProxy(
|
||||
MTP::ToNetworkProxy(MTP::ToDirectIpProxy(proxy)));
|
||||
} else if ((!Core::IsAppLaunched()
|
||||
|| Core::App().settings().proxy().isSystem())
|
||||
// this works stable only in sandboxed environment where it works through portal
|
||||
&& (!Platform::IsLinux() || KSandbox::isInside() || cDebugMode())) {
|
||||
} else if (!Core::IsAppLaunched()
|
||||
|| Core::App().settings().proxy().isSystem()) {
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
} else {
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
|
||||
|
||||
@@ -107,6 +107,7 @@ private:
|
||||
void readClients();
|
||||
void removeClients();
|
||||
|
||||
QEventLoopLocker _eventLoopLocker;
|
||||
const Qt::HANDLE _mainThreadId = nullptr;
|
||||
int _eventNestingLevel = 0;
|
||||
int _loopNestingLevel = 0;
|
||||
|
||||
@@ -230,8 +230,24 @@ void WriteDefaultCustomFile() {
|
||||
const auto path = CustomFilePath();
|
||||
auto input = QFile(":/misc/default_shortcuts-custom.json");
|
||||
auto output = QFile(path);
|
||||
if (input.open(QIODevice::ReadOnly) && output.open(QIODevice::WriteOnly)) {
|
||||
if (input.open(QIODevice::ReadOnly)
|
||||
&& output.open(QIODevice::WriteOnly)) {
|
||||
#ifdef Q_OS_MAC
|
||||
auto text = qs(input.readAll());
|
||||
const auto note = R"(
|
||||
// Note:
|
||||
// On Apple platforms, reference to "ctrl" corresponds to the Command keys )"
|
||||
+ QByteArray()
|
||||
+ R"(on the Macintosh keyboard.
|
||||
// On Apple platforms, reference to "meta" corresponds to the Control keys.
|
||||
|
||||
[
|
||||
)";
|
||||
text.replace(u"\n\n["_q, QString(note));
|
||||
output.write(text.toUtf8());
|
||||
#else
|
||||
output.write(input.readAll());
|
||||
#endif // !Q_OS_MAC
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/application.h"
|
||||
#include "core/sandbox.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "data/components/sponsored_messages.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_sponsored_messages.h"
|
||||
#include "iv/iv_instance.h"
|
||||
#include "ui/text/text_custom_emoji.h"
|
||||
#include "ui/basic_click_handlers.h"
|
||||
#include "ui/emoji_config.h"
|
||||
@@ -241,6 +242,13 @@ bool UiIntegration::handleUrlClick(
|
||||
} else if (local.startsWith(u"internal:"_q, Qt::CaseInsensitive)) {
|
||||
Core::App().openInternalUrl(local, context);
|
||||
return true;
|
||||
} else if (Iv::PreferForUri(url)
|
||||
&& !context.value<ClickHandlerContext>().ignoreIv) {
|
||||
const auto my = context.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
Core::App().iv().openWithIvPreferred(controller, url, context);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (AyuUrlHandlers::TryHandleSpotify(url)) {
|
||||
@@ -295,7 +303,7 @@ bool UiIntegration::allowClickHandlerActivation(
|
||||
const ClickContext &context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto window = my.sessionWindow.get()) {
|
||||
window->session().data().sponsoredMessages().clicked(my.itemId);
|
||||
window->session().sponsoredMessages().clicked(my.itemId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
|
||||
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
|
||||
constexpr auto AppName = "AyuGram Desktop"_cs;
|
||||
constexpr auto AppFile = "AyuGram"_cs;
|
||||
constexpr auto AppVersion = 4016000;
|
||||
constexpr auto AppVersionStr = "4.16";
|
||||
constexpr auto AppVersion = 4016008;
|
||||
constexpr auto AppVersionStr = "4.16.8";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -125,8 +125,10 @@ void Chatbots::togglePaused(not_null<PeerData*> peer, bool paused) {
|
||||
return;
|
||||
} else if (const auto settings = peer->barSettings()) {
|
||||
peer->setBarSettings(paused
|
||||
? (*settings | PeerBarSetting::BusinessBotPaused)
|
||||
: (*settings & ~PeerBarSetting::BusinessBotPaused));
|
||||
? ((*settings | PeerBarSetting::BusinessBotPaused)
|
||||
& ~PeerBarSetting::BusinessBotCanReply)
|
||||
: ((*settings & ~PeerBarSetting::BusinessBotPaused)
|
||||
| PeerBarSetting::BusinessBotCanReply));
|
||||
} else {
|
||||
api->requestPeerSettings(peer);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,13 @@ auto RecipientsFlags(const BusinessRecipients &data) {
|
||||
|
||||
} // namespace
|
||||
|
||||
BusinessRecipients BusinessRecipients::MakeValid(BusinessRecipients value) {
|
||||
if (value.included.empty()) {
|
||||
value.allButExcluded = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
MTPInputBusinessRecipients ForMessagesToMTP(const BusinessRecipients &data) {
|
||||
using Flag = MTPDinputBusinessRecipients::Flag;
|
||||
const auto &chats = data.allButExcluded ? data.excluded : data.included;
|
||||
|
||||
@@ -44,6 +44,9 @@ struct BusinessRecipients {
|
||||
BusinessChats excluded;
|
||||
bool allButExcluded = false;
|
||||
|
||||
[[nodiscard]] static BusinessRecipients MakeValid(
|
||||
BusinessRecipients value);
|
||||
|
||||
friend inline bool operator==(
|
||||
const BusinessRecipients &a,
|
||||
const BusinessRecipients &b) = default;
|
||||
|
||||
+12
-5
@@ -5,7 +5,7 @@ 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 "data/data_scheduled_messages.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
@@ -101,10 +101,10 @@ bool IsScheduledMsgId(MsgId id) {
|
||||
return (id > ServerMaxMsgId) && (id < ScheduledMaxMsgId);
|
||||
}
|
||||
|
||||
ScheduledMessages::ScheduledMessages(not_null<Session*> owner)
|
||||
: _session(&owner->session())
|
||||
ScheduledMessages::ScheduledMessages(not_null<Main::Session*> session)
|
||||
: _session(session)
|
||||
, _clearTimer([=] { clearOldRequests(); }) {
|
||||
owner->itemRemoved(
|
||||
_session->data().itemRemoved(
|
||||
) | rpl::filter([](not_null<const HistoryItem*> item) {
|
||||
return item->isScheduled();
|
||||
}) | rpl::start_with_next([=](not_null<const HistoryItem*> item) {
|
||||
@@ -113,9 +113,16 @@ ScheduledMessages::ScheduledMessages(not_null<Session*> owner)
|
||||
}
|
||||
|
||||
ScheduledMessages::~ScheduledMessages() {
|
||||
for (const auto &request : _requests) {
|
||||
Expects(_data.empty());
|
||||
Expects(_requests.empty());
|
||||
}
|
||||
|
||||
void ScheduledMessages::clear() {
|
||||
_lifetime.destroy();
|
||||
for (const auto &request : base::take(_requests)) {
|
||||
_session->api().request(request.second.requestId).cancel();
|
||||
}
|
||||
base::take(_data);
|
||||
}
|
||||
|
||||
void ScheduledMessages::clearOldRequests() {
|
||||
+3
-2
@@ -18,14 +18,13 @@ class Session;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Session;
|
||||
struct MessagesSlice;
|
||||
|
||||
[[nodiscard]] bool IsScheduledMsgId(MsgId id);
|
||||
|
||||
class ScheduledMessages final {
|
||||
public:
|
||||
explicit ScheduledMessages(not_null<Session*> owner);
|
||||
explicit ScheduledMessages(not_null<Main::Session*> session);
|
||||
ScheduledMessages(const ScheduledMessages &other) = delete;
|
||||
ScheduledMessages &operator=(const ScheduledMessages &other) = delete;
|
||||
~ScheduledMessages();
|
||||
@@ -56,6 +55,8 @@ public:
|
||||
[[nodiscard]] Data::MessagesSlice list(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
using OwnedItem = std::unique_ptr<HistoryItem, HistoryItem::Destroyer>;
|
||||
struct List {
|
||||
+4
-4
@@ -5,7 +5,7 @@ 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 "data/data_sponsored_messages.h"
|
||||
#include "data/components/sponsored_messages.h"
|
||||
|
||||
#include "api/api_text_entities.h"
|
||||
#include "apiwrap.h"
|
||||
@@ -34,8 +34,8 @@ constexpr auto kRequestTimeLimit = 5 * 60 * crl::time(1000);
|
||||
|
||||
} // namespace
|
||||
|
||||
SponsoredMessages::SponsoredMessages(not_null<Session*> owner)
|
||||
: _session(&owner->session())
|
||||
SponsoredMessages::SponsoredMessages(not_null<Main::Session*> session)
|
||||
: _session(session)
|
||||
, _clearTimer([=] { clearOldRequests(); }) {
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ void SponsoredMessages::append(
|
||||
? _session->data().processBotApp(peerId, *data.vapp())
|
||||
: nullptr;
|
||||
result.botLinkInfo = Window::PeerByLinkInfo{
|
||||
.usernameOrId = user->userName(),
|
||||
.usernameOrId = user->username(),
|
||||
.resolveType = botAppData
|
||||
? Window::ResolveType::BotApp
|
||||
: data.vstart_param()
|
||||
+1
-3
@@ -20,8 +20,6 @@ class Session;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Session;
|
||||
|
||||
struct SponsoredReportResult final {
|
||||
using Id = QByteArray;
|
||||
struct Option final {
|
||||
@@ -89,7 +87,7 @@ public:
|
||||
bool canReport = false;
|
||||
};
|
||||
using RandomId = QByteArray;
|
||||
explicit SponsoredMessages(not_null<Session*> owner);
|
||||
explicit SponsoredMessages(not_null<Main::Session*> session);
|
||||
SponsoredMessages(const SponsoredMessages &other) = delete;
|
||||
SponsoredMessages &operator=(const SponsoredMessages &other) = delete;
|
||||
~SponsoredMessages();
|
||||
@@ -127,4 +127,3 @@ rpl::producer<bool> IsBirthdayTodayValue(Birthday date) {
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
|
||||
@@ -139,6 +139,10 @@ const std::vector<QString> &ChannelData::usernames() const {
|
||||
return _username.usernames();
|
||||
}
|
||||
|
||||
bool ChannelData::isUsernameEditable(QString username) const {
|
||||
return _username.isEditable(username);
|
||||
}
|
||||
|
||||
void ChannelData::setAccessHash(uint64 accessHash) {
|
||||
access = accessHash;
|
||||
input = MTP_inputPeerChannel(
|
||||
|
||||
@@ -182,6 +182,7 @@ public:
|
||||
[[nodiscard]] QString username() const;
|
||||
[[nodiscard]] QString editableUsername() const;
|
||||
[[nodiscard]] const std::vector<QString> &usernames() const;
|
||||
[[nodiscard]] bool isUsernameEditable(QString username) const;
|
||||
|
||||
[[nodiscard]] int membersCount() const {
|
||||
return std::max(_membersCount, 1);
|
||||
|
||||
@@ -780,7 +780,9 @@ FilterId ChatFilters::lookupId(int index) const {
|
||||
return FilterId(); // AyuGram: fix crash when using `hideAllChatsFolder`
|
||||
}
|
||||
|
||||
if (_owner->session().user()->isPremium() || !_list.front().id()) {
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
|
||||
if (_owner->session().user()->isPremium() || !_list.front().id() || settings->hideAllChatsFolder) {
|
||||
return _list[index].id();
|
||||
}
|
||||
const auto i = ranges::find(_list, FilterId(0), &ChatFilter::id);
|
||||
|
||||
@@ -22,6 +22,14 @@ CloudFile::~CloudFile() {
|
||||
base::take(loader);
|
||||
}
|
||||
|
||||
void CloudFile::clear() {
|
||||
location = {};
|
||||
base::take(loader);
|
||||
byteSize = 0;
|
||||
progressivePartSize = 0;
|
||||
flags = {};
|
||||
}
|
||||
|
||||
CloudImage::CloudImage() = default;
|
||||
|
||||
CloudImage::CloudImage(
|
||||
|
||||
@@ -37,6 +37,8 @@ struct CloudFile final {
|
||||
|
||||
~CloudFile();
|
||||
|
||||
void clear();
|
||||
|
||||
ImageLocation location;
|
||||
std::unique_ptr<FileLoader> loader;
|
||||
int byteSize = 0;
|
||||
|
||||
@@ -478,6 +478,31 @@ void DocumentData::setattributes(
|
||||
_additional = nullptr;
|
||||
}
|
||||
|
||||
if (!_filename.isEmpty()) {
|
||||
using Type = Core::NameType;
|
||||
if (type == VideoDocument
|
||||
|| type == AnimatedDocument
|
||||
|| type == RoundVideoDocument
|
||||
|| isAnimation()) {
|
||||
if (!enforceNameType(Type::Video)) {
|
||||
type = FileDocument;
|
||||
_additional = nullptr;
|
||||
}
|
||||
}
|
||||
if (type == SongDocument || type == VoiceDocument || isAudioFile()) {
|
||||
if (!enforceNameType(Type::Audio)) {
|
||||
type = FileDocument;
|
||||
_additional = nullptr;
|
||||
}
|
||||
}
|
||||
if (!Core::NameTypeAllowsThumbnail(_nameType)) {
|
||||
_inlineThumbnailBytes = {};
|
||||
_flags &= ~Flag::InlineThumbnailIsPath;
|
||||
_thumbnail.clear();
|
||||
_videoThumbnail.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (isAudioFile()
|
||||
|| isAnimation()
|
||||
|| isVoiceMessage()
|
||||
@@ -530,6 +555,10 @@ void DocumentData::updateThumbnails(
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &videoThumbnail,
|
||||
bool isPremiumSticker) {
|
||||
if (!_filename.isEmpty()
|
||||
&& !Core::NameTypeAllowsThumbnail(Core::DetectNameType(_filename))) {
|
||||
return;
|
||||
}
|
||||
if (!inlineThumbnail.bytes.isEmpty()
|
||||
&& _inlineThumbnailBytes.isEmpty()) {
|
||||
_inlineThumbnailBytes = inlineThumbnail.bytes;
|
||||
@@ -919,6 +948,25 @@ void DocumentData::setFileName(const QString &remoteFileName) {
|
||||
for (const auto &ch : controls) {
|
||||
_filename = std::move(_filename).replace(ch, "_");
|
||||
}
|
||||
_nameType = Core::DetectNameType(_filename);
|
||||
}
|
||||
|
||||
bool DocumentData::enforceNameType(Core::NameType nameType) {
|
||||
if (_nameType == nameType) {
|
||||
return true;
|
||||
}
|
||||
const auto base = _filename.isEmpty() ? u"file"_q : _filename;
|
||||
const auto mime = Core::MimeTypeForName(mimeString());
|
||||
const auto patterns = mime.globPatterns();
|
||||
for (const auto &pattern : mime.globPatterns()) {
|
||||
const auto now = base + QString(pattern).replace('*', QString());
|
||||
if (Core::DetectNameType(now) == nameType) {
|
||||
_filename = now;
|
||||
_nameType = nameType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DocumentData::setLoadedInMediaCacheLocation() {
|
||||
@@ -1460,6 +1508,10 @@ QString DocumentData::filename() const {
|
||||
return _filename;
|
||||
}
|
||||
|
||||
Core::NameType DocumentData::nameType() const {
|
||||
return _nameType;
|
||||
}
|
||||
|
||||
QString DocumentData::mimeString() const {
|
||||
return _mimeString;
|
||||
}
|
||||
@@ -1527,7 +1579,10 @@ bool DocumentData::isVideoMessage() const {
|
||||
bool DocumentData::isAnimation() const {
|
||||
return (type == AnimatedDocument)
|
||||
|| isVideoMessage()
|
||||
|| (hasMimeType(u"image/gif"_q)
|
||||
|| ((_filename.isEmpty()
|
||||
|| _nameType == Core::NameType::Image
|
||||
|| _nameType == Core::NameType::Video)
|
||||
&& hasMimeType(u"image/gif"_q)
|
||||
&& !(_flags & Flag::StreamingPlaybackFailed));
|
||||
}
|
||||
|
||||
@@ -1537,9 +1592,11 @@ bool DocumentData::isGifv() const {
|
||||
}
|
||||
|
||||
bool DocumentData::isTheme() const {
|
||||
return hasMimeType(u"application/x-tgtheme-tdesktop"_q)
|
||||
|| _filename.endsWith(u".tdesktop-theme"_q, Qt::CaseInsensitive)
|
||||
|| _filename.endsWith(u".tdesktop-palette"_q, Qt::CaseInsensitive);
|
||||
return _filename.endsWith(u".tdesktop-theme"_q, Qt::CaseInsensitive)
|
||||
|| _filename.endsWith(u".tdesktop-palette"_q, Qt::CaseInsensitive)
|
||||
|| (hasMimeType(u"application/x-tgtheme-tdesktop"_q)
|
||||
&& (_filename.isEmpty()
|
||||
|| _nameType == Core::NameType::ThemeFile));
|
||||
}
|
||||
|
||||
bool DocumentData::isSong() const {
|
||||
@@ -1562,6 +1619,10 @@ bool DocumentData::isAudioFile() const {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (!_filename.isEmpty()
|
||||
&& _nameType != Core::NameType::Audio
|
||||
&& _nameType != Core::NameType::Video) {
|
||||
return false;
|
||||
}
|
||||
const auto left = _mimeString.mid(prefix.size());
|
||||
const auto types = { u"x-wav"_q, u"wav"_q, u"mp4"_q };
|
||||
|
||||
@@ -20,6 +20,10 @@ namespace Images {
|
||||
class Source;
|
||||
} // namespace Images
|
||||
|
||||
namespace Core {
|
||||
enum class NameType : uchar;
|
||||
} // namespace Core
|
||||
|
||||
namespace Storage {
|
||||
namespace Cache {
|
||||
struct Key;
|
||||
@@ -255,6 +259,7 @@ public:
|
||||
void collectLocalData(not_null<DocumentData*> local);
|
||||
|
||||
[[nodiscard]] QString filename() const;
|
||||
[[nodiscard]] Core::NameType nameType() const;
|
||||
[[nodiscard]] QString mimeString() const;
|
||||
[[nodiscard]] bool hasMimeType(const QString &mime) const;
|
||||
void setMimeString(const QString &mime);
|
||||
@@ -340,6 +345,7 @@ private:
|
||||
void setMaybeSupportsStreaming(bool supports);
|
||||
void setLoadedInMediaCacheLocation();
|
||||
void setFileName(const QString &remoteFileName);
|
||||
bool enforceNameType(Core::NameType nameType);
|
||||
|
||||
void finishLoad();
|
||||
void handleLoaderUpdates();
|
||||
@@ -373,6 +379,7 @@ private:
|
||||
std::unique_ptr<DocumentAdditionalData> _additional;
|
||||
mutable Flags _flags = kStreamingSupportedUnknown;
|
||||
GoodThumbnailState _goodThumbnailState = GoodThumbnailState();
|
||||
Core::NameType _nameType = Core::NameType();
|
||||
std::unique_ptr<FileLoader> _loader;
|
||||
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/themes/window_theme_preview.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/application.h"
|
||||
#include "core/mime_type.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
|
||||
@@ -295,10 +296,12 @@ void DocumentMedia::automaticLoad(
|
||||
// No automatic download in this case.
|
||||
return;
|
||||
}
|
||||
const auto indata = _owner->filename();
|
||||
const auto filename = toCache
|
||||
? QString()
|
||||
: DocumentFileNameForSave(_owner);
|
||||
const auto shouldLoadFromCloud = !Data::IsExecutableName(filename)
|
||||
const auto shouldLoadFromCloud = (indata.isEmpty()
|
||||
|| Core::DetectNameType(indata) != Core::NameType::Executable)
|
||||
&& (item
|
||||
? Data::AutoDownload::Should(
|
||||
_owner->session().settings().autoDownload(),
|
||||
|
||||
@@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/chat/chat_theme.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
@@ -46,11 +47,12 @@ base::options::toggle OptionExternalVideoPlayer({
|
||||
void ConfirmDontWarnBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
rpl::producer<TextWithEntities> &&text,
|
||||
rpl::producer<QString> &&check,
|
||||
rpl::producer<QString> &&confirm,
|
||||
Fn<void(bool)> callback) {
|
||||
auto checkbox = object_ptr<Ui::Checkbox>(
|
||||
box.get(),
|
||||
tr::lng_launch_exe_dont_ask(),
|
||||
std::move(check),
|
||||
false,
|
||||
st::defaultBoxCheckbox);
|
||||
const auto weak = Ui::MakeWeak(checkbox.data());
|
||||
@@ -67,29 +69,43 @@ void ConfirmDontWarnBox(
|
||||
auto padding = st::boxPadding;
|
||||
padding.setTop(padding.bottom());
|
||||
box->addRow(std::move(checkbox), std::move(padding));
|
||||
box->addRow(object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
|
||||
box,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_launch_dont_ask_settings(),
|
||||
st::boxLabel)
|
||||
))->toggleOn(weak->checkedValue());
|
||||
}
|
||||
|
||||
void LaunchWithWarning(
|
||||
// not_null<Window::Controller*> controller,
|
||||
const QString &name,
|
||||
HistoryItem *item) {
|
||||
const auto isExecutable = Data::IsExecutableName(name);
|
||||
const auto isIpReveal = Data::IsIpRevealingName(name);
|
||||
const auto nameType = Core::DetectNameType(name);
|
||||
const auto isIpReveal = (nameType != Core::NameType::Executable)
|
||||
&& Core::IsIpRevealingPath(name);
|
||||
const auto extension = Core::FileExtension(name).toLower();
|
||||
|
||||
auto &app = Core::App();
|
||||
auto &settings = app.settings();
|
||||
const auto warn = [&] {
|
||||
if (item && item->history()->peer->isVerified()) {
|
||||
return false;
|
||||
}
|
||||
return (isExecutable && app.settings().exeLaunchWarning())
|
||||
|| (isIpReveal && app.settings().ipRevealWarning());
|
||||
return (isIpReveal && settings.ipRevealWarning())
|
||||
|| ((nameType == Core::NameType::Executable
|
||||
|| nameType == Core::NameType::Unknown)
|
||||
&& !settings.noWarningExtensions().contains(extension));
|
||||
}();
|
||||
const auto extension = '.' + Data::FileExtension(name);
|
||||
if (Platform::IsWindows() && extension == u"."_q) {
|
||||
if (extension.isEmpty()) {
|
||||
// If you launch a file without extension, like "test", in case
|
||||
// there is an executable file with the same name in this folder,
|
||||
// like "test.bat", the executable file will be launched.
|
||||
//
|
||||
// Now we always force an Open With dialog box for such files.
|
||||
//
|
||||
// Let's force it for all platforms for files without extension.
|
||||
crl::on_main([=] {
|
||||
Platform::File::UnsafeShowOpenWith(name);
|
||||
});
|
||||
@@ -98,27 +114,38 @@ void LaunchWithWarning(
|
||||
File::Launch(name);
|
||||
return;
|
||||
}
|
||||
const auto callback = [=, &app](bool checked) {
|
||||
const auto callback = [=, &app, &settings](bool checked) {
|
||||
if (checked) {
|
||||
if (isExecutable) {
|
||||
app.settings().setExeLaunchWarning(false);
|
||||
} else if (isIpReveal) {
|
||||
app.settings().setIpRevealWarning(false);
|
||||
if (isIpReveal) {
|
||||
settings.setIpRevealWarning(false);
|
||||
} else {
|
||||
auto copy = settings.noWarningExtensions();
|
||||
copy.emplace(extension);
|
||||
settings.setNoWarningExtensions(std::move(copy));
|
||||
}
|
||||
app.saveSettingsDelayed();
|
||||
}
|
||||
File::Launch(name);
|
||||
};
|
||||
auto text = isExecutable
|
||||
? tr::lng_launch_exe_warning(
|
||||
lt_extension,
|
||||
rpl::single(Ui::Text::Bold(extension)),
|
||||
Ui::Text::WithEntities)
|
||||
: tr::lng_launch_svg_warning(Ui::Text::WithEntities);
|
||||
auto text = isIpReveal
|
||||
? tr::lng_launch_svg_warning(Ui::Text::WithEntities)
|
||||
: ((nameType == Core::NameType::Executable)
|
||||
? tr::lng_launch_exe_warning
|
||||
: tr::lng_launch_other_warning)(
|
||||
lt_extension,
|
||||
rpl::single(Ui::Text::Bold('.' + extension)),
|
||||
Ui::Text::WithEntities);
|
||||
auto check = (isIpReveal
|
||||
? tr::lng_launch_exe_dont_ask
|
||||
: tr::lng_launch_dont_ask)();
|
||||
auto confirm = ((nameType == Core::NameType::Executable)
|
||||
? tr::lng_launch_exe_sure
|
||||
: tr::lng_launch_other_sure)();
|
||||
Ui::show(Box(
|
||||
ConfirmDontWarnBox,
|
||||
std::move(text),
|
||||
(isExecutable ? tr::lng_launch_exe_sure : tr::lng_continue)(),
|
||||
std::move(check),
|
||||
std::move(confirm),
|
||||
callback));
|
||||
}
|
||||
|
||||
@@ -126,91 +153,6 @@ void LaunchWithWarning(
|
||||
|
||||
const char kOptionExternalVideoPlayer[] = "external-video-player";
|
||||
|
||||
QString FileExtension(const QString &filepath) {
|
||||
const auto reversed = ranges::views::reverse(filepath);
|
||||
const auto last = ranges::find_first_of(reversed, ".\\/");
|
||||
if (last == reversed.end() || *last != '.') {
|
||||
return QString();
|
||||
}
|
||||
return QString(last.base(), last - reversed.begin());
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool IsValidMediaFile(const QString &filepath) {
|
||||
static const auto kExtensions = [] {
|
||||
const auto list = qsl("\
|
||||
16svx 2sf 3g2 3gp 8svx aac aaf aif aifc aiff amr amv ape asf ast au aup \
|
||||
avchd avi brstm bwf cam cdda cust dat divx drc dsh dsf dts dtshd dtsma \
|
||||
dvr-ms dwd evo f4a f4b f4p f4v fla flac flr flv gif gifv gsf gsm gym iff \
|
||||
ifo it jam la ly m1v m2p m2ts m2v m4a m4p m4v mcf mid mk3d mka mks mkv mng \
|
||||
mov mp1 mp2 mp3 mp4 minipsf mod mpc mpe mpeg mpg mpv mscz mt2 mus mxf mxl \
|
||||
niff nsf nsv off ofr ofs ogg ogv opus ots pac ps psf psf2 psflib ptb qsf \
|
||||
qt ra raw rka rm rmj rmvb roq s3m shn sib sid smi smp sol spc spx ssf svi \
|
||||
swa swf tak ts tta txm usf vgm vob voc vox vqf wav webm wma wmv wrap wtv \
|
||||
wv xm xml ym yuv").split(' ');
|
||||
return base::flat_set<QString>(list.begin(), list.end());
|
||||
}();
|
||||
|
||||
return ranges::binary_search(
|
||||
kExtensions,
|
||||
FileExtension(filepath).toLower());
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsExecutableName(const QString &filepath) {
|
||||
static const auto kExtensions = [] {
|
||||
const auto joined =
|
||||
#ifdef Q_OS_WIN
|
||||
u"\
|
||||
ad ade adp app application appref-ms asp asx bas bat bin cab cdxml cer cfg \
|
||||
chi chm cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget \
|
||||
grp hlp hpj hta htt inf ini ins inx isp isu its jar jnlp job js jse key ksh \
|
||||
lnk local lua mad maf mag mam manifest maq mar mas mat mau mav maw mcf mda \
|
||||
mdb mde mdt mdw mdz mht mhtml mjs mmc mof msc msg msh msh1 msh2 msh1xml \
|
||||
msh2xml mshxml msi msp mst ops osd paf pcd phar php php3 php4 php5 php7 phps \
|
||||
php-s pht phtml pif pl plg pm pod prf prg ps1 ps2 ps1xml ps2xml psc1 psc2 \
|
||||
psd1 psm1 pssc pst py py3 pyc pyd pyi pyo pyw pywz pyz rb reg rgs scf scr \
|
||||
sct search-ms settingcontent-ms sh shb shs slk sys t tmp u3p url vb vbe vbp \
|
||||
vbs vbscript vdx vsmacros vsd vsdm vsdx vss vssm vssx vst vstm vstx vsw vsx \
|
||||
vtx website ws wsc wsf wsh xbap xll xnk xs"_q;
|
||||
#elif defined Q_OS_MAC // Q_OS_MAC
|
||||
u"\
|
||||
applescript action app bin command csh osx workflow terminal url caction \
|
||||
mpkg pkg scpt scptd xhtm webarchive"_q;
|
||||
#else // Q_OS_WIN || Q_OS_MAC
|
||||
u"bin csh deb desktop ksh out pet pkg pup rpm run sh shar \
|
||||
slp zsh"_q;
|
||||
#endif // !Q_OS_WIN && !Q_OS_MAC
|
||||
const auto list = joined.split(' ');
|
||||
return base::flat_set<QString>(list.begin(), list.end());
|
||||
}();
|
||||
|
||||
return ranges::binary_search(
|
||||
kExtensions,
|
||||
FileExtension(filepath).toLower());
|
||||
}
|
||||
|
||||
bool IsIpRevealingName(const QString &filepath) {
|
||||
static const auto kExtensions = [] {
|
||||
const auto joined = u"htm html svg m4v m3u8"_q;
|
||||
const auto list = joined.split(' ');
|
||||
return base::flat_set<QString>(list.begin(), list.end());
|
||||
}();
|
||||
static const auto kMimeTypes = [] {
|
||||
const auto joined = u"text/html image/svg+xml"_q;
|
||||
const auto list = joined.split(' ');
|
||||
return base::flat_set<QString>(list.begin(), list.end());
|
||||
}();
|
||||
|
||||
return ranges::binary_search(
|
||||
kExtensions,
|
||||
FileExtension(filepath).toLower()
|
||||
) || ranges::binary_search(
|
||||
kMimeTypes,
|
||||
QMimeDatabase().mimeTypeForFile(QFileInfo(filepath)).name()
|
||||
);
|
||||
}
|
||||
|
||||
base::binary_guard ReadBackgroundImageAsync(
|
||||
not_null<Data::DocumentMedia*> media,
|
||||
FnMut<QImage(QImage)> postprocess,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user