Improved unit groups screen

Better visuals, less bugs, more animations
This commit is contained in:
Sad Ellie 2022-08-13 14:53:49 +03:00
parent eec27637c6
commit 3ba2d1d5f6
6 changed files with 127 additions and 34 deletions

View File

@ -63,8 +63,9 @@ fun SettingsScreen(
// THEME // THEME
item { item {
SettingsListItem( SettingsListItem(
label = stringResource(id = R.string.unit_groups_setting) label = stringResource(id = R.string.unit_groups_setting),
) { navControllerAction(UNIT_GROUPS_SCREEN) } onClick = { navControllerAction(UNIT_GROUPS_SCREEN) }
)
} }
// PRECISION // PRECISION
@ -102,8 +103,9 @@ fun SettingsScreen(
// CURRENCY RATE NOTE // CURRENCY RATE NOTE
item { item {
SettingsListItem( SettingsListItem(
label = stringResource(R.string.currency_rates_note_setting) label = stringResource(R.string.currency_rates_note_setting),
) { dialogState = DialogState.CURRENCY_RATE } onClick = { dialogState = DialogState.CURRENCY_RATE }
)
} }
// ADDITIONAL GROUP // ADDITIONAL GROUP
@ -112,15 +114,17 @@ fun SettingsScreen(
// TERMS AND CONDITIONS // TERMS AND CONDITIONS
item { item {
SettingsListItem( SettingsListItem(
label = stringResource(R.string.terms_and_conditions) label = stringResource(R.string.terms_and_conditions),
) { openLink(mContext, "http://sadellie.github.io/unitto/terms-app.html") } onClick = { openLink(mContext, "http://sadellie.github.io/unitto/terms-app.html") }
)
} }
// PRIVACY POLICY // PRIVACY POLICY
item { item {
SettingsListItem( SettingsListItem(
label = stringResource(R.string.privacy_policy) label = stringResource(R.string.privacy_policy),
) { openLink(mContext, "http://sadellie.github.io/unitto/privacy-app.html") } onClick = { openLink(mContext, "http://sadellie.github.io/unitto/privacy-app.html") }
)
} }
// ANALYTICS // ANALYTICS
@ -137,16 +141,18 @@ fun SettingsScreen(
// THIRD PARTY // THIRD PARTY
item { item {
SettingsListItem( SettingsListItem(
label = stringResource(R.string.third_party_licenses) label = stringResource(R.string.third_party_licenses),
) { navControllerAction(ABOUT_SCREEN) } onClick = { navControllerAction(ABOUT_SCREEN) }
)
} }
// RATE THIS APP // RATE THIS APP
if (BuildConfig.STORE_LINK.isNotEmpty()) { if (BuildConfig.STORE_LINK.isNotEmpty()) {
item { item {
SettingsListItem( SettingsListItem(
label = stringResource(R.string.rate_this_app) label = stringResource(R.string.rate_this_app),
) { openLink(mContext, BuildConfig.STORE_LINK) } onClick = { openLink(mContext, BuildConfig.STORE_LINK) }
)
} }
} }

View File

@ -21,13 +21,22 @@ package com.sadellie.unitto.screens.setttings
import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AddCircle
import androidx.compose.material.icons.filled.RemoveCircle
import androidx.compose.material.icons.filled.Reorder
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -37,6 +46,7 @@ import com.sadellie.unitto.screens.common.UnittoLargeTopAppBar
import com.sadellie.unitto.screens.second.components.Header import com.sadellie.unitto.screens.second.components.Header
import com.sadellie.unitto.screens.setttings.components.SettingsListItem import com.sadellie.unitto.screens.setttings.components.SettingsListItem
import org.burnoutcrew.reorderable.ReorderableItem import org.burnoutcrew.reorderable.ReorderableItem
import org.burnoutcrew.reorderable.detectReorder
import org.burnoutcrew.reorderable.detectReorderAfterLongPress import org.burnoutcrew.reorderable.detectReorderAfterLongPress
import org.burnoutcrew.reorderable.rememberReorderableLazyListState import org.burnoutcrew.reorderable.rememberReorderableLazyListState
import org.burnoutcrew.reorderable.reorderable import org.burnoutcrew.reorderable.reorderable
@ -64,7 +74,6 @@ fun UnitGroupsScreen(
modifier = Modifier modifier = Modifier
.padding(paddingValues) .padding(paddingValues)
.reorderable(state) .reorderable(state)
.detectReorderAfterLongPress(state)
) { ) {
item(key = "enabled") { item(key = "enabled") {
Header(text = stringResource(id = R.string.enabled_label)) Header(text = stringResource(id = R.string.enabled_label))
@ -81,10 +90,35 @@ fun UnitGroupsScreen(
modifier = Modifier modifier = Modifier
.padding(horizontal = cornerRadius.value) .padding(horizontal = cornerRadius.value)
.clip(RoundedCornerShape(cornerRadius.value)) .clip(RoundedCornerShape(cornerRadius.value))
.background(background.value), .background(background.value)
.clickable { viewModel.hideUnitGroup(item) }
.detectReorderAfterLongPress(state),
label = stringResource(item.res), label = stringResource(item.res),
leadingItem = {
Icon(
Icons.Default.RemoveCircle,
stringResource(id = R.string.disable_unit_group_description),
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(false),
onClick = { viewModel.hideUnitGroup(item) } onClick = { viewModel.hideUnitGroup(item) }
) )
)
},
trailingItem = {
Icon(
Icons.Default.Reorder,
stringResource(id = R.string.reorder_unit_group_description),
modifier = Modifier
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(false),
onClick = {}
)
.detectReorder(state)
)
}
)
} }
} }
@ -97,10 +131,23 @@ fun UnitGroupsScreen(
items(hiddenUnits.value, { it }) { items(hiddenUnits.value, { it }) {
SettingsListItem( SettingsListItem(
modifier = Modifier.animateItemPlacement(), modifier = Modifier
.background(MaterialTheme.colorScheme.surface)
.clickable { viewModel.returnUnitGroup(it) }
.animateItemPlacement(),
label = stringResource(it.res), label = stringResource(it.res),
trailingItem = {
Icon(
Icons.Default.AddCircle,
stringResource(id = R.string.enable_unit_group_description),
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(false),
onClick = { viewModel.returnUnitGroup(it) } onClick = { viewModel.returnUnitGroup(it) }
) )
)
}
)
} }
} }
} }

View File

@ -23,6 +23,7 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
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.RowScope import androidx.compose.foundation.layout.RowScope
@ -62,32 +63,27 @@ import com.sadellie.unitto.R
* @param modifier Modifier that will be applied to a Row. * @param modifier Modifier that will be applied to a Row.
* @param label Main text. * @param label Main text.
* @param supportText Text that is located below label. * @param supportText Text that is located below label.
* @param onClick Action to perform when user clicks on this component (whole component is clickable). * @param trailingItem Additional composable, icons for example.
* @param content Additional composable: buttons, switches, checkboxes or something else. * @param leadingItem Additional composable: buttons, switches, checkboxes or something else.
*/ */
@Composable @Composable
private fun BasicSettingsListItem( private fun BasicSettingsListItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
label: String, label: String,
supportText: String? = null, supportText: String? = null,
onClick: () -> Unit = {}, leadingItem: @Composable() (RowScope.() -> Unit) = {},
content: @Composable RowScope.() -> Unit = {} trailingItem: @Composable() (RowScope.() -> Unit) = {}
) { ) {
Row( Row(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(),
onClick = onClick
)
.padding(horizontal = 16.dp, vertical = 12.dp), .padding(horizontal = 16.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
leadingItem()
Column( Column(
Modifier Modifier.weight(1f), // This makes additional composable to be seen
.padding(horizontal = 0.dp)
.weight(1f) // This makes additional composable to be seen
) { ) {
Text( Text(
modifier = Modifier modifier = Modifier
@ -106,7 +102,7 @@ private fun BasicSettingsListItem(
) )
} }
} }
content() trailingItem()
} }
} }
@ -124,7 +120,15 @@ fun SettingsListItem(
label: String, label: String,
supportText: String? = null, supportText: String? = null,
onClick: () -> Unit, onClick: () -> Unit,
) = BasicSettingsListItem(modifier, label, supportText, onClick) ) = BasicSettingsListItem(
modifier = modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(),
onClick = onClick
),
label = label,
supportText = supportText
)
/** /**
* Represents one item in list on Settings screen. * Represents one item in list on Settings screen.
@ -141,7 +145,15 @@ fun SettingsListItem(
supportText: String? = null, supportText: String? = null,
switchState: Boolean, switchState: Boolean,
onSwitchChange: (Boolean) -> Unit onSwitchChange: (Boolean) -> Unit
) = BasicSettingsListItem(Modifier, label, supportText, { onSwitchChange(!switchState) }) { ) = BasicSettingsListItem(
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(),
onClick = { onSwitchChange(!switchState) }
),
label = label,
supportText = supportText
) {
Switch(checked = switchState, onCheckedChange = { onSwitchChange(it) }) Switch(checked = switchState, onCheckedChange = { onSwitchChange(it) })
} }
@ -162,7 +174,7 @@ fun <T> SettingsListItem(
allOptions: Map<T, String>, allOptions: Map<T, String>,
selected: T, selected: T,
onSelectedChange: (T) -> Unit onSelectedChange: (T) -> Unit
) = BasicSettingsListItem(Modifier, label, supportText, {}) { ) = BasicSettingsListItem(Modifier, label, supportText) {
var dropDownExpanded by rememberSaveable { mutableStateOf(false) } var dropDownExpanded by rememberSaveable { mutableStateOf(false) }
var currentOption by rememberSaveable { mutableStateOf(selected) } var currentOption by rememberSaveable { mutableStateOf(selected) }
val dropDownRotation: Float by animateFloatAsState( val dropDownRotation: Float by animateFloatAsState(
@ -213,3 +225,21 @@ fun <T> SettingsListItem(
} }
} }
} }
/**
* Composable with leading and trailing items.
*
* @param label Main text.
* @param modifier Modifier that will be applied to a Row.
* @param trailingItem Additional composable, icons for example.
* @param leadingItem Additional composable: buttons, switches, checkboxes or something else.
*/
@Composable
fun SettingsListItem(
label: String,
modifier: Modifier = Modifier,
leadingItem: @Composable RowScope.() -> Unit = {},
trailingItem: @Composable RowScope.() -> Unit = {}
) {
BasicSettingsListItem(modifier = modifier, label = label, trailingItem = trailingItem, leadingItem = leadingItem)
}

View File

@ -745,5 +745,8 @@
<string name="search_placeholder_button_label">Open settings</string> <string name="search_placeholder_button_label">Open settings</string>
<string name="enabled_label">Enabled</string> <string name="enabled_label">Enabled</string>
<string name="disabled_label">Disabled</string> <string name="disabled_label">Disabled</string>
<string name="enable_unit_group_description">Enable unit group</string>
<string name="disable_unit_group_description">Disable unit group</string>
<string name="reorder_unit_group_description">Reorder unit group</string>
</resources> </resources>

View File

@ -680,5 +680,8 @@
<string name="search_placeholder_button_label">Открыть настройки</string> <string name="search_placeholder_button_label">Открыть настройки</string>
<string name="enabled_label">Включено</string> <string name="enabled_label">Включено</string>
<string name="disabled_label">Отключено</string> <string name="disabled_label">Отключено</string>
<string name="enable_unit_group_description">Включить группу величин</string>
<string name="disable_unit_group_description">Отключить группу величин</string>
<string name="reorder_unit_group_description">Переместить группу величин</string>
</resources> </resources>

View File

@ -1020,6 +1020,10 @@
<string name="favorite_button_description">Add or remove unit from favorites</string> <string name="favorite_button_description">Add or remove unit from favorites</string>
<string name="empty_search_result_description">Empty search result</string> <string name="empty_search_result_description">Empty search result</string>
<string name="drop_down_description">Open or close drop down menu</string> <string name="drop_down_description">Open or close drop down menu</string>
<string name="enable_unit_group_description">Enable unit group</string>
<string name="reorder_unit_group_description">Reorder unit group</string>
<string name="disable_unit_group_description">Disable unit group</string>
<string name="send_usage_statistics">Send usage statistics</string> <string name="send_usage_statistics">Send usage statistics</string>
<string name="send_usage_statistics_support">All data is anonymous and encrypted</string> <string name="send_usage_statistics_support">All data is anonymous and encrypted</string>
<string name="app_version_name_setting">Version name</string> <string name="app_version_name_setting">Version name</string>