From 2b9a095cbf4720f056532bded1be9f2584f8447a Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 2 Nov 2026 20:50:22 +0100 Subject: 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 --- app/src/main/AndroidManifest.xml | 4 ++ .../java/app/passwordstore/ui/main/MainActivity.kt | 77 ++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 app/src/main/java/app/passwordstore/ui/main/MainActivity.kt (limited to 'app/src') 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 @@ -64,6 +64,10 @@ + + + * 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 { + LegacyScreen( + Intent(this@MainActivity, PasswordStore::class.java).setAction(Intent.ACTION_VIEW) + ) + } + composable { entry -> + val route = entry.toRoute() + 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() + } + } +} -- cgit v1.2.3