Fix app lock issue (#958)

* Fix app lock issue

Fixes #954

Add app lock feature when the app is not in the foreground.

* **Settings Fragment**
  - Add a new setting to specify the time duration after which the app will lock when not in the foreground.
  - Update the UI to include this new setting.

* **Dashboard Activity**
  - Implement logic to lock the app when it goes to the background.
  - Use the new setting to determine the time duration after which the app will lock.
  - Add handlers to manage the lock timeout when the app is paused and resumed.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/yogeshpaliyal/KeyPass/issues/954?shareId=XXXX-XXXX-XXXX-XXXX).

* feat: minor improvements

* feat: minor improvements

* feat: spotless fixes
This commit is contained in:
Yogesh Choudhary Paliyal
2024-09-14 19:41:43 +05:30
committed by GitHub
parent c1822fdef9
commit 7082eddef3
5 changed files with 30 additions and 19 deletions

View File

@@ -48,20 +48,17 @@ fun AuthScreen(state: AuthState) {
mutableStateOf<Int?>(null) mutableStateOf<Int?>(null)
} }
val (passwordHint, setPasswordHint) = remember(state) {
mutableStateOf("")
}
BackHandler(state is AuthState.ConfirmPassword) { BackHandler(state is AuthState.ConfirmPassword) {
dispatchAction(NavigationAction(AuthState.CreatePassword, true)) dispatchAction(NavigationAction(AuthState.CreatePassword, true))
} }
LaunchedEffect(key1 = userSettings.keyPassPassword, block = { LaunchedEffect(key1 = userSettings.keyPassPassword, block = {
if (userSettings.isDefault) {
return@LaunchedEffect
}
val mPassword = userSettings.keyPassPassword val mPassword = userSettings.keyPassPassword
if (mPassword == null) { if (mPassword == null) {
dispatchAction(NavigationAction(AuthState.CreatePassword, true)) dispatchAction(NavigationAction(AuthState.CreatePassword, true))
} else {
dispatchAction(NavigationAction(AuthState.Login, true))
} }
}) })
@@ -107,7 +104,7 @@ fun AuthScreen(state: AuthState) {
hint = if (state is AuthState.Login && userSettings.passwordHint != null) userSettings.passwordHint else null hint = if (state is AuthState.Login && userSettings.passwordHint != null) userSettings.passwordHint else null
) )
ButtonBar(state, password, setPasswordError, passwordHint) { ButtonBar(state, password, setPasswordError) {
dispatchAction(it) dispatchAction(it)
} }
} }

View File

@@ -15,9 +15,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import com.yogeshpaliyal.common.utils.setKeyPassPassword import com.yogeshpaliyal.common.utils.setKeyPassPassword
import com.yogeshpaliyal.common.utils.setPasswordHint
import com.yogeshpaliyal.keypass.R import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.ui.nav.LocalUserSettings import com.yogeshpaliyal.keypass.ui.nav.LocalUserSettings
import com.yogeshpaliyal.keypass.ui.redux.KeyPassRedux
import com.yogeshpaliyal.keypass.ui.redux.actions.Action
import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction
import com.yogeshpaliyal.keypass.ui.redux.actions.NavigationAction import com.yogeshpaliyal.keypass.ui.redux.actions.NavigationAction
import com.yogeshpaliyal.keypass.ui.redux.states.AuthState import com.yogeshpaliyal.keypass.ui.redux.states.AuthState
import com.yogeshpaliyal.keypass.ui.redux.states.HomeState import com.yogeshpaliyal.keypass.ui.redux.states.HomeState
@@ -28,8 +30,7 @@ fun ButtonBar(
state: AuthState, state: AuthState,
password: String, password: String,
setPasswordError: (Int?) -> Unit, setPasswordError: (Int?) -> Unit,
passwordHint: String, // New parameter for password hint dispatchAction: (Action) -> Unit
dispatchAction: (NavigationAction) -> Unit
) { ) {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val context = LocalContext.current val context = LocalContext.current
@@ -71,7 +72,6 @@ fun ButtonBar(
if (state.password == password) { if (state.password == password) {
coroutineScope.launch { coroutineScope.launch {
context.setKeyPassPassword(password) context.setKeyPassPassword(password)
context.setPasswordHint(passwordHint) // Save the password hint
dispatchAction(NavigationAction(HomeState(), true)) dispatchAction(NavigationAction(HomeState(), true))
} }
} else { } else {
@@ -83,7 +83,9 @@ fun ButtonBar(
coroutineScope.launch { coroutineScope.launch {
val savedPassword = userSettings.keyPassPassword val savedPassword = userSettings.keyPassPassword
if (savedPassword == password) { if (savedPassword == password) {
dispatchAction(NavigationAction(HomeState(), true)) KeyPassRedux.getLastScreen()?.let {
dispatchAction(GoBackAction)
} ?: dispatchAction(NavigationAction(HomeState(), true))
} else { } else {
setPasswordError(R.string.incorrect_password) setPasswordError(R.string.incorrect_password)
} }

View File

@@ -18,6 +18,8 @@ import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LifecycleEventEffect
import com.yogeshpaliyal.common.data.UserSettings import com.yogeshpaliyal.common.data.UserSettings
import com.yogeshpaliyal.common.utils.getUserSettings import com.yogeshpaliyal.common.utils.getUserSettings
import com.yogeshpaliyal.common.utils.getUserSettingsFlow import com.yogeshpaliyal.common.utils.getUserSettingsFlow
@@ -38,6 +40,7 @@ import com.yogeshpaliyal.keypass.ui.nav.components.KeyPassBottomBar
import com.yogeshpaliyal.keypass.ui.passwordHint.PasswordHintScreen import com.yogeshpaliyal.keypass.ui.passwordHint.PasswordHintScreen
import com.yogeshpaliyal.keypass.ui.redux.KeyPassRedux import com.yogeshpaliyal.keypass.ui.redux.KeyPassRedux
import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction
import com.yogeshpaliyal.keypass.ui.redux.actions.NavigationAction
import com.yogeshpaliyal.keypass.ui.redux.actions.UpdateContextAction import com.yogeshpaliyal.keypass.ui.redux.actions.UpdateContextAction
import com.yogeshpaliyal.keypass.ui.redux.states.AboutState import com.yogeshpaliyal.keypass.ui.redux.states.AboutState
import com.yogeshpaliyal.keypass.ui.redux.states.AccountDetailState import com.yogeshpaliyal.keypass.ui.redux.states.AccountDetailState
@@ -74,7 +77,7 @@ class DashboardComposeActivity : AppCompatActivity() {
} }
setContent { setContent {
val localUserSettings by getUserSettingsFlow().collectAsState(initial = UserSettings()) val localUserSettings by getUserSettingsFlow().collectAsState(initial = UserSettings(true))
CompositionLocalProvider(LocalUserSettings provides localUserSettings) { CompositionLocalProvider(LocalUserSettings provides localUserSettings) {
KeyPassTheme { KeyPassTheme {
@@ -90,15 +93,16 @@ class DashboardComposeActivity : AppCompatActivity() {
val buildConfigVersion = BuildConfig.VERSION_CODE val buildConfigVersion = BuildConfig.VERSION_CODE
val currentAppVersion = userSettings.currentAppVersion val currentAppVersion = userSettings.currentAppVersion
if (buildConfigVersion != currentAppVersion) { if (buildConfigVersion != currentAppVersion) {
applicationContext.setUserSettings(userSettings.copy(lastAppVersion = currentAppVersion, currentAppVersion = buildConfigVersion)) applicationContext.setUserSettings(
userSettings.copy(
lastAppVersion = currentAppVersion,
currentAppVersion = buildConfigVersion
)
)
} }
}) })
} }
} }
override fun onDestroy() {
super.onDestroy()
}
} }
@Composable @Composable
@@ -112,6 +116,11 @@ fun Dashboard() {
dispatch(GoBackAction) dispatch(GoBackAction)
} }
// Call this like any other SideEffect in your composable
LifecycleEventEffect(Lifecycle.Event.ON_PAUSE) {
dispatch(NavigationAction(AuthState.Login))
}
LaunchedEffect(key1 = systemBackPress, block = { LaunchedEffect(key1 = systemBackPress, block = {
if (systemBackPress) { if (systemBackPress) {
(context as? ComponentActivity)?.finishAffinity() (context as? ComponentActivity)?.finishAffinity()
@@ -174,7 +183,7 @@ fun CurrentPage() {
is BackupImporterState -> BackupImporter(state = it) is BackupImporterState -> BackupImporter(state = it)
is AboutState -> AboutScreen() is AboutState -> AboutScreen()
is PasswordGeneratorState -> GeneratePasswordScreen() is PasswordGeneratorState -> GeneratePasswordScreen()
ChangeAppHintState -> PasswordHintScreen() is ChangeAppHintState -> PasswordHintScreen()
} }
} }
} }

View File

@@ -26,6 +26,8 @@ object KeyPassRedux {
private var arrPages = mutableListOf<ScreenState>() private var arrPages = mutableListOf<ScreenState>()
fun getLastScreen() = arrPages.lastOrNull()
private val reducer: Reducer<KeyPassState> = { state, action -> private val reducer: Reducer<KeyPassState> = { state, action ->
when (action) { when (action) {
is NavigationAction -> { is NavigationAction -> {

View File

@@ -8,6 +8,7 @@ const val DEFAULT_PASSWORD_LENGTH = 10f
@Keep @Keep
@Serializable @Serializable
data class UserSettings( data class UserSettings(
val isDefault: Boolean = false,
val keyPassPassword: String? = null, val keyPassPassword: String? = null,
val dbPassword: String? = null, val dbPassword: String? = null,
@Deprecated("Use passwordConfig instead") @Deprecated("Use passwordConfig instead")