Merge tag 'v4.10.0' into dev

# Conflicts:
#	README.md
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/apiwrap.cpp
#	Telegram/SourceFiles/core/version.h
#	Telegram/SourceFiles/data/data_stories.cpp
#	Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp
#	Telegram/lib_ui
#	snap/snapcraft.yaml
This commit is contained in:
ZavaruKitsu 2023-09-23 10:58:57 +03:00
commit 0502acc8a4
353 changed files with 7144 additions and 3482 deletions

View file

@ -41,7 +41,7 @@ on:
jobs:
linux:
name: CentOS 7
name: Rocky Linux 8
runs-on: ubuntu-latest
container:
image: ghcr.io/${{ github.repository }}/centos_env
@ -51,7 +51,7 @@ jobs:
defaults:
run:
shell: scl enable rh-python38 -- scl enable llvm-toolset-7.0 -- scl enable devtoolset-10 -- bash --noprofile --norc -eo pipefail {0}
shell: scl enable gcc-toolset-12 -- bash --noprofile --norc -eo pipefail {0}
strategy:
matrix:

View file

@ -124,7 +124,7 @@ jobs:
echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV
API="-D TDESKTOP_API_TEST=ON"
if [ ${{ github.ref == 'refs/heads/nightly' }} ]; then
if [ $GITHUB_REF == 'refs/heads/nightly' ]; then
echo "Use the open credentials."
API="-D TDESKTOP_API_ID=611335 -D TDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c"
fi

3
.gitmodules vendored
View file

@ -58,9 +58,6 @@
[submodule "Telegram/ThirdParty/range-v3"]
path = Telegram/ThirdParty/range-v3
url = https://github.com/ericniebler/range-v3.git
[submodule "Telegram/ThirdParty/fcitx-qt5"]
path = Telegram/ThirdParty/fcitx-qt5
url = https://github.com/fcitx/fcitx-qt5.git
[submodule "Telegram/ThirdParty/nimf"]
path = Telegram/ThirdParty/nimf
url = https://github.com/hamonikr/nimf.git

View file

@ -61,7 +61,7 @@ if (NOT DESKTOP_APP_USE_PACKAGED)
if (WIN32)
set(qt_version 5.15.10)
elseif (APPLE)
set(qt_version 6.3.2)
set(qt_version 6.2.5)
endif()
endif()
include(cmake/external/qt/package.cmake)

View file

@ -478,6 +478,7 @@ PRIVATE
core/crash_report_window.h
core/crash_reports.cpp
core/crash_reports.h
core/deadlock_detector.h
core/file_utilities.cpp
core/file_utilities.h
core/launcher.cpp
@ -1541,6 +1542,7 @@ PRIVATE
qrc/emoji_5.qrc
qrc/emoji_6.qrc
qrc/emoji_7.qrc
qrc/emoji_8.qrc
qrc/emoji_preview.qrc
qrc/telegram/animations.qrc
qrc/telegram/export.qrc

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 KiB

After

Width:  |  Height:  |  Size: 832 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 B

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

View file

@ -548,6 +548,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_title_account_name" = "Show active account";
"lng_settings_title_total_count" = "Total unread count";
"lng_settings_native_frame" = "Use system window frame";
"lng_settings_qt_frame" = "Use Qt window frame";
"lng_settings_auto_start" = "Launch Telegram when system starts";
"lng_settings_start_min" = "Launch minimized";
"lng_settings_auto_start_disabled_uwp" = "Starting with the system was disabled in Windows Settings.\n\nPlease enable Telegram Desktop in the Startup Apps Settings.";
@ -1182,6 +1183,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_loading" = "Loading...";
"lng_profile_saved_stories#one" = "{count} saved story";
"lng_profile_saved_stories#other" = "{count} saved stories";
"lng_profile_posts#one" = "{count} post";
"lng_profile_posts#other" = "{count} posts";
"lng_profile_photos#one" = "{count} photo";
"lng_profile_photos#other" = "{count} photos";
"lng_profile_gifs#one" = "{count} GIF";
@ -1611,6 +1614,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_suggested_video" = "{user} suggests you to use this profile video.";
"lng_action_suggested_video_button" = "View Video";
"lng_action_attach_menu_bot_allowed" = "You allowed this bot to message you when you added it in the attachment menu.";
"lng_action_webapp_bot_allowed" = "You allowed this bot to message you in his web-app.";
"lng_action_set_wallpaper_me" = "You set a new wallpaper for this chat";
"lng_action_set_wallpaper" = "{user} set a new wallpaper for this chat";
"lng_action_set_wallpaper_button" = "View Wallpaper";
@ -1799,6 +1803,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_bot_share_location_unavailable" = "Sorry, location sharing is currently unavailable in Telegram Desktop.";
"lng_bot_share_phone" = "Do you want to share your phone number with this bot?";
"lng_bot_share_phone_confirm" = "Share";
"lng_bot_allow_write_title" = "Allow messaging";
"lng_bot_allow_write" = "Do you want to allow this bot writing you?";
"lng_bot_allow_write_confirm" = "Allow";
"lng_attach_failed" = "Failed";
"lng_attach_file" = "File";
@ -1995,6 +2002,38 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_gift_terms" = "You can review the list of features and terms of use for Telegram Premium {link}.";
"lng_premium_gift_terms_link" = "here";
"lng_boost_channel_button" = "Boost Channel";
"lng_boost_level#one" = "Level {count}";
"lng_boost_level#other" = "Level {count}";
"lng_boost_channel_title_first" = "Enable stories for channel";
"lng_boost_channel_needs_first#one" = "{channel} needs **{count}** more boost to enable posting stories. Help make it possible!";
"lng_boost_channel_needs_first#other" = "{channel} needs **{count}** more boosts to enable posting stories. Help make it possible!";
"lng_boost_channel_title_more" = "Help upgrade channel";
"lng_boost_channel_needs_more#one" = "{channel} needs **{count}** more boost to be able to {post}.";
"lng_boost_channel_needs_more#other" = "{channel} needs **{count}** more boosts to be able to {post}.";
"lng_boost_channel_title_max" = "Maximum level reached";
"lng_boost_channel_you_title" = "You boosted {channel}!";
"lng_boost_channel_you_first#one" = "This channel needs **{count}** more boost\nto enable stories.";
"lng_boost_channel_you_first#other" = "This channel needs **{count}** more boosts\nto enable stories.";
"lng_boost_channel_you_more#one" = "This channel needs **{count}** more boost\nto be able to {post}.";
"lng_boost_channel_you_more#other" = "This channel needs **{count}** more boosts\nto be able to {post}.";
"lng_boost_channel_reached_first" = "This channel reached **Level 1** and can now post stories.";
"lng_boost_channel_reached_more#one" = "This channel reached **Level {count}** and can now {post}.";
"lng_boost_channel_reached_more#other" = "This channel reached **Level {count}** and can now {post}.";
"lng_boost_channel_post_stories#one" = "post **{count} story** per day";
"lng_boost_channel_post_stories#other" = "post **{count} stories** per day";
"lng_boost_error_gifted_title" = "Can't boost with gifted Premium!";
"lng_boost_error_gifted_text" = "Because your **Telegram Premium** subscription was gifted to you, you can't use it to boost channels.";
"lng_boost_error_already_title" = "Already Boosted!";
"lng_boost_error_already_text" = "You are already boosting this channel.";
"lng_boost_error_premium_title" = "Premium needed!";
"lng_boost_error_premium_text" = "Only **Telegram Premium** subscribers can boost channels. Do you want to subscribe to **Telegram Premium**?";
"lng_boost_error_premium_yes" = "Yes";
"lng_boost_error_flood_title" = "Can't boost too often!";
"lng_boost_error_flood_text" = "You can change the channel you boost only once a day. Next time you can boost is in {left}.";
"lng_boost_now_instead" = "You currently boost {channel}. Do you want to boost {other} instead?";
"lng_boost_now_replace" = "Replace";
"lng_accounts_limit_title" = "Limit Reached";
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected accounts.";
"lng_accounts_limit1#other" = "You have reached the limit of **{count}** connected accounts.";
@ -2256,17 +2295,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_bot_remove_from_menu" = "Remove From Menu";
"lng_bot_remove_from_menu_sure" = "Remove {bot} from the attachment menu?";
"lng_bot_remove_from_menu_done" = "Bot removed from the menu.";
"lng_bot_remove_from_side_menu" = "Remove From Menu";
"lng_bot_remove_from_side_menu_sure" = "Remove {bot} from the main menu?";
"lng_bot_remove_from_side_menu_done" = "Bot removed from the main menu.";
"lng_bot_settings" = "Settings";
"lng_bot_open" = "Open Bot";
"lng_bot_reload_page" = "Reload Page";
"lng_bot_add_to_menu" = "{bot} asks your permission to be added as an option to your attachments menu so you can access it from any chat.";
"lng_bot_add_to_menu_done" = "Bot added to the menu.";
"lng_bot_will_be_added" = "{bot} shortcuts will be added to the attachment options and the main menu.";
"lng_bot_side_menu_new" = "NEW";
"lng_bot_menu_not_supported" = "This bot isn't supported in the attach menu.";
"lng_bot_menu_already_added" = "This bot is already added in your attach menu.";
"lng_bot_menu_button" = "Menu";
"lng_bot_close_warning_title" = "Warning";
"lng_bot_close_warning" = "Changes that you made may not be saved.";
"lng_bot_close_warning_sure" = "Close anyway";
"lng_bot_add_to_side_menu" = "{bot} asks your permission to be added as an option to your main menu so you can access it any time.";
"lng_bot_add_to_side_menu_done" = "Bot added to the main menu.";
"lng_typing" = "typing";
"lng_user_typing" = "{user} is typing";
@ -2370,6 +2416,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_open_gif" = "Open GIF";
"lng_context_save_gif" = "Save GIF";
"lng_context_delete_gif" = "Delete GIF";
"lng_context_open_channel" = "Open Channel";
"lng_context_attached_stickers" = "Attached Stickers";
"lng_context_to_msg" = "Go To Message";
"lng_context_reply_msg" = "Reply";
@ -2747,6 +2794,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_payments_terms_title" = "Terms of Service";
"lng_payments_terms_text" = "Subscribe and accept terms of service of {bot}?";
"lng_payments_terms_text_once" = "Are you accepting terms of service of {bot}?";
"lng_payments_terms_agree" = "I agree to {link}";
"lng_payments_terms_link" = "Terms of Service";
"lng_payments_terms_accept" = "Accept";
@ -3079,9 +3127,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gigagroup_suggest_more" = "Learn more";
"lng_rights_channel_info" = "Change channel info";
"lng_rights_channel_manage" = "Manage messages";
"lng_rights_channel_post" = "Post messages";
"lng_rights_channel_edit" = "Edit messages of others";
"lng_rights_channel_delete" = "Delete messages of others";
"lng_rights_channel_manage_stories" = "Manage stories";
"lng_rights_channel_post_stories" = "Post stories";
"lng_rights_channel_edit_stories" = "Edit stories of others";
"lng_rights_channel_delete_stories" = "Delete stories of others";
"lng_rights_channel_manage_calls" = "Manage live streams";
"lng_rights_group_info" = "Change group info";
"lng_rights_group_ban" = "Ban users";
@ -3340,6 +3393,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_admin_post_messages" = "Post messages";
"lng_admin_log_admin_edit_messages" = "Edit messages";
"lng_admin_log_admin_delete_messages" = "Delete messages";
"lng_admin_log_admin_post_stories" = "Post stories";
"lng_admin_log_admin_edit_stories" = "Edit stories";
"lng_admin_log_admin_delete_stories" = "Delete stories";
"lng_admin_log_admin_remain_anonymous" = "Remain anonymous";
"lng_admin_log_admin_ban_users" = "Ban users";
"lng_admin_log_admin_invite_users" = "Add members";
@ -3555,6 +3611,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_export_option_choose_format" = "Choose export format";
"lng_export_option_html" = "Human-readable HTML";
"lng_export_option_json" = "Machine-readable JSON";
"lng_export_option_html_and_json" = "Both";
"lng_export_limits" = "From: {from}, to: {till}";
"lng_export_beginning" = "the oldest message";
"lng_export_end" = "present";
@ -3819,6 +3876,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_view_button_voice_chat_channel" = "Live stream";
"lng_view_button_request_join" = "Request to Join";
"lng_view_button_external_link" = "Open link";
"lng_view_button_boost" = "Boost";
"lng_sponsored_hide_ads" = "Hide";
"lng_sponsored_title" = "What are sponsored messages?";
@ -3829,6 +3887,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_telegram_features_url" = "https://t.me/TelegramTips";
"lng_mini_apps_disclaimer_title" = "Warning";
"lng_mini_apps_disclaimer_text" = "You are about to use a mini app operated by an independent party **not affiliated with Telegram**. You must agree to the Terms of Use of mini apps to continue.";
"lng_mini_apps_disclaimer_button" = "I agree to the {link}";
"lng_mini_apps_disclaimer_link" = "Terms of Use";
"lng_mini_apps_tos_url" = "https://telegram.org/tos/mini-apps";
"lng_ringtones_box_title" = "Notification Sound";
"lng_ringtones_box_cloud_subtitle" = "Choose your tone";
"lng_ringtones_box_upload_choose" = "Choose ringtone";
@ -3946,6 +4010,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stories_recent_button" = "Recent Stories";
"lng_stories_archive_title" = "Stories Archive";
"lng_stories_archive_about" = "Only you can see archived stories unless you choose to save them to your profile.";
"lng_stories_channel_archive_about" = "Only admins of the channel can see archived stories unless they are saved to the channel page.";
"lng_stories_reply_sent" = "Message Sent";
"lng_stories_hidden_to_contacts" = "Stories from {user} will now be shown in **Archived Chats**.";
"lng_stories_shown_in_chats" = "Stories from {user} will now be shown in the **Chats List**.";
@ -3965,6 +4030,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stories_archive_done" = "This story is hidden from your profile.";
"lng_stories_archive_done_many#one" = "{count} story is hidden from your profile.";
"lng_stories_archive_done_many#other" = "{count} stories are hidden from your profile.";
"lng_stories_channel_save_sure" = "Do you want to save this story to the channel page?";
"lng_stories_channel_save_sure_many#one" = "Do you want to save {count} story to the channel page?";
"lng_stories_channel_save_sure_many#other" = "Do you want to save {count} stories to the channel page?";
"lng_stories_channel_save_done" = "This story is saved to the channel page.";
"lng_stories_channel_save_done_many#one" = "{count} story is saved to the channel page.";
"lng_stories_channel_save_done_many#other" = "{count} stories are saved to the channel page.";
"lng_stories_channel_save_done_about" = "Saved stories can be viewed by others on the channel page until they are removed.";
"lng_stories_channel_archive_sure" = "Do you want to hide this story from the channel page?";
"lng_stories_channel_archive_sure_many#one" = "Do you want to hide {count} story from the channel page?";
"lng_stories_channel_archive_sure_many#other" = "Do you want to hide {count} stories from the channel page?";
"lng_stories_channel_archive_done" = "This story is hidden from the channel page.";
"lng_stories_channel_archive_done_many#one" = "{count} story is hidden from the channel page.";
"lng_stories_channel_archive_done_many#other" = "{count} stories are hidden from the channel page.";
"lng_stories_save_promo" = "Subscribe to {link} to download other people's unprotected stories to disk.";
"lng_stealth_mode_menu_item" = "Stealth Mode";

View file

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/gui">
<file alias="emoji/emoji_8.webp">../emoji/emoji_8.webp</file>
</qresource>
</RCC>

View file

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

View file

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

View file

@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,9,4,0
PRODUCTVERSION 4,9,4,0
FILEVERSION 4,10,0,0
PRODUCTVERSION 4,10,0,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.9.4.0"
VALUE "FileVersion", "4.10.0.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.9.4.0"
VALUE "ProductVersion", "4.10.0.0"
END
END
BLOCK "VarFileInfo"

View file

@ -267,7 +267,7 @@ int main(int argc, char *argv[])
}
QByteArray inner = f.readAll();
stream << name << quint32(inner.size()) << inner;
#ifdef Q_OS_UNIX
#ifndef Q_OS_WIN
stream << (QFileInfo(fullName).isExecutable() ? true : false);
#endif
}
@ -281,7 +281,7 @@ int main(int argc, char *argv[])
cout << "Compression start, size: " << resultSize << "\n";
QByteArray compressed, resultCheck;
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size
@ -496,10 +496,8 @@ int main(int argc, char *argv[])
QString outName((targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_MAC
QString outName((targetarmac ? QString("tarmacupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_UNIX
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
#else
#error Unknown platform!
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
#endif
if (AlphaVersion) {
outName += "_" + AlphaSignature;

View file

@ -27,7 +27,7 @@ extern "C" {
#include <openssl/evp.h>
} // extern "C"
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
#include <LzmaLib.h>
#else
#include <lzma.h>

View file

@ -41,6 +41,7 @@ bool do_mkdir(const char *path) { // from http://stackoverflow.com/questions/675
}
bool _debug = false;
bool writeprotected = false;
string updaterDir;
string updaterName;
string workDir;
@ -88,7 +89,7 @@ void writeLog(const char *format, ...) {
va_end(args);
}
bool copyFile(const char *from, const char *to, bool writeprotected) {
bool copyFile(const char *from, const char *to) {
FILE *ffrom = fopen(from, "rb"), *fto = fopen(to, "wb");
if (!ffrom) {
if (fto) fclose(fto);
@ -211,7 +212,7 @@ void delFolder() {
rmdir(delFolder.c_str());
}
bool update(bool writeprotected) {
bool update() {
writeLog("Update started..");
string updDir = workDir + "tupdates/temp", readyFilePath = workDir + "tupdates/temp/ready", tdataDir = workDir + "tupdates/temp/tdata";
@ -324,7 +325,7 @@ bool update(bool writeprotected) {
writeLog("Copying file '%s' to '%s'..", fname.c_str(), tofname.c_str());
int copyTries = 0, triesLimit = 30;
do {
if (!copyFile(fname.c_str(), tofname.c_str(), writeprotected)) {
if (!copyFile(fname.c_str(), tofname.c_str())) {
++copyTries;
usleep(100000);
} else {
@ -359,10 +360,10 @@ int main(int argc, char *argv[]) {
bool needupdate = true;
bool autostart = false;
bool debug = false;
bool writeprotected = false;
bool tosettings = false;
bool startintray = false;
bool customWorkingDir = false;
bool justUpdate = false;
char *key = 0;
char *workdir = 0;
@ -381,6 +382,9 @@ int main(int argc, char *argv[]) {
customWorkingDir = true;
} else if (equal(argv[i], "-writeprotected")) {
writeprotected = true;
justUpdate = true;
} else if (equal(argv[i], "-justupdate")) {
justUpdate = true;
} else if (equal(argv[i], "-key") && ++i < argc) {
key = argv[i];
} else if (equal(argv[i], "-workpath") && ++i < argc) {
@ -455,7 +459,7 @@ int main(int argc, char *argv[]) {
} else {
writeLog("Passed workpath is '%s'", workDir.c_str());
}
update(writeprotected);
update();
}
} else {
writeLog("Error: bad exe name!");
@ -464,36 +468,38 @@ int main(int argc, char *argv[]) {
writeLog("Error: short exe name!");
}
const auto fullBinaryPath = exePath + exeName;
auto values = vector<string>();
const auto push = [&](string arg) {
// Force null-terminated .data() call result.
values.push_back(arg + char(0));
};
push(!argv0.empty() ? argv0 : fullBinaryPath);
push("-noupdate");
if (autostart) push("-autostart");
if (debug) push("-debug");
if (startintray) push("-startintray");
if (tosettings) push("-tosettings");
if (key) {
push("-key");
push(key);
}
if (customWorkingDir && workdir) {
push("-workdir");
push(workdir);
}
auto args = vector<char*>();
for (auto &arg : values) {
args.push_back(arg.data());
}
args.push_back(nullptr);
// let the parent launch instead
if (!writeprotected) {
if (justUpdate) {
writeLog("Closing log and quitting..");
} else {
const auto fullBinaryPath = exePath + exeName;
auto values = vector<string>();
const auto push = [&](string arg) {
// Force null-terminated .data() call result.
values.push_back(arg + char(0));
};
push(!argv0.empty() ? argv0 : fullBinaryPath);
push("-noupdate");
if (autostart) push("-autostart");
if (debug) push("-debug");
if (startintray) push("-startintray");
if (tosettings) push("-tosettings");
if (key) {
push("-key");
push(key);
}
if (customWorkingDir && workdir) {
push("-workdir");
push(workdir);
}
auto args = vector<char*>();
for (auto &arg : values) {
args.push_back(arg.data());
}
args.push_back(nullptr);
pid_t pid = fork();
switch (pid) {
case -1:
@ -503,9 +509,10 @@ int main(int argc, char *argv[]) {
execv(fullBinaryPath.c_str(), args.data());
return 1;
}
writeLog("Executed Telegram, closing log and quitting..");
}
writeLog("Executed Telegram, closing log and quitting..");
closeLog();
return 0;

View file

@ -77,45 +77,59 @@ void BlockedPeers::block(not_null<PeerData*> peer) {
_session->changes().peerUpdated(
peer,
Data::PeerUpdate::Flag::IsBlocked);
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
const auto requestId = _api.request(MTPcontacts_Block(
MTP_flags(0),
peer->input
)).done([=] {
_blockRequests.erase(peer);
peer->setIsBlocked(true);
if (_slice) {
_slice->list.insert(
_slice->list.begin(),
{ peer->id, base::unixtime::now() });
++_slice->total;
_changes.fire_copy(*_slice);
}
}).fail([=] {
_blockRequests.erase(peer);
}).send();
_blockRequests.emplace(peer, requestId);
return;
} else if (blockAlreadySent(peer, true)) {
return;
}
const auto requestId = _api.request(MTPcontacts_Block(
MTP_flags(0),
peer->input
)).done([=] {
const auto data = _blockRequests.take(peer);
peer->setIsBlocked(true);
if (_slice) {
_slice->list.insert(
_slice->list.begin(),
{ peer->id, base::unixtime::now() });
++_slice->total;
_changes.fire_copy(*_slice);
}
if (data) {
for (const auto &callback : data->callbacks) {
callback(false);
}
}
}).fail([=] {
if (const auto data = _blockRequests.take(peer)) {
for (const auto &callback : data->callbacks) {
callback(false);
}
}
}).send();
_blockRequests.emplace(peer, Request{
.requestId = requestId,
.blocking = true,
});
}
void BlockedPeers::unblock(
not_null<PeerData*> peer,
Fn<void()> onDone,
Fn<void(bool success)> done,
bool force) {
if (!force && !peer->isBlocked()) {
_session->changes().peerUpdated(
peer,
Data::PeerUpdate::Flag::IsBlocked);
return;
} else if (_blockRequests.find(peer) != end(_blockRequests)) {
} else if (blockAlreadySent(peer, false, done)) {
return;
}
const auto requestId = _api.request(MTPcontacts_Unblock(
MTP_flags(0),
peer->input
)).done([=] {
_blockRequests.erase(peer);
const auto data = _blockRequests.take(peer);
peer->setIsBlocked(false);
if (_slice) {
auto &list = _slice->list;
@ -130,13 +144,46 @@ void BlockedPeers::unblock(
}
_changes.fire_copy(*_slice);
}
if (onDone) {
onDone();
if (data) {
for (const auto &callback : data->callbacks) {
callback(true);
}
}
}).fail([=] {
_blockRequests.erase(peer);
if (const auto data = _blockRequests.take(peer)) {
for (const auto &callback : data->callbacks) {
callback(false);
}
}
}).send();
_blockRequests.emplace(peer, requestId);
const auto i = _blockRequests.emplace(peer, Request{
.requestId = requestId,
.blocking = false,
}).first;
if (done) {
i->second.callbacks.push_back(std::move(done));
}
}
bool BlockedPeers::blockAlreadySent(
not_null<PeerData*> peer,
bool blocking,
Fn<void(bool success)> done) {
const auto i = _blockRequests.find(peer);
if (i == end(_blockRequests)) {
return false;
} else if (i->second.blocking == blocking) {
if (done) {
i->second.callbacks.push_back(std::move(done));
}
return true;
}
const auto callbacks = base::take(i->second.callbacks);
_blockRequests.erase(i);
for (const auto &callback : callbacks) {
callback(false);
}
return false;
}
void BlockedPeers::reload() {
@ -160,7 +207,7 @@ auto BlockedPeers::slice() -> rpl::producer<BlockedPeers::Slice> {
: (_changes.events() | rpl::type_erased());
}
void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> onDone) {
void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> done) {
if (_requestId) {
return;
}
@ -170,7 +217,7 @@ void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> onDone) {
MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice)
)).done([=](const MTPcontacts_Blocked &result) {
_requestId = 0;
onDone(TLToSlice(result, _session->data()));
done(TLToSlice(result, _session->data()));
}).fail([=] {
_requestId = 0;
}).send();

View file

@ -39,20 +39,31 @@ public:
void reload();
rpl::producer<Slice> slice();
void request(int offset, Fn<void(Slice)> onDone);
void request(int offset, Fn<void(Slice)> done);
void block(not_null<PeerData*> peer);
void unblock(
not_null<PeerData*> peer,
Fn<void()> onDone = nullptr,
Fn<void(bool success)> done = nullptr,
bool force = false);
private:
struct Request {
std::vector<Fn<void(bool success)>> callbacks;
mtpRequestId requestId = 0;
bool blocking = false;
};
[[nodiscard]] bool blockAlreadySent(
not_null<PeerData*> peer,
bool blocking,
Fn<void(bool success)> done = nullptr);
const not_null<Main::Session*> _session;
MTP::Sender _api;
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests;
base::flat_map<not_null<PeerData*>, Request> _blockRequests;
mtpRequestId _requestId = 0;
std::optional<Slice> _slice;
rpl::event_stream<Slice> _changes;

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "window/window_session_controller.h"
#include "info/profile/info_profile_badge.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/empty_userpic.h"
@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toast/toast.h"
#include "boxes/premium_limits_box.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h"
#include "styles/style_layers.h"
namespace Api {
@ -195,6 +197,13 @@ ConfirmInviteBox::ConfirmInviteBox(
: _session(session)
, _submit(std::move(submit))
, _title(this, st::confirmInviteTitle)
, _badge(std::make_unique<Info::Profile::Badge>(
this,
st::infoPeerBadge,
_session,
rpl::single(Info::Profile::Badge::Content{ BadgeForInvite(invite) }),
nullptr,
[=] { return false; }))
, _status(this, st::confirmInviteStatus)
, _about(this, st::confirmInviteAbout)
, _aboutRequests(this, st::confirmInviteStatus)
@ -275,9 +284,24 @@ ConfirmInviteBox::ChatInvite ConfirmInviteBox::Parse(
.isMegagroup = data.is_megagroup(),
.isBroadcast = data.is_broadcast(),
.isRequestNeeded = data.is_request_needed(),
.isFake = data.is_fake(),
.isScam = data.is_scam(),
.isVerified = data.is_verified(),
};
}
[[nodiscard]] Info::Profile::BadgeType ConfirmInviteBox::BadgeForInvite(
const ChatInvite &invite) {
using Type = Info::Profile::BadgeType;
return invite.isVerified
? Type::Verified
: invite.isScam
? Type::Scam
: invite.isFake
? Type::Fake
: Type::None;
}
void ConfirmInviteBox::prepare() {
addButton(
(_requestApprove
@ -326,8 +350,26 @@ void ConfirmInviteBox::prepare() {
void ConfirmInviteBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_title->move((width() - _title->width()) / 2, st::confirmInviteTitleTop);
_status->move((width() - _status->width()) / 2, st::confirmInviteStatusTop);
const auto padding = st::boxRowPadding;
auto nameWidth = width() - padding.left() - padding.right();
auto badgeWidth = 0;
if (const auto widget = _badge->widget()) {
badgeWidth = st::infoVerifiedCheckPosition.x() + widget->width();
nameWidth -= badgeWidth;
}
_title->resizeToWidth(std::min(nameWidth, _title->textMaxWidth()));
_title->moveToLeft(
(width() - _title->width() - badgeWidth) / 2,
st::confirmInviteTitleTop);
const auto badgeLeft = _title->x() + _title->width();
const auto badgeTop = _title->y();
const auto badgeBottom = _title->y() + _title->height();
_badge->move(badgeLeft, badgeTop, badgeBottom);
_status->move(
(width() - _status->width()) / 2,
st::confirmInviteStatusTop);
auto bottom = _status->y()
+ _status->height()
+ st::boxPadding.bottom()

View file

@ -12,6 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class UserData;
class ChannelData;
namespace Info::Profile {
class Badge;
enum class BadgeType;
} // namespace Info::Profile
namespace Main {
class Session;
} // namespace Main
@ -66,10 +71,15 @@ private:
bool isMegagroup = false;
bool isBroadcast = false;
bool isRequestNeeded = false;
bool isFake = false;
bool isScam = false;
bool isVerified = false;
};
[[nodiscard]] static ChatInvite Parse(
not_null<Main::Session*> session,
const MTPDchatInvite &data);
[[nodiscard]] Info::Profile::BadgeType BadgeForInvite(
const ChatInvite &invite);
ConfirmInviteBox(
not_null<Main::Session*> session,
@ -81,12 +91,14 @@ private:
Fn<void()> _submit;
object_ptr<Ui::FlatLabel> _title;
std::unique_ptr<Info::Profile::Badge> _badge;
object_ptr<Ui::FlatLabel> _status;
object_ptr<Ui::FlatLabel> _about;
object_ptr<Ui::FlatLabel> _aboutRequests;
std::shared_ptr<Data::PhotoMedia> _photo;
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
std::vector<Participant> _participants;
bool _isChannel = false;
bool _requestApprove = false;

View file

@ -78,12 +78,8 @@ void SendReport(
MTP_string(comment)
)).done(std::move(done)).send();
}, [&](StoryId id) {
const auto user = peer->asUser();
if (!user) {
return;
}
peer->session().api().request(MTPstories_Report(
user->inputUser,
peer->input,
MTP_vector<MTPint>(1, MTP_int(id)),
ReasonToTL(reason),
MTP_string(comment)

View file

@ -17,11 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Api {
namespace {
constexpr auto TestApiId = 17349;
constexpr auto SnapApiId = 611335;
constexpr auto DesktopApiId = 2040;
Websites::Entry ParseEntry(
[[nodiscard]] Websites::Entry ParseEntry(
not_null<Data::Session*> owner,
const MTPDwebAuthorization &data) {
auto result = Websites::Entry{

View file

@ -100,8 +100,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/storage_media_prepare.h"
#include "storage/storage_account.h"
// AyuGram includes
#include "ayu/ayu_settings.h"
namespace {
// Save draft to the cloud with 1 sec extra delay.
@ -791,7 +793,7 @@ QString ApiWrap::exportDirectStoryLink(not_null<Data::Story*> story) {
? i->second
: fallback();
request(MTPstories_ExportStoryLink(
story->peer()->asUser()->inputUser,
story->peer()->input,
MTP_int(story->id())
)).done([=](const MTPExportedStoryLink &result) {
const auto link = qs(result.data().vlink());
@ -2535,14 +2537,9 @@ void ApiWrap::refreshFileReference(
}, [&](Data::FileOriginPremiumPreviews data) {
request(MTPhelp_GetPremiumPromo());
}, [&](Data::FileOriginStory data) {
const auto user = _session->data().peer(data.peerId)->asUser();
if (user) {
request(MTPstories_GetStoriesByID(
user->inputUser,
MTP_vector<MTPint>(1, MTP_int(data.storyId))));
} else {
fail();
}
request(MTPstories_GetStoriesByID(
_session->data().peer(data.peerId)->input,
MTP_vector<MTPint>(1, MTP_int(data.storyId))));
}, [&](v::null_t) {
fail();
});
@ -3322,25 +3319,37 @@ void ApiWrap::shareContact(
const QString &phone,
const QString &firstName,
const QString &lastName,
const SendAction &action) {
const SendAction &action,
Fn<void(bool)> done) {
const auto userId = UserId(0);
sendSharedContact(phone, firstName, lastName, userId, action);
sendSharedContact(
phone,
firstName,
lastName,
userId,
action,
std::move(done));
}
void ApiWrap::shareContact(
not_null<UserData*> user,
const SendAction &action) {
const SendAction &action,
Fn<void(bool)> done) {
const auto userId = peerToUser(user->id);
const auto phone = _session->data().findContactPhone(user);
if (phone.isEmpty()) {
if (done) {
done(false);
}
return;
}
sendSharedContact(
return sendSharedContact(
phone,
user->firstName,
user->lastName,
userId,
action);
action,
std::move(done));
}
void ApiWrap::sendSharedContact(
@ -3348,7 +3357,8 @@ void ApiWrap::sendSharedContact(
const QString &firstName,
const QString &lastName,
UserId userId,
const SendAction &action) {
const SendAction &action,
Fn<void(bool)> done) {
sendAction(action);
const auto history = action.history;
@ -3399,7 +3409,7 @@ void ApiWrap::sendSharedContact(
MTP_string(firstName),
MTP_string(lastName),
MTP_string()); // vcard
sendMedia(item, media, action.options);
sendMedia(item, media, action.options, std::move(done));
_session->data().sendHistoryChangeNotifications();
_session->changes().historyUpdated(
@ -3949,18 +3959,20 @@ void ApiWrap::uploadAlbumMedia(
void ApiWrap::sendMedia(
not_null<HistoryItem*> item,
const MTPInputMedia &media,
Api::SendOptions options) {
Api::SendOptions options,
Fn<void(bool)> done) {
const auto randomId = base::RandomValue<uint64>();
_session->data().registerMessageRandomId(randomId, item->fullId());
sendMediaWithRandomId(item, media, options, randomId);
sendMediaWithRandomId(item, media, options, randomId, std::move(done));
}
void ApiWrap::sendMediaWithRandomId(
not_null<HistoryItem*> item,
const MTPInputMedia &media,
Api::SendOptions options,
uint64 randomId) {
uint64 randomId,
Fn<void(bool)> done) {
// AyuGram useScheduledMessages
const auto settings = &AyuSettings::getInstance();
if (settings->useScheduledMessages && !options.scheduled)
@ -3969,7 +3981,6 @@ void ApiWrap::sendMediaWithRandomId(
auto current = base::unixtime::now();
options.scheduled = current + 12;
}
const auto history = item->history();
const auto replyTo = item->replyTo();
@ -4011,10 +4022,12 @@ void ApiWrap::sendMediaWithRandomId(
MTP_int(options.scheduled),
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty())
), [=](const MTPUpdates &result, const MTP::Response &response) {
if (done) done(true);
if (updateRecentStickers) {
requestRecentStickersForce(true);
}
}, [=](const MTP::Error &error, const MTP::Response &response) {
if (done) done(false);
sendMessageFail(error, peer, randomId, itemId);
});
}

View file

@ -294,8 +294,12 @@ public:
const QString &phone,
const QString &firstName,
const QString &lastName,
const SendAction &action);
void shareContact(not_null<UserData*> user, const SendAction &action);
const SendAction &action,
Fn<void(bool)> done = nullptr);
void shareContact(
not_null<UserData*> user,
const SendAction &action,
Fn<void(bool)> done = nullptr);
void applyAffectedMessages(
not_null<PeerData*> peer,
const MTPmessages_AffectedMessages &result);
@ -489,7 +493,8 @@ private:
const QString &firstName,
const QString &lastName,
UserId userId,
const SendAction &action);
const SendAction &action,
Fn<void(bool)> done);
void deleteHistory(
not_null<PeerData*> peer,
@ -516,12 +521,14 @@ private:
void sendMedia(
not_null<HistoryItem*> item,
const MTPInputMedia &media,
Api::SendOptions options);
Api::SendOptions options,
Fn<void(bool)> done = nullptr);
void sendMediaWithRandomId(
not_null<HistoryItem*> item,
const MTPInputMedia &media,
Api::SendOptions options,
uint64 randomId);
uint64 randomId,
Fn<void(bool)> done = nullptr);
FileLoadTo fileLoadTaskOptions(const SendAction &action) const;
void getTopPromotionDelayed(TimeId now, TimeId next);

View file

@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/toast/toast.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/fields/special_fields.h"
#include "ui/widgets/popup_menu.h"
#include "ui/text/format_values.h"
@ -297,8 +298,11 @@ void AddContactBox::prepare() {
: tr::lng_enter_contact_data());
updateButtons();
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
const auto submitted = [=] { submit(); };
_first->submits(
) | rpl::start_with_next(submitted, _first->lifetime());
_last->submits(
) | rpl::start_with_next(submitted, _last->lifetime());
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
setDimensions(
@ -567,23 +571,24 @@ void GroupInfoBox::prepare() {
_description->setSubmitSettings(
Core::App().settings().sendSubmitWay());
connect(_description, &Ui::InputField::resized, [=] {
_description->heightChanges(
) | rpl::start_with_next([=] {
descriptionResized();
});
connect(_description, &Ui::InputField::submitted, [=] {
submit();
});
connect(_description, &Ui::InputField::cancelled, [=] {
}, _description->lifetime());
_description->submits(
) | rpl::start_with_next([=] { submit(); }, _description->lifetime());
_description->cancelled(
) | rpl::start_with_next([=] {
closeBox();
});
}, _description->lifetime());
Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(),
_description,
&_navigation->session());
}
connect(_title, &Ui::InputField::submitted, [=] { submitName(); });
_title->submits(
) | rpl::start_with_next([=] { submitName(); }, _title->lifetime());
addButton(
((_type != Type::Group || _canAddBot)
@ -1522,20 +1527,22 @@ void EditNameBox::prepare() {
_first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
_last->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
_first->submits(
) | rpl::start_with_next([=] { submit(); }, _first->lifetime());
_last->submits(
) | rpl::start_with_next([=] { submit(); }, _last->lifetime());
_first->customTab(true);
_last->customTab(true);
QObject::connect(
_first,
&Ui::InputField::tabbed,
[=] { _last->setFocus(); });
QObject::connect(
_last,
&Ui::InputField::tabbed,
[=] { _first->setFocus(); });
_first->tabbed(
) | rpl::start_with_next([=] {
_last->setFocus();
}, _first->lifetime());
_last->tabbed(
) | rpl::start_with_next([=] {
_first->setFocus();
}, _last->lifetime());
}
void EditNameBox::setInnerFocus() {

View file

@ -32,27 +32,27 @@ Data::ChatFilter ChangedFilter(
auto never = base::duplicate(filter.never());
if (add) {
never.remove(history);
const auto result = Data::ChatFilter(
filter.id(),
filter.title(),
filter.iconEmoji(),
filter.flags(),
filter.always(),
filter.pinned(),
std::move(never));
if (result.contains(history)) {
return result;
} else {
never = base::duplicate(result.never());
always.insert(history);
}
} else {
const auto alwaysIt = always.find(history);
if (alwaysIt != end(always)) {
always.erase(alwaysIt);
} else {
never.insert(history);
}
always.remove(history);
}
const auto result = Data::ChatFilter(
filter.id(),
filter.title(),
filter.iconEmoji(),
filter.flags(),
std::move(always),
filter.pinned(),
std::move(never));
const auto in = result.contains(history);
if (in == add) {
return result;
}
always = base::duplicate(result.always());
never = base::duplicate(result.never());
if (add) {
always.insert(history);
} else {
never.insert(history);
}
return Data::ChatFilter(
filter.id(),

View file

@ -18,7 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/facade.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/fields/number_input.h"
#include "ui/widgets/fields/password_input.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/wrap/slide_wrap.h"

View file

@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
@ -184,7 +184,8 @@ not_null<Ui::FlatLabel*> CreateWarningLabel(
QString(),
st::createPollWarning);
result->setAttribute(Qt::WA_TransparentForMouseEvents);
QObject::connect(field, &Ui::InputField::changed, [=] {
field->changes(
) | rpl::start_with_next([=] {
Ui::PostponeCall(crl::guard(field, [=] {
const auto length = field->getLastText().size();
const auto value = valueLimit - length;
@ -198,7 +199,7 @@ not_null<Ui::FlatLabel*> CreateWarningLabel(
}
result->setVisible(shown);
}));
});
}, field->lifetime());
return result;
}
@ -243,13 +244,14 @@ Options::Option::Option(
_content->resize(_content->width(), height);
}, _field->lifetime());
QObject::connect(_field, &Ui::InputField::changed, [=] {
_field->changes(
) | rpl::start_with_next([=] {
Ui::PostponeCall(crl::guard(_field, [=] {
if (_hasCorrect) {
_correct->toggle(isGood(), anim::type::normal);
}
}));
});
}, _field->lifetime());
createShadow();
createRemove();
@ -303,10 +305,11 @@ void Options::Option::createRemove() {
const auto toggle = lifetime.make_state<rpl::variable<bool>>(false);
_removeAlways = lifetime.make_state<rpl::variable<bool>>(false);
QObject::connect(field, &Ui::InputField::changed, [=] {
field->changes(
) | rpl::start_with_next([field, toggle] {
// Don't capture 'this'! Because Option is a value type.
*toggle = !field->getLastText().isEmpty();
});
}, field->lifetime());
rpl::combine(
toggle->value(),
_removeAlways->value(),
@ -649,28 +652,32 @@ void Options::addEmptyOption() {
_position + _list.size() + _destroyed.size(),
_chooseCorrectGroup));
const auto field = _list.back()->field();
QObject::connect(field, &Ui::InputField::submitted, [=] {
field->submits(
) | rpl::start_with_next([=] {
const auto index = findField(field);
if (_list[index]->isGood() && index + 1 < _list.size()) {
_list[index + 1]->setFocus();
}
});
QObject::connect(field, &Ui::InputField::changed, [=] {
}, field->lifetime());
field->changes(
) | rpl::start_with_next([=] {
Ui::PostponeCall(crl::guard(field, [=] {
validateState();
}));
});
QObject::connect(field, &Ui::InputField::focused, [=] {
}, field->lifetime());
field->focusedChanges(
) | rpl::filter(rpl::mappers::_1) | rpl::start_with_next([=] {
_scrollToWidget.fire_copy(field);
});
QObject::connect(field, &Ui::InputField::tabbed, [=] {
}, field->lifetime());
field->tabbed(
) | rpl::start_with_next([=] {
const auto index = findField(field);
if (index + 1 < _list.size()) {
_list[index + 1]->setFocus();
} else {
_tabbed.fire({});
}
});
}, field->lifetime());
base::install_event_filter(field, [=](not_null<QEvent*> event) {
if (event->type() != QEvent::KeyPress
|| !field->getLastText().isEmpty()) {
@ -927,9 +934,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
st::boxDividerLabel),
st::createPollLimitPadding));
connect(question, &Ui::InputField::tabbed, [=] {
question->tabbed(
) | rpl::start_with_next([=] {
options->focusFirst();
});
}, question->lifetime());
AddSkip(container);
AddSubsectionTitle(container, tr::lng_polls_create_settings());
@ -975,9 +983,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
}
}, question->lifetime());
connect(solution, &Ui::InputField::tabbed, [=] {
solution->tabbed(
) | rpl::start_with_next([=] {
question->setFocus();
});
}, solution->lifetime());
quiz->setDisabled(_disabled & PollData::Flag::Quiz);
if (multiple) {
@ -1009,12 +1018,12 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
const auto text = question->getLastText().trimmed();
return !text.isEmpty() && (text.size() <= kQuestionLimit);
};
connect(question, &Ui::InputField::submitted, [=] {
question->submits(
) | rpl::start_with_next([=] {
if (isValidQuestion()) {
options->focusFirst();
}
});
}, question->lifetime());
_setInnerFocus = [=] {
question->setFocusFast();

View file

@ -54,7 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/painter.h"
#include "ui/ui_utility.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/scroll_area.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
@ -488,9 +488,16 @@ void EditCaptionBox::setupField() {
Core::App().settings().sendSubmitWay());
_field->setMaxHeight(st::defaultComposeFiles.caption.heightMax);
connect(_field, &Ui::InputField::submitted, [=] { save(); });
connect(_field, &Ui::InputField::cancelled, [=] { closeBox(); });
connect(_field, &Ui::InputField::resized, [=] { captionResized(); });
_field->submits(
) | rpl::start_with_next([=] { save(); }, _field->lifetime());
_field->cancelled(
) | rpl::start_with_next([=] {
closeBox();
}, _field->lifetime());
_field->heightChanges(
) | rpl::start_with_next([=] {
captionResized();
}, _field->lifetime());
_field->setMimeDataHook([=](
not_null<const QMimeData*> data,
Ui::InputField::MimeAction action) {
@ -522,10 +529,11 @@ void EditCaptionBox::setInitialText() {
setCloseByOutsideClick(true);
}
});
connect(_field, &Ui::InputField::changed, [=] {
_field->changes(
) | rpl::start_with_next([=] {
_checkChangedTimer.callOnce(kChangesDebounceTimeout);
setCloseByOutsideClick(false);
});
}, _field->lifetime());
}
void EditCaptionBox::setupControls() {

View file

@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h"
#include "ui/text/text_options.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/effects/panel_animation.h"
#include "ui/filter_icons.h"
@ -619,11 +619,12 @@ void EditFilterBox(
nameEditing->custom = true;
}, box->lifetime());
QObject::connect(name, &Ui::InputField::changed, [=] {
name->changes(
) | rpl::start_with_next([=] {
if (!nameEditing->settingDefault) {
nameEditing->custom = true;
}
});
}, name->lifetime());
const auto updateDefaultTitle = [=](const Data::ChatFilter &filter) {
if (nameEditing->custom) {
return;

View file

@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/invite_link_label.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"

View file

@ -21,10 +21,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/fields/password_input.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/sent_code_field.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/painter.h"
#include "passport/passport_encryption.h"
@ -306,15 +305,26 @@ void PasscodeBox::prepare() {
connect(_oldPasscode, &Ui::MaskedInputField::changed, [=] { oldChanged(); });
connect(_newPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); });
connect(_reenterPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); });
connect(_passwordHint, &Ui::InputField::changed, [=] { newChanged(); });
connect(_recoverEmail, &Ui::InputField::changed, [=] { emailChanged(); });
_passwordHint->changes(
) | rpl::start_with_next([=] {
newChanged();
}, _passwordHint->lifetime());
_recoverEmail->changes(
) | rpl::start_with_next([=] {
if (!_emailError.isEmpty()) {
_emailError = QString();
update();
}
}, _recoverEmail->lifetime());
const auto fieldSubmit = [=] { submit(); };
connect(_oldPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
connect(_newPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
connect(_reenterPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
connect(_passwordHint, &Ui::InputField::submitted, fieldSubmit);
connect(_recoverEmail, &Ui::InputField::submitted, fieldSubmit);
_passwordHint->submits(
) | rpl::start_with_next(fieldSubmit, _passwordHint->lifetime());
_recoverEmail->submits(
) | rpl::start_with_next(fieldSubmit, _recoverEmail->lifetime());
_recover->addClickHandler([=] { recoverByEmail(); });
@ -1061,13 +1071,6 @@ void PasscodeBox::newChanged() {
}
}
void PasscodeBox::emailChanged() {
if (!_emailError.isEmpty()) {
_emailError = QString();
update();
}
}
void PasscodeBox::recoverByEmail() {
if (!_cloudFields.hasRecovery) {
Assert(_session != nullptr);
@ -1189,8 +1192,12 @@ void RecoverBox::prepare() {
+ _recoverCode->height()
+ st::passcodeTextLine));
connect(_recoverCode, &Ui::InputField::changed, [=] { codeChanged(); });
connect(_recoverCode, &Ui::InputField::submitted, [=] { submit(); });
_recoverCode->changes(
) | rpl::start_with_next([=] {
codeChanged();
}, _recoverCode->lifetime());
_recoverCode->submits(
) | rpl::start_with_next([=] { submit(); }, _recoverCode->lifetime());
}
void RecoverBox::paintEvent(QPaintEvent *e) {

View file

@ -90,7 +90,6 @@ private:
void closeReplacedBy();
void oldChanged();
void newChanged();
void emailChanged();
void save(bool force = false);
void badOldPasscode();
void recoverByEmail();

View file

@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/text/format_values.h" // Ui::FormatPhone
#include "ui/text/text_utilities.h"
#include "info/profile/info_profile_cover.h"
@ -239,8 +239,8 @@ void Controller::initNameFields(
_save();
}
};
QObject::connect(first, &Ui::InputField::submitted, submit);
QObject::connect(last, &Ui::InputField::submitted, submit);
first->submits() | rpl::start_with_next(submit, first->lifetime());
last->submits() | rpl::start_with_next(submit, last->lifetime());
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
}

View file

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/peers/edit_forum_topic_box.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/shadow.h"
#include "ui/effects/emoji_fly_animation.h"
#include "ui/abstract_button.h"
@ -465,15 +465,13 @@ void EditForumTopicBox(
ChooseNextColorId(current.colorId, state->otherColorIds),
};
});
base::qt_signal_producer(
title,
&Ui::InputField::changed
title->changes(
) | rpl::start_with_next([=] {
state->defaultIcon = DefaultIcon{
title->getLastText().trimmed(),
state->defaultIcon.current().colorId,
};
}, box->lifetime());
}, title->lifetime());
if (!topic || !topic->isGeneral()) {
Settings::AddDividerText(

View file

@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/box_content_divider.h"
#include "ui/layers/generic_box.h"
#include "ui/toast/toast.h"
@ -384,8 +384,11 @@ void EditAdminBox::prepare() {
if (!_saveCallback) {
return;
} else if (_addAsAdmin && !_addAsAdmin->checked()) {
const auto weak = Ui::MakeWeak(this);
AddBotToGroup(user(), peer(), _addingBot->token);
getDelegate()->hideLayer();
if (const auto strong = weak.data()) {
strong->closeBox();
}
return;
} else if (_addingBot && !_addingBot->existing) {
const auto phrase = peer()->isBroadcast()
@ -461,13 +464,14 @@ not_null<Ui::InputField*> EditAdminBox::addRankInput(
st::rightsAboutMargin);
result->setMaxLength(kAdminRoleLimit);
result->setInstantReplaces(Ui::InstantReplaces::TextOnly());
connect(result, &Ui::InputField::changed, [=] {
result->changes(
) | rpl::start_with_next([=] {
const auto text = result->getLastText();
const auto removed = TextUtilities::RemoveEmoji(text);
if (removed != text) {
result->setText(removed);
}
});
}, result->lifetime());
container->add(
object_ptr<Ui::FlatLabel>(

View file

@ -51,7 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/box_content_divider.h"
#include "ui/wrap/padding_wrap.h"
@ -519,10 +519,10 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
result->entity(),
&_peer->session());
QObject::connect(
result->entity(),
&Ui::InputField::submitted,
[=] { submitTitle(); });
result->entity()->submits(
) | rpl::start_with_next([=] {
submitTitle();
}, result->entity()->lifetime());
_controls.title = result->entity();
return result;
@ -555,10 +555,10 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
result->entity(),
&_peer->session());
QObject::connect(
result->entity(),
&Ui::InputField::submitted,
[=] { submitDescription(); });
result->entity()->submits(
) | rpl::start_with_next([=] {
submitDescription();
}, result->entity()->lifetime());
_controls.description = result->entity();
return result;

View file

@ -51,13 +51,14 @@ constexpr auto kForceDisableTooltipDuration = 3 * crl::time(1000);
}
[[nodiscard]] auto NestedRestrictionLabelsList(
Data::RestrictionsSetOptions options) {
Data::RestrictionsSetOptions options)
-> std::vector<NestedEditFlagsLabels<ChatRestrictions>> {
using Flag = ChatRestriction;
auto first = std::vector<RestrictionLabel>{
{ Flag::SendOther, tr::lng_rights_chat_send_text(tr::now) },
};
auto inner = std::vector<RestrictionLabel>{
auto media = std::vector<RestrictionLabel>{
{ Flag::SendPhotos, tr::lng_rights_chat_photos(tr::now) },
{ Flag::SendVideos, tr::lng_rights_chat_videos(tr::now) },
{ Flag::SendVideoMessages, tr::lng_rights_chat_video_messages(tr::now) },
@ -85,9 +86,64 @@ constexpr auto kForceDisableTooltipDuration = 3 * crl::time(1000);
&RestrictionLabel::flags),
end(second));
}
return std::vector<NestedEditFlagsLabels<ChatRestrictions>>{
return {
{ std::nullopt, std::move(first) },
{ tr::lng_rights_chat_send_media(), std::move(inner) },
{ tr::lng_rights_chat_send_media(), std::move(media) },
{ std::nullopt, std::move(second) },
};
}
[[nodiscard]] auto NestedAdminRightLabels(
Data::AdminRightsSetOptions options)
-> std::vector<NestedEditFlagsLabels<ChatAdminRights>> {
using Flag = ChatAdminRight;
if (options.isGroup) {
auto result = std::vector<AdminRightLabel>{
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
{ Flag::InviteByLinkOrAdd, options.anyoneCanAddMembers
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageTopics, tr::lng_rights_group_topics(tr::now) },
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
};
if (!options.isForum) {
result.erase(
ranges::remove(
result,
Flag::ManageTopics | Flag(),
&AdminRightLabel::flags),
end(result));
}
return { { std::nullopt, std::move(result) } };
}
auto first = std::vector<AdminRightLabel>{
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
};
auto messages = std::vector<AdminRightLabel>{
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
};
auto stories = std::vector<AdminRightLabel>{
{ Flag::PostStories, tr::lng_rights_channel_post_stories(tr::now) },
{ Flag::EditStories, tr::lng_rights_channel_edit_stories(tr::now) },
{ Flag::DeleteStories, tr::lng_rights_channel_delete_stories(tr::now) },
};
auto second = std::vector<AdminRightLabel>{
{ Flag::InviteByLinkOrAdd, tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
};
return {
{ std::nullopt, std::move(first) },
{ tr::lng_rights_channel_manage(), std::move(messages) },
{ tr::lng_rights_channel_manage_stories(), std::move(stories) },
{ std::nullopt, std::move(second) },
};
}
@ -1031,42 +1087,11 @@ std::vector<RestrictionLabel> RestrictionLabels(
std::vector<AdminRightLabel> AdminRightLabels(
Data::AdminRightsSetOptions options) {
using Flag = ChatAdminRight;
if (options.isGroup) {
auto result = std::vector<AdminRightLabel>{
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
{ Flag::InviteByLinkOrAdd, options.anyoneCanAddMembers
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageTopics, tr::lng_rights_group_topics(tr::now) },
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
};
if (!options.isForum) {
result.erase(
ranges::remove(
result,
Flag::ManageTopics | Flag(),
&AdminRightLabel::flags),
end(result));
}
return result;
} else {
return {
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
{ Flag::InviteByLinkOrAdd, tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) }
};
auto result = std::vector<AdminRightLabel>();
for (const auto &[_, r] : NestedAdminRightLabels(options)) {
result.insert(result.end(), r.begin(), r.end());
}
return result;
}
EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
@ -1107,7 +1132,7 @@ EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
rights,
{
.header = std::move(header),
.labels = { { std::nullopt, AdminRightLabels(options) } },
.labels = NestedAdminRightLabels(options),
.disabledMessages = std::move(disabledMessages),
});
result.widget = std::move(widget);

View file

@ -32,7 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/userpic_button.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/box_content_divider.h"
#include "ui/wrap/padding_wrap.h"

View file

@ -48,19 +48,6 @@ struct InfographicDescriptor {
bool complexRatio = false;
};
[[nodiscard]] rpl::producer<> BoxShowFinishes(not_null<Ui::GenericBox*> box) {
const auto singleShot = box->lifetime().make_state<rpl::lifetime>();
const auto showFinishes = singleShot->make_state<rpl::event_stream<>>();
box->setShowFinishedCallback([=] {
showFinishes->fire({});
singleShot->destroy();
box->setShowFinishedCallback(nullptr);
});
return showFinishes->events();
}
void AddSubsectionTitle(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text) {
@ -423,8 +410,9 @@ void SimpleLimitBox(
Settings::AddSkip(top, st::premiumInfographicPadding.top());
Ui::Premium::AddBubbleRow(
top,
st::defaultPremiumBubble,
BoxShowFinishes(box),
descriptor.defaultLimit,
0,
descriptor.current,
descriptor.premiumLimit,
premiumPossible,
@ -783,16 +771,18 @@ void FilterLinksLimitBox(
void FiltersLimitBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) {
not_null<Main::Session*> session,
std::optional<int> filtersCountOverride) {
const auto premium = session->premium();
const auto premiumPossible = session->premiumPossible();
const auto limits = Data::PremiumLimits(session);
const auto defaultLimit = float64(limits.dialogFiltersDefault());
const auto premiumLimit = float64(limits.dialogFiltersPremium());
const auto current = float64(ranges::count_if(
const auto cloud = int(ranges::count_if(
session->data().chatsFilters().list(),
[](const Data::ChatFilter &f) { return f.id() != FilterId(); }));
const auto current = float64(filtersCountOverride.value_or(cloud));
auto text = rpl::combine(
tr::lng_filters_limit1(
@ -1092,6 +1082,7 @@ void AccountsLimitBox(
Settings::AddSkip(top, st::premiumInfographicPadding.top());
Ui::Premium::AddBubbleRow(
top,
st::defaultPremiumBubble,
BoxShowFinishes(box),
0,
current,

View file

@ -42,7 +42,8 @@ void FilterLinksLimitBox(
not_null<Main::Session*> session);
void FiltersLimitBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session);
not_null<Main::Session*> session,
std::optional<int> filtersCountOverride);
void ShareableFiltersLimitBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session);

View file

@ -31,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/scroll_content_shadow.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/popup_menu.h"
#include "ui/wrap/vertical_layout.h"
@ -1033,17 +1033,21 @@ void SendFilesBox::setupCaption() {
Core::App().settings().sendSubmitWay());
_caption->setMaxLength(kMaxMessageLength);
connect(_caption, &Ui::InputField::resized, [=] {
_caption->heightChanges(
) | rpl::start_with_next([=] {
captionResized();
});
connect(_caption, &Ui::InputField::submitted, [=](
Qt::KeyboardModifiers modifiers) {
}, _caption->lifetime());
_caption->submits(
) | rpl::start_with_next([=](Qt::KeyboardModifiers modifiers) {
const auto ctrlShiftEnter = modifiers.testFlag(Qt::ShiftModifier)
&& (modifiers.testFlag(Qt::ControlModifier)
|| modifiers.testFlag(Qt::MetaModifier));
send({}, ctrlShiftEnter);
});
connect(_caption, &Ui::InputField::cancelled, [=] { closeBox(); });
}, _caption->lifetime());
_caption->cancelled(
) | rpl::start_with_next([=] {
closeBox();
}, _caption->lifetime());
_caption->setMimeDataHook([=](
not_null<const QMimeData*> data,
Ui::InputField::MimeAction action) {

View file

@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/scroll_area.h"
#include "ui/wrap/slide_wrap.h"
@ -144,7 +144,7 @@ void RenameBox(not_null<Ui::GenericBox*> box) {
Core::App().settings().setCustomDeviceModel(result);
Core::App().saveSettingsDelayed();
};
QObject::connect(name, &Ui::InputField::submitted, submit);
name->submits() | rpl::start_with_next(submit, name->lifetime());
box->addButton(tr::lng_settings_save(), submit);
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}

View file

@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h"
#include "ui/widgets/multi_select.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/text/text_options.h"
@ -226,9 +226,8 @@ void ShareBox::prepareCommentField() {
const auto field = _comment->entity();
connect(field, &Ui::InputField::submitted, [=] {
submit({});
});
field->submits(
) | rpl::start_with_next([=] { submit({}); }, field->lifetime());
if (const auto show = uiShow(); show->valid()) {
InitMessageFieldHandlers(
_descriptor.session,
@ -249,6 +248,8 @@ void ShareBox::prepareCommentField() {
void ShareBox::prepare() {
prepareCommentField();
setCloseByOutsideClick(false);
_select->resizeToWidth(st::boxWideWidth);
Ui::SendPendingMoveResizeEvents(_select);

View file

@ -31,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/ripple_animation.h"
#include "ui/effects/slide_animation.h"
#include "ui/widgets/discrete_sliders.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/image/image.h"
#include "ui/cached_round_corners.h"
#include "ui/painter.h"

View file

@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/menu/menu_action.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/effects/ripple_animation.h"
#include "ui/layers/generic_box.h"
#include "ui/painter.h"

View file

@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/call_button.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/tooltip.h"
#include "ui/widgets/rp_window.h"
#include "ui/chat/group_call_bar.h"

View file

@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/text/text_utilities.h"

View file

@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image_prepare.h"
#include "ui/layers/generic_box.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h"
#include "styles/style_calls.h"
#include "styles/style_layers.h"
@ -287,7 +287,7 @@ void EditGroupCallTitleBox(
box->closeBox();
done(result);
};
QObject::connect(input, &Ui::InputField::submitted, submit);
input->submits() | rpl::start_with_next(submit, input->lifetime());
box->addButton(tr::lng_settings_save(), submit);
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}
@ -346,7 +346,7 @@ void AddTitleGroupCallRecordingBox(
box->closeBox();
done(result);
};
QObject::connect(input, &Ui::InputField::submitted, submit);
input->submits() | rpl::start_with_next(submit, input->lifetime());
box->addButton(tr::lng_group_call_recording_start_button(), submit);
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}

View file

@ -41,9 +41,9 @@ inline auto PreviewPath(int i) {
const auto kSets = {
Set{ { 0, 0, 0, "Mac" }, PreviewPath(0) },
Set{ { 1, 1392, 8'184'590, "Android" }, PreviewPath(1) },
Set{ { 2, 1393, 5'413'219, "Twemoji" }, PreviewPath(2) },
Set{ { 3, 1394, 6'967'218, "JoyPixels" }, PreviewPath(3) },
Set{ { 1, 1804, 8'115'639, "Android" }, PreviewPath(1) },
Set{ { 2, 1805, 5'481'197, "Twemoji" }, PreviewPath(2) },
Set{ { 3, 1806, 7'047'594, "JoyPixels" }, PreviewPath(3) },
};
using Loading = MTP::DedicatedLoader::Progress;

View file

@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/ripple_animation.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/inner_dropdown.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/emoji_config.h"
#include "ui/ui_utility.h"
#include "ui/cached_round_corners.h"

View file

@ -31,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/clip/media_clip_reader.h"
#include "ui/widgets/popup_menu.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/text/text_options.h"
#include "ui/image/image.h"
#include "ui/effects/path_shift_gradient.h"

View file

@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/click_handler_types.h"
#include "ui/controls/tabbed_search.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h"
#include "ui/effects/ripple_animation.h"
#include "ui/image/image.h"

View file

@ -190,16 +190,18 @@ void EditLinkBox(
}
};
QObject::connect(text, &Ui::InputField::submitted, [=] {
text->submits(
) | rpl::start_with_next([=] {
url->setFocusFast();
});
QObject::connect(url, &Ui::InputField::submitted, [=] {
}, text->lifetime());
url->submits(
) | rpl::start_with_next([=] {
if (text->getLastText().isEmpty()) {
text->setFocusFast();
} else {
submit();
}
});
}, url->lifetime());
box->setTitle(url->getLastText().isEmpty()
? tr::lng_formatting_link_create_title()
@ -223,8 +225,14 @@ void EditLinkBox(
url->customTab(true);
text->customTab(true);
QObject::connect(url, &Ui::InputField::tabbed, [=] { text->setFocus(); });
QObject::connect(text, &Ui::InputField::tabbed, [=] { url->setFocus(); });
url->tabbed(
) | rpl::start_with_next([=] {
text->setFocus();
}, url->lifetime());
text->tabbed(
) | rpl::start_with_next([=] {
url->setFocus();
}, text->lifetime());
}
TextWithEntities StripSupportHashtag(TextWithEntities text) {
@ -590,7 +598,8 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery(
MessageLinksParser::MessageLinksParser(not_null<Ui::InputField*> field)
: _field(field)
, _timer([=] { parse(); }) {
_connection = QObject::connect(_field, &Ui::InputField::changed, [=] {
_lifetime = _field->changes(
) | rpl::start_with_next([=] {
const auto length = _field->getTextWithTags().text.size();
const auto timeout = (std::abs(length - _lastLength) > 2)
? 0

View file

@ -7,9 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "base/timer.h"
#include "base/qt_connection.h"
#include "chat_helpers/compose/compose_features.h"
#ifndef TDESKTOP_DISABLE_SPELLCHECK
@ -132,7 +131,7 @@ private:
int _lastLength = 0;
bool _disabled = false;
base::Timer _timer;
base::qt_connection _connection;
rpl::lifetime _lifetime;
};

View file

@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lottie/lottie_single_player.h"
#include "ui/dpr/dpr_icon.h"
#include "ui/dpr/dpr_image.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/buttons.h"
#include "ui/painter.h"
#include "ui/rect_part.h"

View file

@ -22,110 +22,6 @@ namespace {
std::map<int, const char*> BetaLogs() {
return {
{
4005004,
"- Allow wide range of interface scale options.\n"
"- Show opened chat name in the window title.\n"
"- Bug fixes and other minor improvements.\n"
"- Fix updating on macOS older than 10.14.\n"
},
{
4005006,
"- Try enabling non-fractional scale "
"High DPI support on Windows and Linux.\n"
"- Experimental setting for fractional scale "
"High DPI support on Windows and Linux.\n"
"- Fix navigation to bottom problems in groups you didn't join.\n"
"- Fix a crash in chat export settings changes.\n"
"- Fix a crash in sending some of JPEG images.\n"
"- Fix CJK fonts on Windows.\n"
},
{
4005007,
"- Fix glitches after moving window to another screen.\n",
},
{
4005008,
"- Allow opening another account in a new window "
"(see Settings > Advanced > Experimental Settings).\n"
"- A lot of bugfixes for working with more than one window.\n"
},
{
4006004,
"- Allow media viewer to exit fullscreen and become a normal window."
},
{
4006006,
"- Confirmation window before starting a call.\n"
"- New \"Battery and Animations\" settings section.\n"
"- \"Save Power on Low Battery\" option for laptops.\n"
"- Improved windowed mode support for media viewer.\n"
"- Hardware accelerated video playback fix on macOS.\n"
"- New application icon on macOS following the system guidelines.\n"
},
{
4006007,
"- Fix crash when accepting incoming calls.\n"
"- Remove sound when cancelling an unconfirmed call.\n"
},
{
4006008,
"- Improve quality of voice messages with changed playback speed.\n"
"- Show when your message was read in small groups.\n"
"- Fix pasting images from Firefox on Windows.\n"
"- Improve memory usage for custom emoji.\n"
},
{
4006010,
"- Suggest sending an invite link if user forbids "
"inviting him to groups.\n"
"- Show when a reaction was left on your message in small groups.\n"
"- Fix a crash in video chats on Windows.\n"
"- Fix a crash in audio speed change.\n"
},
{
4006011,
"- Allow larger interface scale values on high-dpi screens.\n"
"- Implement new voice and video speed change interface (up to 2.5x).\n"
"- Support global Fn+F shortcut to toggle fullscreen on macOS.\n"
"- Silent notification sound in Focus Mode on macOS.\n"
"- Fix media viewer on macOS with several screens.\n"
"- Fix a crash in connection type box.\n"
"- Fix possible crash on quit.\n"
},
{
4006012,
"- Fix several possible crashes.\n"
"- Deprecate macOS 10.12, Ubuntu 18.04 and CentOS 7 in July.\n"
},
{
4008011,
"- Fix initial video playback speed.\n"

View file

@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/send_files_box.h"
#include "history/view/history_view_quick_action.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "storage/serialize_common.h"
#include "window/section_widget.h"
#include "base/platform/base_platform_info.h"

View file

@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <new>
#include <mutex>
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
#ifdef Q_OS_WIN
#include <new.h>
@ -25,7 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <client/windows/handler/exception_handler.h>
#pragma warning(pop)
#elif defined Q_OS_UNIX // Q_OS_WIN
#else // Q_OS_WIN
#include <execinfo.h>
#include <sys/syscall.h>
@ -48,7 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#endif // Q_OS_MAC
#endif // Q_OS_WIN
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
namespace CrashReports {
namespace {
@ -59,7 +59,7 @@ using AnnotationRefs = std::map<std::string, const QString*>;
Annotations ProcessAnnotations;
AnnotationRefs ProcessAnnotationRefs;
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
QString ReportPath;
FILE *ReportFile = nullptr;
@ -197,13 +197,15 @@ const int HandledSignals[] = {
SIGABRT,
SIGFPE,
SIGILL,
#ifdef Q_OS_UNIX
#ifndef Q_OS_WIN
SIGBUS,
SIGTRAP,
#endif // Q_OS_UNIX
#endif // !Q_OS_WIN
};
#ifdef Q_OS_UNIX
#ifdef Q_OS_WIN
void SignalHandler(int signum) {
#else // Q_OS_WIN
struct sigaction OldSigActions[32]/* = { 0 }*/;
void RestoreSignalHandlers() {
@ -229,9 +231,7 @@ void InvokeOldSignalHandler(int signum, siginfo_t *info, void *ucontext) {
void SignalHandler(int signum, siginfo_t *info, void *ucontext) {
RestoreSignalHandlers();
#else // Q_OS_UNIX
void SignalHandler(int signum) {
#endif // else for Q_OS_UNIX
#endif // else for Q_OS_WIN
const char* name = 0;
switch (signum) {
@ -253,9 +253,9 @@ void SignalHandler(int signum) {
ReportingThreadId = nullptr;
}
#ifdef Q_OS_UNIX
#ifndef Q_OS_WIN
InvokeOldSignalHandler(signum, info, ucontext);
#endif // Q_OS_UNIX
#endif // !Q_OS_WIN
}
bool SetSignalHandlers = true;
@ -267,9 +267,9 @@ google_breakpad::ExceptionHandler* BreakpadExceptionHandler = 0;
bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success)
#elif defined Q_OS_MAC // Q_OS_WIN
bool DumpCallback(const char* _dump_dir, const char* _minidump_id, void *context, bool success)
#elif defined Q_OS_UNIX // Q_OS_MAC
#else // Q_OS_MAC
bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success)
#endif // Q_OS_UNIX
#endif // else for Q_OS_WIN || Q_OS_MAC
{
if (CrashLogged) return success;
CrashLogged = true;
@ -290,7 +290,7 @@ bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context,
}
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
} // namespace
@ -314,7 +314,7 @@ QString PlatformString() {
}
void StartCatching() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
ProcessAnnotations["Binary"] = cExeName().toUtf8().constData();
ProcessAnnotations["ApiId"] = QString::number(ApiId).toUtf8().constData();
ProcessAnnotations["Version"] = (cAlphaVersion()
@ -370,7 +370,7 @@ void StartCatching() {
false)) { // asynchronous_start
}
#endif // else for MAC_USE_BREAKPAD
#elif defined Q_OS_UNIX
#else
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
google_breakpad::MinidumpDescriptor(QFile::encodeName(dumpspath).toStdString()),
/*FilterCallback*/ 0,
@ -379,22 +379,22 @@ void StartCatching() {
true,
-1
);
#endif // Q_OS_UNIX
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // else for Q_OS_WIN || Q_OS_MAC
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
}
void FinishCatching() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
#if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
delete base::take(BreakpadExceptionHandler);
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
}
StartResult Start() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
ReportPath = cWorkingDir() + u"tdata/working"_q;
#ifdef Q_OS_WIN
@ -420,12 +420,12 @@ StartResult Start() {
return lastdump;
}
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
return Restart();
}
Status Restart() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
if (ReportFile) {
return Started;
}
@ -470,13 +470,13 @@ Status Restart() {
LOG(("FATAL: Could not open '%1' for writing!").arg(ReportPath));
return CantOpen;
#else // !DESKTOP_APP_DISABLE_CRASH_REPORTS
#else // !TDESKTOP_DISABLE_CRASH_REPORTS
return Started;
#endif // else for !DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // else for !TDESKTOP_DISABLE_CRASH_REPORTS
}
void Finish() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
FinishCatching();
if (ReportFile) {
@ -489,7 +489,7 @@ void Finish() {
unlink(ReportPath.toUtf8().constData());
#endif // else for Q_OS_WIN
}
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
}
void SetAnnotation(const std::string &key, const QString &value) {
@ -539,7 +539,7 @@ void SetAnnotationRef(const std::string &key, const QString *valuePtr) {
}
}
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
dump::~dump() {
if (ReportFile) {
@ -604,6 +604,6 @@ const dump &operator<<(const dump &stream, double num) {
return stream;
}
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // TDESKTOP_DISABLE_CRASH_REPORTS
} // namespace CrashReports

View file

@ -11,7 +11,7 @@ namespace CrashReports {
QString PlatformString();
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
struct dump {
~dump();
@ -24,7 +24,7 @@ const dump &operator<<(const dump &stream, unsigned long num);
const dump &operator<<(const dump &stream, unsigned long long num);
const dump &operator<<(const dump &stream, double num);
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS
#endif // TDESKTOP_DISABLE_CRASH_REPORTS
enum Status {
CantOpen,

View file

@ -0,0 +1,83 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Core::DeadlockDetector {
class PingPongEvent : public QEvent {
public:
static auto Type() {
static const auto Result = QEvent::Type(QEvent::registerEventType());
return Result;
}
PingPongEvent(not_null<QObject*> sender)
: QEvent(Type())
, _sender(sender) {
}
[[nodiscard]] not_null<QObject*> sender() const {
return _sender;
}
private:
not_null<QObject*> _sender;
};
class Pinger : public QObject {
public:
Pinger(not_null<QObject*> receiver)
: _receiver(receiver)
, _abortTimer([] { Unexpected("Deadlock found!"); }) {
const auto callback = [=] {
QCoreApplication::postEvent(_receiver, new PingPongEvent(this));
_abortTimer.callOnce(30000);
};
_pingTimer.setCallback(callback);
_pingTimer.callEach(60000);
callback();
}
protected:
bool event(QEvent *e) override {
if (e->type() == PingPongEvent::Type()
&& static_cast<PingPongEvent*>(e)->sender() == _receiver) {
_abortTimer.cancel();
}
return QObject::event(e);
}
private:
not_null<QObject*> _receiver;
base::Timer _pingTimer;
base::Timer _abortTimer;
};
class PingThread : public QThread {
public:
PingThread(not_null<QObject*> parent)
: QThread(parent) {
start();
}
~PingThread() {
quit();
wait();
}
protected:
void run() override {
Pinger pinger(parent());
QThread::run();
}
};
} // namespace Core::DeadlockDetector

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/options.h"
#include <QtCore/QLoggingCategory>
#include <QtCore/QStandardPaths>
namespace Core {
namespace {
@ -115,16 +116,26 @@ void ComputeDebugMode() {
}
void ComputeExternalUpdater() {
QFile file(u"/etc/tdesktop/externalupdater"_q);
if (file.exists() && file.open(QIODevice::ReadOnly)) {
QTextStream fileStream(&file);
while (!fileStream.atEnd()) {
const auto path = fileStream.readLine();
if (path == (cExeDir() + cExeName())) {
SetUpdaterDisabledAtStartup();
return;
auto locations = QStandardPaths::standardLocations(
QStandardPaths::AppDataLocation);
if (locations.isEmpty()) {
locations << QString();
}
locations[0] = QDir::cleanPath(cWorkingDir());
locations << QDir::cleanPath(cExeDir());
for (const auto &location : locations) {
const auto dir = location + u"/externalupdater.d"_q;
for (const auto &info : QDir(dir).entryInfoList(QDir::Files)) {
QFile file(info.absoluteFilePath());
if (file.open(QIODevice::ReadOnly)) {
QTextStream fileStream(&file);
while (!fileStream.atEnd()) {
const auto path = fileStream.readLine();
if (path == (cExeDir() + cExeName())) {
SetUpdaterDisabledAtStartup();
return;
}
}
}
}
}
@ -223,7 +234,7 @@ bool CheckPortableVersionFolder() {
if (cAlphaVersion()) {
Assert(*AlphaPrivateKey != 0);
cForceWorkingDir(portable + '/');
cForceWorkingDir(portable);
QDir().mkpath(cWorkingDir() + u"tdata"_q);
cSetAlphaPrivateKey(QByteArray(AlphaPrivateKey));
if (!key.open(QIODevice::WriteOnly)) {
@ -239,7 +250,7 @@ bool CheckPortableVersionFolder() {
if (!QDir(portable).exists()) {
return true;
}
cForceWorkingDir(portable + '/');
cForceWorkingDir(portable);
if (!key.exists()) {
return true;
}
@ -291,7 +302,8 @@ Launcher::Launcher(int argc, char *argv[])
: _argc(argc)
, _argv(argv)
, _arguments(readArguments(_argc, _argv))
, _baseIntegration(_argc, _argv) {
, _baseIntegration(_argc, _argv)
, _initialWorkingDir(QDir::currentPath() + '/') {
crl::toggle_fp_exceptions(true);
base::Integration::Set(&_baseIntegration);
@ -446,6 +458,10 @@ const QStringList &Launcher::arguments() const {
return _arguments;
}
QString Launcher::initialWorkingDir() const {
return _initialWorkingDir;
}
bool Launcher::customWorkingDir() const {
return !_customWorkingDir.isEmpty();
}

View file

@ -29,6 +29,7 @@ public:
virtual int exec();
const QStringList &arguments() const;
QString initialWorkingDir() const;
bool customWorkingDir() const;
uint64 installationTag() const;
@ -84,6 +85,7 @@ private:
QStringList _arguments;
BaseIntegration _baseIntegration;
QString _initialWorkingDir;
QString _customWorkingDir;
};

View file

@ -378,6 +378,8 @@ bool ResolveUsernameOrPhone(
startToken = params.value(u"startgroup"_q);
} else if (params.contains(u"startchannel"_q)) {
resolveType = ResolveType::AddToChannel;
} else if (params.contains(u"boost"_q)) {
resolveType = ResolveType::Boost;
}
auto post = ShowAtUnreadMsgId;
auto adminRights = ChatAdminRights();
@ -392,7 +394,6 @@ bool ResolveUsernameOrPhone(
const auto storyParam = params.value(u"story"_q);
const auto storyId = storyParam.toInt();
const auto appname = webChannelPreviewLink ? QString() : appnameParam;
const auto appstart = params.value(u"startapp"_q);
const auto commentParam = params.value(u"comment"_q);
const auto commentId = commentParam.toInt();
const auto topicParam = params.value(u"topic"_q);
@ -404,11 +405,11 @@ bool ResolveUsernameOrPhone(
startToken = gameParam;
resolveType = ResolveType::ShareGame;
}
if (startToken.isEmpty() && params.contains(u"startapp"_q)) {
startToken = params.value(u"startapp"_q);
}
if (!appname.isEmpty()) {
resolveType = ResolveType::BotApp;
if (startToken.isEmpty() && params.contains(u"startapp"_q)) {
startToken = params.value(u"startapp"_q);
}
}
const auto myContext = context.value<ClickHandlerContext>();
using Navigation = Window::SessionNavigation;
@ -436,7 +437,11 @@ bool ResolveUsernameOrPhone(
.attachBotUsername = params.value(u"attach"_q),
.attachBotToggleCommand = (params.contains(u"startattach"_q)
? params.value(u"startattach"_q)
: (appname.isEmpty() && params.contains(u"startapp"_q))
? params.value(u"startapp"_q)
: std::optional<QString>()),
.attachBotMenuOpen = (appname.isEmpty()
&& params.contains(u"startapp"_q)),
.attachBotChooseTypes = InlineBots::ParseChooseTypes(
params.value(u"choose"_q)),
.voicechatHash = (params.contains(u"livestream"_q)
@ -839,6 +844,32 @@ bool ResolveLoginCode(
return true;
}
bool ResolveBoost(
Window::SessionController *controller,
const Match &match,
const QVariant &context) {
if (!controller) {
return false;
}
const auto params = url_parse_params(
match->captured(1),
qthelp::UrlParamNameTransform::ToLower);
const auto domainParam = params.value(u"domain"_q);
const auto channelParam = params.value(u"channel"_q);
const auto myContext = context.value<ClickHandlerContext>();
using Navigation = Window::SessionNavigation;
controller->window().activate();
controller->showPeerByLink(Navigation::PeerByLinkInfo{
.usernameOrId = (!domainParam.isEmpty()
? std::variant<QString, ChannelId>(domainParam)
: ChannelId(BareId(channelParam.toULongLong()))),
.resolveType = Window::ResolveType::Boost,
.clickFromMessageId = myContext.itemId,
});
return true;
}
} // namespace
const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
@ -919,6 +950,10 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
u"^login/?(\\?code=([0-9]+))(&|$)"_q,
ResolveLoginCode
},
{
u"^boost/?\\?(.+)(#|$)"_q,
ResolveBoost,
},
{
u"^([^\\?]+)(\\?|#|$)"_q,
HandleUnknown
@ -1022,8 +1057,13 @@ QString TryConvertUrlToLocal(QString url) {
"/\\d+/?(\\?|$)|"
"/\\d+/\\d+/?(\\?|$)"
")"_q, query, matchOptions)) {
const auto channel = privateMatch->captured(1);
const auto params = query.mid(privateMatch->captured(0).size()).toString();
const auto base = u"tg://privatepost?channel="_q + privateMatch->captured(1);
if (params.indexOf("boost", 0, Qt::CaseInsensitive) >= 0
&& params.toLower().split('&').contains(u"boost"_q)) {
return u"tg://boost?channel="_q + channel;
}
const auto base = u"tg://privatepost?channel="_q + channel;
auto added = QString();
if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, privateMatch->captured(2))) {
added = u"&topic=%1&post=%2"_q.arg(threadPostMatch->captured(1)).arg(threadPostMatch->captured(2));
@ -1041,7 +1081,12 @@ QString TryConvertUrlToLocal(QString url) {
"/s/\\d+/?(\\?|$)|"
"/\\d+/\\d+/?(\\?|$)"
")"_q, query, matchOptions)) {
const auto domain = usernameMatch->captured(1);
const auto params = query.mid(usernameMatch->captured(0).size()).toString();
if (params.indexOf("boost", 0, Qt::CaseInsensitive) >= 0
&& params.toLower().split('&').contains(u"boost"_q)) {
return u"tg://boost?domain="_q + domain;
}
const auto base = u"tg://resolve?domain="_q + url_encode(usernameMatch->captured(1));
auto added = QString();
if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) {

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/launcher.h"
#include "core/local_url_handlers.h"
#include "core/update_checker.h"
#include "core/deadlock_detector.h"
#include "base/timer.h"
#include "base/concurrent_timer.h"
#include "base/invoke_queued.h"
@ -202,6 +203,13 @@ void Sandbox::launchApplication() {
}
setupScreenScale();
#ifndef _DEBUG
if (Logs::DebugEnabled()) {
using DeadlockDetector::PingThread;
_deadlockDetector = std::make_unique<PingThread>(this);
}
#endif // !_DEBUG
_application = std::make_unique<Application>();
// Ideally this should go to constructor.
@ -271,6 +279,10 @@ bool Sandbox::event(QEvent *e) {
return false;
} else if (e->type() == QEvent::Close) {
Quit();
} else if (e->type() == DeadlockDetector::PingPongEvent::Type()) {
postEvent(
static_cast<DeadlockDetector::PingPongEvent*>(e)->sender(),
new DeadlockDetector::PingPongEvent(this));
}
return QApplication::event(e);
}

View file

@ -131,6 +131,8 @@ private:
rpl::event_stream<> _widgetUpdateRequests;
std::unique_ptr<QThread> _deadlockDetector;
};
} // namespace Core

View file

@ -370,7 +370,6 @@ QString UiIntegration::phrasePanelCloseAnyway() {
return tr::lng_bot_close_warning_sure(tr::now);
}
#if 0 // disabled for now
QString UiIntegration::phraseBotSharePhone() {
return tr::lng_bot_share_phone(tr::now);
}
@ -382,7 +381,18 @@ QString UiIntegration::phraseBotSharePhoneTitle() {
QString UiIntegration::phraseBotSharePhoneConfirm() {
return tr::lng_bot_share_phone_confirm(tr::now);
}
#endif
QString UiIntegration::phraseBotAllowWrite() {
return tr::lng_bot_allow_write(tr::now);
}
QString UiIntegration::phraseBotAllowWriteTitle() {
return tr::lng_bot_allow_write_title(tr::now);
}
QString UiIntegration::phraseBotAllowWriteConfirm() {
return tr::lng_bot_allow_write_confirm(tr::now);
}
bool OpenGLLastCheckFailed() {
return QFile::exists(OpenGLCheckFilePath());

View file

@ -84,11 +84,12 @@ public:
QString phrasePanelCloseWarning() override;
QString phrasePanelCloseUnsaved() override;
QString phrasePanelCloseAnyway() override;
#if 0 // disabled for now
QString phraseBotSharePhone() override;
QString phraseBotSharePhoneTitle() override;
QString phraseBotSharePhoneConfirm() override;
#endif
QString phraseBotAllowWrite() override;
QString phraseBotAllowWriteTitle() override;
QString phraseBotAllowWriteConfirm() override;
};

View file

@ -42,16 +42,16 @@ extern "C" {
} // extern "C"
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
#include <LzmaLib.h>
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
#else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
#include <lzma.h>
#endif // else of Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
#endif // else of Q_OS_WIN && !TDESKTOP_USE_PACKAGED
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
#ifdef Q_OS_UNIX
#ifndef Q_OS_WIN
#include <unistd.h>
#endif // Q_OS_UNIX
#endif // !Q_OS_WIN
namespace Core {
namespace {
@ -275,11 +275,11 @@ bool UnpackUpdate(const QString &filepath) {
return false;
}
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
#else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header
#endif // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
#endif // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
QByteArray compressed = input.readAll();
int32 compressedLen = compressed.size() - hSize;
@ -330,14 +330,14 @@ bool UnpackUpdate(const QString &filepath) {
uncompressed.resize(uncompressedLen);
size_t resultLen = uncompressed.size();
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
SizeT srcLen = compressedLen;
int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
if (uncompressRes != SZ_OK) {
LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
return false;
}
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
#else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
lzma_stream stream = LZMA_STREAM_INIT;
lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED);
@ -380,7 +380,7 @@ bool UnpackUpdate(const QString &filepath) {
LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res));
return false;
}
#endif // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
#endif // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
tempDir.mkdir(tempDir.absolutePath());
@ -428,9 +428,9 @@ bool UnpackUpdate(const QString &filepath) {
bool executable = false;
stream >> relativeName >> fileSize >> fileInnerData;
#ifdef Q_OS_UNIX
#ifndef Q_OS_WIN
stream >> executable;
#endif // Q_OS_UNIX
#endif // !Q_OS_WIN
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status()));
return false;
@ -1539,10 +1539,10 @@ bool checkReadyUpdate() {
#elif defined Q_OS_MAC // Q_OS_WIN
QString curUpdater = (cExeDir() + cExeName() + u"/Contents/Frameworks/Updater"_q);
QFileInfo updater(cWorkingDir() + u"tupdates/temp/Telegram.app/Contents/Frameworks/Updater"_q);
#elif defined Q_OS_UNIX // Q_OS_MAC
#else // Q_OS_MAC
QString curUpdater = (cExeDir() + u"Updater"_q);
QFileInfo updater(cWorkingDir() + u"tupdates/temp/Updater"_q);
#endif // Q_OS_UNIX
#endif // else for Q_OS_WIN || Q_OS_MAC
if (!updater.exists()) {
QFileInfo current(curUpdater);
if (!current.exists()) {
@ -1576,7 +1576,7 @@ bool checkReadyUpdate() {
ClearAll();
return false;
}
#elif defined Q_OS_UNIX // Q_OS_MAC
#else // Q_OS_MAC
// if the files in the directory are owned by user, while the directory is not,
// update will still fail since it's not possible to remove files
if (QFile::exists(curUpdater)
@ -1604,7 +1604,7 @@ bool checkReadyUpdate() {
return false;
}
}
#endif // Q_OS_UNIX
#endif // else for Q_OS_WIN || Q_OS_MAC
#ifdef Q_OS_MAC
base::Platform::RemoveQuarantine(QFileInfo(curUpdater).absolutePath());

View file

@ -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 = 4009004;
constexpr auto AppVersionStr = "4.9.4";
constexpr auto AppVersion = 4010000;
constexpr auto AppVersionStr = "4.10";
constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View file

@ -24,4 +24,5 @@ struct BotAppData {
uint64 accessHash = 0;
uint64 hash = 0;
bool hasSettings = false;
};

View file

@ -221,14 +221,14 @@ struct StoryUpdate {
enum class Flag : uint32 {
None = 0,
Edited = (1U << 0),
Destroyed = (1U << 1),
NewAdded = (1U << 2),
ViewsAdded = (1U << 3),
MarkRead = (1U << 4),
Reaction = (1U << 5),
Edited = (1U << 0),
Destroyed = (1U << 1),
NewAdded = (1U << 2),
ViewsChanged = (1U << 3),
MarkRead = (1U << 4),
Reaction = (1U << 5),
LastUsedBit = (1U << 5),
LastUsedBit = (1U << 5),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_chat.h"
#include "data/data_session.h"
#include "data/data_stories.h"
#include "data/data_folder.h"
#include "data/data_forum.h"
#include "data/data_forum_icons.h"
@ -530,6 +531,11 @@ bool ChannelData::canBanMembers() const {
|| (adminRights() & AdminRight::BanUsers);
}
bool ChannelData::canPostMessages() const {
return amCreator()
|| (adminRights() & AdminRight::PostMessages);
}
bool ChannelData::canEditMessages() const {
return amCreator()
|| (adminRights() & AdminRight::EditMessages);
@ -540,6 +546,30 @@ bool ChannelData::canDeleteMessages() const {
|| (adminRights() & AdminRight::DeleteMessages);
}
bool ChannelData::canPostStories() const {
if (!isBroadcast()) {
return false;
}
return amCreator()
|| (adminRights() & AdminRight::PostStories);
}
bool ChannelData::canEditStories() const {
if (!isBroadcast()) {
return false;
}
return amCreator()
|| (adminRights() & AdminRight::EditStories);
}
bool ChannelData::canDeleteStories() const {
if (!isBroadcast()) {
return false;
}
return amCreator()
|| (adminRights() & AdminRight::DeleteStories);
}
bool ChannelData::anyoneCanAddMembers() const {
return !(defaultRestrictions() & Restriction::AddParticipants);
}
@ -559,11 +589,6 @@ bool ChannelData::canAddAdmins() const {
|| (adminRights() & AdminRight::AddAdmins);
}
bool ChannelData::canPublish() const {
return amCreator()
|| (adminRights() & AdminRight::PostMessages);
}
bool ChannelData::allowsForwarding() const {
return !(flags() & Flag::NoForwards);
}
@ -877,6 +902,38 @@ const Data::AllowedReactions &ChannelData::allowedReactions() const {
return _allowedReactions;
}
bool ChannelData::hasActiveStories() const {
return flags() & Flag::HasActiveStories;
}
bool ChannelData::hasUnreadStories() const {
return flags() & Flag::HasUnreadStories;
}
void ChannelData::setStoriesState(StoriesState state) {
Expects(state != StoriesState::Unknown);
const auto was = flags();
switch (state) {
case StoriesState::None:
_flags.remove(Flag::HasActiveStories | Flag::HasUnreadStories);
break;
case StoriesState::HasRead:
_flags.set(
(flags() & ~Flag::HasUnreadStories) | Flag::HasActiveStories);
break;
case StoriesState::HasUnread:
_flags.add(Flag::HasActiveStories | Flag::HasUnreadStories);
break;
}
if (flags() != was) {
if (const auto history = owner().historyLoaded(this)) {
history->updateChatListEntryPostponed();
}
session().changes().peerUpdated(this, UpdateFlag::StoriesState);
}
}
void ChannelData::processTopics(const MTPVector<MTPForumTopic> &topics) {
if (const auto forum = this->forum()) {
forum->applyReceivedTopics(topics);
@ -1046,6 +1103,7 @@ void ApplyChannelUpdate(
} else {
channel->setAllowedReactions({});
}
channel->owner().stories().apply(channel, update.vstories());
channel->fullUpdated();
channel->setPendingRequestsCount(
update.vrequests_pending().value_or_empty(),

View file

@ -59,6 +59,9 @@ enum class ChannelDataFlag {
Forum = (1 << 23),
AntiSpam = (1 << 24),
ParticipantsHidden = (1 << 25),
StoriesHidden = (1 << 26),
HasActiveStories = (1 << 27),
HasUnreadStories = (1 << 28),
};
inline constexpr bool is_flag_type(ChannelDataFlag) { return true; };
using ChannelDataFlags = base::flags<ChannelDataFlag>;
@ -226,6 +229,9 @@ public:
[[nodiscard]] bool isFake() const {
return flags() & Flag::Fake;
}
[[nodiscard]] bool hasStoriesHidden() const {
return flags() & Flag::StoriesHidden;
}
[[nodiscard]] static ChatRestrictionsInfo KickedRestrictedRights(
not_null<PeerData*> participant);
@ -329,10 +335,13 @@ public:
[[nodiscard]] bool canBanMembers() const;
[[nodiscard]] bool anyoneCanAddMembers() const;
[[nodiscard]] bool canPostMessages() const;
[[nodiscard]] bool canEditMessages() const;
[[nodiscard]] bool canDeleteMessages() const;
[[nodiscard]] bool canPostStories() const;
[[nodiscard]] bool canEditStories() const;
[[nodiscard]] bool canDeleteStories() const;
[[nodiscard]] bool hiddenPreHistory() const;
[[nodiscard]] bool canPublish() const;
[[nodiscard]] bool canViewMembers() const;
[[nodiscard]] bool canViewAdmins() const;
[[nodiscard]] bool canViewBanned() const;
@ -437,6 +446,10 @@ public:
void setAllowedReactions(Data::AllowedReactions value);
[[nodiscard]] const Data::AllowedReactions &allowedReactions() const;
[[nodiscard]] bool hasActiveStories() const;
[[nodiscard]] bool hasUnreadStories() const;
void setStoriesState(StoriesState state);
[[nodiscard]] Data::Forum *forum() const {
return mgInfo ? mgInfo->forum() : nullptr;
}

View file

@ -146,7 +146,7 @@ bool CanSendAnyOf(
&& !(channel->flags() & Flag::JoinToWrite));
if (!allowed || (forbidInForums && channel->isForum())) {
return false;
} else if (channel->canPublish()) {
} else if (channel->canPostMessages()) {
return true;
} else if (channel->isBroadcast()) {
return false;

View file

@ -25,6 +25,9 @@ enum class ChatAdminRight {
ManageCall = (1 << 11),
Other = (1 << 12),
ManageTopics = (1 << 13),
PostStories = (1 << 14),
EditStories = (1 << 15),
DeleteStories = (1 << 16),
};
inline constexpr bool is_flag_type(ChatAdminRight) { return true; }
using ChatAdminRights = base::flags<ChatAdminRight>;

View file

@ -159,14 +159,7 @@ wv xm xml ym yuv").split(' ');
bool IsExecutableName(const QString &filepath) {
static const auto kExtensions = [] {
const auto joined =
#ifdef Q_OS_MAC
u"\
applescript action app bin command csh osx workflow terminal url caction \
mpkg pkg scpt scptd xhtm webarchive"_q;
#elif defined Q_OS_UNIX // Q_OS_MAC
u"bin csh deb desktop ksh out pet pkg pup rpm run sh shar \
slp zsh"_q;
#else // Q_OS_MAC || Q_OS_UNIX
#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 \
@ -179,7 +172,14 @@ 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;
#endif // !Q_OS_MAC && !Q_OS_UNIX
#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());
}();

View file

@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_drafts.h"
#include "api/api_text_entities.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "chat_helpers/message_field.h"
#include "history/history.h"
#include "history/history_widget.h"

View file

@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "core/application.h"
#include "ui/layers/generic_box.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/fields/input_field.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "window/window_session_controller.h"

View file

@ -73,7 +73,7 @@ struct FullReplyTo {
FullStoryId storyId;
[[nodiscard]] bool valid() const {
return msgId || storyId;
return msgId || (storyId && peerIsUser(storyId.peer));
}
explicit operator bool() const {
return valid();

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