diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/dialogs/RestoreKeyPassBackupDialog.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/dialogs/RestoreKeyPassBackupDialog.kt index abe9210a..9e4d63fa 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/dialogs/RestoreKeyPassBackupDialog.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/dialogs/RestoreKeyPassBackupDialog.kt @@ -20,6 +20,7 @@ import com.yogeshpaliyal.common.dbhelper.restoreBackup import com.yogeshpaliyal.common.utils.BACKUP_KEY_LENGTH import com.yogeshpaliyal.keypass.R import com.yogeshpaliyal.keypass.ui.redux.actions.Action +import com.yogeshpaliyal.keypass.ui.redux.actions.BatchActions import com.yogeshpaliyal.keypass.ui.redux.actions.RestoreAccountsAction import com.yogeshpaliyal.keypass.ui.redux.actions.ToastAction import com.yogeshpaliyal.keypass.ui.redux.actions.UpdateDialogAction @@ -68,9 +69,13 @@ fun RestoreKeyPassBackupDialog( restoreBackup(keyphrase, context.contentResolver, selectedFile) if (result != null) { - dispatchAction(RestoreAccountsAction(result)) - dispatchAction(UpdateDialogAction(null)) - dispatchAction(ToastAction(R.string.backup_restored)) + dispatchAction( + BatchActions( + RestoreAccountsAction(result), + UpdateDialogAction(null), + ToastAction(R.string.backup_restored) + ) + ) } else { dispatchAction(ToastAction(R.string.invalid_keyphrase)) } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/passwordHint/PasswordHintScreen.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/passwordHint/PasswordHintScreen.kt index a2d50843..8ed4cf92 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/passwordHint/PasswordHintScreen.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/passwordHint/PasswordHintScreen.kt @@ -24,6 +24,7 @@ import com.yogeshpaliyal.keypass.ui.commonComponents.DefaultBottomAppBar import com.yogeshpaliyal.keypass.ui.commonComponents.KeyPassInputField import com.yogeshpaliyal.keypass.ui.nav.LocalUserSettings import com.yogeshpaliyal.keypass.ui.redux.actions.Action +import com.yogeshpaliyal.keypass.ui.redux.actions.BatchActions import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction import com.yogeshpaliyal.keypass.ui.redux.actions.ToastAction import kotlinx.coroutines.launch @@ -54,8 +55,7 @@ fun PasswordHintScreen() { Button(modifier = Modifier.fillMaxWidth(1f), onClick = { coroutineScope.launch { context.setPasswordHint(passwordHint) - dispatchAction(ToastAction(R.string.hint_change_success)) - dispatchAction(GoBackAction) + dispatchAction(BatchActions(GoBackAction, ToastAction(R.string.hint_change_success))) } }) { Text(text = stringResource(id = R.string.change_app_hint)) @@ -64,8 +64,7 @@ fun PasswordHintScreen() { OutlinedButton(modifier = Modifier.fillMaxWidth(1f), onClick = { coroutineScope.launch { context.setPasswordHint(null) - dispatchAction(ToastAction(R.string.hint_removed_success)) - dispatchAction(GoBackAction) + dispatchAction(BatchActions(GoBackAction, ToastAction(R.string.hint_removed_success))) } }) { Text(text = stringResource(id = R.string.remove_app_hint)) diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/KeyPassRedux.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/KeyPassRedux.kt index 56c01d9c..16da233f 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/KeyPassRedux.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/KeyPassRedux.kt @@ -1,22 +1,16 @@ package com.yogeshpaliyal.keypass.ui.redux -import android.content.ClipData -import android.content.ClipboardManager -import android.widget.Toast -import androidx.core.content.ContextCompat -import com.yogeshpaliyal.keypass.R +import com.yogeshpaliyal.keypass.ui.redux.actions.BatchActions import com.yogeshpaliyal.keypass.ui.redux.actions.BottomSheetAction -import com.yogeshpaliyal.keypass.ui.redux.actions.CopyToClipboard import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction import com.yogeshpaliyal.keypass.ui.redux.actions.NavigationAction import com.yogeshpaliyal.keypass.ui.redux.actions.RestoreAccountsAction import com.yogeshpaliyal.keypass.ui.redux.actions.StateUpdateAction -import com.yogeshpaliyal.keypass.ui.redux.actions.ToastAction -import com.yogeshpaliyal.keypass.ui.redux.actions.ToastActionStr import com.yogeshpaliyal.keypass.ui.redux.actions.UpdateContextAction import com.yogeshpaliyal.keypass.ui.redux.actions.UpdateDialogAction import com.yogeshpaliyal.keypass.ui.redux.actions.UpdateViewModalAction import com.yogeshpaliyal.keypass.ui.redux.middlewares.intentNavigationMiddleware +import com.yogeshpaliyal.keypass.ui.redux.middlewares.utilityMiddleware import com.yogeshpaliyal.keypass.ui.redux.states.BottomSheetState import com.yogeshpaliyal.keypass.ui.redux.states.KeyPassState import com.yogeshpaliyal.keypass.ui.redux.states.ScreenState @@ -32,7 +26,17 @@ object KeyPassRedux { fun getLastScreen() = arrPages.lastOrNull() private val reducer: Reducer = { state, action -> - when (action) { + if (action is BatchActions) { + action.actions.fold(state) { acc, act -> + handleAction(act, acc) + } + } else { + handleAction(action, state) + } + } + + private fun handleAction(action: Any, state: KeyPassState): KeyPassState { + return when (action) { is NavigationAction -> { if (action.clearBackStack) { arrPages.clear() @@ -49,43 +53,10 @@ object KeyPassRedux { state.copy(currentScreen = action.state) } - is CopyToClipboard -> { - state.context?.let { - val clipboard = ContextCompat.getSystemService( - it, - ClipboardManager::class.java - ) - val clip = ClipData.newPlainText("KeyPass", action.password) - clipboard?.setPrimaryClip(clip) - - Toast.makeText( - it, - R.string.copied_to_clipboard, - Toast.LENGTH_SHORT - ) - .show() - } - state - } - is UpdateContextAction -> { state.copy(context = action.context) } - is ToastAction -> { - state.context?.let { - Toast.makeText(it, action.text, Toast.LENGTH_SHORT).show() - } - state - } - - is ToastActionStr -> { - state.context?.let { - Toast.makeText(it, action.text, Toast.LENGTH_SHORT).show() - } - state - } - is GoBackAction -> { val lastItem = arrPages.removeLastOrNull() if (lastItem != null) { @@ -104,6 +75,7 @@ object KeyPassRedux { ) ) } + is UpdateDialogAction -> { state.copy(dialog = action.dialogState) } @@ -125,6 +97,6 @@ object KeyPassRedux { createStore( reducer, generateDefaultState(), - applyMiddleware(intentNavigationMiddleware) + applyMiddleware(utilityMiddleware, intentNavigationMiddleware) ) } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/Action.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/Action.kt index e6b162e9..b4613b54 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/Action.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/Action.kt @@ -8,12 +8,45 @@ import com.yogeshpaliyal.keypass.ui.redux.states.ScreenState sealed interface Action +/** + * Batch Multiples Actions to send to ingest in one go + */ +class BatchActions(vararg val actions: Action) : Action + +/** + * Used to update context value in redux store + */ class UpdateContextAction(val context: Context?) : Action + +/** + * Used to update ViewModal in redux store + */ class UpdateViewModalAction(val viewModal: DashboardViewModel?) : Action +/** + * Used to navigate from 1 state to another + * @param state: ScreenState New State where to navigate + * @param clearBackStack: Boolean Clear BackStack or not + */ data class NavigationAction(val state: ScreenState, val clearBackStack: Boolean = false) : Action +/** + * Used to send Accounts list which we want to restore + */ data class RestoreAccountsAction(val accounts: List) : Action +/** + * Used to update Screen State in redux store + */ data class StateUpdateAction(val state: ScreenState) : Action + +/** + * used to update dialog state of the app + * @param dialogState: DialogState? New Dialog State or send null to dismiss the dialog + */ data class UpdateDialogAction(val dialogState: DialogState? = null) : Action + +/** + * Used to go back to previous screen + */ +object GoBackAction : Action diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/BottomSheetAction.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/BottomSheetAction.kt index b3bb14dc..73757526 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/BottomSheetAction.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/BottomSheetAction.kt @@ -3,6 +3,9 @@ package com.yogeshpaliyal.keypass.ui.redux.actions import android.os.Bundle import com.yogeshpaliyal.keypass.ui.redux.BottomSheetRoutes +/** + * Bottom Sheet action to open bottom sheet for different routes + */ sealed class BottomSheetAction( val route: String, val globalIsBottomSheetOpen: Boolean, diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/IntentNavigation.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/IntentNavigation.kt index 42a65037..8ccb30ae 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/IntentNavigation.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/IntentNavigation.kt @@ -1,7 +1,10 @@ package com.yogeshpaliyal.keypass.ui.redux.actions +/** + * Intent Navigation actions, used to navigate to different activities + * handled in {@link IntentNavigationMiddleware} + */ sealed interface IntentNavigation : Action { object GeneratePassword : IntentNavigation - object BackupActivity : IntentNavigation object ShareApp : IntentNavigation } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/UtilityAction.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/UtilityAction.kt index acbbcd3a..8f9dda2b 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/UtilityAction.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/actions/UtilityAction.kt @@ -1,9 +1,10 @@ package com.yogeshpaliyal.keypass.ui.redux.actions import androidx.annotation.StringRes +import com.yogeshpaliyal.keypass.R -data class ToastAction(@StringRes val text: Int) : Action -data class ToastActionStr(val text: String) : Action -data class CopyToClipboard(val password: String) : Action +interface UtilityAction : Action -object GoBackAction : Action +data class ToastAction(@StringRes val text: Int) : UtilityAction +data class ToastActionStr(val text: String) : UtilityAction +data class CopyToClipboard(val password: String, @StringRes val successMessage: Int = R.string.copied_to_clipboard) : UtilityAction diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/middlewares/IntentNavigationMiddleware.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/middlewares/IntentNavigationMiddleware.kt index 99530576..9ca00385 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/middlewares/IntentNavigationMiddleware.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/middlewares/IntentNavigationMiddleware.kt @@ -4,23 +4,35 @@ import android.content.Intent import com.yogeshpaliyal.keypass.BuildConfig import com.yogeshpaliyal.keypass.R import com.yogeshpaliyal.keypass.ui.generate.GeneratePasswordActivity +import com.yogeshpaliyal.keypass.ui.redux.actions.BatchActions import com.yogeshpaliyal.keypass.ui.redux.actions.IntentNavigation import com.yogeshpaliyal.keypass.ui.redux.states.KeyPassState +import org.reduxkotlin.Store import org.reduxkotlin.middleware +/** + * Middleware to handle intent navigation + */ val intentNavigationMiddleware = middleware { store, next, action -> val state = store.state + if (action is BatchActions) { + action.actions.forEach { + store.handleAction(it, state) + } + } else { + store.handleAction(action, state) + } + next(action) +} + +private fun Store.handleAction(action: Any, state: KeyPassState) { when (action) { is IntentNavigation.GeneratePassword -> { val intent = Intent(state.context, GeneratePasswordActivity::class.java) state.context?.startActivity(intent) } - is IntentNavigation.BackupActivity -> { - // BackupActivity.start(state.context) - } - is IntentNavigation.ShareApp -> { val sendIntent = Intent() sendIntent.action = Intent.ACTION_SEND @@ -37,5 +49,4 @@ val intentNavigationMiddleware = middleware { store, next, action ) } } - next(action) } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/middlewares/UtilityMiddleware.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/middlewares/UtilityMiddleware.kt new file mode 100644 index 00000000..631526cb --- /dev/null +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/middlewares/UtilityMiddleware.kt @@ -0,0 +1,59 @@ +package com.yogeshpaliyal.keypass.ui.redux.middlewares + +import android.content.ClipData +import android.content.ClipboardManager +import android.widget.Toast +import androidx.core.content.ContextCompat +import com.yogeshpaliyal.keypass.ui.redux.actions.BatchActions +import com.yogeshpaliyal.keypass.ui.redux.actions.CopyToClipboard +import com.yogeshpaliyal.keypass.ui.redux.actions.ToastAction +import com.yogeshpaliyal.keypass.ui.redux.actions.ToastActionStr +import com.yogeshpaliyal.keypass.ui.redux.actions.UtilityAction +import com.yogeshpaliyal.keypass.ui.redux.states.KeyPassState +import org.reduxkotlin.Store +import org.reduxkotlin.middleware + +/** + * Middle ware to handle utility functions like copy to clipboard and toast + */ +val utilityMiddleware = middleware { store, next, action -> + val state = store.state + if (action is BatchActions) { + action.actions.forEach { + store.handleAction(it, state) + } + } else { + store.handleAction(action, state) + } + next(action) +} + +private fun Store.handleAction(action: Any, state: KeyPassState) { + if (action is UtilityAction) { + when (action) { + is ToastActionStr -> { + state.context?.let { + Toast.makeText(it, action.text, Toast.LENGTH_SHORT).show() + } + } + + is ToastAction -> { + state.context?.let { + Toast.makeText(it, action.text, Toast.LENGTH_SHORT).show() + } + } + + is CopyToClipboard -> { + state.context?.let { + val clipboard = ContextCompat.getSystemService( + it, + ClipboardManager::class.java + ) + val clip = ClipData.newPlainText("KeyPass", action.password) + clipboard?.setPrimaryClip(clip) + dispatch(ToastAction(action.successMessage)) + } + } + } + } +}