Skip to content

Commit

Permalink
Some fixes to compass
Browse files Browse the repository at this point in the history
  • Loading branch information
usmonie committed Oct 25, 2023
1 parent 8334ca8 commit 4b9442a
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ data class NavigationGraph(
fun navigateTo(screenId: String, params: Map<String, String>?, extras: Extra? ): Boolean {
val screenBuilder = routes[screenId]
if (screenBuilder != null && canNavigateTo(screenId)) {
backStack.add(NavigationEntry(screenBuilder.build(params, extra), params, extras))
backStack.add(NavigationEntry(screenBuilder.build(params, extras), params, extras))
updateCurrentScreen()
return true
}
Expand All @@ -42,7 +42,7 @@ data class NavigationGraph(
fun navigateBack(): Boolean {
if (backStack.size > 1) {
backStack.removeLast()
currentScreen.value = backStack.last()
updateCurrentScreen()
return true
}
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.runtime.Composable

public abstract class Screen {
abstract class Screen {

val enterTransition: EnterTransition = slideInHorizontally() + fadeIn()
val exitTransition: ExitTransition = slideOutHorizontally() + fadeOut()
open val enterTransition: EnterTransition = slideInHorizontally() + fadeIn()
open val exitTransition: ExitTransition = slideOutHorizontally() + fadeOut()

abstract val id: String

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,46 @@ internal abstract class BasePasscodeViewModel(
private val enteredPasscode: SnapshotStateList<Int>
get() = state.value.enteredPasscode

fun addNumber(number: Int) {
handleAction(PasscodeScreenAction.EnterNumber(number))
}
fun backspace() {
handleAction(PasscodeScreenAction.Backspace)
}

override fun PasscodeScreenState.reduce(event: PasscodeScreenEvent): PasscodeScreenState {
return when (event) {
is PasscodeScreenEvent.EnterNumber -> copy(enteredPasscode = enteredPasscode.apply { add(event.number) })
is PasscodeScreenEvent.EnterNumber -> this.apply { enteredPasscode.add(event.number) }
PasscodeScreenEvent.DeletePasscode -> copy(enteredPasscode = enteredPasscode.apply { removeLastOrNull() })
PasscodeScreenEvent.NonEqualsPasscodes -> copy(contentState = ContentState.Error(PasscodeScreenError.InvalidPasscode))
PasscodeScreenEvent.StartBiometricAuthentication -> onStartBiometricAuth()
is PasscodeScreenEvent.Success -> onSuccess(event.passcode)
}
}


override suspend fun processAction(action: PasscodeScreenAction): PasscodeScreenEvent {
return when (action) {
PasscodeScreenAction.DeletePasscode -> PasscodeScreenEvent.DeletePasscode
PasscodeScreenAction.Backspace -> PasscodeScreenEvent.DeletePasscode
PasscodeScreenAction.EnableBiometricAuth -> PasscodeScreenEvent.StartBiometricAuthentication
is PasscodeScreenAction.EnterNumber -> enterNumber(action.number)
}
}

override fun handleEvent(event: PasscodeScreenEvent): PasscodeScreenEffect? {
return when (event) {
is PasscodeScreenEvent.Success -> PasscodeScreenEffect.AuthSuccess()
is PasscodeScreenEvent.EnterNumber -> checkPasscode(enteredPasscode)
PasscodeScreenEvent.StartBiometricAuthentication -> PasscodeScreenEffect.StartBiometricAuth()
else -> null
}
}

protected abstract fun checkPasscode(passcode: List<Int>): PasscodeScreenEvent
protected abstract fun checkPasscode(passcode: List<Int>): PasscodeScreenEffect?
protected abstract fun PasscodeScreenState.onSuccess(passcode: List<Int>): PasscodeScreenState
protected abstract fun PasscodeScreenState.onStartBiometricAuth(): PasscodeScreenState

private fun enterNumber(number: Int): PasscodeScreenEvent {
val passcode = enteredPasscode
return when {
passcode.size < MAX_PASSCODE_SIZE -> PasscodeScreenEvent.EnterNumber(number)
passcode.size == MAX_PASSCODE_SIZE -> checkPasscode(passcode)
else -> PasscodeScreenEvent.EnterNumber(number)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package wtf.speech.feature.passcode.ui

import wtf.speech.compass.core.NavigationGraph
import wtf.speech.compass.core.Route
import wtf.speech.feature.passcode.ui.confirm.ConfirmPasscodeScreen
import wtf.speech.feature.passcode.ui.create.CreatePasscodeScreen
import wtf.speech.feature.passcode.ui.enter.EnterPasscodeScreen

public object PasscodeGraphs {
object PasscodeGraphs {

public const val CREATE_PASSCODE_GRAPH_ID = "CreatePasscodeGraph"
public const val ENTER_PASSCODE_GRAPH_ID = "EnterPasscodeGraph"
const val CREATE_PASSCODE_GRAPH_ID = "CreatePasscodeGraph"
const val ENTER_PASSCODE_GRAPH_ID = "EnterPasscodeGraph"

val createPasscodeGraph = NavigationGraph(
id = CREATE_PASSCODE_GRAPH_ID,
initialScreen = CreatePasscodeScreen.Builder,
paths = mapOf(CreatePasscodeScreen.ID to setOf(EnterPasscodeScreen.ID))
)
).apply {
register(Route(ConfirmPasscodeScreen.ID, ConfirmPasscodeScreen.Builder))
}

val enterPasscodeGraph = NavigationGraph(
id = ENTER_PASSCODE_GRAPH_ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ internal data class PasscodeScreenState(

internal sealed class PasscodeScreenEvent : ScreenEvent {
data class EnterNumber(val number: Int) : PasscodeScreenEvent()
data class Success(val passcode: List<Int>) : PasscodeScreenEvent()
data object NonEqualsPasscodes : PasscodeScreenEvent()
data object DeletePasscode : PasscodeScreenEvent()
data object StartBiometricAuthentication : PasscodeScreenEvent()
}

internal sealed class PasscodeScreenAction : ScreenAction {
data class EnterNumber(val number: Int) : PasscodeScreenAction()
data object DeletePasscode : PasscodeScreenAction()
data object Backspace : PasscodeScreenAction()
data object EnableBiometricAuth : PasscodeScreenAction()
}

internal sealed class PasscodeScreenEffect : ScreenEffect {
class AuthSuccess : PasscodeScreenEffect()
data class AuthSuccess(val passcode: List<Int>) : PasscodeScreenEffect()
class WrongPasscode : PasscodeScreenEffect()
class StartBiometricAuth : PasscodeScreenEffect()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.snapshots.SnapshotStateList
import kotlinx.coroutines.delay
import wtf.speech.compass.core.Extra
import wtf.speech.compass.core.LocalRouteManager
import wtf.speech.compass.core.Screen
import wtf.speech.compass.core.ScreenBuilder
import wtf.speech.core.ui.ContentState
Expand All @@ -30,14 +30,14 @@ class ConfirmPasscodeScreen private constructor(private val viewModel: ConfirmPa
}

PasscodeContent(
onPasscodeEntered = passcode::add,
title = "Create Passcode",
onDeletePressed = passcode::removeLastOrNull,
onPasscodeEntered = viewModel::addNumber,
title = "Confirm Passcode",
onDeletePressed = viewModel::backspace,
passcodeScreenState = state
)
}

public data class ConfirmPasscodeExtra(val passcode: List<Int>) : Extra {
public data class ConfirmPasscodeExtra(val passcode: SnapshotStateList<Int>) : Extra {
override val key: String = KEY
override val data: Any = passcode

Expand All @@ -46,13 +46,13 @@ class ConfirmPasscodeScreen private constructor(private val viewModel: ConfirmPa
}
}

public companion object Builder : ScreenBuilder {
companion object Builder : ScreenBuilder {
const val ID = "ConfirmPasscode"
override val id: String
get() = ID

override fun build(params: Map<String, String>?, extra: Extra?): Screen {
val passcode = extra?.data as? ConfirmPasscodeExtra ?: throw IllegalArgumentException("Illegal arguments passed: $extra")
val passcode = (extra as? ConfirmPasscodeExtra) ?: throw IllegalArgumentException("Illegal arguments passed: $extra")
val checkPasscodeUseCase = CheckPasscodesEqualsUseCase()
return ConfirmPasscodeScreen(ConfirmPasscodeViewModel(passcode, checkPasscodeUseCase))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package wtf.speech.feature.passcode.ui.confirm

import wtf.speech.core.domain.usecases.UseCase
import wtf.speech.feature.passcode.ui.BasePasscodeViewModel
import wtf.speech.feature.passcode.ui.PasscodeScreenEvent
import wtf.speech.feature.passcode.ui.PasscodeScreenEffect
import wtf.speech.feature.passcode.ui.PasscodeScreenState
import wtf.speech.features.passcode.domain.usecase.CheckPasscodesEqualsUseCase

Expand All @@ -11,13 +11,12 @@ internal class ConfirmPasscodeViewModel(
private val checkPasscodeUseCase: UseCase<CheckPasscodesEqualsUseCase.Params, Boolean>
) : BasePasscodeViewModel(PasscodeScreenState()) {

override fun checkPasscode(passcode: List<Int>): PasscodeScreenEvent {
override fun checkPasscode(passcode: List<Int>): PasscodeScreenEffect? {
return checkPasscodeUseCase(CheckPasscodesEqualsUseCase.Params(extras.passcode, passcode))
.let { isEquals ->
if (isEquals) {
PasscodeScreenEvent.Success(passcode)
} else {
PasscodeScreenEvent.NonEqualsPasscodes
when {
isEquals -> PasscodeScreenEffect.AuthSuccess(passcode)
else -> null
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class CreatePasscodeScreen private constructor(private val viewModel: CreatePass
val effect by viewModel.effect.collectAsState(null)
val passcode = state.enteredPasscode

LaunchedEffect(state) {
LaunchedEffect(state.contentState) {
when (state.contentState) {
is ContentState.Error<*, *> -> {
delay(ERROR_ANIMATION_DELAY)
Expand All @@ -40,20 +40,20 @@ class CreatePasscodeScreen private constructor(private val viewModel: CreatePass

LaunchedEffect(effect) {
when (effect) {
is PasscodeScreenEffect.AuthSuccess -> routeManager.navigateTo(
ConfirmPasscodeScreen.ID,
extras = ConfirmPasscodeScreen.ConfirmPasscodeExtra(passcode)
)

is PasscodeScreenEffect.StartBiometricAuth -> Unit
null -> Unit
is PasscodeScreenEffect.AuthSuccess -> {
routeManager.navigateTo(
ConfirmPasscodeScreen.ID,
extras = ConfirmPasscodeScreen.ConfirmPasscodeExtra(passcode)
)
}
else -> Unit
}
}

PasscodeContent(
onPasscodeEntered = passcode::add,
onPasscodeEntered = viewModel::addNumber,
title = "Create Passcode",
onDeletePressed = passcode::removeLastOrNull,
onDeletePressed = viewModel::backspace,
passcodeScreenState = state
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ package wtf.speech.feature.passcode.ui.create

import wtf.speech.core.ui.ContentState
import wtf.speech.feature.passcode.ui.BasePasscodeViewModel
import wtf.speech.feature.passcode.ui.PasscodeScreenEvent
import wtf.speech.feature.passcode.ui.MAX_PASSCODE_SIZE
import wtf.speech.feature.passcode.ui.PasscodeScreenEffect
import wtf.speech.feature.passcode.ui.PasscodeScreenState

internal class CreatePasscodeViewModel(state: PasscodeScreenState = PasscodeScreenState()) : BasePasscodeViewModel(state) {

override fun checkPasscode(passcode: List<Int>): PasscodeScreenEvent {
return PasscodeScreenEvent.Success(passcode)
override fun checkPasscode(passcode: List<Int>): PasscodeScreenEffect? {
return if (passcode.size == MAX_PASSCODE_SIZE) {
PasscodeScreenEffect.AuthSuccess(passcode)
} else {
null
}
}

override fun PasscodeScreenState.onSuccess(passcode: List<Int>): PasscodeScreenState {
return copy(contentState = ContentState.Success(Unit))
}

override fun PasscodeScreenState.onStartBiometricAuth() = this
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ class EnterPasscodeScreen private constructor(private val viewModel: EnterPassco

Column {
PasscodeContent(
onPasscodeEntered = passcode::add,
onPasscodeEntered = viewModel::addNumber,
title = "Enter Passcode",
onDeletePressed = passcode::removeLastOrNull,
onDeletePressed = viewModel::backspace,
passcodeScreenState = state
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ package wtf.speech.feature.passcode.ui.enter

import wtf.speech.core.domain.usecases.UseCase
import wtf.speech.feature.passcode.ui.BasePasscodeViewModel
import wtf.speech.feature.passcode.ui.PasscodeScreenEvent
import wtf.speech.feature.passcode.ui.PasscodeScreenEffect
import wtf.speech.feature.passcode.ui.PasscodeScreenState
import wtf.speech.features.passcode.domain.usecase.CheckPasscodesEqualsUseCase

internal class EnterPasscodeViewModel(
private val checkPasscodeUseCase: UseCase<CheckPasscodesEqualsUseCase.Params, Boolean>
) : BasePasscodeViewModel(PasscodeScreenState()) {

override fun checkPasscode(passcode: List<Int>): PasscodeScreenEvent {
override fun checkPasscode(passcode: List<Int>): PasscodeScreenEffect {
return checkPasscodeUseCase(CheckPasscodesEqualsUseCase.Params(listOf(1,1,1,1,1,1), passcode))
.let { isEquals ->
if (isEquals) {
PasscodeScreenEvent.Success(passcode)
PasscodeScreenEffect.AuthSuccess(passcode)
} else {
PasscodeScreenEvent.NonEqualsPasscodes
PasscodeScreenEffect.WrongPasscode()
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion shared/src/androidMain/kotlin/main.android.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import wtf.speech.compass.core.RouteManager
import wtf.speech.features.home.ui.HomeScreen
import wtf.speech.features.home.ui.HomeViewModel
import wtf.speech.vault.shared.App

@Composable
fun MainView() = App()
fun MainView(routeManager: RouteManager) = App(routeManager)

/**
* A function for displaying the preview version of the screen with cryptocurrencies.
Expand Down
8 changes: 3 additions & 5 deletions shared/src/commonMain/kotlin/wtf/speech/vault/shared/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import wtf.speech.compass.core.LocalRouteManager
import wtf.speech.compass.core.NavigationHost
import wtf.speech.compass.core.rememberRouteManager
import wtf.speech.compass.core.RouteManager
import wtf.speech.core.design.themes.SpeechTheme
import wtf.speech.feature.passcode.ui.PasscodeGraphs

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun App() {
CompositionLocalProvider(LocalRouteManager provides rememberRouteManager(PasscodeGraphs.createPasscodeGraph)) {
val routeManager = LocalRouteManager.current
fun App(routeManager: RouteManager) {
CompositionLocalProvider(LocalRouteManager provides routeManager) {
SpeechTheme {
Scaffold {
NavigationHost(routeManager)
Expand Down
2 changes: 2 additions & 0 deletions vaultAndroid/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,6 @@ dependencies {
implementation(dependencyNotation = libs.compose.activity)
implementation(dependencyNotation = libs.appCompat)
implementation(dependencyNotation = libs.coreKtx)

implementation(projects.features.passcode.ui)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package wtf.speech.vault.app
import MainView
import android.os.Bundle
import android.util.Log
import androidx.activity.addCallback
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import wtf.speech.compass.core.rememberRouteManager
import wtf.speech.core.cryptokt.CryptoApi
import wtf.speech.feature.passcode.ui.PasscodeGraphs

class MainActivity : AppCompatActivity() {

Expand All @@ -16,8 +19,14 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val backPressedDispatcher = onBackPressedDispatcher
setContent {
MainView()
val routeManager = rememberRouteManager(PasscodeGraphs.createPasscodeGraph)
backPressedDispatcher.addCallback {
if (!routeManager.navigateBack()) super.onBackPressed()
}

MainView(routeManager)
}

val creator = CryptoApi()
Expand Down

0 comments on commit 4b9442a

Please sign in to comment.