[BIT-148] Adding wireframe UI for password generator screen (#37)

This commit is contained in:
joshua-livefront 2023-09-11 10:16:18 -04:00 committed by Álison Fernandes
parent b0c794acd5
commit 4c92ee0b23
2 changed files with 294 additions and 0 deletions

View file

@ -0,0 +1,273 @@
package com.x8bit.bitwarden.ui.tools.feature.generator
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Slider
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
/**
* Top level composable for the generator screen.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun GeneratorScreen() {
Scaffold(
topBar = {
TopAppBar(
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.onPrimary,
),
title = {
Text(
text = stringResource(id = R.string.generator_label),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
)
},
navigationIcon = {
Spacer(Modifier.width(40.dp))
},
actions = {
OverflowMenu()
},
)
},
) { innerPadding ->
ScrollContent(modifier = Modifier.padding(innerPadding))
}
}
@Composable
private fun OverflowMenu() {
IconButton(
onClick = {},
) {
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = stringResource(id = R.string.overflow_menu),
tint = MaterialTheme.colorScheme.onPrimary,
)
}
}
@Composable
private fun ScrollContent(modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier.fillMaxSize()) {
item { DynamicStringItem() }
item { TextItem(title = stringResource(id = R.string.generation_prompt)) }
item { TextItem(title = stringResource(id = R.string.password_type), showOptions = true) }
item { LengthSliderItem() }
item { ToggleItem(stringResource(id = R.string.capital_letters_toggle_text)) }
item { ToggleItem(stringResource(id = R.string.lowercase_letters_toggle_text)) }
item { ToggleItem(stringResource(id = R.string.numbers_toggle_text)) }
item { ToggleItem(stringResource(id = R.string.special_characters_toggle_text)) }
item { CounterItem(label = stringResource(id = R.string.minimum_numbers)) }
item { CounterItem(label = stringResource(id = R.string.minimum_special)) }
item { ToggleItem(stringResource(id = R.string.avoid_ambiguous_characters)) }
}
}
@Composable
private fun DynamicStringItem() {
// TODO(BIT-276): Move this state to ViewModel
val placeholderPassword = stringResource(id = R.string.placeholder_password)
val dynamicString = remember { mutableStateOf(placeholderPassword) }
Box(modifier = Modifier.padding(horizontal = 16.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = dynamicString.value)
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
IconButton(
onClick = {},
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = stringResource(id = R.string.copy),
tint = MaterialTheme.colorScheme.primary,
)
}
IconButton(
onClick = {},
) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = stringResource(id = R.string.refresh),
tint = MaterialTheme.colorScheme.primary,
)
}
}
}
}
}
@Composable
private fun TextItem(title: String, showOptions: Boolean = false) {
// TODO(BIT-276): Move this state to ViewModel
val defaultType = stringResource(id = R.string.password)
val content = remember { mutableStateOf(defaultType) }
CommonPadding {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(top = 4.dp, bottom = 4.dp),
verticalArrangement = Arrangement.Center,
) {
if (showOptions) {
Text(
stringResource(id = R.string.options),
style = TextStyle(fontSize = 12.sp),
color = MaterialTheme.colorScheme.primary,
)
}
Text(title, style = TextStyle(fontSize = 10.sp))
Text(content.value)
}
}
}
@Composable
private fun LengthSliderItem() {
// TODO(BIT-276): Move this state to ViewModel
val sliderPosition = remember { mutableStateOf(0f) }
CommonPadding {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(stringResource(id = R.string.length))
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Spacer(modifier = Modifier.width(16.dp))
Text(sliderPosition.value.toInt().toString())
Slider(
value = sliderPosition.value,
onValueChange = {},
)
}
}
}
}
@Composable
private fun ToggleItem(title: String) {
// TODO(BIT-276): Move this state to ViewModel
val isToggled = remember { mutableStateOf(false) }
CommonPadding {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(title)
Switch(checked = isToggled.value, onCheckedChange = { isToggled.value = it })
}
}
}
@Composable
private fun CounterItem(label: String) {
// TODO(BIT-276): Move this state to ViewModel
val counter = remember { mutableStateOf(1) }
CommonPadding {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth(),
) {
Text(label)
Row(
verticalAlignment = Alignment.CenterVertically,
) {
Text(counter.value.toString())
IconButton(
onClick = {},
) {
Icon(
Icons.Default.ArrowBack,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)
}
IconButton(
onClick = {},
) {
Icon(
Icons.Default.ArrowForward,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)
}
}
}
}
}
@Composable
private fun CommonPadding(content: @Composable () -> Unit) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
) {
content()
Divider()
}
}
@Preview(showBackground = true)
@Composable
private fun GeneratorPreview() {
BitwardenTheme {
GeneratorScreen()
}
}

View file

@ -18,6 +18,27 @@
<string name="new_around_here">New around here?</string>
<string name="remember_me">Remember me</string>
<!-- Generator Screen-->
<string name="placeholder_password">PLACEHOLDER</string>
<string name="generation_prompt">What would you like to generate?</string>
<string name="password">Password</string>
<string name="passphrase">Passphrase</string>
<string name="password_type">Password type</string>
<string name="capital_letters_toggle_text">AZ</string>
<string name="lowercase_letters_toggle_text">az</string>
<string name="numbers_toggle_text">09</string>
<string name="special_characters_toggle_text">!@#$%^&amp;*</string>
<string name="minimum_numbers">Minimum numbers</string>
<string name="minimum_special">Minimum special</string>
<string name="avoid_ambiguous_characters">Avoid ambiguous characters</string>
<string name="copy">Copy</string>
<string name="refresh">Refresh</string>
<string name="decrease">Decrease</string>
<string name="increase">Increase</string>
<string name="options">Options</string>
<string name="length">Length</string>
<string name="overflow_menu">Overflow menu</string>
<!--Bottom Navigation-->
<string name="generator_tab_content_description">Press to navigate to the generator screen.</string>
<string name="send_tab_content_description">Press to navigate to the send screen.</string>