From 62c4b1f30b9dce56e5a0278c64819f9dfb48f3de Mon Sep 17 00:00:00 2001 From: AlexeyZavar <sltkval1@gmail.com> Date: Thu, 16 Jan 2025 16:40:43 +0300 Subject: [PATCH] fix: process more shortcuts --- Telegram/Resources/langs/lang.strings | 28 ++- .../ayu/ui/settings/settings_ayu.cpp | 2 +- .../SourceFiles/ayu/utils/windows_utils.cpp | 166 +++++++++++++++--- .../info/profile/info_profile_cover.cpp | 14 +- .../info/profile/info_profile_cover.h | 2 +- .../win/windows_app_user_model_id.cpp | 6 +- .../platform/win/windows_app_user_model_id.h | 3 + 7 files changed, 179 insertions(+), 42 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index cbd28cefb..8f598d172 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -6108,13 +6108,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_DontSendOnlinePackets" = "Don't Send Online"; "ayu_DontSendUploadProgress" = "Don't Send Typing"; "ayu_SendOfflinePacketAfterOnline" = "Go Offline Automatically"; +"ayu_GhostModeOptionLongTapDescription" = "Long tap on any option to prevent it from changing on toggling Ghost Mode."; "ayu_MarkReadAfterAction" = "Read on Interact"; "ayu_MarkReadAfterActionDescription" = "Automatically reads message when you send a new one or tap a reaction."; "ayu_MarkReadAfterSend" = "Send"; "ayu_MarkReadAfterReaction" = "Reaction"; "ayu_MarkReadAfterPoll" = "Poll"; "ayu_UseScheduledMessages" = "Schedule Messages"; -"ayu_UseScheduledMessagesDescription" = "Automatically schedules outgoing messages for ~12 seconds, and more for media. Don't use on bad networks."; +"ayu_UseScheduledMessagesDescription" = "Automatically schedules outgoing messages for ~12 seconds, and more for media. Sending messages this way, you won't appear online.\nDon't use on bad networks."; "ayu_SendWithoutSoundByDefault" = "Send without Sound"; "ayu_SendWithoutSoundByDefaultDescription" = "Automatically sends outgoing messages without sound."; "ayu_SuggestGhostModeBeforeViewingStory" = "Story Ghost Mode Alert"; @@ -6146,6 +6147,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_DisableCustomBackgrounds" = "Disable Custom Backgrounds"; "ayu_DisableNotificationsDelay" = "Disable Notify Delay"; "ayu_LocalPremium" = "Local Telegram Premium"; +"ayu_DisplayGhostStatus" = "Display Ghost Mode Status"; "ayu_CopyUsernameAsLink" = "Copy Username as Link"; "ayu_CustomizationHeader" = "Customization"; "ayu_DeletedMarkText" = "Deleted Mark"; @@ -6154,6 +6156,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_DeletedMarkCross" = "Cross"; "ayu_DeletedMarkEyeCrossed" = "Eye Crossed"; "ayu_EditedMarkText" = "Edited Mark"; +"ayu_ReplaceMarksWithIcons" = "Replace with Icons"; "ayu_SemiTransparentDeletedMessages" = "Translucent Deleted Messages"; "ayu_HideNotificationCounters" = "Hide Notification Counters"; "ayu_HideNotificationBadge" = "Hide Notification Badge"; @@ -6224,6 +6227,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_RegexFilterQuickAdd" = "Add Filter"; "ayu_RegexFilterBulletinText" = "Filter added to the **Shared filters**."; "ayu_RegexFilterBulletinAction" = "To Current Chat"; +"ayu_RegexFiltersListEmpty" = "No filters here yet."; "ayu_FiltersMenuSelectChat" = "Select Chat"; "ayu_FiltersMenuImport" = "Import"; "ayu_FiltersMenuExport" = "Export"; @@ -6302,6 +6306,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_DisableGhostModeTray" = "Disable Ghost Mode"; "ayu_GhostModeEnabled" = "Ghost Mode turned on"; "ayu_GhostModeDisabled" = "Ghost Mode turned off"; +"ayu_GhostModeGlobalSettings" = "Global Settings"; +"ayu_GhostModeGlobalSettingsDescription" = "Same for all accounts"; +"ayu_GhostModeSwitchedToGlobalSettings" = "Switched to same settings for all accounts."; +"ayu_GhostModeSwitchedToIndividualSettings" = "Switched to individual settings for each account."; "ayu_StreamerModeToggle" = "Streamer Mode"; "ayu_EnableStreamerModeTray" = "Enable Streamer Mode"; "ayu_DisableStreamerModeTray" = "Disable Streamer Mode"; @@ -6311,6 +6319,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_ClearDeletedMenuText" = "Clear Deleted"; "ayu_ViewDeletedMenuText" = "View Deleted"; "ayu_ViewFiltersMenuText" = "View Filters"; +"ayu_ReadExclusionMenuText" = "Read Exclusion"; +"ayu_TypingExclusionMenuText" = "Typing Exclusion"; +"ayu_ExclusionTitle" = "Select exclusion type"; +"ayu_ExclusionUseDefault" = "Default"; +"ayu_ExclusionDontRead" = "Never Read"; +"ayu_ExclusionAlwaysRead" = "Always Read"; +"ayu_ExclusionDontType" = "Never Type"; +"ayu_ExclusionAlwaysType" = "Always Type"; "ayu_PeekOnlineSuccess" = "Peeked via"; "ayu_OneViewTTL" = "one view"; "ayu_OnePlayTTL" = "one play"; @@ -6327,9 +6343,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_SuggestGhostModeStoryText" = "Do you want to enable **Ghost Mode** before viewing the story?"; "ayu_SuggestGhostModeStoryActionTextYes" = "Yes"; "ayu_SuggestGhostModeStoryActionTextNo" = "No"; +"ayu_ClearAttachmentsFolderWarning" = "Are you sure you want to clear the **attachments folder**? This action cannot be undone."; +"ayu_ClearMessagesDatabaseWarning" = "Are you sure you want to clear **all deleted & edited messages**? This action cannot be undone."; +"ayu_ClearTelegramDatabaseWarning" = "Are you sure you want to clear the **Telegram internal database**? This action cannot be undone."; +"ayu_FirstLaunchAlert" = "AyuGram is **free** software and should only be obtained from our **official sources**. You assume **full responsibility** for using this application with your account."; +"ayu_LocalPremiumAlert" = "With local Telegram Premium you won't have increased limits and won't be able to send animated emojis. Other users won't see your premium emoji and quote color."; +"ayu_ExteraChatsAlert" = "Don't ask questions related to **AyuGram** in **exteraGram** chats. If you need help, ask in the official **AyuGram** chat."; "ayu_HideNextViewsDescriptionAyu" = "Hide my views forever, until Ghost Mode disabled."; "ayu_EnableGhostModeStories" = "Enable Ghost Mode"; -"ayu_GhostModeIsActive" = "Ghost Mode Is Active"; +"ayu_GhostModeIsActive" = "Ghost Mode is Active"; "ayu_SimpleQuotesAndReplies" = "Disable Colorful Replies"; "ayu_DisableSimilarChannels" = "Disable Similar Channels"; "ayu_CollapseSimilarChannels" = "Collapse Similar Channels"; @@ -6376,7 +6398,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_ContextHideMessage" = "Hide"; "ayu_ContextCopyCallbackData" = "Copy Callback Data"; "ayu_RegisterURLScheme" = "Register URL Scheme"; -"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_LocalPremiumNotice" = "You're using **local** Telegram Premium.\nIt **won't** give you any benefits.\n**Enjoy the star near your nickname!**"; "ayu_SettingsWatermark" = "AyuGram developed and maintained by Radolyn Labs."; "ayu_ConfirmationSticker" = "Do you want to send this sticker?"; "ayu_ConfirmationGIF" = "Do you want to send this GIF?"; diff --git a/Telegram/SourceFiles/ayu/ui/settings/settings_ayu.cpp b/Telegram/SourceFiles/ayu/ui/settings/settings_ayu.cpp index 56866a8f3..efba614cc 100644 --- a/Telegram/SourceFiles/ayu/ui/settings/settings_ayu.cpp +++ b/Telegram/SourceFiles/ayu/ui/settings/settings_ayu.cpp @@ -1460,7 +1460,7 @@ void SetupMarks(not_null<Ui::VerticalLayout*> container) { AddButtonWithIcon( container, - rpl::single(QString("Replace with Icons")), + tr::ayu_ReplaceMarksWithIcons(), st::settingsButtonNoIcon )->toggleOn( rpl::single(settings->replaceBottomInfoWithIcons) diff --git a/Telegram/SourceFiles/ayu/utils/windows_utils.cpp b/Telegram/SourceFiles/ayu/utils/windows_utils.cpp index c324bf1d3..016ccf1f5 100644 --- a/Telegram/SourceFiles/ayu/utils/windows_utils.cpp +++ b/Telegram/SourceFiles/ayu/utils/windows_utils.cpp @@ -8,46 +8,158 @@ #include "windows_utils.h" +#include "base/platform/win/base_windows_winrt.h" +#include "platform/win/windows_app_user_model_id.h" + #include <ShlObj_core.h> +#include <propvarutil.h> -void reloadAppIconFromTaskBar() { - QString appdata = QDir::fromNativeSeparators(qgetenv("APPDATA")); - QString ayugramIconPath = appdata + "/AyuGram.ico"; - - QString shortcut = appdata + "/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar/AyuGram Desktop.lnk"; +void processIcon(QString shortcut, QString iconPath) { if (!QFile::exists(shortcut)) { - shortcut = appdata + "/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar/AyuGram.lnk"; + return; } - if (QFile::exists(shortcut)) { - IShellLink *pShellLink = NULL; - IPersistFile *pPersistFile = NULL; + IShellLink *pShellLink = NULL; + IPersistFile *pPersistFile = NULL; - HRESULT hr = CoCreateInstance(CLSID_ShellLink, - NULL, - CLSCTX_INPROC_SERVER, - IID_IShellLink, - (void**) &pShellLink); + HRESULT hr = CoCreateInstance(CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + IID_IShellLink, + (void**) &pShellLink); + if (SUCCEEDED(hr)) { + hr = pShellLink->QueryInterface(IID_IPersistFile, (void**) &pPersistFile); if (SUCCEEDED(hr)) { - hr = pShellLink->QueryInterface(IID_IPersistFile, (void**) &pPersistFile); - if (SUCCEEDED(hr)) { - WCHAR wszShortcutPath[MAX_PATH]; - shortcut.toWCharArray(wszShortcutPath); - wszShortcutPath[shortcut.length()] = '\0'; + WCHAR wszShortcutPath[MAX_PATH]; + shortcut.toWCharArray(wszShortcutPath); + wszShortcutPath[shortcut.length()] = '\0'; - if (SUCCEEDED(pPersistFile->Load(wszShortcutPath, STGM_READWRITE))) { - pShellLink->SetIconLocation(ayugramIconPath.toStdWString().c_str(), 0); - pPersistFile->Save(wszShortcutPath, TRUE); - } - - pPersistFile->Release(); + if (SUCCEEDED(pPersistFile->Load(wszShortcutPath, STGM_READWRITE))) { + pShellLink->SetIconLocation(iconPath.toStdWString().c_str(), 0); + pPersistFile->Save(wszShortcutPath, TRUE); } - pShellLink->Release(); + pPersistFile->Release(); } - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); + pShellLink->Release(); } } +void processLegacy(const QString &appdata, const QString &iconPath) { + auto shortcut = appdata + "/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar/AyuGram Desktop.lnk"; + if (!QFile::exists(shortcut)) { + shortcut = appdata + "/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar/AyuGram.lnk"; + } + if (!QFile::exists(shortcut)) { + return; + } + + processIcon(shortcut, iconPath); +} + +void processNewPinned(const QString &iconPath) { + if (!SUCCEEDED(CoInitialize(0))) { + return; + } + const auto coGuard = gsl::finally([] + { + CoUninitialize(); + }); + + const auto path = Platform::AppUserModelId::PinnedIconsPath(); + const auto native = QDir::toNativeSeparators(path).toStdWString(); + + const auto srcid = Platform::AppUserModelId::MyExecutablePathId(); + if (!srcid) { + return; + } + + WIN32_FIND_DATA findData; + HANDLE findHandle = FindFirstFileEx( + (native + L"*").c_str(), + FindExInfoStandard, + &findData, + FindExSearchNameMatch, + 0, + 0); + if (findHandle == INVALID_HANDLE_VALUE) { + return; + } + + do { + std::wstring fname = native + findData.cFileName; + const auto filePath = QString::fromStdWString(fname); + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + continue; + } + + DWORD attributes = GetFileAttributes(fname.c_str()); + if (attributes >= 0xFFFFFFF) { + continue; // file does not exist + } + + auto shellLink = base::WinRT::TryCreateInstance<IShellLink>( + CLSID_ShellLink); + if (!shellLink) { + continue; + } + + auto persistFile = shellLink.try_as<IPersistFile>(); + if (!persistFile) { + continue; + } + + auto hr = persistFile->Load(fname.c_str(), STGM_READWRITE); + if (!SUCCEEDED(hr)) continue; + + WCHAR dst[MAX_PATH] = {0}; + hr = shellLink->GetPath(dst, MAX_PATH, nullptr, 0); + if (!SUCCEEDED(hr)) continue; + + if (Platform::AppUserModelId::GetUniqueFileId(dst) == srcid) { + auto propertyStore = shellLink.try_as<IPropertyStore>(); + if (!propertyStore) { + continue; + } + + processIcon(filePath, iconPath); + } + } while (FindNextFile(findHandle, &findData)); + DWORD errorCode = GetLastError(); + if (errorCode && errorCode != ERROR_NO_MORE_FILES) { + return; + } + FindClose(findHandle); +} + +void processNewShortcuts(const QString &iconPath) { + const auto path = Platform::AppUserModelId::systemShortcutPath(); + if (path.isEmpty()) { + return; + } + + const auto shortcut = path + u"AyuGram Desktop/AyuGram.lnk"_q; + const auto native = QDir::toNativeSeparators(path).toStdWString(); + + DWORD attributes = GetFileAttributes(native.c_str()); + if (attributes >= 0xFFFFFFF) { + return; // file does not exist + } + + const auto normalizedPath = QString::fromStdWString(native); + processIcon(normalizedPath, iconPath); +} + +void reloadAppIconFromTaskBar() { + QString appdata = QDir::fromNativeSeparators(qgetenv("APPDATA")); + QString iconPath = appdata + "/AyuGram.ico"; + + processNewPinned(iconPath); + processNewShortcuts(iconPath); + processLegacy(appdata, iconPath); + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); +} + #endif diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 58d7f2fd2..675e3a0dc 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -357,7 +357,7 @@ Cover::Cover( return controller->isGifPausedAtLeastFor( Window::GifPauseReason::Layer); })) -, _devBadge( +, _exteraBadge( std::make_unique<Badge>( this, st::infoPeerBadge, @@ -419,14 +419,14 @@ Cover::Cover( }, _name->lifetime()); if (isExteraPeer(getBareID(_peer))) { - _devBadge->setContent(Info::Profile::Badge::Content{BadgeType::Extera}); + _exteraBadge->setContent(Info::Profile::Badge::Content{BadgeType::Extera}); } else if (isSupporterPeer(getBareID(_peer))) { - _devBadge->setContent(Info::Profile::Badge::Content{BadgeType::ExteraSupporter}); + _exteraBadge->setContent(Info::Profile::Badge::Content{BadgeType::ExteraSupporter}); } else { - _devBadge->setContent(Info::Profile::Badge::Content{BadgeType::None}); + _exteraBadge->setContent(Info::Profile::Badge::Content{BadgeType::None}); } - _devBadge->updated() | rpl::start_with_next( + _exteraBadge->updated() | rpl::start_with_next( [=] { refreshNameGeometry(width()); @@ -769,7 +769,7 @@ void Cover::refreshNameGeometry(int newWidth) { if (const auto widget = _badge->widget()) { nameWidth -= st::infoVerifiedCheckPosition.x() + widget->width(); } - if (const auto widget = _devBadge->widget()) { + if (const auto widget = _exteraBadge->widget()) { nameWidth -= st::infoVerifiedCheckPosition.x() + widget->width() + (_badge->widget() @@ -800,7 +800,7 @@ void Cover::refreshNameGeometry(int newWidth) { : 0); const auto devBadgeTop = _st.nameTop; const auto devBadgeBottom = _st.nameTop + _name->height(); - _devBadge->move(devBadgeLeft, devBadgeTop, devBadgeBottom); + _exteraBadge->move(devBadgeLeft, devBadgeTop, devBadgeBottom); } void Cover::refreshStatusGeometry(int newWidth) { diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.h b/Telegram/SourceFiles/info/profile/info_profile_cover.h index 360460877..15e3875c5 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.h +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.h @@ -149,7 +149,7 @@ private: const std::unique_ptr<EmojiStatusPanel> _emojiStatusPanel; const std::unique_ptr<Badge> _verify; const std::unique_ptr<Badge> _badge; - const std::unique_ptr<Badge> _devBadge; + const std::unique_ptr<Badge> _exteraBadge; rpl::variable<int> _onlineCount; const object_ptr<Ui::UserpicButton> _userpic; diff --git a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp index 83ec19e86..7faeab8e2 100644 --- a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp +++ b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp @@ -31,7 +31,9 @@ const WCHAR AppUserModelIdBase[] = L"AyuGram.AyuGramDesktop.Store"; const WCHAR AppUserModelIdBase[] = L"AyuGram.AyuGramDesktop"; #endif // OS_WIN_STORE -[[nodiscard]] QString PinnedIconsPath() { +} // namespace + +QString PinnedIconsPath() { WCHAR wstrPath[kMaxFileLen] = {}; if (GetEnvironmentVariable(L"APPDATA", wstrPath, kMaxFileLen)) { auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath))); @@ -41,8 +43,6 @@ const WCHAR AppUserModelIdBase[] = L"AyuGram.AyuGramDesktop"; return QString(); } -} // namespace - const std::wstring &MyExecutablePath() { static const auto Path = [&] { auto result = std::wstring(kMaxFileLen, 0); diff --git a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h index 76a7a3312..6680ae0ce 100644 --- a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h +++ b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h @@ -12,6 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Platform { namespace AppUserModelId { +[[nodiscard]] QString PinnedIconsPath(); +QString systemShortcutPath(); + void CleanupShortcut(); void CheckPinned();