Skip to content

Commit 50bddb1

Browse files
trinadhthatakuladependabot[bot]gemini-code-assist[bot]CopilotCopilot
authored
New Settings and Biometric Auth (#137)
* Shizuku and Dhizuku app installer Stability fix (#131) * Update project inspection profiles and build configuration * **IDE**: Extensively expanded `Project_Default.xml` with numerous Android Lint inspection tools, specifically covering Accessibility, Jetpack Compose, Fragments, and various Google Play policies. * **Build**: Updated `app/build.gradle.kts` to exclude dependency information from APKs while retaining it in App Bundles. * chore(deps): bump com.google.devtools.ksp in the maven group (#128) Bumps the maven group with 1 update: [com.google.devtools.ksp](https://github.com/google/ksp). Updates `com.google.devtools.ksp` from 2.3.5 to 2.3.6 - [Release notes](https://github.com/google/ksp/releases) - [Commits](google/ksp@2.3.5...2.3.6) --- updated-dependencies: - dependency-name: com.google.devtools.ksp dependency-version: 2.3.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: maven ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump the maven group with 2 updates (#129) Bumps the maven group with 2 updates: com.android.application and com.android.test. Updates `com.android.application` from 9.1.0-alpha09 to 9.2.0-alpha01 Updates `com.android.test` from 9.1.0-alpha09 to 9.2.0-alpha01 Updates `com.android.test` from 9.1.0-alpha09 to 9.2.0-alpha01 --- updated-dependencies: - dependency-name: com.android.application dependency-version: 9.2.0-alpha01 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: maven - dependency-name: com.android.test dependency-version: 9.2.0-alpha01 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: maven - dependency-name: com.android.test dependency-version: 9.2.0-alpha01 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: maven ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Revise APK size details and add support options Updated download sizes and added support development section. * Add Ko-fi funding option to FUNDING.yml add ko-fi and patreon * Clean up project dependencies by removing benchmarking and profiling libraries * **Build**: Remove unused versions and library definitions for `annotationJvm`, `uiautomator`, `benchmarkMacroJunit4`, `baselineprofile`, and `profileinstaller` from `gradle/libs.versions.toml`. * Clean up project-level build configuration and plugin definitions * **Build**: Remove unused `kotlin-android` and `baselineprofile` plugin definitions from `gradle/libs.versions.toml`. * **Build**: Remove the commented-out `kotlin.android` plugin alias from the top-level `build.gradle.kts`. * Enhance Shizuku/Dhizuku installer stability and fallbacks * **Build**: Bump `versionCode` to 1715 and `versionName` to 1.71.5 in `gradle.properties`. * **Installer**: * Implement a silent fallback mechanism in `InstallerRepositoryImpl` that reverts to the system's default `PackageInstaller` if Shizuku or Dhizuku privileged installations fail. * Refactor `getDhizukuPackageInstaller` and `getShizukuPackageInstaller` to use `ShizukuPackageInstallerUtils` for better compatibility across API levels and ROMs, avoiding `NoSuchMethodError` on certain devices. * Ensure created installation sessions belong to the app's own package name to prevent UID mismatch errors. * Add `emitErrors` flag to `performPackageInstallerInstall` to allow internal retries without triggering error UI states prematurely. * **ShizukuReflector**: Add `createPackageInstallerFor(installerPackageName)` to allow creating privileged installers for specific package identities. * **IDE**: Clean up `Project_Default.xml` by removing numerous explicit Android Lint inspection rules. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Trinadh Thatakula <YOUR_EMAIL_HERE> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * New Settings page (#135) * chore(deps): bump io.coil-kt.coil3:coil-compose in the maven group (#132) Bumps the maven group with 1 update: [io.coil-kt.coil3:coil-compose](https://github.com/coil-kt/coil). Updates `io.coil-kt.coil3:coil-compose` from 3.3.0 to 3.4.0 - [Release notes](https://github.com/coil-kt/coil/releases) - [Changelog](https://github.com/coil-kt/coil/blob/main/CHANGELOG.md) - [Commits](coil-kt/coil@3.3.0...3.4.0) --- updated-dependencies: - dependency-name: io.coil-kt.coil3:coil-compose dependency-version: 3.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: maven ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump the maven group across 1 directory with 3 updates (#134) Bumps the maven group with 3 updates in the / directory: androidx.compose.material3:material3, com.android.application and com.android.test. Updates `androidx.compose.material3:material3` from 1.5.0-alpha14 to 1.5.0-alpha15 Updates `com.android.application` from 9.2.0-alpha01 to 9.2.0-alpha02 Updates `com.android.test` from 9.2.0-alpha01 to 9.2.0-alpha02 Updates `com.android.test` from 9.2.0-alpha01 to 9.2.0-alpha02 --- updated-dependencies: - dependency-name: androidx.compose.material3:material3 dependency-version: 1.5.0-alpha15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: maven - dependency-name: com.android.application dependency-version: 9.2.0-alpha02 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: maven - dependency-name: com.android.test dependency-version: 9.2.0-alpha02 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: maven - dependency-name: com.android.test dependency-version: 9.2.0-alpha02 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: maven ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update Gradle wrapper to 9.4.0-rc-1 * Update `distributionUrl` to Gradle 9.4.0-rc-1 in `gradle-wrapper.properties`. * Add `distributionSha256Sum` for the new Gradle distribution. * Add AndroidX Biometric dependency * **Build**: Add `androidx.biometric:biometric-ktx` version `1.2.0-alpha05` to `gradle/libs.versions.toml`. * **App**: Include `libs.androidx.biometric` as an implementation dependency in `app/build.gradle.kts`. * Implement biometric authentication and expanded user preferences * **Core**: Add `BiometricHelper` utility to check for biometric hardware and authentication capabilities using `androidx.biometric`. * **Preferences**: * Expand `UserPreferences` and `PreferenceRepository` to support `ThemeMode`, `useDynamicColor`, and `biometricLockEnabled`. * Refactor `PreferenceRepositoryImpl` to use `runCatching` for safer enum parsing and organize keys into logical groups (App List, Theme, Security). * **Security UI**: * Implement `BiometricScreen` to handle the transition between the system biometric prompt and a custom `BiometricErrorScreen`. * Add `AuthState` sealed interface to manage the application's authentication lifecycle (NotRequired, Locked, Unlocked, Error). * Use `FragmentActivity` for hosting `BiometricPrompt` and provide a Material Expressive error UI with retry/exit actions. * Add SettingsViewModel and initial SettingsScreen with ThemeMode domain model * **Domain**: Add `ThemeMode` enum to represent Light, Dark, and System theme preferences with associated labels. * **Presentation**: * Implement `SettingsViewModel` to manage user preferences (theme mode, dynamic color, and biometric lock) and interface with `BiometricHelper` for hardware capability checks. * Create a placeholder `SettingsScreen` composable integrated with Koin for view model injection. * Add Settings screen and biometric authentication support * **Navigation**: Enable the `SETTINGS` destination in `AppDestinations.kt` and integrate `SettingsScreen` into the `MainScreen` navigation logic. * **Security**: * Implement `SecurityViewModel` to manage session-based authentication states (`Locked`, `Unlocked`, `Error`, `NotRequired`). * Add `BiometricHelper` to the dependency injection `coreModule`. * Update `HomeActivity` to conditionally display a `BiometricScreen` based on the current authentication state before granting access to the `MainScreen`. * **Preferences**: Expand `UserPreferences` to include settings for `themeMode`, `useDynamicColor`, and `biometricLockEnabled`. * **Dependency Injection**: Register `SettingsViewModel`, `SecurityViewModel`, and `BiometricHelper` in `Modules.kt`. * **Code Cleanup**: Remove redundant comments regarding Shizuku permission handling in `HomeActivity`. * Add UI components and building blocks for Settings screen * **UI Components**: Implement reusable Composable functions for the settings interface: * `SettingsHeader`: Displays a header with an icon and "Settings" title. * `SettingsSectionLabel` and `SettingsDivider`: Provides visual separation for setting groups. * `SettingsRow`: A base layout for setting items with an icon, title, and subtitle. * `SettingsSwitchRow`: A specialized row containing a toggle switch. * `SettingsInfoRow`: A row for displaying static key-value information. * `SettingsLinkRow`: A row with an action button for external links. * `EnrollBiometricRow`: A specific action row for directing users to system biometric settings. * Introduce `ConnectedButtonGroup` component and refactor UI selection controls * **Components**: Create `ConnectedButtonGroup`, a reusable selection component built on Material 3 Expressive APIs (`ButtonGroup` and `ToggleButton`) that supports animated width transitions and custom item types (Icon, Label, or both). * **UI Refactoring**: Replace `SingleChoiceSegmentedButtonRow` and `SegmentedButton` with the new `ConnectedButtonGroup` across multiple screens for a more consistent and animated experience: * `SettingsScreen`: Updated theme mode selection. * `AppListScreen` & `FreezerScreen`: Updated app type switcher (User/System). * `DashboardHeader`: Updated app type switcher. * `AppFilterSheet`: Updated tab selection (Filters/Sort). * **Security**: Wrap `BiometricScreen` content in a `Scaffold` and `Box` to ensure proper layout and padding. * **Navigation**: Fix a duplicate `SettingsScreen` entry in `MainScreen`'s destination logic. * **Activity**: Update `HomeActivity` to inherit from `FragmentActivity` instead of `ComponentActivity` to support fragment-based APIs (likely for biometric integration). * Update theme handling in HomeActivity and adjust versioning in gradle.properties * Update theme settings icon in SettingsScreen * **UI**: Update the `SettingsRow` for the "Theme" option in `SettingsScreen.kt` to use the new `theme_panel` icon instead of the shield icon. * **Resources**: Add `app/src/main/res/drawable/theme_panel.xml`, a new vector drawable representing a color palette/theme panel. * Add AMOLED mode support for pure black background in dark theme * **UI**: Add "AMOLED Mode" switch to `SettingsScreen` with a description for pure black backgrounds. * **Theme**: Update `ThorTheme` to override background and surface colors to pure black when `amoledMode` and `darkTheme` are enabled. * **Domain**: Add `useAmoled` property to `UserPreferences` and define `setUseAmoled` in `PreferenceRepository`. * **Data**: Implement `USE_AMOLED` DataStore key and persistence logic in `PreferenceRepositoryImpl`. * **Integration**: Update `SettingsViewModel` to handle AMOLED toggle and `HomeActivity` to pass the preference to the theme engine. * Update app/src/main/java/com/valhalla/thor/HomeActivity.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update app/src/main/java/com/valhalla/thor/presentation/main/MainScreen.kt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix review feedback: compilation errors, auth flicker, dead file, Gradle RC (#136) * Initial plan * Address all open review comments from Settings page PR Co-authored-by: trinadhthatakula <33689525+trinadhthatakula@users.noreply.github.com> * Revert Gradle wrapper back to 9.4.0-rc-1 (9.4 stable not yet released) Co-authored-by: trinadhthatakula <33689525+trinadhthatakula@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: trinadhthatakula <33689525+trinadhthatakula@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove distribution SHA-256 sum from Gradle wrapper * Remove the `distributionSha256Sum` property from `gradle/wrapper/gradle-wrapper.properties`. * Update app/src/main/java/com/valhalla/thor/presentation/security/BiometricPromptHandler.kt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update app/src/main/java/com/valhalla/thor/presentation/common/components/ConnectedButtonGroup.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Trinadh Thatakula <YOUR_EMAIL_HERE> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> * Clean up redundant code and imports in UI and security components * **UI**: Remove unused `Spacer`, `width`, and `animateWidth` imports from `ConnectedButtonGroup.kt`. * **UI**: Remove duplicate `@OptIn` and `@Composable` annotations from the `connectedShapesFor` function in `ConnectedButtonGroup.kt`. * **Security**: Remove a duplicate `BiometricPromptHandler` object declaration and its associated KDoc in `BiometricPromptHandler.kt`. * Update README to reflect Fingerprint Lock status Removed Fingerprint Lock from upcoming features and added it to working features. * Update app/src/main/java/com/valhalla/thor/data/repository/InstallerRepositoryImpl.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Trinadh Thatakula <YOUR_EMAIL_HERE>
1 parent 58ece4f commit 50bddb1

31 files changed

+1357
-166
lines changed

.github/FUNDING.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# These are supported funding model platforms
2-
31
github: trinadhthatakula
42
patreon: trinadh
3+
ko_fi: trinadh
54
buy_me_a_coffee: trinadh
5+
custom: ["https://www.paypal.me/trinadhthatakula"]

README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,18 @@
2828
* 100% Kotlin
2929
* Material 3 Design
3030
* Jetpack Compose
31-
* PlayStore Download Size (less than 2.0 MB)
32-
* Smallest APK size (less than 2.50 MB)
31+
* PlayStore Download Size (around 2.0 MB)
32+
* Smallest APK size (less than 4 MB)
3333
* FOSS - GPL-3.0
3434
* Fully Offline
3535
* No Ads/Trackers
3636

3737
## Working Features
3838

39-
- App Installer (install with root, shizuku or normal) **TESTING**
39+
- Fingerprint Lock
40+
- Themes (dark, light, system) + AMOLED
41+
- App Installer (install with root, shizuku or normal)
42+
- Dhizuku Support (testing)
4043
- Shizuku Support
4144
- Fully reproducible, copyleft libre software (GPLv3.0)
4245
- Material 3 with dynamic colors
@@ -61,6 +64,16 @@
6164
- Option to choose installers when reinstalling
6265
- Many more
6366

67+
## 💖 Support Development
68+
69+
Thor is a labor of love, built to be **100% offline, ad-free, and tracker-free**. If this tool has made your Android management easier, consider supporting its continued development. Your contributions help keep the project alive and free for everyone.
70+
71+
| Platform | Link |
72+
| --- | --- |
73+
| **Patreon** | [Support on Patreon](https://www.patreon.com/trinadh) |
74+
| **Buy Me a Coffee** | [Buy me a coffee](https://www.buymeacoffee.com/trinadh) |
75+
| **PayPal** | [Donate via PayPal](https://www.paypal.me/trinadhthatakula) |
76+
6477
## Credits
6578

6679
- Portions of this app use code from [`libsu`](https://github.com/topjohnwu/libsu)
@@ -80,4 +93,4 @@ This project is licensed under the GNU General Public License v3.0 (GPL-3.0).
8093
- `libsu` is licensed under the Apache License 2.0. All modifications and usage in this project
8194
comply with the Apache-2.0 requirements.
8295
- This project as a whole is distributed under the GNU General Public License v3.0 (GPL-3.0).
83-
- See the [LICENSE](LICENSE) file for full license text.
96+
- See the [LICENSE](LICENSE) file for full license text.

app/build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ android {
9797
}
9898
}
9999

100+
dependenciesInfo {
101+
includeInApk = false
102+
includeInBundle = true
103+
}
104+
100105
buildTypes {
101106
release {
102107
isMinifyEnabled = true
@@ -188,6 +193,7 @@ dependencies {
188193
implementation(libs.androidx.splashscreen)
189194
implementation(libs.androidx.core.ktx)
190195
implementation(libs.androidx.activity.compose)
196+
implementation(libs.androidx.biometric)
191197
implementation(platform(libs.androidx.compose.bom))
192198
implementation(libs.androidx.ui)
193199
implementation(libs.androidx.ui.graphics)
Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
package com.valhalla.thor
22

33
import android.os.Bundle
4-
import androidx.activity.ComponentActivity
54
import androidx.activity.compose.setContent
65
import androidx.activity.enableEdgeToEdge
6+
import androidx.compose.foundation.isSystemInDarkTheme
7+
import androidx.compose.runtime.getValue
78
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
9+
import androidx.fragment.app.FragmentActivity
10+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
811
import androidx.lifecycle.lifecycleScope
12+
import com.valhalla.thor.domain.model.ThemeMode
913
import com.valhalla.thor.domain.repository.SystemRepository
1014
import com.valhalla.thor.presentation.common.ShizukuPermissionHandler
1115
import com.valhalla.thor.presentation.home.HomeViewModel
1216
import com.valhalla.thor.presentation.main.MainScreen
17+
import com.valhalla.thor.presentation.security.AuthState
18+
import com.valhalla.thor.presentation.security.BiometricScreen
19+
import com.valhalla.thor.presentation.security.SecurityViewModel
20+
import com.valhalla.thor.presentation.settings.SettingsViewModel
1321
import com.valhalla.thor.presentation.theme.ThorTheme
1422
import com.valhalla.thor.util.Logger
1523
import kotlinx.coroutines.launch
1624
import org.koin.android.ext.android.inject
1725
import org.koin.androidx.viewmodel.ext.android.viewModel
1826

19-
class HomeActivity : ComponentActivity() {
27+
class HomeActivity : FragmentActivity() {
2028

2129
private val systemRepository: SystemRepository by inject()
2230
private val homeViewModel: HomeViewModel by viewModel()
31+
private val securityViewModel: SecurityViewModel by viewModel()
32+
private val settingsViewModel: SettingsViewModel by viewModel()
2333

2434
private val requestCode = 1001
2535
private var hasRequestedShizuku = false
@@ -31,7 +41,6 @@ class HomeActivity : ComponentActivity() {
3141
},
3242
onPermissionDenied = {
3343
Logger.d("HomeActivity", "Shizuku Denied")
34-
// We stop asking automatically. User must click "Refresh" in dashboard manually now.
3544
},
3645
onBinderDead = {
3746
Logger.w("HomeActivity", "Shizuku Binder Died")
@@ -42,23 +51,55 @@ class HomeActivity : ComponentActivity() {
4251
super.onCreate(savedInstanceState)
4352
installSplashScreen()
4453
enableEdgeToEdge()
45-
4654
shizukuHandler.register()
4755

4856
setContent {
49-
ThorTheme {
50-
MainScreen(
51-
homeViewModel = homeViewModel,
52-
onExit = { finish() }
53-
)
57+
val prefs by settingsViewModel.preferences.collectAsStateWithLifecycle()
58+
val systemDark = isSystemInDarkTheme()
59+
val darkTheme = when (prefs.themeMode) {
60+
ThemeMode.LIGHT -> false
61+
ThemeMode.DARK -> true
62+
ThemeMode.SYSTEM -> systemDark
63+
}
64+
65+
ThorTheme(
66+
darkTheme = darkTheme,
67+
dynamicColor = prefs.useDynamicColor,
68+
amoledMode = prefs.useAmoled,
69+
) {
70+
val authState by securityViewModel.authState.collectAsStateWithLifecycle()
71+
72+
when (authState) {
73+
AuthState.NotRequired,
74+
AuthState.Unlocked -> {
75+
MainScreen(
76+
homeViewModel = homeViewModel,
77+
onExit = { finish() }
78+
)
79+
}
80+
81+
AuthState.Locked,
82+
is AuthState.Error -> {
83+
BiometricScreen(
84+
isError = authState is AuthState.Error,
85+
errorMessage = (authState as? AuthState.Error)?.message ?: "",
86+
onAuthenticated = { securityViewModel.onAuthenticated() },
87+
onError = { message ->
88+
Logger.e("HomeActivity", "Biometric error: $message")
89+
securityViewModel.onAuthError(message)
90+
},
91+
onRetry = { securityViewModel.onRetry() },
92+
onExit = { finish() }
93+
)
94+
}
95+
}
5496
}
5597
}
5698
}
5799

58100
override fun onResume() {
59101
super.onResume()
60102
lifecycleScope.launch {
61-
// Only ask automatically ONCE per session if not rooted.
62103
if (!systemRepository.isRootAvailable() && !hasRequestedShizuku) {
63104
hasRequestedShizuku = true
64105
shizukuHandler.checkAndRequestPermission(requestCode)
@@ -70,4 +111,4 @@ class HomeActivity : ComponentActivity() {
70111
shizukuHandler.unregister()
71112
super.onDestroy()
72113
}
73-
}
114+
}

0 commit comments

Comments
 (0)