Skip to content

Commit 708aecf

Browse files
authored
Merge pull request #101 from xLexip/develop
v1.1.0
2 parents f859d3c + 098ca7b commit 708aecf

File tree

15 files changed

+173
-42
lines changed

15 files changed

+173
-42
lines changed

README.md

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# Adaptive Theme: Auto Dark Mode by Ambient Light
44

5-
Adaptive Theme automatically switches between Light and **Dark mode**
5+
Adaptive Theme automatically switches between light and **dark mode**
66
using the **ambient light sensor** — not a fixed schedule.
77

88
It adapts to real lighting conditions to optimize **readability**, **eye comfort**, and **battery
@@ -19,16 +19,16 @@ life**.
1919
## 🚀 Quick Start (2 minutes)
2020

2121
1. **Install** Adaptive Theme.
22-
2. **Grant the permission** with a [web-tool](https://lexip.dev/setup), Shizuku, or other methods
22+
2. **Grant the permission** with the [web-tool](https://lexip.dev/setup), Shizuku, or other methods
2323
below.
2424
3. **Pick your lux threshold** and you’re done. ✅
2525

2626
## 📋 Table of Contents
2727

2828
- [✨ Features & Highlights](#-features--highlights)
2929
- [🛠️ One-Time Setup](#%EF%B8%8F-one-time-setup)
30-
- [⚙️ How it Works](#%EF%B8%8F-how-it-works)
3130
- [✅ Safety](#-safety)
31+
- [⚙️ How it Works](#%EF%B8%8F-how-it-works)
3232
- [❓ FAQ](#-faq)
3333
- [❤️ Support the Project](#%EF%B8%8F-support-the-project)
3434
- [🏗️ Architecture & Tech Stack](#%EF%B8%8F-architecture--tech-stack)
@@ -37,15 +37,17 @@ life**.
3737

3838
* 🌤️ **Smart Detection:** Uses your devices physical light sensor to switch the system
3939
theme.
40-
* ⚙️ **Custom brightness threshold:** Choose exactly when Light ↔ Dark should flip.
40+
* ⚙️ **Custom brightness threshold:** Choose exactly when the theme should flip or use a preset (
41+
indoor, outdoor, sunlight, etc.).
4142
* 🔋 **Battery Friendly:** The app is passive. Its event-driven architecture only checks the sensor
4243
when you turn on the screen — zero battery drain in the background.
43-
* 🗝️ **No Root Required:** Root access is not required (but is supported as an alternative setup
44+
* 🗝️ **No Root Required:** Root access is not required (but supported as an alternative setup
4445
method).
4546
* 🐱 **Shizuku Support:** One of multiple setup options is
4647
using [Shizuku](https://github.com/RikkaApps/Shizuku).
4748
* 🚀 **Modern & Native:** Built with best-practices using Kotlin, Jetpack Compose and Material You
4849
for a smooth and solid experience.
50+
* 🌍 **50+ Languages:** Applied globalization at its best.
4951
* 🔒 **Transparent:** Free, open-source, no-ads.
5052

5153
## 🛠️ One-Time Setup
@@ -56,44 +58,49 @@ permission (`WRITE_SECURE_SETTINGS`) has to be granted.
5658
The app comes with an easy step-by-step setup process, that lets you choose one of the following
5759
methods to do so:
5860

59-
* **Web Tool (Recommended)**Use our browser-based setup tool on a secondary device (Computer,
60-
Tablet,
61-
or Phone). No code or ADB
62-
installation required (WebADB).
63-
👉 **[lexip.dev/setup](https://lexip.dev/setup)**
61+
* **Web Tool (Recommended)**A browser-based setup tool on a secondary device (Computer,
62+
Tablet,
63+
or Phone). No code or ADB
64+
installation required (WebADB).
65+
👉 **[lexip.dev/setup](https://lexip.dev/setup)**
6466

6567
* **Shizuku** – If you have **[Shizuku](https://github.com/RikkaApps/Shizuku)** installed and
6668
configured, you can
67-
grant the permission directly within the Adaptive Theme app.
69+
grant the permission directly within Adaptive Theme.
70+
71+
* **Root** – If your device is rooted, you can grant the permission directly in Adaptive Theme as
72+
well.
73+
74+
* **Manual ADB** – If you have ADB installed on your computer, you can simply run the ADB command
75+
manually:
76+
```adb shell pm grant dev.lexip.hecate android.permission.WRITE_SECURE_SETTINGS```
6877

69-
* **Root** – If your device is rooted, you can grant the permission with one tap inside the app.
78+
## ✅ Safety
7079

71-
* **Manual ADB** – If you have ADB installed on your computer, you can run the ADB command manually.
80+
The required permission only allows the app to change system settings such as the dark mode. This is
81+
absolutely safe and
82+
completely reversible by uninstalling the app. It does **not** grant root access or read any user
83+
data.
7284

7385
## ⚙️ How it Works
7486

7587
**Wondering why the theme didn't change immediately?**
7688

7789
To avoid screen flicker and unnecessary background work, Adaptive Theme follows strict rules:
7890

79-
- **Event-driven:** It checks the light sensor only immediately after the screen turns on.
91+
- **Event-driven:** It checks the light sensor only right after the screen turns on. Combined with
92+
hysteresis, this prevents flicker, avoids interruptions while you’re using the phone, and saves
93+
battery.
8094
- **Validity check:** It verifies that the sensor is not obstructed (e.g., by a hand or pocket).
8195
- **Seamless switch:** It switches the theme instantly, ensuring the UI is ready before you start
8296
interacting with it.
8397

84-
## ✅ Safety
85-
86-
The required permission only allows the app to change system settings such as the dark mode. This is
87-
absolutely safe and
88-
completely reversible by uninstalling the app. It does **not** grant root access or read any user
89-
data.
90-
9198
## ❓ FAQ
9299

93100
**Does this require root?**
94101

95-
* No. It works on stock devices. However, if you have Root, it can optionally be used to set up the
96-
service faster.
102+
* No. It works on stock devices. However, if you have Root, it can be used as an alternative setup
103+
method.
97104

98105
**Does it work with custom Android skins (Xiaomi MIUI, Samsung OneUI, etc.)?**
99106

@@ -107,11 +114,12 @@ data.
107114
your device usage.
108115
- Check that your sensor isn’t covered when you turn the screen on.
109116
- Adjust your lux threshold and test in clearly bright/dim conditions.
117+
- Check if the current lux value is shown correctly in the Adaptive Theme app.
110118

111119
### Support & Feedback
112120

113-
If Adaptive Theme doesn’t work for you — or if you have any questions or ideas — please open an
114-
issue here or send feedback via the app.
121+
If Adaptive Theme doesn’t work for you — or if you have any questions or ideas — please [open an
122+
issue](https://github.com/xLexip/Adaptive-Theme/issues/new) here or send feedback via the app.
115123

116124
## ❤️ Support the Project
117125

@@ -142,7 +150,8 @@ also [buy me a coffee](https://buymeacoffee.com/lexip).
142150
Adaptive Theme is built with modern Android engineering standards to ensure a lightweight,
143151
maintainable, and production-ready codebase.
144152

145-
**Modern Codebase:** Written entirely in Kotlin with Jetpack Compose and Material 3 (Material You).
153+
**Modern Codebase:** Written entirely in Kotlin with Jetpack Compose and Material 3 (Material You),
154+
including haptic feedback.
146155

147156
**Architecture:** Follows the MVVM pattern with a Single-Activity architecture.
148157

@@ -155,7 +164,8 @@ broadcasts – ensuring zero unnecessary battery drain in the background.
155164

156165
### **Made with 🥨 in Germany.**
157166

158-
> ~~> Keywords: theme switcher · android automation · night mode · dark sense · automatic dark
167+
> ~~> Keywords: theme switcher · android automation · night mode · dark sense · automatic android
168+
dark
159169
mode ·
160170
brightness-based ·
161171
light-based · based on lux · google pixel · auto dark theme · shizuku apps · android 14 · android

app/build.gradle.kts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ android {
1616
applicationId = "dev.lexip.hecate"
1717
minSdk = 34
1818
targetSdk = 35
19-
versionCode = 97
20-
versionName = "1.0.0"
19+
versionCode = 103
20+
versionName = "1.1.0"
2121
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2222
}
2323

@@ -123,6 +123,8 @@ dependencies {
123123
"playImplementation"(libs.firebase.analytics)
124124
"playImplementation"(libs.firebase.crashlytics)
125125
"playImplementation"(libs.app.update.ktx)
126+
"playImplementation"(libs.review)
127+
"playImplementation"(libs.review.ktx)
126128
testImplementation(libs.junit)
127129
androidTestImplementation(libs.androidx.junit)
128130
androidTestImplementation(libs.androidx.espresso.core)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) 2025 xLexip <https://lexip.dev>
3+
*
4+
* Licensed under the GNU General Public License, Version 3.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.gnu.org/licenses/gpl-3.0
9+
*
10+
* Please see the License for specific terms regarding permissions and limitations.
11+
*/
12+
13+
package dev.lexip.hecate.util
14+
15+
import android.app.Activity
16+
17+
object InAppReviewHandler {
18+
19+
fun setReviewPending() {
20+
// No-op for FOSS flavor
21+
}
22+
23+
fun checkAndTriggerReview(activity: Activity) {
24+
// No-op for FOSS flavor
25+
}
26+
}
27+

app/src/main/kotlin/dev/lexip/hecate/ui/MainActivity.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import dev.lexip.hecate.services.BroadcastReceiverService
2525
import dev.lexip.hecate.ui.navigation.NavigationManager
2626
import dev.lexip.hecate.ui.theme.HecateTheme
2727
import dev.lexip.hecate.util.DarkThemeHandler
28+
import dev.lexip.hecate.util.InAppReviewHandler
2829
import dev.lexip.hecate.util.InAppUpdateManager
2930
import dev.lexip.hecate.util.InstallSourceChecker
3031

@@ -74,6 +75,8 @@ class MainActivity : ComponentActivity() {
7475
override fun onResume() {
7576
super.onResume()
7677

78+
InAppReviewHandler.checkAndTriggerReview(this)
79+
7780
inAppUpdateManager?.resumeImmediateUpdateIfNeeded()
7881
inAppUpdateManager?.resumeFlexibleUpdateIfNeeded()
7982

app/src/main/kotlin/dev/lexip/hecate/ui/MainScreen.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import androidx.compose.animation.fadeIn
2424
import androidx.compose.animation.fadeOut
2525
import androidx.compose.animation.slideInVertically
2626
import androidx.compose.animation.slideOutVertically
27+
import androidx.compose.foundation.isSystemInDarkTheme
2728
import androidx.compose.foundation.layout.Arrangement
2829
import androidx.compose.foundation.layout.Column
2930
import androidx.compose.foundation.layout.Spacer
@@ -97,6 +98,8 @@ fun MainScreen(
9798

9899
val internalUiState by mainViewModel.uiState.collectAsState()
99100

101+
val isSystemDark = isSystemInDarkTheme()
102+
100103
LaunchedEffect(Unit) {
101104
val installed = ShizukuAvailability.isShizukuInstalled(context)
102105
mainViewModel.setShizukuInstalled(installed)
@@ -271,7 +274,11 @@ fun MainScreen(
271274
onValueChange = { index ->
272275
mainViewModel.setPendingCustomSliderLux(lux[index])
273276
mainViewModel.onSliderValueCommitted(index)
274-
textShakeKey.intValue += 1
277+
278+
// Shake the description text when the user could expect an immediate theme switch
279+
if ((currentLux > lux[index]) == isSystemDark) {
280+
textShakeKey.intValue += 1
281+
}
275282
},
276283
enabled = uiState.adaptiveThemeEnabled,
277284
firstCard = true,

app/src/main/kotlin/dev/lexip/hecate/ui/components/ThreeDotMenu.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ import androidx.core.net.toUri
2828
import dev.lexip.hecate.BuildConfig
2929
import dev.lexip.hecate.R
3030
import dev.lexip.hecate.logging.Logger
31+
import dev.lexip.hecate.util.InAppReviewHandler
3132
import dev.lexip.hecate.util.InstallSourceChecker
3233
import java.net.URLEncoder
3334
import java.nio.charset.StandardCharsets
3435

35-
3636
const val FEEDBACK_SUBJECT = "Adaptive Theme Feedback (v${BuildConfig.VERSION_NAME})"
3737

3838
@Composable
@@ -150,6 +150,11 @@ fun ThreeDotMenu(
150150
context,
151151
"support_project"
152152
)
153+
154+
if (isAdaptiveThemeEnabled) {
155+
InAppReviewHandler.setReviewPending()
156+
}
157+
153158
val supportUri =
154159
"https://github.com/xLexip/Adaptive-Theme?tab=readme-ov-file#%EF%B8%8F-support-the-project".toUri()
155160
val supportIntent = Intent(Intent.ACTION_VIEW, supportUri)

app/src/main/kotlin/dev/lexip/hecate/ui/setup/SetupViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ class SetupViewModel(
586586

587587
fun onGrantViaRootRequested() {
588588
val context = application.applicationContext
589-
Toast.makeText(context, R.string.setup_root_grant_starting, Toast.LENGTH_SHORT).show()
589+
Toast.makeText(context, R.string.setup_root_request, Toast.LENGTH_SHORT).show()
590590

591591
viewModelScope.launch(ioDispatcher) {
592592
val result = tryGrantViaRoot()

app/src/main/kotlin/dev/lexip/hecate/ui/setup/components/ForExpertsSection.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ internal fun ForExpertsSectionCard(
115115
Column(modifier = Modifier.fillMaxWidth()) {
116116
Spacer(modifier = Modifier.height(8.dp))
117117
Text(
118-
text = stringResource(id = R.string.setup_manual_command),
118+
text = stringResource(id = R.string.setup_alternatives),
119119
style = MaterialTheme.typography.bodyMedium,
120120
color = MaterialTheme.colorScheme.onSurfaceVariant
121121
)

app/src/main/res/values-de/strings.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
<string name="setup_alternative_methods">Alternative Methoden</string>
6363
<string name="setup_grant_title">Schritt 3: Berechtigung mit dem anderen Gerät erteilen</string>
6464
<string name="setup_grant_body">Öffne den folgenden Link auf deinem anderen Gerät und folge den Anweisungen:</string>
65-
<string name="setup_manual_command">Alternativ kannst du diesen ADB-Command ausführen oder Root benutzen. Shizuku wird ebenfalls unterstützt.</string>
65+
<string name="setup_alternatives">Alternativ kannst du einen ADB-Command ausführen oder Root benutzen. Shizuku wird ebenfalls unterstützt.</string>
6666
<string name="setup_permission_granted">Berechtigung erteilt.</string>
6767
<string name="setup_permission_not_granted">Berechtigung noch nicht erteilt. Bitte schließe die Einrichtung mit dem anderen Gerät ab.</string>
6868
<string name="setup_usb_debugging_disabled">USB-Debugging aktivieren</string>
@@ -73,12 +73,12 @@
7373
<string name="setup_why_other_device_title">Warum ist ein anderes Gerät nötig?</string>
7474
<string name="setup_why_other_device">Android verhindert, dass Apps sich die benötigte Berechtigung selbst erteilen. Es wird ein anderes Gerät mit einem Webbrowser oder ADB benötigt.</string>
7575
<string name="setup_is_this_safe_title">Ist das sicher?</string>
76-
<string name="setup_is_this_safe_body">Ja. Es erlaubt der App nur, Einstellungen wie den Dunkelmodus zu ändern. Das ist absolut sicher und vollständig rückgängig zu machen.</string>
76+
<string name="setup_is_this_safe_body">Ja. Es erlaubt der App nur, Einstellungen wie den Dark Mode zu ändern. Das ist absolut sicher und vollständig rückgängig zu machen. Außerdem ist der Quellcode öffentlich auf GitHub einsehbar.</string>
7777
<string name="setup_shizuku_title">Alternative: Shizuku</string>
7878
<string name="setup_shizuku_body">Wenn du Shizuku bereits verwendest, benötigst du weder ein zweites Gerät noch ADB.</string>
7979
<string name="setup_shizuku_action">Shizuku verwenden</string>
8080
<string name="setup_action_use_root">Root verwenden</string>
81-
<string name="setup_root_grant_starting">Root-Zugriff angefragt… (beta)</string>
81+
<string name="setup_root_request">Root-Zugriff angefragt…</string>
8282
<string name="setup_root_grant_failed">Root-Vergabe fehlgeschlagen.</string>
8383
<string name="setup_root_question">Ist das Gerät gerooted?</string>
8484

app/src/main/res/values/strings.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<string name="setup_alternative_methods">Alternative methods</string>
6868
<string name="setup_grant_title">Step 3: Grant permission with the other device</string>
6969
<string name="setup_grant_body">Open the following link on your other device and follow the instructions:</string>
70-
<string name="setup_manual_command">Alternatively, you can execute this ADB command or use root to grant the permission. Shizuku is also supported.</string>
70+
<string name="setup_alternatives">Alternatively, you can execute an ADB command yourself or use root to grant the permission. Shizuku is also supported.</string>
7171
<string name="setup_permission_granted">Permission granted.</string>
7272
<string name="setup_permission_not_granted">Permission not yet granted. Please complete the setup with the other device.</string>
7373
<string name="setup_usb_debugging_disabled">Enable USB Debugging</string>
@@ -78,12 +78,12 @@
7878
<string name="setup_why_other_device_title">Why is another device required?</string>
7979
<string name="setup_why_other_device">Android prevents apps from granting the required permission themselves. It requires another device with either a web browser or ADB installed. </string>
8080
<string name="setup_is_this_safe_title">Is this safe?</string>
81-
<string name="setup_is_this_safe_body">Yes. It just allows the app to modify settings like the dark mode. This is absolutely safe and completely reversible.</string>
81+
<string name="setup_is_this_safe_body">Yes. It just allows the app to modify settings like the dark mode. This is absolutely safe and completely reversible. Furthermore, the source code is publicly available on GitHub.</string>
8282
<string name="setup_shizuku_title">Alternative: Shizuku</string>
8383
<string name="setup_shizuku_body">If you already use Shizuku, you won’t need a second device or ADB.</string>
8484
<string name="setup_shizuku_action">Use Shizuku instead</string>
8585
<string name="setup_action_use_root">Use Root</string>
86-
<string name="setup_root_grant_starting">Requesting root access… (beta)</string>
86+
<string name="setup_root_request">Requesting root access…</string>
8787
<string name="setup_root_grant_failed">Root grant failed.</string>
8888
<string name="setup_root_question">Is the device rooted?</string>
8989

0 commit comments

Comments
 (0)