@ -24,13 +24,13 @@ import androidx.compose.runtime.mutableStateOf
@@ -24,13 +24,13 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.pin.PinCodeManager
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.matrix.api.MatrixClient
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@ -44,10 +44,10 @@ class PinUnlockPresenter @Inject constructor(
@@ -44,10 +44,10 @@ class PinUnlockPresenter @Inject constructor(
@Composable
override fun present ( ) : PinUnlockState {
var pinEntry by remember {
//TODO fetch size from db
mutableStateOf ( PinEntry . createEmpty ( LockScreenConfig . PIN _SIZE ) )
val pinEntryState = remember {
mutableStateOf < Async < PinEntry > > ( Async . Uninitialized )
}
val pinEntry by pinEntryState
var remainingAttempts by remember {
mutableStateOf < Async < Int > > ( Async . Uninitialized )
}
@ -62,11 +62,18 @@ class PinUnlockPresenter @Inject constructor(
@@ -62,11 +62,18 @@ class PinUnlockPresenter @Inject constructor(
mutableStateOf < Async < String ? > > ( Async . Uninitialized )
}
LaunchedEffect ( Unit ) {
suspend {
val pinCodeSize = pinCodeManager . getPinCodeSize ( )
PinEntry . createEmpty ( pinCodeSize )
} . runCatchingUpdatingState ( pinEntryState )
}
LaunchedEffect ( pinEntry ) {
if ( pinEntry . isComplete ( ) ) {
val isVerified = pinCodeManager . verifyPinCode ( pinEntry . toText ( ) )
if ( !is Verified ) {
pinEntry = pinEntry . clear ( )
pinEntryState . value = pinEntry . clear ( )
showWrongPinTitle = true
}
}
@ -80,7 +87,7 @@ class PinUnlockPresenter @Inject constructor(
@@ -80,7 +87,7 @@ class PinUnlockPresenter @Inject constructor(
fun handleEvents ( event : PinUnlockEvents ) {
when ( event ) {
is PinUnlockEvents . OnPinKeypadPressed -> {
pinEntry = pinEntry . process ( event . pinKeypadModel )
pinEntryState . value = pinEntry . process ( event . pinKeypadModel )
}
PinUnlockEvents . OnForgetPin -> showSignOutPrompt = true
PinUnlockEvents . ClearSignOutPrompt -> showSignOutPrompt = false
@ -103,17 +110,38 @@ class PinUnlockPresenter @Inject constructor(
@@ -103,17 +110,38 @@ class PinUnlockPresenter @Inject constructor(
)
}
private fun Async < PinEntry > . isComplete ( ) : Boolean {
return dataOrNull ( ) ?. isComplete ( ) . orFalse ( )
}
private fun Async < PinEntry > . toText ( ) : String {
return dataOrNull ( ) ?. toText ( ) ?: " "
}
private fun Async < PinEntry > . clear ( ) : Async < PinEntry > {
return when ( this ) {
is Async . Success -> Async . Success ( data . clear ( ) )
else -> this
}
}
private fun Async < PinEntry > . process ( pinKeypadModel : PinKeypadModel ) : Async < PinEntry > {
return when ( this ) {
is Async . Success -> {
val pinEntry = when ( pinKeypadModel ) {
PinKeypadModel . Back -> data . deleteLast ( )
is PinKeypadModel . Number -> data . addDigit ( pinKeypadModel . number )
PinKeypadModel . Empty -> data
}
Async . Success ( pinEntry )
}
else -> this
}
}
private fun CoroutineScope . signOut ( signOutAction : MutableState < Async < String ? > > ) = launch {
suspend {
matrixClient . logout ( )
} . runCatchingUpdatingState ( signOutAction )
}
private fun PinEntry . process ( pinKeypadModel : PinKeypadModel ) : PinEntry {
return when ( pinKeypadModel ) {
PinKeypadModel . Back -> deleteLast ( )
is PinKeypadModel . Number -> addDigit ( pinKeypadModel . number )
PinKeypadModel . Empty -> this
}
}
}