ganfra
11 months ago
3 changed files with 304 additions and 19 deletions
@ -0,0 +1,182 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.lockscreen.impl.auth.numpad |
||||||
|
|
||||||
|
import androidx.compose.foundation.background |
||||||
|
import androidx.compose.foundation.layout.Arrangement |
||||||
|
import androidx.compose.foundation.layout.Column |
||||||
|
import androidx.compose.foundation.layout.PaddingValues |
||||||
|
import androidx.compose.foundation.layout.Row |
||||||
|
import androidx.compose.foundation.layout.Spacer |
||||||
|
import androidx.compose.foundation.layout.size |
||||||
|
import androidx.compose.foundation.shape.CircleShape |
||||||
|
import androidx.compose.material.icons.Icons |
||||||
|
import androidx.compose.material.icons.automirrored.filled.Backspace |
||||||
|
import androidx.compose.material3.Button |
||||||
|
import androidx.compose.material3.ButtonDefaults |
||||||
|
import androidx.compose.material3.IconButton |
||||||
|
import androidx.compose.material3.Text |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.Alignment |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import androidx.compose.ui.draw.clip |
||||||
|
import androidx.compose.ui.graphics.Color |
||||||
|
import androidx.compose.ui.unit.Dp |
||||||
|
import androidx.compose.ui.unit.dp |
||||||
|
import androidx.compose.ui.unit.sp |
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview |
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight |
||||||
|
import io.element.android.libraries.designsystem.text.toSp |
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon |
||||||
|
import io.element.android.libraries.theme.ElementTheme |
||||||
|
|
||||||
|
@Composable |
||||||
|
fun PinKeypad( |
||||||
|
onClick: (PinKeypadModel) -> Unit, |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
verticalArrangement: Arrangement.Vertical = Arrangement.Top, |
||||||
|
verticalAlignment: Alignment.Vertical = Alignment.Top, |
||||||
|
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, |
||||||
|
horizontalAlignment: Alignment.Horizontal = Alignment.Start, |
||||||
|
) { |
||||||
|
Column( |
||||||
|
modifier = modifier, |
||||||
|
verticalArrangement = verticalArrangement, |
||||||
|
horizontalAlignment = horizontalAlignment, |
||||||
|
) { |
||||||
|
PinKeypadRow( |
||||||
|
verticalAlignment = verticalAlignment, |
||||||
|
horizontalArrangement = horizontalArrangement, |
||||||
|
models = listOf(PinKeypadModel.Number("1"), PinKeypadModel.Number("2"), PinKeypadModel.Number("3")), |
||||||
|
onClick = onClick, |
||||||
|
) |
||||||
|
PinKeypadRow( |
||||||
|
verticalAlignment = verticalAlignment, |
||||||
|
horizontalArrangement = horizontalArrangement, |
||||||
|
models = listOf(PinKeypadModel.Number("4"), PinKeypadModel.Number("5"), PinKeypadModel.Number("6")), |
||||||
|
onClick = onClick, |
||||||
|
) |
||||||
|
PinKeypadRow( |
||||||
|
verticalAlignment = verticalAlignment, |
||||||
|
horizontalArrangement = horizontalArrangement, |
||||||
|
models = listOf(PinKeypadModel.Number("7"), PinKeypadModel.Number("8"), PinKeypadModel.Number("9")), |
||||||
|
onClick = onClick, |
||||||
|
) |
||||||
|
PinKeypadRow( |
||||||
|
verticalAlignment = verticalAlignment, |
||||||
|
horizontalArrangement = horizontalArrangement, |
||||||
|
models = listOf(PinKeypadModel.Empty, PinKeypadModel.Number("0"), PinKeypadModel.Back), |
||||||
|
onClick = onClick, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun PinKeypadRow( |
||||||
|
models: List<PinKeypadModel>, |
||||||
|
onClick: (PinKeypadModel) -> Unit, |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, |
||||||
|
verticalAlignment: Alignment.Vertical = Alignment.Top, |
||||||
|
) { |
||||||
|
Row( |
||||||
|
horizontalArrangement = horizontalArrangement, |
||||||
|
verticalAlignment = verticalAlignment, |
||||||
|
modifier = modifier, |
||||||
|
) { |
||||||
|
val commonModifier = Modifier.size(80.dp) |
||||||
|
for (model in models) { |
||||||
|
when (model) { |
||||||
|
is PinKeypadModel.Empty -> { |
||||||
|
Spacer(modifier = commonModifier) |
||||||
|
} |
||||||
|
is PinKeypadModel.Back -> { |
||||||
|
PinKeypadBackButton( |
||||||
|
modifier = commonModifier, |
||||||
|
onClick = { onClick(model) }, |
||||||
|
) |
||||||
|
} |
||||||
|
is PinKeypadModel.Number -> { |
||||||
|
PinKeyBadDigitButton( |
||||||
|
size = 80.dp, |
||||||
|
modifier = commonModifier, |
||||||
|
digit = model.number, |
||||||
|
onClick = { onClick(model) }, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun PinKeyBadDigitButton( |
||||||
|
digit: String, |
||||||
|
size: Dp, |
||||||
|
onClick: (String) -> Unit, |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
) { |
||||||
|
Button( |
||||||
|
colors = ButtonDefaults.buttonColors( |
||||||
|
containerColor = ElementTheme.colors.bgSubtlePrimary, |
||||||
|
contentColor = Color.Transparent, |
||||||
|
), |
||||||
|
shape = CircleShape, |
||||||
|
contentPadding = PaddingValues(0.dp), |
||||||
|
modifier = modifier |
||||||
|
.clip(CircleShape), |
||||||
|
onClick = { onClick(digit) } |
||||||
|
) { |
||||||
|
val fontSize = 80.dp.toSp() / 2 |
||||||
|
val originalFont = ElementTheme.typography.fontHeadingXlBold |
||||||
|
val ratio = fontSize.value / originalFont.fontSize.value |
||||||
|
val lineHeight = originalFont.lineHeight * ratio |
||||||
|
Text( |
||||||
|
text = digit, |
||||||
|
color = ElementTheme.colors.textPrimary, |
||||||
|
style = originalFont.copy(fontSize = fontSize, lineHeight = lineHeight, letterSpacing = 0.sp), |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun PinKeypadBackButton( |
||||||
|
onClick: () -> Unit, |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
) { |
||||||
|
IconButton( |
||||||
|
modifier = modifier |
||||||
|
.clip(CircleShape) |
||||||
|
.background(color = Color.Transparent, shape = CircleShape), |
||||||
|
onClick = onClick, |
||||||
|
) { |
||||||
|
Icon( |
||||||
|
imageVector = Icons.AutoMirrored.Filled.Backspace, |
||||||
|
contentDescription = null, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
@PreviewsDayNight |
||||||
|
fun PinKeypad() { |
||||||
|
ElementPreview { |
||||||
|
PinKeypad(onClick = {}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.lockscreen.impl.auth.numpad |
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable |
||||||
|
|
||||||
|
@Immutable |
||||||
|
sealed interface PinKeypadModel { |
||||||
|
data object Empty : PinKeypadModel |
||||||
|
data object Back : PinKeypadModel |
||||||
|
data class Number(val number: String) : PinKeypadModel |
||||||
|
} |
Loading…
Reference in new issue