From 5ba9265de65a42bf364bbf0dbfeaa1432c3508e9 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:13:50 +0530 Subject: [PATCH 01/86] Update source file strings.xml --- app/src/main/res/values/strings.xml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f2d59759..ba891f36 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -408,8 +408,6 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. - Modify System Settings - Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -436,15 +434,6 @@ Switch to Essentials Keyboard is active and ready! - Enabled - Disabled - - Adaptive Brightness - Toggle adaptive brightness - - Maps Power Saving - Toggle maps power saving mode - Search for Tools, Mods and Tweaks Search Stop From c7e680f74b4b4c56359654bf986aad5bda35d6c1 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:23 +0530 Subject: [PATCH 02/86] New translations strings.xml (Romanian) --- app/src/main/res/values-ro/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index b5f2102e..bb812770 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From ae2c9c449079d6b10de64784ecd009cf7c42110a Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:25 +0530 Subject: [PATCH 03/86] New translations strings.xml (French) --- app/src/main/res/values-fr/strings.xml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 5ce97d95..16ded80e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -44,7 +44,7 @@ Écran allumé Volume Haut Volume Bas - Basculer la lampe-torche + Allumer/éteindre la lampe-torche Jouer/mettre en pause le média Prochain média Média précédent @@ -389,6 +389,8 @@ Modifier les paramètres de sécurité Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Permission de superposition Required to display the notification lighting overlay on the screen Administrateur de l\'appareil @@ -402,8 +404,8 @@ Ensure the service is not killed by the system to save power. Essentials - Geler - Gelée + Gel d\'applis + Gel d\'applis DIY Applications désactivées Do It Yourself @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Rechercher Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination à proximité From b8fa26c82b6eab250cace0e57eb854024b9ac793 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:26 +0530 Subject: [PATCH 04/86] New translations strings.xml (Spanish) --- app/src/main/res/values-es/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From a53704f81463df17cfda9f16ca47de8de9c0dc6b Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:27 +0530 Subject: [PATCH 05/86] New translations strings.xml (Afrikaans) --- app/src/main/res/values-af/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-af/strings.xml b/app/src/main/res/values-af/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-af/strings.xml +++ b/app/src/main/res/values-af/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 5166ee72c987d100cfc8d4f26aaadef71f579650 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:28 +0530 Subject: [PATCH 06/86] New translations strings.xml (Arabic) --- app/src/main/res/values-ar/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From a5e88cf5a1fbc2cd226643bfdce1a876aaea5976 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:30 +0530 Subject: [PATCH 07/86] New translations strings.xml (Catalan) --- app/src/main/res/values-ca/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 192c5857941fc5516967d4cd17849af13c29d770 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:31 +0530 Subject: [PATCH 08/86] New translations strings.xml (Czech) --- app/src/main/res/values-cs/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From e8b5c77c8f7b495242a98978929a99f69734646f Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:32 +0530 Subject: [PATCH 09/86] New translations strings.xml (Danish) --- app/src/main/res/values-da/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 28d22c8a65b5f5c09e7ac4957fdc319e84570698 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:33 +0530 Subject: [PATCH 10/86] New translations strings.xml (German) --- app/src/main/res/values-de/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d6b7016f..7eff30e1 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -389,6 +389,8 @@ Geschützte Einstellungen umschreiben Benötigt für Statusleisten-Symbole und Sicherheit bei Bildschirmsperre Benötigt, um das Nachtlicht zu aktivieren. Über ADB oder Root gewähren. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay-Berechtigung Benötigt, um das Benachrichtigungslicht auf dem Bildschirm anzuzeigen Geräteadministrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Suche nach Werkzeugen, Modifikationen und Anpassungen Suche Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Reisealarm aktiv - %1$s verbleibend + %1$s verbleibend (%2$d%%) Reisefortschritt Zeigt die Entfernung zum Zielort in Echtzeit an Ziel in der Nähe From 30f6a83a570340f87a29ddaa8880d7bcf31b797d Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:34 +0530 Subject: [PATCH 11/86] New translations strings.xml (Greek) --- app/src/main/res/values-el/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 3d8642a354f7baa0b294ea7b470ef4fe4f603ac3 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:35 +0530 Subject: [PATCH 12/86] New translations strings.xml (Finnish) --- app/src/main/res/values-fi/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 16808972144abc3294ca7f5aad8fdefb7ebfecdf Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:36 +0530 Subject: [PATCH 13/86] New translations strings.xml (Hebrew) --- app/src/main/res/values-he/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From be9030a2ade0933204bdc45e202044a5dfaab8c9 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:38 +0530 Subject: [PATCH 14/86] New translations strings.xml (Hungarian) --- app/src/main/res/values-hu/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From bed888a24a48bd0af548dae2c60002fa85616096 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:39 +0530 Subject: [PATCH 15/86] New translations strings.xml (Italian) --- app/src/main/res/values-it/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 020bc7f7..ff41b9fb 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -390,6 +390,8 @@ Le app bloccate richiederanno l\'autenticazione all\'apertura. L\'app rimarrà s Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -413,6 +415,12 @@ Le app bloccate richiederanno l\'autenticazione all\'apertura. L\'app rimarrà s Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -789,7 +797,7 @@ Le app bloccate richiederanno l\'autenticazione all\'apertura. L\'app rimarrà s %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From cd075247f3bd8061cd28dbc491bfc9a6c786381d Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:40 +0530 Subject: [PATCH 16/86] New translations strings.xml (Japanese) --- app/src/main/res/values-ja/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index fcb832b5..de0ceaf6 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 551168ab08fc32f07f8b870eccf84e00651d30fb Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:41 +0530 Subject: [PATCH 17/86] New translations strings.xml (Korean) --- app/src/main/res/values-ko/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From fa9bda2a61411abe9e61c8458878c9b661fd7f2a Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:42 +0530 Subject: [PATCH 18/86] New translations strings.xml (Dutch) --- app/src/main/res/values-nl/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From a6a610980cacdef6afd700ff4b6054cc094e5b27 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:43 +0530 Subject: [PATCH 19/86] New translations strings.xml (Norwegian) --- app/src/main/res/values-no/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 283f168f2748e2278731af38213d677b3cb0e381 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:44 +0530 Subject: [PATCH 20/86] New translations strings.xml (Polish) --- app/src/main/res/values-pl/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 73d6c019766b5e7ed160198b2042e5b4ac600730 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:45 +0530 Subject: [PATCH 21/86] New translations strings.xml (Portuguese) --- app/src/main/res/values-pt/strings.xml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 8e2f74e7..7e0295c0 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -27,7 +27,7 @@ Another note, the biometric authentication prompt only lets you use STRONG secure class methods. Face unlock security methods in WEAK class in devices such as Pixel 7 will only be able to utilize the available other STRONG auth methods such as fingerprint or pin. Enable Button Remap - Use Shizuku + Use Shizuku or Root or Root Works with screen off (Recommended) Shizuku is not running Detected %1$s @@ -373,7 +373,7 @@ Shizuku Required for advanced commands. Install Shizuku from the Play Store. Install Shizuku - Shizuku permission + Grant Permission Required to run power-saving commands while maps is navigating. Root Access Permissions required for system actions using Root privileges. @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -736,7 +744,7 @@ Notification lighting does not work It depends on the OEM. Some like OneUI does not seem to allow overlays above the AOD preventing the lighting effects being shown. In this case, try the ambient display as a workaround. Button remap does not work while display is off - Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. + Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku or Root\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. Flashlight brightness does not work Only a limited number of devices got hardware and software support adjusting the flashlight intensity. \n\n\'The minimum version of Android is 13 (SDK33).\nFlashlight brightness control only supports HAL version 3.8 and higher, so among the supported devices, the latest ones (For example, Pixel 6/7, Samsung S23, etc.)\'\npolodarb/Flashlight-Tiramisu What the hell is this app? @@ -755,14 +763,14 @@ Essentials Bug Report Send via - Location reached - Get notified when you arrive at a specific destination. + Are we there yet? + Destination nearby alerts Destination Set Destination Tracking: %1$.4f, %2$.4f No destination set - Open your map app, pick a location, and share it to Essentials. - Radius: %d m + Open Google Maps, pick a location, and share it to Essentials. + Alert Radius: %d m Distance to trigger the alarm Enable notification Location @@ -787,7 +795,7 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel Alarm active + Travel alarm active %1$s remaining Travel Progress Shows real-time distance to destination From 67569c2b1a3995579a17db87f9623df613a39180 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:47 +0530 Subject: [PATCH 22/86] New translations strings.xml (Russian) --- app/src/main/res/values-ru/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 2fb71eb390e2b1e51301ec843d40572e4c58254f Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:48 +0530 Subject: [PATCH 23/86] New translations strings.xml (Serbian (Cyrillic)) --- app/src/main/res/values-sr/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From bb5ab13c143f481abf3064419150fb8f8af1ad4f Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:49 +0530 Subject: [PATCH 24/86] New translations strings.xml (Swedish) --- app/src/main/res/values-sv/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 38bdcd3925893f4362fe1174ffae63d0893d4fa8 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:50 +0530 Subject: [PATCH 25/86] New translations strings.xml (Turkish) --- app/src/main/res/values-tr/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 07e1f4c9ab518733fd06bda915acd6c74686e987 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:51 +0530 Subject: [PATCH 26/86] New translations strings.xml (Ukrainian) --- app/src/main/res/values-uk/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 64c0543ce21b32c7b0b9905765ae28be7e4c140a Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:52 +0530 Subject: [PATCH 27/86] New translations strings.xml (Chinese Simplified) --- app/src/main/res/values-zh/strings.xml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 8e2f74e7..7e0295c0 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -27,7 +27,7 @@ Another note, the biometric authentication prompt only lets you use STRONG secure class methods. Face unlock security methods in WEAK class in devices such as Pixel 7 will only be able to utilize the available other STRONG auth methods such as fingerprint or pin. Enable Button Remap - Use Shizuku + Use Shizuku or Root or Root Works with screen off (Recommended) Shizuku is not running Detected %1$s @@ -373,7 +373,7 @@ Shizuku Required for advanced commands. Install Shizuku from the Play Store. Install Shizuku - Shizuku permission + Grant Permission Required to run power-saving commands while maps is navigating. Root Access Permissions required for system actions using Root privileges. @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -736,7 +744,7 @@ Notification lighting does not work It depends on the OEM. Some like OneUI does not seem to allow overlays above the AOD preventing the lighting effects being shown. In this case, try the ambient display as a workaround. Button remap does not work while display is off - Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. + Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku or Root\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. Flashlight brightness does not work Only a limited number of devices got hardware and software support adjusting the flashlight intensity. \n\n\'The minimum version of Android is 13 (SDK33).\nFlashlight brightness control only supports HAL version 3.8 and higher, so among the supported devices, the latest ones (For example, Pixel 6/7, Samsung S23, etc.)\'\npolodarb/Flashlight-Tiramisu What the hell is this app? @@ -755,14 +763,14 @@ Essentials Bug Report Send via - Location reached - Get notified when you arrive at a specific destination. + Are we there yet? + Destination nearby alerts Destination Set Destination Tracking: %1$.4f, %2$.4f No destination set - Open your map app, pick a location, and share it to Essentials. - Radius: %d m + Open Google Maps, pick a location, and share it to Essentials. + Alert Radius: %d m Distance to trigger the alarm Enable notification Location @@ -787,7 +795,7 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel Alarm active + Travel alarm active %1$s remaining Travel Progress Shows real-time distance to destination From 5a2533a5a11e01f2928454c946eb1321f92a3fc8 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:53 +0530 Subject: [PATCH 28/86] New translations strings.xml (Chinese Traditional) --- app/src/main/res/values-zh/strings.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 7e0295c0..468fc383 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -27,7 +27,7 @@ Another note, the biometric authentication prompt only lets you use STRONG secure class methods. Face unlock security methods in WEAK class in devices such as Pixel 7 will only be able to utilize the available other STRONG auth methods such as fingerprint or pin. Enable Button Remap - Use Shizuku or Root or Root + Use Shizuku Works with screen off (Recommended) Shizuku is not running Detected %1$s @@ -373,7 +373,7 @@ Shizuku Required for advanced commands. Install Shizuku from the Play Store. Install Shizuku - Grant Permission + Shizuku permission Required to run power-saving commands while maps is navigating. Root Access Permissions required for system actions using Root privileges. @@ -744,7 +744,7 @@ Notification lighting does not work It depends on the OEM. Some like OneUI does not seem to allow overlays above the AOD preventing the lighting effects being shown. In this case, try the ambient display as a workaround. Button remap does not work while display is off - Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku or Root\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. + Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. Flashlight brightness does not work Only a limited number of devices got hardware and software support adjusting the flashlight intensity. \n\n\'The minimum version of Android is 13 (SDK33).\nFlashlight brightness control only supports HAL version 3.8 and higher, so among the supported devices, the latest ones (For example, Pixel 6/7, Samsung S23, etc.)\'\npolodarb/Flashlight-Tiramisu What the hell is this app? @@ -763,14 +763,14 @@ Essentials Bug Report Send via - Are we there yet? - Destination nearby alerts + Location reached + Get notified when you arrive at a specific destination. Destination Set Destination Tracking: %1$.4f, %2$.4f No destination set - Open Google Maps, pick a location, and share it to Essentials. - Alert Radius: %d m + Open your map app, pick a location, and share it to Essentials. + Radius: %d m Distance to trigger the alarm Enable notification Location @@ -795,8 +795,8 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel alarm active - %1$s remaining + Travel Alarm active + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 88662ff3627b8cdb6943976abb9492a131383f45 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:54 +0530 Subject: [PATCH 29/86] New translations strings.xml (English) --- app/src/main/res/values-en/strings.xml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 49850d64..468fc383 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -787,8 +795,8 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel alarm active - %1$s remaining + Travel Alarm active + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 0f208515d22ff63ff1dbcb74cf5aaab74b36520a Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:55 +0530 Subject: [PATCH 30/86] New translations strings.xml (Vietnamese) --- app/src/main/res/values-vi/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 4301ad88d81a857b5b57eb823a6305ce63bf20b8 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:56 +0530 Subject: [PATCH 31/86] New translations strings.xml (Portuguese, Brazilian) --- app/src/main/res/values-pt/strings.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 7e0295c0..468fc383 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -27,7 +27,7 @@ Another note, the biometric authentication prompt only lets you use STRONG secure class methods. Face unlock security methods in WEAK class in devices such as Pixel 7 will only be able to utilize the available other STRONG auth methods such as fingerprint or pin. Enable Button Remap - Use Shizuku or Root or Root + Use Shizuku Works with screen off (Recommended) Shizuku is not running Detected %1$s @@ -373,7 +373,7 @@ Shizuku Required for advanced commands. Install Shizuku from the Play Store. Install Shizuku - Grant Permission + Shizuku permission Required to run power-saving commands while maps is navigating. Root Access Permissions required for system actions using Root privileges. @@ -744,7 +744,7 @@ Notification lighting does not work It depends on the OEM. Some like OneUI does not seem to allow overlays above the AOD preventing the lighting effects being shown. In this case, try the ambient display as a workaround. Button remap does not work while display is off - Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku or Root\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. + Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. Flashlight brightness does not work Only a limited number of devices got hardware and software support adjusting the flashlight intensity. \n\n\'The minimum version of Android is 13 (SDK33).\nFlashlight brightness control only supports HAL version 3.8 and higher, so among the supported devices, the latest ones (For example, Pixel 6/7, Samsung S23, etc.)\'\npolodarb/Flashlight-Tiramisu What the hell is this app? @@ -763,14 +763,14 @@ Essentials Bug Report Send via - Are we there yet? - Destination nearby alerts + Location reached + Get notified when you arrive at a specific destination. Destination Set Destination Tracking: %1$.4f, %2$.4f No destination set - Open Google Maps, pick a location, and share it to Essentials. - Alert Radius: %d m + Open your map app, pick a location, and share it to Essentials. + Radius: %d m Distance to trigger the alarm Enable notification Location @@ -795,8 +795,8 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel alarm active - %1$s remaining + Travel Alarm active + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 39dde87bfebd5517d771395e09a891ca293b7938 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:58 +0530 Subject: [PATCH 32/86] New translations strings.xml (Sinhala) --- app/src/main/res/values-si/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From d5dca3d3b1dc8c9480e19bfdd61de19dc2166b75 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 17:25:59 +0530 Subject: [PATCH 33/86] New translations strings.xml (Acholi) --- app/src/main/res/values-ach/strings.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ach/strings.xml b/app/src/main/res/values-ach/strings.xml index 8e2f74e7..468fc383 100644 --- a/app/src/main/res/values-ach/strings.xml +++ b/app/src/main/res/values-ach/strings.xml @@ -389,6 +389,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -412,6 +414,12 @@ Enable in settings Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + Adaptive Brightness + Toggle adaptive brightness + Maps Power Saving + Toggle maps power saving mode Search for Tools, Mods and Tweaks Search Stop @@ -788,7 +796,7 @@ %1$d m %1$.1f km Travel Alarm active - %1$s remaining + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 1f042d68e18a0c318c51e7edb3d696293780f9df Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 18:26:27 +0530 Subject: [PATCH 34/86] Update source file strings.xml --- app/src/main/res/values/strings.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ba891f36..f2d59759 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -408,6 +408,8 @@ Write Secure Settings Required for Statusbar icons and Screen Locked Security Needed to toggle Night Light. Grant via ADB or root. + Modify System Settings + Required to toggle Adaptive Brightness and other system settings Overlay Permission Required to display the notification lighting overlay on the screen Device Administrator @@ -434,6 +436,15 @@ Switch to Essentials Keyboard is active and ready! + Enabled + Disabled + + Adaptive Brightness + Toggle adaptive brightness + + Maps Power Saving + Toggle maps power saving mode + Search for Tools, Mods and Tweaks Search Stop From 982dc086442b53bb76ae4c7c6e036a85175964ea Mon Sep 17 00:00:00 2001 From: sameerasw Date: Thu, 15 Jan 2026 18:47:40 +0530 Subject: [PATCH 35/86] Initial battery widget impleemntation --- app/build.gradle.kts | 8 +- app/src/main/AndroidManifest.xml | 16 ++ .../essentials/FeatureSettingsActivity.kt | 7 + .../domain/registry/FeatureRegistry.kt | 13 ++ .../services/widgets/BatteriesWidget.kt | 93 +++++++++++ .../widgets/BatteriesWidgetReceiver.kt | 29 ++++ .../configs/BatteriesSettingsUI.kt | 46 ++++++ .../essentials/utils/BatteryRingDrawer.kt | 156 ++++++++++++++++++ app/src/main/res/values/strings.xml | 3 + .../main/res/xml/batteries_widget_info.xml | 9 + 10 files changed, 378 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt create mode 100644 app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt create mode 100644 app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt create mode 100644 app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt create mode 100644 app/src/main/res/xml/batteries_widget_info.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 67dc4616..06c6fee5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -56,8 +56,8 @@ dependencies { // Android 12+ SplashScreen API with backward compatibility attributes implementation("androidx.core:core-splashscreen:1.0.1") - // Force latest Material3 1.5.0-alpha10 for ToggleButton & ButtonGroup support - implementation("androidx.compose.material3:material3:1.5.0-alpha10") + // Force latest Material3 1.5.0-alpha12 for ToggleButton & ButtonGroup support + implementation("androidx.compose.material3:material3:1.5.0-alpha12") implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.ui.graphics) @@ -104,4 +104,8 @@ dependencies { // SymSpell for word suggestions implementation("com.darkrockstudios:symspellkt:3.4.0") + + // Glance for Widgets + implementation("androidx.glance:glance-appwidget:1.1.0") + implementation("androidx.glance:glance-material3:1.1.0") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0358cf2e..87d7bf27 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -248,6 +248,22 @@ android:resource="@xml/screen_off_widget_info" /> + + + + + + + + + + + { + BatteriesSettingsUI( + viewModel = viewModel, + modifier = Modifier.padding(top = 16.dp) + ) + } // else -> default UI (optional cleanup) } } diff --git a/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt b/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt index 2c99e1fe..1eb38c99 100644 --- a/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt +++ b/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt @@ -509,6 +509,19 @@ object FeatureRegistry { ) { override fun isEnabled(viewModel: MainViewModel) = true override fun onToggle(viewModel: MainViewModel, context: Context, enabled: Boolean) {} + }, + + object : Feature( + id = "Batteries", + title = R.string.feat_batteries_title, + iconRes = R.drawable.rounded_battery_charging_60_24, + category = R.string.cat_tools, + description = R.string.feat_batteries_desc, + showToggle = false, + hasMoreSettings = true + ) { + override fun isEnabled(viewModel: MainViewModel) = true + override fun onToggle(viewModel: MainViewModel, context: Context, enabled: Boolean) {} } ) } \ No newline at end of file diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt new file mode 100644 index 00000000..86b3dcaf --- /dev/null +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -0,0 +1,93 @@ +package com.sameerasw.essentials.services.widgets + +import android.content.Context +import android.os.BatteryManager +import androidx.glance.GlanceId +import androidx.glance.GlanceModifier +import androidx.glance.GlanceTheme +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.provideContent +import androidx.glance.background +import androidx.glance.layout.Alignment +import androidx.glance.layout.Box +import androidx.glance.layout.fillMaxSize +import androidx.glance.layout.padding +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat +import androidx.core.graphics.ColorUtils +import androidx.glance.Image +import androidx.glance.ImageProvider +import com.sameerasw.essentials.R + +class BatteriesWidget : GlanceAppWidget() { + + override suspend fun provideGlance(context: Context, id: GlanceId) { + provideContent { + GlanceTheme { + val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager + val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + + // Use ContextThemeWrapper to ensure we get the App's theme colors (Light/Dark aware) + val themedContext = android.view.ContextThemeWrapper(context, R.style.Theme_Essentials) + + // Resolve Colors from Attributes + val primaryColor = resolveColor(themedContext, android.R.attr.colorActivatedHighlight) + val errorColor = resolveColor(themedContext, android.R.attr.colorError) + val surfaceVariant = resolveColor(themedContext, android.R.attr.colorPressedHighlight) + val surfaceColor = resolveColor(themedContext, android.R.attr.colorForeground) + + // Icon Tint: User preferred the previous primary color look + val iconTint = primaryColor + + // Custom Warning Color (Amber) + val warningColor = android.graphics.Color.parseColor("#FFC107") + + val ringColor = when { + batteryLevel <= 10 -> errorColor + batteryLevel < 20 -> warningColor + else -> primaryColor + } + + val trackColor = ColorUtils.setAlphaComponent(surfaceVariant, 76) // ~30% alpha + + // Generate Bitmap + val bitmapSize = 512 + val deviceIcon = ContextCompat.getDrawable(context, R.drawable.rounded_mobile_text_2_24) + + val bitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( + context, + batteryLevel, + ringColor, + trackColor, + iconTint, + surfaceColor, + deviceIcon, + bitmapSize, + bitmapSize + ) + + Box( + modifier = GlanceModifier + .fillMaxSize() + .background(GlanceTheme.colors.surface) + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + Image( + provider = ImageProvider(bitmap), + contentDescription = "Battery Level $batteryLevel%", + modifier = GlanceModifier.fillMaxSize() + ) + } + } + } + } + + private fun resolveColor(context: Context, @androidx.annotation.AttrRes attr: Int): Int { + val typedValue = android.util.TypedValue() + val theme = context.theme + theme.resolveAttribute(attr, typedValue, true) + return typedValue.data + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt new file mode 100644 index 00000000..f10fa869 --- /dev/null +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt @@ -0,0 +1,29 @@ +package com.sameerasw.essentials.services.widgets + +import android.content.Context +import android.content.Intent +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.GlanceAppWidgetReceiver +import kotlinx.coroutines.launch + +class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { + override val glanceAppWidget: GlanceAppWidget = BatteriesWidget() + + override fun onReceive(context: Context, intent: Intent) { + super.onReceive(context, intent) + if (intent.action == Intent.ACTION_POWER_CONNECTED || + intent.action == Intent.ACTION_POWER_DISCONNECTED || + intent.action == Intent.ACTION_BATTERY_LOW || + intent.action == Intent.ACTION_BATTERY_OKAY) { + + // Trigger update + val glanceAppWidgetManager = androidx.glance.appwidget.GlanceAppWidgetManager(context) + kotlinx.coroutines.MainScope().launch { + val glanceIds = glanceAppWidgetManager.getGlanceIds(BatteriesWidget::class.java) + glanceIds.forEach { glanceId -> + glanceAppWidget.update(context, glanceId) + } + } + } + } +} diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt new file mode 100644 index 00000000..8b05f65f --- /dev/null +++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt @@ -0,0 +1,46 @@ +package com.sameerasw.essentials.ui.composables.configs + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.sameerasw.essentials.R +import com.sameerasw.essentials.viewmodels.MainViewModel + +@OptIn(androidx.compose.material3.ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun BatteriesSettingsUI( + viewModel: MainViewModel, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier.padding(16.dp), + horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally + ) { + Text( + text = stringResource(R.string.feat_batteries_desc), + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 32.dp) + ) + + // Preview of the Battery Indicator + androidx.compose.material3.CircularWavyProgressIndicator( + progress = { 0.75f }, // Demo value + modifier = Modifier.size(120.dp), + color = androidx.compose.ui.graphics.Color(0xFF4CAF50), + trackColor = androidx.compose.ui.graphics.Color.Gray.copy(alpha = 0.2f) + ) + + Text( + text = "Widget Preview Style", + style = androidx.compose.material3.MaterialTheme.typography.labelMedium, + modifier = Modifier.padding(top = 16.dp) + ) + } +} diff --git a/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt b/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt new file mode 100644 index 00000000..191dabc9 --- /dev/null +++ b/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt @@ -0,0 +1,156 @@ +package com.sameerasw.essentials.utils + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import android.graphics.drawable.Drawable +import androidx.annotation.ColorInt +import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.toBitmap +import com.sameerasw.essentials.R +import kotlin.math.PI + +object BatteryRingDrawer { + + fun drawBatteryWidget( + context: Context, + batteryLevel: Int, + @ColorInt ringColor: Int, + @ColorInt trackColor: Int, + @ColorInt iconTint: Int, + @ColorInt backgroundColor: Int, + deviceIcon: Drawable?, + width: Int, + height: Int + ): Bitmap { + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + + // Config + val strokeWidth = width * 0.11f // Slightly thicker than before? + val trackStrokeWidth = strokeWidth * 0.5f + + val padding = strokeWidth + (width * 0.05f) + val rect = RectF( + padding, + padding, + width - padding, + height - padding + ) + val radius = rect.width() / 2f + + val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.STROKE + strokeCap = Paint.Cap.ROUND + } + + val topGapDegrees = 40f + + val capAngleDegrees = ((strokeWidth / 2f) / radius) * (180f / PI.toFloat()) + val trackCapAngleDegrees = ((trackStrokeWidth / 2f) / radius) * (180f / PI.toFloat()) + + // Start drawing from: -90 (top) + half gap + val startAngle = -90f + (topGapDegrees / 2) + val totalAvailableSweep = 360f - topGapDegrees + + val clampedLevel = batteryLevel.coerceIn(0, 100) + + val progressSweepRaw = (clampedLevel / 100f) * totalAvailableSweep + + // Visual Gap between segments + val segmentGapDegrees = 8f + + // --- Draw Progress Arc --- + if (clampedLevel > 0) { + paint.strokeWidth = strokeWidth + paint.color = ringColor + + val visualStart = startAngle + val visualEnd = if (clampedLevel >= 100) { + startAngle + totalAvailableSweep + } else { + (startAngle + progressSweepRaw - (segmentGapDegrees / 2)).coerceAtLeast(startAngle) + } + + val visualSpan = visualEnd - visualStart + + if (visualSpan > (capAngleDegrees * 2)) { + val drawStart = visualStart + capAngleDegrees + val drawSweep = (visualEnd - capAngleDegrees) - drawStart + if (drawSweep > 0) { + canvas.drawArc(rect, drawStart, drawSweep, false, paint) + } + } else { + if (visualSpan > 0) { + val center = visualStart + visualSpan/2 + paint.style = Paint.Style.FILL + canvas.drawArc(rect, center, 0.1f, false, paint) + } + } + } + + // --- Draw Track Arc (Filler) --- + if (clampedLevel < 100) { + paint.strokeWidth = trackStrokeWidth + paint.color = trackColor + + val visualStart = (startAngle + progressSweepRaw + (segmentGapDegrees / 2)) + .coerceAtMost(startAngle + totalAvailableSweep) + + val visualEnd = startAngle + totalAvailableSweep + + val visualSpan = visualEnd - visualStart + if (visualSpan > (trackCapAngleDegrees * 2)) { + val drawStart = visualStart + trackCapAngleDegrees + val drawSweep = (visualEnd - trackCapAngleDegrees) - drawStart + if (drawSweep > 0) { + canvas.drawArc(rect, drawStart, drawSweep, false, paint) + } + } + } + + // --- Draw Small Battery Icon (Top) --- + val smallIconRadius = strokeWidth * 1.3f + val centerX = width / 2f + val topY = padding + val iconCenterY = rect.top + + val smallIconPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.FILL + color = ringColor + } + // Bubble Background + canvas.drawCircle(centerX, iconCenterY, smallIconRadius, smallIconPaint) + + val smallIconDrawable = ContextCompat.getDrawable(context, R.drawable.rounded_battery_android_frame_3_24) + smallIconDrawable?.let { + val iconSize = (smallIconRadius * 1.5f).toInt() + val iconLeft = (centerX - iconSize / 2).toInt() + val iconTop = (iconCenterY - iconSize / 2).toInt() + it.setBounds(iconLeft, iconTop, iconLeft + iconSize, iconTop + iconSize) + it.setTint(backgroundColor) + it.draw(canvas) + } + + // --- Draw Center Device Icon --- + val innerPadding = strokeWidth * 1.5f + deviceIcon?.let { + val availableWidth = (rect.width() - innerPadding * 2).toInt() + val availableHeight = (rect.height() - innerPadding * 2).toInt() + val iconBitmap = it.toBitmap(availableWidth, availableHeight) + + val iconLeft = (width - iconBitmap.width) / 2f + val iconTop = (height - iconBitmap.height) / 2f + + val iconPaint = Paint(Paint.ANTI_ALIAS_FLAG) + val colorFilter = android.graphics.PorterDuffColorFilter(iconTint, android.graphics.PorterDuff.Mode.SRC_IN) + iconPaint.colorFilter = colorFilter + + canvas.drawBitmap(iconBitmap, iconLeft, iconTop, iconPaint) + } + + return bitmap + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f2d59759..b08b6704 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -893,4 +893,7 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status \ No newline at end of file diff --git a/app/src/main/res/xml/batteries_widget_info.xml b/app/src/main/res/xml/batteries_widget_info.xml new file mode 100644 index 00000000..936c457b --- /dev/null +++ b/app/src/main/res/xml/batteries_widget_info.xml @@ -0,0 +1,9 @@ + + From d67c8c69f501bbab22b731c1e2802566de01884a Mon Sep 17 00:00:00 2001 From: sameerasw Date: Thu, 15 Jan 2026 20:29:01 +0530 Subject: [PATCH 36/86] AirSync integration with battery --- app/src/main/AndroidManifest.xml | 11 ++ .../data/repository/SettingsRepository.kt | 10 +- .../receivers/AirSyncBridgeReceiver.kt | 62 ++++++++ .../services/widgets/BatteriesWidget.kt | 132 ++++++++++++------ .../widgets/BatteriesWidgetReceiver.kt | 12 +- .../configs/BatteriesSettingsUI.kt | 60 +++++--- .../essentials/viewmodels/MainViewModel.kt | 27 ++++ .../res/drawable/rounded_laptop_mac_24.xml | 10 ++ .../main/res/drawable/rounded_mobile_24.xml | 5 + app/src/main/res/values/strings.xml | 4 + 10 files changed, 270 insertions(+), 63 deletions(-) create mode 100644 app/src/main/java/com/sameerasw/essentials/services/receivers/AirSyncBridgeReceiver.kt create mode 100644 app/src/main/res/drawable/rounded_laptop_mac_24.xml create mode 100644 app/src/main/res/drawable/rounded_mobile_24.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 87d7bf27..4ea94d0c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,6 +24,8 @@ + + @@ -521,6 +523,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt index f00ca1b1..17aa1d28 100644 --- a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt +++ b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt @@ -107,6 +107,12 @@ class SettingsRepository(private val context: Context) { const val KEY_KEYBOARD_PITCH_BLACK = "keyboard_pitch_black" const val KEY_KEYBOARD_CLIPBOARD_ENABLED = "keyboard_clipboard_enabled" + // Essentials-AirSync Bridge + const val KEY_AIRSYNC_CONNECTION_ENABLED = "airsync_connection_enabled" + const val KEY_MAC_BATTERY_LEVEL = "mac_battery_level" + const val KEY_MAC_BATTERY_IS_CHARGING = "mac_battery_is_charging" + const val KEY_MAC_BATTERY_LAST_UPDATED = "mac_battery_last_updated" + const val KEY_AIRSYNC_MAC_CONNECTED = "airsync_mac_connected" } // Observe changes @@ -300,8 +306,8 @@ class SettingsRepository(private val context: Context) { val wrapperMap = mutableMapOf>() p.all.forEach { (key, value) -> - // Skip app lists as requested - if (key.endsWith("_selected_apps") || key == "freeze_auto_excluded_apps") { + // Skip app lists as requested, and stale data + if (key.endsWith("_selected_apps") || key == "freeze_auto_excluded_apps" || key.startsWith("mac_battery_") || key == "airsync_mac_connected") { return@forEach } diff --git a/app/src/main/java/com/sameerasw/essentials/services/receivers/AirSyncBridgeReceiver.kt b/app/src/main/java/com/sameerasw/essentials/services/receivers/AirSyncBridgeReceiver.kt new file mode 100644 index 00000000..a5c39945 --- /dev/null +++ b/app/src/main/java/com/sameerasw/essentials/services/receivers/AirSyncBridgeReceiver.kt @@ -0,0 +1,62 @@ +package com.sameerasw.essentials.services.receivers + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import com.sameerasw.essentials.data.repository.SettingsRepository +import kotlinx.coroutines.launch + +class AirSyncBridgeReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == "com.sameerasw.essentials.action.UPDATE_MAC_BATTERY") { + val pendingResult = goAsync() + val level = intent.getIntExtra("level", -1) + val isCharging = intent.getBooleanExtra("isCharging", false) + val lastUpdated = intent.getLongExtra("lastUpdated", System.currentTimeMillis()) + val isConnected = intent.getBooleanExtra("isConnected", true) + + android.util.Log.d("AirSyncBridge", "Received Mac status: level=$level, connected=$isConnected") + + val repository = SettingsRepository(context) + if (repository.getBoolean(SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED)) { + repository.putInt(SettingsRepository.KEY_MAC_BATTERY_LEVEL, level) + repository.putBoolean(SettingsRepository.KEY_MAC_BATTERY_IS_CHARGING, isCharging) + repository.putLong(SettingsRepository.KEY_MAC_BATTERY_LAST_UPDATED, lastUpdated) + repository.putBoolean(SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED, isConnected) + + // Trigger widget update directly + val glanceAppWidgetManager = androidx.glance.appwidget.GlanceAppWidgetManager(context) + // Use IO dispatcher to avoid main thread jank/timeouts + kotlinx.coroutines.CoroutineScope(kotlinx.coroutines.Dispatchers.IO).launch { + try { + // Define keys matching BatteriesWidget + val KEY_AIRSYNC_ENABLED = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED) + val KEY_MAC_LEVEL = androidx.datastore.preferences.core.intPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_MAC_BATTERY_LEVEL) + val KEY_MAC_CONNECTED = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED) + + val glanceIds = glanceAppWidgetManager.getGlanceIds(com.sameerasw.essentials.services.widgets.BatteriesWidget::class.java) + + android.util.Log.d("AirSyncBridge", "Found ${glanceIds.size} widgets to update") + + glanceIds.forEach { glanceId -> + androidx.glance.appwidget.state.updateAppWidgetState(context, glanceId) { prefs -> + prefs[KEY_AIRSYNC_ENABLED] = true + prefs[KEY_MAC_LEVEL] = level + prefs[KEY_MAC_CONNECTED] = isConnected + } + + android.util.Log.d("AirSyncBridge", "Triggering update for glanceId: $glanceId") + com.sameerasw.essentials.services.widgets.BatteriesWidget().update(context, glanceId) + } + } catch (e: Exception) { + android.util.Log.e("AirSyncBridge", "Error updating widget", e) + } finally { + pendingResult.finish() + } + } + } else { + pendingResult.finish() + } + } + } +} diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index 86b3dcaf..cd83f7dd 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -1,3 +1,4 @@ + package com.sameerasw.essentials.services.widgets import android.content.Context @@ -10,8 +11,14 @@ import androidx.glance.appwidget.provideContent import androidx.glance.background import androidx.glance.layout.Alignment import androidx.glance.layout.Box +import androidx.glance.layout.Column +import androidx.glance.layout.Row +import androidx.glance.layout.Spacer +import androidx.glance.layout.fillMaxHeight import androidx.glance.layout.fillMaxSize import androidx.glance.layout.padding +import androidx.glance.layout.width +import androidx.glance.layout.height import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat @@ -25,60 +32,103 @@ class BatteriesWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { provideContent { GlanceTheme { + // System Service and Android Battery val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) - // Use ContextThemeWrapper to ensure we get the App's theme colors (Light/Dark aware) - val themedContext = android.view.ContextThemeWrapper(context, R.style.Theme_Essentials) + // Mac Battery + val prefs = androidx.glance.currentState() + val KEY_AIRSYNC_ENABLED = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED) + val KEY_MAC_LEVEL = androidx.datastore.preferences.core.intPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_MAC_BATTERY_LEVEL) + val KEY_MAC_CONNECTED = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED) + + // Read from Glance State + val isAirSyncEnabled = prefs[KEY_AIRSYNC_ENABLED] ?: false + val macLevel = prefs[KEY_MAC_LEVEL] ?: -1 + val isMacConnected = prefs[KEY_MAC_CONNECTED] ?: false + + val showMac = isAirSyncEnabled && macLevel != -1 && isMacConnected + + val isMacFresh = true + + android.util.Log.d("BatteriesWidget", "Update: enabled=$isAirSyncEnabled, level=$macLevel, connected=$isMacConnected -> showMac=$showMac") - // Resolve Colors from Attributes + // Style & Colors + val themedContext = android.view.ContextThemeWrapper(context, R.style.Theme_Essentials) val primaryColor = resolveColor(themedContext, android.R.attr.colorActivatedHighlight) val errorColor = resolveColor(themedContext, android.R.attr.colorError) val surfaceVariant = resolveColor(themedContext, android.R.attr.colorPressedHighlight) val surfaceColor = resolveColor(themedContext, android.R.attr.colorForeground) - - // Icon Tint: User preferred the previous primary color look - val iconTint = primaryColor - - // Custom Warning Color (Amber) val warningColor = android.graphics.Color.parseColor("#FFC107") - - val ringColor = when { - batteryLevel <= 10 -> errorColor - batteryLevel < 20 -> warningColor - else -> primaryColor - } - val trackColor = ColorUtils.setAlphaComponent(surfaceVariant, 76) // ~30% alpha + val trackColor = ColorUtils.setAlphaComponent(surfaceVariant, 76) - // Generate Bitmap - val bitmapSize = 512 - val deviceIcon = ContextCompat.getDrawable(context, R.drawable.rounded_mobile_text_2_24) + // Layout + if (showMac) { + Row( + modifier = GlanceModifier + .fillMaxSize() + .background(GlanceTheme.colors.surface) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalAlignment = Alignment.CenterVertically + ) { + // Android Section + val androidRingColor = when { + batteryLevel <= 10 -> errorColor + batteryLevel < 20 -> warningColor + else -> primaryColor + } + + val deviceIcon = ContextCompat.getDrawable(context, R.drawable.rounded_mobile_24) + val androidBitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( + context, batteryLevel, androidRingColor, trackColor, primaryColor, surfaceColor, deviceIcon, 300, 300 + ) + Box(modifier = GlanceModifier.defaultWeight().fillMaxHeight(), contentAlignment = Alignment.Center) { + Image(provider = ImageProvider(androidBitmap), contentDescription = "Android: $batteryLevel%", modifier = GlanceModifier.fillMaxSize()) + } + + Spacer(modifier = GlanceModifier.width(8.dp)) - val bitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( - context, - batteryLevel, - ringColor, - trackColor, - iconTint, - surfaceColor, - deviceIcon, - bitmapSize, - bitmapSize - ) + // Mac Section + val macRingColor = when { + macLevel <= 10 -> errorColor + macLevel < 20 -> warningColor + else -> primaryColor + } + val macIcon = ContextCompat.getDrawable(context, R.drawable.rounded_laptop_mac_24) + val macBitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( + context, macLevel, macRingColor, trackColor, primaryColor, surfaceColor, macIcon, 300, 300 + ) + Box(modifier = GlanceModifier.defaultWeight().fillMaxHeight(), contentAlignment = Alignment.Center) { + Image(provider = ImageProvider(macBitmap), contentDescription = "Mac: $macLevel%", modifier = GlanceModifier.fillMaxSize()) + } + + } + } else { + val ringColor = when { + batteryLevel <= 10 -> errorColor + batteryLevel < 20 -> warningColor + else -> primaryColor + } + val deviceIcon = ContextCompat.getDrawable(context, R.drawable.rounded_mobile_24) + val bitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( + context, batteryLevel, ringColor, trackColor, primaryColor, surfaceColor, deviceIcon, 512, 512 + ) - Box( - modifier = GlanceModifier - .fillMaxSize() - .background(GlanceTheme.colors.surface) - .padding(16.dp), - contentAlignment = Alignment.Center - ) { - Image( - provider = ImageProvider(bitmap), - contentDescription = "Battery Level $batteryLevel%", - modifier = GlanceModifier.fillMaxSize() - ) + Box( + modifier = GlanceModifier + .fillMaxSize() + .background(GlanceTheme.colors.surface) + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + Image( + provider = ImageProvider(bitmap), + contentDescription = "Battery Level $batteryLevel%", + modifier = GlanceModifier.fillMaxSize() + ) + } } } } diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt index f10fa869..72faf2ed 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt @@ -14,7 +14,8 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { if (intent.action == Intent.ACTION_POWER_CONNECTED || intent.action == Intent.ACTION_POWER_DISCONNECTED || intent.action == Intent.ACTION_BATTERY_LOW || - intent.action == Intent.ACTION_BATTERY_OKAY) { + intent.action == Intent.ACTION_BATTERY_OKAY || + intent.action == android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE) { // Trigger update val glanceAppWidgetManager = androidx.glance.appwidget.GlanceAppWidgetManager(context) @@ -24,6 +25,15 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { glanceAppWidget.update(context, glanceId) } } + + try { + val requestIntent = Intent("com.sameerasw.airsync.action.REQUEST_MAC_BATTERY").apply { + setPackage("com.sameerasw.airsync") + } + context.sendBroadcast(requestIntent, "com.sameerasw.permission.ESSENTIALS_AIRSYNC_BRIDGE") + } catch (e: Exception) { + // Ignore if AirSync not installed/found + } } } } diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt index 8b05f65f..392c5120 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt @@ -4,12 +4,15 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.material3.ListItem import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.sameerasw.essentials.R +import com.sameerasw.essentials.ui.components.containers.RoundedCardContainer import com.sameerasw.essentials.viewmodels.MainViewModel @OptIn(androidx.compose.material3.ExperimentalMaterial3ExpressiveApi::class) @@ -18,29 +21,48 @@ fun BatteriesSettingsUI( viewModel: MainViewModel, modifier: Modifier = Modifier ) { + val context = LocalContext.current Column( modifier = modifier.padding(16.dp), horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally ) { - Text( - text = stringResource(R.string.feat_batteries_desc), - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 32.dp) - ) + // AirSync Interaction + RoundedCardContainer { + val isAirSyncInstalled = try { + context.packageManager.getPackageInfo("com.sameerasw.airsync", 0) + true + } catch (e: android.content.pm.PackageManager.NameNotFoundException) { + false + } - // Preview of the Battery Indicator - androidx.compose.material3.CircularWavyProgressIndicator( - progress = { 0.75f }, // Demo value - modifier = Modifier.size(120.dp), - color = androidx.compose.ui.graphics.Color(0xFF4CAF50), - trackColor = androidx.compose.ui.graphics.Color.Gray.copy(alpha = 0.2f) - ) - - Text( - text = "Widget Preview Style", - style = androidx.compose.material3.MaterialTheme.typography.labelMedium, - modifier = Modifier.padding(top = 16.dp) - ) + if (isAirSyncInstalled) { + ListItem( + headlineContent = { Text(stringResource(R.string.connect_to_airsync)) }, + supportingContent = { Text(stringResource(R.string.connect_to_airsync_summary)) }, + trailingContent = { + androidx.compose.material3.Switch( + checked = viewModel.isAirSyncConnectionEnabled.value, + onCheckedChange = { viewModel.setAirSyncConnectionEnabled(it, context) } + ) + } + ) + } else { + ListItem( + headlineContent = { Text(stringResource(R.string.download_airsync)) }, + supportingContent = { Text(stringResource(R.string.download_airsync_summary)) }, + trailingContent = { + androidx.compose.material3.Button( + onClick = { + val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse("https://play.google.com/store/apps/details?id=com.sameerasw.airsync")) + intent.flags = android.content.Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + } + ) { + Text("Download") + } + } + ) + } + } } } diff --git a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt index 73321ae0..353ef8bf 100644 --- a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt +++ b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt @@ -144,6 +144,13 @@ class MainViewModel : ViewModel() { val isKeyboardSelected = mutableStateOf(false) val isWriteSettingsEnabled = mutableStateOf(false) + // AirSync Bridge + val isAirSyncConnectionEnabled = mutableStateOf(false) + val macBatteryLevel = mutableIntStateOf(-1) + val isMacBatteryCharging = mutableStateOf(false) + val macBatteryLastUpdated = mutableStateOf(0L) + val isMacConnected = mutableStateOf(false) + private var lastUpdateCheckTime: Long = 0 private lateinit var settingsRepository: SettingsRepository private lateinit var updateRepository: UpdateRepository @@ -185,6 +192,11 @@ class MainViewModel : ViewModel() { SettingsRepository.KEY_KEYBOARD_ALWAYS_DARK -> isKeyboardAlwaysDark.value = settingsRepository.getBoolean(key, false) SettingsRepository.KEY_KEYBOARD_PITCH_BLACK -> isKeyboardPitchBlack.value = settingsRepository.getBoolean(key, false) SettingsRepository.KEY_KEYBOARD_CLIPBOARD_ENABLED -> isKeyboardClipboardEnabled.value = settingsRepository.getBoolean(key, true) + SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED -> isAirSyncConnectionEnabled.value = settingsRepository.getBoolean(key) + SettingsRepository.KEY_MAC_BATTERY_LEVEL -> macBatteryLevel.intValue = settingsRepository.getInt(key, -1) + SettingsRepository.KEY_MAC_BATTERY_IS_CHARGING -> isMacBatteryCharging.value = settingsRepository.getBoolean(key, false) + SettingsRepository.KEY_MAC_BATTERY_LAST_UPDATED -> macBatteryLastUpdated.value = settingsRepository.getLong(key, 0L) + SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED -> isMacConnected.value = settingsRepository.getBoolean(key, false) } } @@ -304,6 +316,12 @@ class MainViewModel : ViewModel() { isKeyboardPitchBlack.value = settingsRepository.getBoolean(SettingsRepository.KEY_KEYBOARD_PITCH_BLACK, false) isKeyboardClipboardEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_KEYBOARD_CLIPBOARD_ENABLED, true) + isAirSyncConnectionEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED) + macBatteryLevel.intValue = settingsRepository.getInt(SettingsRepository.KEY_MAC_BATTERY_LEVEL, -1) + isMacBatteryCharging.value = settingsRepository.getBoolean(SettingsRepository.KEY_MAC_BATTERY_IS_CHARGING, false) + macBatteryLastUpdated.value = settingsRepository.getLong(SettingsRepository.KEY_MAC_BATTERY_LAST_UPDATED, 0L) + isMacConnected.value = settingsRepository.getBoolean(SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED, false) + isScreenLockedSecurityEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_SCREEN_LOCKED_SECURITY_ENABLED) isDeviceAdminEnabled.value = isDeviceAdminActive(context) @@ -741,6 +759,15 @@ class MainViewModel : ViewModel() { settingsRepository.putBoolean(SettingsRepository.KEY_KEYBOARD_CLIPBOARD_ENABLED, enabled) } + fun setAirSyncConnectionEnabled(enabled: Boolean, context: Context) { + if (enabled) { + // Request permission if not granted, though it's signature level so should be automatic if signed correctly + // but we can check it + } + isAirSyncConnectionEnabled.value = enabled + settingsRepository.putBoolean(SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED, enabled) + } + private fun isAccessibilityServiceEnabled(context: Context): Boolean { diff --git a/app/src/main/res/drawable/rounded_laptop_mac_24.xml b/app/src/main/res/drawable/rounded_laptop_mac_24.xml new file mode 100644 index 00000000..b8c1fd91 --- /dev/null +++ b/app/src/main/res/drawable/rounded_laptop_mac_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/rounded_mobile_24.xml b/app/src/main/res/drawable/rounded_mobile_24.xml new file mode 100644 index 00000000..8fb43901 --- /dev/null +++ b/app/src/main/res/drawable/rounded_mobile_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b08b6704..8f63190f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -896,4 +896,8 @@ Batteries Monitor your device battery levels Battery Status + Connect to AirSync + Share Mac battery status with the widget + Download AirSync App + Required for Mac battery sync \ No newline at end of file From eeac9f262f90e21ed0eb28d48c579ecebe3acdf5 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Thu, 15 Jan 2026 23:26:53 +0530 Subject: [PATCH 37/86] New translations strings.xml (German) --- app/src/main/res/values-de/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7eff30e1..15b185d8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -81,10 +81,10 @@ Abort with screen off Timeout Presets Select available durations for QS tile - 5m - 10m - 30m - 1h + 5min + 10min + 30min + 1std Starting in %1$ds… %1$s remaining From f435e21d6e3aad5e2e636713248d908c2024b6dd Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 15:17:25 +0530 Subject: [PATCH 38/86] Bluetooth abttery support --- app/src/main/AndroidManifest.xml | 7 + .../data/repository/SettingsRepository.kt | 21 ++ .../domain/registry/FeatureRegistry.kt | 1 + .../domain/registry/PermissionRegistry.kt | 4 + .../services/widgets/BatteriesWidget.kt | 197 ++++++++++++------ .../widgets/BatteriesWidgetReceiver.kt | 36 +++- .../configs/BatteriesSettingsUI.kt | 72 ++++++- .../essentials/utils/BluetoothBatteryUtils.kt | 53 +++++ .../essentials/utils/PermissionUtils.kt | 15 ++ .../essentials/viewmodels/MainViewModel.kt | 28 +++ .../main/res/drawable/rounded_watch_24.xml | 5 + app/src/main/res/values/strings.xml | 4 +- 12 files changed, 369 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/com/sameerasw/essentials/utils/BluetoothBatteryUtils.kt create mode 100644 app/src/main/res/drawable/rounded_watch_24.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4ea94d0c..cf876d31 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,9 @@ + + @@ -260,6 +263,10 @@ + + + + { + val json = prefs.getString(KEY_BLUETOOTH_DEVICES_BATTERY, null) ?: return emptyList() + val type = object : TypeToken>() {}.type + return try { + gson.fromJson(json, type) ?: emptyList() + } catch (e: Exception) { + emptyList() + } + } + + fun saveBluetoothDevicesBattery(devices: List) { + val json = gson.toJson(devices) + putString(KEY_BLUETOOTH_DEVICES_BATTERY, json) + } + + fun isBluetoothDevicesEnabled(): Boolean = getBoolean(KEY_SHOW_BLUETOOTH_DEVICES, false) + fun setBluetoothDevicesEnabled(enabled: Boolean) = putBoolean(KEY_SHOW_BLUETOOTH_DEVICES, enabled) } diff --git a/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt b/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt index 1eb38c99..10a235b2 100644 --- a/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt +++ b/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt @@ -517,6 +517,7 @@ object FeatureRegistry { iconRes = R.drawable.rounded_battery_charging_60_24, category = R.string.cat_tools, description = R.string.feat_batteries_desc, + permissionKeys = listOf("BLUETOOTH_CONNECT", "BLUETOOTH_SCAN"), showToggle = false, hasMoreSettings = true ) { diff --git a/app/src/main/java/com/sameerasw/essentials/domain/registry/PermissionRegistry.kt b/app/src/main/java/com/sameerasw/essentials/domain/registry/PermissionRegistry.kt index 8ade7d30..7a8d4501 100644 --- a/app/src/main/java/com/sameerasw/essentials/domain/registry/PermissionRegistry.kt +++ b/app/src/main/java/com/sameerasw/essentials/domain/registry/PermissionRegistry.kt @@ -42,6 +42,10 @@ fun initPermissionRegistry() { PermissionRegistry.register("NOTIFICATION_LISTENER", R.string.feat_maps_power_saving_title) PermissionRegistry.register("NOTIFICATION_LISTENER", R.string.feat_notification_lighting_title) + // Bluetooth permissions + PermissionRegistry.register("BLUETOOTH_CONNECT", R.string.feat_batteries_title) + PermissionRegistry.register("BLUETOOTH_SCAN", R.string.feat_batteries_title) + // Draw over other apps permission PermissionRegistry.register("DRAW_OVER_OTHER_APPS", R.string.feat_notification_lighting_title) diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index cd83f7dd..1a287ba5 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -32,39 +32,85 @@ class BatteriesWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { provideContent { GlanceTheme { - // System Service and Android Battery + // 1. Fetch Data val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager - val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) - - // Mac Battery + val androidLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + val prefs = androidx.glance.currentState() + + // Keys val KEY_AIRSYNC_ENABLED = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED) val KEY_MAC_LEVEL = androidx.datastore.preferences.core.intPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_MAC_BATTERY_LEVEL) val KEY_MAC_CONNECTED = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED) - - // Read from Glance State + val KEY_SHOW_BLUETOOTH = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_SHOW_BLUETOOTH_DEVICES) + val KEY_BLUETOOTH_BATTERY = androidx.datastore.preferences.core.stringPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BLUETOOTH_DEVICES_BATTERY) + + // State val isAirSyncEnabled = prefs[KEY_AIRSYNC_ENABLED] ?: false val macLevel = prefs[KEY_MAC_LEVEL] ?: -1 val isMacConnected = prefs[KEY_MAC_CONNECTED] ?: false - + val isShowBluetoothEnabled = prefs[KEY_SHOW_BLUETOOTH] ?: false + val bluetoothJson = prefs[KEY_BLUETOOTH_BATTERY] + val showMac = isAirSyncEnabled && macLevel != -1 && isMacConnected - - val isMacFresh = true - - android.util.Log.d("BatteriesWidget", "Update: enabled=$isAirSyncEnabled, level=$macLevel, connected=$isMacConnected -> showMac=$showMac") - - // Style & Colors - val themedContext = android.view.ContextThemeWrapper(context, R.style.Theme_Essentials) - val primaryColor = resolveColor(themedContext, android.R.attr.colorActivatedHighlight) - val errorColor = resolveColor(themedContext, android.R.attr.colorError) - val surfaceVariant = resolveColor(themedContext, android.R.attr.colorPressedHighlight) - val surfaceColor = resolveColor(themedContext, android.R.attr.colorForeground) - val warningColor = android.graphics.Color.parseColor("#FFC107") - - val trackColor = ColorUtils.setAlphaComponent(surfaceVariant, 76) + val hasBluetooth = isShowBluetoothEnabled && !bluetoothJson.isNullOrEmpty() && bluetoothJson != "[]" + + // 2. Prepare List of Items to Display + val batteryItems = mutableListOf() - // Layout + // Android Item + batteryItems.add( + BatteryItemData( + level = androidLevel, + iconRes = R.drawable.rounded_mobile_24, + name = "Android" + ) + ) + + // Mac Item if (showMac) { + batteryItems.add( + BatteryItemData( + level = macLevel, + iconRes = R.drawable.rounded_laptop_mac_24, + name = "Mac" + ) + ) + } + + // Bluetooth Items + if (hasBluetooth) { + try { + val type = object : com.google.gson.reflect.TypeToken>() {}.type + val devices: List = com.google.gson.Gson().fromJson(bluetoothJson, type) ?: emptyList() + + devices.forEach { device -> + val iconRes = when { + device.name.contains("watch", true) -> R.drawable.rounded_watch_24 + device.name.contains("bud", true) || + device.name.contains("pod", true) || + device.name.contains("head", true) -> R.drawable.rounded_headphones_24 + else -> R.drawable.rounded_bluetooth_24 + } + batteryItems.add( + BatteryItemData( + level = device.level, + iconRes = iconRes, + name = device.name + ) + ) + } + } catch (e: Exception) { + // ignore parsing error + } + } + + // 3. Render + // Resolve Theme Colors once + val colors = resolveThemeColors(context) + + if (batteryItems.size > 1) { + // Multi-item layout Row( modifier = GlanceModifier .fillMaxSize() @@ -73,49 +119,18 @@ class BatteriesWidget : GlanceAppWidget() { horizontalAlignment = Alignment.CenterHorizontally, verticalAlignment = Alignment.CenterVertically ) { - // Android Section - val androidRingColor = when { - batteryLevel <= 10 -> errorColor - batteryLevel < 20 -> warningColor - else -> primaryColor - } - - val deviceIcon = ContextCompat.getDrawable(context, R.drawable.rounded_mobile_24) - val androidBitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( - context, batteryLevel, androidRingColor, trackColor, primaryColor, surfaceColor, deviceIcon, 300, 300 - ) - Box(modifier = GlanceModifier.defaultWeight().fillMaxHeight(), contentAlignment = Alignment.Center) { - Image(provider = ImageProvider(androidBitmap), contentDescription = "Android: $batteryLevel%", modifier = GlanceModifier.fillMaxSize()) - } - - Spacer(modifier = GlanceModifier.width(8.dp)) - - // Mac Section - val macRingColor = when { - macLevel <= 10 -> errorColor - macLevel < 20 -> warningColor - else -> primaryColor - } - val macIcon = ContextCompat.getDrawable(context, R.drawable.rounded_laptop_mac_24) - val macBitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( - context, macLevel, macRingColor, trackColor, primaryColor, surfaceColor, macIcon, 300, 300 - ) - Box(modifier = GlanceModifier.defaultWeight().fillMaxHeight(), contentAlignment = Alignment.Center) { - Image(provider = ImageProvider(macBitmap), contentDescription = "Mac: $macLevel%", modifier = GlanceModifier.fillMaxSize()) + batteryItems.forEachIndexed { index, item -> + BatteryItemBox(context, item, colors, modifier = GlanceModifier.defaultWeight().fillMaxHeight()) + + if (index < batteryItems.size - 1) { + Spacer(modifier = GlanceModifier.width(8.dp)) + } } - } } else { - val ringColor = when { - batteryLevel <= 10 -> errorColor - batteryLevel < 20 -> warningColor - else -> primaryColor - } - val deviceIcon = ContextCompat.getDrawable(context, R.drawable.rounded_mobile_24) - val bitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( - context, batteryLevel, ringColor, trackColor, primaryColor, surfaceColor, deviceIcon, 512, 512 - ) - + // Single item layout (Big) + val item = batteryItems.firstOrNull() ?: BatteryItemData(androidLevel, R.drawable.rounded_mobile_24, "Android") + Box( modifier = GlanceModifier .fillMaxSize() @@ -123,21 +138,69 @@ class BatteriesWidget : GlanceAppWidget() { .padding(16.dp), contentAlignment = Alignment.Center ) { - Image( - provider = ImageProvider(bitmap), - contentDescription = "Battery Level $batteryLevel%", - modifier = GlanceModifier.fillMaxSize() - ) + // Use a larger size for single item if needed, but the drawer handles scaling logic internally usually + // or we pass size. The previous code passed 512x512 for single. + BatteryItemBox(context, item, colors, size = 512, modifier = GlanceModifier.fillMaxSize()) } } } } } + data class BatteryItemData(val level: Int, val iconRes: Int, val name: String) + + data class ThemeColors( + val primary: Int, + val error: Int, + val warning: Int, + val track: Int, + val surface: Int + ) + + private fun resolveThemeColors(context: Context): ThemeColors { + val themedContext = android.view.ContextThemeWrapper(context, R.style.Theme_Essentials) + val primary = resolveColor(themedContext, android.R.attr.colorActivatedHighlight) + val error = resolveColor(themedContext, android.R.attr.colorError) + val surfaceVariant = resolveColor(themedContext, android.R.attr.colorPressedHighlight) + val surface = resolveColor(themedContext, android.R.attr.colorForeground) + val warning = android.graphics.Color.parseColor("#FFC107") + val track = ColorUtils.setAlphaComponent(surfaceVariant, 76) + + return ThemeColors(primary, error, warning, track, surface) + } + private fun resolveColor(context: Context, @androidx.annotation.AttrRes attr: Int): Int { val typedValue = android.util.TypedValue() val theme = context.theme theme.resolveAttribute(attr, typedValue, true) return typedValue.data } + + @androidx.compose.runtime.Composable + private fun BatteryItemBox( + context: Context, + item: BatteryItemData, + colors: ThemeColors, + size: Int = 300, + modifier: GlanceModifier = GlanceModifier + ) { + val ringColor = when { + item.level <= 10 -> colors.error + item.level < 20 -> colors.warning + else -> colors.primary + } + + val icon = ContextCompat.getDrawable(context, item.iconRes) + val bitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( + context, item.level, ringColor, colors.track, colors.primary, colors.surface, icon, size, size + ) + + Box(modifier = modifier, contentAlignment = Alignment.Center) { + Image( + provider = ImageProvider(bitmap), + contentDescription = "${item.name}: ${item.level}%", + modifier = GlanceModifier.fillMaxSize() + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt index 72faf2ed..823ef1bf 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt @@ -15,16 +15,42 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { intent.action == Intent.ACTION_POWER_DISCONNECTED || intent.action == Intent.ACTION_BATTERY_LOW || intent.action == Intent.ACTION_BATTERY_OKAY || + intent.action == "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED" || + intent.action == android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED || + intent.action == android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED || + intent.action == android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED || intent.action == android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE) { // Trigger update val glanceAppWidgetManager = androidx.glance.appwidget.GlanceAppWidgetManager(context) kotlinx.coroutines.MainScope().launch { - val glanceIds = glanceAppWidgetManager.getGlanceIds(BatteriesWidget::class.java) - glanceIds.forEach { glanceId -> - glanceAppWidget.update(context, glanceId) - } - } + // Check permissions first + val repository = com.sameerasw.essentials.data.repository.SettingsRepository(context) + val hasPerm = com.sameerasw.essentials.utils.PermissionUtils.hasBluetoothPermission(context) + + val isEnabled = repository.isBluetoothDevicesEnabled() + val bluetoothDevices = if (isEnabled && hasPerm) { + com.sameerasw.essentials.utils.BluetoothBatteryUtils.getPairedDevicesBattery(context) + } else { + emptyList() + } + + repository.saveBluetoothDevicesBattery(bluetoothDevices) + + val devicesJson = com.google.gson.Gson().toJson(bluetoothDevices) + + val glanceIds = glanceAppWidgetManager.getGlanceIds(BatteriesWidget::class.java) + glanceIds.forEach { glanceId -> + androidx.glance.appwidget.state.updateAppWidgetState(context, glanceId) { prefs -> + val KEY_SHOW = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_SHOW_BLUETOOTH_DEVICES) + val KEY_DATA = androidx.datastore.preferences.core.stringPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BLUETOOTH_DEVICES_BATTERY) + + prefs[KEY_SHOW] = isEnabled + prefs[KEY_DATA] = devicesJson + } + glanceAppWidget.update(context, glanceId) + } + } try { val requestIntent = Intent("com.sameerasw.airsync.action.REQUEST_MAC_BATTERY").apply { diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt index 392c5120..af8cfa8c 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt @@ -13,7 +13,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.sameerasw.essentials.R import com.sameerasw.essentials.ui.components.containers.RoundedCardContainer +import com.sameerasw.essentials.ui.components.containers.RoundedCardContainer import com.sameerasw.essentials.viewmodels.MainViewModel +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.remember +import androidx.compose.runtime.mutableStateOf @OptIn(androidx.compose.material3.ExperimentalMaterial3ExpressiveApi::class) @Composable @@ -26,8 +31,8 @@ fun BatteriesSettingsUI( modifier = modifier.padding(16.dp), horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally ) { - // AirSync Interaction RoundedCardContainer { + // AirSync Interaction val isAirSyncInstalled = try { context.packageManager.getPackageInfo("com.sameerasw.airsync", 0) true @@ -37,6 +42,12 @@ fun BatteriesSettingsUI( if (isAirSyncInstalled) { ListItem( + leadingContent = { + androidx.compose.material3.Icon( + painter = androidx.compose.ui.res.painterResource(R.drawable.rounded_laptop_mac_24), + contentDescription = null + ) + }, headlineContent = { Text(stringResource(R.string.connect_to_airsync)) }, supportingContent = { Text(stringResource(R.string.connect_to_airsync_summary)) }, trailingContent = { @@ -48,6 +59,12 @@ fun BatteriesSettingsUI( ) } else { ListItem( + leadingContent = { + androidx.compose.material3.Icon( + painter = androidx.compose.ui.res.painterResource(R.drawable.rounded_laptop_mac_24), + contentDescription = null + ) + }, headlineContent = { Text(stringResource(R.string.download_airsync)) }, supportingContent = { Text(stringResource(R.string.download_airsync_summary)) }, trailingContent = { @@ -63,6 +80,59 @@ fun BatteriesSettingsUI( } ) } + + // Divider? Maybe not needed inside RoundedCardContainer if items are distinct, but useful for visual separation + // But usually ListItem handles it or specific design. Assuming standard list items stack fine. + + // Bluetooth Devices + val isBluetoothEnabled = viewModel.isBluetoothDevicesEnabled.value + val isPermissionGranted = viewModel.isBluetoothPermissionGranted.value + + val launcher = androidx.activity.compose.rememberLauncherForActivityResult( + contract = androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions() + ) { permissions -> + val allGranted = permissions.values.all { it } + if (allGranted) { + viewModel.isBluetoothPermissionGranted.value = true + viewModel.setBluetoothDevicesEnabled(true, context) + } + } + + ListItem( + leadingContent = { + androidx.compose.material3.Icon( + painter = androidx.compose.ui.res.painterResource(R.drawable.rounded_bluetooth_24), + contentDescription = null + ) + }, + headlineContent = { Text(stringResource(R.string.show_bluetooth_devices)) }, + supportingContent = { Text(stringResource(R.string.show_bluetooth_devices_summary)) }, + trailingContent = { + androidx.compose.material3.Switch( + checked = isBluetoothEnabled, + onCheckedChange = { enabled -> + if (enabled) { + if (isPermissionGranted) { + viewModel.setBluetoothDevicesEnabled(true, context) + } else { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + launcher.launch( + arrayOf( + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_SCAN + ) + ) + } else { + viewModel.setBluetoothDevicesEnabled(true, context) + } + } + } else { + viewModel.setBluetoothDevicesEnabled(false, context) + } + } + ) + } + ) } } } diff --git a/app/src/main/java/com/sameerasw/essentials/utils/BluetoothBatteryUtils.kt b/app/src/main/java/com/sameerasw/essentials/utils/BluetoothBatteryUtils.kt new file mode 100644 index 00000000..392dde1c --- /dev/null +++ b/app/src/main/java/com/sameerasw/essentials/utils/BluetoothBatteryUtils.kt @@ -0,0 +1,53 @@ +package com.sameerasw.essentials.utils + +import android.annotation.SuppressLint +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothManager +import android.bluetooth.BluetoothProfile +import android.content.Context +import androidx.annotation.Keep + +object BluetoothBatteryUtils { + + @Keep + data class BluetoothDeviceBattery( + val name: String, + val level: Int, + val address: String + ) + + @SuppressLint("MissingPermission") + fun getPairedDevicesBattery(context: Context): List { + val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager + val adapter = bluetoothManager?.adapter ?: return emptyList() + + if (!adapter.isEnabled) return emptyList() + + val devices = try { + adapter.bondedDevices + } catch (e: SecurityException) { + return emptyList() + } + + val batteryList = mutableListOf() + + devices.forEach { device -> + try { + // Method 1: Reflection on device.getBatteryLevel() + // This is a hidden API, widely supported on many devices. + // Returns -1 if not supported or not connected. + val method = device.javaClass.getMethod("getBatteryLevel") + val level = method.invoke(device) as Int + + if (level != -1) { + val name = device.alias ?: device.name ?: "Unknown" + batteryList.add(BluetoothDeviceBattery(name, level, device.address)) + } + } catch (e: Exception) { + // Reflection might fail or permission issues + } + } + + return batteryList + } +} diff --git a/app/src/main/java/com/sameerasw/essentials/utils/PermissionUtils.kt b/app/src/main/java/com/sameerasw/essentials/utils/PermissionUtils.kt index 98f4ed0d..83edafc4 100644 --- a/app/src/main/java/com/sameerasw/essentials/utils/PermissionUtils.kt +++ b/app/src/main/java/com/sameerasw/essentials/utils/PermissionUtils.kt @@ -151,4 +151,19 @@ object PermissionUtils { fun canWriteSystemSettings(context: Context): Boolean { return Settings.System.canWrite(context) } + + fun hasBluetoothPermission(context: Context): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + androidx.core.content.ContextCompat.checkSelfPermission( + context, + android.Manifest.permission.BLUETOOTH_CONNECT + ) == android.content.pm.PackageManager.PERMISSION_GRANTED && + androidx.core.content.ContextCompat.checkSelfPermission( + context, + android.Manifest.permission.BLUETOOTH_SCAN + ) == android.content.pm.PackageManager.PERMISSION_GRANTED + } else { + true + } + } } diff --git a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt index 353ef8bf..e997cae0 100644 --- a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt +++ b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt @@ -86,6 +86,9 @@ class MainViewModel : ViewModel() { val isLocationPermissionGranted = mutableStateOf(false) val isBackgroundLocationPermissionGranted = mutableStateOf(false) val isFullScreenIntentPermissionGranted = mutableStateOf(false) + val isBluetoothPermissionGranted = mutableStateOf(false) + + val isBluetoothDevicesEnabled = mutableStateOf(false) @@ -227,6 +230,8 @@ class MainViewModel : ViewModel() { isKeyboardSelected.value = PermissionUtils.isKeyboardSelected(context) isWriteSettingsEnabled.value = PermissionUtils.canWriteSystemSettings(context) + isBluetoothPermissionGranted.value = PermissionUtils.hasBluetoothPermission(context) + isRootAvailable.value = com.sameerasw.essentials.utils.RootUtils.isRootAvailable() isRootPermissionGranted.value = com.sameerasw.essentials.utils.RootUtils.isRootPermissionGranted() @@ -322,6 +327,8 @@ class MainViewModel : ViewModel() { macBatteryLastUpdated.value = settingsRepository.getLong(SettingsRepository.KEY_MAC_BATTERY_LAST_UPDATED, 0L) isMacConnected.value = settingsRepository.getBoolean(SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED, false) + isBluetoothDevicesEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_SHOW_BLUETOOTH_DEVICES, false) + isScreenLockedSecurityEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_SCREEN_LOCKED_SECURITY_ENABLED) isDeviceAdminEnabled.value = isDeviceAdminActive(context) @@ -768,6 +775,17 @@ class MainViewModel : ViewModel() { settingsRepository.putBoolean(SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED, enabled) } + fun setBluetoothDevicesEnabled(enabled: Boolean, context: Context) { + isBluetoothDevicesEnabled.value = enabled + settingsRepository.setBluetoothDevicesEnabled(enabled) + + // Trigger widget update to fetch data immediately + val intent = Intent(context, com.sameerasw.essentials.services.widgets.BatteriesWidgetReceiver::class.java).apply { + action = android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE + } + context.sendBroadcast(intent) + } + private fun isAccessibilityServiceEnabled(context: Context): Boolean { @@ -804,6 +822,16 @@ class MainViewModel : ViewModel() { } } + fun requestBluetoothPermission(activity: androidx.activity.ComponentActivity) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + androidx.core.app.ActivityCompat.requestPermissions( + activity, + arrayOf(Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN), + 1005 + ) + } + } + fun requestNotificationPermission(activity: androidx.activity.ComponentActivity) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) { androidx.core.app.ActivityCompat.requestPermissions( diff --git a/app/src/main/res/drawable/rounded_watch_24.xml b/app/src/main/res/drawable/rounded_watch_24.xml new file mode 100644 index 00000000..305c0ba6 --- /dev/null +++ b/app/src/main/res/drawable/rounded_watch_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8f63190f..90874ffa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -286,6 +286,8 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices Trigger Automation @@ -897,7 +899,7 @@ Monitor your device battery levels Battery Status Connect to AirSync - Share Mac battery status with the widget + Display battery from your connected mac device in AirSync Download AirSync App Required for Mac battery sync \ No newline at end of file From 0a9e3bce40242b98c92ae50ee10723c22f59f581 Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 16:18:24 +0530 Subject: [PATCH 39/86] Batteris widget styling --- app/src/main/AndroidManifest.xml | 2 + .../services/widgets/BatteriesWidget.kt | 55 ++++++++++--------- .../widgets/BatteriesWidgetReceiver.kt | 27 ++++++++- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cf876d31..eff3fc25 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -263,10 +263,12 @@ + + 1) { // Multi-item layout @@ -138,8 +163,6 @@ class BatteriesWidget : GlanceAppWidget() { .padding(16.dp), contentAlignment = Alignment.Center ) { - // Use a larger size for single item if needed, but the drawer handles scaling logic internally usually - // or we pass size. The previous code passed 512x512 for single. BatteryItemBox(context, item, colors, size = 512, modifier = GlanceModifier.fillMaxSize()) } } @@ -154,28 +177,10 @@ class BatteriesWidget : GlanceAppWidget() { val error: Int, val warning: Int, val track: Int, - val surface: Int + val surface: Int, + val iconTint: Int ) - private fun resolveThemeColors(context: Context): ThemeColors { - val themedContext = android.view.ContextThemeWrapper(context, R.style.Theme_Essentials) - val primary = resolveColor(themedContext, android.R.attr.colorActivatedHighlight) - val error = resolveColor(themedContext, android.R.attr.colorError) - val surfaceVariant = resolveColor(themedContext, android.R.attr.colorPressedHighlight) - val surface = resolveColor(themedContext, android.R.attr.colorForeground) - val warning = android.graphics.Color.parseColor("#FFC107") - val track = ColorUtils.setAlphaComponent(surfaceVariant, 76) - - return ThemeColors(primary, error, warning, track, surface) - } - - private fun resolveColor(context: Context, @androidx.annotation.AttrRes attr: Int): Int { - val typedValue = android.util.TypedValue() - val theme = context.theme - theme.resolveAttribute(attr, typedValue, true) - return typedValue.data - } - @androidx.compose.runtime.Composable private fun BatteryItemBox( context: Context, @@ -192,7 +197,7 @@ class BatteriesWidget : GlanceAppWidget() { val icon = ContextCompat.getDrawable(context, item.iconRes) val bitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( - context, item.level, ringColor, colors.track, colors.primary, colors.surface, icon, size, size + context, item.level, ringColor, colors.track, colors.iconTint, colors.surface, icon, size, size ) Box(modifier = modifier, contentAlignment = Alignment.Center) { diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt index 823ef1bf..5e3f3a11 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt @@ -11,6 +11,31 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { override fun onReceive(context: Context, intent: Intent) { super.onReceive(context, intent) + + // Always update widget on configuration changes (including theme changes) + if (intent.action == Intent.ACTION_CONFIGURATION_CHANGED) { + val glanceAppWidgetManager = androidx.glance.appwidget.GlanceAppWidgetManager(context) + kotlinx.coroutines.MainScope().launch { + try { + // Add a small delay to allow system theme colors to propagate + kotlinx.coroutines.delay(500) + + val glanceIds = glanceAppWidgetManager.getGlanceIds(BatteriesWidget::class.java) + glanceIds.forEach { glanceId -> + // Update widget state with a timestamp to force re-render + androidx.glance.appwidget.state.updateAppWidgetState(context, glanceId) { prefs -> + val THEME_UPDATE_KEY = androidx.datastore.preferences.core.longPreferencesKey("theme_update_time") + prefs[THEME_UPDATE_KEY] = System.currentTimeMillis() + } + glanceAppWidget.update(context, glanceId) + } + } catch (e: Exception) { + android.util.Log.e("BatteriesWidget", "Error updating widget on config change", e) + } + } + return + } + if (intent.action == Intent.ACTION_POWER_CONNECTED || intent.action == Intent.ACTION_POWER_DISCONNECTED || intent.action == Intent.ACTION_BATTERY_LOW || @@ -20,7 +45,7 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { intent.action == android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED || intent.action == android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED || intent.action == android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE) { - + // Trigger update val glanceAppWidgetManager = androidx.glance.appwidget.GlanceAppWidgetManager(context) kotlinx.coroutines.MainScope().launch { From fd31f71a6507c93446f42f39262f43ee0cb58f5b Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 16:44:04 +0530 Subject: [PATCH 40/86] widget theme simplifications --- .../services/widgets/BatteriesWidget.kt | 59 ++++++++----------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index fc172d51..332f0be8 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -1,4 +1,3 @@ - package com.sameerasw.essentials.services.widgets import android.content.Context @@ -37,7 +36,7 @@ class BatteriesWidget : GlanceAppWidget() { val androidLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) val prefs = androidx.glance.currentState() - + // Keys val KEY_AIRSYNC_ENABLED = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_AIRSYNC_CONNECTION_ENABLED) val KEY_MAC_LEVEL = androidx.datastore.preferences.core.intPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_MAC_BATTERY_LEVEL) @@ -83,12 +82,12 @@ class BatteriesWidget : GlanceAppWidget() { try { val type = object : com.google.gson.reflect.TypeToken>() {}.type val devices: List = com.google.gson.Gson().fromJson(bluetoothJson, type) ?: emptyList() - + devices.forEach { device -> val iconRes = when { device.name.contains("watch", true) -> R.drawable.rounded_watch_24 - device.name.contains("bud", true) || - device.name.contains("pod", true) || + device.name.contains("bud", true) || + device.name.contains("pod", true) || device.name.contains("head", true) -> R.drawable.rounded_headphones_24 else -> R.drawable.rounded_bluetooth_24 } @@ -106,32 +105,19 @@ class BatteriesWidget : GlanceAppWidget() { } // 3. Render - - // Use Glance's dynamic colors directly - these update automatically with theme changes + // Get dynamic theme colors from GlanceTheme val basePrimary = GlanceTheme.colors.primary.getColor(context).toArgb() - val onPrimary = GlanceTheme.colors.onPrimary.getColor(context).toArgb() + val baseError = GlanceTheme.colors.error.getColor(context).toArgb() val onSurface = GlanceTheme.colors.onSurface.getColor(context).toArgb() val surfaceColor = GlanceTheme.colors.surface.getColor(context).toArgb() - val errorColor = GlanceTheme.colors.error.getColor(context).toArgb() - // Use the primary color for ring - it adapts to theme automatically - val ringColor = basePrimary - - // Use onPrimary for icon tint when ring is primary - // onPrimary is specifically designed to contrast with primary color - val iconTintColor = onPrimary - - val trackColor = ColorUtils.setAlphaComponent(onSurface, 30) - - val warningColor = android.graphics.Color.parseColor("#FFC107") - val colors = ThemeColors( - primary = ringColor, - error = errorColor, - warning = warningColor, - track = trackColor, + primary = basePrimary, + error = baseError, + warning = android.graphics.Color.parseColor("#FFC107"), + track = ColorUtils.setAlphaComponent(onSurface, 30), surface = surfaceColor, - iconTint = iconTintColor + iconTint = onSurface ) if (batteryItems.size > 1) { @@ -146,7 +132,7 @@ class BatteriesWidget : GlanceAppWidget() { ) { batteryItems.forEachIndexed { index, item -> BatteryItemBox(context, item, colors, modifier = GlanceModifier.defaultWeight().fillMaxHeight()) - + if (index < batteryItems.size - 1) { Spacer(modifier = GlanceModifier.width(8.dp)) } @@ -155,7 +141,7 @@ class BatteriesWidget : GlanceAppWidget() { } else { // Single item layout (Big) val item = batteryItems.firstOrNull() ?: BatteryItemData(androidLevel, R.drawable.rounded_mobile_24, "Android") - + Box( modifier = GlanceModifier .fillMaxSize() @@ -171,7 +157,7 @@ class BatteriesWidget : GlanceAppWidget() { } data class BatteryItemData(val level: Int, val iconRes: Int, val name: String) - + data class ThemeColors( val primary: Int, val error: Int, @@ -183,9 +169,9 @@ class BatteriesWidget : GlanceAppWidget() { @androidx.compose.runtime.Composable private fun BatteryItemBox( - context: Context, - item: BatteryItemData, - colors: ThemeColors, + context: Context, + item: BatteryItemData, + colors: ThemeColors, size: Int = 300, modifier: GlanceModifier = GlanceModifier ) { @@ -194,18 +180,19 @@ class BatteriesWidget : GlanceAppWidget() { item.level < 20 -> colors.warning else -> colors.primary } - + val icon = ContextCompat.getDrawable(context, item.iconRes) val bitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( context, item.level, ringColor, colors.track, colors.iconTint, colors.surface, icon, size, size ) - + Box(modifier = modifier, contentAlignment = Alignment.Center) { Image( - provider = ImageProvider(bitmap), - contentDescription = "${item.name}: ${item.level}%", + provider = ImageProvider(bitmap), + contentDescription = "${item.name}: ${item.level}%", modifier = GlanceModifier.fillMaxSize() ) } } -} \ No newline at end of file +} + From 2f3b3dbc26bb46bbe47fce67019f34a68bff1eab Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 16:46:31 +0530 Subject: [PATCH 41/86] New translations strings.xml (Japanese) --- app/src/main/res/values-ja/strings.xml | 64 +++++++++++++------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index de0ceaf6..1b356307 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -73,22 +73,22 @@ 通知を発信 アプリに通知の表示を許可する 権限を付与 - Caffeinate Active - Active - Screen is being kept awake - Ignore battery optimization - Recommended for reliable service on some devices - Abort with screen off - Timeout Presets - Select available durations for QS tile - 5m - 10m - 30m - 1h - - Starting in %1$ds… - %1$s remaining - Persistent notification for Caffeinate + カフェイン 動作中 + 動作中 + 画面を起動したままにしています + バッテリーの最適化を無視 + 一部のデバイスで信頼性の高いサービスが提供される場合に推奨されます + 画面をオフにして停止 + タイムアウト時間 + クイック設定タイルでオンにしたときの動作時間 + 5分 + 10分 + 30分 + 1時間 + 無限 + あと%1$dで開始します… + 残り%1$s + カフェインの永続的な通知 ダイナミックナイトモードを有効にする ナイトモードを無効にするアプリ @@ -166,10 +166,10 @@ アプリフリーズ ライト点滅 スリープしない - Essentials Keyboard - English (US) - Active - Inactive + Essentials キーボード + English (US) 英語 + 動作中 + 停止中 NFC オン オフ @@ -271,12 +271,12 @@ スリープしないタイル クイック設定タイルで充電中にスリープするかを切り替える - Trigger Automation - Schedule an action to trigger on an observation - State Automation - Schedule an action to execute based on the state of a condition in and out - New Automation - Edit Automation + トリガーオートメーション + トリガーされるアクションをスケジュールする + ステータスオートメーション + 条件の状態に基づいて実行するアクションをスケジュールする + 新規作成 + オートメーションの編集 リンクアクション リンクの処理を複数のアプリで行う システム通知をスヌーズ @@ -302,8 +302,8 @@ 特定の通信世代でモバイルデータを非表示にします 全てのアイコンをリセット ステータスバーアイコンの表示をデフォルトに戻す - Abort Caffeinate with screen off - Automatically turn off Caffeinate when manually locking the device + 画面をオフにしてカフェインを停止する + デバイスをロックしたあと、カフェインの動作を停止させる ライトのスタイル ストローク、グロー、スピナーなどに選択 角の半径 @@ -353,11 +353,11 @@ 音量ボタンの機能を再設定する機能を使うか切り替える リマップ触覚フィードバック 再設定されたボタンを押したときの感触フィードバック - Flashlight toggle + フラッシュライト フラッシュライトを音量ボタンで切り替える - Enable Dynamic Night Light - Master switch for dynamic night light - Enable app lock + ダイナミックナイトモードを有効にする + ダイナミックナイトモードを使うか切り替える + アプリロックを有効にする Master toggle for app locking Select locked apps Choose which apps require authentication From 02fd15fede500d6ab646b2e84c534c53ce714daf Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 17:37:36 +0530 Subject: [PATCH 42/86] Auto update colors with the widget --- .../services/widgets/BatteriesWidget.kt | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index 332f0be8..5a06a2e2 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -51,6 +51,10 @@ class BatteriesWidget : GlanceAppWidget() { val isShowBluetoothEnabled = prefs[KEY_SHOW_BLUETOOTH] ?: false val bluetoothJson = prefs[KEY_BLUETOOTH_BATTERY] + // Force recomposition when theme changes + val THEME_UPDATE_KEY = androidx.datastore.preferences.core.longPreferencesKey("theme_update_time") + val themeLastUpdated = prefs[THEME_UPDATE_KEY] + val showMac = isAirSyncEnabled && macLevel != -1 && isMacConnected val hasBluetooth = isShowBluetoothEnabled && !bluetoothJson.isNullOrEmpty() && bluetoothJson != "[]" @@ -105,14 +109,32 @@ class BatteriesWidget : GlanceAppWidget() { } // 3. Render - // Get dynamic theme colors from GlanceTheme - val basePrimary = GlanceTheme.colors.primary.getColor(context).toArgb() - val baseError = GlanceTheme.colors.error.getColor(context).toArgb() - val onSurface = GlanceTheme.colors.onSurface.getColor(context).toArgb() - val surfaceColor = GlanceTheme.colors.surface.getColor(context).toArgb() + val context = androidx.glance.LocalContext.current + val systemConfig = android.content.res.Resources.getSystem().configuration + + val forcedConfig = android.content.res.Configuration(context.resources.configuration) + forcedConfig.uiMode = systemConfig.uiMode + + val configContext = context.createConfigurationContext(forcedConfig) + + val basePrimary = GlanceTheme.colors.primary.getColor(configContext).toArgb() + val baseError = GlanceTheme.colors.error.getColor(configContext).toArgb() + val onSurface = GlanceTheme.colors.onSurface.getColor(configContext).toArgb() + val surfaceColor = GlanceTheme.colors.surface.getColor(configContext).toArgb() + + val isNightMode = (systemConfig.uiMode and + android.content.res.Configuration.UI_MODE_NIGHT_MASK) == + android.content.res.Configuration.UI_MODE_NIGHT_YES + + // Calculate primary color based on theme + val primaryCalculated = if (isNightMode) { + basePrimary + } else { + androidx.core.graphics.ColorUtils.blendARGB(basePrimary, android.graphics.Color.BLACK, 0.4f) + } val colors = ThemeColors( - primary = basePrimary, + primary = primaryCalculated, error = baseError, warning = android.graphics.Color.parseColor("#FFC107"), track = ColorUtils.setAlphaComponent(onSurface, 30), @@ -131,7 +153,7 @@ class BatteriesWidget : GlanceAppWidget() { verticalAlignment = Alignment.CenterVertically ) { batteryItems.forEachIndexed { index, item -> - BatteryItemBox(context, item, colors, modifier = GlanceModifier.defaultWeight().fillMaxHeight()) + BatteryItemBox(configContext, item, colors, modifier = GlanceModifier.defaultWeight().fillMaxHeight()) if (index < batteryItems.size - 1) { Spacer(modifier = GlanceModifier.width(8.dp)) @@ -149,7 +171,7 @@ class BatteriesWidget : GlanceAppWidget() { .padding(16.dp), contentAlignment = Alignment.Center ) { - BatteryItemBox(context, item, colors, size = 512, modifier = GlanceModifier.fillMaxSize()) + BatteryItemBox(configContext, item, colors, size = 512, modifier = GlanceModifier.fillMaxSize()) } } } From b224b44652e90d0ca9ad8ed2c7c4cb1dcff9b43d Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 18:01:17 +0530 Subject: [PATCH 43/86] minor color updates --- .../essentials/services/widgets/BatteriesWidget.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index 5a06a2e2..bdb077e7 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -126,15 +126,9 @@ class BatteriesWidget : GlanceAppWidget() { android.content.res.Configuration.UI_MODE_NIGHT_MASK) == android.content.res.Configuration.UI_MODE_NIGHT_YES - // Calculate primary color based on theme - val primaryCalculated = if (isNightMode) { - basePrimary - } else { - androidx.core.graphics.ColorUtils.blendARGB(basePrimary, android.graphics.Color.BLACK, 0.4f) - } val colors = ThemeColors( - primary = primaryCalculated, + primary = basePrimary, error = baseError, warning = android.graphics.Color.parseColor("#FFC107"), track = ColorUtils.setAlphaComponent(onSurface, 30), From 0638c0dc27a6ae8d0d86870f1d7fcef8bf4ec8a7 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 18:32:49 +0530 Subject: [PATCH 44/86] New translations strings.xml (Japanese) --- app/src/main/res/values-ja/strings.xml | 102 ++++++++++++------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 1b356307..5a90326f 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -358,54 +358,54 @@ ダイナミックナイトモードを有効にする ダイナミックナイトモードを使うか切り替える アプリロックを有効にする - Master toggle for app locking - Select locked apps - Choose which apps require authentication - Pick apps to freeze - Choose which apps can be frozen - Freeze all apps - Immediately freeze all picked apps + アプリロックをするか切り替える + ロックするアプリを選択 + 認証が必要なアプリを選択 + フリーズさせるアプリを選択 + フリーズできるアプリを選択 + すべてのアプリをフリーズ + 選択したアプリ全てを直ちにフリーズする Freeze when locked - Freeze selected apps when device locks - Freeze delay - Delay before freezing after locking + デバイスがロックされたときに選択したアプリをフリーズする + タイミング + 画面をロックしてから何分後にアプリをロックするか Shizuku - Required for advanced commands. Install Shizuku from the Play Store. - Install Shizuku + 高度なコマンドを実行するのに必要です。PlayストアからShizukuをインストールしてください。 + Shizukuをインストール Shizuku permission - Required to run power-saving commands while maps is navigating. - Root Access - Permissions required for system actions using Root privileges. - Notification Listener - Required to detect when Maps is navigating. - Required to detect new notifications - Required to detect and snooze notifications - Accessibility Service - Required for App Lock, Screen off widget and other features to detect interactions - Required to trigger notification lighting on new notifications - Required to intercept hardware button events - Needed to monitor foreground applications. - Write Secure Settings - Required for Statusbar icons and Screen Locked Security - Needed to toggle Night Light. Grant via ADB or root. - Modify System Settings - Required to toggle Adaptive Brightness and other system settings - Overlay Permission - Required to display the notification lighting overlay on the screen - Device Administrator - Required to hard-lock the device (disabling biometrics) on unauthorized access attempts - Grant Permission - Copy ADB - Check - Enable in Settings - How to grant - Battery Optimization - Ensure the service is not killed by the system to save power. + マップパワーセービングモードを実行するのに必要です。 + Rootアクセス + Root権限を使用したシステムアクションをするのに必要です。 + 通知アクセス + マップがナビ中であることを検知するために必要です。 + 新しい通知を検知するために必要 + 通知を検知してスヌーズするために必要 + アクセシビリティサービス + アプリロック、画面オフウィジェット、その他の機能でインタラクションを検知するために必要 + 新しい通知を検知して通知ライトを動作させるために必要 + ハードウェアボタンイベントをインターセプトするために必要 + フォグラウンドアプリを検知するために必要です。 + セキュア設定を書き込む + ステータスバーアイコンの編集とロック画面のセキュリティに必要 + ナイトモードの切り替えに必要です。ADBまたはRoot権限で許可してください。 + システム設定の変更 + 明るさの自動調整やその他のシステム設定を切り替えるのに必要 + 他のアプリの上に重ねて表示 + 画面に通知ライトオーバーレイを表示するために必要 + デバイス管理アプリ + 不正アクセスに対してデバイスをハードロック(生体認証の無効化)するのに必要 + 権限を付与 + コマンドをコピー + チェック + 設定で有効にする + 付与の方法 + バッテリーの最適化を無視 + バッテリー節約のためにシステムがアプリを強制終了しないようにしてください。 Essentials - Freeze - Frozen + フリーズ + フリーズ DIY Disabled apps Do It Yourself @@ -459,15 +459,15 @@ Select Trigger Select State Select Action - In Action - Out Action - Cancel - Save - Edit - Delete - Enable - Disable - Automation Service + 条件と合うとき + 条件と合わないとき + キャンセル + 保存 + 編集 + 削除 + 有効 + 無効 + オートメーションサービス Automations Active Monitoring system events for your automations From 42b112f76613f2c9c5f12c59b8399b12dc78ccbe Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 18:41:20 +0530 Subject: [PATCH 45/86] visual updates in ui of widget --- .../receivers/AirSyncBridgeReceiver.kt | 3 ++ .../services/widgets/BatteriesWidget.kt | 32 ++++++++++++--- .../essentials/utils/BatteryRingDrawer.kt | 40 +++++++++---------- .../rounded_battery_android_frame_bolt_24.xml | 5 +++ 4 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 app/src/main/res/drawable/rounded_battery_android_frame_bolt_24.xml diff --git a/app/src/main/java/com/sameerasw/essentials/services/receivers/AirSyncBridgeReceiver.kt b/app/src/main/java/com/sameerasw/essentials/services/receivers/AirSyncBridgeReceiver.kt index a5c39945..792c0171 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/receivers/AirSyncBridgeReceiver.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/receivers/AirSyncBridgeReceiver.kt @@ -43,6 +43,9 @@ class AirSyncBridgeReceiver : BroadcastReceiver() { prefs[KEY_AIRSYNC_ENABLED] = true prefs[KEY_MAC_LEVEL] = level prefs[KEY_MAC_CONNECTED] = isConnected + // Add charging state + val KEY_MAC_IS_CHARGING = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_MAC_BATTERY_IS_CHARGING) + prefs[KEY_MAC_IS_CHARGING] = isCharging } android.util.Log.d("AirSyncBridge", "Triggering update for glanceId: $glanceId") diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index bdb077e7..92953591 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -50,6 +50,10 @@ class BatteriesWidget : GlanceAppWidget() { val isMacConnected = prefs[KEY_MAC_CONNECTED] ?: false val isShowBluetoothEnabled = prefs[KEY_SHOW_BLUETOOTH] ?: false val bluetoothJson = prefs[KEY_BLUETOOTH_BATTERY] + + // Add key for Mac Charging + val KEY_MAC_IS_CHARGING = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_MAC_BATTERY_IS_CHARGING) + val macIsCharging = prefs[KEY_MAC_IS_CHARGING] ?: false // Force recomposition when theme changes val THEME_UPDATE_KEY = androidx.datastore.preferences.core.longPreferencesKey("theme_update_time") @@ -62,21 +66,32 @@ class BatteriesWidget : GlanceAppWidget() { val batteryItems = mutableListOf() // Android Item + val isAndroidCharging = (batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS) == BatteryManager.BATTERY_STATUS_CHARGING) + + val androidFinalStatusIcon = if (isAndroidCharging) R.drawable.rounded_battery_android_frame_bolt_24 + else if (androidLevel <= 15) R.drawable.rounded_battery_android_frame_alert_24 + else null + batteryItems.add( BatteryItemData( level = androidLevel, iconRes = R.drawable.rounded_mobile_24, - name = "Android" + name = "Android", + statusIconRes = androidFinalStatusIcon ) ) // Mac Item if (showMac) { + val macStatusIcon = if (macIsCharging) R.drawable.rounded_battery_android_frame_bolt_24 + else if (macLevel <= 15) R.drawable.rounded_battery_android_frame_alert_24 + else null batteryItems.add( BatteryItemData( level = macLevel, iconRes = R.drawable.rounded_laptop_mac_24, - name = "Mac" + name = "Mac", + statusIconRes = macStatusIcon ) ) } @@ -95,11 +110,16 @@ class BatteriesWidget : GlanceAppWidget() { device.name.contains("head", true) -> R.drawable.rounded_headphones_24 else -> R.drawable.rounded_bluetooth_24 } + + // Bluetooth doesn't report charging usually, so just Low Battery check + val statusIcon = if (device.level <= 15) R.drawable.rounded_battery_android_frame_alert_24 else null + batteryItems.add( BatteryItemData( level = device.level, iconRes = iconRes, - name = device.name + name = device.name, + statusIconRes = statusIcon ) ) } @@ -172,7 +192,7 @@ class BatteriesWidget : GlanceAppWidget() { } } - data class BatteryItemData(val level: Int, val iconRes: Int, val name: String) + data class BatteryItemData(val level: Int, val iconRes: Int, val name: String, val statusIconRes: Int? = null) data class ThemeColors( val primary: Int, @@ -198,8 +218,10 @@ class BatteriesWidget : GlanceAppWidget() { } val icon = ContextCompat.getDrawable(context, item.iconRes) + val statusIcon = item.statusIconRes?.let { ContextCompat.getDrawable(context, it) } + val bitmap = com.sameerasw.essentials.utils.BatteryRingDrawer.drawBatteryWidget( - context, item.level, ringColor, colors.track, colors.iconTint, colors.surface, icon, size, size + context, item.level, ringColor, colors.track, colors.iconTint, colors.surface, icon, statusIcon, size, size ) Box(modifier = modifier, contentAlignment = Alignment.Center) { diff --git a/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt b/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt index 191dabc9..76d55abb 100644 --- a/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt +++ b/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt @@ -22,6 +22,7 @@ object BatteryRingDrawer { @ColorInt iconTint: Int, @ColorInt backgroundColor: Int, deviceIcon: Drawable?, + statusIcon: Drawable?, // New parameter for charging/warning icon width: Int, height: Int ): Bitmap { @@ -29,7 +30,7 @@ object BatteryRingDrawer { val canvas = Canvas(bitmap) // Config - val strokeWidth = width * 0.11f // Slightly thicker than before? + val strokeWidth = width * 0.11f val trackStrokeWidth = strokeWidth * 0.5f val padding = strokeWidth + (width * 0.05f) @@ -46,7 +47,8 @@ object BatteryRingDrawer { strokeCap = Paint.Cap.ROUND } - val topGapDegrees = 40f + // Dynamic Gap: 60 degrees if status icon present, otherwise 0 (full circle) + val topGapDegrees = if (statusIcon != null) 60f else 10f val capAngleDegrees = ((strokeWidth / 2f) / radius) * (180f / PI.toFloat()) val trackCapAngleDegrees = ((trackStrokeWidth / 2f) / radius) * (180f / PI.toFloat()) @@ -111,27 +113,25 @@ object BatteryRingDrawer { } } - // --- Draw Small Battery Icon (Top) --- - val smallIconRadius = strokeWidth * 1.3f - val centerX = width / 2f - val topY = padding - val iconCenterY = rect.top - - val smallIconPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - style = Paint.Style.FILL - color = ringColor - } - // Bubble Background - canvas.drawCircle(centerX, iconCenterY, smallIconRadius, smallIconPaint) - - val smallIconDrawable = ContextCompat.getDrawable(context, R.drawable.rounded_battery_android_frame_3_24) - smallIconDrawable?.let { + // --- Draw Status Icon (Top) if present --- + if (statusIcon != null) { + val smallIconRadius = strokeWidth * 1.3f + val centerX = width / 2f + val iconCenterY = rect.top + + val smallIconPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.FILL + color = ringColor + } + // Bubble Background + canvas.drawCircle(centerX, iconCenterY, smallIconRadius, smallIconPaint) + val iconSize = (smallIconRadius * 1.5f).toInt() val iconLeft = (centerX - iconSize / 2).toInt() val iconTop = (iconCenterY - iconSize / 2).toInt() - it.setBounds(iconLeft, iconTop, iconLeft + iconSize, iconTop + iconSize) - it.setTint(backgroundColor) - it.draw(canvas) + statusIcon.setBounds(iconLeft, iconTop, iconLeft + iconSize, iconTop + iconSize) + statusIcon.setTint(backgroundColor) + statusIcon.draw(canvas) } // --- Draw Center Device Icon --- diff --git a/app/src/main/res/drawable/rounded_battery_android_frame_bolt_24.xml b/app/src/main/res/drawable/rounded_battery_android_frame_bolt_24.xml new file mode 100644 index 00000000..2d28b67b --- /dev/null +++ b/app/src/main/res/drawable/rounded_battery_android_frame_bolt_24.xml @@ -0,0 +1,5 @@ + + + + + From 7896633d10977982e51d8460c95e9f8672086dfb Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 19:07:31 +0530 Subject: [PATCH 46/86] Limit max devices in the widget --- .../data/repository/SettingsRepository.kt | 4 +++ .../services/widgets/BatteriesWidget.kt | 17 +++++---- .../widgets/BatteriesWidgetReceiver.kt | 5 +++ .../configs/BatteriesSettingsUI.kt | 36 +++++++++++++++++++ .../essentials/viewmodels/MainViewModel.kt | 14 ++++++++ .../main/res/drawable/rounded_flash_on_24.xml | 5 +++ app/src/main/res/values/strings.xml | 2 ++ 7 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 app/src/main/res/drawable/rounded_flash_on_24.xml diff --git a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt index 59da3ac2..62001f32 100644 --- a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt +++ b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt @@ -116,6 +116,7 @@ class SettingsRepository(private val context: Context) { const val KEY_BLUETOOTH_DEVICES_BATTERY = "bluetooth_devices_battery" const val KEY_SHOW_BLUETOOTH_DEVICES = "show_bluetooth_devices" + const val KEY_BATTERY_WIDGET_MAX_DEVICES = "battery_widget_max_devices" } // Observe changes @@ -407,4 +408,7 @@ class SettingsRepository(private val context: Context) { fun isBluetoothDevicesEnabled(): Boolean = getBoolean(KEY_SHOW_BLUETOOTH_DEVICES, false) fun setBluetoothDevicesEnabled(enabled: Boolean) = putBoolean(KEY_SHOW_BLUETOOTH_DEVICES, enabled) + + fun getBatteryWidgetMaxDevices(): Int = getInt(KEY_BATTERY_WIDGET_MAX_DEVICES, 8) + fun setBatteryWidgetMaxDevices(count: Int) = putInt(KEY_BATTERY_WIDGET_MAX_DEVICES, count) } diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index 92953591..e8cc708c 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -55,6 +55,9 @@ class BatteriesWidget : GlanceAppWidget() { val KEY_MAC_IS_CHARGING = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_MAC_BATTERY_IS_CHARGING) val macIsCharging = prefs[KEY_MAC_IS_CHARGING] ?: false + val KEY_MAX_DEVICES = androidx.datastore.preferences.core.intPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BATTERY_WIDGET_MAX_DEVICES) + val maxDevices = prefs[KEY_MAX_DEVICES] ?: 8 + // Force recomposition when theme changes val THEME_UPDATE_KEY = androidx.datastore.preferences.core.longPreferencesKey("theme_update_time") val themeLastUpdated = prefs[THEME_UPDATE_KEY] @@ -68,7 +71,7 @@ class BatteriesWidget : GlanceAppWidget() { // Android Item val isAndroidCharging = (batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS) == BatteryManager.BATTERY_STATUS_CHARGING) - val androidFinalStatusIcon = if (isAndroidCharging) R.drawable.rounded_battery_android_frame_bolt_24 + val androidFinalStatusIcon = if (isAndroidCharging) R.drawable.rounded_flash_on_24 else if (androidLevel <= 15) R.drawable.rounded_battery_android_frame_alert_24 else null @@ -83,7 +86,7 @@ class BatteriesWidget : GlanceAppWidget() { // Mac Item if (showMac) { - val macStatusIcon = if (macIsCharging) R.drawable.rounded_battery_android_frame_bolt_24 + val macStatusIcon = if (macIsCharging) R.drawable.rounded_flash_on_24 else if (macLevel <= 15) R.drawable.rounded_battery_android_frame_alert_24 else null batteryItems.add( @@ -128,6 +131,8 @@ class BatteriesWidget : GlanceAppWidget() { } } + val displayedItems = batteryItems.take(maxDevices) + // 3. Render val context = androidx.glance.LocalContext.current val systemConfig = android.content.res.Resources.getSystem().configuration @@ -156,7 +161,7 @@ class BatteriesWidget : GlanceAppWidget() { iconTint = onSurface ) - if (batteryItems.size > 1) { + if (displayedItems.size > 1) { // Multi-item layout Row( modifier = GlanceModifier @@ -166,17 +171,17 @@ class BatteriesWidget : GlanceAppWidget() { horizontalAlignment = Alignment.CenterHorizontally, verticalAlignment = Alignment.CenterVertically ) { - batteryItems.forEachIndexed { index, item -> + displayedItems.forEachIndexed { index, item -> BatteryItemBox(configContext, item, colors, modifier = GlanceModifier.defaultWeight().fillMaxHeight()) - if (index < batteryItems.size - 1) { + if (index < displayedItems.size - 1) { Spacer(modifier = GlanceModifier.width(8.dp)) } } } } else { // Single item layout (Big) - val item = batteryItems.firstOrNull() ?: BatteryItemData(androidLevel, R.drawable.rounded_mobile_24, "Android") + val item = displayedItems.firstOrNull() ?: BatteryItemData(androidLevel, R.drawable.rounded_mobile_24, "Android") Box( modifier = GlanceModifier diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt index 5e3f3a11..38e94692 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt @@ -60,7 +60,10 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { emptyList() } + repository.saveBluetoothDevicesBattery(bluetoothDevices) + + val maxDevices = repository.getBatteryWidgetMaxDevices() val devicesJson = com.google.gson.Gson().toJson(bluetoothDevices) @@ -69,9 +72,11 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { androidx.glance.appwidget.state.updateAppWidgetState(context, glanceId) { prefs -> val KEY_SHOW = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_SHOW_BLUETOOTH_DEVICES) val KEY_DATA = androidx.datastore.preferences.core.stringPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BLUETOOTH_DEVICES_BATTERY) + val KEY_MAX = androidx.datastore.preferences.core.intPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BATTERY_WIDGET_MAX_DEVICES) prefs[KEY_SHOW] = isEnabled prefs[KEY_DATA] = devicesJson + prefs[KEY_MAX] = maxDevices } glanceAppWidget.update(context, glanceId) } diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt index af8cfa8c..f75535a5 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt @@ -133,6 +133,42 @@ fun BatteriesSettingsUI( ) } ) + + + // Limit Max Devices + ListItem( + leadingContent = { + androidx.compose.material3.Icon( + painter = androidx.compose.ui.res.painterResource(R.drawable.rounded_devices_24), + contentDescription = null + ) + }, + headlineContent = { Text(stringResource(R.string.limit_max_devices)) }, + supportingContent = { + Column { + Text(stringResource(R.string.limit_max_devices_summary)) + val haptic = androidx.compose.ui.platform.LocalHapticFeedback.current + androidx.compose.material3.Slider( + value = viewModel.batteryWidgetMaxDevices.intValue.toFloat(), + onValueChange = { + val newInt = it.toInt() + if (newInt != viewModel.batteryWidgetMaxDevices.intValue) { + haptic.performHapticFeedback(androidx.compose.ui.hapticfeedback.HapticFeedbackType.TextHandleMove) + viewModel.setBatteryWidgetMaxDevices(newInt, context) + } + }, + valueRange = 1f..8f, + steps = 6 + ) + } + }, + trailingContent = { + Text( + text = viewModel.batteryWidgetMaxDevices.intValue.toString(), + style = androidx.compose.material3.MaterialTheme.typography.bodyLarge + ) + } + ) } } } diff --git a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt index e997cae0..4ec94006 100644 --- a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt +++ b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt @@ -153,6 +153,7 @@ class MainViewModel : ViewModel() { val isMacBatteryCharging = mutableStateOf(false) val macBatteryLastUpdated = mutableStateOf(0L) val isMacConnected = mutableStateOf(false) + val batteryWidgetMaxDevices = mutableIntStateOf(8) private var lastUpdateCheckTime: Long = 0 private lateinit var settingsRepository: SettingsRepository @@ -200,6 +201,7 @@ class MainViewModel : ViewModel() { SettingsRepository.KEY_MAC_BATTERY_IS_CHARGING -> isMacBatteryCharging.value = settingsRepository.getBoolean(key, false) SettingsRepository.KEY_MAC_BATTERY_LAST_UPDATED -> macBatteryLastUpdated.value = settingsRepository.getLong(key, 0L) SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED -> isMacConnected.value = settingsRepository.getBoolean(key, false) + SettingsRepository.KEY_BATTERY_WIDGET_MAX_DEVICES -> batteryWidgetMaxDevices.intValue = settingsRepository.getInt(key, 8) } } @@ -328,6 +330,7 @@ class MainViewModel : ViewModel() { isMacConnected.value = settingsRepository.getBoolean(SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED, false) isBluetoothDevicesEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_SHOW_BLUETOOTH_DEVICES, false) + batteryWidgetMaxDevices.intValue = settingsRepository.getBatteryWidgetMaxDevices() isScreenLockedSecurityEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_SCREEN_LOCKED_SECURITY_ENABLED) isDeviceAdminEnabled.value = isDeviceAdminActive(context) @@ -786,6 +789,17 @@ class MainViewModel : ViewModel() { context.sendBroadcast(intent) } + fun setBatteryWidgetMaxDevices(count: Int, context: Context) { + batteryWidgetMaxDevices.intValue = count + settingsRepository.setBatteryWidgetMaxDevices(count) + + // Trigger widget update + val intent = Intent(context, com.sameerasw.essentials.services.widgets.BatteriesWidgetReceiver::class.java).apply { + action = android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE + } + context.sendBroadcast(intent) + } + private fun isAccessibilityServiceEnabled(context: Context): Boolean { diff --git a/app/src/main/res/drawable/rounded_flash_on_24.xml b/app/src/main/res/drawable/rounded_flash_on_24.xml new file mode 100644 index 00000000..61ba59e5 --- /dev/null +++ b/app/src/main/res/drawable/rounded_flash_on_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 90874ffa..df712950 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -288,6 +288,8 @@ QS tile to toggle stay awake Show Bluetooth devices Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget Trigger Automation From 857fe4bf8a9c4faaf4a7809019e79affe5bf3a31 Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 19:33:15 +0530 Subject: [PATCH 47/86] improve battery ring --- .../services/widgets/BatteriesWidget.kt | 74 +++++++++++++++---- .../essentials/utils/BatteryRingDrawer.kt | 2 +- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index e8cc708c..86bb3903 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -18,6 +18,7 @@ import androidx.glance.layout.fillMaxSize import androidx.glance.layout.padding import androidx.glance.layout.width import androidx.glance.layout.height +import androidx.glance.layout.fillMaxWidth import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat @@ -27,10 +28,15 @@ import androidx.glance.ImageProvider import com.sameerasw.essentials.R class BatteriesWidget : GlanceAppWidget() { + override val sizeMode = androidx.glance.appwidget.SizeMode.Exact override suspend fun provideGlance(context: Context, id: GlanceId) { provideContent { GlanceTheme { + val size = androidx.glance.LocalSize.current + val width = size.width + val height = size.height + // 1. Fetch Data val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager val androidLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) @@ -162,20 +168,62 @@ class BatteriesWidget : GlanceAppWidget() { ) if (displayedItems.size > 1) { - // Multi-item layout - Row( - modifier = GlanceModifier - .fillMaxSize() - .background(GlanceTheme.colors.surface) - .padding(8.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalAlignment = Alignment.CenterVertically - ) { - displayedItems.forEachIndexed { index, item -> - BatteryItemBox(configContext, item, colors, modifier = GlanceModifier.defaultWeight().fillMaxHeight()) + val isGridCapable = width >= 200.dp && height >= 140.dp + + if (isGridCapable) { + // GRID / WRAPPING LAYOUT + val itemWidth = 72.dp + val columns = (width / itemWidth).toInt().coerceAtLeast(1) + val rows = displayedItems.chunked(columns) + + Column( + modifier = GlanceModifier + .fillMaxSize() + .background(GlanceTheme.colors.surface) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalAlignment = Alignment.CenterVertically + ) { + rows.forEachIndexed { rowIndex, rowItems -> + Row( + modifier = GlanceModifier.fillMaxWidth().defaultWeight(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalAlignment = Alignment.CenterVertically + ) { + rowItems.forEachIndexed { colIndex, item -> + BatteryItemBox(configContext, item, colors, modifier = GlanceModifier.defaultWeight().fillMaxHeight()) + if (colIndex < rowItems.size - 1) { + Spacer(modifier = GlanceModifier.width(8.dp)) + } + } + if (rowItems.size < columns) { + repeat(columns - rowItems.size) { + Spacer(modifier = GlanceModifier.defaultWeight().fillMaxHeight()) + if (it < (columns - rowItems.size - 1)) Spacer(modifier = GlanceModifier.width(8.dp)) + } + } + } + if (rowIndex < rows.size - 1) { + Spacer(modifier = GlanceModifier.height(8.dp)) + } + } + } + } else { + // STANDARD SINGLE ROW LAYOUT + Row( + modifier = GlanceModifier + .fillMaxSize() + .background(GlanceTheme.colors.surface) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalAlignment = Alignment.CenterVertically + ) { + displayedItems.forEachIndexed { index, item -> + BatteryItemBox(configContext, item, colors, modifier = GlanceModifier.defaultWeight().fillMaxHeight()) - if (index < displayedItems.size - 1) { - Spacer(modifier = GlanceModifier.width(8.dp)) + if (index < displayedItems.size - 1) { + Spacer(modifier = GlanceModifier.width(8.dp)) + } } } } diff --git a/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt b/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt index 76d55abb..7a45f0b3 100644 --- a/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt +++ b/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt @@ -48,7 +48,7 @@ object BatteryRingDrawer { } // Dynamic Gap: 60 degrees if status icon present, otherwise 0 (full circle) - val topGapDegrees = if (statusIcon != null) 60f else 10f + val topGapDegrees = if (statusIcon != null) 60f else 0f val capAngleDegrees = ((strokeWidth / 2f) / radius) * (180f / PI.toFloat()) val trackCapAngleDegrees = ((trackStrokeWidth / 2f) / radius) * (180f / PI.toFloat()) From bf7ef52ee58047fc45fe2e4747525ebe6049c371 Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 19:45:54 +0530 Subject: [PATCH 48/86] Widget background toggle --- .../data/repository/SettingsRepository.kt | 4 ++++ .../services/widgets/BatteriesWidget.kt | 16 +++++++++++++--- .../widgets/BatteriesWidgetReceiver.kt | 3 +++ .../composables/configs/BatteriesSettingsUI.kt | 18 ++++++++++++++++++ .../essentials/utils/BatteryRingDrawer.kt | 17 ++++++++++++++--- .../essentials/viewmodels/MainViewModel.kt | 14 ++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 7 files changed, 68 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt index 62001f32..24f161ab 100644 --- a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt +++ b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt @@ -117,6 +117,7 @@ class SettingsRepository(private val context: Context) { const val KEY_BLUETOOTH_DEVICES_BATTERY = "bluetooth_devices_battery" const val KEY_SHOW_BLUETOOTH_DEVICES = "show_bluetooth_devices" const val KEY_BATTERY_WIDGET_MAX_DEVICES = "battery_widget_max_devices" + const val KEY_BATTERY_WIDGET_BACKGROUND_ENABLED = "battery_widget_background_enabled" } // Observe changes @@ -411,4 +412,7 @@ class SettingsRepository(private val context: Context) { fun getBatteryWidgetMaxDevices(): Int = getInt(KEY_BATTERY_WIDGET_MAX_DEVICES, 8) fun setBatteryWidgetMaxDevices(count: Int) = putInt(KEY_BATTERY_WIDGET_MAX_DEVICES, count) + + fun isBatteryWidgetBackgroundEnabled(): Boolean = getBoolean(KEY_BATTERY_WIDGET_BACKGROUND_ENABLED, true) + fun setBatteryWidgetBackgroundEnabled(enabled: Boolean) = putBoolean(KEY_BATTERY_WIDGET_BACKGROUND_ENABLED, enabled) } diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt index 86bb3903..a222f374 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidget.kt @@ -63,6 +63,9 @@ class BatteriesWidget : GlanceAppWidget() { val KEY_MAX_DEVICES = androidx.datastore.preferences.core.intPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BATTERY_WIDGET_MAX_DEVICES) val maxDevices = prefs[KEY_MAX_DEVICES] ?: 8 + + val KEY_BACKGROUND_ENABLED = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BATTERY_WIDGET_BACKGROUND_ENABLED) + val isBackgroundEnabled = prefs[KEY_BACKGROUND_ENABLED] ?: true // Force recomposition when theme changes val THEME_UPDATE_KEY = androidx.datastore.preferences.core.longPreferencesKey("theme_update_time") @@ -167,6 +170,13 @@ class BatteriesWidget : GlanceAppWidget() { iconTint = onSurface ) + + val backgroundModifier = if (isBackgroundEnabled) { + GlanceModifier.background(GlanceTheme.colors.surface) + } else { + GlanceModifier.background(android.graphics.Color.TRANSPARENT) + } + if (displayedItems.size > 1) { val isGridCapable = width >= 200.dp && height >= 140.dp @@ -179,7 +189,7 @@ class BatteriesWidget : GlanceAppWidget() { Column( modifier = GlanceModifier .fillMaxSize() - .background(GlanceTheme.colors.surface) + .then(backgroundModifier) .padding(8.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalAlignment = Alignment.CenterVertically @@ -213,7 +223,7 @@ class BatteriesWidget : GlanceAppWidget() { Row( modifier = GlanceModifier .fillMaxSize() - .background(GlanceTheme.colors.surface) + .then(backgroundModifier) .padding(8.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalAlignment = Alignment.CenterVertically @@ -234,7 +244,7 @@ class BatteriesWidget : GlanceAppWidget() { Box( modifier = GlanceModifier .fillMaxSize() - .background(GlanceTheme.colors.surface) + .then(backgroundModifier) .padding(16.dp), contentAlignment = Alignment.Center ) { diff --git a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt index 38e94692..fa840c98 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/widgets/BatteriesWidgetReceiver.kt @@ -64,6 +64,7 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { repository.saveBluetoothDevicesBattery(bluetoothDevices) val maxDevices = repository.getBatteryWidgetMaxDevices() + val isBackgroundEnabled = repository.isBatteryWidgetBackgroundEnabled() val devicesJson = com.google.gson.Gson().toJson(bluetoothDevices) @@ -73,10 +74,12 @@ class BatteriesWidgetReceiver : GlanceAppWidgetReceiver() { val KEY_SHOW = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_SHOW_BLUETOOTH_DEVICES) val KEY_DATA = androidx.datastore.preferences.core.stringPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BLUETOOTH_DEVICES_BATTERY) val KEY_MAX = androidx.datastore.preferences.core.intPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BATTERY_WIDGET_MAX_DEVICES) + val KEY_BG = androidx.datastore.preferences.core.booleanPreferencesKey(com.sameerasw.essentials.data.repository.SettingsRepository.KEY_BATTERY_WIDGET_BACKGROUND_ENABLED) prefs[KEY_SHOW] = isEnabled prefs[KEY_DATA] = devicesJson prefs[KEY_MAX] = maxDevices + prefs[KEY_BG] = isBackgroundEnabled } glanceAppWidget.update(context, glanceId) } diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt index f75535a5..67800401 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt @@ -169,6 +169,24 @@ fun BatteriesSettingsUI( ) } ) + + // Widget Background Toggle + ListItem( + leadingContent = { + androidx.compose.material3.Icon( + painter = androidx.compose.ui.res.painterResource(R.drawable.rounded_circles_24), + contentDescription = null + ) + }, + headlineContent = { Text(stringResource(R.string.widget_background_title)) }, + supportingContent = { Text(stringResource(R.string.widget_background_summary)) }, + trailingContent = { + androidx.compose.material3.Switch( + checked = viewModel.isBatteryWidgetBackgroundEnabled.value, + onCheckedChange = { viewModel.setBatteryWidgetBackgroundEnabled(it, context) } + ) + } + ) } } } diff --git a/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt b/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt index 7a45f0b3..9a0591d2 100644 --- a/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt +++ b/app/src/main/java/com/sameerasw/essentials/utils/BatteryRingDrawer.kt @@ -29,10 +29,14 @@ object BatteryRingDrawer { val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) - // Config - val strokeWidth = width * 0.11f - val trackStrokeWidth = strokeWidth * 0.5f + val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.FILL + color = backgroundColor + } + val centerX = width / 2f + val centerY = height / 2f + val strokeWidth = width * 0.11f val padding = strokeWidth + (width * 0.05f) val rect = RectF( padding, @@ -41,6 +45,13 @@ object BatteryRingDrawer { height - padding ) val radius = rect.width() / 2f + + val bubbleRadius = radius + (strokeWidth / 2f) + + canvas.drawCircle(centerX, centerY, bubbleRadius, bgPaint) + + // Config + val trackStrokeWidth = strokeWidth * 0.5f val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE diff --git a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt index 4ec94006..b6a05e12 100644 --- a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt +++ b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt @@ -154,6 +154,7 @@ class MainViewModel : ViewModel() { val macBatteryLastUpdated = mutableStateOf(0L) val isMacConnected = mutableStateOf(false) val batteryWidgetMaxDevices = mutableIntStateOf(8) + val isBatteryWidgetBackgroundEnabled = mutableStateOf(true) private var lastUpdateCheckTime: Long = 0 private lateinit var settingsRepository: SettingsRepository @@ -329,8 +330,10 @@ class MainViewModel : ViewModel() { macBatteryLastUpdated.value = settingsRepository.getLong(SettingsRepository.KEY_MAC_BATTERY_LAST_UPDATED, 0L) isMacConnected.value = settingsRepository.getBoolean(SettingsRepository.KEY_AIRSYNC_MAC_CONNECTED, false) + isBluetoothDevicesEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_SHOW_BLUETOOTH_DEVICES, false) isBluetoothDevicesEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_SHOW_BLUETOOTH_DEVICES, false) batteryWidgetMaxDevices.intValue = settingsRepository.getBatteryWidgetMaxDevices() + isBatteryWidgetBackgroundEnabled.value = settingsRepository.isBatteryWidgetBackgroundEnabled() isScreenLockedSecurityEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_SCREEN_LOCKED_SECURITY_ENABLED) isDeviceAdminEnabled.value = isDeviceAdminActive(context) @@ -800,6 +803,17 @@ class MainViewModel : ViewModel() { context.sendBroadcast(intent) } + fun setBatteryWidgetBackgroundEnabled(enabled: Boolean, context: Context) { + isBatteryWidgetBackgroundEnabled.value = enabled + settingsRepository.setBatteryWidgetBackgroundEnabled(enabled) + + // Trigger widget update + val intent = Intent(context, com.sameerasw.essentials.services.widgets.BatteriesWidgetReceiver::class.java).apply { + action = android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE + } + context.sendBroadcast(intent) + } + private fun isAccessibilityServiceEnabled(context: Context): Boolean { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index df712950..a23d06cd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -290,6 +290,8 @@ Display battery level of connected Bluetooth devices Limit max devices Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation From d268851a6700ecb24e45a5b730c4dc656ff98d8a Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 19:55:03 +0530 Subject: [PATCH 49/86] Batteries haptics --- .../ui/composables/configs/BatteriesSettingsUI.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt index 67800401..2a882716 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt @@ -27,6 +27,7 @@ fun BatteriesSettingsUI( modifier: Modifier = Modifier ) { val context = LocalContext.current + val haptic = androidx.compose.ui.platform.LocalHapticFeedback.current Column( modifier = modifier.padding(16.dp), horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally @@ -53,7 +54,10 @@ fun BatteriesSettingsUI( trailingContent = { androidx.compose.material3.Switch( checked = viewModel.isAirSyncConnectionEnabled.value, - onCheckedChange = { viewModel.setAirSyncConnectionEnabled(it, context) } + onCheckedChange = { + haptic.performHapticFeedback(androidx.compose.ui.hapticfeedback.HapticFeedbackType.TextHandleMove) + viewModel.setAirSyncConnectionEnabled(it, context) + } ) } ) @@ -111,6 +115,7 @@ fun BatteriesSettingsUI( androidx.compose.material3.Switch( checked = isBluetoothEnabled, onCheckedChange = { enabled -> + haptic.performHapticFeedback(androidx.compose.ui.hapticfeedback.HapticFeedbackType.TextHandleMove) if (enabled) { if (isPermissionGranted) { viewModel.setBluetoothDevicesEnabled(true, context) @@ -147,7 +152,7 @@ fun BatteriesSettingsUI( supportingContent = { Column { Text(stringResource(R.string.limit_max_devices_summary)) - val haptic = androidx.compose.ui.platform.LocalHapticFeedback.current + // val haptic = androidx.compose.ui.platform.LocalHapticFeedback.current (Moved to top) androidx.compose.material3.Slider( value = viewModel.batteryWidgetMaxDevices.intValue.toFloat(), onValueChange = { @@ -183,7 +188,10 @@ fun BatteriesSettingsUI( trailingContent = { androidx.compose.material3.Switch( checked = viewModel.isBatteryWidgetBackgroundEnabled.value, - onCheckedChange = { viewModel.setBatteryWidgetBackgroundEnabled(it, context) } + onCheckedChange = { + haptic.performHapticFeedback(androidx.compose.ui.hapticfeedback.HapticFeedbackType.TextHandleMove) + viewModel.setBatteryWidgetBackgroundEnabled(it, context) + } ) } ) From f248583b6308fd895e24cb339b8ebd1533a4dff6 Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 20:18:14 +0530 Subject: [PATCH 50/86] cleanup --- .../essentials/ui/composables/configs/BatteriesSettingsUI.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt index 2a882716..27b69857 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/BatteriesSettingsUI.kt @@ -85,9 +85,6 @@ fun BatteriesSettingsUI( ) } - // Divider? Maybe not needed inside RoundedCardContainer if items are distinct, but useful for visual separation - // But usually ListItem handles it or specific design. Assuming standard list items stack fine. - // Bluetooth Devices val isBluetoothEnabled = viewModel.isBluetoothDevicesEnabled.value val isPermissionGranted = viewModel.isBluetoothPermissionGranted.value @@ -152,7 +149,6 @@ fun BatteriesSettingsUI( supportingContent = { Column { Text(stringResource(R.string.limit_max_devices_summary)) - // val haptic = androidx.compose.ui.platform.LocalHapticFeedback.current (Moved to top) androidx.compose.material3.Slider( value = viewModel.batteryWidgetMaxDevices.intValue.toFloat(), onValueChange = { From e6069dac98434afcb70a6dfb8f300a39d287d2f8 Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 20:27:00 +0530 Subject: [PATCH 51/86] Fix #112 not using the new float values instead of int for notification lighting --- .../sameerasw/essentials/services/NotificationListener.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/sameerasw/essentials/services/NotificationListener.kt b/app/src/main/java/com/sameerasw/essentials/services/NotificationListener.kt index 03df9ce8..0c1aab83 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/NotificationListener.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/NotificationListener.kt @@ -118,14 +118,14 @@ class NotificationListener : NotificationListenerService() { val appSelected = isAppSelectedForNotificationLighting(sbn.packageName) if (appSelected) { val cornerRadius = try { - prefs.getInt("edge_lighting_corner_radius", 20) + prefs.getFloat("edge_lighting_corner_radius", 20f) } catch (e: ClassCastException) { - prefs.getFloat("edge_lighting_corner_radius", 20f).toInt() + prefs.getInt("edge_lighting_corner_radius", 20).toFloat() } val strokeThickness = try { - prefs.getInt("edge_lighting_stroke_thickness", 8) + prefs.getFloat("edge_lighting_stroke_thickness", 8f) } catch (e: ClassCastException) { - prefs.getFloat("edge_lighting_stroke_thickness", 8f).toInt() + prefs.getInt("edge_lighting_stroke_thickness", 8).toFloat() } val colorModeName = prefs.getString("edge_lighting_color_mode", NotificationLightingColorMode.SYSTEM.name) val colorMode = NotificationLightingColorMode.valueOf(colorModeName ?: NotificationLightingColorMode.SYSTEM.name) From ac7cb5e689a6365f2b97d3e862e42ddfac0fd182 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:37 +0530 Subject: [PATCH 52/86] New translations strings.xml (Romanian) --- app/src/main/res/values-ro/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index bb812770..8d28e05a 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 5f139f5a77ffb77659ca1a2b915f5a097cca2e82 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:38 +0530 Subject: [PATCH 53/86] New translations strings.xml (French) --- app/src/main/res/values-fr/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 16ded80e..21fea74e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -270,6 +270,12 @@ Bloc \"Réglages rapides\" pour changer le mode de sonnerie Bloc \"rester allumé\" Bloc \"Réglages rapides\" pour activer/désactiver le maintien de l\'écran allumé + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Déclencher une automatisation Prévoir une action à déclencher lors d\'une observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 554db71cbc9212434ca8013d512242424d4b77ce Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:40 +0530 Subject: [PATCH 54/86] New translations strings.xml (Spanish) --- app/src/main/res/values-es/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 13f887b84292749aaf20327e8e7571296d6c8118 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:41 +0530 Subject: [PATCH 55/86] New translations strings.xml (Afrikaans) --- app/src/main/res/values-af/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-af/strings.xml b/app/src/main/res/values-af/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-af/strings.xml +++ b/app/src/main/res/values-af/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From a17c486e6e347166eee2df592514119de3f893d2 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:42 +0530 Subject: [PATCH 56/86] New translations strings.xml (Arabic) --- app/src/main/res/values-ar/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 4d0f0269f9403b8bf735ff2d083fd64b743aeb1d Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:43 +0530 Subject: [PATCH 57/86] New translations strings.xml (Catalan) --- app/src/main/res/values-ca/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From a7d61b5949c31c6356246e46afd99524a582eed7 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:44 +0530 Subject: [PATCH 58/86] New translations strings.xml (Czech) --- app/src/main/res/values-cs/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 80ecaf32825af1362148d980e5ee5615c4d744fa Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:45 +0530 Subject: [PATCH 59/86] New translations strings.xml (Danish) --- app/src/main/res/values-da/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 1e8c7bd9e19aff440daceaca223b0507b6f0f705 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:46 +0530 Subject: [PATCH 60/86] New translations strings.xml (German) --- app/src/main/res/values-de/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 15b185d8..50ec600e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -270,6 +270,12 @@ Kachel in den Schnelleinstellungen zum Umschalten des Tonmodus \'Wach bleiben\'-Kachel Kachel in den Schnelleinstellungen zum Umschalten des Wachbleibens + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Auslöser-Automatisierung Eine Aktion planen, die bei einer Beobachtung ausgelöst wird @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 6376f7ef91d8c2aca999b489003bbbcfbf382a10 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:48 +0530 Subject: [PATCH 61/86] New translations strings.xml (Greek) --- app/src/main/res/values-el/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From f877872895ed130d24b0fab1212505a177729377 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:49 +0530 Subject: [PATCH 62/86] New translations strings.xml (Finnish) --- app/src/main/res/values-fi/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From e2497f1769bb9479ffff2500cc1d694d0b963aed Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:50 +0530 Subject: [PATCH 63/86] New translations strings.xml (Hebrew) --- app/src/main/res/values-he/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From c60da608b26f8added6cfadb61452631534fc1c3 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:51 +0530 Subject: [PATCH 64/86] New translations strings.xml (Hungarian) --- app/src/main/res/values-hu/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From f12486e8d8727a93e524886a13a3ae6a85a7063d Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:52 +0530 Subject: [PATCH 65/86] New translations strings.xml (Italian) --- app/src/main/res/values-it/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index ff41b9fb..7b5279c5 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -271,6 +271,12 @@ Le app bloccate richiederanno l\'autenticazione all\'apertura. L\'app rimarrà s QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -832,4 +838,11 @@ Le app bloccate richiederanno l\'autenticazione all\'apertura. L\'app rimarrà s Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From c9999ea7bed81a5761b3411110bf7d8c936d7edb Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:53 +0530 Subject: [PATCH 66/86] New translations strings.xml (Japanese) --- app/src/main/res/values-ja/strings.xml | 229 +++++++++++++------------ 1 file changed, 121 insertions(+), 108 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 5a90326f..8f628ec9 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -270,6 +270,12 @@ クイック設定タイルでサイレントモードを切り替える スリープしないタイル クイック設定タイルで充電中にスリープするかを切り替える + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background トリガーオートメーション トリガーされるアクションをスケジュールする @@ -365,7 +371,7 @@ フリーズできるアプリを選択 すべてのアプリをフリーズ 選択したアプリ全てを直ちにフリーズする - Freeze when locked + 画面ロック時にフリーズ デバイスがロックされたときに選択したアプリをフリーズする タイミング 画面をロックしてから何分後にアプリをロックするか @@ -407,58 +413,58 @@ フリーズ フリーズ DIY - Disabled apps - Do It Yourself + アプリを無効化 + 自分で作る - Keyboard Setup - Enable in settings - Switch to Essentials - Keyboard is active and ready! - Enabled - Disabled - Adaptive Brightness - Toggle adaptive brightness - Maps Power Saving - Toggle maps power saving mode - Search for Tools, Mods and Tweaks - Search - Stop - Search + キーボードセットアップ + 設定で有効にする + Essentialsに切り替える + キーボードは準備済みです! + 有効 + 無効 + 明るさの自動調整 + 画面の明るさを自動調整するか切り替える + マップパワーセービング + マップパワーセービングモードを切り替える + ツール、Mod、微調整を検索 + 検索 + 停止 + 検索 - Back - Done - Preview - Help Guide - Update Available - Download + 戻る + 完了 + プレビュー + ヘルプガイド + アップデートがあります + ダウンロード - Do It Yourself - Something experimental is brewing here. Stay tuned for automations and advanced mods. - Coming Soon - Trigger - State - Action - In - Out - Automation - Screen Off - Screen On - Device Unlock - Charger Connected - Charger Disconnected - Charging - Screen On - Vibrate - Show Notification - Remove Notification - Turn On Flashlight - Turn Off Flashlight - Toggle Flashlight - Dim Wallpaper - This action requires Shizuku or Root to adjust system wallpaper dimming. - Select Trigger - Select State - Select Action + 自分で作る + 実験的な何かが進行中です。自動化や高度なMODについては、今後の発表をお楽しみに。 + Comingsoon + トリガー + ステータス + アクション + イン + アウト + オートメーション + 画面オフ + 画面オン + ロック解除 + 充電器を接続 + 充電器を切断 + 充電中 + 画面点灯中 + バイブレーション + 通知を表示 + 通知を削除 + フラッシュライトを点灯 + フラッシュライトを消灯 + フラッシュライトを切り替える + 暗い壁紙 + このアクションでは、壁紙を暗くするために、ShizukuまたはRootが必要です。 + トリガーを選択 + ステータスを選択 + アクションを選択 条件と合うとき 条件と合わないとき キャンセル @@ -533,84 +539,84 @@ alert - light - torch + ライト + トーチ - light - torch - pulse - notification + ライト + トーチ + 点滅 + 通知 - tile - qs - awake + タイル + クイック設定 + 起動 - awake - developer - power - charge + 起動 + 開発者 + 電源 + 充電 - glow - notification - led + グロー + 通知 + LED - round - shape - edge + + シャープ + エッジ - secure - privacy - biometric - face - fingerprint + セキュア + プライバシー + 生体認証 + + 指紋 - sound - accessibility - hear + + アクセシビリティ + 聞く - stay - on - timeout + 待つ + オン + タイムアウト - touch - wake - display + タッチ + 起動 + 画面 - usb - file - transfer - mtp + USB + ファイル + ファイル転送 + MTP - timer - wait - timeout + タイマー + 待機 + タイムアウト - Always dark theme - Pitch black theme - Clipboard History + 常にダークテーマ + ブラックテーマにする + クリップボード履歴 - list - picker - selection + リスト + ピッカー + 選択 - animation - visual - look + アニメーション + ビジュアル + ロック - quiet + 静かな ignore filter @@ -691,16 +697,16 @@ Subtle Double Click - Tick + ティック - Turn Off - Flashlight Brightness + オフにする + ライトの明るさ - %1$s Settings - Confirm identity to open settings - Authentication Required - Confirm your identity - Unlock phone to change network settings + %1$s設定 + 設定を開くには認証してください + 認証リクエスト + 本人確認 + ネットワーク設定を変更するには、ロックを解除してください Developed by %1$s\nwith ❤\uFE0F from \uD83C\uDDF1\uD83C\uDDF0 Website @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 5e84b70738ca7f332cb98a1ae8116cd12f334fab Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:55 +0530 Subject: [PATCH 67/86] New translations strings.xml (Korean) --- app/src/main/res/values-ko/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From d5a5e7a62f4b92fec39a0b41cff970b23123f188 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:56 +0530 Subject: [PATCH 68/86] New translations strings.xml (Dutch) --- app/src/main/res/values-nl/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 9e8d2db7f3550f8822e09f01b34d08e5db023c2e Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:57 +0530 Subject: [PATCH 69/86] New translations strings.xml (Norwegian) --- app/src/main/res/values-no/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 6ec8c3acc165a00dcb8e1d1d13bae5c0a263f965 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:58 +0530 Subject: [PATCH 70/86] New translations strings.xml (Polish) --- app/src/main/res/values-pl/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From a2c5d2249d969dca0c9ab0040d2fe79f92a82ef2 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:40:59 +0530 Subject: [PATCH 71/86] New translations strings.xml (Portuguese) --- app/src/main/res/values-pt/strings.xml | 31 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 468fc383..35bc7189 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -27,7 +27,7 @@ Another note, the biometric authentication prompt only lets you use STRONG secure class methods. Face unlock security methods in WEAK class in devices such as Pixel 7 will only be able to utilize the available other STRONG auth methods such as fingerprint or pin. Enable Button Remap - Use Shizuku + Use Shizuku or Root or Root Works with screen off (Recommended) Shizuku is not running Detected %1$s @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -373,7 +379,7 @@ Shizuku Required for advanced commands. Install Shizuku from the Play Store. Install Shizuku - Shizuku permission + Grant Permission Required to run power-saving commands while maps is navigating. Root Access Permissions required for system actions using Root privileges. @@ -744,7 +750,7 @@ Notification lighting does not work It depends on the OEM. Some like OneUI does not seem to allow overlays above the AOD preventing the lighting effects being shown. In this case, try the ambient display as a workaround. Button remap does not work while display is off - Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. + Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku or Root\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. Flashlight brightness does not work Only a limited number of devices got hardware and software support adjusting the flashlight intensity. \n\n\'The minimum version of Android is 13 (SDK33).\nFlashlight brightness control only supports HAL version 3.8 and higher, so among the supported devices, the latest ones (For example, Pixel 6/7, Samsung S23, etc.)\'\npolodarb/Flashlight-Tiramisu What the hell is this app? @@ -763,14 +769,14 @@ Essentials Bug Report Send via - Location reached - Get notified when you arrive at a specific destination. + Are we there yet? + Destination nearby alerts Destination Set Destination Tracking: %1$.4f, %2$.4f No destination set - Open your map app, pick a location, and share it to Essentials. - Radius: %d m + Open Google Maps, pick a location, and share it to Essentials. + Alert Radius: %d m Distance to trigger the alarm Enable notification Location @@ -795,8 +801,8 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel Alarm active - %1$s remaining (%2$d%%) + Travel alarm active + %1$s remaining Travel Progress Shows real-time distance to destination Destination Nearby @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 78a7c4c09f0dc77250e8864e227a5883e299c2aa Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:01 +0530 Subject: [PATCH 72/86] New translations strings.xml (Russian) --- app/src/main/res/values-ru/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 77e41cd590991bcf0b5e6bbfee694ffb164c8e16 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:02 +0530 Subject: [PATCH 73/86] New translations strings.xml (Serbian (Cyrillic)) --- app/src/main/res/values-sr/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 08c1553511d054a0d41b7a8d26846e59bd9b18e9 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:03 +0530 Subject: [PATCH 74/86] New translations strings.xml (Swedish) --- app/src/main/res/values-sv/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 176942e6286526694e47448d577708186281f199 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:05 +0530 Subject: [PATCH 75/86] New translations strings.xml (Turkish) --- app/src/main/res/values-tr/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 87735300224ec8e7af4d98f5934caf565dc4f209 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:06 +0530 Subject: [PATCH 76/86] New translations strings.xml (Ukrainian) --- app/src/main/res/values-uk/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 4ddb67f1563f275888a8469875d82917b84fc2c8 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:07 +0530 Subject: [PATCH 77/86] New translations strings.xml (Chinese Simplified) --- app/src/main/res/values-zh/strings.xml | 31 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 468fc383..35bc7189 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -27,7 +27,7 @@ Another note, the biometric authentication prompt only lets you use STRONG secure class methods. Face unlock security methods in WEAK class in devices such as Pixel 7 will only be able to utilize the available other STRONG auth methods such as fingerprint or pin. Enable Button Remap - Use Shizuku + Use Shizuku or Root or Root Works with screen off (Recommended) Shizuku is not running Detected %1$s @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -373,7 +379,7 @@ Shizuku Required for advanced commands. Install Shizuku from the Play Store. Install Shizuku - Shizuku permission + Grant Permission Required to run power-saving commands while maps is navigating. Root Access Permissions required for system actions using Root privileges. @@ -744,7 +750,7 @@ Notification lighting does not work It depends on the OEM. Some like OneUI does not seem to allow overlays above the AOD preventing the lighting effects being shown. In this case, try the ambient display as a workaround. Button remap does not work while display is off - Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. + Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku or Root\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. Flashlight brightness does not work Only a limited number of devices got hardware and software support adjusting the flashlight intensity. \n\n\'The minimum version of Android is 13 (SDK33).\nFlashlight brightness control only supports HAL version 3.8 and higher, so among the supported devices, the latest ones (For example, Pixel 6/7, Samsung S23, etc.)\'\npolodarb/Flashlight-Tiramisu What the hell is this app? @@ -763,14 +769,14 @@ Essentials Bug Report Send via - Location reached - Get notified when you arrive at a specific destination. + Are we there yet? + Destination nearby alerts Destination Set Destination Tracking: %1$.4f, %2$.4f No destination set - Open your map app, pick a location, and share it to Essentials. - Radius: %d m + Open Google Maps, pick a location, and share it to Essentials. + Alert Radius: %d m Distance to trigger the alarm Enable notification Location @@ -795,8 +801,8 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel Alarm active - %1$s remaining (%2$d%%) + Travel alarm active + %1$s remaining Travel Progress Shows real-time distance to destination Destination Nearby @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From e6938a85fcb9c0045c584a5aa20aad98d958abe2 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:08 +0530 Subject: [PATCH 78/86] New translations strings.xml (Chinese Traditional) --- app/src/main/res/values-zh/strings.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 35bc7189..2828ec5d 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -27,7 +27,7 @@ Another note, the biometric authentication prompt only lets you use STRONG secure class methods. Face unlock security methods in WEAK class in devices such as Pixel 7 will only be able to utilize the available other STRONG auth methods such as fingerprint or pin. Enable Button Remap - Use Shizuku or Root or Root + Use Shizuku Works with screen off (Recommended) Shizuku is not running Detected %1$s @@ -379,7 +379,7 @@ Shizuku Required for advanced commands. Install Shizuku from the Play Store. Install Shizuku - Grant Permission + Shizuku permission Required to run power-saving commands while maps is navigating. Root Access Permissions required for system actions using Root privileges. @@ -750,7 +750,7 @@ Notification lighting does not work It depends on the OEM. Some like OneUI does not seem to allow overlays above the AOD preventing the lighting effects being shown. In this case, try the ambient display as a workaround. Button remap does not work while display is off - Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku or Root\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. + Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. Flashlight brightness does not work Only a limited number of devices got hardware and software support adjusting the flashlight intensity. \n\n\'The minimum version of Android is 13 (SDK33).\nFlashlight brightness control only supports HAL version 3.8 and higher, so among the supported devices, the latest ones (For example, Pixel 6/7, Samsung S23, etc.)\'\npolodarb/Flashlight-Tiramisu What the hell is this app? @@ -769,14 +769,14 @@ Essentials Bug Report Send via - Are we there yet? - Destination nearby alerts + Location reached + Get notified when you arrive at a specific destination. Destination Set Destination Tracking: %1$.4f, %2$.4f No destination set - Open Google Maps, pick a location, and share it to Essentials. - Alert Radius: %d m + Open your map app, pick a location, and share it to Essentials. + Radius: %d m Distance to trigger the alarm Enable notification Location @@ -801,8 +801,8 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel alarm active - %1$s remaining + Travel Alarm active + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From e55108818fd03de4497332dce32d630058304dc7 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:09 +0530 Subject: [PATCH 79/86] New translations strings.xml (English) --- app/src/main/res/values-en/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 7f5c5fb6017ed69df9a774729ee4f390b1881236 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:11 +0530 Subject: [PATCH 80/86] New translations strings.xml (Vietnamese) --- app/src/main/res/values-vi/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From f47e98e1b8e21c56543341c49a33f963a8dabff7 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:12 +0530 Subject: [PATCH 81/86] New translations strings.xml (Portuguese, Brazilian) --- app/src/main/res/values-pt/strings.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 35bc7189..2828ec5d 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -27,7 +27,7 @@ Another note, the biometric authentication prompt only lets you use STRONG secure class methods. Face unlock security methods in WEAK class in devices such as Pixel 7 will only be able to utilize the available other STRONG auth methods such as fingerprint or pin. Enable Button Remap - Use Shizuku or Root or Root + Use Shizuku Works with screen off (Recommended) Shizuku is not running Detected %1$s @@ -379,7 +379,7 @@ Shizuku Required for advanced commands. Install Shizuku from the Play Store. Install Shizuku - Grant Permission + Shizuku permission Required to run power-saving commands while maps is navigating. Root Access Permissions required for system actions using Root privileges. @@ -750,7 +750,7 @@ Notification lighting does not work It depends on the OEM. Some like OneUI does not seem to allow overlays above the AOD preventing the lighting effects being shown. In this case, try the ambient display as a workaround. Button remap does not work while display is off - Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku or Root\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. + Some OEMs limit the accessibility service reporting once the display is actually off but they may still work while the AOD is on. \nIn this case, you may able to use button remaps with AOD on but not with off. \n\nAs a workaround, you will need to use Shizuku permissions and turn on the \'Use Shizuku\' toggle in button remap settings which identifies and listen to hardware input events.\nThis is not guaranteed to work on all devices and needs testing.\n\nAnd even if it\'s on, Shizuku method only will be used when it\'s needed. Otherwise it will always fallback to Accessibility which also handles the blocking of the actual input during long press. Flashlight brightness does not work Only a limited number of devices got hardware and software support adjusting the flashlight intensity. \n\n\'The minimum version of Android is 13 (SDK33).\nFlashlight brightness control only supports HAL version 3.8 and higher, so among the supported devices, the latest ones (For example, Pixel 6/7, Samsung S23, etc.)\'\npolodarb/Flashlight-Tiramisu What the hell is this app? @@ -769,14 +769,14 @@ Essentials Bug Report Send via - Are we there yet? - Destination nearby alerts + Location reached + Get notified when you arrive at a specific destination. Destination Set Destination Tracking: %1$.4f, %2$.4f No destination set - Open Google Maps, pick a location, and share it to Essentials. - Alert Radius: %d m + Open your map app, pick a location, and share it to Essentials. + Radius: %d m Distance to trigger the alarm Enable notification Location @@ -801,8 +801,8 @@ Required to wake your device upon arrival. Tap to grant. %1$d m %1$.1f km - Travel alarm active - %1$s remaining + Travel Alarm active + %1$s remaining (%2$d%%) Travel Progress Shows real-time distance to destination Destination Nearby From 1fffe95a71a99186dd5e8221590429fb8beb9017 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:13 +0530 Subject: [PATCH 82/86] New translations strings.xml (Sinhala) --- app/src/main/res/values-si/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 4c75de2d77090d611221c5f8e49d88dbe9245d4d Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 20:41:15 +0530 Subject: [PATCH 83/86] New translations strings.xml (Acholi) --- app/src/main/res/values-ach/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-ach/strings.xml b/app/src/main/res/values-ach/strings.xml index 468fc383..2828ec5d 100644 --- a/app/src/main/res/values-ach/strings.xml +++ b/app/src/main/res/values-ach/strings.xml @@ -270,6 +270,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation Schedule an action to trigger on an observation @@ -831,4 +837,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync From 20df4240ba3b5e0a22b433be3c93aab60fa5f358 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 22:13:16 +0530 Subject: [PATCH 84/86] Update source file strings.xml --- app/src/main/res/values/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f2d59759..a23d06cd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -286,6 +286,12 @@ QS tile to toggle sound mode Stay awake tile QS tile to toggle stay awake + Show Bluetooth devices + Display battery level of connected Bluetooth devices + Limit max devices + Adjust max devices visible in widget + Widget background + Show widget background Trigger Automation @@ -893,4 +899,11 @@ Round Flat Inverse + Batteries + Monitor your device battery levels + Battery Status + Connect to AirSync + Display battery from your connected mac device in AirSync + Download AirSync App + Required for Mac battery sync \ No newline at end of file From 0dd2bb9f7a2bcb12fc6c2a6d25a9d994e942ccf4 Mon Sep 17 00:00:00 2001 From: Sameera Wijerathna Date: Fri, 16 Jan 2026 22:13:20 +0530 Subject: [PATCH 85/86] New translations strings.xml (Japanese) --- app/src/main/res/values-ja/strings.xml | 52 +++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 8f628ec9..3fc26021 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -708,42 +708,42 @@ 本人確認 ネットワーク設定を変更するには、ロックを解除してください - Developed by %1$s\nwith ❤\uFE0F from \uD83C\uDDF1\uD83C\uDDF0 - Website - Contact + 制作者 %1$s\n with ❤\uFE0F from \uD83C\uDDF1\uD83C\uDDF0 + ウェブサイト + お問い合わせ Telegram - Support - Other Apps + サポート + その他のアプリ AirSync ZenZero Canvas Tasks Zero - Developer Avatar + 開発者のアバター - Help & Guides - Need more support? Reach out, - Collapse - Expand - Support Group - Email - Send email - No email app available + ヘルプ&ガイド + さらにサポートが必要ですか? + 崩壊 + 拡大 + サポートグループ + メール + メールを送る + メールアプリがありません Step %1$d Image - Accessibility, Notification and Overlay permissions - You may get this access denied message if you try to grant sensitive permissions such as accessibility, notification listener or overlay permissions. To grant it, check the steps below. - 1. Go to app info page of Essentials. - 2. Open the 3-dot menu and select \'Allow restricted settings\'. You may have to authenticate with biometrics. Once done, Try to grant the permission again. + アクセシビリティ、通知、他のアプリの上に重ねて表示権限 + アクセシビリティ、通知の読み取り、オーバーレイなどの機密性の高い権限を付与しようとすると、このアクセス拒否メッセージが表示されることがあります。付与するには以下の手順を確認してください。 + 1. Essentialsのアプリ情報に移動する。 + 2. 3点メニューを開き、「制限付き設定を許可」を選択します。生体認証が必要になる場合があります。完了したら、再度権限を付与してください。 Shizuku - Shizuku is a powerful tool that allows apps to use system APIs directly with ADB or root permissions. It is required for features like Maps min mode, App Freezer. And willa ssist granting some permissions such as WRITE_SECURE_SETTINGS. \n\nBut the Play Store version of Shizuku might be outdated and will probably be unusable on recent Android versions so in that case, please get the latest version from the github or an up-to-date fork of it. - Maps power saving mode - This feature automatically triggers Google Maps power saving mode which is currently exclusive to the Pixel 10 series. A community member discovered that it is still usable on any Android device by launching the maps minMode activity with root privileges. \n\nAnd then, I had it automated with Tasker to automatically trigger when the screen turns off during a navigation session and then was able to achieve the same with just runtime Shizuku permissions. \n\nIt is intended to be shown over the AOD of Pixel 10 series so because of that, you may see an occasional message popping up on the display that it does not support landscape mode. That is not avoidable by the app and you can ignore. - Silent sound mode - You may have noticed that the silent mode also triggers DND. \n\nThis is due to how the Android implemented it as even if we use the same API to switch to vibrate mode, it for some reason turns on DND along with the silent mode and this is not avoidable at this moment. :( - What is freeze? - Pause and stay away from app distractions while saving a little bit of power preventing apps running in the background. Suitable for rarely used apps. \n\nNot recommended for any communication services as they will not notify you in an emergency unless you unfreeze them. \n\nHighly advised to not freeze system apps as they can lead to system instability. Proceed with caution, You were warned. \n\nInspired by Hail <3 - Are app lock and screen locked security actually secure? + Shizukuは、アプリがADBまたはRoot権限でシステムAPIを直接使用できるようにする強力なツールです。マップパワーセービングモード、アプリフリーズなどの機能に必要です。また、WRITE_SECURE_SETTINGSなどの一部の権限の付与を支援します。\n\nただし、Playストア版のShizukuは古く、最近のAndroidバージョンでは使用できない可能性があります。その場合は、GitHubまたは最新バージョンのフォークを入手してください。 + マップパワーセービングモード + この機能は、現在Pixel 10シリーズ限定のGoogleマップ省電力モードを自動的に起動します。コミュニティメンバーが、Root権限でマップの minMode アクティビティを起動することで、どのAndroidデバイスでも使用できることを発見しました。\n\nその後、Taskerを使って自動化し、ナビゲーション中に画面がオフになったときに自動的に起動できるように設定し、ランタイムのShizuku権限だけで同じことを実現できました。\n\nPixel 10シリーズの常時表示ディスプレイ上に表示されていることを想定しているため、横向きモードをサポートしていないというメッセージがディスプレイに表示されている場合があります。これはアプリでは回避できないため、無視できます。 + サイレントモード + サイレントモードでもDNDが起動することにお気づきかもしれません。\n\nこれはAndroidの実験方法によるもので、同じAPIを使用してバイブレーションモードに切り替えても、何らかの理由でサイレントモードと同時にDNDがオンになり、現時点では回避できません。:( + フリーズとは? + 一時停止してアプリを邪魔することなく、バックグラウンドでアプリが動作しないようにすることで、電力を少し節約できます。あまり使用しないアプリに適しています。\n\nSNSなどの通信サービスは、フリーズを解除しない限り、緊急時に通知されないため、推奨されません。\n\nシステムアプリをフリーズするとシステムが不安定になる可能性があるため、フリーズしないことを強くおすすめします。注意して操作してください。警告しましたからね!\n\nInspired by Hail <3 + アプリロックとロック画面セキュリティは本当に安全ですか? Absolutely not. \n\nAny 3rd party application can not 100% interfere with regular device interactions and even the app lock is only an overlay above selected apps to prevent interacting with them. There are workarounds and it is not foolproof. \n\nSame goes with the screen locked security feature which detects someone trying to interact with the network tiles which for some reason are still accessible for anyone on Pixels. So if they try hard enough they might still be able to change them and especially if you have a flight mode QS tile added, this app can not prevent interactions with it. \n\nThese features are made just as experiments for light usage and would never recommend as strong security and privacy solutions. \n\nSecure alternatives:\n - App lock: Private Space and Secure folder on Pixels and Samsung\n - Preventing mobile networks access: Make sure your theft protection and offline/ power off find my device settings are on. You may look into Graphene OS as well. Statusbar icons You may notice that even after resetting the statusbar icons, Some icons such as device rotation, wired headphone icons may stay visible. This is due to how the statubar blacklist is implemented in Android and how your OEM may have customized them. \nYou may need further adjustments. \n\nAlso not all icon visibility options may work as they depend on the OEM implementations and availability. From 2c65f74ca29f7c15321781b199c13ba5da7a1fef Mon Sep 17 00:00:00 2001 From: sameerasw Date: Fri, 16 Jan 2026 22:51:09 +0530 Subject: [PATCH 86/86] version upgrade --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 06c6fee5..0191243f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,8 +21,8 @@ android { applicationId = "com.sameerasw.essentials" minSdk = 26 targetSdk = 36 - versionCode = 21 - versionName = "10.0" + versionCode = 22 + versionName = "10.1" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" }