Skip to content
This repository was archived by the owner on Oct 19, 2024. It is now read-only.

Commit 4684a5c

Browse files
committed
Revert "Initial ui rewrite"
This reverts commit 2b2933d.
1 parent 43586b6 commit 4684a5c

File tree

82 files changed

+5521
-1821
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+5521
-1821
lines changed

app/build.gradle.kts

+43-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ plugins {
33
alias(libs.plugins.dagger.hilt)
44
alias(libs.plugins.kotlin.ksp)
55
alias(libs.plugins.kotlin.android)
6+
alias(libs.plugins.kotlin.serialization)
7+
alias(libs.plugins.kotlin.parcelize)
68
alias(libs.plugins.compose.compiler)
79
}
810

@@ -69,14 +71,53 @@ android {
6971
}
7072

7173
dependencies {
74+
implementation(libs.androidx.core.ktx)
75+
implementation(libs.androidx.activity.compose)
76+
77+
implementation(libs.compose.material.icons)
78+
implementation(libs.compose.material3)
79+
implementation(libs.compose.navigation)
80+
implementation(libs.compose.ui)
81+
82+
implementation(libs.accompanist.drawablepainter)
83+
84+
implementation(libs.androidx.biometric.ktx)
85+
86+
// used for calling `onResume` and locking vault after X minutes
87+
implementation(libs.compose.lifecycle.runtime)
88+
89+
implementation(projects.databaseLogic)
90+
7291
// dagger
7392
implementation(libs.dagger.hilt)
7493
implementation(libs.hilt.navigation.compose)
7594
ksp(libs.dagger.hilt.compiler)
7695

77-
implementation(projects.uiLogic)
78-
implementation(projects.databaseLogic)
96+
implementation(libs.coil.compose)
97+
98+
implementation(libs.librepass.client)
99+
implementation(libs.otp)
100+
101+
implementation(libs.kotlinx.coroutines)
102+
implementation(libs.kotlinx.serialization.json)
103+
104+
implementation(projects.common)
105+
implementation(projects.businessLogic)
79106

80107
// for splash screen with material3 and dynamic color
81108
implementation(libs.google.material)
109+
110+
implementation(libs.zxing.android) { isTransitive = false }
111+
implementation(libs.zxing)
112+
113+
implementation(libs.medzik.android.compose)
114+
implementation(libs.medzik.android.crypto)
115+
implementation(libs.medzik.android.utils)
116+
117+
// for testing
118+
debugImplementation(libs.compose.ui.test.manifest)
119+
120+
// for preview support
121+
debugImplementation(libs.compose.ui.tooling)
122+
implementation(libs.compose.ui.tooling.preview)
82123
}

app/src/main/java/dev/medzik/librepass/android/MainActivity.kt

+40-24
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ import android.os.Bundle
44
import android.util.Log
55
import androidx.activity.compose.setContent
66
import androidx.activity.enableEdgeToEdge
7+
import androidx.compose.foundation.isSystemInDarkTheme
78
import androidx.fragment.app.FragmentActivity
9+
import androidx.navigation.NavController
810
import dagger.hilt.android.AndroidEntryPoint
11+
import dev.medzik.android.utils.openEmailApplication
12+
import dev.medzik.librepass.android.business.VaultCache
13+
import dev.medzik.librepass.android.common.popUpToDestination
914
import dev.medzik.librepass.android.database.Repository
1015
import dev.medzik.librepass.android.ui.LibrePassNavigation
16+
import dev.medzik.librepass.android.ui.screens.auth.Unlock
1117
import dev.medzik.librepass.android.ui.theme.LibrePassTheme
1218
import javax.inject.Inject
1319

@@ -16,6 +22,9 @@ class MainActivity : FragmentActivity() {
1622
@Inject
1723
lateinit var repository: Repository
1824

25+
@Inject
26+
lateinit var vault: VaultCache
27+
1928
override fun onCreate(savedInstanceState: Bundle?) {
2029
super.onCreate(savedInstanceState)
2130

@@ -25,42 +34,49 @@ class MainActivity : FragmentActivity() {
2534
Thread.setDefaultUncaughtExceptionHandler { _, e ->
2635
Log.e("LibrePass", "Uncaught exception", e)
2736

28-
// TODO
37+
openEmailApplication(
38+
email = "[email protected]",
39+
subject = "[Bug] [Android]: ",
40+
body = "<A few words about the error>\n\n\n---- Stack trace for debugging ----\n\n${Log.getStackTraceString(e)}"
41+
)
2942

3043
finish()
3144
}
3245

3346
MigrationsManager.run(this, repository)
3447

3548
// retrieves aes key for vault decryption if key is valid
36-
// vault.getSecretsIfNotExpired(this)
49+
vault.getSecretsIfNotExpired(this)
3750

3851
setContent {
39-
LibrePassTheme {
52+
LibrePassTheme(
53+
darkTheme = isSystemInDarkTheme(),
54+
dynamicColor = true
55+
) {
4056
LibrePassNavigation()
4157
}
4258
}
4359
}
4460

45-
// override fun onPause() {
46-
// super.onPause()
47-
//
48-
// // check if user is logged
49-
// if (repository.credentials.get() == null) return
50-
//
51-
// vault.saveVaultExpiration(this)
52-
// }
53-
//
54-
// /** Called from [LibrePassNavigation]. */
55-
// fun onResume(navController: NavController) {
56-
// // check if user is logged
57-
// if (repository.credentials.get() == null) return
58-
//
59-
// val expired = vault.handleExpiration(this)
60-
// if (expired) {
61-
// navController.navigate(Unlock) {
62-
// popUpToDestination(Unlock)
63-
// }
64-
// }
65-
// }
61+
override fun onPause() {
62+
super.onPause()
63+
64+
// check if user is logged
65+
if (repository.credentials.get() == null) return
66+
67+
vault.saveVaultExpiration(this)
68+
}
69+
70+
/** Called from [LibrePassNavigation]. */
71+
fun onResume(navController: NavController) {
72+
// check if user is logged
73+
if (repository.credentials.get() == null) return
74+
75+
val expired = vault.handleExpiration(this)
76+
if (expired) {
77+
navController.navigate(Unlock) {
78+
popUpToDestination(Unlock)
79+
}
80+
}
81+
}
6682
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package dev.medzik.librepass.android.ui
2+
3+
import androidx.annotation.StringRes
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.fillMaxSize
6+
import androidx.compose.foundation.layout.imePadding
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.material3.Scaffold
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.runtime.LaunchedEffect
11+
import androidx.compose.runtime.getValue
12+
import androidx.compose.runtime.remember
13+
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.platform.LocalContext
15+
import androidx.compose.ui.res.stringResource
16+
import androidx.compose.ui.unit.dp
17+
import androidx.hilt.navigation.compose.hiltViewModel
18+
import androidx.lifecycle.Lifecycle
19+
import androidx.lifecycle.compose.LocalLifecycleOwner
20+
import androidx.lifecycle.compose.currentStateAsState
21+
import androidx.navigation.NavController
22+
import androidx.navigation.compose.NavHost
23+
import androidx.navigation.compose.composable
24+
import androidx.navigation.compose.rememberNavController
25+
import dev.medzik.android.compose.icons.TopAppBarBackIcon
26+
import dev.medzik.android.compose.navigation.NavigationAnimations
27+
import dev.medzik.librepass.android.MainActivity
28+
import dev.medzik.librepass.android.common.LibrePassViewModel
29+
import dev.medzik.librepass.android.ui.components.TopBar
30+
import dev.medzik.librepass.android.ui.screens.Welcome
31+
import dev.medzik.librepass.android.ui.screens.WelcomeScreen
32+
import dev.medzik.librepass.android.ui.screens.auth.Unlock
33+
import dev.medzik.librepass.android.ui.screens.auth.authNavigation
34+
import dev.medzik.librepass.android.ui.screens.settings.settingsNavigation
35+
import dev.medzik.librepass.android.ui.screens.vault.Vault
36+
import dev.medzik.librepass.android.ui.screens.vault.vaultNavigation
37+
38+
@Composable
39+
fun LibrePassNavigation(viewModel: LibrePassViewModel = hiltViewModel()) {
40+
val context = LocalContext.current
41+
val navController = rememberNavController()
42+
43+
// Lifecycle events handler.
44+
// This calls the `onResume` function from MainActivity when the application is resumed.
45+
// This is used to lock the vault after X minutes of application sleep in memory.
46+
val lifecycleOwner = LocalLifecycleOwner.current
47+
val lifecycleState by lifecycleOwner.lifecycle.currentStateAsState()
48+
LaunchedEffect(lifecycleState) {
49+
when (lifecycleState) {
50+
// when the application was resumed
51+
Lifecycle.State.RESUMED -> {
52+
// calls the `onResume` function from MainActivity
53+
(context as MainActivity).onResume(navController)
54+
}
55+
// ignore any other lifecycle state
56+
else -> {}
57+
}
58+
}
59+
60+
fun getStartRoute(): Any {
61+
// if a user is not logged in, show welcome screen
62+
viewModel.credentialRepository.get() ?: return Welcome
63+
64+
// if user secrets are not set, show unlock screen
65+
if (viewModel.vault.aesKey.isEmpty())
66+
return Unlock
67+
68+
// else where the user secrets are set, show vault screen
69+
return Vault
70+
}
71+
72+
NavHost(
73+
navController,
74+
startDestination = remember { getStartRoute() },
75+
modifier = Modifier.imePadding(),
76+
enterTransition = {
77+
NavigationAnimations.enterTransition()
78+
},
79+
exitTransition = {
80+
NavigationAnimations.exitTransition()
81+
},
82+
popEnterTransition = {
83+
NavigationAnimations.popEnterTransition()
84+
},
85+
popExitTransition = {
86+
NavigationAnimations.popExitTransition()
87+
}
88+
) {
89+
composable<Welcome> {
90+
WelcomeScreen(navController)
91+
}
92+
93+
authNavigation(navController)
94+
95+
vaultNavigation(navController)
96+
97+
settingsNavigation(navController)
98+
}
99+
}
100+
101+
@Composable
102+
fun DefaultScaffold(
103+
topBar: @Composable () -> Unit = {},
104+
floatingActionButton: @Composable () -> Unit = {},
105+
horizontalPadding: Boolean = true,
106+
composable: @Composable () -> Unit
107+
) {
108+
Scaffold(
109+
topBar = { topBar() },
110+
floatingActionButton = { floatingActionButton() }
111+
) { innerPadding ->
112+
Column(
113+
modifier = Modifier
114+
.fillMaxSize()
115+
.padding(innerPadding)
116+
.padding(horizontal = if (horizontalPadding) 16.dp else 0.dp)
117+
) {
118+
composable()
119+
}
120+
}
121+
}
122+
123+
@Composable
124+
fun TopBarWithBack(@StringRes title: Int, navController: NavController) {
125+
TopBar(
126+
title = stringResource(title),
127+
navigationIcon = { TopAppBarBackIcon(navController) }
128+
)
129+
}

0 commit comments

Comments
 (0)