Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f668c8d5ac | |||
| ef60e12f19 | |||
| 96461b91c5 | |||
| f955db2c2c | |||
| 649e0b0412 | |||
| dff168c62e | |||
| b39bf11d9e | |||
| ca9feab071 | |||
| 8e8719870a | |||
| d8f53d5f60 | |||
| f10da51517 | |||
| 3dc0e3818b | |||
| 1493b23574 | |||
| 70e298cfe4 | |||
| 9d4b8bb9b0 | |||
| 089432be5e | |||
| 4b503ad7ed | |||
| aeb593dd77 | |||
| 0d4a83ea47 | |||
| 7fe6ca1f41 | |||
| 95b26911e0 | |||
| 4c2be58dd3 | |||
| 374e95de31 | |||
| ae52c833c5 | |||
| cfe3285e68 | |||
| 7b184e553b | |||
| 5c5276d133 | |||
| 02e37ab2f2 | |||
| 48206bcf95 | |||
| d0eb7ec522 | |||
| e9d9e8df49 | |||
| c226311126 | |||
| 77c2e12ebc | |||
| a479fcd55c | |||
| 396635fa1d | |||
| 4755be4ace | |||
| 1148a2e144 | |||
| 827e755552 | |||
| b80f5f9706 | |||
| 518f0e22cd | |||
| 610e0e7913 |
@@ -50,6 +50,7 @@ If you enjoy using **AyuGram** and want to send us a tip, here's how you can do
|
||||
- [Telegram Desktop](https://github.com/telegramdesktop/tdesktop)
|
||||
- [Kotatogram](https://github.com/kotatogram/kotatogram-desktop)
|
||||
- [64Gram](https://github.com/TDesktop-x64/tdesktop)
|
||||
- [Forkgram](https://github.com/forkgram/tdesktop)
|
||||
- [SQLite](https://github.com/sqlite/sqlite)
|
||||
- [sqlite_orm](https://github.com/fnc12/sqlite_orm)
|
||||
|
||||
|
||||
@@ -102,8 +102,16 @@ PRIVATE
|
||||
ayu/ayu_lang.cpp
|
||||
ayu/ayu_lang.h
|
||||
ayu/ayu_constants.h
|
||||
ayu/utils/telegram_helpers.cpp
|
||||
ayu/utils/telegram_helpers.h
|
||||
ayu/ui/ayu_lottie.cpp
|
||||
ayu/ui/ayu_lottie.h
|
||||
ayu/ui/ayu_assets.cpp
|
||||
ayu/ui/ayu_assets.h
|
||||
ayu/ui/utils/ayu_profile_values.cpp
|
||||
ayu/ui/utils/ayu_profile_values.h
|
||||
ayu/ui/settings/icon_picker.cpp
|
||||
ayu/ui/settings/icon_picker.h
|
||||
ayu/ui/settings/settings_ayu.cpp
|
||||
ayu/ui/settings/settings_ayu.h
|
||||
ayu/ui/context_menu/context_menu.cpp
|
||||
@@ -124,8 +132,6 @@ PRIVATE
|
||||
ayu/sync/utils/ayu_pipe_wrapper.cpp
|
||||
ayu/sync/utils/ayu_pipe_wrapper.h
|
||||
ayu/sync/utils/process_utils.hpp
|
||||
ayu/sync/utils/telegram_helpers.cpp
|
||||
ayu/sync/utils/telegram_helpers.h
|
||||
ayu/messages/ayu_messages_controller.cpp
|
||||
ayu/messages/ayu_messages_controller.h
|
||||
ayu/libs/pipe.hpp
|
||||
@@ -135,6 +141,9 @@ PRIVATE
|
||||
ayu/libs/sqlite/sqlite3.c
|
||||
ayu/libs/sqlite/sqlite3.h
|
||||
ayu/libs/sqlite/sqlite_orm.h
|
||||
ayu/features/streamer_mode/streamer_mode_windows.cpp
|
||||
ayu/features/streamer_mode/streamer_mode_linux.cpp
|
||||
ayu/features/streamer_mode/streamer_mode.h
|
||||
ayu/database/entities.h
|
||||
ayu/database/ayu_database.cpp
|
||||
ayu/database/ayu_database.h
|
||||
@@ -1305,6 +1314,8 @@ PRIVATE
|
||||
settings/settings_main.h
|
||||
settings/settings_notifications.cpp
|
||||
settings/settings_notifications.h
|
||||
settings/settings_notifications_type.cpp
|
||||
settings/settings_notifications_type.h
|
||||
settings/settings_power_saving.cpp
|
||||
settings/settings_power_saving.h
|
||||
settings/settings_premium.cpp
|
||||
@@ -1509,6 +1520,8 @@ endif()
|
||||
|
||||
nice_target_sources(Telegram ${res_loc}
|
||||
PRIVATE
|
||||
qrc/ayu/ayu.qrc
|
||||
|
||||
qrc/emoji_1.qrc
|
||||
qrc/emoji_2.qrc
|
||||
qrc/emoji_3.qrc
|
||||
@@ -1812,13 +1825,13 @@ if (LINUX AND DESKTOP_APP_USE_PACKAGED)
|
||||
configure_file("../lib/xdg/ayugram.desktop.metainfo.xml" "${CMAKE_CURRENT_BINARY_DIR}/ayugram.desktop.metainfo.xml" @ONLY)
|
||||
generate_appdata_changelog(Telegram "${CMAKE_SOURCE_DIR}/changelog.txt" "${CMAKE_CURRENT_BINARY_DIR}/ayugram.desktop.metainfo.xml")
|
||||
install(TARGETS Telegram RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
install(FILES "Resources/art/icon16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "ayugram.png")
|
||||
install(FILES "Resources/art/icon32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "ayugram.png")
|
||||
install(FILES "Resources/art/icon48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "ayugram.png")
|
||||
install(FILES "Resources/art/icon64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "ayugram.png")
|
||||
install(FILES "Resources/art/icon128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "ayugram.png")
|
||||
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "ayugram.png")
|
||||
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "ayugram.png")
|
||||
install(FILES "../lib/xdg/ayugram.desktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ayugram.desktop.service" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/dbus-1/services")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ayugram.desktop.metainfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
|
||||
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 832 B |
|
Before Width: | Height: | Size: 921 B After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 921 B After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 583 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 337 B |
|
After Width: | Height: | Size: 527 B |
|
After Width: | Height: | Size: 772 B |
|
After Width: | Height: | Size: 563 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
@@ -451,6 +451,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_show_from" = "Show notifications from";
|
||||
"lng_settings_notify_all" = "All accounts";
|
||||
"lng_settings_notify_all_about" = "Turn this off if you want to receive notifications only from the account you are currently using.";
|
||||
"lng_settings_notify_global" = "Global settings";
|
||||
"lng_settings_notify_title" = "Notifications for chats";
|
||||
"lng_settings_desktop_notify" = "Desktop notifications";
|
||||
"lng_settings_native_title" = "Native notifications";
|
||||
@@ -458,8 +459,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_use_native_notifications" = "Use native notifications";
|
||||
"lng_settings_notifications_position" = "Location on the screen";
|
||||
"lng_settings_notifications_count" = "Notifications count";
|
||||
"lng_settings_sound_notify" = "Play sound";
|
||||
"lng_settings_sound_notify_off" = "Off";
|
||||
"lng_settings_sound_allowed" = "Allow sound";
|
||||
"lng_settings_alert_windows" = "Flash the taskbar icon";
|
||||
"lng_settings_alert_mac" = "Bounce the dock icon";
|
||||
"lng_settings_alert_linux" = "Draw attention to the window";
|
||||
@@ -480,6 +480,36 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_notification_hide_all" = "Hide all";
|
||||
"lng_notification_sample" = "This is a sample notification";
|
||||
"lng_notification_reminder" = "Reminder";
|
||||
"lng_notification_private_chats" = "Private chats";
|
||||
"lng_notification_groups" = "Groups";
|
||||
"lng_notification_channels" = "Channels";
|
||||
"lng_notification_click_to_change" = "Click here to change";
|
||||
"lng_notification_on" = "On, {exceptions}";
|
||||
"lng_notification_off" = "Off, {exceptions}";
|
||||
"lng_notification_exceptions#one" = "{count} exception";
|
||||
"lng_notification_exceptions#other" = "{count} exceptions";
|
||||
"lng_notification_exceptions_title" = "Exceptions";
|
||||
"lng_notification_title_private_chats" = "Notifications for private chats";
|
||||
"lng_notification_about_private_chats#one" = "Please note that **{count} chat** is listed as an exception and won't be affected by this change.";
|
||||
"lng_notification_about_private_chats#other" = "Please note that **{count} chats** are listed as exceptions and won't be affected by this change.";
|
||||
"lng_notification_title_groups" = "Notifications for groups";
|
||||
"lng_notification_about_groups#one" = "Please note that **{count} group** is listed as an exception and won't be affected by this change.";
|
||||
"lng_notification_about_groups#other" = "Please note that **{count} groups** are listed as exceptions and won't be affected by this change.";
|
||||
"lng_notification_title_channels" = "Notifications for channels";
|
||||
"lng_notification_about_channels#one" = "Please note that **{count} channel** is listed as an exception and won't be affected by this change.";
|
||||
"lng_notification_about_channels#other" = "Please note that **{count} channels** are listed as exceptions and won't be affected by this change.";
|
||||
"lng_notification_exceptions_view" = "View exceptions";
|
||||
"lng_notification_enable" = "Enable notifications";
|
||||
"lng_notification_sound" = "Sound";
|
||||
"lng_notification_tone" = "Notification tone";
|
||||
"lng_notification_exceptions_muted" = "Muted";
|
||||
"lng_notification_exceptions_unmuted" = "Unmuted";
|
||||
"lng_notification_exceptions_add" = "Add an exception";
|
||||
"lng_notification_exceptions_clear" = "Delete all exceptions";
|
||||
"lng_notification_exceptions_clear_sure" = "Are you sure you want to delete all exceptions?";
|
||||
"lng_notification_exceptions_clear_button" = "Delete";
|
||||
"lng_notification_exceptions_remove" = "Remove";
|
||||
"lng_notification_context_remove" = "Remove exception";
|
||||
|
||||
"lng_reaction_text" = "{reaction} to your «{text}»";
|
||||
"lng_reaction_notext" = "{reaction} to your message";
|
||||
@@ -4082,10 +4112,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"ayu_AyuSyncStatusTitle" = "Sync status";
|
||||
"ayu_AyuSyncStatusOk" = "connected";
|
||||
"ayu_AyuSyncStatusErrorDisconnected" = "disconnected";
|
||||
"ayu_AyuSyncStatusErrorNotRegistered" = "not registered";
|
||||
"ayu_AyuSyncStatusErrorNoToken" = "no token";
|
||||
"ayu_AyuSyncStatusErrorInvalidToken" = "invalid token";
|
||||
"ayu_AyuSyncStatusErrorNoMVP" = "no MVP";
|
||||
"ayu_AyuSyncServerURL" = "Server URL";
|
||||
"ayu_AyuSyncServerToken" = "Access token";
|
||||
"ayu_AyuSyncEnable" = "Enable synchronization";
|
||||
@@ -4100,6 +4128,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"ayu_AyuSyncRegisterStatusCode" = "Register status code";
|
||||
"ayu_AyuSyncOpenPreferences" = "Open preferences";
|
||||
"ayu_AyuSyncDownloadAgent" = "Download agent";
|
||||
"ayu_IconDefault" = "Default";
|
||||
"ayu_IconAlternative" = "AyuGram Alt";
|
||||
"ayu_IconNothing" = "Nothing";
|
||||
"ayu_WALMode" = "Enable WAL mode";
|
||||
"ayu_ClearAyuDatabase" = "Clear Ayu Database";
|
||||
"ayu_ClearAyuDatabaseNotification" = "AyuGram database cleared";
|
||||
@@ -4110,17 +4141,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"ayu_StickerConfirmation" = "Confirmation when sending stickers";
|
||||
"ayu_GIFConfirmation" = "Confirmation when sending GIFs";
|
||||
"ayu_VoiceConfirmation" = "Confirmation when sending voice messages";
|
||||
"ayu_EnableGhostMode" = "Enable Ghost";
|
||||
"ayu_DisableGhostMode" = "Disable Ghost";
|
||||
"ayu_KillApp" = "Kill App";
|
||||
"ayu_LReadMessages" = "Read on Local";
|
||||
"ayu_SReadMessages" = "Read on Server";
|
||||
"ayu_GhostModeToggle" = "Ghost Mode";
|
||||
"ayu_EnableGhostMode" = "Enable Ghost";
|
||||
"ayu_DisableGhostMode" = "Disable Ghost";
|
||||
"ayu_EnableGhostModeTray" = "Enable Ghost Mode";
|
||||
"ayu_DisableGhostModeTray" = "Disable Ghost Mode";
|
||||
"ayu_GhostModeEnabled" = "Ghost mode turned on";
|
||||
"ayu_GhostModeDisabled" = "Ghost mode turned off";
|
||||
"ayu_StreamerModeToggle" = "Streamer Mode";
|
||||
"ayu_EnableStreamerModeTray" = "Enable Streamer Mode";
|
||||
"ayu_DisableStreamerModeTray" = "Disable Streamer Mode";
|
||||
"ayu_EditsHistoryTitle" = "Edits history";
|
||||
"ayu_EditsHistoryMenuText" = "History";
|
||||
"ayu_ReadUntilMenuText" = "Read until";
|
||||
"ayu_ReadUntilMenuText" = "Read Message";
|
||||
"ayu_DeleteKeepLocally" = "Keep locally";
|
||||
"ayu_BoxActionReset" = "Reset";
|
||||
"ayu_ReadConfirmationBoxQuestion" = "Do you want to read all messages?";
|
||||
@@ -4139,3 +4175,5 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"ayu_ContextCopyCallbackData" = "Copy Callback Data";
|
||||
"ayu_LocalPremiumNotice" = "You're using **local** Telegram Premium.\nIt **won't** give you any benefits, except translator.\n**Enjoy the star near your nickname!**";
|
||||
"ayu_SettingsWatermark" = "AyuGram developed and maintained by Radolyn Labs.";
|
||||
"ayu_UpdateAyuGram" = "Update AyuGram";
|
||||
"ayu_UtilityRestartRequired" = "App will close in 5 seconds.";
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="art/ayu/alt/logo256.png">../../art/ayu/alt/logo256.png</file>
|
||||
<file alias="art/ayu/alt/logo256_no_margin.png">../../art/ayu/alt/logo256_no_margin.png</file>
|
||||
<file alias="art/ayu/nothing/logo256.png">../../art/ayu/nothing/logo256.png</file>
|
||||
<file alias="art/ayu/nothing/logo256_no_margin.png">../../art/ayu/nothing/logo256_no_margin.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="4.9.3.0" />
|
||||
Version="4.9.4.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,9,3,0
|
||||
PRODUCTVERSION 4,9,3,0
|
||||
FILEVERSION 4,9,4,0
|
||||
PRODUCTVERSION 4,9,4,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.3.0"
|
||||
VALUE "FileVersion", "4.9.4.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "4.9.3.0"
|
||||
VALUE "ProductVersion", "4.9.4.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,9,3,0
|
||||
PRODUCTVERSION 4,9,3,0
|
||||
FILEVERSION 4,9,4,0
|
||||
PRODUCTVERSION 4,9,4,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.3.0"
|
||||
VALUE "FileVersion", "4.9.4.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "4.9.3.0"
|
||||
VALUE "ProductVersion", "4.9.4.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -1889,17 +1889,8 @@ void ApiWrap::sendNotifySettingsUpdates() {
|
||||
}
|
||||
const auto &settings = session().data().notifySettings();
|
||||
for (const auto type : base::take(_updateNotifyDefaults)) {
|
||||
const auto input = [&] {
|
||||
switch (type) {
|
||||
case Data::DefaultNotify::User: return MTP_inputNotifyUsers();
|
||||
case Data::DefaultNotify::Group: return MTP_inputNotifyChats();
|
||||
case Data::DefaultNotify::Broadcast:
|
||||
return MTP_inputNotifyBroadcasts();
|
||||
}
|
||||
Unexpected("Default notify type in sendNotifySettingsUpdates");
|
||||
}();
|
||||
request(MTPaccount_UpdateNotifySettings(
|
||||
input,
|
||||
Data::DefaultNotifyToMTP(type),
|
||||
settings.defaultSettings(type).serialize()
|
||||
)).afterDelay(kSmallDelayMs).send();
|
||||
}
|
||||
|
||||
@@ -224,6 +224,16 @@ namespace AyuSettings
|
||||
localPremium = val;
|
||||
}
|
||||
|
||||
void AyuGramSettings::set_copyUsernameAsLink(bool val)
|
||||
{
|
||||
copyUsernameAsLink = val;
|
||||
}
|
||||
|
||||
void AyuGramSettings::set_appIcon(QString val)
|
||||
{
|
||||
appIcon = std::move(val);
|
||||
}
|
||||
|
||||
void AyuGramSettings::set_deletedMark(QString val)
|
||||
{
|
||||
deletedMark = std::move(val);
|
||||
@@ -277,11 +287,6 @@ namespace AyuSettings
|
||||
voiceConfirmation = val;
|
||||
}
|
||||
|
||||
void AyuGramSettings::set_copyUsernameAsLink(bool val)
|
||||
{
|
||||
copyUsernameAsLink = val;
|
||||
}
|
||||
|
||||
bool get_ghostModeEnabled()
|
||||
{
|
||||
return ghostModeEnabled.current();
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
namespace AyuSettings
|
||||
{
|
||||
const auto DEFAULT_ICON = QString("default");
|
||||
const auto ALT_ICON = QString("alt");
|
||||
const auto NOTHING_ICON = QString("nothing");
|
||||
|
||||
class AyuGramSettings
|
||||
{
|
||||
public:
|
||||
@@ -40,6 +44,7 @@ namespace AyuSettings
|
||||
copyUsernameAsLink = true;
|
||||
|
||||
// ~ Customization
|
||||
appIcon = DEFAULT_ICON;
|
||||
deletedMark = "🧹";
|
||||
editedMark = tr::lng_edited(tr::now);
|
||||
recentStickersCount = 20;
|
||||
@@ -74,6 +79,7 @@ namespace AyuSettings
|
||||
bool disableStories;
|
||||
bool localPremium;
|
||||
bool copyUsernameAsLink;
|
||||
QString appIcon;
|
||||
QString deletedMark;
|
||||
QString editedMark;
|
||||
int recentStickersCount;
|
||||
@@ -114,6 +120,8 @@ namespace AyuSettings
|
||||
|
||||
void set_copyUsernameAsLink(bool val);
|
||||
|
||||
void set_appIcon(QString val);
|
||||
|
||||
void set_deletedMark(QString val);
|
||||
|
||||
void set_editedMark(QString val);
|
||||
@@ -150,6 +158,7 @@ namespace AyuSettings
|
||||
disableStories,
|
||||
localPremium,
|
||||
copyUsernameAsLink,
|
||||
appIcon,
|
||||
deletedMark,
|
||||
editedMark,
|
||||
recentStickersCount,
|
||||
@@ -174,7 +183,6 @@ namespace AyuSettings
|
||||
|
||||
rpl::producer<int> get_showPeerIdReactive();
|
||||
|
||||
// computed fields
|
||||
bool get_ghostModeEnabled();
|
||||
|
||||
rpl::producer<bool> get_ghostModeEnabledReactive();
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "entities.h"
|
||||
#include "ayu/libs/sqlite/sqlite_orm.h"
|
||||
#include "ayu/sync/utils/telegram_helpers.h"
|
||||
#include "ayu/utils/telegram_helpers.h"
|
||||
|
||||
using namespace sqlite_orm;
|
||||
auto storage = make_storage(
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace AyuFeatures::StreamerMode
|
||||
{
|
||||
bool isEnabled();
|
||||
void enable();
|
||||
void disable();
|
||||
void hideWidgetWindow(QWidget* widget);
|
||||
void showWidgetWindow(QWidget* widget);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include "streamer_mode.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "window/window_controller.h"
|
||||
|
||||
namespace AyuFeatures::StreamerMode
|
||||
{
|
||||
bool isEnabledVal;
|
||||
|
||||
bool isEnabled()
|
||||
{
|
||||
return isEnabledVal;
|
||||
}
|
||||
|
||||
void enable()
|
||||
{
|
||||
isEnabledVal = true;
|
||||
}
|
||||
|
||||
void disable()
|
||||
{
|
||||
isEnabledVal = false;
|
||||
}
|
||||
|
||||
void hideWidgetWindow(QWidget* widget) {
|
||||
|
||||
}
|
||||
|
||||
void showWidgetWindow(QWidget* widget) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include "streamer_mode.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "window/window_controller.h"
|
||||
|
||||
namespace AyuFeatures::StreamerMode
|
||||
{
|
||||
bool isEnabledVal;
|
||||
|
||||
bool isEnabled()
|
||||
{
|
||||
return isEnabledVal;
|
||||
}
|
||||
|
||||
void enable()
|
||||
{
|
||||
auto handle = Core::App().activeWindow()->widget()->psHwnd();
|
||||
SetWindowDisplayAffinity(handle, WDA_EXCLUDEFROMCAPTURE);
|
||||
|
||||
isEnabledVal = true;
|
||||
}
|
||||
|
||||
void disable()
|
||||
{
|
||||
auto handle = Core::App().activeWindow()->widget()->psHwnd();
|
||||
SetWindowDisplayAffinity(handle, WDA_NONE);
|
||||
|
||||
isEnabledVal = false;
|
||||
}
|
||||
|
||||
void hideWidgetWindow(QWidget* widget)
|
||||
{
|
||||
auto handle = reinterpret_cast<HWND>(widget->window()->winId());
|
||||
SetWindowDisplayAffinity(handle, WDA_EXCLUDEFROMCAPTURE);
|
||||
}
|
||||
|
||||
void showWidgetWindow(QWidget* widget)
|
||||
{
|
||||
auto handle = reinterpret_cast<HWND>(widget->window()->winId());
|
||||
SetWindowDisplayAffinity(handle, WDA_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "ayu/ayu_constants.h"
|
||||
#include "ayu/database/ayu_database.h"
|
||||
#include "ayu/sync/utils/telegram_helpers.h"
|
||||
#include "ayu/utils/telegram_helpers.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "ayu/libs/process.hpp"
|
||||
#include "ayu/sync/models.h"
|
||||
#include "ayu/sync/utils/process_utils.hpp"
|
||||
#include "ayu/sync/utils/telegram_helpers.h"
|
||||
#include "ayu/utils/telegram_helpers.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#include "ayu_assets.h"
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
QString LAST_LOADED_NAME;
|
||||
QImage LAST_LOADED;
|
||||
QImage LAST_LOADED_NO_MARGIN;
|
||||
|
||||
void loadIcons()
|
||||
{
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
if (LAST_LOADED_NAME != settings->appIcon)
|
||||
{
|
||||
LAST_LOADED_NAME = settings->appIcon;
|
||||
if (settings->appIcon == AyuSettings::DEFAULT_ICON)
|
||||
{
|
||||
LAST_LOADED = logo();
|
||||
LAST_LOADED_NO_MARGIN = logoNoMargin();
|
||||
}
|
||||
else if (settings->appIcon == AyuSettings::ALT_ICON)
|
||||
{
|
||||
LAST_LOADED = logoAlt();
|
||||
LAST_LOADED_NO_MARGIN = logoAltNoMargin();
|
||||
}
|
||||
else if (settings->appIcon == AyuSettings::NOTHING_ICON)
|
||||
{
|
||||
LAST_LOADED = logoNothing();
|
||||
LAST_LOADED_NO_MARGIN = logoNothingNoMargin();
|
||||
}
|
||||
else
|
||||
{
|
||||
LAST_LOADED = logo();
|
||||
LAST_LOADED_NO_MARGIN = logoNoMargin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QImage logo()
|
||||
{
|
||||
return QImage(qsl(":/gui/art/logo_256.png"));
|
||||
}
|
||||
|
||||
QImage logoNoMargin()
|
||||
{
|
||||
return QImage(qsl(":/gui/art/logo_256_no_margin.png"));
|
||||
}
|
||||
|
||||
QImage logoAlt()
|
||||
{
|
||||
return QImage(qsl(":/gui/art/ayu/alt/logo256.png"));
|
||||
}
|
||||
|
||||
QImage logoAltNoMargin()
|
||||
{
|
||||
return QImage(qsl(":/gui/art/ayu/alt/logo256_no_margin.png"));
|
||||
}
|
||||
|
||||
QImage logoNothing()
|
||||
{
|
||||
return QImage(qsl(":/gui/art/ayu/nothing/logo256.png"));
|
||||
}
|
||||
|
||||
QImage logoNothingNoMargin()
|
||||
{
|
||||
return QImage(qsl(":/gui/art/ayu/nothing/logo256_no_margin.png"));
|
||||
}
|
||||
|
||||
QString currentAppLogoName()
|
||||
{
|
||||
return LAST_LOADED_NAME;
|
||||
}
|
||||
|
||||
QImage currentAppLogo()
|
||||
{
|
||||
loadIcons();
|
||||
return LAST_LOADED;
|
||||
}
|
||||
|
||||
QImage currentAppLogoNoMargin()
|
||||
{
|
||||
loadIcons();
|
||||
return LAST_LOADED_NO_MARGIN;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#pragma once
|
||||
|
||||
QImage logo();
|
||||
QImage logoNoMargin();
|
||||
|
||||
QImage logoAlt();
|
||||
QImage logoAltNoMargin();
|
||||
|
||||
QImage logoNothing();
|
||||
QImage logoNothingNoMargin();
|
||||
|
||||
QString currentAppLogoName();
|
||||
QImage currentAppLogo();
|
||||
QImage currentAppLogoNoMargin();
|
||||
@@ -1,3 +1,12 @@
|
||||
/*
|
||||
* This is the source code of AyuGram for Desktop.
|
||||
*
|
||||
* We do not and cannot prevent the use of our code,
|
||||
* but be respectful and credit the original author.
|
||||
*
|
||||
* Copyright @Radolyn, 2023
|
||||
*/
|
||||
|
||||
using "ui/colors.palette";
|
||||
using "ui/widgets/widgets.style";
|
||||
|
||||
@@ -5,3 +14,4 @@ ayuGhostIcon: icon {{ "ayu/ghost", menuIconColor }};
|
||||
ayuMenuIcon: icon {{ "ayu/ayu_menu", menuIconColor }};
|
||||
ayuLReadMenuIcon: icon {{ "ayu/lread", menuIconColor }};
|
||||
ayuSReadMenuIcon: icon {{ "ayu/sread", menuIconColor }};
|
||||
ayuStreamerModeMenuIcon: icon {{ "ayu/streamer", menuIconColor }};
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#include "ayu_lottie.h"
|
||||
|
||||
namespace AyuUi
|
||||
{
|
||||
std::unique_ptr<Lottie::Icon> getLottie(const QString& text)
|
||||
{
|
||||
// todo: some kind of mapping
|
||||
// Lottie::MakeIcon({.json = QString(), .sizeOverride = {24, 24}});
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lottie/lottie_icon.h"
|
||||
|
||||
namespace AyuUi
|
||||
{
|
||||
std::unique_ptr<Lottie::Icon> getLottie(const QString& text);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* This is the source code of AyuGram for Desktop.
|
||||
*
|
||||
* We do not and cannot prevent the use of our code,
|
||||
* but be respectful and credit the original author.
|
||||
*
|
||||
* Copyright @Radolyn, 2023
|
||||
*/
|
||||
|
||||
using "ui/basic.style";
|
||||
using "ui/colors.palette";
|
||||
using "ui/widgets/widgets.style";
|
||||
|
||||
iconPreviewStroke: activeButtonBg;
|
||||
@@ -0,0 +1,85 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#include "icon_picker.h"
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "core/application.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
#include "ayu/ui/ayu_assets.h"
|
||||
#include "main/main_domain.h"
|
||||
#include "styles/style_ayu_styles.h"
|
||||
#include "ui/painter.h"
|
||||
#include "window/main_window.h"
|
||||
|
||||
void drawIcon(QPainter& p, const QImage& icon, int offset, bool selected)
|
||||
{
|
||||
if (selected)
|
||||
{
|
||||
p.save();
|
||||
p.setPen(QPen(st::iconPreviewStroke, 2));
|
||||
p.drawEllipse(offset + 2, 2, 68, 68);
|
||||
p.restore();
|
||||
}
|
||||
|
||||
auto rect = QRect(offset + 4, 4, 64, 64);
|
||||
p.drawImage(rect, icon);
|
||||
}
|
||||
|
||||
IconPicker::IconPicker(QWidget* parent) : RpWidget(parent)
|
||||
{
|
||||
setMinimumSize(st::boxWidth, 72);
|
||||
}
|
||||
|
||||
void IconPicker::paintEvent(QPaintEvent* e)
|
||||
{
|
||||
Painter p(this);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
|
||||
auto icon1 = logo().scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
auto icon2 = logoAlt().scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
auto icon3 = logoNothing().scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
// todo: center
|
||||
drawIcon(p, icon1, 0, currentAppLogoName() == AyuSettings::DEFAULT_ICON);
|
||||
drawIcon(p, icon2, 0 + 64 + 16, currentAppLogoName() == AyuSettings::ALT_ICON);
|
||||
drawIcon(p, icon3, 0 + 64 + 16 + 64 + 16, currentAppLogoName() == AyuSettings::NOTHING_ICON);
|
||||
}
|
||||
|
||||
void IconPicker::mousePressEvent(QMouseEvent* e)
|
||||
{
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
auto changed = false;
|
||||
|
||||
auto x = e->pos().x();
|
||||
if (x <= 64 && settings->appIcon != AyuSettings::DEFAULT_ICON)
|
||||
{
|
||||
settings->set_appIcon(AyuSettings::DEFAULT_ICON);
|
||||
changed = true;
|
||||
}
|
||||
else if (x >= 64 + 16 && x <= 64 + 16 + 64 && settings->appIcon != AyuSettings::ALT_ICON)
|
||||
{
|
||||
settings->set_appIcon(AyuSettings::ALT_ICON);
|
||||
changed = true;
|
||||
}
|
||||
else if (x >= 64 + 16 + 64 + 16 && x < 64 + 16 + 64 + 16 + 64 && settings->appIcon != AyuSettings::NOTHING_ICON)
|
||||
{
|
||||
settings->set_appIcon(AyuSettings::NOTHING_ICON);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
AyuSettings::save();
|
||||
|
||||
Window::OverrideApplicationIcon(currentAppLogo());
|
||||
Core::App().refreshApplicationIcon();
|
||||
Core::App().domain().notifyUnreadBadgeChanged();
|
||||
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// This is the source code of AyuGram for Desktop.
|
||||
//
|
||||
// We do not and cannot prevent the use of our code,
|
||||
// but be respectful and credit the original author.
|
||||
//
|
||||
// Copyright @Radolyn, 2023
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
class IconPicker : public Ui::RpWidget
|
||||
{
|
||||
public:
|
||||
IconPicker(QWidget* parent);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* e) override;
|
||||
void mousePressEvent(QMouseEvent* e) override;
|
||||
};
|
||||
@@ -15,11 +15,15 @@
|
||||
#include "lang_auto.h"
|
||||
#include "mainwindow.h"
|
||||
#include "api/api_blocked_peers.h"
|
||||
|
||||
#include "ayu/features/streamer_mode/streamer_mode.h"
|
||||
|
||||
#include "boxes/connection_box.h"
|
||||
#include "core/application.h"
|
||||
#include "data/data_session.h"
|
||||
#include "lang/lang_instance.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/system_media_controls_manager.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "storage/localstorage.h"
|
||||
@@ -30,7 +34,9 @@
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include "icon_picker.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/boxes/single_choice_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
@@ -45,6 +51,17 @@ constexpr auto GhostModeOptionsCount = 5;
|
||||
|
||||
class PainterHighQualityEnabler;
|
||||
|
||||
const char kStreamerMode[] =
|
||||
"streamer-mode";
|
||||
|
||||
base::options::toggle StreamerMode({
|
||||
.id = kStreamerMode,
|
||||
.name = "Show streamer mode toggles",
|
||||
.description = "Streamer mode completely hides AyuGram windows and notifications from capture apps.",
|
||||
.scope = base::options::windows,
|
||||
.restartRequired = true
|
||||
});
|
||||
|
||||
not_null<Ui::RpWidget*> AddInnerToggle(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
const style::SettingsButton& st,
|
||||
@@ -112,7 +129,7 @@ not_null<Ui::RpWidget*> AddInnerToggle(
|
||||
) | start_with_next([=](const QRect& r)
|
||||
{
|
||||
const auto w = st::rightsButtonToggleWidth;
|
||||
constexpr auto kLineWidth = static_cast<int>(1);
|
||||
constexpr auto kLineWidth = 1;
|
||||
toggleButton->setGeometry(
|
||||
r.x() + r.width() - w,
|
||||
r.y(),
|
||||
@@ -267,6 +284,69 @@ namespace Settings
|
||||
setupContent(controller);
|
||||
}
|
||||
|
||||
void Ayu::AddPlatformOption(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
base::options::option<bool>& option,
|
||||
rpl::producer<> resetClicks)
|
||||
{
|
||||
auto& lifetime = container->lifetime();
|
||||
const auto name = option.name().isEmpty() ? option.id() : option.name();
|
||||
const auto toggles = lifetime.make_state<rpl::event_stream<bool>>();
|
||||
std::move(
|
||||
resetClicks
|
||||
) | rpl::map_to(
|
||||
option.defaultValue()
|
||||
) | start_to_stream(*toggles, lifetime);
|
||||
|
||||
const auto button = AddButton(
|
||||
container,
|
||||
rpl::single(name),
|
||||
(option.relevant()
|
||||
? st::settingsButtonNoIcon
|
||||
: st::settingsOptionDisabled)
|
||||
)->toggleOn(toggles->events_starting_with(option.value()));
|
||||
|
||||
const auto restarter = (option.relevant() && option.restartRequired())
|
||||
? button->lifetime().make_state<base::Timer>()
|
||||
: nullptr;
|
||||
if (restarter)
|
||||
{
|
||||
restarter->setCallback([=]
|
||||
{
|
||||
window->show(Ui::MakeConfirmBox({
|
||||
.text = tr::lng_settings_need_restart(),
|
||||
.confirmed = [] { Core::Restart(); },
|
||||
.confirmText = tr::lng_settings_restart_now(),
|
||||
.cancelText = tr::lng_settings_restart_later(),
|
||||
}));
|
||||
});
|
||||
}
|
||||
button->toggledChanges(
|
||||
) | start_with_next([=, &option](bool toggled)
|
||||
{
|
||||
if (!option.relevant() && toggled != option.defaultValue())
|
||||
{
|
||||
toggles->fire_copy(option.defaultValue());
|
||||
window->showToast(
|
||||
tr::lng_settings_experimental_irrelevant(tr::now));
|
||||
return;
|
||||
}
|
||||
option.set(toggled);
|
||||
if (restarter)
|
||||
{
|
||||
restarter->callOnce(st::settingsButtonNoIcon.toggle.duration);
|
||||
}
|
||||
}, container->lifetime());
|
||||
|
||||
const auto& description = option.description();
|
||||
if (!description.isEmpty())
|
||||
{
|
||||
AddSkip(container);
|
||||
AddDividerText(container, rpl::single(description));
|
||||
}
|
||||
}
|
||||
|
||||
void Ayu::SetupGhostEssentials(not_null<Ui::VerticalLayout*> container)
|
||||
{
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
@@ -333,11 +413,6 @@ namespace Settings
|
||||
std::function<void(bool)> callback;
|
||||
};
|
||||
|
||||
struct LabeledEntryGroup
|
||||
{
|
||||
std::vector<NestedEntry> nested;
|
||||
};
|
||||
|
||||
std::vector checkboxes{
|
||||
NestedEntry{
|
||||
tr::ayu_DontReadMessages(tr::now), !settings->sendReadMessages, [=](bool enabled)
|
||||
@@ -552,6 +627,13 @@ namespace Settings
|
||||
}, container->lifetime());
|
||||
}
|
||||
|
||||
void Ayu::SetupAppIcon(not_null<Ui::VerticalLayout*> container)
|
||||
{
|
||||
container->add(
|
||||
object_ptr<IconPicker>(container),
|
||||
st::settingsSubsectionTitlePadding);
|
||||
}
|
||||
|
||||
void Ayu::SetupCustomization(not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionController*> controller)
|
||||
{
|
||||
@@ -559,6 +641,8 @@ namespace Settings
|
||||
|
||||
AddSubsectionTitle(container, tr::ayu_CustomizationHeader());
|
||||
|
||||
SetupAppIcon(container);
|
||||
|
||||
auto btn = AddButtonWithLabel(
|
||||
container,
|
||||
tr::ayu_DeletedMarkText(),
|
||||
@@ -791,6 +875,13 @@ namespace Settings
|
||||
}, container->lifetime());
|
||||
}
|
||||
|
||||
void Ayu::SetupExperimental(not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionController*> controller)
|
||||
{
|
||||
AddSubsectionTitle(container, tr::lng_settings_experimental());
|
||||
AddPlatformOption(controller, container, StreamerMode, rpl::producer<>());
|
||||
}
|
||||
|
||||
void Ayu::SetupAyuGramSettings(not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionController*> controller)
|
||||
{
|
||||
@@ -818,7 +909,7 @@ namespace Settings
|
||||
AddDividerText(container, tr::ayu_SettingsCustomizationHint());
|
||||
|
||||
// todo: compilation flag
|
||||
if (false)
|
||||
if constexpr (false)
|
||||
{
|
||||
AddSkip(container);
|
||||
SetupAyuSync(container);
|
||||
@@ -831,6 +922,9 @@ namespace Settings
|
||||
SetupSendConfirmations(container);
|
||||
AddSkip(container);
|
||||
|
||||
AddDivider(container);
|
||||
SetupExperimental(container, controller);
|
||||
|
||||
AddDividerText(container, tr::ayu_SettingsWatermark());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/options.h"
|
||||
#include "settings/settings_common.h"
|
||||
|
||||
class BoxContent;
|
||||
@@ -18,6 +19,9 @@ namespace Window
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
extern const char kStreamerMode[];
|
||||
extern base::options::toggle StreamerMode;
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
class Ayu : public Section<Ayu>
|
||||
@@ -28,12 +32,20 @@ namespace Settings
|
||||
[[nodiscard]] rpl::producer<QString> title() override;
|
||||
|
||||
private:
|
||||
void AddPlatformOption(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
base::options::option<bool>& option,
|
||||
rpl::producer<> resetClicks);
|
||||
|
||||
void SetupGhostEssentials(not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
void SetupSpyEssentials(not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
void SetupQoLToggles(not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
void SetupAppIcon(not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
void SetupCustomization(not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionController*> controller);
|
||||
|
||||
@@ -45,6 +57,9 @@ namespace Settings
|
||||
|
||||
void SetupSendConfirmations(not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
void SetupExperimental(not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionController*> controller);
|
||||
|
||||
void SetupAyuGramSettings(not_null<Ui::VerticalLayout*> container, not_null<Window::SessionController*> null);
|
||||
|
||||
void setupContent(not_null<Window::SessionController*> controller);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
Main::Session* getSession(ID userId)
|
||||
{
|
||||
for (auto& [index, account] : Core::App().domain().accounts())
|
||||
for (const auto& [index, account] : Core::App().domain().accounts())
|
||||
{
|
||||
if (const auto session = account->maybeSession())
|
||||
{
|
||||
@@ -15,14 +15,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::Bold
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_payments.h" // paymentsSectionButton
|
||||
#include "styles/style_media_player.h" // mediaPlayerMenuCheck
|
||||
|
||||
namespace {
|
||||
@@ -32,16 +29,30 @@ Data::ChatFilter ChangedFilter(
|
||||
not_null<History*> history,
|
||||
bool add) {
|
||||
auto always = base::duplicate(filter.always());
|
||||
if (add) {
|
||||
always.insert(history);
|
||||
} else {
|
||||
always.remove(history);
|
||||
}
|
||||
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 {
|
||||
never.insert(history);
|
||||
const auto alwaysIt = always.find(history);
|
||||
if (alwaysIt != end(always)) {
|
||||
always.erase(alwaysIt);
|
||||
} else {
|
||||
never.insert(history);
|
||||
}
|
||||
}
|
||||
return Data::ChatFilter(
|
||||
filter.id(),
|
||||
|
||||
@@ -622,9 +622,10 @@ void EditCaptionBox::setupDragArea() {
|
||||
};
|
||||
// Avoid both drag areas appearing at one time.
|
||||
auto computeState = [=](const QMimeData *data) {
|
||||
using DragState = Storage::MimeDataState;
|
||||
const auto state = Storage::ComputeMimeDataState(data);
|
||||
return (state == Storage::MimeDataState::PhotoFiles)
|
||||
? Storage::MimeDataState::Image
|
||||
return (state == DragState::PhotoFiles || state == DragState::Image)
|
||||
? (_asFile ? DragState::Files : DragState::Image)
|
||||
: state;
|
||||
};
|
||||
const auto areas = DragArea::SetupDragAreaToContainer(
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/peer_list_box.h"
|
||||
|
||||
#include "history/history.h" // chatListNameSortKey.
|
||||
#include "main/session/session_show.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwidget.h"
|
||||
@@ -396,6 +397,27 @@ void PeerListController::setSearchNoResultsText(const QString &text) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListController::sortByName() {
|
||||
auto keys = base::flat_map<PeerListRowId, QString>();
|
||||
keys.reserve(delegate()->peerListFullRowsCount());
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto id = row.id();
|
||||
const auto i = keys.find(id);
|
||||
if (i != end(keys)) {
|
||||
return i->second;
|
||||
}
|
||||
const auto peer = row.peer();
|
||||
const auto history = peer->owner().history(peer);
|
||||
return keys.emplace(
|
||||
id,
|
||||
history->chatListNameSortKey()).first->second;
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return (key(a).compare(key(b)) < 0);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> PeerListController::rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) {
|
||||
@@ -741,8 +763,8 @@ int PeerListRow::paintNameIconGetWidth(
|
||||
? st::dialogsVerifiedIconOver
|
||||
: st::dialogsVerifiedIcon),
|
||||
.premium = &(selected
|
||||
? st::dialogsPremiumIconOver
|
||||
: st::dialogsPremiumIcon),
|
||||
? st::dialogsPremiumIcon.over
|
||||
: st::dialogsPremiumIcon.icon),
|
||||
.scam = &(selected ? st::dialogsScamFgOver : st::dialogsScamFg),
|
||||
.premiumFg = &(selected
|
||||
? st::dialogsVerifiedIconBgOver
|
||||
|
||||
@@ -560,6 +560,8 @@ protected:
|
||||
delegate()->peerListSetSearchNoResults(std::move(noResults));
|
||||
}
|
||||
|
||||
void sortByName();
|
||||
|
||||
private:
|
||||
PeerListDelegate *_delegate = nullptr;
|
||||
std::unique_ptr<PeerListSearchController> _searchController = nullptr;
|
||||
|
||||
@@ -594,25 +594,6 @@ void ContactsBoxController::sort() {
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsBoxController::sortByName() {
|
||||
auto keys = base::flat_map<PeerListRowId, QString>();
|
||||
keys.reserve(delegate()->peerListFullRowsCount());
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto id = row.id();
|
||||
const auto i = keys.find(id);
|
||||
if (i != end(keys)) {
|
||||
return i->second;
|
||||
}
|
||||
const auto peer = row.peer();
|
||||
const auto history = peer->owner().history(peer);
|
||||
return keys.emplace(id, history->chatListNameSortKey()).first->second;
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return (key(a).compare(key(b)) < 0);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
void ContactsBoxController::sortByOnline() {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
|
||||
@@ -192,7 +192,6 @@ protected:
|
||||
|
||||
private:
|
||||
void sort();
|
||||
void sortByName();
|
||||
void sortByOnline();
|
||||
void rebuildRows();
|
||||
void checkForEmptyRows();
|
||||
|
||||
@@ -319,16 +319,15 @@ not_null<Ui::RpWidget*> AddInnerToggle(
|
||||
button->geometryValue(
|
||||
) | rpl::start_with_next([=](const QRect &r) {
|
||||
const auto w = st::rightsButtonToggleWidth;
|
||||
constexpr auto kLineWidth = int(1);
|
||||
toggleButton->setGeometry(
|
||||
r.x() + r.width() - w,
|
||||
r.y(),
|
||||
w,
|
||||
r.height());
|
||||
separator->setGeometry(
|
||||
toggleButton->x() - kLineWidth,
|
||||
toggleButton->x() - st::lineWidth,
|
||||
r.y() + (r.height() - separatorHeight) / 2,
|
||||
kLineWidth,
|
||||
st::lineWidth,
|
||||
separatorHeight);
|
||||
}, toggleButton->lifetime());
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/call_delayed.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/scroll_content_shadow.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
@@ -42,9 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/chat/attach/attach_album_preview.h"
|
||||
#include "ui/chat/attach/attach_single_file_preview.h"
|
||||
#include "ui/chat/attach/attach_single_media_preview.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/grouped_layout.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
#include "ui/painter.h"
|
||||
@@ -54,16 +50,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "api/api_common.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
#include <QtCore/QMimeData>
|
||||
@@ -77,10 +70,14 @@ constexpr auto kMaxMessageLength = 4096;
|
||||
|
||||
using Ui::SendFilesWay;
|
||||
|
||||
inline bool CanAddUrls(const QList<QUrl> &urls) {
|
||||
[[nodiscard]] inline bool CanAddUrls(const QList<QUrl> &urls) {
|
||||
return !urls.isEmpty() && ranges::all_of(urls, &QUrl::isLocalFile);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool CanAddFiles(not_null<const QMimeData*> data) {
|
||||
return data->hasImage() || CanAddUrls(Core::ReadMimeUrls(data));
|
||||
}
|
||||
|
||||
void FileDialogCallback(
|
||||
FileDialog::OpenResult &&result,
|
||||
Fn<bool(const Ui::PreparedList&)> checkResult,
|
||||
@@ -448,13 +445,15 @@ void SendFilesBox::setupDragArea() {
|
||||
auto computeState = [=](const QMimeData *data) {
|
||||
using DragState = Storage::MimeDataState;
|
||||
const auto state = Storage::ComputeMimeDataState(data);
|
||||
return (state == DragState::PhotoFiles)
|
||||
? DragState::Image
|
||||
return (state == DragState::PhotoFiles || state == DragState::Image)
|
||||
? (_sendWay.current().sendImagesAsPhotos()
|
||||
? DragState::Image
|
||||
: DragState::Files)
|
||||
: state;
|
||||
};
|
||||
const auto areas = DragArea::SetupDragAreaToContainer(
|
||||
this,
|
||||
[=](not_null<const QMimeData*> d) { return canAddFiles(d); },
|
||||
CanAddFiles,
|
||||
[=](bool f) { _caption->setAcceptDrops(f); },
|
||||
[=] { updateControlsGeometry(); },
|
||||
std::move(computeState));
|
||||
@@ -1049,7 +1048,7 @@ void SendFilesBox::setupCaption() {
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return canAddFiles(data);
|
||||
return CanAddFiles(data);
|
||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||
return addFiles(data);
|
||||
}
|
||||
@@ -1145,10 +1144,6 @@ void SendFilesBox::captionResized() {
|
||||
update();
|
||||
}
|
||||
|
||||
bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
|
||||
return data->hasImage() || CanAddUrls(Core::ReadMimeUrls(data));
|
||||
}
|
||||
|
||||
bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
|
||||
const auto premium = _show->session().premium();
|
||||
auto list = [&] {
|
||||
|
||||
@@ -213,7 +213,6 @@ private:
|
||||
void updateControlsGeometry();
|
||||
void updateCaptionPlaceholder();
|
||||
|
||||
bool canAddFiles(not_null<const QMimeData*> data) const;
|
||||
bool addFiles(not_null<const QMimeData*> data);
|
||||
bool addFiles(Ui::PreparedList list);
|
||||
void addFile(Ui::PreparedFile &&file);
|
||||
|
||||
@@ -18,7 +18,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
@@ -602,7 +601,7 @@ void ShareBox::submitWhenOnline() {
|
||||
submit(Api::DefaultSendWhenOnlineOptions());
|
||||
}
|
||||
|
||||
void ShareBox::copyLink() {
|
||||
void ShareBox::copyLink() const {
|
||||
if (const auto onstack = _descriptor.copyCallback) {
|
||||
onstack();
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ private:
|
||||
void submitSilent();
|
||||
void submitScheduled();
|
||||
void submitWhenOnline();
|
||||
void copyLink();
|
||||
void copyLink() const;
|
||||
bool searchByUsername(bool useCache = false);
|
||||
|
||||
SendMenu::Type sendMenuType() const;
|
||||
|
||||
@@ -53,6 +53,22 @@ constexpr auto kArchivedLimitFirstRequest = 10;
|
||||
constexpr auto kArchivedLimitPerPage = 30;
|
||||
constexpr auto kHandleMegagroupSetAddressChangeTimeout = crl::time(1000);
|
||||
|
||||
[[nodiscard]] QString FillSetTitle(
|
||||
not_null<StickersSet*> set,
|
||||
int maxNameWidth,
|
||||
int *outTitleWidth) {
|
||||
auto result = set->title;
|
||||
auto titleWidth = st::contactsNameStyle.font->width(result);
|
||||
if (titleWidth > maxNameWidth) {
|
||||
result = st::contactsNameStyle.font->elided(result, maxNameWidth);
|
||||
titleWidth = st::contactsNameStyle.font->width(result);
|
||||
}
|
||||
if (outTitleWidth) {
|
||||
*outTitleWidth = titleWidth;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class StickersBox::CounterWidget : public Ui::RpWidget {
|
||||
@@ -98,22 +114,25 @@ public:
|
||||
void updateRows(); // refresh only pack cover stickers
|
||||
bool appendSet(not_null<StickersSet*> set);
|
||||
|
||||
StickersSetsOrder getOrder() const;
|
||||
StickersSetsOrder getFullOrder() const;
|
||||
StickersSetsOrder getRemovedSets() const;
|
||||
StickersSetsOrder order() const;
|
||||
StickersSetsOrder fullOrder() const;
|
||||
StickersSetsOrder removedSets() const;
|
||||
|
||||
void setFullOrder(const StickersSetsOrder &order);
|
||||
void setRemovedSets(const StickersSetsOrder &removed);
|
||||
|
||||
void setRowRemovedBySetId(uint64 setId, bool removed);
|
||||
|
||||
void setInstallSetCallback(Fn<void(uint64 setId)> callback) {
|
||||
_installSetCallback = std::move(callback);
|
||||
}
|
||||
void setRemoveSetCallback(Fn<void(uint64 setId)> callback) {
|
||||
_removeSetCallback = std::move(callback);
|
||||
}
|
||||
void setLoadMoreCallback(Fn<void()> callback) {
|
||||
_loadMoreCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setMinHeight(int newWidth, int minHeight);
|
||||
|
||||
int getVisibleTop() const {
|
||||
return _visibleTop;
|
||||
}
|
||||
@@ -151,13 +170,13 @@ private:
|
||||
int32 pixh);
|
||||
~Row();
|
||||
|
||||
bool isRecentSet() const;
|
||||
bool isMasksSet() const;
|
||||
bool isEmojiSet() const;
|
||||
bool isWebm() const;
|
||||
bool isInstalled() const;
|
||||
bool isUnread() const;
|
||||
bool isArchived() const;
|
||||
[[nodiscard]] bool isRecentSet() const;
|
||||
[[nodiscard]] bool isMasksSet() const;
|
||||
[[nodiscard]] bool isEmojiSet() const;
|
||||
[[nodiscard]] bool isWebm() const;
|
||||
[[nodiscard]] bool isInstalled() const;
|
||||
[[nodiscard]] bool isUnread() const;
|
||||
[[nodiscard]] bool isArchived() const;
|
||||
|
||||
const not_null<StickersSet*> set;
|
||||
DocumentData *sticker = nullptr;
|
||||
@@ -212,7 +231,11 @@ private:
|
||||
void setPressed(SelectedRow pressed);
|
||||
void setup();
|
||||
QRect relativeButtonRect(bool removeButton, bool installedSet) const;
|
||||
void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton);
|
||||
void ensureRipple(
|
||||
const style::RippleAnimation &st,
|
||||
QImage mask,
|
||||
bool removeButton,
|
||||
bool installedSet);
|
||||
|
||||
bool shiftingAnimationCallback(crl::time now);
|
||||
void paintRow(Painter &p, not_null<Row*> row, int index);
|
||||
@@ -237,10 +260,6 @@ private:
|
||||
void rebuildAppendSet(not_null<StickersSet*> set);
|
||||
void fillSetCover(not_null<StickersSet*> set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
|
||||
int fillSetCount(not_null<StickersSet*> set) const;
|
||||
[[nodiscard]] QString fillSetTitle(
|
||||
not_null<StickersSet*> set,
|
||||
int maxNameWidth,
|
||||
int *outTitleWidth) const;
|
||||
[[nodiscard]] Data::StickersSetFlags fillSetFlags(
|
||||
not_null<StickersSet*> set) const;
|
||||
void rebuildMegagroupSet();
|
||||
@@ -270,6 +289,7 @@ private:
|
||||
Ui::Animations::Basic _shiftingAnimation;
|
||||
|
||||
Fn<void(uint64 setId)> _installSetCallback;
|
||||
Fn<void(uint64 setId)> _removeSetCallback;
|
||||
Fn<void()> _loadMoreCallback;
|
||||
|
||||
int _visibleTop = 0;
|
||||
@@ -598,17 +618,43 @@ void StickersBox::prepare() {
|
||||
_attached.widget()->hide();
|
||||
}
|
||||
|
||||
const auto installCallback = [=](uint64 setId) { installSet(setId); };
|
||||
if (_featured.widget()) {
|
||||
_featured.widget()->setInstallSetCallback(installCallback);
|
||||
}
|
||||
if (_archived.widget()) {
|
||||
_archived.widget()->setInstallSetCallback(installCallback);
|
||||
_archived.widget()->setLoadMoreCallback([=] { loadMoreArchived(); });
|
||||
}
|
||||
if (_attached.widget()) {
|
||||
_attached.widget()->setInstallSetCallback(installCallback);
|
||||
_attached.widget()->setLoadMoreCallback([=] { showAttachedStickers(); });
|
||||
{
|
||||
const auto installCallback = [=](uint64 setId) { installSet(setId); };
|
||||
const auto markAsInstalledCallback = [=](uint64 setId) {
|
||||
if (_installed.widget()) {
|
||||
_installed.widget()->setRowRemovedBySetId(setId, false);
|
||||
}
|
||||
if (_featured.widget()) {
|
||||
_featured.widget()->setRowRemovedBySetId(setId, false);
|
||||
}
|
||||
};
|
||||
const auto markAsRemovedCallback = [=](uint64 setId) {
|
||||
if (_installed.widget()) {
|
||||
_installed.widget()->setRowRemovedBySetId(setId, true);
|
||||
}
|
||||
if (_featured.widget()) {
|
||||
_featured.widget()->setRowRemovedBySetId(setId, true);
|
||||
}
|
||||
};
|
||||
if (const auto installed = _installed.widget()) {
|
||||
installed->setInstallSetCallback(markAsInstalledCallback);
|
||||
installed->setRemoveSetCallback(markAsRemovedCallback);
|
||||
}
|
||||
if (const auto featured = _featured.widget()) {
|
||||
featured->setInstallSetCallback([=](uint64 setId) {
|
||||
markAsInstalledCallback(setId);
|
||||
installCallback(setId);
|
||||
});
|
||||
featured->setRemoveSetCallback(markAsRemovedCallback);
|
||||
}
|
||||
if (const auto archived = _archived.widget()) {
|
||||
archived->setInstallSetCallback(installCallback);
|
||||
archived->setLoadMoreCallback([=] { loadMoreArchived(); });
|
||||
}
|
||||
if (const auto attached = _attached.widget()) {
|
||||
attached->setInstallSetCallback(installCallback);
|
||||
attached->setLoadMoreCallback([=] { showAttachedStickers(); });
|
||||
}
|
||||
}
|
||||
|
||||
if (_megagroupSet) {
|
||||
@@ -634,7 +680,7 @@ void StickersBox::prepare() {
|
||||
} else { // _section == Section::Featured
|
||||
_tab = &_featured;
|
||||
}
|
||||
setInnerWidget(_tab->takeWidget(), getTopSkip());
|
||||
setInnerWidget(_tab->takeWidget(), topSkip());
|
||||
setDimensions(st::boxWideWidth, st::boxMaxListHeight);
|
||||
|
||||
session().data().stickers().updated(_isEmoji
|
||||
@@ -757,7 +803,7 @@ void StickersBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
if (_slideAnimation) {
|
||||
_slideAnimation->paintFrame(p, 0, getTopSkip(), width());
|
||||
_slideAnimation->paintFrame(p, 0, topSkip(), width());
|
||||
if (!_slideAnimation->animating()) {
|
||||
_slideAnimation.reset();
|
||||
setInnerVisible(true);
|
||||
@@ -774,7 +820,7 @@ void StickersBox::updateTabsGeometry() {
|
||||
_tabs->resizeToWidth(_tabIndices.size() * width() / maxTabs);
|
||||
_unreadBadge->setVisible(_tabIndices.contains(Section::Featured));
|
||||
|
||||
setInnerTopSkip(getTopSkip());
|
||||
setInnerTopSkip(topSkip());
|
||||
|
||||
auto featuredLeft = width() / maxTabs;
|
||||
auto featuredRight = 2 * width() / maxTabs;
|
||||
@@ -790,7 +836,7 @@ void StickersBox::updateTabsGeometry() {
|
||||
_tabs->moveToLeft(0, 0);
|
||||
}
|
||||
|
||||
int StickersBox::getTopSkip() const {
|
||||
int StickersBox::topSkip() const {
|
||||
return _tabs ? (_tabs->height() - st::lineWidth) : 0;
|
||||
}
|
||||
|
||||
@@ -819,8 +865,8 @@ void StickersBox::switchTab() {
|
||||
}
|
||||
|
||||
if (_tab == &_installed) {
|
||||
_localOrder = _tab->widget()->getFullOrder();
|
||||
_localRemoved = _tab->widget()->getRemovedSets();
|
||||
_localOrder = _tab->widget()->fullOrder();
|
||||
_localRemoved = _tab->widget()->removedSets();
|
||||
}
|
||||
auto wasCache = grabContentCache();
|
||||
auto wasIndex = _tab->index();
|
||||
@@ -831,12 +877,12 @@ void StickersBox::switchTab() {
|
||||
_tab->returnWidget(std::move(widget));
|
||||
_tab = newTab;
|
||||
_section = newSection;
|
||||
setInnerWidget(_tab->takeWidget(), getTopSkip());
|
||||
setInnerWidget(_tab->takeWidget(), topSkip());
|
||||
_tabs->raise();
|
||||
_unreadBadge->raise();
|
||||
_tab->widget()->show();
|
||||
rebuildList();
|
||||
scrollToY(_tab->getScrollTop());
|
||||
scrollToY(_tab->scrollTop());
|
||||
setInnerVisible(true);
|
||||
auto nowCache = grabContentCache();
|
||||
auto nowIndex = _tab->index();
|
||||
@@ -901,7 +947,7 @@ void StickersBox::installSet(uint64 setId) {
|
||||
}
|
||||
|
||||
void StickersBox::installDone(
|
||||
const MTPmessages_StickerSetInstallResult &result) {
|
||||
const MTPmessages_StickerSetInstallResult &result) const {
|
||||
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
|
||||
session().data().stickers().applyArchivedResult(
|
||||
result.c_messages_stickerSetInstallResultArchive());
|
||||
@@ -998,12 +1044,12 @@ void StickersBox::rebuildList(Tab *tab) {
|
||||
tab = _tab;
|
||||
}
|
||||
|
||||
if ((tab == &_installed) || (tab == &_masks)) {
|
||||
_localOrder = tab->widget()->getFullOrder();
|
||||
_localRemoved = tab->widget()->getRemovedSets();
|
||||
if ((tab == &_installed) || (tab == &_masks) || (_tab == &_featured)) {
|
||||
_localOrder = tab->widget()->fullOrder();
|
||||
_localRemoved = tab->widget()->removedSets();
|
||||
}
|
||||
tab->widget()->rebuild(_isMasks);
|
||||
if ((tab == &_installed) || (tab == &_masks)) {
|
||||
if ((tab == &_installed) || (tab == &_masks) || (_tab == &_featured)) {
|
||||
tab->widget()->setFullOrder(_localOrder);
|
||||
}
|
||||
tab->widget()->setRemovedSets(_localRemoved);
|
||||
@@ -1030,14 +1076,14 @@ void StickersBox::saveChanges() {
|
||||
}
|
||||
if (installed) {
|
||||
session().api().saveStickerSets(
|
||||
installed->getOrder(),
|
||||
installed->getRemovedSets(),
|
||||
installed->order(),
|
||||
installed->removedSets(),
|
||||
Data::StickersType::Stickers);
|
||||
}
|
||||
if (masks) {
|
||||
session().api().saveStickerSets(
|
||||
masks->getOrder(),
|
||||
masks->getRemovedSets(),
|
||||
masks->order(),
|
||||
masks->removedSets(),
|
||||
Data::StickersType::Masks);
|
||||
}
|
||||
}
|
||||
@@ -1056,7 +1102,7 @@ const Data::StickersSetsOrder &StickersBox::archivedSetsOrder() const {
|
||||
: session().data().stickers().archivedMaskSetsOrder();
|
||||
}
|
||||
|
||||
Data::StickersSetsOrder &StickersBox::archivedSetsOrderRef() {
|
||||
Data::StickersSetsOrder &StickersBox::archivedSetsOrderRef() const {
|
||||
return !_isMasks
|
||||
? session().data().stickers().archivedSetsOrderRef()
|
||||
: session().data().stickers().archivedMaskSetsOrderRef();
|
||||
@@ -1594,6 +1640,12 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int ind
|
||||
const auto textWidth = _installedWidth;
|
||||
const auto &text = _installedText;
|
||||
_inactiveButtonBg.paint(p, myrtlrect(rect));
|
||||
if (row->ripple) {
|
||||
row->ripple->paint(p, rect.x(), rect.y(), width());
|
||||
if (row->ripple->empty()) {
|
||||
row->ripple.reset();
|
||||
}
|
||||
}
|
||||
p.setFont(st.font);
|
||||
p.setPen(st.textFg);
|
||||
p.drawTextLeft(rect.x() - (st.width / 2), rect.y() + st.textTop, width(), text, textWidth);
|
||||
@@ -1673,16 +1725,27 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
|
||||
if (row->removed) {
|
||||
auto rippleSize = QSize(_undoWidth - st::stickersUndoRemove.width, st::stickersUndoRemove.height);
|
||||
auto rippleMask = Ui::RippleAnimation::RoundRectMask(rippleSize, st::roundRadiusLarge);
|
||||
ensureRipple(st::stickersUndoRemove.ripple, std::move(rippleMask), removeButton);
|
||||
ensureRipple(st::stickersUndoRemove.ripple, std::move(rippleMask), removeButton, false);
|
||||
} else {
|
||||
auto rippleSize = st::stickersRemove.rippleAreaSize;
|
||||
auto rippleMask = Ui::RippleAnimation::EllipseMask(QSize(rippleSize, rippleSize));
|
||||
ensureRipple(st::stickersRemove.ripple, std::move(rippleMask), removeButton);
|
||||
ensureRipple(st::stickersRemove.ripple, std::move(rippleMask), removeButton, false);
|
||||
}
|
||||
} else if (!row->isInstalled() || row->isArchived() || row->removed) {
|
||||
auto rippleSize = QSize(_addWidth - st::stickersTrendingAdd.width, st::stickersTrendingAdd.height);
|
||||
auto rippleMask = Ui::RippleAnimation::RoundRectMask(rippleSize, st::roundRadiusLarge);
|
||||
ensureRipple(st::stickersTrendingAdd.ripple, std::move(rippleMask), removeButton);
|
||||
} else {
|
||||
const auto installedSet = row->isInstalled()
|
||||
&& !row->isArchived()
|
||||
&& !row->removed;
|
||||
const auto &st = installedSet
|
||||
? st::stickersTrendingInstalled
|
||||
: st::stickersTrendingAdd;
|
||||
auto rippleMask = Ui::RippleAnimation::RoundRectMask(
|
||||
QSize(_addWidth - st.width, st.height),
|
||||
st::roundRadiusLarge);
|
||||
ensureRipple(
|
||||
st.ripple,
|
||||
std::move(rippleMask),
|
||||
removeButton,
|
||||
installedSet);
|
||||
}
|
||||
}
|
||||
if (row->ripple) {
|
||||
@@ -1747,9 +1810,14 @@ void StickersBox::Inner::setPressed(SelectedRow pressed) {
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton) {
|
||||
_rows[_actionDown]->ripple = std::make_unique<Ui::RippleAnimation>(st, std::move(mask), [this, index = _actionDown, removeButton] {
|
||||
update(myrtlrect(relativeButtonRect(removeButton, false).translated(0, _itemsTop + index * _rowHeight)));
|
||||
void StickersBox::Inner::ensureRipple(
|
||||
const style::RippleAnimation &st,
|
||||
QImage mask,
|
||||
bool removeButton,
|
||||
bool installedSet) {
|
||||
const auto dy = _itemsTop + _actionDown * _rowHeight;
|
||||
_rows[_actionDown]->ripple = std::make_unique<Ui::RippleAnimation>(st, std::move(mask), [=] {
|
||||
update(myrtlrect(relativeButtonRect(removeButton, installedSet).translated(0, dy)));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1812,7 +1880,7 @@ void StickersBox::Inner::updateSelected() {
|
||||
selected = selectedIndex;
|
||||
local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight);
|
||||
const auto row = _rows[selectedIndex].get();
|
||||
if (!_megagroupSet && (_isInstalledTab || !row->isInstalled() || row->isArchived() || row->removed)) {
|
||||
if (!_megagroupSet && (_isInstalledTab || (_section == Section::Featured) || !row->isInstalled() || row->isArchived() || row->removed)) {
|
||||
auto removeButton = (_isInstalledTab && !row->removed);
|
||||
auto rect = myrtlrect(relativeButtonRect(removeButton, false));
|
||||
actionSel = rect.contains(local) ? selectedIndex : -1;
|
||||
@@ -1857,7 +1925,7 @@ float64 StickersBox::Inner::aboveShadowOpacity() const {
|
||||
|
||||
auto dx = 0;
|
||||
auto dy = qAbs(_above * _rowHeight + qRound(_rows[_above]->yadd.current()) - _started * _rowHeight);
|
||||
return qMin((dx + dy) * 2. / _rowHeight, 1.);
|
||||
return qMin((dx + dy) * 2. / _rowHeight, 1.);
|
||||
}
|
||||
|
||||
void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
@@ -1868,10 +1936,11 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_mouse = e->globalPos();
|
||||
updateSelected();
|
||||
if (_actionDown == _actionSel && _actionSel >= 0) {
|
||||
if (_isInstalledTab) {
|
||||
setRowRemoved(_actionDown, !_rows[_actionDown]->removed);
|
||||
} else if (_installSetCallback) {
|
||||
_installSetCallback(_rows[_actionDown]->set->id);
|
||||
const auto callback = _rows[_actionDown]->removed
|
||||
? _installSetCallback
|
||||
: _removeSetCallback;
|
||||
if (callback) {
|
||||
callback(_rows[_actionDown]->set->id);
|
||||
}
|
||||
} else if (_dragging >= 0) {
|
||||
_rows[_dragging]->yadd.start(0.);
|
||||
@@ -1921,6 +1990,13 @@ void StickersBox::Inner::saveGroupSet() {
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::setRowRemovedBySetId(uint64 setId, bool removed) {
|
||||
const auto index = getRowIndex(setId);
|
||||
if (index >= 0) {
|
||||
setRowRemoved(index, removed);
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::setRowRemoved(int index, bool removed) {
|
||||
auto &row = _rows[index];
|
||||
if (row->removed != removed) {
|
||||
@@ -2114,7 +2190,7 @@ void StickersBox::Inner::rebuildMegagroupSet() {
|
||||
auto removed = false;
|
||||
auto maxNameWidth = countMaxNameWidth(!_isInstalledTab);
|
||||
auto titleWidth = 0;
|
||||
auto title = fillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
auto title = FillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
if (!_megagroupSelectedSet
|
||||
|| _megagroupSelectedSet->set->id != set->id) {
|
||||
_megagroupSetField->setText(set->shortName);
|
||||
@@ -2217,11 +2293,6 @@ void StickersBox::Inner::setMegagroupSelectedSet(
|
||||
updateSelected();
|
||||
}
|
||||
|
||||
void StickersBox::Inner::setMinHeight(int newWidth, int minHeight) {
|
||||
_minHeight = minHeight;
|
||||
updateSize(newWidth);
|
||||
}
|
||||
|
||||
void StickersBox::Inner::updateSize(int newWidth) {
|
||||
auto naturalHeight = _itemsTop + int(_rows.size()) * _rowHeight + st::membersMarginBottom;
|
||||
resize(newWidth ? newWidth : width(), qMax(_minHeight, naturalHeight));
|
||||
@@ -2269,7 +2340,7 @@ void StickersBox::Inner::updateRows() {
|
||||
&& row->isInstalled()
|
||||
&& !row->isArchived()
|
||||
&& !row->removed);
|
||||
row->title = fillSetTitle(
|
||||
row->title = FillSetTitle(
|
||||
set,
|
||||
installedSet ? maxNameWidthInstalled : maxNameWidth,
|
||||
&row->titleWidth);
|
||||
@@ -2331,7 +2402,7 @@ void StickersBox::Inner::rebuildAppendSet(not_null<StickersSet*> set) {
|
||||
&& !(flagsOverride & SetFlag::Archived)
|
||||
&& !removed);
|
||||
int titleWidth = 0;
|
||||
QString title = fillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
QString title = FillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
int count = fillSetCount(set);
|
||||
|
||||
const auto existing = [&]{
|
||||
@@ -2458,22 +2529,6 @@ int StickersBox::Inner::fillSetCount(not_null<StickersSet*> set) const {
|
||||
return result + added;
|
||||
}
|
||||
|
||||
QString StickersBox::Inner::fillSetTitle(
|
||||
not_null<StickersSet*> set,
|
||||
int maxNameWidth,
|
||||
int *outTitleWidth) const {
|
||||
auto result = set->title;
|
||||
int titleWidth = st::contactsNameStyle.font->width(result);
|
||||
if (titleWidth > maxNameWidth) {
|
||||
result = st::contactsNameStyle.font->elided(result, maxNameWidth);
|
||||
titleWidth = st::contactsNameStyle.font->width(result);
|
||||
}
|
||||
if (outTitleWidth) {
|
||||
*outTitleWidth = titleWidth;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Data::StickersSetFlags StickersBox::Inner::fillSetFlags(
|
||||
not_null<StickersSet*> set) const {
|
||||
const auto result = set->flags;
|
||||
@@ -2494,19 +2549,19 @@ StickersSetsOrder StickersBox::Inner::collectSets(Check check) const {
|
||||
return result;
|
||||
}
|
||||
|
||||
StickersSetsOrder StickersBox::Inner::getOrder() const {
|
||||
StickersSetsOrder StickersBox::Inner::order() const {
|
||||
return collectSets([](Row *row) {
|
||||
return !row->isArchived() && !row->removed && !row->isRecentSet();
|
||||
});
|
||||
}
|
||||
|
||||
StickersSetsOrder StickersBox::Inner::getFullOrder() const {
|
||||
StickersSetsOrder StickersBox::Inner::fullOrder() const {
|
||||
return collectSets([](Row *row) {
|
||||
return !row->isRecentSet();
|
||||
});
|
||||
}
|
||||
|
||||
StickersSetsOrder StickersBox::Inner::getRemovedSets() const {
|
||||
StickersSetsOrder StickersBox::Inner::removedSets() const {
|
||||
return collectSets([](Row *row) {
|
||||
return row->removed;
|
||||
});
|
||||
|
||||
@@ -104,7 +104,7 @@ private:
|
||||
[[nodiscard]] int index() const;
|
||||
|
||||
void saveScrollTop();
|
||||
int getScrollTop() const {
|
||||
int scrollTop() const {
|
||||
return _scrollTop;
|
||||
}
|
||||
|
||||
@@ -122,12 +122,12 @@ private:
|
||||
void updateTabsGeometry();
|
||||
void switchTab();
|
||||
void installSet(uint64 setId);
|
||||
int getTopSkip() const;
|
||||
int topSkip() const;
|
||||
void saveChanges();
|
||||
|
||||
QPixmap grabContentCache();
|
||||
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result) const;
|
||||
void installFail(const MTP::Error &error, uint64 setId);
|
||||
|
||||
void preloadArchivedSets();
|
||||
@@ -139,7 +139,7 @@ private:
|
||||
void showAttachedStickers();
|
||||
|
||||
const Data::StickersSetsOrder &archivedSetsOrder() const;
|
||||
Data::StickersSetsOrder &archivedSetsOrderRef();
|
||||
Data::StickersSetsOrder &archivedSetsOrderRef() const;
|
||||
|
||||
std::array<Inner*, 5> widgets() const;
|
||||
|
||||
|
||||
@@ -294,8 +294,11 @@ stickersTrendingAdd: RoundButton(defaultActiveButton) {
|
||||
stickersTrendingInstalled: RoundButton(stickersTrendingAdd) {
|
||||
textFg: activeButtonBg;
|
||||
textFgOver: activeButtonBgOver;
|
||||
textBg: activeButtonSecondaryFg;
|
||||
textBgOver: activeButtonSecondaryFgOver;
|
||||
textBg: lightButtonBgOver;
|
||||
textBgOver: lightButtonBgOver;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: activeButtonSecondaryFg;
|
||||
}
|
||||
}
|
||||
stickersRemove: IconButton(defaultIconButton) {
|
||||
width: 40px;
|
||||
|
||||
@@ -742,7 +742,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
case ScreenCorner::TopLeft:
|
||||
case ScreenCorner::TopRight:
|
||||
case ScreenCorner::BottomRight:
|
||||
case ScreenCorner::BottomLeft: _notificationsCorner = uncheckedNotificationsCorner; break;
|
||||
case ScreenCorner::BottomLeft:
|
||||
case ScreenCorner::TopCenter:_notificationsCorner = uncheckedNotificationsCorner; break;
|
||||
}
|
||||
_includeMutedCounter = (includeMutedCounter == 1);
|
||||
_countUnreadMessages = (countUnreadMessages == 1);
|
||||
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
TopRight = 1,
|
||||
BottomRight = 2,
|
||||
BottomLeft = 3,
|
||||
TopCenter = 4,
|
||||
};
|
||||
enum class NotifyView {
|
||||
ShowPreview = 0,
|
||||
@@ -130,11 +131,16 @@ public:
|
||||
|
||||
[[nodiscard]] static bool IsLeftCorner(ScreenCorner corner) {
|
||||
return (corner == ScreenCorner::TopLeft)
|
||||
|| (corner == ScreenCorner::BottomLeft);
|
||||
|| (corner == ScreenCorner::BottomLeft)
|
||||
|| (corner == ScreenCorner::TopCenter);
|
||||
}
|
||||
[[nodiscard]] static bool IsTopCorner(ScreenCorner corner) {
|
||||
return (corner == ScreenCorner::TopLeft)
|
||||
|| (corner == ScreenCorner::TopRight);
|
||||
|| (corner == ScreenCorner::TopRight)
|
||||
|| (corner == ScreenCorner::TopCenter);
|
||||
}
|
||||
[[nodiscard]] static bool IsTopCenterCorner(ScreenCorner corner) {
|
||||
return corner == ScreenCorner::TopCenter;
|
||||
}
|
||||
|
||||
[[nodiscard]] QByteArray serialize() const;
|
||||
|
||||
@@ -45,12 +45,9 @@ inline QString IconName() {
|
||||
|
||||
inline bool CanReadDirectory(const QString &path) {
|
||||
#ifndef Q_OS_MAC // directory_iterator since 10.15
|
||||
try {
|
||||
std::filesystem::directory_iterator(path.toStdString());
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
std::error_code error;
|
||||
std::filesystem::directory_iterator(path.toStdString(), error);
|
||||
return !error;
|
||||
#else
|
||||
Unexpected("Not implemented.");
|
||||
#endif
|
||||
|
||||
@@ -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 = 4009003;
|
||||
constexpr auto AppVersionStr = "4.9.3";
|
||||
constexpr auto AppVersion = 4009004;
|
||||
constexpr auto AppVersionStr = "4.9.4";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -1058,6 +1058,21 @@ void Stories::markAsRead(FullStoryId id, bool viewed) {
|
||||
if (!maybeStory) {
|
||||
return;
|
||||
}
|
||||
|
||||
// AyuGram sendReadStories
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
|
||||
if (!settings->sendReadStories)
|
||||
{
|
||||
_markReadRequests.clear();
|
||||
_markReadPending.clear();
|
||||
|
||||
_incrementViewsRequests.clear();
|
||||
_incrementViewsPending.clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto story = *maybeStory;
|
||||
if (story->expired() && story->pinned()) {
|
||||
_incrementViewsPending[id.peer].emplace(id.story);
|
||||
@@ -1207,6 +1222,10 @@ void Stories::sendMarkAsReadRequest(
|
||||
{
|
||||
_markReadRequests.clear();
|
||||
_markReadPending.clear();
|
||||
|
||||
_incrementViewsRequests.clear();
|
||||
_incrementViewsPending.clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1588,7 +1607,13 @@ void Stories::report(
|
||||
|
||||
bool Stories::isQuitPrevent() {
|
||||
if (!_markReadPending.empty()) {
|
||||
sendMarkAsReadRequests();
|
||||
// AyuGram sendReadStories
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
|
||||
if (settings->sendReadStories)
|
||||
{
|
||||
sendMarkAsReadRequests();
|
||||
}
|
||||
}
|
||||
if (!_incrementViewsPending.empty()) {
|
||||
sendIncrementViewsRequests();
|
||||
|
||||
@@ -28,7 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
// AyuGram includes
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/sync/utils/telegram_helpers.h"
|
||||
#include "ayu/utils/telegram_helpers.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -42,11 +42,39 @@ constexpr auto kMaxNotifyCheckDelay = 24 * 3600 * crl::time(1000);
|
||||
return (result > 0);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool SkipAddException(not_null<PeerData*> peer) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
return user->isInaccessible();
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
return chat->isDeactivated() || chat->isForbidden();
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
return channel->isForbidden();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DefaultNotify DefaultNotifyType(not_null<const PeerData*> peer) {
|
||||
return peer->isUser()
|
||||
? DefaultNotify::User
|
||||
: (peer->isChat() || peer->isMegagroup())
|
||||
? DefaultNotify::Group
|
||||
: DefaultNotify::Broadcast;
|
||||
}
|
||||
|
||||
MTPInputNotifyPeer DefaultNotifyToMTP(DefaultNotify type) {
|
||||
switch (type) {
|
||||
case DefaultNotify::User: return MTP_inputNotifyUsers();
|
||||
case DefaultNotify::Group: return MTP_inputNotifyChats();
|
||||
case DefaultNotify::Broadcast: return MTP_inputNotifyBroadcasts();
|
||||
}
|
||||
Unexpected("Default notify type in sendNotifySettingsUpdates");
|
||||
}
|
||||
|
||||
NotifySettings::NotifySettings(not_null<Session*> owner)
|
||||
: _owner(owner)
|
||||
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
|
||||
: _owner(owner)
|
||||
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
|
||||
}
|
||||
|
||||
void NotifySettings::request(not_null<PeerData*> peer) {
|
||||
@@ -63,7 +91,7 @@ void NotifySettings::request(not_null<PeerData*> peer) {
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::request(not_null<Data::Thread*> thread) {
|
||||
void NotifySettings::request(not_null<Thread*> thread) {
|
||||
if (const auto topic = thread->asTopic()) {
|
||||
if (topic->notify().settingsUnknown()) {
|
||||
topic->session().api().requestNotifySettings(
|
||||
@@ -145,6 +173,7 @@ void NotifySettings::apply(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (peer->notify().change(settings)) {
|
||||
updateException(peer);
|
||||
updateLocal(peer);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
@@ -162,7 +191,7 @@ void NotifySettings::apply(
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
not_null<ForumTopic*> topic,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (topic->notify().change(settings)) {
|
||||
updateLocal(topic);
|
||||
@@ -171,8 +200,8 @@ void NotifySettings::apply(
|
||||
}
|
||||
|
||||
void NotifySettings::update(
|
||||
not_null<Data::Thread*> thread,
|
||||
Data::MuteValue muteForSeconds,
|
||||
not_null<Thread*> thread,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound,
|
||||
std::optional<bool> storiesMuted) {
|
||||
@@ -181,34 +210,29 @@ void NotifySettings::update(
|
||||
silentPosts,
|
||||
sound,
|
||||
storiesMuted)) {
|
||||
if (const auto history = thread->asHistory()) {
|
||||
updateException(history->peer);
|
||||
}
|
||||
updateLocal(thread);
|
||||
thread->session().api().updateNotifySettingsDelayed(thread);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::resetToDefault(not_null<Data::Thread*> thread) {
|
||||
const auto empty = MTP_peerNotifySettings(
|
||||
MTP_flags(0),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPint(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound());
|
||||
if (thread->notify().change(empty)) {
|
||||
void NotifySettings::resetToDefault(not_null<Thread*> thread) {
|
||||
// Duplicated in clearExceptions(type) and resetToDefault(peer).
|
||||
if (thread->notify().resetToDefault()) {
|
||||
if (const auto history = thread->asHistory()) {
|
||||
updateException(history->peer);
|
||||
}
|
||||
updateLocal(thread);
|
||||
thread->session().api().updateNotifySettingsDelayed(thread);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::update(
|
||||
not_null<PeerData*> peer,
|
||||
Data::MuteValue muteForSeconds,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound,
|
||||
std::optional<bool> storiesMuted) {
|
||||
@@ -217,33 +241,24 @@ void NotifySettings::update(
|
||||
silentPosts,
|
||||
sound,
|
||||
storiesMuted)) {
|
||||
updateException(peer);
|
||||
updateLocal(peer);
|
||||
peer->session().api().updateNotifySettingsDelayed(peer);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::resetToDefault(not_null<PeerData*> peer) {
|
||||
const auto empty = MTP_peerNotifySettings(
|
||||
MTP_flags(0),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPint(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound());
|
||||
if (peer->notify().change(empty)) {
|
||||
// Duplicated in clearExceptions(type) and resetToDefault(thread).
|
||||
if (peer->notify().resetToDefault()) {
|
||||
updateException(peer);
|
||||
updateLocal(peer);
|
||||
peer->session().api().updateNotifySettingsDelayed(peer);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::forumParentMuteUpdated(not_null<Data::Forum*> forum) {
|
||||
forum->enumerateTopics([&](not_null<Data::ForumTopic*> topic) {
|
||||
void NotifySettings::forumParentMuteUpdated(not_null<Forum*> forum) {
|
||||
forum->enumerateTopics([&](not_null<ForumTopic*> topic) {
|
||||
if (!topic->notify().settingsUnknown()) {
|
||||
updateLocal(topic);
|
||||
}
|
||||
@@ -266,11 +281,7 @@ auto NotifySettings::defaultValue(DefaultNotify type) const
|
||||
|
||||
const PeerNotifySettings &NotifySettings::defaultSettings(
|
||||
not_null<const PeerData*> peer) const {
|
||||
return defaultSettings(peer->isUser()
|
||||
? DefaultNotify::User
|
||||
: (peer->isChat() || peer->isMegagroup())
|
||||
? DefaultNotify::Group
|
||||
: DefaultNotify::Broadcast);
|
||||
return defaultSettings(DefaultNotifyType(peer));
|
||||
}
|
||||
|
||||
const PeerNotifySettings &NotifySettings::defaultSettings(
|
||||
@@ -278,9 +289,16 @@ const PeerNotifySettings &NotifySettings::defaultSettings(
|
||||
return defaultValue(type).settings;
|
||||
}
|
||||
|
||||
bool NotifySettings::isMuted(DefaultNotify type) const {
|
||||
if (const auto until = defaultSettings(type).muteUntil()) {
|
||||
return MutedFromUntil(*until, nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NotifySettings::defaultUpdate(
|
||||
DefaultNotify type,
|
||||
Data::MuteValue muteForSeconds,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound,
|
||||
std::optional<bool> storiesMuted) {
|
||||
@@ -291,7 +309,7 @@ void NotifySettings::defaultUpdate(
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::updateLocal(not_null<Data::Thread*> thread) {
|
||||
void NotifySettings::updateLocal(not_null<Thread*> thread) {
|
||||
const auto topic = thread->asTopic();
|
||||
if (!topic) {
|
||||
return updateLocal(thread->peer());
|
||||
@@ -351,7 +369,7 @@ void NotifySettings::cacheSound(not_null<DocumentData*> document) {
|
||||
const auto view = document->createMediaView();
|
||||
_ringtones.views.emplace(document->id, view);
|
||||
document->forceToCache(true);
|
||||
document->save(Data::FileOriginRingtones(), QString());
|
||||
document->save(FileOriginRingtones(), QString());
|
||||
}
|
||||
|
||||
void NotifySettings::cacheSound(const std::optional<NotifySound> &sound) {
|
||||
@@ -459,7 +477,7 @@ void NotifySettings::unmuteByFinished() {
|
||||
}
|
||||
|
||||
bool NotifySettings::isMuted(
|
||||
not_null<const Data::Thread*> thread,
|
||||
not_null<const Thread*> thread,
|
||||
crl::time *changesIn) const {
|
||||
const auto topic = thread->asTopic();
|
||||
const auto until = topic ? topic->notify().muteUntil() : std::nullopt;
|
||||
@@ -468,27 +486,24 @@ bool NotifySettings::isMuted(
|
||||
: isMuted(thread->peer(), changesIn);
|
||||
}
|
||||
|
||||
bool NotifySettings::isMuted(not_null<const Data::Thread*> thread) const {
|
||||
bool NotifySettings::isMuted(not_null<const Thread*> thread) const {
|
||||
return isMuted(thread, nullptr);
|
||||
}
|
||||
|
||||
NotifySound NotifySettings::sound(
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
NotifySound NotifySettings::sound(not_null<const Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
const auto sound = topic ? topic->notify().sound() : std::nullopt;
|
||||
return sound ? *sound : this->sound(thread->peer());
|
||||
}
|
||||
|
||||
bool NotifySettings::muteUnknown(
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
bool NotifySettings::muteUnknown(not_null<const Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return (topic && topic->notify().settingsUnknown())
|
||||
|| ((!topic || !topic->notify().muteUntil().has_value())
|
||||
&& muteUnknown(thread->peer()));
|
||||
}
|
||||
|
||||
bool NotifySettings::soundUnknown(
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
bool NotifySettings::soundUnknown(not_null<const Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return (topic && topic->notify().settingsUnknown())
|
||||
|| ((!topic || !topic->notify().sound().has_value())
|
||||
@@ -543,8 +558,7 @@ bool NotifySettings::silentPostsUnknown(
|
||||
&& defaultSettings(peer).settingsUnknown());
|
||||
}
|
||||
|
||||
bool NotifySettings::soundUnknown(
|
||||
not_null<const PeerData*> peer) const {
|
||||
bool NotifySettings::soundUnknown(not_null<const PeerData*> peer) const {
|
||||
return peer->notify().settingsUnknown()
|
||||
|| (!peer->notify().sound().has_value()
|
||||
&& defaultSettings(peer).settingsUnknown());
|
||||
@@ -556,8 +570,7 @@ bool NotifySettings::settingsUnknown(not_null<const PeerData*> peer) const {
|
||||
|| soundUnknown(peer);
|
||||
}
|
||||
|
||||
bool NotifySettings::settingsUnknown(
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
bool NotifySettings::settingsUnknown(not_null<const Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return muteUnknown(thread)
|
||||
|| soundUnknown(thread)
|
||||
@@ -577,4 +590,85 @@ rpl::producer<> NotifySettings::defaultUpdates(
|
||||
: DefaultNotify::Broadcast);
|
||||
}
|
||||
|
||||
void NotifySettings::loadExceptions() {
|
||||
for (auto i = 0; i != kDefaultNotifyTypes; ++i) {
|
||||
if (_exceptionsRequestId[i]) {
|
||||
continue;
|
||||
}
|
||||
const auto type = static_cast<DefaultNotify>(i);
|
||||
const auto api = &_owner->session().api();
|
||||
const auto requestId = api->request(MTPaccount_GetNotifyExceptions(
|
||||
MTP_flags(MTPaccount_GetNotifyExceptions::Flag::f_peer),
|
||||
DefaultNotifyToMTP(type)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
api->applyUpdates(result);
|
||||
}).send();
|
||||
_exceptionsRequestId[i] = requestId;
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::updateException(not_null<PeerData*> peer) {
|
||||
const auto type = DefaultNotifyType(peer);
|
||||
const auto index = static_cast<int>(type);
|
||||
const auto exception = peer->notify().muteUntil().has_value();
|
||||
if (!exception) {
|
||||
if (_exceptions[index].remove(peer)) {
|
||||
exceptionsUpdated(type);
|
||||
}
|
||||
} else if (SkipAddException(peer)) {
|
||||
return;
|
||||
} else if (_exceptions[index].emplace(peer).second) {
|
||||
exceptionsUpdated(type);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::exceptionsUpdated(DefaultNotify type) {
|
||||
if (!ranges::contains(_exceptionsUpdatesScheduled, true)) {
|
||||
crl::on_main(&_owner->session(), [=] {
|
||||
const auto scheduled = base::take(_exceptionsUpdatesScheduled);
|
||||
for (auto i = 0; i != kDefaultNotifyTypes; ++i) {
|
||||
if (scheduled[i]) {
|
||||
_exceptionsUpdates.fire(static_cast<DefaultNotify>(i));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
_exceptionsUpdatesScheduled[static_cast<int>(type)] = true;
|
||||
_exceptionsUpdatesRealtime.fire_copy(type);
|
||||
}
|
||||
|
||||
rpl::producer<DefaultNotify> NotifySettings::exceptionsUpdates() const {
|
||||
return _exceptionsUpdates.events();
|
||||
}
|
||||
|
||||
auto NotifySettings::exceptionsUpdatesRealtime() const
|
||||
-> rpl::producer<DefaultNotify> {
|
||||
return _exceptionsUpdatesRealtime.events();
|
||||
}
|
||||
|
||||
const base::flat_set<not_null<PeerData*>> &NotifySettings::exceptions(
|
||||
DefaultNotify type) const {
|
||||
const auto index = static_cast<int>(type);
|
||||
Assert(index >= 0 && index < kDefaultNotifyTypes);
|
||||
|
||||
return _exceptions[index];
|
||||
}
|
||||
|
||||
void NotifySettings::clearExceptions(DefaultNotify type) {
|
||||
const auto index = static_cast<int>(type);
|
||||
const auto list = base::take(_exceptions[index]);
|
||||
if (list.empty()) {
|
||||
return;
|
||||
}
|
||||
for (const auto &peer : list) {
|
||||
// Duplicated in resetToDefault(peer / thread).
|
||||
if (peer->notify().resetToDefault()) {
|
||||
updateLocal(peer);
|
||||
peer->session().api().updateNotifySettingsDelayed(peer);
|
||||
}
|
||||
}
|
||||
Core::App().notifications().checkDelayed();
|
||||
exceptionsUpdated(type);
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
@@ -26,13 +26,17 @@ enum class DefaultNotify {
|
||||
Group,
|
||||
Broadcast,
|
||||
};
|
||||
[[nodiscard]] DefaultNotify DefaultNotifyType(
|
||||
not_null<const PeerData*> peer);
|
||||
|
||||
[[nodiscard]] MTPInputNotifyPeer DefaultNotifyToMTP(DefaultNotify type);
|
||||
|
||||
class NotifySettings final {
|
||||
public:
|
||||
NotifySettings(not_null<Session*> owner);
|
||||
|
||||
void request(not_null<PeerData*> peer);
|
||||
void request(not_null<Data::Thread*> thread);
|
||||
void request(not_null<Thread*> thread);
|
||||
|
||||
void apply(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
@@ -50,25 +54,25 @@ public:
|
||||
MsgId topicRootId,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
void apply(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
not_null<ForumTopic*> topic,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
|
||||
void update(
|
||||
not_null<Data::Thread*> thread,
|
||||
Data::MuteValue muteForSeconds,
|
||||
not_null<Thread*> thread,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt,
|
||||
std::optional<bool> storiesMuted = std::nullopt);
|
||||
void resetToDefault(not_null<Data::Thread*> thread);
|
||||
void resetToDefault(not_null<Thread*> thread);
|
||||
void update(
|
||||
not_null<PeerData*> peer,
|
||||
Data::MuteValue muteForSeconds,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt,
|
||||
std::optional<bool> storiesMuted = std::nullopt);
|
||||
void resetToDefault(not_null<PeerData*> peer);
|
||||
|
||||
void forumParentMuteUpdated(not_null<Data::Forum*> forum);
|
||||
void forumParentMuteUpdated(not_null<Forum*> forum);
|
||||
|
||||
void cacheSound(DocumentId id);
|
||||
void cacheSound(not_null<DocumentData*> document);
|
||||
@@ -81,21 +85,19 @@ public:
|
||||
|
||||
[[nodiscard]] const PeerNotifySettings &defaultSettings(
|
||||
DefaultNotify type) const;
|
||||
[[nodiscard]] bool isMuted(DefaultNotify type) const;
|
||||
|
||||
void defaultUpdate(
|
||||
DefaultNotify type,
|
||||
Data::MuteValue muteForSeconds,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt,
|
||||
std::optional<bool> storiesMuted = std::nullopt);
|
||||
|
||||
[[nodiscard]] bool isMuted(not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] NotifySound sound(
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] bool muteUnknown(
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] bool soundUnknown(
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] bool isMuted(not_null<const Thread*> thread) const;
|
||||
[[nodiscard]] NotifySound sound(not_null<const Thread*> thread) const;
|
||||
[[nodiscard]] bool muteUnknown(not_null<const Thread*> thread) const;
|
||||
[[nodiscard]] bool soundUnknown(not_null<const Thread*> thread) const;
|
||||
|
||||
[[nodiscard]] bool isMuted(not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool silentPosts(not_null<const PeerData*> peer) const;
|
||||
@@ -105,7 +107,17 @@ public:
|
||||
not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool soundUnknown(not_null<const PeerData*> peer) const;
|
||||
|
||||
void loadExceptions();
|
||||
[[nodiscard]] rpl::producer<DefaultNotify> exceptionsUpdates() const;
|
||||
[[nodiscard]] auto exceptionsUpdatesRealtime() const
|
||||
-> rpl::producer<DefaultNotify>;
|
||||
[[nodiscard]] const base::flat_set<not_null<PeerData*>> &exceptions(
|
||||
DefaultNotify type) const;
|
||||
void clearExceptions(DefaultNotify type);
|
||||
|
||||
private:
|
||||
static constexpr auto kDefaultNotifyTypes = 3;
|
||||
|
||||
struct DefaultValue {
|
||||
PeerNotifySettings settings;
|
||||
rpl::event_stream<> updates;
|
||||
@@ -114,7 +126,7 @@ private:
|
||||
void cacheSound(const std::optional<NotifySound> &sound);
|
||||
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const Data::Thread*> thread,
|
||||
not_null<const Thread*> thread,
|
||||
crl::time *changesIn) const;
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const PeerData*> peer,
|
||||
@@ -126,21 +138,22 @@ private:
|
||||
not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool settingsUnknown(not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool settingsUnknown(
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
not_null<const Thread*> thread) const;
|
||||
|
||||
void unmuteByFinished();
|
||||
void unmuteByFinishedDelayed(crl::time delay);
|
||||
void updateLocal(not_null<Data::Thread*> thread);
|
||||
void updateLocal(not_null<Thread*> thread);
|
||||
void updateLocal(not_null<PeerData*> peer);
|
||||
void updateLocal(DefaultNotify type);
|
||||
|
||||
void updateException(not_null<PeerData*> peer);
|
||||
void exceptionsUpdated(DefaultNotify type);
|
||||
|
||||
const not_null<Session*> _owner;
|
||||
|
||||
DefaultValue _defaultValues[3];
|
||||
std::unordered_set<not_null<const PeerData*>> _mutedPeers;
|
||||
std::unordered_map<
|
||||
not_null<Data::ForumTopic*>,
|
||||
rpl::lifetime> _mutedTopics;
|
||||
std::unordered_map<not_null<ForumTopic*>, rpl::lifetime> _mutedTopics;
|
||||
base::Timer _unmuteByFinishedTimer;
|
||||
|
||||
struct {
|
||||
@@ -151,6 +164,14 @@ private:
|
||||
rpl::lifetime pendingLifetime;
|
||||
} _ringtones;
|
||||
|
||||
rpl::event_stream<DefaultNotify> _exceptionsUpdates;
|
||||
rpl::event_stream<DefaultNotify> _exceptionsUpdatesRealtime;
|
||||
std::array<
|
||||
base::flat_set<not_null<PeerData*>>,
|
||||
kDefaultNotifyTypes> _exceptions;
|
||||
std::array<mtpRequestId, kDefaultNotifyTypes> _exceptionsRequestId = {};
|
||||
std::array<bool, kDefaultNotifyTypes> _exceptionsUpdatesScheduled = {};
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
|
||||
@@ -256,6 +256,15 @@ bool PeerNotifySettings::change(
|
||||
SerializeSound(std::nullopt))); // stories_sound
|
||||
}
|
||||
|
||||
bool PeerNotifySettings::resetToDefault() {
|
||||
if (_known && !_value) {
|
||||
return false;
|
||||
}
|
||||
_known = true;
|
||||
_value = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<TimeId> PeerNotifySettings::muteUntil() const {
|
||||
return _value
|
||||
? _value->muteUntil()
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound,
|
||||
std::optional<bool> storiesMuted);
|
||||
bool resetToDefault();
|
||||
|
||||
bool settingsUnknown() const;
|
||||
std::optional<TimeId> muteUntil() const;
|
||||
|
||||
@@ -23,6 +23,12 @@ DialogRow {
|
||||
unreadMarkDiameter: pixels;
|
||||
}
|
||||
|
||||
ThreeStateIcon {
|
||||
icon: icon;
|
||||
over: icon;
|
||||
active: icon;
|
||||
}
|
||||
|
||||
ForumTopicIcon {
|
||||
size: pixels;
|
||||
font: font;
|
||||
@@ -316,38 +322,56 @@ dialogSearchFrom: IconButton(dialogCalendar) {
|
||||
}
|
||||
|
||||
dialogsChatTypeSkip: 3px;
|
||||
dialogsChatIcon: icon {{ "dialogs/dialogs_chat", dialogsChatIconFg, point(1px, 4px) }};
|
||||
dialogsChatIconOver: icon {{ "dialogs/dialogs_chat", dialogsChatIconFgOver, point(1px, 4px) }};
|
||||
dialogsChatIconActive: icon {{ "dialogs/dialogs_chat", dialogsChatIconFgActive, point(1px, 4px) }};
|
||||
dialogsChannelIcon: icon {{ "dialogs/dialogs_channel", dialogsChatIconFg, point(3px, 4px) }};
|
||||
dialogsChannelIconOver: icon {{ "dialogs/dialogs_channel", dialogsChatIconFgOver, point(3px, 4px) }};
|
||||
dialogsChannelIconActive: icon {{ "dialogs/dialogs_channel", dialogsChatIconFgActive, point(3px, 4px) }};
|
||||
dialogsBotIcon: icon {{ "dialogs/dialogs_bot", dialogsChatIconFg, point(1px, 3px) }};
|
||||
dialogsBotIconOver: icon {{ "dialogs/dialogs_bot", dialogsChatIconFgOver, point(1px, 3px) }};
|
||||
dialogsBotIconActive: icon {{ "dialogs/dialogs_bot", dialogsChatIconFgActive, point(1px, 3px) }};
|
||||
dialogsForumIcon: icon {{ "dialogs/dialogs_forum", dialogsChatIconFg, point(1px, 4px) }};
|
||||
dialogsForumIconOver: icon {{ "dialogs/dialogs_forum", dialogsChatIconFgOver, point(1px, 4px) }};
|
||||
dialogsForumIconActive: icon {{ "dialogs/dialogs_forum", dialogsChatIconFgActive, point(1px, 4px) }};
|
||||
dialogsChatIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_chat", dialogsChatIconFg, point(1px, 4px) }};
|
||||
over: icon {{ "dialogs/dialogs_chat", dialogsChatIconFgOver, point(1px, 4px) }};
|
||||
active: icon {{ "dialogs/dialogs_chat", dialogsChatIconFgActive, point(1px, 4px) }};
|
||||
}
|
||||
dialogsChannelIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_channel", dialogsChatIconFg, point(3px, 4px) }};
|
||||
over: icon {{ "dialogs/dialogs_channel", dialogsChatIconFgOver, point(3px, 4px) }};
|
||||
active: icon {{ "dialogs/dialogs_channel", dialogsChatIconFgActive, point(3px, 4px) }};
|
||||
}
|
||||
dialogsBotIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_bot", dialogsChatIconFg, point(1px, 3px) }};
|
||||
over: icon {{ "dialogs/dialogs_bot", dialogsChatIconFgOver, point(1px, 3px) }};
|
||||
active: icon {{ "dialogs/dialogs_bot", dialogsChatIconFgActive, point(1px, 3px) }};
|
||||
}
|
||||
dialogsForumIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_forum", dialogsChatIconFg, point(1px, 4px) }};
|
||||
over: icon {{ "dialogs/dialogs_forum", dialogsChatIconFgOver, point(1px, 4px) }};
|
||||
active: icon {{ "dialogs/dialogs_forum", dialogsChatIconFgActive, point(1px, 4px) }};
|
||||
}
|
||||
dialogsArchiveUserpic: icon {{ "archive_userpic", historyPeerUserpicFg }};
|
||||
dialogsRepliesUserpic: icon {{ "replies_userpic", historyPeerUserpicFg }};
|
||||
dialogsInaccessibleUserpic: icon {{ "dialogs/inaccessible_userpic", historyPeerUserpicFg }};
|
||||
|
||||
dialogsSendStateSkip: 20px;
|
||||
dialogsSendingIcon: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFg, point(8px, 4px) }};
|
||||
dialogsSendingIconOver: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFgOver, point(8px, 4px) }};
|
||||
dialogsSendingIconActive: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFgActive, point(8px, 4px) }};
|
||||
dialogsSentIcon: icon {{ "dialogs/dialogs_sent", dialogsSentIconFg, point(10px, 4px) }};
|
||||
dialogsSentIconOver: icon {{ "dialogs/dialogs_sent", dialogsSentIconFgOver, point(10px, 4px) }};
|
||||
dialogsSentIconActive: icon {{ "dialogs/dialogs_sent", dialogsSentIconFgActive, point(10px, 4px) }};
|
||||
dialogsReceivedIcon: icon {{ "dialogs/dialogs_received", dialogsSentIconFg, point(5px, 4px) }};
|
||||
dialogsReceivedIconOver: icon {{ "dialogs/dialogs_received", dialogsSentIconFgOver, point(5px, 4px) }};
|
||||
dialogsReceivedIconActive: icon {{ "dialogs/dialogs_received", dialogsSentIconFgActive, point(5px, 4px) }};
|
||||
dialogsPinnedIcon: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMuted }};
|
||||
dialogsPinnedIconOver: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMutedOver }};
|
||||
dialogsPinnedIconActive: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMutedActive }};
|
||||
dialogsLockIcon: icon {{ "emoji/premium_lock", dialogsUnreadBgMuted, point(4px, 0px) }};
|
||||
dialogsLockIconOver: icon {{ "emoji/premium_lock", dialogsUnreadBgMutedOver, point(4px, 0px) }};
|
||||
dialogsLockIconActive: icon {{ "emoji/premium_lock", dialogsUnreadBgMutedActive, point(4px, 0px) }};
|
||||
dialogsSendingIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFg, point(8px, 4px) }};
|
||||
over: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFgOver, point(8px, 4px) }};
|
||||
active: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFgActive, point(8px, 4px) }};
|
||||
}
|
||||
dialogsSentIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_sent", dialogsSentIconFg, point(10px, 4px) }};
|
||||
over: icon {{ "dialogs/dialogs_sent", dialogsSentIconFgOver, point(10px, 4px) }};
|
||||
active: icon {{ "dialogs/dialogs_sent", dialogsSentIconFgActive, point(10px, 4px) }};
|
||||
}
|
||||
dialogsReceivedIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_received", dialogsSentIconFg, point(5px, 4px) }};
|
||||
over: icon {{ "dialogs/dialogs_received", dialogsSentIconFgOver, point(5px, 4px) }};
|
||||
active: icon {{ "dialogs/dialogs_received", dialogsSentIconFgActive, point(5px, 4px) }};
|
||||
}
|
||||
dialogsPinnedIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMuted }};
|
||||
over: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMutedOver }};
|
||||
active: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMutedActive }};
|
||||
}
|
||||
dialogsLockIcon: ThreeStateIcon {
|
||||
icon: icon {{ "emoji/premium_lock", dialogsUnreadBgMuted, point(4px, 0px) }};
|
||||
over: icon {{ "emoji/premium_lock", dialogsUnreadBgMutedOver, point(4px, 0px) }};
|
||||
active: icon {{ "emoji/premium_lock", dialogsUnreadBgMutedActive, point(4px, 0px) }};
|
||||
}
|
||||
|
||||
dialogsVerifiedIcon: icon {
|
||||
{ "dialogs/dialogs_verified_star", dialogsVerifiedIconBg },
|
||||
@@ -361,9 +385,11 @@ dialogsVerifiedIconActive: icon {
|
||||
{ "dialogs/dialogs_verified_star", dialogsVerifiedIconBgActive },
|
||||
{ "dialogs/dialogs_verified_check", dialogsVerifiedIconFgActive },
|
||||
};
|
||||
dialogsPremiumIcon: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBg }};
|
||||
dialogsPremiumIconOver: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBgOver }};
|
||||
dialogsPremiumIconActive: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBgActive }};
|
||||
dialogsPremiumIcon: ThreeStateIcon {
|
||||
icon: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBg }};
|
||||
over: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBgOver }};
|
||||
active: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBgActive }};
|
||||
}
|
||||
|
||||
historySendingIcon: icon {{ "dialogs/dialogs_sending", historySendingOutIconFg, point(5px, 5px) }};
|
||||
historySendingInvertedIcon: icon {{ "dialogs/dialogs_sending", historySendingInvertedIconFg, point(5px, 5px) }};
|
||||
@@ -436,12 +462,28 @@ dialogsMiniPreviewSkip: 2px;
|
||||
dialogsMiniPreviewRight: 3px;
|
||||
dialogsMiniPlay: icon{{ "dialogs/dialogs_mini_play", videoPlayIconFg }};
|
||||
|
||||
dialogsUnreadMention: icon{{ "dialogs/dialogs_mention", dialogsUnreadFg }};
|
||||
dialogsUnreadMentionOver: icon{{ "dialogs/dialogs_mention", dialogsUnreadFgOver }};
|
||||
dialogsUnreadMentionActive: icon{{ "dialogs/dialogs_mention", dialogsUnreadFgActive }};
|
||||
dialogsUnreadReaction: icon{{ "dialogs/dialogs_reaction", dialogsUnreadFg }};
|
||||
dialogsUnreadReactionOver: icon{{ "dialogs/dialogs_reaction", dialogsUnreadFgOver }};
|
||||
dialogsUnreadReactionActive: icon{{ "dialogs/dialogs_reaction", dialogsUnreadFgActive }};
|
||||
dialogsMiniForwardIcon: ThreeStateIcon {
|
||||
icon: icon {{ "mini_forward", dialogsTextFg, point(0px, 1px) }};
|
||||
over: icon {{ "mini_forward", dialogsTextFgOver, point(0px, 1px) }};
|
||||
active: icon {{ "mini_forward", dialogsTextFgActive, point(0px, 1px) }};
|
||||
}
|
||||
dialogsMiniIconSkip: 2px;
|
||||
dialogsMiniReplyStoryIcon: ThreeStateIcon {
|
||||
icon: icon {{ "mini_reply_story", dialogsTextFg, point(0px, 1px) }};
|
||||
over: icon {{ "mini_reply_story", dialogsTextFgOver, point(0px, 1px) }};
|
||||
active: icon {{ "mini_reply_story", dialogsTextFgActive, point(0px, 1px) }};
|
||||
}
|
||||
|
||||
dialogsUnreadMention: ThreeStateIcon {
|
||||
icon: icon{{ "dialogs/dialogs_mention", dialogsUnreadFg }};
|
||||
over: icon{{ "dialogs/dialogs_mention", dialogsUnreadFgOver }};
|
||||
active: icon{{ "dialogs/dialogs_mention", dialogsUnreadFgActive }};
|
||||
}
|
||||
dialogsUnreadReaction: ThreeStateIcon {
|
||||
icon: icon{{ "dialogs/dialogs_reaction", dialogsUnreadFg }};
|
||||
over: icon{{ "dialogs/dialogs_reaction", dialogsUnreadFgOver }};
|
||||
active: icon{{ "dialogs/dialogs_reaction", dialogsUnreadFgActive }};
|
||||
}
|
||||
|
||||
downloadBarHeight: 46px;
|
||||
downloadArrow: icon{{ "fast_to_original", menuIconFg }};
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "dialogs/dialogs_inner_widget.h"
|
||||
|
||||
#include "dialogs/dialogs_three_state_icon.h"
|
||||
#include "dialogs/ui/dialogs_layout.h"
|
||||
#include "dialogs/ui/dialogs_stories_content.h"
|
||||
#include "dialogs/ui/dialogs_stories_list.h"
|
||||
@@ -1010,11 +1011,10 @@ void InnerWidget::paintPeerSearchResult(
|
||||
: context.selected
|
||||
? &st::dialogsVerifiedIconOver
|
||||
: &st::dialogsVerifiedIcon),
|
||||
.premium = (context.active
|
||||
? &st::dialogsPremiumIconActive
|
||||
: context.selected
|
||||
? &st::dialogsPremiumIconOver
|
||||
: &st::dialogsPremiumIcon),
|
||||
.premium = &ThreeStateIcon(
|
||||
st::dialogsPremiumIcon,
|
||||
context.active,
|
||||
context.selected),
|
||||
.scam = (context.active
|
||||
? &st::dialogsScamFgActive
|
||||
: context.selected
|
||||
|
||||
@@ -194,6 +194,11 @@ UnreadState MainList::unreadState() const {
|
||||
result.chatsMuted = result.chats;
|
||||
result.marksMuted = result.marks;
|
||||
}
|
||||
volatile auto touch = _unreadState.marks + _unreadState.marksMuted
|
||||
+ _unreadState.messages + _unreadState.messagesMuted
|
||||
+ _unreadState.chats + _unreadState.chatsMuted
|
||||
+ _unreadState.reactions + _unreadState.reactionsMuted
|
||||
+ _unreadState.mentions;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
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
|
||||
|
||||
#include "styles/style_dialogs.h"
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
[[nodiscard]] inline const style::icon &ThreeStateIcon(
|
||||
const style::ThreeStateIcon &icons,
|
||||
bool active,
|
||||
bool over) {
|
||||
return active ? icons.active : over ? icons.over : icons.icon;
|
||||
}
|
||||
|
||||
} // namespace Dialogs
|
||||
@@ -1339,7 +1339,7 @@ void Widget::checkUpdateStatus() {
|
||||
}
|
||||
_updateTelegram.create(
|
||||
this,
|
||||
tr::lng_update_telegram(tr::now),
|
||||
tr::ayu_UpdateAyuGram(tr::now),
|
||||
st::dialogsUpdateButton,
|
||||
st::dialogsInstallUpdate,
|
||||
st::dialogsInstallUpdateOver);
|
||||
|
||||
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_session.h"
|
||||
#include "dialogs/dialogs_list.h"
|
||||
#include "dialogs/dialogs_three_state_icon.h"
|
||||
#include "dialogs/ui/dialogs_video_userpic.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_window.h"
|
||||
@@ -147,11 +148,10 @@ int PaintBadges(
|
||||
const auto badge = PaintUnreadBadge(p, counter, right, top, st);
|
||||
right -= badge.width() + st.padding;
|
||||
} else if (displayPinnedIcon) {
|
||||
const auto &icon = context.active
|
||||
? st::dialogsPinnedIconActive
|
||||
: context.selected
|
||||
? st::dialogsPinnedIconOver
|
||||
: st::dialogsPinnedIcon;
|
||||
const auto &icon = ThreeStateIcon(
|
||||
st::dialogsPinnedIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
icon.paint(p, right - icon.width(), pinnedIconTop, context.width);
|
||||
right -= icon.width() + st::dialogsUnreadPadding;
|
||||
}
|
||||
@@ -169,17 +169,12 @@ int PaintBadges(
|
||||
st.textTop = 0;
|
||||
const auto counter = QString();
|
||||
const auto badge = PaintUnreadBadge(p, counter, right, top, st);
|
||||
(badgesState.mention
|
||||
? (st.active
|
||||
? st::dialogsUnreadMentionActive
|
||||
: st.selected
|
||||
? st::dialogsUnreadMentionOver
|
||||
: st::dialogsUnreadMention)
|
||||
: (st.active
|
||||
? st::dialogsUnreadReactionActive
|
||||
: st.selected
|
||||
? st::dialogsUnreadReactionOver
|
||||
: st::dialogsUnreadReaction)).paintInCenter(p, badge);
|
||||
ThreeStateIcon(
|
||||
badgesState.mention
|
||||
? st::dialogsUnreadMention
|
||||
: st::dialogsUnreadReaction,
|
||||
st.active,
|
||||
st.selected).paintInCenter(p, badge);
|
||||
right -= badge.width() + st.padding + st::dialogsUnreadPadding;
|
||||
}
|
||||
return (initial - right);
|
||||
@@ -437,11 +432,10 @@ void PaintRow(
|
||||
auto availableWidth = namewidth;
|
||||
if (entry->isPinnedDialog(context.filter)
|
||||
&& (context.filter || !entry->fixedOnTopIndex())) {
|
||||
auto &icon = context.active
|
||||
? st::dialogsPinnedIconActive
|
||||
: context.selected
|
||||
? st::dialogsPinnedIconOver
|
||||
: st::dialogsPinnedIcon;
|
||||
auto &icon = ThreeStateIcon(
|
||||
st::dialogsPinnedIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
icon.paint(
|
||||
p,
|
||||
context.width - context.st->padding.right() - icon.width(),
|
||||
@@ -527,11 +521,10 @@ void PaintRow(
|
||||
auto availableWidth = namewidth;
|
||||
if (entry->isPinnedDialog(context.filter)
|
||||
&& (context.filter || !entry->fixedOnTopIndex())) {
|
||||
auto &icon = context.active
|
||||
? st::dialogsPinnedIconActive
|
||||
: context.selected
|
||||
? st::dialogsPinnedIconOver
|
||||
: st::dialogsPinnedIcon;
|
||||
auto &icon = ThreeStateIcon(
|
||||
st::dialogsPinnedIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
icon.paint(p, context.width - context.st->padding.right() - icon.width(), texttop, context.width);
|
||||
availableWidth -= icon.width() + st::dialogsUnreadPadding;
|
||||
}
|
||||
@@ -561,51 +554,49 @@ void PaintRow(
|
||||
paintItemCallback(nameleft, namewidth);
|
||||
} else if (entry->isPinnedDialog(context.filter)
|
||||
&& (context.filter || !entry->fixedOnTopIndex())) {
|
||||
auto &icon = context.active
|
||||
? st::dialogsPinnedIconActive
|
||||
: context.selected
|
||||
? st::dialogsPinnedIconOver
|
||||
: st::dialogsPinnedIcon;
|
||||
icon.paint(p, context.width - context.st->padding.right() - icon.width(), texttop, context.width);
|
||||
auto &icon = ThreeStateIcon(
|
||||
st::dialogsPinnedIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
icon.paint(
|
||||
p,
|
||||
context.width - context.st->padding.right() - icon.width(),
|
||||
texttop,
|
||||
context.width);
|
||||
}
|
||||
const auto sendStateIcon = [&]() -> const style::icon* {
|
||||
if (!thread) {
|
||||
return nullptr;
|
||||
} else if (const auto topic = thread->asTopic()
|
||||
; !context.search && topic && topic->closed()) {
|
||||
return &(context.active
|
||||
? st::dialogsLockIconActive
|
||||
: context.selected
|
||||
? st::dialogsLockIconOver
|
||||
: st::dialogsLockIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsLockIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
} else if (draft) {
|
||||
if (draft->saveRequestId) {
|
||||
return &(context.active
|
||||
? st::dialogsSendingIconActive
|
||||
: context.selected
|
||||
? st::dialogsSendingIconOver
|
||||
: st::dialogsSendingIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsSendingIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
}
|
||||
} else if (item && !item->isEmpty() && item->needCheck()) {
|
||||
if (!item->isSending() && !item->hasFailed()) {
|
||||
if (item->unread(thread)) {
|
||||
return &(context.active
|
||||
? st::dialogsSentIconActive
|
||||
: context.selected
|
||||
? st::dialogsSentIconOver
|
||||
: st::dialogsSentIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsSentIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
}
|
||||
return &(context.active
|
||||
? st::dialogsReceivedIconActive
|
||||
: context.selected
|
||||
? st::dialogsReceivedIconOver
|
||||
: st::dialogsReceivedIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsReceivedIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
}
|
||||
return &(context.active
|
||||
? st::dialogsSendingIconActive
|
||||
: context.selected
|
||||
? st::dialogsSendingIconOver
|
||||
: st::dialogsSendingIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsSendingIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
@@ -643,11 +634,10 @@ void PaintRow(
|
||||
: context.selected
|
||||
? &st::dialogsVerifiedIconOver
|
||||
: &st::dialogsVerifiedIcon),
|
||||
.premium = (context.active
|
||||
? &st::dialogsPremiumIconActive
|
||||
: context.selected
|
||||
? &st::dialogsPremiumIconOver
|
||||
: &st::dialogsPremiumIcon),
|
||||
.premium = &ThreeStateIcon(
|
||||
st::dialogsPremiumIcon,
|
||||
context.active,
|
||||
context.selected),
|
||||
.scam = (context.active
|
||||
? &st::dialogsScamFgActive
|
||||
: context.selected
|
||||
@@ -710,30 +700,26 @@ const style::icon *ChatTypeIcon(
|
||||
const PaintContext &context) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (ShowUserBotIcon(user)) {
|
||||
return &(context.active
|
||||
? st::dialogsBotIconActive
|
||||
: context.selected
|
||||
? st::dialogsBotIconOver
|
||||
: st::dialogsBotIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsBotIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
}
|
||||
} else if (peer->isBroadcast()) {
|
||||
return &(context.active
|
||||
? st::dialogsChannelIconActive
|
||||
: context.selected
|
||||
? st::dialogsChannelIconOver
|
||||
: st::dialogsChannelIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsChannelIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
} else if (peer->isForum()) {
|
||||
return &(context.active
|
||||
? st::dialogsForumIconActive
|
||||
: context.selected
|
||||
? st::dialogsForumIconOver
|
||||
: st::dialogsForumIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsForumIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
} else {
|
||||
return &(context.active
|
||||
? st::dialogsChatIconActive
|
||||
: context.selected
|
||||
? st::dialogsChatIconOver
|
||||
: st::dialogsChatIcon);
|
||||
return &ThreeStateIcon(
|
||||
st::dialogsChatIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_item.h"
|
||||
#include "history/view/history_view_item_preview.h"
|
||||
#include "main/main_session.h"
|
||||
#include "dialogs/dialogs_three_state_icon.h"
|
||||
#include "dialogs/ui/dialogs_layout.h"
|
||||
#include "dialogs/ui/dialogs_topics_view.h"
|
||||
#include "ui/effects/spoiler_mess.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/power_saving.h"
|
||||
#include "core/ui_integration.h"
|
||||
@@ -159,6 +159,11 @@ void MessageView::prepare(
|
||||
options.ignoreTopic = true;
|
||||
options.spoilerLoginCode = true;
|
||||
auto preview = item->toPreview(options);
|
||||
_leftIcon = (preview.icon == ItemPreview::Icon::ForwardedMessage)
|
||||
? &st::dialogsMiniForwardIcon
|
||||
: (preview.icon == ItemPreview::Icon::ReplyToStory)
|
||||
? &st::dialogsMiniReplyStoryIcon
|
||||
: nullptr;
|
||||
const auto hasImages = !preview.images.empty();
|
||||
const auto history = item->history();
|
||||
const auto context = Core::MarkedTextContext{
|
||||
@@ -169,7 +174,7 @@ void MessageView::prepare(
|
||||
const auto senderTill = (preview.arrowInTextPosition > 0)
|
||||
? preview.arrowInTextPosition
|
||||
: preview.imagesInTextPosition;
|
||||
if (hasImages && senderTill > 0) {
|
||||
if ((hasImages || _leftIcon) && senderTill > 0) {
|
||||
auto sender = Text::Mid(preview.text, 0, senderTill);
|
||||
TextUtilities::Trim(sender);
|
||||
_senderCache.setMarkedText(
|
||||
@@ -314,6 +319,15 @@ void MessageView::paint(
|
||||
rect.setLeft(rect.x() + skip);
|
||||
}
|
||||
}
|
||||
|
||||
if (_leftIcon) {
|
||||
const auto &icon = ThreeStateIcon(
|
||||
*_leftIcon,
|
||||
context.active,
|
||||
context.selected);
|
||||
icon.paint(p, rect.topLeft(), rect.width());
|
||||
rect.setLeft(rect.x() + icon.width() + st::dialogsMiniIconSkip);
|
||||
}
|
||||
for (const auto &image : _imagesCache) {
|
||||
if (rect.width() < st::dialogsMiniPreview) {
|
||||
break;
|
||||
|
||||
@@ -15,6 +15,7 @@ enum class ImageRoundRadius;
|
||||
|
||||
namespace style {
|
||||
struct DialogRow;
|
||||
struct ThreeStateIcon;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui {
|
||||
@@ -92,6 +93,7 @@ private:
|
||||
mutable std::vector<ItemPreviewImage> _imagesCache;
|
||||
mutable std::unique_ptr<SpoilerAnimation> _spoiler;
|
||||
mutable std::unique_ptr<LoadingContext> _loadingContext;
|
||||
mutable const style::ThreeStateIcon *_leftIcon = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -10,19 +10,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/algorithm.h"
|
||||
#include "logs.h"
|
||||
|
||||
#if !defined DESKTOP_APP_USE_PACKAGED && !defined Q_OS_WIN && !defined Q_OS_MAC
|
||||
#include "base/platform/linux/base_linux_library.h"
|
||||
#include <deque>
|
||||
#endif // !DESKTOP_APP_USE_PACKAGED && !Q_OS_WIN && !Q_OS_MAC
|
||||
|
||||
#include <QImage>
|
||||
|
||||
#ifdef LIB_FFMPEG_USE_QT_PRIVATE_API
|
||||
#include <private/qdrawhelper_p.h>
|
||||
#endif // LIB_FFMPEG_USE_QT_PRIVATE_API
|
||||
|
||||
#include <deque>
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/opt.h>
|
||||
#if !defined DESKTOP_APP_USE_PACKAGED && !defined Q_OS_WIN && !defined Q_OS_MAC
|
||||
#include <dlfcn.h>
|
||||
#endif // !DESKTOP_APP_USE_PACKAGED && !Q_OS_WIN && !Q_OS_MAC
|
||||
} // extern "C"
|
||||
|
||||
namespace FFmpeg {
|
||||
@@ -95,19 +95,10 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
|
||||
auto list = std::deque{
|
||||
AV_PIX_FMT_CUDA,
|
||||
};
|
||||
const auto vdpau = [&] {
|
||||
if (const auto handle = dlopen("libvdpau.so.1", RTLD_LAZY)) {
|
||||
dlclose(handle);
|
||||
}
|
||||
if (dlerror()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
if (vdpau) {
|
||||
if (base::Platform::LoadLibrary("libvdpau.so.1")) {
|
||||
list.push_front(AV_PIX_FMT_VDPAU);
|
||||
}
|
||||
const auto va = [&] {
|
||||
if ([&] {
|
||||
const auto list = std::array{
|
||||
"libva-drm.so.1",
|
||||
"libva-x11.so.1",
|
||||
@@ -115,16 +106,12 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
|
||||
"libdrm.so.2",
|
||||
};
|
||||
for (const auto lib : list) {
|
||||
if (const auto handle = dlopen(lib, RTLD_LAZY)) {
|
||||
dlclose(handle);
|
||||
}
|
||||
if (dlerror()) {
|
||||
if (!base::Platform::LoadLibrary(lib)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
if (va) {
|
||||
}()) {
|
||||
list.push_front(AV_PIX_FMT_VAAPI);
|
||||
}
|
||||
return list;
|
||||
|
||||
@@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_inner_widget.h"
|
||||
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "history/history.h"
|
||||
#include "history/admin_log/history_admin_log_item.h"
|
||||
@@ -32,7 +31,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||
#include "ui/widgets/menu/menu_multiline_action.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/effects/path_shift_gradient.h"
|
||||
#include "ui/effects/message_sending_animation_controller.h"
|
||||
#include "ui/effects/reaction_fly_animation.h"
|
||||
@@ -40,16 +38,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/boxes/report_box.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/controls/delete_message_context_action.h"
|
||||
#include "ui/controls/who_reacted_context_action.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "ui/inactive_press.h"
|
||||
#include "window/window_adaptive.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "boxes/about_sponsored_box.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
@@ -94,12 +88,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_sponsored_messages.h"
|
||||
#include "dialogs/ui/dialogs_video_userpic.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_window.h" // st::windowMinWidth
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
@@ -15,17 +15,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/history_view_message.h"
|
||||
#include "history/view/history_view_service_message.h"
|
||||
#include "history/view/media/history_view_media_grouped.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "history/history_unread_things.h"
|
||||
#include "history/history.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_isolated_emoji.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "storage/file_upload.h"
|
||||
#include "storage/storage_facade.h"
|
||||
@@ -41,7 +38,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwindow.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/timer_rpl.h"
|
||||
@@ -72,7 +68,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "chat_helpers/stickers_gift_box_pack.h"
|
||||
#include "payments/payments_checkout_process.h" // CheckoutProcess::Start.
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
@@ -2972,6 +2967,11 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
|
||||
? tr::lng_from_you(tr::now)
|
||||
: sender->shortName();
|
||||
};
|
||||
result.icon = (Get<HistoryMessageForwarded>() != nullptr)
|
||||
? ItemPreview::Icon::ForwardedMessage
|
||||
: replyToStory().valid()
|
||||
? ItemPreview::Icon::ReplyToStory
|
||||
: ItemPreview::Icon::None;
|
||||
const auto fromForwarded = [&]() -> std::optional<QString> {
|
||||
if (const auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||
return forwarded->originalSender
|
||||
|
||||
@@ -43,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_bot.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_dialogs.h" // dialogsMiniReplyStoryIcon.
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
||||
@@ -460,7 +461,14 @@ void HistoryMessageReply::updateName(
|
||||
w += st::msgServiceFont->spacew + replyToVia->maxWidth;
|
||||
}
|
||||
|
||||
maxReplyWidth = previewSkip + qMax(w, qMin(replyToText.maxWidth(), int32(st::maxSignatureSize)));
|
||||
maxReplyWidth = previewSkip
|
||||
+ std::max(
|
||||
w,
|
||||
std::min(replyToText.maxWidth(), st::maxSignatureSize))
|
||||
+ (storyReply
|
||||
? (st::dialogsMiniIconSkip
|
||||
+ st::dialogsMiniReplyStoryIcon.icon.width())
|
||||
: 0);
|
||||
} else {
|
||||
maxReplyWidth = st::msgDateFont->width(statePhrase());
|
||||
}
|
||||
@@ -596,14 +604,27 @@ void HistoryMessageReply::paint(
|
||||
? stm->historyTextFg
|
||||
: st->msgImgReplyBarColor());
|
||||
holder->prepareCustomEmojiPaint(p, context, replyToText);
|
||||
auto replyToTextPosition = QPoint(
|
||||
x + st::msgReplyBarSkip + previewSkip,
|
||||
y + st::msgReplyPadding.top() + st::msgServiceNameFont->height);
|
||||
const auto replyToTextPalette = &(inBubble
|
||||
? stm->replyTextPalette
|
||||
: st->imgReplyTextPalette());
|
||||
if (storyReply) {
|
||||
st::dialogsMiniReplyStoryIcon.icon.paint(
|
||||
p,
|
||||
replyToTextPosition,
|
||||
w - st::msgReplyBarSkip - previewSkip,
|
||||
replyToTextPalette->linkFg->c);
|
||||
replyToTextPosition += QPoint(
|
||||
st::dialogsMiniIconSkip
|
||||
+ st::dialogsMiniReplyStoryIcon.icon.width(),
|
||||
0);
|
||||
}
|
||||
replyToText.draw(p, {
|
||||
.position = QPoint(
|
||||
x + st::msgReplyBarSkip + previewSkip,
|
||||
y + st::msgReplyPadding.top() + st::msgServiceNameFont->height),
|
||||
.position = replyToTextPosition,
|
||||
.availableWidth = w - st::msgReplyBarSkip - previewSkip,
|
||||
.palette = &(inBubble
|
||||
? stm->replyTextPalette
|
||||
: st->imgReplyTextPalette()),
|
||||
.palette = replyToTextPalette,
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
.pausedEmoji = (context.paused
|
||||
|
||||
@@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_chat_participants.h"
|
||||
#include "api/api_report.h"
|
||||
#include "api/api_sending.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_send_progress.h"
|
||||
#include "api/api_unread_things.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
@@ -32,12 +31,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/inner_dropdown.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/effects/message_sending_animation_controller.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/chat/forward_options_box.h"
|
||||
#include "ui/chat/message_bar.h"
|
||||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
#include "ui/chat/choose_send_as.h"
|
||||
@@ -62,7 +59,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_forum.h"
|
||||
@@ -107,7 +103,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/history_view_translate_bar.h"
|
||||
#include "history/view/media/history_view_media.h"
|
||||
#include "profile/profile_block_group_members.h"
|
||||
#include "info/info_memento.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
@@ -138,7 +133,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/chat/continuous_scroll.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/item_text_options.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "main/session/send_as_peers.h"
|
||||
@@ -152,7 +146,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "inline_bots/bot_attach_web_view.h"
|
||||
#include "info/profile/info_profile_values.h" // SharedMediaCountValue.
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/shortcuts.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "support/support_common.h"
|
||||
@@ -160,12 +153,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "support/support_preload.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "api/api_bot.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_profile.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
|
||||
@@ -23,11 +23,17 @@ struct ItemPreviewImage {
|
||||
};
|
||||
|
||||
struct ItemPreview {
|
||||
enum class Icon {
|
||||
None,
|
||||
ForwardedMessage,
|
||||
ReplyToStory,
|
||||
};
|
||||
TextWithEntities text;
|
||||
std::vector<ItemPreviewImage> images;
|
||||
int arrowInTextPosition = -1;
|
||||
int imagesInTextPosition = 0;
|
||||
std::any loadingContext;
|
||||
Icon icon = Icon::None;
|
||||
};
|
||||
|
||||
struct ToPreviewOptions {
|
||||
|
||||
@@ -759,7 +759,9 @@ QSize Message::performCountOptimalSize() {
|
||||
: item->hiddenSenderInfo()->nameText();
|
||||
auto namew = st::msgPadding.left()
|
||||
+ name.maxWidth()
|
||||
+ (_fromNameStatus ? st::dialogsPremiumIcon.width() : 0)
|
||||
+ (_fromNameStatus
|
||||
? st::dialogsPremiumIcon.icon.width()
|
||||
: 0)
|
||||
+ st::msgPadding.right();
|
||||
if (via && !displayForwardedFrom()) {
|
||||
namew += st::msgServiceFont->spacew + via->maxWidth
|
||||
@@ -1358,7 +1360,7 @@ void Message::paintFromName(
|
||||
return &info->nameText();
|
||||
}();
|
||||
const auto statusWidth = _fromNameStatus
|
||||
? st::dialogsPremiumIcon.width()
|
||||
? st::dialogsPremiumIcon.icon.width()
|
||||
: 0;
|
||||
if (statusWidth && availableWidth > statusWidth) {
|
||||
const auto x = availableLeft
|
||||
@@ -1398,7 +1400,7 @@ void Message::paintFromName(
|
||||
.paused = context.paused || On(PowerSaving::kEmojiStatus),
|
||||
});
|
||||
} else {
|
||||
st::dialogsPremiumIcon.paint(p, x, y, width(), color);
|
||||
st::dialogsPremiumIcon.icon.paint(p, x, y, width(), color);
|
||||
}
|
||||
availableWidth -= statusWidth;
|
||||
}
|
||||
@@ -1407,7 +1409,8 @@ void Message::paintFromName(
|
||||
nameText->drawElided(p, availableLeft, trect.top(), availableWidth);
|
||||
const auto skipWidth = nameText->maxWidth()
|
||||
+ (_fromNameStatus
|
||||
? (st::dialogsPremiumIcon.width() + st::msgServiceFont->spacew)
|
||||
? (st::dialogsPremiumIcon.icon.width()
|
||||
+ st::msgServiceFont->spacew)
|
||||
: 0)
|
||||
+ st::msgServiceFont->spacew;
|
||||
availableLeft += skipWidth;
|
||||
@@ -3525,7 +3528,7 @@ void Message::fromNameUpdated(int width) const {
|
||||
- st::msgPadding.right()
|
||||
- nameText->maxWidth()
|
||||
+ (_fromNameStatus
|
||||
? (st::dialogsPremiumIcon.width()
|
||||
? (st::dialogsPremiumIcon.icon.width()
|
||||
+ st::msgServiceFont->spacew)
|
||||
: 0)
|
||||
- st::msgServiceFont->spacew);
|
||||
|
||||
@@ -566,7 +566,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
||||
{
|
||||
.peer = peer,
|
||||
.verified = &st::dialogsVerifiedIcon,
|
||||
.premium = &st::dialogsPremiumIcon,
|
||||
.premium = &st::dialogsPremiumIcon.icon,
|
||||
.scam = &st::attentionButtonFg,
|
||||
.premiumFg = &st::dialogsVerifiedIconBg,
|
||||
.customEmojiRepaint = [=] { update(); },
|
||||
|
||||
@@ -241,7 +241,7 @@ int Selector::countWidth(int desiredWidth, int maxWidth) {
|
||||
return std::max(2 * _skipx + _columns * _size, desiredWidth);
|
||||
}
|
||||
|
||||
QMargins Selector::extentsForShadow() const {
|
||||
QMargins Selector::marginsForShadow() const {
|
||||
const auto line = st::lineWidth;
|
||||
return useTransparency()
|
||||
? st::reactionCornerShadow
|
||||
@@ -264,26 +264,26 @@ void Selector::setSpecialExpandTopSkip(int skip) {
|
||||
}
|
||||
|
||||
void Selector::initGeometry(int innerTop) {
|
||||
const auto extents = extentsForShadow();
|
||||
const auto margins = marginsForShadow();
|
||||
const auto parent = parentWidget()->rect();
|
||||
const auto innerWidth = 2 * _skipx + _columns * _size;
|
||||
const auto innerHeight = st::reactStripHeight;
|
||||
const auto width = _useTransparency
|
||||
? (innerWidth + extents.left() + extents.right())
|
||||
? (innerWidth + margins.left() + margins.right())
|
||||
: parent.width();
|
||||
const auto height = innerHeight + extents.top() + extents.bottom();
|
||||
const auto height = innerHeight + margins.top() + margins.bottom();
|
||||
const auto left = style::RightToLeft() ? 0 : (parent.width() - width);
|
||||
_collapsedTopSkip = _useTransparency
|
||||
? (extendTopForCategories() + _specialExpandTopSkip)
|
||||
: 0;
|
||||
const auto top = innerTop - extents.top() - _collapsedTopSkip;
|
||||
const auto add = _st.icons.stripBubble.height() - extents.bottom();
|
||||
const auto top = innerTop - margins.top() - _collapsedTopSkip;
|
||||
const auto add = _st.icons.stripBubble.height() - margins.bottom();
|
||||
_outer = QRect(0, _collapsedTopSkip, width, height);
|
||||
_outerWithBubble = _outer.marginsAdded({ 0, 0, 0, add });
|
||||
setGeometry(_outerWithBubble.marginsAdded(
|
||||
{ 0, _collapsedTopSkip, 0, 0 }
|
||||
).translated(left, top));
|
||||
_inner = _outer.marginsRemoved(extents);
|
||||
_inner = _outer.marginsRemoved(margins);
|
||||
|
||||
if (!_strip) {
|
||||
expand();
|
||||
@@ -343,9 +343,9 @@ void Selector::paintAppearing(QPainter &p) {
|
||||
}
|
||||
_paintBuffer.fill(_st.bg->c);
|
||||
auto q = QPainter(&_paintBuffer);
|
||||
const auto extents = extentsForShadow();
|
||||
const auto margins = marginsForShadow();
|
||||
const auto appearedWidth = countAppearedWidth(_appearProgress);
|
||||
const auto fullWidth = _inner.x() + appearedWidth + extents.right();
|
||||
const auto fullWidth = _inner.x() + appearedWidth + margins.right();
|
||||
const auto size = QSize(fullWidth, _outer.height());
|
||||
|
||||
q.translate(_inner.topLeft() - QPoint(0, _collapsedTopSkip));
|
||||
@@ -455,7 +455,7 @@ auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
||||
const auto radius = _reactions.customAllowed
|
||||
? (radiusStart + progress * (radiusEnd - radiusStart))
|
||||
: radiusStart;
|
||||
const auto extents = extentsForShadow();
|
||||
const auto margins = marginsForShadow();
|
||||
const auto expanding = anim::easeOutCirc(1., progress);
|
||||
const auto expandUp = anim::interpolate(0, _collapsedTopSkip, expanding);
|
||||
const auto expandDown = anim::interpolate(
|
||||
@@ -470,7 +470,7 @@ auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
||||
p.fillRect(fill, _st.bg);
|
||||
}
|
||||
} else {
|
||||
const auto inner = outer.marginsRemoved(extentsForShadow());
|
||||
const auto inner = outer.marginsRemoved(marginsForShadow());
|
||||
p.fillRect(inner, _st.bg);
|
||||
p.fillRect(
|
||||
inner.x(),
|
||||
@@ -483,7 +483,7 @@ auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
||||
0,
|
||||
extendTopForCategories(),
|
||||
expanding);
|
||||
const auto inner = outer.marginsRemoved(extents);
|
||||
const auto inner = outer.marginsRemoved(margins);
|
||||
_shadowTop = inner.y() + categories;
|
||||
_shadowSkip = (_useTransparency && categories < radius)
|
||||
? int(base::SafeRound(
|
||||
@@ -494,7 +494,7 @@ auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
||||
.list = inner.marginsRemoved({ 0, categories, 0, 0 }),
|
||||
.radius = radius,
|
||||
.expanding = expanding,
|
||||
.finalBottom = height() - extents.bottom(),
|
||||
.finalBottom = height() - margins.bottom(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -521,7 +521,7 @@ void Selector::paintExpanded(QPainter &p) {
|
||||
if (_useTransparency) {
|
||||
p.drawImage(0, 0, _paintBuffer);
|
||||
} else {
|
||||
const auto inner = rect().marginsRemoved(extentsForShadow());
|
||||
const auto inner = rect().marginsRemoved(marginsForShadow());
|
||||
p.fillRect(inner, _st.bg);
|
||||
p.fillRect(
|
||||
inner.x(),
|
||||
@@ -694,13 +694,13 @@ void Selector::expand() {
|
||||
_willExpand.fire({});
|
||||
preloadAllRecentsAnimations();
|
||||
const auto parent = parentWidget()->geometry();
|
||||
const auto extents = extentsForShadow();
|
||||
const auto margins = marginsForShadow();
|
||||
const auto heightLimit = _reactions.customAllowed
|
||||
? st::emojiPanMaxHeight
|
||||
: minimalHeight();
|
||||
const auto willBeHeight = std::min(
|
||||
parent.height() - y(),
|
||||
extents.top() + heightLimit + extents.bottom());
|
||||
margins.top() + heightLimit + margins.bottom());
|
||||
const auto additionalBottom = willBeHeight - height();
|
||||
const auto additional = _specialExpandTopSkip + additionalBottom;
|
||||
if (additionalBottom < 0 || additional <= 0) {
|
||||
@@ -834,7 +834,7 @@ void Selector::createList() {
|
||||
_list->jumpedToPremium(
|
||||
) | rpl::start_with_next(_jumpedToPremium, _list->lifetime());
|
||||
|
||||
const auto inner = rect().marginsRemoved(extentsForShadow());
|
||||
const auto inner = rect().marginsRemoved(marginsForShadow());
|
||||
const auto footer = _reactions.customAllowed
|
||||
? _list->createFooter().data()
|
||||
: nullptr;
|
||||
@@ -904,16 +904,16 @@ bool AdjustMenuGeometryForSelector(
|
||||
const auto desiredWidth = menu->menu()->width() + added;
|
||||
const auto maxWidth = menu->st().menu.widthMax + added;
|
||||
const auto width = selector->countWidth(desiredWidth, maxWidth);
|
||||
const auto extents = selector->extentsForShadow();
|
||||
const auto margins = selector->marginsForShadow();
|
||||
const auto categoriesTop = selector->useTransparency()
|
||||
? selector->extendTopForCategories()
|
||||
: 0;
|
||||
menu->setForceWidth(width - added);
|
||||
const auto height = menu->height();
|
||||
const auto fullTop = extents.top() + categoriesTop + extend.top();
|
||||
const auto minimalHeight = extents.top()
|
||||
const auto fullTop = margins.top() + categoriesTop + extend.top();
|
||||
const auto minimalHeight = margins.top()
|
||||
+ selector->minimalHeight()
|
||||
+ extents.bottom();
|
||||
+ margins.bottom();
|
||||
const auto willBeHeightWithoutBottomPadding = fullTop
|
||||
+ height
|
||||
- menu->st().shadow.extend.top();
|
||||
@@ -924,15 +924,15 @@ bool AdjustMenuGeometryForSelector(
|
||||
? (minimalHeight - willBeHeightWithoutBottomPadding)
|
||||
: 0);
|
||||
menu->setAdditionalMenuPadding(QMargins(
|
||||
extents.left() + extend.left(),
|
||||
margins.left() + extend.left(),
|
||||
fullTop,
|
||||
extents.right() + extend.right(),
|
||||
margins.right() + extend.right(),
|
||||
additionalPaddingBottom
|
||||
), QMargins(
|
||||
extents.left(),
|
||||
extents.top(),
|
||||
extents.right(),
|
||||
std::min(additionalPaddingBottom, extents.bottom())
|
||||
margins.left(),
|
||||
margins.top(),
|
||||
margins.right(),
|
||||
std::min(additionalPaddingBottom, margins.bottom())
|
||||
));
|
||||
if (!menu->prepareGeometryFor(desiredPosition)) {
|
||||
return false;
|
||||
@@ -944,14 +944,14 @@ bool AdjustMenuGeometryForSelector(
|
||||
return true;
|
||||
}
|
||||
menu->setAdditionalMenuPadding(QMargins(
|
||||
extents.left() + extend.left(),
|
||||
margins.left() + extend.left(),
|
||||
fullTop + additionalPaddingBottom,
|
||||
extents.right() + extend.right(),
|
||||
margins.right() + extend.right(),
|
||||
0
|
||||
), QMargins(
|
||||
extents.left(),
|
||||
extents.top(),
|
||||
extents.right(),
|
||||
margins.left(),
|
||||
margins.top(),
|
||||
margins.right(),
|
||||
0
|
||||
));
|
||||
selector->setSpecialExpandTopSkip(additionalPaddingBottom);
|
||||
|
||||