diff --git a/fluxer_app/src/features/app/components/AppNotificationBadge.ts b/fluxer_app/src/features/app/components/AppNotificationBadge.ts index fe5d78e44..733a4281c 100644 --- a/fluxer_app/src/features/app/components/AppNotificationBadge.ts +++ b/fluxer_app/src/features/app/components/AppNotificationBadge.ts @@ -58,10 +58,12 @@ const initFavico = (): Favico | null => { }; const setElectronBadge = (badge: number): void => { const electronApi = getElectronAPI(); - if (!electronApi?.setBadgeCount) return; - const electronBadge = badge > 0 ? badge : 0; try { - electronApi.setBadgeCount(electronBadge); + if (electronApi?.setUnreadBadge) { + electronApi.setUnreadBadge(badge); + } else { + electronApi?.setBadgeCount?.(badge > 0 ? badge : 0); + } } catch (e) { logger.warn('Failed to set Electron badge', e); } diff --git a/fluxer_app/src/features/i18n/locales/ar/messages.po b/fluxer_app/src/features/i18n/locales/ar/messages.po index 5198b6092..93e1ba6fe 100644 --- a/fluxer_app/src/features/i18n/locales/ar/messages.po +++ b/fluxer_app/src/features/i18n/locales/ar/messages.po @@ -30767,6 +30767,11 @@ msgstr "إظهار أيقونة علبة النظام" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "عرض النص بخط Fluxer Sans، الخط الافتراضي السابق، بدلاً من خط نظام Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "عرض أيقونة {productName} بالألوان الكاملة بدلاً من أيقونة أحادية اللون تتطابق مع شريط المهام الخاص بك." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "استخدام إعدادات القناة الافتراضية" msgid "Use coal theme (pitch-black surfaces)" msgstr "استخدام سمة الفحم (أسطح سوداء حالكة)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "استخدم أيقونة ملونة في شريط المهام" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/bg/messages.po b/fluxer_app/src/features/i18n/locales/bg/messages.po index 23c071083..f783e2848 100644 --- a/fluxer_app/src/features/i18n/locales/bg/messages.po +++ b/fluxer_app/src/features/i18n/locales/bg/messages.po @@ -30767,6 +30767,11 @@ msgstr "Показване на иконата в системния трей" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Показвай текста с Fluxer Sans, предишния шрифт по подразбиране, вместо системния шрифт на Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Показвай цветната икона на {productName} вместо монохромна, която съответства на лентата на задачите." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Използвай канала по подразбиране" msgid "Use coal theme (pitch-black surfaces)" msgstr "Използване на въгленова тема (наситено черни повърхности)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Използвай цветна икона в системната област" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/cs/messages.po b/fluxer_app/src/features/i18n/locales/cs/messages.po index ec7add2dc..761aa9423 100644 --- a/fluxer_app/src/features/i18n/locales/cs/messages.po +++ b/fluxer_app/src/features/i18n/locales/cs/messages.po @@ -30767,6 +30767,11 @@ msgstr "Zobrazit ikonu v oznamovací oblasti" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Zobrazit text písmem Fluxer Sans, dřívějším výchozím písmem, místo systémového písma Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Zobrazit plnobarevný motiv ikony {productName} místo monochromatického, který odpovídá hlavnímu panelu." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Použít výchozí nastavení kanálu" msgid "Use coal theme (pitch-black surfaces)" msgstr "Použít uhelný motiv (černočerné plochy)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Použít barevnou ikonu v oznamovací oblasti" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/da/messages.po b/fluxer_app/src/features/i18n/locales/da/messages.po index b7e9ee6d2..dd979e59a 100644 --- a/fluxer_app/src/features/i18n/locales/da/messages.po +++ b/fluxer_app/src/features/i18n/locales/da/messages.po @@ -30767,6 +30767,11 @@ msgstr "Vis ikon i systembakken" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Vis tekst i Fluxer Sans, den tidligere standardfont, i stedet for Windows' systemskrifttype" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Vis ikonet i fuld farve fra {productName} i stedet for et monokromt ikon, der matcher din proceslinje." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Brug kanalens standard" msgid "Use coal theme (pitch-black surfaces)" msgstr "Brug kulsort tema (kulsorte overflader)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Brug farvet systembakkeikon" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/de/messages.po b/fluxer_app/src/features/i18n/locales/de/messages.po index f8c1a7490..8d4fd24bf 100644 --- a/fluxer_app/src/features/i18n/locales/de/messages.po +++ b/fluxer_app/src/features/i18n/locales/de/messages.po @@ -30767,6 +30767,11 @@ msgstr "Symbol im Infobereich anzeigen" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Text in Fluxer Sans anzeigen, der vorherigen Standardschriftart, anstelle der Windows-Systemschriftart" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Zeige das vollfarbige {productName}-Symbol anstelle eines monochromen, das zu deiner Taskleiste passt." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Kanalstandard verwenden" msgid "Use coal theme (pitch-black surfaces)" msgstr "Kohlrabenschwarz (pechschwarze Oberflächen)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Farbiges Tray-Symbol verwenden" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/el/messages.po b/fluxer_app/src/features/i18n/locales/el/messages.po index c6ed2b7a2..2add36f67 100644 --- a/fluxer_app/src/features/i18n/locales/el/messages.po +++ b/fluxer_app/src/features/i18n/locales/el/messages.po @@ -30767,6 +30767,11 @@ msgstr "Εμφάνιση εικονιδίου στην περιοχή ειδοπ msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Εμφάνιση κειμένου με γραμματοσειρά Fluxer Sans, την προηγούμενη προεπιλεγμένη γραμματοσειρά, αντί για τη γραμματοσειρά συστήματος των Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Εμφάνιση του εικονιδίου {productName} με πλήρη χρώματα αντί για μονόχρωμο που ταιριάζει με τη γραμμή εργασιών σας." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Χρήση προεπιλογής καναλιού" msgid "Use coal theme (pitch-black surfaces)" msgstr "Χρήση θέματος Coal (κατάμαυρες επιφάνειες)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Χρησιμοποιήστε έγχρωμο εικονίδιο στη γραμμή εργασιών" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/en-GB/messages.po b/fluxer_app/src/features/i18n/locales/en-GB/messages.po index 2ca8d7aec..41507a7fc 100644 --- a/fluxer_app/src/features/i18n/locales/en-GB/messages.po +++ b/fluxer_app/src/features/i18n/locales/en-GB/messages.po @@ -30767,6 +30767,11 @@ msgstr "Show system tray icon" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Show the full-colour {productName} icon instead of a monochrome one that matches your taskbar." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Use channel default" msgid "Use coal theme (pitch-black surfaces)" msgstr "Use coal theme (pitch-black surfaces)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Use coloured tray icon" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/en-US/messages.po b/fluxer_app/src/features/i18n/locales/en-US/messages.po index e7791ec23..9c721a057 100644 --- a/fluxer_app/src/features/i18n/locales/en-US/messages.po +++ b/fluxer_app/src/features/i18n/locales/en-US/messages.po @@ -30767,6 +30767,11 @@ msgstr "Show system tray icon" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Use channel default" msgid "Use coal theme (pitch-black surfaces)" msgstr "Use coal theme (pitch-black surfaces)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Use colored tray icon" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/es-419/messages.po b/fluxer_app/src/features/i18n/locales/es-419/messages.po index 4fab259f8..d5e34b2f5 100644 --- a/fluxer_app/src/features/i18n/locales/es-419/messages.po +++ b/fluxer_app/src/features/i18n/locales/es-419/messages.po @@ -30767,6 +30767,11 @@ msgstr "Mostrar ícono en la bandeja del sistema" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Mostrar texto en Fluxer Sans, la fuente predeterminada anterior, en lugar de la fuente del sistema de Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Mostrar el icono a todo color de {productName} en lugar de uno monocromático que coincida con tu barra de tareas." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Usar predeterminado del canal" msgid "Use coal theme (pitch-black surfaces)" msgstr "Usar tema carbón (superficies negro intenso)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Usar ícono de bandeja a color" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/es-ES/messages.po b/fluxer_app/src/features/i18n/locales/es-ES/messages.po index 42f05bfd7..4bbe71db8 100644 --- a/fluxer_app/src/features/i18n/locales/es-ES/messages.po +++ b/fluxer_app/src/features/i18n/locales/es-ES/messages.po @@ -30767,6 +30767,11 @@ msgstr "Mostrar icono en la bandeja del sistema" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Mostrar texto en Fluxer Sans, la fuente predeterminada anterior, en lugar de la fuente del sistema de Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Mostrar el icono de {productName} a todo color en lugar de uno monocromático que coincida con tu barra de tareas." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Usar el predeterminado del canal" msgid "Use coal theme (pitch-black surfaces)" msgstr "Usar tema carbón (superficies totalmente negras)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Usar icono de bandeja a color" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/fi/messages.po b/fluxer_app/src/features/i18n/locales/fi/messages.po index bf5f710fc..2636b1c8b 100644 --- a/fluxer_app/src/features/i18n/locales/fi/messages.po +++ b/fluxer_app/src/features/i18n/locales/fi/messages.po @@ -30767,6 +30767,11 @@ msgstr "Näytä ilmaisinalueen kuvake" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Näytä teksti Fluxer Sans -fontilla, aiemmalla oletusfontilla, Windowsin järjestelmäfontin sijaan" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Näytä täysvärinen {productName}-kuvake yksivärisen sijaan, joka vastaa tehtäväpalkkiasi." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Käytä kanavan oletusasetusta" msgid "Use coal theme (pitch-black surfaces)" msgstr "Käytä hiiliteemaa (sysimustat pinnat)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Käytä värillistä ilmoitusalueen kuvaketta" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/fr/messages.po b/fluxer_app/src/features/i18n/locales/fr/messages.po index fba9f94d1..f9a290ecb 100644 --- a/fluxer_app/src/features/i18n/locales/fr/messages.po +++ b/fluxer_app/src/features/i18n/locales/fr/messages.po @@ -30767,6 +30767,11 @@ msgstr "Afficher l’icône dans la zone de notification" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Afficher le texte en Fluxer Sans, la police par défaut précédente, au lieu de la police système Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Afficher l’icône {productName} en couleur au lieu d’une icône monochrome qui correspond à votre barre des tâches." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Utiliser le défaut du canal" msgid "Use coal theme (pitch-black surfaces)" msgstr "Utiliser le thème charbon (surfaces noir de jais)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Utiliser l'icône de la barre des tâches en couleur" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/he/messages.po b/fluxer_app/src/features/i18n/locales/he/messages.po index ec3900fa2..2a064c930 100644 --- a/fluxer_app/src/features/i18n/locales/he/messages.po +++ b/fluxer_app/src/features/i18n/locales/he/messages.po @@ -30767,6 +30767,11 @@ msgstr "הצג סמל במגש המערכת" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "הצג טקסט בגופן Fluxer Sans, הגופן הקודם, במקום גופן מערכת Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "הצג את סמל ה-{productName} בצבע מלא במקום סמל מונוכרומטי שמתאים לשורת המשימות שלך." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "השתמש בברירת המחדל של הערוץ" msgid "Use coal theme (pitch-black surfaces)" msgstr "שימוש בערכת נושא פחם (משטחים שחורים לחלוטין)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "השתמש בסמל מגש צבעוני" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/hi/messages.po b/fluxer_app/src/features/i18n/locales/hi/messages.po index 9f4b2c74e..ff6430033 100644 --- a/fluxer_app/src/features/i18n/locales/hi/messages.po +++ b/fluxer_app/src/features/i18n/locales/hi/messages.po @@ -30767,6 +30767,11 @@ msgstr "सिस्टम ट्रे आइकॉन दिखाएं" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "विंडोज सिस्टम फ़ॉन्ट के बजाय, पिछले डिफ़ॉल्ट फ़ॉन्ट, Fluxer Sans में टेक्स्ट दिखाएं" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "टास्कबार से मेल खाने वाले मोनोक्रोम के बजाय, पूरे रंग का {productName} आइकन दिखाएं।" + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "चैनल डिफ़ॉल्ट का उपयोग करे msgid "Use coal theme (pitch-black surfaces)" msgstr "कोल थीम इस्तेमाल करें (पूरी तरह से काले रंग की सतहें)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "रंगीन ट्रे आइकन का उपयोग करें" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/hr/messages.po b/fluxer_app/src/features/i18n/locales/hr/messages.po index f7b3d6a74..731061a87 100644 --- a/fluxer_app/src/features/i18n/locales/hr/messages.po +++ b/fluxer_app/src/features/i18n/locales/hr/messages.po @@ -30767,6 +30767,11 @@ msgstr "Prikaži ikonu u paleti sustava" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Prikaži tekst u Fluxer Sans, prethodnom zadanim fontu, umjesto fonta sustava Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Prikaži {productName} ikonu u punoj boji umjesto jednobojne koja odgovara vašoj programskoj traci." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Upotrijebi zadano za kanal" msgid "Use coal theme (pitch-black surfaces)" msgstr "Koristi ugljenu temu (potpuno crne površine)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Upotrijebi šarenu ikonu u području obavijesti" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/hu/messages.po b/fluxer_app/src/features/i18n/locales/hu/messages.po index f12ed7513..a89d3b05e 100644 --- a/fluxer_app/src/features/i18n/locales/hu/messages.po +++ b/fluxer_app/src/features/i18n/locales/hu/messages.po @@ -30767,6 +30767,11 @@ msgstr "Ikon megjelenítése az értesítési területen" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Szöveg megjelenítése Fluxer Sans, a korábbi alapértelmezett betűtípus, a Windows rendszerbetűtípusa helyett" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Mutassa a teljes színű {productName} ikont a monokróm helyett, amely illeszkedik a tálcához." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Csatorna alapértelmezett használata" msgid "Use coal theme (pitch-black surfaces)" msgstr "Szén téma használata (koromfekete felületek)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Színes tálca ikon használata" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/id/messages.po b/fluxer_app/src/features/i18n/locales/id/messages.po index fbfad8a03..8ca688678 100644 --- a/fluxer_app/src/features/i18n/locales/id/messages.po +++ b/fluxer_app/src/features/i18n/locales/id/messages.po @@ -30767,6 +30767,11 @@ msgstr "Tampilkan ikon baki sistem" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Tampilkan teks dalam Fluxer Sans, font default sebelumnya, alih-alih font sistem Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Tampilkan ikon {productName} berwarna penuh alih-alih yang monokrom agar sesuai dengan taskbar Anda." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Gunakan default channel" msgid "Use coal theme (pitch-black surfaces)" msgstr "Gunakan tema batu bara (permukaan hitam pekat)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Gunakan ikon baki berwarna" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/it/messages.po b/fluxer_app/src/features/i18n/locales/it/messages.po index 04b05177d..eb97843cc 100644 --- a/fluxer_app/src/features/i18n/locales/it/messages.po +++ b/fluxer_app/src/features/i18n/locales/it/messages.po @@ -30767,6 +30767,11 @@ msgstr "Mostra icona nell’area di notifica" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Mostra il testo in Fluxer Sans, il precedente font predefinito, invece del font di sistema di Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Mostra l'icona a colori di {productName} invece di una monocromatica che corrisponde alla barra delle applicazioni." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Usa le impostazioni predefinite del canale" msgid "Use coal theme (pitch-black surfaces)" msgstr "Usa tema carbone (superfici nero pece)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Usa l'icona a colori nella barra delle applicazioni" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/ja/messages.po b/fluxer_app/src/features/i18n/locales/ja/messages.po index 097e294aa..1114c887e 100644 --- a/fluxer_app/src/features/i18n/locales/ja/messages.po +++ b/fluxer_app/src/features/i18n/locales/ja/messages.po @@ -30767,6 +30767,11 @@ msgstr "システムトレイにアイコンを表示" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Windowsのシステムフォントではなく、以前のデフォルトフォントであるFluxer Sansでテキストを表示する" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "タスクバーに合わせたモノクロではなく、フルカラーの{productName}アイコンを表示します。" + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "チャンネルのデフォルトを使用" msgid "Use coal theme (pitch-black surfaces)" msgstr "石炭テーマを使用(完全な黒)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "カラーのトレイアイコンを使用" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/ko/messages.po b/fluxer_app/src/features/i18n/locales/ko/messages.po index c885afb57..da6929a3b 100644 --- a/fluxer_app/src/features/i18n/locales/ko/messages.po +++ b/fluxer_app/src/features/i18n/locales/ko/messages.po @@ -30767,6 +30767,11 @@ msgstr "시스템 트레이 아이콘 표시" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Windows 시스템 글꼴 대신 이전 기본 글꼴인 Fluxer Sans로 텍스트 표시" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "작업 표시줄 색상과 일치하는 단색 아이콘 대신 전체 색상의 {productName} 아이콘을 표시합니다." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "채널 기본값 사용" msgid "Use coal theme (pitch-black surfaces)" msgstr "석탄 테마 사용 (완전한 검정 화면)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "컬러 트레이 아이콘 사용" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/lt/messages.po b/fluxer_app/src/features/i18n/locales/lt/messages.po index 83e8ff46f..c34c0a237 100644 --- a/fluxer_app/src/features/i18n/locales/lt/messages.po +++ b/fluxer_app/src/features/i18n/locales/lt/messages.po @@ -30768,6 +30768,11 @@ msgstr "Rodyti sistemos dėklo piktogramą" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Rodyti tekstą „Fluxer Sans“ (ankstesnis numatytasis šriftas), o ne „Windows“ sistemos šriftą" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Rodyti visos spalvos „{productName}“ piktogramą, o ne vienspalvę, atitinkančią užduočių juostą." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -37000,6 +37005,11 @@ msgstr "Naudoti kanalo numatytuosius nustatymus" msgid "Use coal theme (pitch-black surfaces)" msgstr "Naudoti anglies temą (visiškai juodi paviršiai)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Naudoti spalvotą piktogramą sistemos dėkle" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/nl/messages.po b/fluxer_app/src/features/i18n/locales/nl/messages.po index 33c2f3e9b..92c8aa3ba 100644 --- a/fluxer_app/src/features/i18n/locales/nl/messages.po +++ b/fluxer_app/src/features/i18n/locales/nl/messages.po @@ -30767,6 +30767,11 @@ msgstr "Pictogram in systeemvak weergeven" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Toon tekst in Fluxer Sans, het vorige standaardlettertype, in plaats van het Windows-systeempje" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Toon het volledig gekleurde {productName}-pictogram in plaats van een monochroom pictogram dat overeenkomt met uw taakbalk." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Gebruik kanaalstandaard" msgid "Use coal theme (pitch-black surfaces)" msgstr "Kolenzwart thema gebruiken (gitzwarte oppervlakken)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Gebruik gekleurde systeembalk-icoon" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/no/messages.po b/fluxer_app/src/features/i18n/locales/no/messages.po index 02fde8d7b..e5f316fb8 100644 --- a/fluxer_app/src/features/i18n/locales/no/messages.po +++ b/fluxer_app/src/features/i18n/locales/no/messages.po @@ -30767,6 +30767,11 @@ msgstr "Vis ikon i systemstatusfeltet" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Vis tekst i Fluxer Sans, den forrige standardfonten, i stedet for Windows-systemfonten" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Vis ikonet i fullfarge for {productName} i stedet for et monokromt ikon som matcher oppgavelinjen din." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Bruk kanalens standard" msgid "Use coal theme (pitch-black surfaces)" msgstr "Bruk kulltema (beksvarte overflater)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Bruk fargeikon i systemstatusfeltet" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/pl/messages.po b/fluxer_app/src/features/i18n/locales/pl/messages.po index 6cda7d0c4..565d3b623 100644 --- a/fluxer_app/src/features/i18n/locales/pl/messages.po +++ b/fluxer_app/src/features/i18n/locales/pl/messages.po @@ -30767,6 +30767,11 @@ msgstr "Pokaż ikonę w zasobniku systemowym" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Wyświetlaj tekst czcionką Fluxer Sans, poprzednią domyślną czcionką, zamiast czcionki systemowej Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Pokaż pełnokolorową ikonę {productName} zamiast monochromatycznej, dopasowanej do paska zadań." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Użyj domyślnych ustawień kanału" msgid "Use coal theme (pitch-black surfaces)" msgstr "Użyj motywu węglowego (całkowicie czarne powierzchnie)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Używaj kolorowej ikony zasobnika" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/pt-BR/messages.po b/fluxer_app/src/features/i18n/locales/pt-BR/messages.po index 59f893400..6a06e18fd 100644 --- a/fluxer_app/src/features/i18n/locales/pt-BR/messages.po +++ b/fluxer_app/src/features/i18n/locales/pt-BR/messages.po @@ -30767,6 +30767,11 @@ msgstr "Mostrar ícone na bandeja do sistema" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Mostrar texto em Fluxer Sans, a fonte padrão anterior, em vez da fonte do sistema do Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Mostrar o ícone do {productName} em cores em vez de um ícone monocromático que combine com a sua barra de tarefas." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Usar padrão do canal" msgid "Use coal theme (pitch-black surfaces)" msgstr "Usar tema carvão (superfícies pretas)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Usar ícone colorido na bandeja" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/ro/messages.po b/fluxer_app/src/features/i18n/locales/ro/messages.po index 290b256cc..79ea3f476 100644 --- a/fluxer_app/src/features/i18n/locales/ro/messages.po +++ b/fluxer_app/src/features/i18n/locales/ro/messages.po @@ -30767,6 +30767,11 @@ msgstr "Afișează pictograma din bara de sistem" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Afișează textul în Fluxer Sans, fontul implicit anterior, în loc de fontul sistemului Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Afișează pictograma {productName} color completă în loc de una monocromă care se potrivește barei de activități." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Folosește implicit canalul" msgid "Use coal theme (pitch-black surfaces)" msgstr "Folosește tema cărbune (suprafețe negru-smoală)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Folosește pictograma colorată din bara de sistem" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/ru/messages.po b/fluxer_app/src/features/i18n/locales/ru/messages.po index d51aa23dc..52e15067b 100644 --- a/fluxer_app/src/features/i18n/locales/ru/messages.po +++ b/fluxer_app/src/features/i18n/locales/ru/messages.po @@ -30767,6 +30767,11 @@ msgstr "Показывать значок в системном трее" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Показывать текст шрифтом Fluxer Sans, предыдущим шрифтом по умолчанию, вместо системного шрифта Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Показывать полноцветный значок {productName} вместо монохромного, соответствующего панели задач." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Использовать настройки канала по умолч msgid "Use coal theme (pitch-black surfaces)" msgstr "Использовать угольную тему (абсолютно черные поверхности)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Использовать цветной значок в трее" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/sv-SE/messages.po b/fluxer_app/src/features/i18n/locales/sv-SE/messages.po index d1f783717..bb2bcb80e 100644 --- a/fluxer_app/src/features/i18n/locales/sv-SE/messages.po +++ b/fluxer_app/src/features/i18n/locales/sv-SE/messages.po @@ -30767,6 +30767,11 @@ msgstr "Visa ikon i meddelandefältet" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Visa text i Fluxer Sans, det tidigare standardtypsnittet, istället för Windows systemtypsnitt" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Visa {productName}-ikonen i full färg istället för en monokrom ikon som matchar aktivitetsfältet." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Använd kanalens standard" msgid "Use coal theme (pitch-black surfaces)" msgstr "Använd koltema (kolsvarta ytor)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Använd färgad ikon i meddelandefältet" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/th/messages.po b/fluxer_app/src/features/i18n/locales/th/messages.po index 890747288..1c77ecf23 100644 --- a/fluxer_app/src/features/i18n/locales/th/messages.po +++ b/fluxer_app/src/features/i18n/locales/th/messages.po @@ -30767,6 +30767,11 @@ msgstr "แสดงไอคอนในถาดระบบ" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "แสดงข้อความด้วยฟอนต์ Fluxer Sans ซึ่งเป็นฟอนต์เริ่มต้นก่อนหน้า แทนฟอนต์ระบบของ Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "แสดงไอคอน {productName} สีเต็มแทนไอคอนสีเดียวที่เข้ากับแถบงานของคุณ" + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "ใช้ค่าเริ่มต้นของช่อง" msgid "Use coal theme (pitch-black surfaces)" msgstr "ใช้ธีมถ่านหิน (พื้นผิวสีดำสนิท)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "ใช้ไอคอนถาดสี" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/tr/messages.po b/fluxer_app/src/features/i18n/locales/tr/messages.po index 0dd165f82..091e557e7 100644 --- a/fluxer_app/src/features/i18n/locales/tr/messages.po +++ b/fluxer_app/src/features/i18n/locales/tr/messages.po @@ -30767,6 +30767,11 @@ msgstr "Sistem tepsisi simgesini göster" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Fluxer Sans ile metinleri göster, Windows sistem yazı tipi yerine önceki varsayılan yazı tipi" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Tam renkli {productName} simgesini, görev çubuğunuzla eşleşen tek renkli bir simge yerine göster." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Kanal varsayılanını kullan" msgid "Use coal theme (pitch-black surfaces)" msgstr "Kömür temasını kullan (zifiri siyah yüzeyler)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Renkli sistem tepsisi simgesi kullan" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/uk/messages.po b/fluxer_app/src/features/i18n/locales/uk/messages.po index 98a7ed3dd..740392cbe 100644 --- a/fluxer_app/src/features/i18n/locales/uk/messages.po +++ b/fluxer_app/src/features/i18n/locales/uk/messages.po @@ -30767,6 +30767,11 @@ msgstr "Показувати іконку в системному треї" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Відображати текст шрифтом Fluxer Sans (попередній стандартний шрифт) замість системного шрифту Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Показувати повноколірний значок {productName} замість монохромного, що відповідає панелі завдань." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Використовувати стандартні налаштуван msgid "Use coal theme (pitch-black surfaces)" msgstr "Використовувати вугільну тему (абсолютно чорні поверхні)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Використовувати кольорову піктограму в треї" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/vi/messages.po b/fluxer_app/src/features/i18n/locales/vi/messages.po index 6356e6b52..0fc3e064d 100644 --- a/fluxer_app/src/features/i18n/locales/vi/messages.po +++ b/fluxer_app/src/features/i18n/locales/vi/messages.po @@ -30767,6 +30767,11 @@ msgstr "Hiện biểu tượng trên khay hệ thống" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "Hiển thị văn bản bằng Fluxer Sans, phông chữ mặc định trước đây, thay vì phông chữ hệ thống của Windows" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "Hiển thị biểu tượng {productName} đầy đủ màu sắc thay vì đơn sắc, phù hợp với thanh tác vụ của bạn." + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "Sử dụng mặc định của kênh" msgid "Use coal theme (pitch-black surfaces)" msgstr "Dùng giao diện Than (nền đen tuyền)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "Sử dụng biểu tượng màu trên khay hệ thống" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/zh-CN/messages.po b/fluxer_app/src/features/i18n/locales/zh-CN/messages.po index c1765100e..b0371acc4 100644 --- a/fluxer_app/src/features/i18n/locales/zh-CN/messages.po +++ b/fluxer_app/src/features/i18n/locales/zh-CN/messages.po @@ -30767,6 +30767,11 @@ msgstr "显示系统托盘图标" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "以 Fluxer Sans(之前的默认字体)显示文本,而不是使用 Windows 系统字体" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "在任务栏显示全彩 {productName} 图标,而非单色图标。" + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "使用频道默认设置" msgid "Use coal theme (pitch-black surfaces)" msgstr "使用煤炭主题(纯黑界面)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "使用彩色托盘图标" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/i18n/locales/zh-TW/messages.po b/fluxer_app/src/features/i18n/locales/zh-TW/messages.po index 4f2f7e611..1ca7b388e 100644 --- a/fluxer_app/src/features/i18n/locales/zh-TW/messages.po +++ b/fluxer_app/src/features/i18n/locales/zh-TW/messages.po @@ -30767,6 +30767,11 @@ msgstr "顯示系統匣圖示" msgid "Show text in Fluxer Sans, the previous default font, instead of the Windows system font" msgstr "以 Fluxer Sans(先前預設字體)顯示文字,而非 Windows 系統字體" +#. Desktop setting description under the colored tray icon toggle on Windows and Linux. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Show the full-color {productName} icon instead of a monochrome one that matches your taskbar." +msgstr "在工作列顯示全彩的 {productName} 圖示,而非單色的。" + #. Switch label in the role editor (hoist toggle). When on, members with this role appear in their own member-list section. #: src/features/guild/components/modals/guild_tabs/guild_roles_tab/RoleEditor.tsx msgid "Show this role separately" @@ -36999,6 +37004,11 @@ msgstr "沿用頻道預設" msgid "Use coal theme (pitch-black surfaces)" msgstr "使用煤炭主題(純黑介面)" +#. Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon. +#: src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +msgid "Use colored tray icon" +msgstr "使用彩色系統匣圖示" + #. Plutonium page comparison row label for global emojis and stickers. #: src/features/premium/components/plutonium_page/PlutoniumPageMessages.ts msgid "Use custom emojis and stickers in any community" diff --git a/fluxer_app/src/features/user/components/modals/tabs/DesktopSettingsTab.tsx b/fluxer_app/src/features/user/components/modals/tabs/DesktopSettingsTab.tsx index 1557bef83..b963501dc 100644 --- a/fluxer_app/src/features/user/components/modals/tabs/DesktopSettingsTab.tsx +++ b/fluxer_app/src/features/user/components/modals/tabs/DesktopSettingsTab.tsx @@ -40,6 +40,17 @@ const RESTART_PRODUCT_FOR_TRAY_CHANGE_DESCRIPTOR = msg({ comment: 'Desktop setting description shown when a tray-icon change on Linux requires restart.', }); +const USE_COLORED_TRAY_ICON_DESCRIPTOR = msg({ + message: 'Use colored tray icon', + comment: + 'Desktop setting toggle label on Windows and Linux. Switches the system tray icon from monochrome to the full-color app icon.', +}); + +const USE_COLORED_TRAY_ICON_DESCRIPTION_DESCRIPTOR = msg({ + message: 'Show the full-color {productName} icon instead of a monochrome one that matches your taskbar.', + comment: 'Desktop setting description under the colored tray icon toggle on Windows and Linux.', +}); + const DesktopSettingsTab: React.FC = observer(() => { const {i18n} = useLingui(); const cachedAutostart = getCachedAutostartStatus(); @@ -188,6 +199,18 @@ const DesktopSettingsTab: React.FC = observer(() => { onChange={handleShowTrayIconChange} data-flx="user.desktop-settings-tab.switch.show-tray-icon-change" /> + {!isMac && desktopWindowBehavior.coloredTrayIcon !== undefined && ( + handleDesktopWindowBehaviorChange({coloredTrayIcon: value})} + data-flx="user.desktop-settings-tab.switch.colored-tray-icon-change" + /> + )} Minimize to menu bar : Minimize to tray} value={desktopWindowBehavior.minimizeToTray} diff --git a/fluxer_app/src/types/electron.d.ts b/fluxer_app/src/types/electron.d.ts index 7e43a758d..187c36172 100644 --- a/fluxer_app/src/types/electron.d.ts +++ b/fluxer_app/src/types/electron.d.ts @@ -98,6 +98,7 @@ export interface DesktopInfo { export interface DesktopWindowBehaviorSettings { showTrayIcon: boolean; + coloredTrayIcon?: boolean; minimizeToTray: boolean; closeToTray: boolean; startMinimized?: boolean; @@ -335,6 +336,7 @@ export interface ElectronAPI { clipboardWriteFile?(options: ClipboardWriteFileOptions): Promise; pasteFromClipboard?(): Promise; setBadgeCount?(count: number): void; + setUnreadBadge?(badge: number): void; setNativeLocale?(locale: string, strings: Record): void; flashFrame?(persistent?: boolean): void; stopFlashFrame?(): void; diff --git a/fluxer_desktop/src/common/DesktopConfig.ts b/fluxer_desktop/src/common/DesktopConfig.ts index 4bb16a6b1..5c61b9e0b 100644 --- a/fluxer_desktop/src/common/DesktopConfig.ts +++ b/fluxer_desktop/src/common/DesktopConfig.ts @@ -57,6 +57,7 @@ export type ChromiumSwitchesSetting = ReadonlyArray | Record) => void; onNotificationClick: (callback: (id: string, url?: string) => void) => () => void; setBadgeCount: (count: number) => void; + setUnreadBadge: (badge: number) => void; setNativeLocale: (locale: string, strings: Record) => void; flashFrame: (persistent?: boolean) => void; stopFlashFrame: () => void; diff --git a/fluxer_desktop/src/main/DesktopDebugInfo.ts b/fluxer_desktop/src/main/DesktopDebugInfo.ts index c090982fa..f9ea069a6 100644 --- a/fluxer_desktop/src/main/DesktopDebugInfo.ts +++ b/fluxer_desktop/src/main/DesktopDebugInfo.ts @@ -231,6 +231,7 @@ export async function getDesktopDebugInfo( function formatWindowBehavior(settings: DesktopWindowBehaviorSettings): string { return [ `showTrayIcon=${settings.showTrayIcon}`, + `coloredTrayIcon=${settings.coloredTrayIcon}`, `minimizeToTray=${settings.minimizeToTray}`, `closeToTray=${settings.closeToTray}`, `startMinimized=${settings.startMinimized}`, diff --git a/fluxer_desktop/src/main/DesktopTray.ts b/fluxer_desktop/src/main/DesktopTray.ts index 2ff0ac686..a831f1fbf 100644 --- a/fluxer_desktop/src/main/DesktopTray.ts +++ b/fluxer_desktop/src/main/DesktopTray.ts @@ -16,7 +16,9 @@ import {checkForUpdatesFromShell, startDesktopUpdateFromShell} from '@electron/m import {areModuleUpdatesDisabled} from '@electron/main/LaunchOptions'; import {relaunchStableLaunchPath} from '@electron/main/LinuxLaunchPath'; import {onLocaleChange, t} from '@electron/main/MainI18n'; -import {app, type BrowserWindow, clipboard, Menu, nativeImage, Tray} from 'electron'; +import {renderTrayIcon, resolveTrayIconAppearance} from '@electron/main/TrayIconImage'; +import {describeUnreadBadge} from '@electron/main/UnreadBadge'; +import {app, type BrowserWindow, clipboard, Menu, nativeImage, nativeTheme, Tray} from 'electron'; const logger = createChildLogger('DesktopTray'); const ICON_DIR_NAMES: Record = { @@ -53,6 +55,10 @@ let pendingTrayActionFlush: NodeJS.Timeout | null = null; let trayActionBridgeWebContentsId: number | null = null; let trayForcedExitTimer: NodeJS.Timeout | null = null; let pendingTrayActions: Array = []; +let trayUnreadBadge = 0; +let trayBaseIcon: Electron.NativeImage | null = null; +let appliedTrayIconKey: string | null = null; +const trayIconCache = new Map(); const BIDI_FIRST_STRONG_ISOLATE = '\u2068'; const BIDI_POP_DIRECTIONAL_ISOLATE = '\u2069'; @@ -240,6 +246,47 @@ function createTrayIcon(): Electron.NativeImage | null { return createTrayImage(['256x256.png', '512x512.png', '128x128.png', '64x64.png', '48x48.png', 'icon.png']); } +function resolveTrayIcon(): {key: string; image: Electron.NativeImage} | null { + trayBaseIcon ??= createTrayIcon(); + if (!trayBaseIcon) return null; + const appearance = resolveTrayIconAppearance({ + platform: process.platform, + coloredTrayIcon: getDesktopWindowBehaviorSettings().coloredTrayIcon, + darkSystemUI: nativeTheme.shouldUseDarkColorsForSystemIntegratedUI, + }); + const indicator = trayUnreadBadge !== 0; + const key = `${appearance}:${indicator}`; + let image = trayIconCache.get(key); + if (!image) { + image = renderTrayIcon(trayBaseIcon, appearance, indicator); + trayIconCache.set(key, image); + } + return {key, image}; +} + +function getTrayToolTip(): string { + const description = describeUnreadBadge(trayUnreadBadge); + return description ? `${APP_NAME} - ${description}` : APP_NAME; +} + +function syncTrayIcon(force: boolean): void { + if (!tray || tray.isDestroyed()) return; + const icon = resolveTrayIcon(); + if (!icon) { + logger.warn('Tray icon asset could not be reloaded; keeping existing tray image'); + } else if (force || icon.key !== appliedTrayIconKey) { + tray.setImage(icon.image); + appliedTrayIconKey = icon.key; + } + tray.setToolTip(getTrayToolTip()); +} + +export function setDesktopTrayUnreadBadge(badge: number): void { + if (badge === trayUnreadBadge) return; + trayUnreadBadge = badge; + syncTrayIcon(false); +} + function ensureMainWindowVisible(): void { if (!controller) return; const mainWindow = controller.getMainWindow(); @@ -434,14 +481,16 @@ function buildTrayMenu(): Menu { } function createTray(): Tray | null { - const trayIcon = createTrayIcon(); + const trayIcon = resolveTrayIcon(); if (!trayIcon) { logger.warn('Tray icon asset could not be resolved; tray disabled'); return null; } try { - const nextTray = process.platform === 'darwin' ? new Tray(trayIcon, TRAY_POSITION_GUID) : new Tray(trayIcon); - nextTray.setToolTip(APP_NAME); + const nextTray = + process.platform === 'darwin' ? new Tray(trayIcon.image, TRAY_POSITION_GUID) : new Tray(trayIcon.image); + appliedTrayIconKey = trayIcon.key; + nextTray.setToolTip(getTrayToolTip()); nextTray.setContextMenu(buildTrayMenu()); if (process.platform !== 'darwin') { nextTray.on('click', toggleMainWindow); @@ -520,13 +569,7 @@ export function applyDesktopWindowBehaviorSettings(): void { tray = createTray(); } } else { - const nextTrayIcon = createTrayIcon(); - if (nextTrayIcon) { - tray.setImage(nextTrayIcon); - } else { - logger.warn('Tray icon asset could not be reloaded; keeping existing tray image'); - } - tray.setToolTip(APP_NAME); + syncTrayIcon(true); } refreshDesktopTrayMenu(); revealHiddenWindowIfTrayUnavailable(); @@ -546,10 +589,13 @@ export function initializeDesktopTray(nextController: DesktopTrayController): vo trayLocaleSubscribed = true; onLocaleChange(() => { if (tray && !tray.isDestroyed()) { - tray.setToolTip(APP_NAME); + tray.setToolTip(getTrayToolTip()); } refreshDesktopTrayMenu(); }); + if (process.platform === 'win32') { + nativeTheme.on('updated', () => syncTrayIcon(false)); + } observeDesktopUpdateState(refreshDesktopTrayMenu); } } diff --git a/fluxer_desktop/src/main/DesktopTrayIcon.test.mjs b/fluxer_desktop/src/main/DesktopTrayIcon.test.mjs new file mode 100644 index 000000000..698224307 --- /dev/null +++ b/fluxer_desktop/src/main/DesktopTrayIcon.test.mjs @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import {describe, test} from 'node:test'; +import {installElectronStub, installTestModuleStub} from './LocalAppTestSupport.test.mjs'; +import {fakeNativeImageModule, pixel} from './TrayIconTestSupport.test.mjs'; + +const resourcesPath = fs.mkdtempSync(path.join(os.tmpdir(), 'fluxer-desktop-tray-icon-test-')); +fs.mkdirSync(path.join(resourcesPath, 'icons')); +fs.writeFileSync(path.join(resourcesPath, 'icons', '16x16.png'), ''); +Object.defineProperty(process, 'resourcesPath', {value: resourcesPath, configurable: true}); +Object.defineProperty(process, 'platform', {value: 'win32', configurable: true}); + +const settings = {showTrayIcon: true, coloredTrayIcon: false}; +globalThis.__fluxerDesktopTrayIconTestSettings__ = settings; + +installTestModuleStub( + '@electron/common/DesktopConfig', + 'export const getDesktopWindowBehaviorSettings = () => ({...globalThis.__fluxerDesktopTrayIconTestSettings__});', +); +installTestModuleStub( + '@electron/main/DesktopUpdatePrompt', + 'export const checkForUpdatesFromShell = async () => {}; export const startDesktopUpdateFromShell = () => {};', +); +installTestModuleStub('@electron/main/LinuxLaunchPath', 'export const relaunchStableLaunchPath = () => {};'); + +const trays = []; + +class FakeTray { + constructor(image) { + this.images = [image]; + this.toolTips = []; + this.destroyed = false; + trays.push(this); + } + + get image() { + return this.images.at(-1); + } + + setImage(image) { + this.images.push(image); + } + + setToolTip(toolTip) { + this.toolTips.push(toolTip); + } + + setContextMenu() {} + + on() {} + + removeAllListeners() {} + + isDestroyed() { + return this.destroyed; + } + + destroy() { + this.destroyed = true; + } +} + +const themeListeners = []; +const nativeTheme = { + shouldUseDarkColorsForSystemIntegratedUI: true, + on: (event, listener) => { + if (event === 'updated') themeListeners.push(listener); + }, +}; + +installElectronStub({ + nativeImage: fakeNativeImageModule, + nativeTheme, + Tray: FakeTray, + Menu: {buildFromTemplate: () => ({})}, + clipboard: {}, + app: {getPath: () => resourcesPath}, +}); + +const {applyDesktopWindowBehaviorSettings, initializeDesktopTray, setDesktopTrayUnreadBadge} = await import( + './DesktopTray.ts' +); + +const controller = { + createWindow: () => null, + getMainWindow: () => null, + isMainWindowTakenOver: () => false, + hideWindow: () => {}, + setQuitting: () => {}, + showWindow: () => {}, +}; + +function topRight(image) { + return pixel(image.toBitmap(), 16, 12, 3); +} + +describe('desktop tray icon state', () => { + test('follows the unread badge, theme and colored setting, and survives tray recreation', () => { + initializeDesktopTray(controller); + const [tray] = trays; + const plainWhite = tray.image; + assert.deepEqual(topRight(plainWhite), [0xff, 0xff, 0xff, 0xff], 'white glyph on a dark taskbar'); + assert.match(tray.toolTips.at(-1), /^Fluxer[^-]*$/); + + setDesktopTrayUnreadBadge(3); + assert.equal(tray.images.length, 2); + assert.deepEqual(topRight(tray.image), [0x00, 0x00, 0xdd, 0xff], 'red dot'); + assert.match(tray.toolTips.at(-1), / - Unread messages: 3$/); + + const dotted = tray.image; + setDesktopTrayUnreadBadge(4); + setDesktopTrayUnreadBadge(4); + setDesktopTrayUnreadBadge(-1); + assert.equal(tray.images.length, 2, 'the image is only set when the dot appears or disappears'); + assert.match(tray.toolTips.at(-1), / - Unread messages$/); + + setDesktopTrayUnreadBadge(0); + assert.equal(tray.image, plainWhite, 'clearing reuses the cached plain image'); + setDesktopTrayUnreadBadge(2); + assert.equal(tray.image, dotted, 'the dotted image is cached too'); + + nativeTheme.shouldUseDarkColorsForSystemIntegratedUI = false; + for (const listener of themeListeners) listener(); + assert.deepEqual(topRight(tray.image), [0x00, 0x00, 0xdd, 0xff]); + assert.deepEqual(pixel(tray.image.toBitmap(), 16, 2, 8), [0x1c, 0x1c, 0x1c, 0xff], 'dark glyph on a light taskbar'); + + settings.coloredTrayIcon = true; + applyDesktopWindowBehaviorSettings(); + assert.deepEqual(pixel(tray.image.toBitmap(), 16, 2, 8), [0xd9, 0x41, 0x46, 0xff], 'colored icon'); + assert.deepEqual(topRight(tray.image), [0x00, 0x00, 0xdd, 0xff], 'the dot stays on the colored icon'); + + settings.showTrayIcon = false; + applyDesktopWindowBehaviorSettings(); + assert.equal(tray.destroyed, true); + setDesktopTrayUnreadBadge(0); + settings.showTrayIcon = true; + applyDesktopWindowBehaviorSettings(); + assert.equal(trays.length, 2); + assert.deepEqual(trays[1].images.length, 1); + assert.deepEqual(pixel(trays[1].image.toBitmap(), 16, 2, 8), [0xd9, 0x41, 0x46, 0xff]); + assert.notDeepEqual(topRight(trays[1].image), [0x00, 0x00, 0xdd, 0xff], 'a recreated tray shows the current state'); + setDesktopTrayUnreadBadge(1); + assert.deepEqual(topRight(trays[1].image), [0x00, 0x00, 0xdd, 0xff]); + }); +}); diff --git a/fluxer_desktop/src/main/DesktopTrayIconSetting.test.mjs b/fluxer_desktop/src/main/DesktopTrayIconSetting.test.mjs new file mode 100644 index 000000000..efcf5ec06 --- /dev/null +++ b/fluxer_desktop/src/main/DesktopTrayIconSetting.test.mjs @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import {describe, test} from 'node:test'; +import {installElectronStub} from './LocalAppTestSupport.test.mjs'; + +installElectronStub(); + +const {getDesktopWindowBehaviorSettings, loadDesktopConfig, setDesktopWindowBehaviorSettings} = await import( + '../common/DesktopConfig.ts' +); + +function loadSettings(windowBehavior) { + const userDataPath = fs.mkdtempSync(path.join(os.tmpdir(), 'fluxer-desktop-tray-setting-test-')); + fs.writeFileSync(path.join(userDataPath, 'settings.json'), JSON.stringify({window_behavior: windowBehavior})); + loadDesktopConfig(userDataPath); + return userDataPath; +} + +function readPersisted(userDataPath) { + return JSON.parse(fs.readFileSync(path.join(userDataPath, 'settings.json'), 'utf8')).window_behavior; +} + +describe('colored tray icon setting', () => { + test('defaults to the monochrome icon for existing and new configs', () => { + loadSettings(undefined); + assert.equal(getDesktopWindowBehaviorSettings().coloredTrayIcon, false); + loadSettings({showTrayIcon: true}); + assert.equal(getDesktopWindowBehaviorSettings().coloredTrayIcon, false); + }); + + test('drops values that are not booleans', () => { + for (const value of ['true', 1, null, {}]) { + loadSettings({coloredTrayIcon: value}); + assert.equal(getDesktopWindowBehaviorSettings().coloredTrayIcon, false, String(value)); + } + }); + + test('persists and reloads the choice without touching the tray visibility', () => { + const userDataPath = loadSettings({showTrayIcon: false}); + assert.equal(setDesktopWindowBehaviorSettings({coloredTrayIcon: true}).coloredTrayIcon, true); + assert.equal(readPersisted(userDataPath).coloredTrayIcon, true); + loadDesktopConfig(userDataPath); + const settings = getDesktopWindowBehaviorSettings(); + assert.equal(settings.coloredTrayIcon, true); + assert.equal(settings.showTrayIcon, false); + }); +}); diff --git a/fluxer_desktop/src/main/IpcHandlers.ts b/fluxer_desktop/src/main/IpcHandlers.ts index 763e3044d..035a8ad32 100644 --- a/fluxer_desktop/src/main/IpcHandlers.ts +++ b/fluxer_desktop/src/main/IpcHandlers.ts @@ -26,6 +26,7 @@ import { applyDesktopWindowBehaviorSettings, desktopTrayChangePendingRestart, hasActiveDesktopTray, + setDesktopTrayUnreadBadge, updateTrayRuntimeState, } from '@electron/main/DesktopTray'; import {getDesktopUpdateState, observeDesktopUpdateState, startDesktopUpdate} from '@electron/main/DesktopUpdateGate'; @@ -57,6 +58,7 @@ import {registerPasskeyHandlers} from '@electron/main/Passkeys'; import {getAppMetricsSnapshot, getDesktopInfo, getGpuInfo} from '@electron/main/PlatformInfo'; import { createPrivilegedRendererDocumentOwners, + isPrivilegedRendererDocumentSender, requirePrivilegedRendererDocumentSender, } from '@electron/main/PrivilegedRendererDocuments'; import {getDesktopSelectedInstanceClient} from '@electron/main/SelectedInstanceFetch'; @@ -72,6 +74,7 @@ import { setHardwareAccelerationDisabled, setHardwareAccelerationDisabledAndRestart, } from '@electron/main/Troubleshooting'; +import {parseUnreadBadge, UNREAD_BADGE_DOT} from '@electron/main/UnreadBadge'; import {registerVoiceBackgroundMediaCacheHandlers} from '@electron/main/VoiceBackgroundMediaCache'; import { focusVoiceDebugEventSinkPopout, @@ -119,6 +122,9 @@ function normalizeDesktopWindowBehaviorUpdate(value: unknown): Partial { - if (process.platform === 'darwin') { - app.setBadgeCount(count); - } else if (process.platform === 'win32') { - setWindowsBadgeOverlay(getMainWindow(), count); - } else { - app.setBadgeCount(count); - } + ipcMain.on('set-badge-count', (event, count: unknown) => { + const badge = parseUnreadBadge(count); + if (badge === null || !isPrivilegedRendererDocumentSender(event)) return; + applyUnreadBadge(Math.max(badge, 0)); + }); + ipcMain.on('set-unread-badge', (event, value: unknown) => { + const badge = parseUnreadBadge(value); + if (badge === null || !isPrivilegedRendererDocumentSender(event)) return; + applyUnreadBadge(badge); }); ipcMain.on('set-zoom-factor', (event, factor: number) => { const win = BrowserWindow.fromWebContents(event.sender); diff --git a/fluxer_desktop/src/main/TrayIconImage.test.mjs b/fluxer_desktop/src/main/TrayIconImage.test.mjs new file mode 100644 index 000000000..b82a16cb4 --- /dev/null +++ b/fluxer_desktop/src/main/TrayIconImage.test.mjs @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import assert from 'node:assert/strict'; +import {describe, test} from 'node:test'; +import {installElectronStub} from './LocalAppTestSupport.test.mjs'; +import {BLUE_BGRA, discBitmap, FakeNativeImage, fakeNativeImageModule, pixel} from './TrayIconTestSupport.test.mjs'; + +installElectronStub({nativeImage: fakeNativeImageModule}); + +const {paintMonochromeGlyph, paintTrayIndicatorDot, renderTrayIcon, resolveTrayIconAppearance} = await import( + './TrayIconImage.ts' +); + +describe('tray icon appearance', () => { + test('macOS always uses the template image', () => { + for (const coloredTrayIcon of [false, true]) { + for (const darkSystemUI of [false, true]) { + assert.equal(resolveTrayIconAppearance({platform: 'darwin', coloredTrayIcon, darkSystemUI}), 'template'); + } + } + }); + + test('Windows follows the taskbar theme unless the colored icon is chosen', () => { + assert.equal(resolveTrayIconAppearance({platform: 'win32', coloredTrayIcon: false, darkSystemUI: true}), 'white'); + assert.equal(resolveTrayIconAppearance({platform: 'win32', coloredTrayIcon: false, darkSystemUI: false}), 'black'); + assert.equal(resolveTrayIconAppearance({platform: 'win32', coloredTrayIcon: true, darkSystemUI: false}), 'colored'); + }); + + test('Linux uses a white glyph whatever the system theme says', () => { + assert.equal(resolveTrayIconAppearance({platform: 'linux', coloredTrayIcon: false, darkSystemUI: false}), 'white'); + assert.equal(resolveTrayIconAppearance({platform: 'linux', coloredTrayIcon: true, darkSystemUI: false}), 'colored'); + }); +}); + +describe('monochrome glyph', () => { + test('keeps the body, cuts out the light mark and leaves the outside transparent', () => { + const bitmap = discBitmap(32); + paintMonochromeGlyph(bitmap, [0xff, 0xff, 0xff]); + assert.deepEqual(pixel(bitmap, 32, 16, 6), [0xff, 0xff, 0xff, 0xff]); + assert.deepEqual(pixel(bitmap, 32, 16, 16), [0, 0, 0, 0]); + assert.deepEqual(pixel(bitmap, 32, 0, 0), [0, 0, 0, 0]); + }); + + test('tints the glyph with premultiplied color', () => { + const bitmap = discBitmap(32); + paintMonochromeGlyph(bitmap, [0x1c, 0x1c, 0x1c]); + assert.deepEqual(pixel(bitmap, 32, 16, 6), [0x1c, 0x1c, 0x1c, 0xff]); + }); + + test('an icon without a light mark keeps its whole silhouette', () => { + const bitmap = Buffer.alloc(4 * 4 * 4); + for (let offset = 0; offset < bitmap.length; offset += 4) bitmap.set(BLUE_BGRA, offset); + bitmap.set([0, 0, 0, 0], 0); + paintMonochromeGlyph(bitmap, [0xff, 0xff, 0xff]); + assert.deepEqual(pixel(bitmap, 4, 0, 0), [0, 0, 0, 0]); + assert.deepEqual(pixel(bitmap, 4, 2, 2), [0xff, 0xff, 0xff, 0xff]); + }); +}); + +describe('unread dot', () => { + test('draws an opaque dot in the top-right corner with a transparent gap around it', () => { + const size = 64; + const bitmap = Buffer.alloc(size * size * 4, 0xff); + paintTrayIndicatorDot(bitmap, size, size, [0x00, 0x00, 0xdd]); + const radius = size * 0.22; + assert.deepEqual(pixel(bitmap, size, Math.floor(size - radius), Math.floor(radius)), [0x00, 0x00, 0xdd, 0xff]); + assert.deepEqual(pixel(bitmap, size, Math.floor(size - radius), Math.floor(radius * 2 + 2)), [0, 0, 0, 0]); + assert.deepEqual(pixel(bitmap, size, 4, size - 4), [0xff, 0xff, 0xff, 0xff]); + }); +}); + +describe('renderTrayIcon', () => { + test('returns the base image untouched for the colored icon without a dot', () => { + const base = FakeNativeImage.fromBitmap(16); + assert.equal(renderTrayIcon(base, 'colored', false), base); + const template = FakeNativeImage.fromBitmap(16); + template.setTemplateImage(true); + assert.equal(renderTrayIcon(template, 'template', false), template); + }); + + test('paints every scale factor and keeps the template flag', () => { + const base = FakeNativeImage.fromBitmap(16); + base.addRepresentation({scaleFactor: 2, width: 32, height: 32, buffer: discBitmap(32)}); + base.setTemplateImage(true); + const result = renderTrayIcon(base, 'template', true); + assert.notEqual(result, base); + assert.deepEqual(result.getScaleFactors(), [1, 2]); + assert.equal(result.isTemplateImage(), true); + assert.deepEqual(pixel(result.toBitmap({scaleFactor: 2}), 32, 25, 7), [0, 0, 0, 0xff]); + assert.deepEqual(pixel(base.toBitmap({scaleFactor: 2}), 32, 25, 7), BLUE_BGRA, 'the base image is not mutated'); + }); + + test('combines the monochrome glyph with a red dot', () => { + const result = renderTrayIcon(FakeNativeImage.fromBitmap(32), 'white', true); + assert.equal(result.isTemplateImage(), false); + const bitmap = result.toBitmap(); + assert.deepEqual(pixel(bitmap, 32, 25, 7), [0x00, 0x00, 0xdd, 0xff]); + assert.deepEqual(pixel(bitmap, 32, 6, 16), [0xff, 0xff, 0xff, 0xff]); + }); + + test('skips representations whose bitmap does not match their size', () => { + const base = FakeNativeImage.fromBitmap(16); + base.toBitmap = () => Buffer.alloc(3); + assert.equal(renderTrayIcon(base, 'white', true), base); + }); +}); diff --git a/fluxer_desktop/src/main/TrayIconImage.ts b/fluxer_desktop/src/main/TrayIconImage.ts new file mode 100644 index 000000000..79e15e86d --- /dev/null +++ b/fluxer_desktop/src/main/TrayIconImage.ts @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {type NativeImage, nativeImage} from 'electron'; + +export type TrayIconAppearance = 'colored' | 'template' | 'white' | 'black'; + +type Bgr = Readonly<[number, number, number]>; + +const DOT_RADIUS_RATIO = 0.22; +const DOT_GAP_RATIO = 0.0625; +const SUBSAMPLES = 4; +const MIN_GLYPH_CONTRAST = 32; +const GLYPH_CUTOUT_START = 0.1; +const GLYPH_CUTOUT_END = 0.5; +const DOT_BGR: Bgr = [0x00, 0x00, 0xdd]; +const TEMPLATE_DOT_BGR: Bgr = [0x00, 0x00, 0x00]; +const GLYPH_BGR: Readonly> = { + white: [0xff, 0xff, 0xff], + black: [0x1c, 0x1c, 0x1c], +}; + +export function resolveTrayIconAppearance(options: { + platform: NodeJS.Platform; + coloredTrayIcon: boolean; + darkSystemUI: boolean; +}): TrayIconAppearance { + if (options.platform === 'darwin') return 'template'; + if (options.coloredTrayIcon) return 'colored'; + if (options.platform === 'win32' && !options.darkSystemUI) return 'black'; + return 'white'; +} + +function coverage(x: number, y: number, centerX: number, centerY: number, radius: number): number { + let hits = 0; + for (let sy = 0; sy < SUBSAMPLES; sy++) { + const dy = y + (sy + 0.5) / SUBSAMPLES - centerY; + for (let sx = 0; sx < SUBSAMPLES; sx++) { + const dx = x + (sx + 0.5) / SUBSAMPLES - centerX; + if (dx * dx + dy * dy <= radius * radius) { + hits++; + } + } + } + return hits / (SUBSAMPLES * SUBSAMPLES); +} + +function luminance(bitmap: Buffer, offset: number): number { + const alpha = bitmap[offset + 3]; + if (alpha === 0) return 0; + return (0.0722 * bitmap[offset] + 0.7152 * bitmap[offset + 1] + 0.2126 * bitmap[offset + 2]) * (255 / alpha); +} + +function bodyLuminance(bitmap: Buffer): number | null { + const histogram = new Array(256).fill(0); + let opaque = 0; + for (let offset = 0; offset < bitmap.length; offset += 4) { + if (bitmap[offset + 3] !== 255) continue; + histogram[Math.min(255, Math.round(luminance(bitmap, offset)))]++; + opaque++; + } + let seen = 0; + for (let level = 0; level < 256; level++) { + seen += histogram[level]; + if (seen * 2 >= opaque && opaque > 0) return level; + } + return null; +} + +export function paintMonochromeGlyph(bitmap: Buffer, glyphBgr: Bgr): void { + const body = bodyLuminance(bitmap); + let highlight = 0; + for (let offset = 0; offset < bitmap.length; offset += 4) { + if (bitmap[offset + 3] >= 128) { + highlight = Math.max(highlight, luminance(bitmap, offset)); + } + } + const contrast = body === null ? 0 : highlight - body; + for (let offset = 0; offset < bitmap.length; offset += 4) { + let alpha = bitmap[offset + 3]; + if (body !== null && contrast >= MIN_GLYPH_CONTRAST) { + const position = (luminance(bitmap, offset) - body) / contrast; + const cutout = Math.min( + 1, + Math.max(0, (position - GLYPH_CUTOUT_START) / (GLYPH_CUTOUT_END - GLYPH_CUTOUT_START)), + ); + alpha = Math.round(alpha * (1 - cutout)); + } + for (let channel = 0; channel < 3; channel++) { + bitmap[offset + channel] = Math.round((glyphBgr[channel] * alpha) / 255); + } + bitmap[offset + 3] = alpha; + } +} + +export function paintTrayIndicatorDot(bitmap: Buffer, width: number, height: number, dotBgr: Bgr): void { + const size = Math.min(width, height); + const radius = size * DOT_RADIUS_RATIO; + const cutRadius = radius + size * DOT_GAP_RATIO; + const centerX = width - radius; + const centerY = radius; + const minX = Math.max(0, Math.floor(centerX - cutRadius)); + const maxY = Math.min(height, Math.ceil(centerY + cutRadius)); + for (let y = 0; y < maxY; y++) { + for (let x = minX; x < width; x++) { + const cut = coverage(x, y, centerX, centerY, cutRadius); + if (cut === 0) continue; + const dot = coverage(x, y, centerX, centerY, radius); + const offset = (y * width + x) * 4; + for (let channel = 0; channel < 3; channel++) { + bitmap[offset + channel] = Math.round(bitmap[offset + channel] * (1 - cut) + dotBgr[channel] * dot); + } + bitmap[offset + 3] = Math.round(bitmap[offset + 3] * (1 - cut) + 255 * dot); + } + } +} + +export function renderTrayIcon(base: NativeImage, appearance: TrayIconAppearance, indicator: boolean): NativeImage { + const monochrome = appearance === 'white' || appearance === 'black'; + if (!monochrome && !indicator) { + return base; + } + const result = nativeImage.createEmpty(); + const scaleFactors = base.getScaleFactors(); + for (const scaleFactor of scaleFactors.length > 0 ? scaleFactors : [1]) { + const size = base.getSize(scaleFactor); + const width = Math.round(size.width * scaleFactor); + const height = Math.round(size.height * scaleFactor); + const bitmap = Buffer.from(base.toBitmap({scaleFactor})); + if (width === 0 || height === 0 || bitmap.length !== width * height * 4) continue; + if (monochrome) { + paintMonochromeGlyph(bitmap, GLYPH_BGR[appearance]); + } + if (indicator) { + paintTrayIndicatorDot(bitmap, width, height, appearance === 'template' ? TEMPLATE_DOT_BGR : DOT_BGR); + } + result.addRepresentation({scaleFactor, width, height, buffer: bitmap}); + } + if (result.isEmpty()) { + return base; + } + result.setTemplateImage(appearance === 'template'); + return result; +} diff --git a/fluxer_desktop/src/main/TrayIconTestSupport.test.mjs b/fluxer_desktop/src/main/TrayIconTestSupport.test.mjs new file mode 100644 index 000000000..a1175a257 --- /dev/null +++ b/fluxer_desktop/src/main/TrayIconTestSupport.test.mjs @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +export const BLUE_BGRA = [0xd9, 0x41, 0x46, 0xff]; +export const WHITE_BGRA = [0xff, 0xff, 0xff, 0xff]; + +export function pixel(bitmap, width, x, y) { + const offset = (y * width + x) * 4; + return [...bitmap.subarray(offset, offset + 4)]; +} + +export function discBitmap(size) { + const bitmap = Buffer.alloc(size * size * 4); + const center = size / 2; + for (let y = 0; y < size; y++) { + for (let x = 0; x < size; x++) { + const dx = x + 0.5 - center; + const dy = y + 0.5 - center; + if (dx * dx + dy * dy > center * center) continue; + const color = Math.abs(dy) < size / 16 && Math.abs(dx) < size / 4 ? WHITE_BGRA : BLUE_BGRA; + bitmap.set(color, (y * size + x) * 4); + } + } + return bitmap; +} + +export class FakeNativeImage { + constructor() { + this.representations = new Map(); + this.template = false; + } + + static fromBitmap(size, scaleFactor = 1) { + const image = new FakeNativeImage(); + const width = size * scaleFactor; + image.addRepresentation({scaleFactor, width, height: width, buffer: discBitmap(width)}); + return image; + } + + addRepresentation({scaleFactor = 1, width, height, buffer}) { + this.representations.set(scaleFactor, {width, height, buffer: Buffer.from(buffer)}); + } + + isEmpty() { + return this.representations.size === 0; + } + + getScaleFactors() { + return [...this.representations.keys()]; + } + + getSize(scaleFactor = 1) { + const representation = this.representations.get(scaleFactor) ?? [...this.representations.values()][0]; + if (!representation) return {width: 0, height: 0}; + return {width: representation.width / scaleFactor, height: representation.height / scaleFactor}; + } + + toBitmap({scaleFactor = 1} = {}) { + return Buffer.from(this.representations.get(scaleFactor).buffer); + } + + resize() { + return this; + } + + setTemplateImage(template) { + this.template = template; + } + + isTemplateImage() { + return this.template; + } +} + +export const fakeNativeImageModule = { + createEmpty: () => new FakeNativeImage(), + createFromPath: () => FakeNativeImage.fromBitmap(16), +}; diff --git a/fluxer_desktop/src/main/UnreadBadge.test.mjs b/fluxer_desktop/src/main/UnreadBadge.test.mjs new file mode 100644 index 000000000..a13511a2d --- /dev/null +++ b/fluxer_desktop/src/main/UnreadBadge.test.mjs @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import assert from 'node:assert/strict'; +import {describe, test} from 'node:test'; +import {installElectronStub} from './LocalAppTestSupport.test.mjs'; + +installElectronStub(); + +const {UNREAD_BADGE_DOT, describeUnreadBadge, parseUnreadBadge} = await import('./UnreadBadge.ts'); + +describe('parseUnreadBadge', () => { + test('accepts the dot, zero and positive counts', () => { + assert.equal(parseUnreadBadge(UNREAD_BADGE_DOT), -1); + assert.equal(parseUnreadBadge(0), 0); + assert.equal(parseUnreadBadge(7), 7); + assert.equal(parseUnreadBadge(Number.MAX_SAFE_INTEGER), Number.MAX_SAFE_INTEGER); + }); + + test('rejects anything that is not a safe integer of at least -1', () => { + for (const value of [ + -2, + 1.5, + Number.NaN, + Number.POSITIVE_INFINITY, + 2 ** 53, + '3', + null, + undefined, + {count: 1}, + true, + ]) { + assert.equal(parseUnreadBadge(value), null, String(value)); + } + }); +}); + +describe('describeUnreadBadge', () => { + test('describes the dot and counts and nothing for zero', () => { + assert.equal(describeUnreadBadge(UNREAD_BADGE_DOT), 'Unread messages'); + assert.equal(describeUnreadBadge(1234), 'Unread messages: 1,234'); + assert.equal(describeUnreadBadge(0), null); + }); +}); diff --git a/fluxer_desktop/src/main/UnreadBadge.ts b/fluxer_desktop/src/main/UnreadBadge.ts new file mode 100644 index 000000000..8b85db021 --- /dev/null +++ b/fluxer_desktop/src/main/UnreadBadge.ts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {getNativeLocale, t} from '@electron/main/MainI18n'; + +export const UNREAD_BADGE_DOT = -1; + +export function parseUnreadBadge(value: unknown): number | null { + if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < UNREAD_BADGE_DOT) { + return null; + } + return value; +} + +function formatBadgeCount(count: number): string { + try { + return count.toLocaleString(getNativeLocale()); + } catch { + return String(count); + } +} + +export function describeUnreadBadge(badge: number): string | null { + if (badge === UNREAD_BADGE_DOT) { + return t('desktop.badge.unreadMessages'); + } + if (badge <= 0) { + return null; + } + return t('desktop.badge.unreadMessagesCount', {count: formatBadgeCount(badge)}); +} diff --git a/fluxer_desktop/src/main/WindowsBadge.ts b/fluxer_desktop/src/main/WindowsBadge.ts index 052841399..9e343dadd 100644 --- a/fluxer_desktop/src/main/WindowsBadge.ts +++ b/fluxer_desktop/src/main/WindowsBadge.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import path from 'node:path'; -import {getNativeLocale, t} from '@electron/main/MainI18n'; +import {describeUnreadBadge, UNREAD_BADGE_DOT} from '@electron/main/UnreadBadge'; import type {BrowserWindow, NativeImage} from 'electron'; import {nativeImage} from 'electron'; @@ -34,35 +34,18 @@ function ensureInitialized(): void { } } -function formatBadgeCount(count: number): string { - try { - return count.toLocaleString(getNativeLocale()); - } catch { - return String(count); - } -} - function getOverlayIconData(count: number): { index: number | null; description: string; } { - if (count === -1) { - return { - index: 10, - description: t('desktop.badge.unreadMessages'), - }; + const description = describeUnreadBadge(count) ?? 'No Notifications'; + if (count === UNREAD_BADGE_DOT) { + return {index: 10, description}; } - if (count === 0) { - return { - index: null, - description: 'No Notifications', - }; + if (count <= 0) { + return {index: null, description}; } - const index = Math.max(1, Math.min(count, 10)) - 1; - return { - index, - description: t('desktop.badge.unreadMessagesCount', {count: formatBadgeCount(count)}), - }; + return {index: Math.min(count, 10) - 1, description}; } function applyOverlay(win: BrowserWindow | null, count: number, force: boolean): void { diff --git a/fluxer_desktop/src/preload/index.ts b/fluxer_desktop/src/preload/index.ts index 96b58fca9..ed387c443 100644 --- a/fluxer_desktop/src/preload/index.ts +++ b/fluxer_desktop/src/preload/index.ts @@ -587,6 +587,9 @@ const api: ElectronAPI = { setBadgeCount: (count: number): void => { ipcRenderer.send('set-badge-count', count); }, + setUnreadBadge: (badge: number): void => { + ipcRenderer.send('set-unread-badge', badge); + }, setNativeLocale: (locale: string, strings: Record): void => { ipcRenderer.send('native-locale-set', {locale, strings}); },