From c4c9f779e8e3f0e5be10c316cb4b789b192cd3c2 Mon Sep 17 00:00:00 2001 From: Leonardo Colman Lopes Date: Mon, 27 May 2024 20:25:56 -0300 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20settings=20view?= =?UTF-8?q?=20to=20use=20componentized=20list=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The settings view has been refactored to use componentized list items, improving code readability and maintainability. Each settings item and dialog was extracted into a separate Composable function in separate files, which also allows easier and isolated previewing using the @Preview annotation. The componentized settings items include: Currency, PIN, Repository, Date, Time, Milliseconds Bar Enabled, Hit Timer Milliseconds Enabled, Precision, and Share App items. Signed-off-by: Leonardo Colman Lopes --- .../colman/petals/settings/SettingsView.kt | 688 +----------------- .../view/dialog/SelectFromListDialog.kt | 75 ++ .../settings/view/dialog/TextfieldDialog.kt | 47 ++ .../view/listitem/CurrencyListItem.kt | 35 + .../settings/view/listitem/DateListItem.kt | 41 ++ .../settings/view/listitem/DialogListItem.kt | 40 + .../HitTimerMillisecondsEnabledListItem.kt | 48 ++ .../MillisecondsBarEnabledListItem.kt | 41 ++ .../settings/view/listitem/PinListItem.kt | 36 + .../view/listitem/PrecisionListItem.kt | 41 ++ .../view/listitem/RepositoryListItem.kt | 34 + .../view/listitem/ShareAppListItem.kt | 49 ++ .../settings/view/listitem/TimeListItem.kt | 41 ++ 13 files changed, 562 insertions(+), 654 deletions(-) create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/dialog/SelectFromListDialog.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/dialog/TextfieldDialog.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/CurrencyListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/DateListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/DialogListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/HitTimerMillisecondsEnabledListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/MillisecondsBarEnabledListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/PinListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/PrecisionListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/RepositoryListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/ShareAppListItem.kt create mode 100644 app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/TimeListItem.kt diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/SettingsView.kt b/app/src/main/kotlin/br/com/colman/petals/settings/SettingsView.kt index 37e1480c..efd2654a 100644 --- a/app/src/main/kotlin/br/com/colman/petals/settings/SettingsView.kt +++ b/app/src/main/kotlin/br/com/colman/petals/settings/SettingsView.kt @@ -1,678 +1,58 @@ -@file:OptIn(ExperimentalMaterialApi::class) -@file:Suppress("TooManyFunctions") - package br.com.colman.petals.settings -import android.content.Context -import android.content.Intent -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.AlertDialog -import androidx.compose.material.DropdownMenuItem -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.ExposedDropdownMenuBox -import androidx.compose.material.ExposedDropdownMenuDefaults -import androidx.compose.material.Icon -import androidx.compose.material.ListItem -import androidx.compose.material.OutlinedTextField -import androidx.compose.material.Text -import androidx.compose.material.TextField -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Share import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.PasswordVisualTransformation -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat -import br.com.colman.petals.R.string.app_pin -import br.com.colman.petals.R.string.currency_icon -import br.com.colman.petals.R.string.date_format_label -import br.com.colman.petals.R.string.decimal_precision -import br.com.colman.petals.R.string.enable_or_disable_milliseconds_bar_on_home_page -import br.com.colman.petals.R.string.enable_or_disable_milliseconds_on_hit_timer_page -import br.com.colman.petals.R.string.hit_timer_milliseconds_enabled -import br.com.colman.petals.R.string.milliseconds_enabled -import br.com.colman.petals.R.string.ok -import br.com.colman.petals.R.string.password_description -import br.com.colman.petals.R.string.repository_link_description -import br.com.colman.petals.R.string.repository_link_title -import br.com.colman.petals.R.string.share_app -import br.com.colman.petals.R.string.share_app_message -import br.com.colman.petals.R.string.share_app_title -import br.com.colman.petals.R.string.time_format_label -import br.com.colman.petals.R.string.what_date_format_should_be_used -import br.com.colman.petals.R.string.what_decimal_precision_should_be_used -import br.com.colman.petals.R.string.what_icon_should_be_used_for_currency -import br.com.colman.petals.R.string.what_time_format_should_be_used -import compose.icons.TablerIcons -import compose.icons.tablericons.BrandGithub -import compose.icons.tablericons.Calculator -import compose.icons.tablericons.Calendar -import compose.icons.tablericons.Cash -import compose.icons.tablericons.CircleOff -import compose.icons.tablericons.Clock -import compose.icons.tablericons.Lock -import compose.icons.tablericons.ToggleLeft +import br.com.colman.petals.settings.view.listitem.CurrencyListItem +import br.com.colman.petals.settings.view.listitem.DateListItem +import br.com.colman.petals.settings.view.listitem.HitTimerMillisecondsEnabledListItem +import br.com.colman.petals.settings.view.listitem.MillisecondsBarEnabledListItem +import br.com.colman.petals.settings.view.listitem.PinListItem +import br.com.colman.petals.settings.view.listitem.PrecisionListItem +import br.com.colman.petals.settings.view.listitem.RepositoryListItem +import br.com.colman.petals.settings.view.listitem.ShareApp +import br.com.colman.petals.settings.view.listitem.TimeListItem @Composable fun SettingsView(settingsRepository: SettingsRepository) { val currentCurrency by settingsRepository.currencyIcon.collectAsState("$") - val setCurrency = settingsRepository::setCurrencyIcon - val setDateFormat = settingsRepository::setDateFormat - val dateFormatList = settingsRepository.dateFormatList - val currentDateFormat by settingsRepository.dateFormat.collectAsState(dateFormatList[0]) - val setTimeFormat = settingsRepository::setTimeFormat - val timeFormatList = settingsRepository.timeFormatList - val currentTimeFormat by settingsRepository.timeFormat.collectAsState(timeFormatList[0]) - val setPin = settingsRepository::setPin - val setMillisecondsEnabled = settingsRepository::setMillisecondsEnabled - val millisecondsEnabledList = settingsRepository.millisecondsEnabledList - val currentMillisecondsEnabled by settingsRepository.millisecondsEnabled.collectAsState(millisecondsEnabledList[0]) - val setHitTimerMillisecondsEnabled = settingsRepository::setHitTimerMillisecondsEnabled - val hitTimerMillisecondsEnabledList = settingsRepository.hitTimerMillisecondsEnabledList + val currentDateFormat by settingsRepository.dateFormat.collectAsState(settingsRepository.dateFormatList[0]) + val currentTimeFormat by settingsRepository.timeFormat.collectAsState(settingsRepository.timeFormatList[0]) + val currentMillisecondsEnabled by settingsRepository.millisecondsEnabled.collectAsState( + settingsRepository.millisecondsEnabledList[0] + ) val currentHitTimerMillisecondsEnabled by settingsRepository.hitTimerMillisecondsEnabled.collectAsState( - hitTimerMillisecondsEnabledList[0] + settingsRepository.hitTimerMillisecondsEnabledList[0] + ) + val currentDecimalPrecision by settingsRepository.decimalPrecision.collectAsState( + settingsRepository.decimalPrecisionList[2] ) - val setDecimalPrecision = settingsRepository::setDecimalPrecision - val decimalPrecisionList = settingsRepository.decimalPrecisionList - val currentDecimalPrecision by settingsRepository.decimalPrecision.collectAsState(decimalPrecisionList[2]) Column(Modifier.verticalScroll(rememberScrollState())) { - CurrencyListItem(currentCurrency, setCurrency) - PinListItem(setPin) + CurrencyListItem(currentCurrency, settingsRepository::setCurrencyIcon) + PinListItem(settingsRepository::setPin) RepositoryListItem() - DateListItem(currentDateFormat, dateFormatList, setDateFormat) - TimeListItem(currentTimeFormat, timeFormatList, setTimeFormat) - MillisecondsEnabledListItem(currentMillisecondsEnabled, millisecondsEnabledList, setMillisecondsEnabled) + DateListItem(currentDateFormat, settingsRepository.dateFormatList, settingsRepository::setDateFormat) + TimeListItem(currentTimeFormat, settingsRepository.timeFormatList, settingsRepository::setTimeFormat) + MillisecondsBarEnabledListItem( + currentMillisecondsEnabled, + settingsRepository.millisecondsEnabledList, + settingsRepository::setMillisecondsEnabled + ) HitTimerMillisecondsEnabledListItem( currentHitTimerMillisecondsEnabled, - hitTimerMillisecondsEnabledList, - setHitTimerMillisecondsEnabled + settingsRepository.hitTimerMillisecondsEnabledList, + settingsRepository::setHitTimerMillisecondsEnabled ) - PrecisionListItem(currentDecimalPrecision, decimalPrecisionList, setDecimalPrecision) - ShareApp() - } -} - -@Preview -@Composable -private fun RepositoryListItem() { - val uriHandler = LocalUriHandler.current - val openUrl = { uriHandler.openUri("https://github.com/LeoColman/Petals") } - - ListItem( - modifier = Modifier.clickable { openUrl() }, - icon = { Icon(TablerIcons.BrandGithub, null, Modifier.size(42.dp)) }, - secondaryText = { Text(stringResource(repository_link_description)) } - ) { - Text(stringResource(repository_link_title)) - } -} - -@Preview -@Composable -private fun CurrencyListItem( - currency: String = "", - setCurrency: (String) -> Unit = {} -) { - var shouldShowDialog by remember { mutableStateOf(false) } - - ListItem( - modifier = Modifier.clickable { shouldShowDialog = true }, - icon = { Icon(TablerIcons.Cash, null, Modifier.size(42.dp)) }, - - secondaryText = { Text(stringResource(what_icon_should_be_used_for_currency)) } - ) { - Text(stringResource(currency_icon)) - } - - if (shouldShowDialog) { - CurrencyDialog(currency, setCurrency) { shouldShowDialog = false } - } -} - -@Preview -@Composable -private fun PinListItem( - setPin: (String?) -> Unit = {} -) { - var shouldShowDialog by remember { mutableStateOf(false) } - - ListItem( - modifier = Modifier.clickable { shouldShowDialog = true }, - icon = { Icon(TablerIcons.Lock, null, Modifier.size(42.dp)) }, - - secondaryText = { Text(stringResource(password_description)) } - ) { - Text(stringResource(app_pin)) - } - - if (shouldShowDialog) { - PinDialog(setPin) { shouldShowDialog = false } - } -} - -@Preview -@Composable -fun DateListItem( - dateFormat: String = "", - dateFormatList: List = listOf(), - setDateFormat: (String) -> Unit = {} -) { - var shouldShowDialog by remember { mutableStateOf(false) } - - ListItem( - modifier = Modifier.clickable { shouldShowDialog = true }, - icon = { Icon(TablerIcons.Calendar, null, Modifier.size(42.dp)) }, - - secondaryText = { Text(stringResource(what_date_format_should_be_used)) } - ) { - Text(stringResource(date_format_label)) - } - - if (shouldShowDialog) { - DateDialog(dateFormat, dateFormatList, setDateFormat) { shouldShowDialog = false } - } -} - -@Preview -@Composable -fun TimeListItem( - timeFormat: String = "", - timeFormatList: List = listOf(), - setTimeFormat: (String) -> Unit = {} -) { - var shouldShowDialog by remember { mutableStateOf(false) } - - ListItem( - modifier = Modifier.clickable { shouldShowDialog = true }, - icon = { Icon(TablerIcons.Clock, null, Modifier.size(42.dp)) }, - - secondaryText = { Text(stringResource(what_time_format_should_be_used)) } - ) { - Text(stringResource(time_format_label)) - } - - if (shouldShowDialog) { - TimeDialog(timeFormat, timeFormatList, setTimeFormat) { shouldShowDialog = false } - } -} - -@Preview -@Composable -fun MillisecondsEnabledListItem( - millisEnabled: String = "", - millisOptions: List = listOf(), - setMillisEnabled: (String) -> Unit = {} -) { - var shouldShowDialog by remember { mutableStateOf(false) } - - ListItem( - modifier = Modifier.clickable { shouldShowDialog = true }, - icon = { Icon(TablerIcons.CircleOff, null, Modifier.size(42.dp)) }, - - secondaryText = { Text(stringResource(enable_or_disable_milliseconds_bar_on_home_page)) } - ) { - Text(stringResource(milliseconds_enabled)) - } - - if (shouldShowDialog) { - MillisecondsEnabledDialog(millisEnabled, millisOptions, setMillisEnabled) { - shouldShowDialog = false - } - } -} - -@Preview -@Composable -fun HitTimerMillisecondsEnabledListItem( - hitTimerMillisecondsEnabled: String = "", - hitTimerMillisecondsEnabledList: List = listOf(), - setHitTimerMillisecondsEnabled: (String) -> Unit = {} -) { - var shouldShowDialog by remember { mutableStateOf(false) } - - ListItem( - modifier = Modifier.clickable { shouldShowDialog = true }, - icon = { Icon(TablerIcons.ToggleLeft, null, Modifier.size(42.dp)) }, - - secondaryText = { Text(stringResource(enable_or_disable_milliseconds_on_hit_timer_page)) } - ) { - Text(stringResource(hit_timer_milliseconds_enabled)) - } - - if (shouldShowDialog) { - HitTimerMillisecondsEnabledDialog( - hitTimerMillisecondsEnabled, - hitTimerMillisecondsEnabledList, - setHitTimerMillisecondsEnabled - ) { shouldShowDialog = false } - } -} - -@Preview -@Composable -fun PrecisionListItem( - decimalPrecision: Int = 2, - decimalPrecisionList: List = listOf(), - setDecimalPrecision: (Int) -> Unit = {} -) { - var shouldShowDialog by remember { mutableStateOf(false) } - - ListItem( - modifier = Modifier.clickable { shouldShowDialog = true }, - icon = { Icon(TablerIcons.Calculator, null, Modifier.size(42.dp)) }, - - secondaryText = { Text(stringResource(what_decimal_precision_should_be_used)) } - ) { - Text(stringResource(decimal_precision)) - } - - if (shouldShowDialog) { - PrecisionDialog(decimalPrecision, decimalPrecisionList, setDecimalPrecision) { shouldShowDialog = false } - } -} - -@Preview -@Composable -fun ShareApp( - shareIcon: ImageVector = Icons.Default.Share, - context: Context = LocalContext.current -) { - val sendIntent: Intent = Intent().apply { - action = Intent.ACTION_SEND - putExtra( - Intent.EXTRA_TEXT, - stringResource(share_app_message) + PrecisionListItem( + currentDecimalPrecision, + settingsRepository.decimalPrecisionList, + settingsRepository::setDecimalPrecision ) - type = "text/plain" - } - val shareIntent = Intent.createChooser(sendIntent, null) - ListItem( - modifier = Modifier.clickable { - ContextCompat.startActivity(context, shareIntent, null) - }, - icon = { Icon(shareIcon, null, Modifier.size(42.dp)) }, - secondaryText = { Text(stringResource(share_app)) } - ) { - Text(stringResource(share_app_title)) + ShareApp() } } - -@Preview -@Composable -private fun TimeDialog( - initialTimeFormat: String = "", - timeFormatList: List = listOf(), - setTimeFormat: (String) -> Unit = {}, - onDismiss: () -> Unit = {}, -) { - var timeFormat by remember { mutableStateOf(initialTimeFormat) } - var expanded by remember { mutableStateOf(false) } - - AlertDialog( - onDismissRequest = onDismiss, - text = { - ExposedDropdownMenuBox( - expanded = false, - onExpandedChange = { expanded = !expanded } - ) { - TextField( - value = timeFormat, - onValueChange = {}, - readOnly = true, - label = { Text(text = stringResource(time_format_label)) }, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon( - expanded = expanded - ) - }, - colors = ExposedDropdownMenuDefaults.textFieldColors() - ) - - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { - timeFormatList.forEach { selectedOption -> - DropdownMenuItem(onClick = { - timeFormat = selectedOption - expanded = false - }) { - Text(text = selectedOption) - } - } - } - } - }, - confirmButton = { - Text( - stringResource(ok), - Modifier - .padding(8.dp) - .clickable { - setTimeFormat(timeFormat) - onDismiss() - } - ) - } - ) -} - -@Preview -@Composable -private fun DateDialog( - initialDateFormat: String = "", - dateFormatList: List = listOf(), - setDateFormat: (String) -> Unit = {}, - onDismiss: () -> Unit = {}, -) { - var dateFormat by remember { mutableStateOf(initialDateFormat) } - var expanded by remember { mutableStateOf(false) } - - AlertDialog( - onDismissRequest = onDismiss, - text = { - ExposedDropdownMenuBox( - expanded = false, - onExpandedChange = { expanded = !expanded } - ) { - TextField( - value = dateFormat, - onValueChange = {}, - readOnly = true, - label = { Text(text = stringResource(date_format_label)) }, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon( - expanded = expanded - ) - }, - colors = ExposedDropdownMenuDefaults.textFieldColors() - ) - - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { - dateFormatList.forEach { selectedOption -> - DropdownMenuItem(onClick = { - dateFormat = selectedOption - expanded = false - }) { - Text(text = selectedOption) - } - } - } - } - }, - confirmButton = { - Text( - stringResource(ok), - Modifier - .padding(8.dp) - .clickable { - setDateFormat(dateFormat) - onDismiss() - } - ) - } - ) -} - -@Preview -@Composable -private fun CurrencyDialog( - initialCurrency: String = "$", - setCurrency: (String) -> Unit = {}, - onDismiss: () -> Unit = {}, -) { - var currency by remember { mutableStateOf(initialCurrency) } - - AlertDialog( - onDismissRequest = onDismiss, - text = { - OutlinedTextField( - currency, - { currency = it }, - label = { Text(stringResource(currency_icon)) } - ) - }, - confirmButton = { - Text( - stringResource(ok), - Modifier - .padding(8.dp) - .clickable { - setCurrency(currency) - onDismiss() - } - ) - } - ) -} - -@Preview -@Composable -private fun PinDialog( - setPin: (String?) -> Unit = {}, - onDismiss: () -> Unit = {}, -) { - var pin by remember { mutableStateOf(null as String?) } - - AlertDialog( - onDismissRequest = onDismiss, - text = { - OutlinedTextField( - pin.orEmpty(), - { pin = it.ifBlank { null } }, - label = { Text(stringResource(app_pin)) }, - visualTransformation = PasswordVisualTransformation() - ) - }, - confirmButton = { - Text( - stringResource(ok), - Modifier - .padding(8.dp) - .clickable { - setPin(pin) - onDismiss() - } - ) - } - ) -} - -@Preview -@Composable -private fun MillisecondsEnabledDialog( - initialMillisecondsEnabled: String = "", - millisecondsEnabledList: List = listOf(), - setMillisecondsEnabled: (String) -> Unit = {}, - onDismiss: () -> Unit = {}, -) { - var millisecondsEnabled by remember { mutableStateOf(initialMillisecondsEnabled) } - var expanded by remember { mutableStateOf(false) } - - AlertDialog( - onDismissRequest = onDismiss, - text = { - ExposedDropdownMenuBox( - expanded = false, - onExpandedChange = { expanded = !expanded } - ) { - TextField( - value = millisecondsEnabled, - onValueChange = {}, - readOnly = true, - label = { Text(text = stringResource(milliseconds_enabled)) }, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon( - expanded = expanded - ) - }, - colors = ExposedDropdownMenuDefaults.textFieldColors() - ) - - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { - millisecondsEnabledList.forEach { selectedOption -> - DropdownMenuItem(onClick = { - millisecondsEnabled = selectedOption - expanded = false - }) { - Text(text = selectedOption) - } - } - } - } - }, - confirmButton = { - Text( - stringResource(ok), - Modifier - .padding(8.dp) - .clickable { - setMillisecondsEnabled(millisecondsEnabled) - onDismiss() - } - ) - } - ) -} - -@Preview -@Composable -private fun HitTimerMillisecondsEnabledDialog( - initialHitTimerMillisecondsEnabled: String = "", - hitTimerMillisecondsEnabledList: List = listOf(), - setHitTimerMillisecondsEnabled: (String) -> Unit = {}, - onDismiss: () -> Unit = {}, -) { - var hitTimerMillisecondsEnabled by remember { mutableStateOf(initialHitTimerMillisecondsEnabled) } - var expanded by remember { mutableStateOf(false) } - - AlertDialog( - onDismissRequest = onDismiss, - text = { - ExposedDropdownMenuBox( - expanded = false, - onExpandedChange = { expanded = !expanded } - ) { - TextField( - value = hitTimerMillisecondsEnabled, - onValueChange = {}, - readOnly = true, - label = { Text(text = stringResource(hit_timer_milliseconds_enabled)) }, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon( - expanded = expanded - ) - }, - colors = ExposedDropdownMenuDefaults.textFieldColors() - ) - - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { - hitTimerMillisecondsEnabledList.forEach { selectedOption -> - DropdownMenuItem(onClick = { - hitTimerMillisecondsEnabled = selectedOption - expanded = false - }) { - Text(text = selectedOption) - } - } - } - } - }, - confirmButton = { - Text( - stringResource(ok), - Modifier - .padding(8.dp) - .clickable { - setHitTimerMillisecondsEnabled(hitTimerMillisecondsEnabled) - onDismiss() - } - ) - } - ) -} - -@Preview -@Composable -private fun PrecisionDialog( - initialDecimalPrecision: Int = 2, - decimalPrecisionList: List = listOf(), - setDecimalPrecision: (Int) -> Unit = {}, - onDismiss: () -> Unit = {}, -) { - var decimalPrecision by remember { mutableStateOf(initialDecimalPrecision) } - var expanded by remember { mutableStateOf(false) } - - AlertDialog( - onDismissRequest = onDismiss, - text = { - ExposedDropdownMenuBox( - expanded = false, - onExpandedChange = { expanded = !expanded } - ) { - TextField( - value = decimalPrecision.toString(), - onValueChange = {}, - readOnly = true, - label = { Text(text = stringResource(decimal_precision)) }, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon( - expanded = expanded - ) - }, - colors = ExposedDropdownMenuDefaults.textFieldColors() - ) - - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { - decimalPrecisionList.forEach { selectedOption -> - DropdownMenuItem(onClick = { - decimalPrecision = selectedOption - expanded = false - }) { - Text(text = selectedOption.toString()) - } - } - } - } - }, - confirmButton = { - Text( - stringResource(ok), - Modifier - .padding(8.dp) - .clickable { - setDecimalPrecision(decimalPrecision) - onDismiss() - } - ) - } - ) -} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/dialog/SelectFromListDialog.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/dialog/SelectFromListDialog.kt new file mode 100644 index 00000000..9558d8c9 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/dialog/SelectFromListDialog.kt @@ -0,0 +1,75 @@ +@file:OptIn(ExperimentalMaterialApi::class) + +package br.com.colman.petals.settings.view.dialog + +import androidx.annotation.StringRes +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.padding +import androidx.compose.material.AlertDialog +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.ExposedDropdownMenuBox +import androidx.compose.material.ExposedDropdownMenuDefaults +import androidx.compose.material.Text +import androidx.compose.material.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import br.com.colman.petals.R + +@Composable +fun SelectFromListDialog( + initialValue: String, + possibleValues: List, + setValue: (String) -> Unit, + onDismiss: () -> Unit, + @StringRes label: Int, +) { + var value by remember { mutableStateOf(initialValue) } + var expanded by remember { mutableStateOf(false) } + AlertDialog( + onDismissRequest = onDismiss, + text = { + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { expanded = !expanded } + ) { + TextField( + value = value, + onValueChange = { }, + readOnly = true, + label = { Text(text = stringResource(label)) }, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, + colors = ExposedDropdownMenuDefaults.textFieldColors() + ) + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + possibleValues.forEach { selectedOption -> + DropdownMenuItem(onClick = { + value = selectedOption + expanded = false + }) { Text(text = selectedOption) } + } + } + } + }, + confirmButton = { + Text( + stringResource(R.string.ok), + Modifier + .padding(8.dp) + .clickable { + setValue(value) + onDismiss() + } + ) + } + ) +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/dialog/TextfieldDialog.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/dialog/TextfieldDialog.kt new file mode 100644 index 00000000..1d1bdda9 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/dialog/TextfieldDialog.kt @@ -0,0 +1,47 @@ +package br.com.colman.petals.settings.view.dialog + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.padding +import androidx.compose.material.AlertDialog +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import br.com.colman.petals.R + +@Composable +fun TextfieldDialog( + initialValue: String, + setValue: (String) -> Unit, + onDismiss: () -> Unit, + resourceLabel: Int, +) { + var value by remember { mutableStateOf(initialValue) } + AlertDialog( + onDismissRequest = onDismiss, + text = { + OutlinedTextField( + value, + { value = it }, + label = { Text(stringResource(resourceLabel)) } + ) + }, + confirmButton = { + Text( + stringResource(R.string.ok), + Modifier + .padding(8.dp) + .clickable { + setValue(value) + onDismiss() + } + ) + } + ) +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/CurrencyListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/CurrencyListItem.kt new file mode 100644 index 00000000..11629a65 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/CurrencyListItem.kt @@ -0,0 +1,35 @@ +package br.com.colman.petals.settings.view.listitem + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import br.com.colman.petals.R +import br.com.colman.petals.R.string +import br.com.colman.petals.settings.view.dialog.TextfieldDialog +import compose.icons.TablerIcons +import compose.icons.tablericons.Cash + +@Preview +@Composable +fun CurrencyListItem(currency: String = "", setCurrency: (String) -> Unit = {}) { + DialogListItem( + icon = TablerIcons.Cash, + textId = R.string.currency_icon, + descriptionId = R.string.what_icon_should_be_used_for_currency, + dialog = { hideDialog -> CurrencyDialog(currency, setCurrency, hideDialog) } + ) +} + +@Preview +@Composable +private fun CurrencyDialog( + initialCurrencyFormat: String = "$", + setCurrencyFormat: (String) -> Unit = {}, + onDismiss: () -> Unit = {}, +) { + TextfieldDialog( + initialValue = initialCurrencyFormat, + setValue = setCurrencyFormat, + onDismiss = onDismiss, + resourceLabel = string.currency_icon + ) +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/DateListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/DateListItem.kt new file mode 100644 index 00000000..d1e5c100 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/DateListItem.kt @@ -0,0 +1,41 @@ +package br.com.colman.petals.settings.view.listitem + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import br.com.colman.petals.R.string.date_format_label +import br.com.colman.petals.R.string.what_date_format_should_be_used +import br.com.colman.petals.settings.view.dialog.SelectFromListDialog +import compose.icons.TablerIcons +import compose.icons.tablericons.Calendar + +@Preview +@Composable +fun DateListItem( + dateFormat: String = "", + dateFormatList: List = listOf(), + setDateFormat: (String) -> Unit = {} +) { + DialogListItem( + icon = TablerIcons.Calendar, + textId = date_format_label, + descriptionId = what_date_format_should_be_used, + dialog = { hideDialog -> DateDialog(dateFormat, dateFormatList, setDateFormat, hideDialog) } + ) +} + +@Preview +@Composable +private fun DateDialog( + initialDateFormat: String = "", + dateFormatList: List = listOf(), + setDateFormat: (String) -> Unit = {}, + onDismiss: () -> Unit = {}, +) { + SelectFromListDialog( + initialValue = initialDateFormat, + possibleValues = dateFormatList, + setValue = setDateFormat, + onDismiss = onDismiss, + label = date_format_label + ) +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/DialogListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/DialogListItem.kt new file mode 100644 index 00000000..aa321353 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/DialogListItem.kt @@ -0,0 +1,40 @@ +@file:OptIn(ExperimentalMaterialApi::class) + +package br.com.colman.petals.settings.view.listitem + +import androidx.annotation.StringRes +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.size +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.ListItem +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp + +@Composable +fun DialogListItem( + icon: ImageVector, + @StringRes textId: Int, + @StringRes descriptionId: Int, + dialog: @Composable (hideDialog: () -> Unit) -> Unit +) { + var showDialog by remember { mutableStateOf(false) } + ListItem( + modifier = Modifier.clickable { showDialog = true }, + icon = { Icon(icon, null, Modifier.size(42.dp)) }, + secondaryText = { Text(stringResource(descriptionId)) } + ) { + Text(stringResource(textId)) + } + if (showDialog) { + dialog { showDialog = false } + } +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/HitTimerMillisecondsEnabledListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/HitTimerMillisecondsEnabledListItem.kt new file mode 100644 index 00000000..ef530a50 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/HitTimerMillisecondsEnabledListItem.kt @@ -0,0 +1,48 @@ +package br.com.colman.petals.settings.view.listitem + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import br.com.colman.petals.R.string.enable_or_disable_milliseconds_on_hit_timer_page +import br.com.colman.petals.R.string.hit_timer_milliseconds_enabled +import br.com.colman.petals.settings.view.dialog.SelectFromListDialog +import compose.icons.TablerIcons +import compose.icons.tablericons.ToggleLeft + +@Preview +@Composable +fun HitTimerMillisecondsEnabledListItem( + hitTimerMillisecondsEnabled: String = "", + hitTimerMillisecondsEnabledList: List = listOf(), + setHitTimerMillisecondsEnabled: (String) -> Unit = {} +) { + DialogListItem( + icon = TablerIcons.ToggleLeft, + textId = hit_timer_milliseconds_enabled, + descriptionId = enable_or_disable_milliseconds_on_hit_timer_page, + dialog = { hideDialog -> + HitTimerMillisecondsEnabledDialog( + hitTimerMillisecondsEnabled, + hitTimerMillisecondsEnabledList, + setHitTimerMillisecondsEnabled, + hideDialog + ) + } + ) +} + +@Preview +@Composable +private fun HitTimerMillisecondsEnabledDialog( + initialHitTimerMillisecondsEnabled: String = "", + hitTimerMillisecondsEnabledList: List = listOf(), + setHitTimerMillisecondsEnabled: (String) -> Unit = {}, + onDismiss: () -> Unit = {}, +) { + SelectFromListDialog( + initialValue = initialHitTimerMillisecondsEnabled, + possibleValues = hitTimerMillisecondsEnabledList, + setValue = setHitTimerMillisecondsEnabled, + onDismiss = onDismiss, + label = hit_timer_milliseconds_enabled + ) +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/MillisecondsBarEnabledListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/MillisecondsBarEnabledListItem.kt new file mode 100644 index 00000000..6bc5659a --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/MillisecondsBarEnabledListItem.kt @@ -0,0 +1,41 @@ +package br.com.colman.petals.settings.view.listitem + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import br.com.colman.petals.R.string.enable_or_disable_milliseconds_bar_on_home_page +import br.com.colman.petals.R.string.milliseconds_enabled +import br.com.colman.petals.settings.view.dialog.SelectFromListDialog +import compose.icons.TablerIcons +import compose.icons.tablericons.CircleOff + +@Preview +@Composable +fun MillisecondsBarEnabledListItem( + millisEnabled: String = "", + millisOptions: List = listOf(), + setMillisEnabled: (String) -> Unit = {} +) { + DialogListItem( + icon = TablerIcons.CircleOff, + textId = milliseconds_enabled, + descriptionId = enable_or_disable_milliseconds_bar_on_home_page, + dialog = { hideDialog -> MillisecondsEnabledDialog(millisEnabled, millisOptions, setMillisEnabled, hideDialog) } + ) +} + +@Preview +@Composable +private fun MillisecondsEnabledDialog( + initialMillisecondsEnabled: String = "", + millisecondsEnabledList: List = listOf(), + setMillisecondsEnabled: (String) -> Unit = {}, + onDismiss: () -> Unit = {}, +) { + SelectFromListDialog( + initialValue = initialMillisecondsEnabled, + possibleValues = millisecondsEnabledList, + setValue = setMillisecondsEnabled, + onDismiss = onDismiss, + label = milliseconds_enabled + ) +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/PinListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/PinListItem.kt new file mode 100644 index 00000000..c6926ed5 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/PinListItem.kt @@ -0,0 +1,36 @@ +package br.com.colman.petals.settings.view.listitem + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import br.com.colman.petals.R.string.app_pin +import br.com.colman.petals.R.string.password_description +import br.com.colman.petals.settings.view.dialog.TextfieldDialog +import compose.icons.TablerIcons +import compose.icons.tablericons.Lock + +@Preview +@Composable +fun PinListItem(setPin: (String?) -> Unit = {}) { + DialogListItem( + icon = TablerIcons.Lock, + descriptionId = password_description, + textId = app_pin, + dialog = { hideDialog -> PinDialog(setPin, hideDialog) } + ) +} + +@Preview +@Composable +private fun PinDialog( + setPin: (String?) -> Unit = {}, + onDismiss: () -> Unit = {}, +) { + fun setValue(value: String) = if (value.isEmpty()) setPin(null) else setPin(value) + + TextfieldDialog( + initialValue = "", + setValue = { setValue(it) }, + onDismiss = onDismiss, + resourceLabel = app_pin + ) +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/PrecisionListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/PrecisionListItem.kt new file mode 100644 index 00000000..c6818cc9 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/PrecisionListItem.kt @@ -0,0 +1,41 @@ +package br.com.colman.petals.settings.view.listitem + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import br.com.colman.petals.R.string.decimal_precision +import br.com.colman.petals.R.string.what_decimal_precision_should_be_used +import br.com.colman.petals.settings.view.dialog.SelectFromListDialog +import compose.icons.TablerIcons +import compose.icons.tablericons.Calculator + +@Preview +@Composable +fun PrecisionListItem( + decimalPrecision: Int = 2, + decimalPrecisionList: List = listOf(), + setDecimalPrecision: (Int) -> Unit = {} +) { + DialogListItem( + icon = TablerIcons.Calculator, + textId = decimal_precision, + descriptionId = what_decimal_precision_should_be_used, + dialog = { hideDialog -> PrecisionDialog(decimalPrecision, decimalPrecisionList, setDecimalPrecision, hideDialog) } + ) +} + +@Preview +@Composable +private fun PrecisionDialog( + initialDecimalPrecision: Int = 2, + decimalPrecisionList: List = listOf(), + setDecimalPrecision: (Int) -> Unit = {}, + onDismiss: () -> Unit = {}, +) { + SelectFromListDialog( + initialValue = initialDecimalPrecision.toString(), + possibleValues = decimalPrecisionList.map { "$it" }, + setValue = { setDecimalPrecision(it.toInt()) }, + onDismiss = onDismiss, + label = decimal_precision + ) +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/RepositoryListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/RepositoryListItem.kt new file mode 100644 index 00000000..6083f3da --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/RepositoryListItem.kt @@ -0,0 +1,34 @@ +@file:OptIn(ExperimentalMaterialApi::class) + +package br.com.colman.petals.settings.view.listitem + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.size +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.ListItem +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import br.com.colman.petals.R.string +import compose.icons.TablerIcons +import compose.icons.tablericons.BrandGithub + +@Preview +@Composable +fun RepositoryListItem() { + val uriHandler = LocalUriHandler.current + val openProjectPage = { uriHandler.openUri("https://github.com/LeoColman/Petals") } + + ListItem( + modifier = Modifier.clickable { openProjectPage() }, + icon = { Icon(TablerIcons.BrandGithub, null, Modifier.size(42.dp)) }, + secondaryText = { Text(stringResource(string.repository_link_description)) } + ) { + Text(stringResource(string.repository_link_title)) + } +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/ShareAppListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/ShareAppListItem.kt new file mode 100644 index 00000000..01edc4e2 --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/ShareAppListItem.kt @@ -0,0 +1,49 @@ +@file:OptIn(ExperimentalMaterialApi::class) + +package br.com.colman.petals.settings.view.listitem + +import android.content.Context +import android.content.Intent +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.size +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.ListItem +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Share +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat +import br.com.colman.petals.R.string + +@Preview +@Composable +fun ShareApp( + shareIcon: ImageVector = Icons.Default.Share, + context: Context = LocalContext.current +) { + val sendIntent: Intent = Intent().apply { + action = Intent.ACTION_SEND + putExtra( + Intent.EXTRA_TEXT, + stringResource(string.share_app_message) + ) + type = "text/plain" + } + val shareIntent = Intent.createChooser(sendIntent, null) + ListItem( + modifier = Modifier.clickable { + ContextCompat.startActivity(context, shareIntent, null) + }, + icon = { Icon(shareIcon, null, Modifier.size(42.dp)) }, + secondaryText = { Text(stringResource(string.share_app)) } + ) { + Text(stringResource(string.share_app_title)) + } +} diff --git a/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/TimeListItem.kt b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/TimeListItem.kt new file mode 100644 index 00000000..e6719bfe --- /dev/null +++ b/app/src/main/kotlin/br/com/colman/petals/settings/view/listitem/TimeListItem.kt @@ -0,0 +1,41 @@ +package br.com.colman.petals.settings.view.listitem + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import br.com.colman.petals.R.string.time_format_label +import br.com.colman.petals.R.string.what_time_format_should_be_used +import br.com.colman.petals.settings.view.dialog.SelectFromListDialog +import compose.icons.TablerIcons +import compose.icons.tablericons.Clock + +@Preview +@Composable +fun TimeListItem( + timeFormat: String = "", + timeFormatList: List = listOf(), + setTimeFormat: (String) -> Unit = {} +) { + DialogListItem( + icon = TablerIcons.Clock, + textId = what_time_format_should_be_used, + descriptionId = time_format_label, + dialog = { hideDialog -> TimeDialog(timeFormat, timeFormatList, setTimeFormat, hideDialog) } + ) +} + +@Preview +@Composable +private fun TimeDialog( + initialTimeFormat: String = "", + timeFormatList: List = listOf(), + setTimeFormat: (String) -> Unit = {}, + onDismiss: () -> Unit = {}, +) { + SelectFromListDialog( + initialValue = initialTimeFormat, + possibleValues = timeFormatList, + setValue = setTimeFormat, + onDismiss = onDismiss, + label = time_format_label + ) +}