Format time as a separate setting

This commit is contained in:
Sad Ellie 2023-04-04 19:15:34 +03:00
parent ff48ac6444
commit 82a4f4ad0a
8 changed files with 70 additions and 38 deletions

View File

@ -1243,6 +1243,8 @@
<string name="unit_groups_setting">Unit groups</string> <string name="unit_groups_setting">Unit groups</string>
<string name="enable_vibrations">Vibrations</string> <string name="enable_vibrations">Vibrations</string>
<string name="enable_vibrations_support">Haptic feedback when clicking keyboard buttons</string> <string name="enable_vibrations_support">Haptic feedback when clicking keyboard buttons</string>
<string name="format_time">Format time</string>
<string name="format_time_support">Example: Show 130 minutes as 2h 10m</string>
<string name="currency_rates_note_setting">Wrong currency rates?</string> <string name="currency_rates_note_setting">Wrong currency rates?</string>
<string name="currency_rates_note_title">Note</string> <string name="currency_rates_note_title">Note</string>
<string name="currency_rates_note_text">Currency rates are updated daily. There\'s no real-time market monitoring in the app</string> <string name="currency_rates_note_text">Currency rates are updated daily. There\'s no real-time market monitoring in the app</string>

View File

@ -21,7 +21,7 @@ package com.sadellie.unitto.data.units
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, R> combine( fun <T1, T2, T3, T4, T5, T6, T7, T8, R> combine(
flow: Flow<T1>, flow: Flow<T1>,
flow2: Flow<T2>, flow2: Flow<T2>,
flow3: Flow<T3>, flow3: Flow<T3>,
@ -30,10 +30,9 @@ fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, R> combine(
flow6: Flow<T6>, flow6: Flow<T6>,
flow7: Flow<T7>, flow7: Flow<T7>,
flow8: Flow<T8>, flow8: Flow<T8>,
flow9: Flow<T9>, transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R
transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8, T9) -> R
): Flow<R> = ): Flow<R> =
kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8, flow9) { args: Array<*> -> kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8) { args: Array<*> ->
transform( transform(
args[0] as T1, args[0] as T1,
args[1] as T2, args[1] as T2,
@ -43,6 +42,5 @@ fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, R> combine(
args[5] as T6, args[5] as T6,
args[6] as T7, args[6] as T7,
args[7] as T8, args[7] as T8,
args[8] as T9,
) )
} }

View File

@ -56,6 +56,7 @@ import javax.inject.Inject
* @property enableToolsExperiment When true will enable experimental Tools screen. * @property enableToolsExperiment When true will enable experimental Tools screen.
* @property radianMode AngleMode in mxParser. When true - Radian, when False - Degree. * @property radianMode AngleMode in mxParser. When true - Radian, when False - Degree.
* @property unitConverterFavoritesOnly If true will show only units that are marked as favorite. * @property unitConverterFavoritesOnly If true will show only units that are marked as favorite.
* @property unitConverterFormatTime If true will format time to be more human readable
*/ */
data class UserPreferences( data class UserPreferences(
val themingMode: ThemingMode? = null, val themingMode: ThemingMode? = null,
@ -71,7 +72,8 @@ data class UserPreferences(
val enableToolsExperiment: Boolean = false, val enableToolsExperiment: Boolean = false,
val startingScreen: String = TopLevelDestinations.Converter.route, val startingScreen: String = TopLevelDestinations.Converter.route,
val radianMode: Boolean = true, val radianMode: Boolean = true,
val unitConverterFavoritesOnly: Boolean = false val unitConverterFavoritesOnly: Boolean = false,
val unitConverterFormatTime: Boolean = false,
) )
/** /**
@ -96,6 +98,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
val STARTING_SCREEN = stringPreferencesKey("STARTING_SCREEN_PREF_KEY") val STARTING_SCREEN = stringPreferencesKey("STARTING_SCREEN_PREF_KEY")
val RADIAN_MODE = booleanPreferencesKey("RADIAN_MODE_PREF_KEY") val RADIAN_MODE = booleanPreferencesKey("RADIAN_MODE_PREF_KEY")
val UNIT_CONVERTER_FAVORITES_ONLY = booleanPreferencesKey("UNIT_CONVERTER_FAVORITES_ONLY_PREF_KEY") val UNIT_CONVERTER_FAVORITES_ONLY = booleanPreferencesKey("UNIT_CONVERTER_FAVORITES_ONLY_PREF_KEY")
val UNIT_CONVERTER_FORMAT_TIME = booleanPreferencesKey("UNIT_CONVERTER_FORMAT_TIME_PREF_KEY")
} }
val userPreferencesFlow: Flow<UserPreferences> = dataStore.data val userPreferencesFlow: Flow<UserPreferences> = dataStore.data
@ -142,6 +145,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
val startingScreen: String = preferences[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.Converter.route val startingScreen: String = preferences[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.Converter.route
val radianMode: Boolean = preferences[PrefsKeys.RADIAN_MODE] ?: true val radianMode: Boolean = preferences[PrefsKeys.RADIAN_MODE] ?: true
val unitConverterFavoritesOnly: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] ?: false val unitConverterFavoritesOnly: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] ?: false
val unitConverterFormatTime: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] ?: false
UserPreferences( UserPreferences(
themingMode = themingMode, themingMode = themingMode,
@ -157,7 +161,8 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
enableToolsExperiment = enableToolsExperiment, enableToolsExperiment = enableToolsExperiment,
startingScreen = startingScreen, startingScreen = startingScreen,
radianMode = radianMode, radianMode = radianMode,
unitConverterFavoritesOnly = unitConverterFavoritesOnly unitConverterFavoritesOnly = unitConverterFavoritesOnly,
unitConverterFormatTime = unitConverterFormatTime,
) )
} }
@ -301,4 +306,15 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] = enabled preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] = enabled
} }
} }
/**
* Update [UserPreferences.unitConverterFormatTime].
*
* @see UserPreferences.unitConverterFormatTime
*/
suspend fun updateUnitConverterFormatTime(enabled: Boolean) {
dataStore.edit { preferences ->
preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] = enabled
}
}
} }

View File

@ -62,7 +62,6 @@ internal fun ConverterRoute(
processInput = viewModel::processInput, processInput = viewModel::processInput,
deleteDigit = viewModel::deleteDigit, deleteDigit = viewModel::deleteDigit,
clearInput = viewModel::clearInput, clearInput = viewModel::clearInput,
onOutputTextFieldClick = viewModel::toggleFormatTime
) )
} }
@ -77,7 +76,6 @@ private fun ConverterScreen(
processInput: (String) -> Unit, processInput: (String) -> Unit,
deleteDigit: () -> Unit, deleteDigit: () -> Unit,
clearInput: () -> Unit, clearInput: () -> Unit,
onOutputTextFieldClick: () -> Unit
) { ) {
UnittoScreenWithTopBar( UnittoScreenWithTopBar(
title = { Text(stringResource(R.string.unit_converter)) }, title = { Text(stringResource(R.string.unit_converter)) },
@ -109,8 +107,7 @@ private fun ConverterScreen(
navigateToRightScreen = navigateToRightScreen, navigateToRightScreen = navigateToRightScreen,
swapUnits = swapMeasurements, swapUnits = swapMeasurements,
converterMode = uiState.mode, converterMode = uiState.mode,
formatTime = uiState.formatTime, formatTime = uiState.formatTime
onOutputTextFieldClick = onOutputTextFieldClick
) )
}, },
content2 = { content2 = {
@ -156,6 +153,5 @@ private fun PreviewConverterScreen(
processInput = {}, processInput = {},
deleteDigit = {}, deleteDigit = {},
clearInput = {}, clearInput = {},
onOutputTextFieldClick = {}
) )
} }

View File

@ -110,8 +110,6 @@ class ConverterViewModel @Inject constructor(
*/ */
private val _showError: MutableStateFlow<Boolean> = MutableStateFlow(false) private val _showError: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val _formatTime: MutableStateFlow<Boolean> = MutableStateFlow(true)
/** /**
* Current state of UI. * Current state of UI.
*/ */
@ -123,9 +121,8 @@ class ConverterViewModel @Inject constructor(
_result, _result,
_showLoading, _showLoading,
_showError, _showError,
_formatTime,
_userPrefs _userPrefs
) { inputValue, unitFromValue, unitToValue, calculatedValue, resultValue, showLoadingValue, showErrorValue, formatTime, prefs -> ) { inputValue, unitFromValue, unitToValue, calculatedValue, resultValue, showLoadingValue, showErrorValue, prefs ->
return@combine ConverterUIState( return@combine ConverterUIState(
inputValue = inputValue, inputValue = inputValue,
calculatedValue = calculatedValue, calculatedValue = calculatedValue,
@ -139,7 +136,7 @@ class ConverterViewModel @Inject constructor(
* changing units. * changing units.
*/ */
mode = if (_unitFrom.value is NumberBaseUnit) ConverterMode.BASE else ConverterMode.DEFAULT, mode = if (_unitFrom.value is NumberBaseUnit) ConverterMode.BASE else ConverterMode.DEFAULT,
formatTime = formatTime, formatTime = prefs.unitConverterFormatTime,
allowVibration = prefs.enableVibrations allowVibration = prefs.enableVibrations
) )
} }
@ -373,10 +370,6 @@ class ConverterViewModel @Inject constructor(
setInputSymbols(Token._0, false) setInputSymbols(Token._0, false)
} }
fun toggleFormatTime() {
_formatTime.update { !it }
}
private suspend fun convertInput() { private suspend fun convertInput() {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
while (isActive) { while (isActive) {

View File

@ -77,7 +77,6 @@ import com.sadellie.unitto.feature.converter.ConverterMode
* @param swapUnits Method to swap units. * @param swapUnits Method to swap units.
* @param converterMode [ConverterMode.BASE] doesn't use formatting for input/output. * @param converterMode [ConverterMode.BASE] doesn't use formatting for input/output.
* @param formatTime If True will use [Formatter.formatTime]. * @param formatTime If True will use [Formatter.formatTime].
* @param onOutputTextFieldClick Action to be called when user clicks on output text field.
*/ */
@Composable @Composable
internal fun TopScreenPart( internal fun TopScreenPart(
@ -94,7 +93,6 @@ internal fun TopScreenPart(
swapUnits: () -> Unit, swapUnits: () -> Unit,
converterMode: ConverterMode, converterMode: ConverterMode,
formatTime: Boolean, formatTime: Boolean,
onOutputTextFieldClick: () -> Unit
) { ) {
var swapped by remember { mutableStateOf(false) } var swapped by remember { mutableStateOf(false) }
val swapButtonRotation: Float by animateFloatAsState( val swapButtonRotation: Float by animateFloatAsState(

View File

@ -27,6 +27,7 @@ import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Palette import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.RateReview import androidx.compose.material.icons.filled.RateReview
import androidx.compose.material.icons.filled.Rule import androidx.compose.material.icons.filled.Rule
import androidx.compose.material.icons.filled.Timer
import androidx.compose.material.icons.filled.Vibration import androidx.compose.material.icons.filled.Vibration
import androidx.compose.material.icons.filled._123 import androidx.compose.material.icons.filled._123
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@ -76,21 +77,6 @@ internal fun SettingsScreen(
) { padding -> ) { padding ->
LazyColumn(contentPadding = padding) { LazyColumn(contentPadding = padding) {
// UNIT GROUPS
item {
ListItem(
leadingContent = {
Icon(
Icons.Default.Rule,
stringResource(R.string.disable_unit_group_description),
)
},
headlineText = { Text(stringResource(R.string.unit_groups_setting)) },
supportingText = { Text(stringResource(R.string.unit_groups_support)) },
modifier = Modifier.clickable { navControllerAction(unitsGroupRoute) }
)
}
// THEME // THEME
item { item {
ListItem( ListItem(
@ -161,6 +147,40 @@ internal fun SettingsScreen(
) )
} }
// UNIT CONVERTER GROUP
item { Header(stringResource(R.string.unit_converter)) }
// UNIT GROUPS
item {
ListItem(
leadingContent = {
Icon(
Icons.Default.Rule,
stringResource(R.string.disable_unit_group_description),
)
},
headlineText = { Text(stringResource(R.string.unit_groups_setting)) },
supportingText = { Text(stringResource(R.string.unit_groups_support)) },
modifier = Modifier.clickable { navControllerAction(unitsGroupRoute) }
)
}
// FORMAT TIME
item {
UnittoListItem(
label = stringResource(R.string.format_time),
leadingContent = {
Icon(
Icons.Default.Timer,
stringResource(R.string.format_time)
)
},
supportText = stringResource(R.string.format_time_support),
switchState = userPrefs.value.unitConverterFormatTime,
onSwitchChange = viewModel::updateUnitConverterFormatTime
)
}
// ADDITIONAL GROUP // ADDITIONAL GROUP
item { Header(stringResource(R.string.additional_settings_group)) } item { Header(stringResource(R.string.additional_settings_group)) }

View File

@ -168,6 +168,15 @@ class SettingsViewModel @Inject constructor(
} }
} }
/**
* @see UserPreferencesRepository.updateUnitConverterFormatTime
*/
fun updateUnitConverterFormatTime(enabled: Boolean) {
viewModelScope.launch {
userPrefsRepository.updateUnitConverterFormatTime(enabled)
}
}
/** /**
* Prevent from dragging over non-draggable items (headers and hidden) * Prevent from dragging over non-draggable items (headers and hidden)
* *