diff --git a/core/base/src/main/res/values/strings.xml b/core/base/src/main/res/values/strings.xml index 1ddab2a9..78978fe1 100644 --- a/core/base/src/main/res/values/strings.xml +++ b/core/base/src/main/res/values/strings.xml @@ -1243,6 +1243,8 @@ Unit groups Vibrations Haptic feedback when clicking keyboard buttons + Format time + Example: Show 130 minutes as 2h 10m Wrong currency rates? Note Currency rates are updated daily. There\'s no real-time market monitoring in the app diff --git a/data/units/src/main/java/com/sadellie/unitto/data/units/FlowUtils.kt b/data/units/src/main/java/com/sadellie/unitto/data/units/FlowUtils.kt index fd1ffa2d..83f5f89f 100644 --- a/data/units/src/main/java/com/sadellie/unitto/data/units/FlowUtils.kt +++ b/data/units/src/main/java/com/sadellie/unitto/data/units/FlowUtils.kt @@ -21,7 +21,7 @@ package com.sadellie.unitto.data.units import kotlinx.coroutines.flow.Flow @Suppress("UNCHECKED_CAST") -fun combine( +fun combine( flow: Flow, flow2: Flow, flow3: Flow, @@ -30,10 +30,9 @@ fun combine( flow6: Flow, flow7: Flow, flow8: Flow, - flow9: Flow, - transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8, T9) -> R + transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R ): Flow = - 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( args[0] as T1, args[1] as T2, @@ -43,6 +42,5 @@ fun combine( args[5] as T6, args[6] as T7, args[7] as T8, - args[8] as T9, ) } diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt index cd1ae09e..741b2166 100644 --- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt +++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt @@ -56,6 +56,7 @@ import javax.inject.Inject * @property enableToolsExperiment When true will enable experimental Tools screen. * @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 unitConverterFormatTime If true will format time to be more human readable */ data class UserPreferences( val themingMode: ThemingMode? = null, @@ -71,7 +72,8 @@ data class UserPreferences( val enableToolsExperiment: Boolean = false, val startingScreen: String = TopLevelDestinations.Converter.route, 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 RADIAN_MODE = booleanPreferencesKey("RADIAN_MODE_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 = 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 radianMode: Boolean = preferences[PrefsKeys.RADIAN_MODE] ?: true val unitConverterFavoritesOnly: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] ?: false + val unitConverterFormatTime: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] ?: false UserPreferences( themingMode = themingMode, @@ -157,7 +161,8 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS enableToolsExperiment = enableToolsExperiment, startingScreen = startingScreen, 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 } } + + /** + * Update [UserPreferences.unitConverterFormatTime]. + * + * @see UserPreferences.unitConverterFormatTime + */ + suspend fun updateUnitConverterFormatTime(enabled: Boolean) { + dataStore.edit { preferences -> + preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] = enabled + } + } } diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt index 697ba53e..23465338 100644 --- a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterScreen.kt @@ -62,7 +62,6 @@ internal fun ConverterRoute( processInput = viewModel::processInput, deleteDigit = viewModel::deleteDigit, clearInput = viewModel::clearInput, - onOutputTextFieldClick = viewModel::toggleFormatTime ) } @@ -77,7 +76,6 @@ private fun ConverterScreen( processInput: (String) -> Unit, deleteDigit: () -> Unit, clearInput: () -> Unit, - onOutputTextFieldClick: () -> Unit ) { UnittoScreenWithTopBar( title = { Text(stringResource(R.string.unit_converter)) }, @@ -109,8 +107,7 @@ private fun ConverterScreen( navigateToRightScreen = navigateToRightScreen, swapUnits = swapMeasurements, converterMode = uiState.mode, - formatTime = uiState.formatTime, - onOutputTextFieldClick = onOutputTextFieldClick + formatTime = uiState.formatTime ) }, content2 = { @@ -156,6 +153,5 @@ private fun PreviewConverterScreen( processInput = {}, deleteDigit = {}, clearInput = {}, - onOutputTextFieldClick = {} ) } \ No newline at end of file diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterViewModel.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterViewModel.kt index adfa06f8..cd5b64b5 100644 --- a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterViewModel.kt +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/ConverterViewModel.kt @@ -110,8 +110,6 @@ class ConverterViewModel @Inject constructor( */ private val _showError: MutableStateFlow = MutableStateFlow(false) - private val _formatTime: MutableStateFlow = MutableStateFlow(true) - /** * Current state of UI. */ @@ -123,9 +121,8 @@ class ConverterViewModel @Inject constructor( _result, _showLoading, _showError, - _formatTime, _userPrefs - ) { inputValue, unitFromValue, unitToValue, calculatedValue, resultValue, showLoadingValue, showErrorValue, formatTime, prefs -> + ) { inputValue, unitFromValue, unitToValue, calculatedValue, resultValue, showLoadingValue, showErrorValue, prefs -> return@combine ConverterUIState( inputValue = inputValue, calculatedValue = calculatedValue, @@ -139,7 +136,7 @@ class ConverterViewModel @Inject constructor( * changing units. */ mode = if (_unitFrom.value is NumberBaseUnit) ConverterMode.BASE else ConverterMode.DEFAULT, - formatTime = formatTime, + formatTime = prefs.unitConverterFormatTime, allowVibration = prefs.enableVibrations ) } @@ -373,10 +370,6 @@ class ConverterViewModel @Inject constructor( setInputSymbols(Token._0, false) } - fun toggleFormatTime() { - _formatTime.update { !it } - } - private suspend fun convertInput() { withContext(Dispatchers.Default) { while (isActive) { diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/TopScreen.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/TopScreen.kt index aa40fe21..39f1af65 100644 --- a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/TopScreen.kt +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/TopScreen.kt @@ -77,7 +77,6 @@ import com.sadellie.unitto.feature.converter.ConverterMode * @param swapUnits Method to swap units. * @param converterMode [ConverterMode.BASE] doesn't use formatting for input/output. * @param formatTime If True will use [Formatter.formatTime]. - * @param onOutputTextFieldClick Action to be called when user clicks on output text field. */ @Composable internal fun TopScreenPart( @@ -94,7 +93,6 @@ internal fun TopScreenPart( swapUnits: () -> Unit, converterMode: ConverterMode, formatTime: Boolean, - onOutputTextFieldClick: () -> Unit ) { var swapped by remember { mutableStateOf(false) } val swapButtonRotation: Float by animateFloatAsState( diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsScreen.kt index c843c389..7073da12 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsScreen.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsScreen.kt @@ -27,6 +27,7 @@ import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Palette import androidx.compose.material.icons.filled.RateReview 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._123 import androidx.compose.material3.Icon @@ -76,21 +77,6 @@ internal fun SettingsScreen( ) { 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 item { 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 item { Header(stringResource(R.string.additional_settings_group)) } diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt index 3b3e77cf..07740129 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt @@ -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) *