diff --git a/core/base/src/main/res/values/strings.xml b/core/base/src/main/res/values/strings.xml
index 78978fe1..ab3740f5 100644
--- a/core/base/src/main/res/values/strings.xml
+++ b/core/base/src/main/res/values/strings.xml
@@ -1245,6 +1245,8 @@
Haptic feedback when clicking keyboard buttons
Format time
Example: Show 130 minutes as 2h 10m
+ Units list sorting
+ Change units order
Wrong currency rates?
Note
Currency rates are updated daily. There\'s no real-time market monitoring in the app
@@ -1303,6 +1305,12 @@
Allow engineering
Force engineering
+
+ Usage
+ Alphabetical
+ Scale (Desc.)
+ Scale (Asc.)
+
App look and feel
Auto
diff --git a/data/model/src/main/java/com/sadellie/unitto/data/model/UnitsListSorting.kt b/data/model/src/main/java/com/sadellie/unitto/data/model/UnitsListSorting.kt
new file mode 100644
index 00000000..a2689d24
--- /dev/null
+++ b/data/model/src/main/java/com/sadellie/unitto/data/model/UnitsListSorting.kt
@@ -0,0 +1,21 @@
+/*
+ * Unitto is a unit converter for Android
+ * Copyright (c) 2023 Elshan Agaev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sadellie.unitto.data.model
+
+enum class UnitsListSorting { USAGE, ALPHABETICAL, SCALE_DESC, SCALE_ASC }
diff --git a/data/units/src/main/java/com/sadellie/unitto/data/units/AllUnitsRepository.kt b/data/units/src/main/java/com/sadellie/unitto/data/units/AllUnitsRepository.kt
index d8d7e1b8..83e22057 100644
--- a/data/units/src/main/java/com/sadellie/unitto/data/units/AllUnitsRepository.kt
+++ b/data/units/src/main/java/com/sadellie/unitto/data/units/AllUnitsRepository.kt
@@ -23,6 +23,7 @@ import com.sadellie.unitto.core.base.MAX_PRECISION
import com.sadellie.unitto.data.database.UnitsEntity
import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.UnitGroup
+import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.sortByLev
import com.sadellie.unitto.data.units.collections.accelerationCollection
import com.sadellie.unitto.data.units.collections.angleCollection
@@ -129,6 +130,8 @@ class AllUnitsRepository @Inject constructor() {
* set to True.
* @param searchQuery When not empty, will search by [AbstractUnit.renderedName] using [sortByLev].
* @param allUnitsGroups All [UnitGroup]s. Determines which units will be used for filtering.
+ * @param sorting Sorting mode from [UnitsListSorting]
+ *
* @return Grouped by [UnitGroup] list of [AbstractUnit]s.
*/
fun filterUnits(
@@ -136,9 +139,11 @@ class AllUnitsRepository @Inject constructor() {
chosenUnitGroup: UnitGroup?,
favoritesOnly: Boolean,
searchQuery: String,
- allUnitsGroups: List
+ allUnitsGroups: List,
+ sorting: UnitsListSorting = UnitsListSorting.USAGE
): Map> {
- var basicFilteredUnits: Sequence = if (chosenUnitGroup == null) {
+ // Leave only shown unit groups
+ var units: Sequence = if (chosenUnitGroup == null) {
allUnits.filter { it.group in allUnitsGroups }
} else {
val collection = getCollectionByGroup(chosenUnitGroup)
@@ -146,20 +151,27 @@ class AllUnitsRepository @Inject constructor() {
}.asSequence()
if (favoritesOnly) {
- basicFilteredUnits = basicFilteredUnits.filter { it.isFavorite }
+ units = units.filter { it.isFavorite }
}
if (hideBrokenCurrencies) {
- basicFilteredUnits = basicFilteredUnits.filter { it.isEnabled }
- }
- val unitsToShow = if (searchQuery.isEmpty()) {
- // Query is empty, i.e. we want to see all units and they need to be sorted by usage
- basicFilteredUnits.sortedByDescending { it.counter }
- } else {
- // We sort by popularity and Levenshtein distance (short and long name).
- basicFilteredUnits.sortedByDescending { it.counter }.sortByLev(searchQuery)
+ units = units.filter { it.isEnabled }
}
- return unitsToShow.groupBy { it.group }
+ units = when (sorting) {
+ UnitsListSorting.USAGE -> units.sortedByDescending { it.counter }
+ UnitsListSorting.ALPHABETICAL -> units.sortedBy { it.renderedName }
+ UnitsListSorting.SCALE_ASC -> units.sortedBy { it.basicUnit }
+ UnitsListSorting.SCALE_DESC -> units.sortedByDescending { it.basicUnit }
+ }
+
+ units = if (searchQuery.isEmpty()) {
+ units.sortedByDescending { it.isFavorite }
+ } else {
+ // For search we sort by popularity and Levenshtein distance (short and long name).
+ units.sortByLev(searchQuery)
+ }
+
+ return units.groupBy { it.group }
}
/**
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 741b2166..5942b3ff 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
@@ -31,6 +31,7 @@ import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.UnitGroup
+import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.units.MyUnitIDS
import io.github.sadellie.themmo.ThemingMode
import kotlinx.coroutines.flow.Flow
@@ -56,7 +57,8 @@ 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
+ * @property unitConverterFormatTime If true will format time to be more human readable.
+ * @property unitConverterSorting Units list sorting mode.
*/
data class UserPreferences(
val themingMode: ThemingMode? = null,
@@ -74,6 +76,7 @@ data class UserPreferences(
val radianMode: Boolean = true,
val unitConverterFavoritesOnly: Boolean = false,
val unitConverterFormatTime: Boolean = false,
+ val unitConverterSorting: UnitsListSorting = UnitsListSorting.USAGE,
)
/**
@@ -99,6 +102,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
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 UNIT_CONVERTER_SORTING = stringPreferencesKey("UNIT_CONVERTER_SORTING_PREF_KEY")
}
val userPreferencesFlow: Flow = dataStore.data
@@ -146,6 +150,8 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
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
+ val unitConverterSorting: UnitsListSorting = preferences[PrefsKeys.UNIT_CONVERTER_SORTING]?.let { UnitsListSorting.valueOf(it) }
+ ?: UnitsListSorting.USAGE
UserPreferences(
themingMode = themingMode,
@@ -163,6 +169,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
radianMode = radianMode,
unitConverterFavoritesOnly = unitConverterFavoritesOnly,
unitConverterFormatTime = unitConverterFormatTime,
+ unitConverterSorting = unitConverterSorting
)
}
@@ -317,4 +324,15 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] = enabled
}
}
+
+ /**
+ * Update [UserPreferences.unitConverterSorting].
+ *
+ * @see UserPreferences.unitConverterSorting
+ */
+ suspend fun updateUnitConverterSorting(sorting: UnitsListSorting) {
+ dataStore.edit { preferences ->
+ preferences[PrefsKeys.UNIT_CONVERTER_SORTING] = sorting.name
+ }
+ }
}
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 7073da12..4b287ed9 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.Sort
import androidx.compose.material.icons.filled.Timer
import androidx.compose.material.icons.filled.Vibration
import androidx.compose.material.icons.filled._123
@@ -51,9 +52,10 @@ import com.sadellie.unitto.core.base.TOP_LEVEL_DESTINATIONS
import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.core.ui.common.Header
import com.sadellie.unitto.core.ui.common.MenuButton
-import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.common.UnittoListItem
+import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.openLink
+import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.feature.settings.components.AlertDialogWithList
import com.sadellie.unitto.feature.settings.navigation.aboutRoute
import com.sadellie.unitto.feature.settings.navigation.themesRoute
@@ -165,6 +167,21 @@ internal fun SettingsScreen(
)
}
+ // UNITS LIST SORTING
+ item {
+ ListItem(
+ leadingContent = {
+ Icon(
+ Icons.Default.Sort,
+ stringResource(R.string.units_sorting)
+ )
+ },
+ headlineText = { Text(stringResource(R.string.units_sorting)) },
+ supportingText = { Text(stringResource(R.string.units_sorting_support)) },
+ modifier = Modifier.clickable { dialogState = DialogState.UNIT_LIST_SORTING }
+ )
+ }
+
// FORMAT TIME
item {
UnittoListItem(
@@ -280,6 +297,20 @@ internal fun SettingsScreen(
dismissAction = { resetDialog() }
)
}
+ DialogState.UNIT_LIST_SORTING -> {
+ AlertDialogWithList(
+ title = stringResource(R.string.units_sorting),
+ listItems = mapOf(
+ UnitsListSorting.USAGE to R.string.sort_by_usage,
+ UnitsListSorting.ALPHABETICAL to R.string.sort_by_alphabetical,
+ UnitsListSorting.SCALE_DESC to R.string.sort_by_scale_desc,
+ UnitsListSorting.SCALE_ASC to R.string.sort_by_scale_asc,
+ ),
+ selectedItemIndex = userPrefs.value.unitConverterSorting,
+ selectAction = viewModel::updateUnitConverterSorting,
+ dismissAction = { resetDialog() }
+ )
+ }
// Dismissing alert dialog
else -> {}
}
@@ -289,5 +320,5 @@ internal fun SettingsScreen(
* All possible states for alert dialog that opens when user clicks on settings.
*/
private enum class DialogState {
- NONE, PRECISION, SEPARATOR, OUTPUT_FORMAT, START_SCREEN
+ NONE, PRECISION, SEPARATOR, OUTPUT_FORMAT, START_SCREEN, UNIT_LIST_SORTING
}
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 07740129..6f4ebfc4 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
@@ -22,6 +22,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.ui.Formatter
import com.sadellie.unitto.data.model.UnitGroup
+import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.unitgroups.UnitGroupsRepository
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -177,6 +178,15 @@ class SettingsViewModel @Inject constructor(
}
}
+ /**
+ * @see UserPreferencesRepository.updateUnitConverterSorting
+ */
+ fun updateUnitConverterSorting(sorting: UnitsListSorting) {
+ viewModelScope.launch {
+ userPrefsRepository.updateUnitConverterSorting(sorting)
+ }
+ }
+
/**
* Prevent from dragging over non-draggable items (headers and hidden)
*
diff --git a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/UnitsListViewModel.kt b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/UnitsListViewModel.kt
index dab4dbc6..af2fea90 100644
--- a/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/UnitsListViewModel.kt
+++ b/feature/unitslist/src/main/java/com/sadellie/unitto/feature/unitslist/UnitsListViewModel.kt
@@ -134,7 +134,8 @@ class UnitsListViewModel @Inject constructor(
chosenUnitGroup = _chosenUnitGroup.value,
favoritesOnly = _userPrefs.value.unitConverterFavoritesOnly,
searchQuery = _searchQuery.value,
- allUnitsGroups = _shownUnitGroups.value
+ allUnitsGroups = _shownUnitGroups.value,
+ sorting = _userPrefs.value.unitConverterSorting
)
_unitsToShow.update { unitsToShow }