diff options
| author | Danilo M. <danix@danix.xyz> | 2026-11-02 20:50:22 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-11-02 20:50:22 +0100 |
| commit | 2b9a095cbf4720f056532bded1be9f2584f8447a (patch) | |
| tree | 58c2224d23a646352de7f72467555afaf70bffcb | |
| parent | 4a011721261bd46da3e84d443154d8e360494ece (diff) | |
| download | HardenedPass-2b9a095cbf4720f056532bded1be9f2584f8447a.tar.gz HardenedPass-2b9a095cbf4720f056532bded1be9f2584f8447a.zip | |
feat(app): add the single-activity Compose host
Its two routes hand off to the legacy list and decrypt activities until
those screens are ported.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | app/src/main/AndroidManifest.xml | 4 | ||||
| -rw-r--r-- | app/src/main/java/app/passwordstore/ui/main/MainActivity.kt | 77 |
2 files changed, 81 insertions, 0 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1cbe76a9..457647d5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -65,6 +65,10 @@ </activity> <activity + android:name=".ui.main.MainActivity" + android:exported="false" /> + + <activity android:name="com.journeyapps.barcodescanner.CaptureActivity" android:clearTaskOnLaunch="true" android:exported="false" diff --git a/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt b/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt new file mode 100644 index 00000000..018deae3 --- /dev/null +++ b/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2026 Danilo M. <danix@danix.xyz> + * SPDX-License-Identifier: GPL-3.0-only + */ + +package app.passwordstore.ui.main + +import android.content.Intent +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.fragment.app.FragmentActivity +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import androidx.navigation.toRoute +import app.passwordstore.data.repo.PasswordRepository +import app.passwordstore.ui.compose.theme.APSTheme +import app.passwordstore.ui.crypto.BasePGPActivity +import app.passwordstore.ui.crypto.DecryptActivity +import app.passwordstore.ui.passwords.PasswordStore +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.serialization.Serializable + +/** The password list, at the store root. */ +@Serializable data object ListRoute + +/** One entry. [filePath] was checked with [LaunchActivity.isFileInRepo] before routing here. */ +@Serializable data class EntryRoute(val filePath: String) + +/** + * Single-activity host for the Compose UI. Not exported: it is only started by [LaunchActivity], + * after its biometric gate and path check. Extends [FragmentActivity] only because BiometricPrompt + * needs one; it hosts no fragments. + */ +@AndroidEntryPoint +class MainActivity : FragmentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val filePath = intent.getStringExtra(BasePGPActivity.EXTRA_FILE_PATH) + val start: Any = if (filePath != null) EntryRoute(filePath) else ListRoute + setContent { + APSTheme { + NavHost(rememberNavController(), startDestination = start) { + composable<ListRoute> { + LegacyScreen( + Intent(this@MainActivity, PasswordStore::class.java).setAction(Intent.ACTION_VIEW) + ) + } + composable<EntryRoute> { entry -> + val route = entry.toRoute<EntryRoute>() + LegacyScreen( + Intent(this@MainActivity, DecryptActivity::class.java) + .putExtra(BasePGPActivity.EXTRA_FILE_PATH, route.filePath) + .putExtra( + BasePGPActivity.EXTRA_REPO_PATH, + PasswordRepository.getRepositoryDirectory().absolutePath, + ) + ) + } + } + } + } + } + + // ponytail: trampoline to a screen not yet ported; each port replaces one call with the + // real composable, and the last port deletes this function. + @Composable + private fun LegacyScreen(intent: Intent) { + LaunchedEffect(Unit) { + startActivity(intent) + finish() + } + } +} |
