Lockscreen: renaming
This commit is contained in:
parent
11adae6cd0
commit
fbced52fee
23 changed files with 135 additions and 141 deletions
|
|
@ -251,8 +251,7 @@ koverMerged {
|
||||||
// Some options can't be tested at the moment
|
// Some options can't be tested at the moment
|
||||||
excludes += "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*"
|
excludes += "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*"
|
||||||
// Temporary until we have actually something to test.
|
// Temporary until we have actually something to test.
|
||||||
excludes += "io.element.android.features.lockscreen.impl.auth.PinAuthenticationPresenter"
|
excludes += "io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter$*"
|
||||||
excludes += "io.element.android.features.lockscreen.impl.auth.PinAuthenticationPresenter$*"
|
|
||||||
}
|
}
|
||||||
bound {
|
bound {
|
||||||
minValue = 85
|
minValue = 85
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ import com.bumble.appyx.navmodel.backstack.BackStack
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.features.lockscreen.impl.auth.PinAuthenticationNode
|
import io.element.android.features.lockscreen.impl.setup.SetupPinNode
|
||||||
import io.element.android.features.lockscreen.impl.create.CreatePinNode
|
import io.element.android.features.lockscreen.impl.unlock.PinUnlockNode
|
||||||
import io.element.android.libraries.architecture.BackstackNode
|
import io.element.android.libraries.architecture.BackstackNode
|
||||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
|
@ -41,7 +41,7 @@ class LockScreenFlowNode @AssistedInject constructor(
|
||||||
@Assisted plugins: List<Plugin>,
|
@Assisted plugins: List<Plugin>,
|
||||||
) : BackstackNode<LockScreenFlowNode.NavTarget>(
|
) : BackstackNode<LockScreenFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
initialElement = NavTarget.Auth,
|
initialElement = NavTarget.Unlock,
|
||||||
savedStateMap = buildContext.savedStateMap,
|
savedStateMap = buildContext.savedStateMap,
|
||||||
),
|
),
|
||||||
buildContext = buildContext,
|
buildContext = buildContext,
|
||||||
|
|
@ -50,19 +50,19 @@ class LockScreenFlowNode @AssistedInject constructor(
|
||||||
|
|
||||||
sealed interface NavTarget : Parcelable {
|
sealed interface NavTarget : Parcelable {
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object Auth : NavTarget
|
data object Unlock : NavTarget
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object Create : NavTarget
|
data object Setup : NavTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||||
return when (navTarget) {
|
return when (navTarget) {
|
||||||
NavTarget.Auth -> {
|
NavTarget.Unlock -> {
|
||||||
createNode<PinAuthenticationNode>(buildContext)
|
createNode<PinUnlockNode>(buildContext)
|
||||||
}
|
}
|
||||||
NavTarget.Create -> {
|
NavTarget.Setup -> {
|
||||||
createNode<CreatePinNode>(buildContext)
|
createNode<SetupPinNode>(buildContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class DefaultPinCodeManager @Inject constructor(
|
||||||
return pinCodeStore.hasPinCode()
|
return pinCodeStore.hasPinCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createPinCode(pinCode: String) {
|
override suspend fun SetupPinCode(pinCode: String) {
|
||||||
val secretKey = secretKeyProvider.getOrCreateKey(SECRET_KEY_ALIAS)
|
val secretKey = secretKeyProvider.getOrCreateKey(SECRET_KEY_ALIAS)
|
||||||
val encryptedPinCode = encryptionDecryptionService.encrypt(secretKey, pinCode.toByteArray()).toBase64()
|
val encryptedPinCode = encryptionDecryptionService.encrypt(secretKey, pinCode.toByteArray()).toBase64()
|
||||||
pinCodeStore.saveEncryptedPinCode(encryptedPinCode)
|
pinCodeStore.saveEncryptedPinCode(encryptedPinCode)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ interface PinCodeManager {
|
||||||
* Creates a new encrypted pin code.
|
* Creates a new encrypted pin code.
|
||||||
* @param pinCode the clear pin code to create
|
* @param pinCode the clear pin code to create
|
||||||
*/
|
*/
|
||||||
suspend fun createPinCode(pinCode: String)
|
suspend fun SetupPinCode(pinCode: String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the pin code is correct.
|
* @return true if the pin code is correct.
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create
|
package io.element.android.features.lockscreen.impl.setup
|
||||||
|
|
||||||
sealed interface CreatePinEvents {
|
sealed interface SetupPinEvents {
|
||||||
data class OnPinEntryChanged(val entryAsText: String) : CreatePinEvents
|
data class OnPinEntryChanged(val entryAsText: String) : SetupPinEvents
|
||||||
data object ClearFailure : CreatePinEvents
|
data object ClearFailure : SetupPinEvents
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create
|
package io.element.android.features.lockscreen.impl.setup
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -27,16 +27,16 @@ import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
|
|
||||||
@ContributesNode(AppScope::class)
|
@ContributesNode(AppScope::class)
|
||||||
class CreatePinNode @AssistedInject constructor(
|
class SetupPinNode @AssistedInject constructor(
|
||||||
@Assisted buildContext: BuildContext,
|
@Assisted buildContext: BuildContext,
|
||||||
@Assisted plugins: List<Plugin>,
|
@Assisted plugins: List<Plugin>,
|
||||||
private val presenter: CreatePinPresenter,
|
private val presenter: SetupPinPresenter,
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
val state = presenter.present()
|
val state = presenter.present()
|
||||||
CreatePinView(
|
SetupPinView(
|
||||||
state = state,
|
state = state,
|
||||||
onBackClicked = { },
|
onBackClicked = { },
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
|
@ -14,29 +14,29 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create
|
package io.element.android.features.lockscreen.impl.setup
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import io.element.android.features.lockscreen.impl.create.model.PinEntry
|
import io.element.android.features.lockscreen.impl.setup.model.PinEntry
|
||||||
import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure
|
import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure
|
||||||
import io.element.android.features.lockscreen.impl.create.validation.PinValidator
|
import io.element.android.features.lockscreen.impl.setup.validation.PinValidator
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.core.meta.BuildMeta
|
import io.element.android.libraries.core.meta.BuildMeta
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val PIN_SIZE = 4
|
private const val PIN_SIZE = 4
|
||||||
|
|
||||||
class CreatePinPresenter @Inject constructor(
|
class SetupPinPresenter @Inject constructor(
|
||||||
private val pinValidator: PinValidator,
|
private val pinValidator: PinValidator,
|
||||||
private val buildMeta: BuildMeta,
|
private val buildMeta: BuildMeta,
|
||||||
) : Presenter<CreatePinState> {
|
) : Presenter<SetupPinState> {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): CreatePinState {
|
override fun present(): SetupPinState {
|
||||||
var choosePinEntry by remember {
|
var choosePinEntry by remember {
|
||||||
mutableStateOf(PinEntry.empty(PIN_SIZE))
|
mutableStateOf(PinEntry.empty(PIN_SIZE))
|
||||||
}
|
}
|
||||||
|
|
@ -46,20 +46,20 @@ class CreatePinPresenter @Inject constructor(
|
||||||
var isConfirmationStep by remember {
|
var isConfirmationStep by remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var createPinFailure by remember {
|
var setupPinFailure by remember {
|
||||||
mutableStateOf<CreatePinFailure?>(null)
|
mutableStateOf<SetupPinFailure?>(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleEvents(event: CreatePinEvents) {
|
fun handleEvents(event: SetupPinEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is CreatePinEvents.OnPinEntryChanged -> {
|
is SetupPinEvents.OnPinEntryChanged -> {
|
||||||
if (isConfirmationStep) {
|
if (isConfirmationStep) {
|
||||||
confirmPinEntry = confirmPinEntry.fillWith(event.entryAsText)
|
confirmPinEntry = confirmPinEntry.fillWith(event.entryAsText)
|
||||||
if (confirmPinEntry.isPinComplete()) {
|
if (confirmPinEntry.isPinComplete()) {
|
||||||
if (confirmPinEntry == choosePinEntry) {
|
if (confirmPinEntry == choosePinEntry) {
|
||||||
//TODO save in db and navigate to next screen
|
//TODO save in db and navigate to next screen
|
||||||
} else {
|
} else {
|
||||||
createPinFailure = CreatePinFailure.PinsDontMatch
|
setupPinFailure = SetupPinFailure.PinsDontMatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -67,35 +67,35 @@ class CreatePinPresenter @Inject constructor(
|
||||||
if (choosePinEntry.isPinComplete()) {
|
if (choosePinEntry.isPinComplete()) {
|
||||||
when (val pinValidationResult = pinValidator.isPinValid(choosePinEntry)) {
|
when (val pinValidationResult = pinValidator.isPinValid(choosePinEntry)) {
|
||||||
is PinValidator.Result.Invalid -> {
|
is PinValidator.Result.Invalid -> {
|
||||||
createPinFailure = pinValidationResult.failure
|
setupPinFailure = pinValidationResult.failure
|
||||||
}
|
}
|
||||||
PinValidator.Result.Valid -> isConfirmationStep = true
|
PinValidator.Result.Valid -> isConfirmationStep = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CreatePinEvents.ClearFailure -> {
|
SetupPinEvents.ClearFailure -> {
|
||||||
when (createPinFailure) {
|
when (setupPinFailure) {
|
||||||
is CreatePinFailure.PinsDontMatch -> {
|
is SetupPinFailure.PinsDontMatch -> {
|
||||||
choosePinEntry = PinEntry.empty(PIN_SIZE)
|
choosePinEntry = PinEntry.empty(PIN_SIZE)
|
||||||
confirmPinEntry = PinEntry.empty(PIN_SIZE)
|
confirmPinEntry = PinEntry.empty(PIN_SIZE)
|
||||||
}
|
}
|
||||||
is CreatePinFailure.PinBlacklisted -> {
|
is SetupPinFailure.PinBlacklisted -> {
|
||||||
choosePinEntry = PinEntry.empty(PIN_SIZE)
|
choosePinEntry = PinEntry.empty(PIN_SIZE)
|
||||||
}
|
}
|
||||||
null -> Unit
|
null -> Unit
|
||||||
}
|
}
|
||||||
isConfirmationStep = false
|
isConfirmationStep = false
|
||||||
createPinFailure = null
|
setupPinFailure = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreatePinState(
|
return SetupPinState(
|
||||||
choosePinEntry = choosePinEntry,
|
choosePinEntry = choosePinEntry,
|
||||||
confirmPinEntry = confirmPinEntry,
|
confirmPinEntry = confirmPinEntry,
|
||||||
isConfirmationStep = isConfirmationStep,
|
isConfirmationStep = isConfirmationStep,
|
||||||
createPinFailure = createPinFailure,
|
SetupPinFailure = setupPinFailure,
|
||||||
appName = buildMeta.applicationName,
|
appName = buildMeta.applicationName,
|
||||||
eventSink = ::handleEvents
|
eventSink = ::handleEvents
|
||||||
)
|
)
|
||||||
|
|
@ -14,18 +14,18 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create
|
package io.element.android.features.lockscreen.impl.setup
|
||||||
|
|
||||||
import io.element.android.features.lockscreen.impl.create.model.PinEntry
|
import io.element.android.features.lockscreen.impl.setup.model.PinEntry
|
||||||
import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure
|
import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure
|
||||||
|
|
||||||
data class CreatePinState(
|
data class SetupPinState(
|
||||||
val choosePinEntry: PinEntry,
|
val choosePinEntry: PinEntry,
|
||||||
val confirmPinEntry: PinEntry,
|
val confirmPinEntry: PinEntry,
|
||||||
val isConfirmationStep: Boolean,
|
val isConfirmationStep: Boolean,
|
||||||
val createPinFailure: CreatePinFailure?,
|
val SetupPinFailure: SetupPinFailure?,
|
||||||
val appName: String,
|
val appName: String,
|
||||||
val eventSink: (CreatePinEvents) -> Unit
|
val eventSink: (SetupPinEvents) -> Unit
|
||||||
) {
|
) {
|
||||||
val pinSize = choosePinEntry.size
|
val pinSize = choosePinEntry.size
|
||||||
val activePinEntry = if (isConfirmationStep) {
|
val activePinEntry = if (isConfirmationStep) {
|
||||||
|
|
@ -14,47 +14,47 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create
|
package io.element.android.features.lockscreen.impl.setup
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.features.lockscreen.impl.create.model.PinEntry
|
import io.element.android.features.lockscreen.impl.setup.model.PinEntry
|
||||||
import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure
|
import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure
|
||||||
|
|
||||||
open class CreatePinStateProvider : PreviewParameterProvider<CreatePinState> {
|
open class SetupPinStateProvider : PreviewParameterProvider<SetupPinState> {
|
||||||
override val values: Sequence<CreatePinState>
|
override val values: Sequence<SetupPinState>
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
aCreatePinState(),
|
aSetupPinState(),
|
||||||
aCreatePinState(
|
aSetupPinState(
|
||||||
choosePinEntry = PinEntry.empty(4).fillWith("12")
|
choosePinEntry = PinEntry.empty(4).fillWith("12")
|
||||||
),
|
),
|
||||||
aCreatePinState(
|
aSetupPinState(
|
||||||
choosePinEntry = PinEntry.empty(4).fillWith("1789"),
|
choosePinEntry = PinEntry.empty(4).fillWith("1789"),
|
||||||
isConfirmationStep = true,
|
isConfirmationStep = true,
|
||||||
),
|
),
|
||||||
aCreatePinState(
|
aSetupPinState(
|
||||||
choosePinEntry = PinEntry.empty(4).fillWith("1789"),
|
choosePinEntry = PinEntry.empty(4).fillWith("1789"),
|
||||||
confirmPinEntry = PinEntry.empty(4).fillWith("1788"),
|
confirmPinEntry = PinEntry.empty(4).fillWith("1788"),
|
||||||
isConfirmationStep = true,
|
isConfirmationStep = true,
|
||||||
creationFailure = CreatePinFailure.PinsDontMatch
|
creationFailure = SetupPinFailure.PinsDontMatch
|
||||||
),
|
),
|
||||||
aCreatePinState(
|
aSetupPinState(
|
||||||
choosePinEntry = PinEntry.empty(4).fillWith("1111"),
|
choosePinEntry = PinEntry.empty(4).fillWith("1111"),
|
||||||
creationFailure = CreatePinFailure.PinBlacklisted
|
creationFailure = SetupPinFailure.PinBlacklisted
|
||||||
),
|
),
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun aCreatePinState(
|
fun aSetupPinState(
|
||||||
choosePinEntry: PinEntry = PinEntry.empty(4),
|
choosePinEntry: PinEntry = PinEntry.empty(4),
|
||||||
confirmPinEntry: PinEntry = PinEntry.empty(4),
|
confirmPinEntry: PinEntry = PinEntry.empty(4),
|
||||||
isConfirmationStep: Boolean = false,
|
isConfirmationStep: Boolean = false,
|
||||||
creationFailure: CreatePinFailure? = null,
|
creationFailure: SetupPinFailure? = null,
|
||||||
) = CreatePinState(
|
) = SetupPinState(
|
||||||
choosePinEntry = choosePinEntry,
|
choosePinEntry = choosePinEntry,
|
||||||
confirmPinEntry = confirmPinEntry,
|
confirmPinEntry = confirmPinEntry,
|
||||||
isConfirmationStep = isConfirmationStep,
|
isConfirmationStep = isConfirmationStep,
|
||||||
createPinFailure = creationFailure,
|
SetupPinFailure = creationFailure,
|
||||||
appName = "Element",
|
appName = "Element",
|
||||||
eventSink = {}
|
eventSink = {}
|
||||||
)
|
)
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create
|
package io.element.android.features.lockscreen.impl.setup
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
|
@ -46,9 +46,9 @@ import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.features.lockscreen.impl.R
|
import io.element.android.features.lockscreen.impl.R
|
||||||
import io.element.android.features.lockscreen.impl.create.model.PinDigit
|
import io.element.android.features.lockscreen.impl.setup.model.PinDigit
|
||||||
import io.element.android.features.lockscreen.impl.create.model.PinEntry
|
import io.element.android.features.lockscreen.impl.setup.model.PinEntry
|
||||||
import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure
|
import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||||
|
|
@ -61,8 +61,8 @@ import io.element.android.libraries.designsystem.theme.pinDigitBg
|
||||||
import io.element.android.libraries.theme.ElementTheme
|
import io.element.android.libraries.theme.ElementTheme
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CreatePinView(
|
fun SetupPinView(
|
||||||
state: CreatePinState,
|
state: SetupPinState,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
|
@ -86,15 +86,15 @@ fun CreatePinView(
|
||||||
.verticalScroll(state = scrollState)
|
.verticalScroll(state = scrollState)
|
||||||
.padding(vertical = 16.dp, horizontal = 20.dp),
|
.padding(vertical = 16.dp, horizontal = 20.dp),
|
||||||
) {
|
) {
|
||||||
CreatePinHeader(state.isConfirmationStep, state.appName)
|
SetupPinHeader(state.isConfirmationStep, state.appName)
|
||||||
CreatePinContent(state)
|
SetupPinContent(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CreatePinHeader(
|
private fun SetupPinHeader(
|
||||||
isValidationStep: Boolean,
|
isValidationStep: Boolean,
|
||||||
appName: String,
|
appName: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|
@ -116,44 +116,44 @@ private fun CreatePinHeader(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CreatePinContent(
|
private fun SetupPinContent(
|
||||||
state: CreatePinState,
|
state: SetupPinState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
PinEntryTextField(
|
PinEntryTextField(
|
||||||
state.activePinEntry,
|
state.activePinEntry,
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
state.eventSink(CreatePinEvents.OnPinEntryChanged(it))
|
state.eventSink(SetupPinEvents.OnPinEntryChanged(it))
|
||||||
},
|
},
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(top = 36.dp)
|
.padding(top = 36.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
)
|
)
|
||||||
if (state.createPinFailure != null) {
|
if (state.SetupPinFailure != null) {
|
||||||
ErrorDialog(
|
ErrorDialog(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
title = state.createPinFailure.title(),
|
title = state.SetupPinFailure.title(),
|
||||||
content = state.createPinFailure.content(),
|
content = state.SetupPinFailure.content(),
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
state.eventSink(CreatePinEvents.ClearFailure)
|
state.eventSink(SetupPinEvents.ClearFailure)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CreatePinFailure.content(): String {
|
private fun SetupPinFailure.content(): String {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
CreatePinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_content)
|
SetupPinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_content)
|
||||||
CreatePinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_content)
|
SetupPinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CreatePinFailure.title(): String {
|
private fun SetupPinFailure.title(): String {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
CreatePinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_title)
|
SetupPinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_title)
|
||||||
CreatePinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_title)
|
SetupPinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,9 +225,9 @@ private fun PinDigitView(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@PreviewsDayNight
|
@PreviewsDayNight
|
||||||
internal fun CreatePinViewPreview(@PreviewParameter(CreatePinStateProvider::class) state: CreatePinState) {
|
internal fun SetupPinViewPreview(@PreviewParameter(SetupPinStateProvider::class) state: SetupPinState) {
|
||||||
ElementPreview {
|
ElementPreview {
|
||||||
CreatePinView(
|
SetupPinView(
|
||||||
state = state,
|
state = state,
|
||||||
onBackClicked = {},
|
onBackClicked = {},
|
||||||
)
|
)
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create.model
|
package io.element.android.features.lockscreen.impl.setup.model
|
||||||
|
|
||||||
sealed interface PinDigit {
|
sealed interface PinDigit {
|
||||||
data object Empty : PinDigit
|
data object Empty : PinDigit
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create.model
|
package io.element.android.features.lockscreen.impl.setup.model
|
||||||
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toPersistentList
|
import kotlinx.collections.immutable.toPersistentList
|
||||||
|
|
@ -14,9 +14,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create.validation
|
package io.element.android.features.lockscreen.impl.setup.validation
|
||||||
|
|
||||||
sealed interface CreatePinFailure {
|
sealed interface SetupPinFailure {
|
||||||
data object PinBlacklisted : CreatePinFailure
|
data object PinBlacklisted : SetupPinFailure
|
||||||
data object PinsDontMatch : CreatePinFailure
|
data object PinsDontMatch : SetupPinFailure
|
||||||
}
|
}
|
||||||
|
|
@ -14,10 +14,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create.validation
|
package io.element.android.features.lockscreen.impl.setup.validation
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import io.element.android.features.lockscreen.impl.create.model.PinEntry
|
import io.element.android.features.lockscreen.impl.setup.model.PinEntry
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class PinValidator @Inject constructor() {
|
class PinValidator @Inject constructor() {
|
||||||
|
|
@ -29,14 +29,14 @@ class PinValidator @Inject constructor() {
|
||||||
|
|
||||||
sealed interface Result {
|
sealed interface Result {
|
||||||
data object Valid : Result
|
data object Valid : Result
|
||||||
data class Invalid(val failure: CreatePinFailure) : Result
|
data class Invalid(val failure: SetupPinFailure) : Result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isPinValid(pinEntry: PinEntry): Result {
|
fun isPinValid(pinEntry: PinEntry): Result {
|
||||||
val pinAsText = pinEntry.toText()
|
val pinAsText = pinEntry.toText()
|
||||||
val isBlacklisted = BLACKLIST.any { it == pinAsText }
|
val isBlacklisted = BLACKLIST.any { it == pinAsText }
|
||||||
return if (isBlacklisted) {
|
return if (isBlacklisted) {
|
||||||
Result.Invalid(CreatePinFailure.PinBlacklisted)
|
Result.Invalid(SetupPinFailure.PinBlacklisted)
|
||||||
} else {
|
} else {
|
||||||
Result.Valid
|
Result.Valid
|
||||||
}
|
}
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.auth
|
package io.element.android.features.lockscreen.impl.unlock
|
||||||
|
|
||||||
sealed interface PinAuthenticationEvents {
|
sealed interface PinUnlockEvents {
|
||||||
data object Unlock : PinAuthenticationEvents
|
data object Unlock : PinUnlockEvents
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.auth
|
package io.element.android.features.lockscreen.impl.unlock
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -27,16 +27,16 @@ import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
|
|
||||||
@ContributesNode(AppScope::class)
|
@ContributesNode(AppScope::class)
|
||||||
class PinAuthenticationNode @AssistedInject constructor(
|
class PinUnlockNode @AssistedInject constructor(
|
||||||
@Assisted buildContext: BuildContext,
|
@Assisted buildContext: BuildContext,
|
||||||
@Assisted plugins: List<Plugin>,
|
@Assisted plugins: List<Plugin>,
|
||||||
private val presenter: PinAuthenticationPresenter,
|
private val presenter: PinUnlockPresenter,
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
val state = presenter.present()
|
val state = presenter.present()
|
||||||
PinAuthenticationView(
|
PinUnlockView(
|
||||||
state = state,
|
state = state,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.auth
|
package io.element.android.features.lockscreen.impl.unlock
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import io.element.android.features.lockscreen.api.LockScreenStateService
|
import io.element.android.features.lockscreen.api.LockScreenStateService
|
||||||
|
|
@ -23,20 +23,20 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class PinAuthenticationPresenter @Inject constructor(
|
class PinUnlockPresenter @Inject constructor(
|
||||||
private val pinStateService: LockScreenStateService,
|
private val pinStateService: LockScreenStateService,
|
||||||
private val coroutineScope: CoroutineScope,
|
private val coroutineScope: CoroutineScope,
|
||||||
) : Presenter<PinAuthenticationState> {
|
) : Presenter<PinUnlockState> {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): PinAuthenticationState {
|
override fun present(): PinUnlockState {
|
||||||
|
|
||||||
fun handleEvents(event: PinAuthenticationEvents) {
|
fun handleEvents(event: PinUnlockEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
PinAuthenticationEvents.Unlock -> coroutineScope.launch { pinStateService.unlock() }
|
PinUnlockEvents.Unlock -> coroutineScope.launch { pinStateService.unlock() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PinAuthenticationState(
|
return PinUnlockState(
|
||||||
eventSink = ::handleEvents
|
eventSink = ::handleEvents
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.auth
|
package io.element.android.features.lockscreen.impl.unlock
|
||||||
|
|
||||||
data class PinAuthenticationState(
|
data class PinUnlockState(
|
||||||
val eventSink: (PinAuthenticationEvents) -> Unit
|
val eventSink: (PinUnlockEvents) -> Unit
|
||||||
)
|
)
|
||||||
|
|
@ -14,17 +14,17 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.auth
|
package io.element.android.features.lockscreen.impl.unlock
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
|
||||||
open class PinAuthenticationStateProvider : PreviewParameterProvider<PinAuthenticationState> {
|
open class PinUnlockStateProvider : PreviewParameterProvider<PinUnlockState> {
|
||||||
override val values: Sequence<PinAuthenticationState>
|
override val values: Sequence<PinUnlockState>
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
aPinAuthenticationState(),
|
aPinUnlockState(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun aPinAuthenticationState() = PinAuthenticationState(
|
fun aPinUnlockState() = PinUnlockState(
|
||||||
eventSink = {}
|
eventSink = {}
|
||||||
)
|
)
|
||||||
|
|
@ -14,23 +14,18 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.auth
|
package io.element.android.features.lockscreen.impl.unlock
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.gestures.Orientation
|
|
||||||
import androidx.compose.foundation.gestures.scrollable
|
|
||||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.heightIn
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Lock
|
import androidx.compose.material.icons.filled.Lock
|
||||||
|
|
@ -41,7 +36,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.features.lockscreen.impl.auth.numpad.PinKeypad
|
import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypad
|
||||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
|
@ -52,13 +47,13 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.theme.ElementTheme
|
import io.element.android.libraries.theme.ElementTheme
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PinAuthenticationView(
|
fun PinUnlockView(
|
||||||
state: PinAuthenticationState,
|
state: PinUnlockState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Surface(modifier) {
|
Surface(modifier) {
|
||||||
HeaderFooterPage(
|
HeaderFooterPage(
|
||||||
header = { PinAuthenticationHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) },
|
header = { PinUnlockHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) },
|
||||||
content = {
|
content = {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -76,12 +71,12 @@ fun PinAuthenticationView(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun PinAuthenticationFooter(state: PinAuthenticationState) {
|
private fun PinUnlockFooter(state: PinUnlockState) {
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = "Unlock",
|
text = "Unlock",
|
||||||
onClick = {
|
onClick = {
|
||||||
state.eventSink(PinAuthenticationEvents.Unlock)
|
state.eventSink(PinUnlockEvents.Unlock)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +111,7 @@ private fun PinDot(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun PinAuthenticationHeader(
|
private fun PinUnlockHeader(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
|
@ -151,9 +146,9 @@ private fun PinAuthenticationHeader(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@PreviewsDayNight
|
@PreviewsDayNight
|
||||||
internal fun PinAuthenticationViewPreview(@PreviewParameter(PinAuthenticationStateProvider::class) state: PinAuthenticationState) {
|
internal fun PinUnlockViewPreview(@PreviewParameter(PinUnlockStateProvider::class) state: PinUnlockState) {
|
||||||
ElementPreview {
|
ElementPreview {
|
||||||
PinAuthenticationView(
|
PinUnlockView(
|
||||||
state = state,
|
state = state,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.auth.numpad
|
package io.element.android.features.lockscreen.impl.unlock.numpad
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.auth.numpad
|
package io.element.android.features.lockscreen.impl.unlock.numpad
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
|
|
||||||
|
|
@ -14,16 +14,16 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.create
|
package io.element.android.features.lockscreen.impl.setup
|
||||||
|
|
||||||
import app.cash.molecule.RecompositionMode
|
import app.cash.molecule.RecompositionMode
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.lockscreen.impl.create.model.PinDigit
|
import io.element.android.features.lockscreen.impl.setup.model.PinDigit
|
||||||
import io.element.android.features.lockscreen.impl.create.model.PinEntry
|
import io.element.android.features.lockscreen.impl.setup.model.PinEntry
|
||||||
import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure
|
import io.element.android.features.lockscreen.impl.setup.validation.CreatePinFailure
|
||||||
import io.element.android.features.lockscreen.impl.create.validation.PinValidator
|
import io.element.android.features.lockscreen.impl.setup.validation.PinValidator
|
||||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
Loading…
Add table
Add a link
Reference in a new issue