ganfra
11 months ago
3 changed files with 304 additions and 19 deletions
@ -0,0 +1,182 @@
@@ -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 @@
@@ -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