Improve testability

- Use interfaces to mock objects
- Use only primitives in preferences
This commit is contained in:
Sad Ellie 2023-10-31 00:25:08 +03:00
parent e42fd625a5
commit 1475e5a948
39 changed files with 736 additions and 171 deletions

View File

@ -35,7 +35,7 @@ import com.sadellie.unitto.core.ui.LocalLocale
import com.sadellie.unitto.core.ui.theme.LocalNumberTypography import com.sadellie.unitto.core.ui.theme.LocalNumberTypography
import com.sadellie.unitto.core.ui.theme.NumberTypographySystem import com.sadellie.unitto.core.ui.theme.NumberTypographySystem
import com.sadellie.unitto.core.ui.theme.NumberTypographyUnitto import com.sadellie.unitto.core.ui.theme.NumberTypographyUnitto
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject

View File

@ -49,7 +49,9 @@ import com.sadellie.unitto.core.ui.pushDynamicShortcut
import com.sadellie.unitto.core.ui.theme.DarkThemeColors import com.sadellie.unitto.core.ui.theme.DarkThemeColors
import com.sadellie.unitto.core.ui.theme.LightThemeColors import com.sadellie.unitto.core.ui.theme.LightThemeColors
import com.sadellie.unitto.core.ui.theme.TypographySystem import com.sadellie.unitto.core.ui.theme.TypographySystem
import com.sadellie.unitto.data.userprefs.AppPreferences import com.sadellie.unitto.data.model.userprefs.AppPreferences
import io.github.sadellie.themmo.MonetMode
import io.github.sadellie.themmo.ThemingMode
import io.github.sadellie.themmo.Themmo import io.github.sadellie.themmo.Themmo
import io.github.sadellie.themmo.ThemmoController import io.github.sadellie.themmo.ThemmoController
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -80,11 +82,11 @@ internal fun UnittoApp(prefs: AppPreferences?) {
ThemmoController( ThemmoController(
lightColorScheme = LightThemeColors, lightColorScheme = LightThemeColors,
darkColorScheme = DarkThemeColors, darkColorScheme = DarkThemeColors,
themingMode = prefs.themingMode, themingMode = prefs.themingMode.toThemingMode(),
dynamicThemeEnabled = prefs.enableDynamicTheme, dynamicThemeEnabled = prefs.enableDynamicTheme,
amoledThemeEnabled = prefs.enableAmoledTheme, amoledThemeEnabled = prefs.enableAmoledTheme,
customColor = prefs.customColor, customColor = prefs.customColor.toColor(),
monetMode = prefs.monetMode monetMode = prefs.monetMode.toMonetMode()
) )
} }
@ -150,3 +152,21 @@ internal fun UnittoApp(prefs: AppPreferences?) {
drawerScope.launch { drawerState.close() } drawerScope.launch { drawerState.close() }
} }
} }
private fun String.toThemingMode(): ThemingMode = try {
ThemingMode.valueOf(this)
} catch (e: Exception) {
ThemingMode.AUTO
}
private fun String.toMonetMode(): MonetMode = try {
MonetMode.valueOf(this)
} catch (e: Exception) {
MonetMode.TonalSpot
}
private fun Long.toColor(): Color = try {
Color(this.toULong())
} catch (e: Exception) {
Color.Unspecified
}

View File

@ -21,25 +21,26 @@ package com.sadellie.unitto.data.calculator
import com.sadellie.unitto.data.database.CalculatorHistoryDao import com.sadellie.unitto.data.database.CalculatorHistoryDao
import com.sadellie.unitto.data.database.CalculatorHistoryEntity import com.sadellie.unitto.data.database.CalculatorHistoryEntity
import com.sadellie.unitto.data.model.HistoryItem import com.sadellie.unitto.data.model.HistoryItem
import com.sadellie.unitto.data.model.repository.CalculatorHistoryRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import java.util.* import java.util.Date
import javax.inject.Inject import javax.inject.Inject
class CalculatorHistoryRepository @Inject constructor( class CalculatorHistoryRepositoryImpl @Inject constructor(
private val calculatorHistoryDao: CalculatorHistoryDao private val calculatorHistoryDao: CalculatorHistoryDao
) { ) : CalculatorHistoryRepository {
/** /**
* Calculator history sorted by [CalculatorHistoryEntity.timestamp] from new to old (DESC). * Calculator history sorted by [CalculatorHistoryEntity.timestamp] from new to old (DESC).
*/ */
val historyFlow: Flow<List<HistoryItem>> = calculatorHistoryDao override val historyFlow: Flow<List<HistoryItem>> = calculatorHistoryDao
.getAllDescending() .getAllDescending()
.map { it.toHistoryItemList() } .map { it.toHistoryItemList() }
.flowOn(Dispatchers.IO) .flowOn(Dispatchers.IO)
suspend fun add( override suspend fun add(
expression: String, expression: String,
result: String result: String
) { ) {
@ -52,7 +53,7 @@ class CalculatorHistoryRepository @Inject constructor(
) )
} }
suspend fun clear() { override suspend fun clear() {
calculatorHistoryDao.clear() calculatorHistoryDao.clear()
} }

View File

@ -0,0 +1,35 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.calculator
import com.sadellie.unitto.data.database.CalculatorHistoryDao
import com.sadellie.unitto.data.model.repository.CalculatorHistoryRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class DataStoreModule {
@Provides
fun provideCalculatorHistoryRepository(calculatorHistoryDao: CalculatorHistoryDao): CalculatorHistoryRepository {
return CalculatorHistoryRepositoryImpl(calculatorHistoryDao)
}
}

View File

@ -0,0 +1,33 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.repository
import com.sadellie.unitto.data.model.HistoryItem
import kotlinx.coroutines.flow.Flow
interface CalculatorHistoryRepository {
val historyFlow: Flow<List<HistoryItem>>
suspend fun add(
expression: String,
result: String
)
suspend fun clear()
}

View File

@ -0,0 +1,50 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.repository
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.unit.AbstractUnit
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
interface UnitsRepository {
val allUnits: Flow<List<AbstractUnit>>
suspend fun getById(id: String): AbstractUnit
suspend fun getCollection(group: UnitGroup): List<AbstractUnit>
suspend fun favorite(unit: AbstractUnit)
suspend fun incrementCounter(unit: AbstractUnit)
suspend fun setPair(unit: AbstractUnit, pair: AbstractUnit)
suspend fun updateRates(unit: AbstractUnit): LocalDate?
suspend fun filterUnits(
query: String,
unitGroup: UnitGroup?,
favoritesOnly: Boolean,
hideBrokenUnits: Boolean,
sorting: UnitsListSorting,
shownUnitGroups: List<UnitGroup> = emptyList(),
): Map<UnitGroup, List<AbstractUnit>>
}

View File

@ -0,0 +1,89 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.repository
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.unit.AbstractUnit
import com.sadellie.unitto.data.model.userprefs.AboutPreferences
import com.sadellie.unitto.data.model.userprefs.AddSubtractPreferences
import com.sadellie.unitto.data.model.userprefs.AppPreferences
import com.sadellie.unitto.data.model.userprefs.CalculatorPreferences
import com.sadellie.unitto.data.model.userprefs.ConverterPreferences
import com.sadellie.unitto.data.model.userprefs.DisplayPreferences
import com.sadellie.unitto.data.model.userprefs.FormattingPreferences
import com.sadellie.unitto.data.model.userprefs.GeneralPreferences
import com.sadellie.unitto.data.model.userprefs.StartingScreenPreferences
import com.sadellie.unitto.data.model.userprefs.UnitGroupsPreferences
import kotlinx.coroutines.flow.Flow
interface UserPreferencesRepository {
val appPrefs: Flow<AppPreferences>
val generalPrefs: Flow<GeneralPreferences>
val calculatorPrefs: Flow<CalculatorPreferences>
val converterPrefs: Flow<ConverterPreferences>
val displayPrefs: Flow<DisplayPreferences>
val formattingPrefs: Flow<FormattingPreferences>
val unitGroupsPrefs: Flow<UnitGroupsPreferences>
val addSubtractPrefs: Flow<AddSubtractPreferences>
val aboutPrefs: Flow<AboutPreferences>
val startingScreenPrefs: Flow<StartingScreenPreferences>
suspend fun updateDigitsPrecision(precision: Int)
suspend fun updateSeparator(separator: Int)
suspend fun updateOutputFormat(outputFormat: Int)
suspend fun updateLatestPairOfUnits(unitFrom: AbstractUnit, unitTo: AbstractUnit)
suspend fun updateThemingMode(themingMode: String)
suspend fun updateDynamicTheme(enabled: Boolean)
suspend fun updateAmoledTheme(enabled: Boolean)
suspend fun updateCustomColor(color: Long)
suspend fun updateMonetMode(monetMode: String)
suspend fun updateStartingScreen(startingScreen: String)
suspend fun updateShownUnitGroups(shownUnitGroups: List<UnitGroup>)
suspend fun updateVibrations(enabled: Boolean)
suspend fun updateMiddleZero(enabled: Boolean)
suspend fun updateToolsExperiment(enabled: Boolean)
suspend fun updateRadianMode(radianMode: Boolean)
suspend fun updateUnitConverterFavoritesOnly(enabled: Boolean)
suspend fun updateUnitConverterFormatTime(enabled: Boolean)
suspend fun updateUnitConverterSorting(sorting: UnitsListSorting)
suspend fun updateSystemFont(enabled: Boolean)
suspend fun updatePartialHistoryView(enabled: Boolean)
suspend fun updateAcButton(enabled: Boolean)
}

View File

@ -0,0 +1,23 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
interface AboutPreferences{
val enableToolsExperiment: Boolean
}

View File

@ -0,0 +1,24 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
interface AddSubtractPreferences{
val separator: Int
val enableVibrations: Boolean
}

View File

@ -0,0 +1,30 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
interface AppPreferences {
val themingMode: String
val enableDynamicTheme: Boolean
val enableAmoledTheme: Boolean
val customColor: Long
val monetMode: String
val startingScreen: String
val enableToolsExperiment: Boolean
val systemFont: Boolean
}

View File

@ -0,0 +1,30 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
interface CalculatorPreferences {
val radianMode: Boolean
val enableVibrations: Boolean
val separator: Int
val middleZero: Boolean
val acButton: Boolean
val partialHistoryView: Boolean
val precision: Int
val outputFormat: Int
}

View File

@ -0,0 +1,38 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
interface ConverterPreferences {
val enableVibrations: Boolean
val separator: Int
val middleZero: Boolean
val acButton: Boolean
val precision: Int
val outputFormat: Int
val unitConverterFormatTime: Boolean
val unitConverterSorting: UnitsListSorting
val shownUnitGroups: List<UnitGroup>
val unitConverterFavoritesOnly: Boolean
val enableToolsExperiment: Boolean
val latestLeftSideUnit: String
val latestRightSideUnit: String
}

View File

@ -0,0 +1,25 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
interface DisplayPreferences {
val systemFont: Boolean
val middleZero: Boolean
val acButton: Boolean
}

View File

@ -0,0 +1,25 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
interface FormattingPreferences{
val digitsPrecision: Int
val separator: Int
val outputFormat: Int
}

View File

@ -0,0 +1,23 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
interface GeneralPreferences {
val enableVibrations: Boolean
}

View File

@ -0,0 +1,23 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
interface StartingScreenPreferences{
val startingScreen: String
}

View File

@ -0,0 +1,25 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.model.userprefs
import com.sadellie.unitto.data.model.UnitGroup
interface UnitGroupsPreferences{
val shownUnitGroups: List<UnitGroup>
}

View File

@ -0,0 +1,46 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.units
import android.content.Context
import com.sadellie.unitto.data.database.CurrencyRatesDao
import com.sadellie.unitto.data.database.UnitsDao
import com.sadellie.unitto.data.model.repository.UnitsRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class DataStoreModule {
@Provides
fun provideUnitsRepository(
unitsDao: UnitsDao,
currencyRatesDao: CurrencyRatesDao,
@ApplicationContext appContext: Context
): UnitsRepository {
return UnitsRepositoryImpl(
unitsDao = unitsDao,
currencyRatesDao = currencyRatesDao,
mContext = appContext
)
}
}

View File

@ -26,6 +26,7 @@ import com.sadellie.unitto.data.database.UnitsDao
import com.sadellie.unitto.data.database.UnitsEntity import com.sadellie.unitto.data.database.UnitsEntity
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.repository.UnitsRepository
import com.sadellie.unitto.data.model.unit.AbstractUnit import com.sadellie.unitto.data.model.unit.AbstractUnit
import com.sadellie.unitto.data.model.unit.ReverseUnit import com.sadellie.unitto.data.model.unit.ReverseUnit
import com.sadellie.unitto.data.model.unit.filterByLev import com.sadellie.unitto.data.model.unit.filterByLev
@ -67,11 +68,11 @@ import java.math.BigDecimal
import java.time.LocalDate import java.time.LocalDate
import javax.inject.Inject import javax.inject.Inject
class UnitsRepository @Inject constructor( class UnitsRepositoryImpl @Inject constructor(
private val unitsDao: UnitsDao, private val unitsDao: UnitsDao,
private val currencyRatesDao: CurrencyRatesDao, private val currencyRatesDao: CurrencyRatesDao,
@ApplicationContext private val mContext: Context, @ApplicationContext private val mContext: Context,
) { ) : UnitsRepository {
private val myUnits = MutableStateFlow( private val myUnits = MutableStateFlow(
lengthCollection + lengthCollection +
currencyCollection + currencyCollection +
@ -99,7 +100,7 @@ class UnitsRepository @Inject constructor(
fuelConsumptionCollection fuelConsumptionCollection
) )
val allUnits: Flow<List<AbstractUnit>> = combine( override val allUnits: Flow<List<AbstractUnit>> = combine(
unitsDao.getAllFlow(), unitsDao.getAllFlow(),
myUnits myUnits
) { basedList, inMemoryList -> ) { basedList, inMemoryList ->
@ -115,15 +116,15 @@ class UnitsRepository @Inject constructor(
} }
.flowOn(Dispatchers.IO) .flowOn(Dispatchers.IO)
suspend fun getById(id: String): AbstractUnit { override suspend fun getById(id: String): AbstractUnit {
return allUnits.first().first { it.id == id } return allUnits.first().first { it.id == id }
} }
suspend fun getCollection(group: UnitGroup): List<AbstractUnit> { override suspend fun getCollection(group: UnitGroup): List<AbstractUnit> {
return allUnits.first().filter { it.group == group } return allUnits.first().filter { it.group == group }
} }
suspend fun favorite(unit: AbstractUnit) = withContext(Dispatchers.IO) { override suspend fun favorite(unit: AbstractUnit) = withContext(Dispatchers.IO) {
val basedUnit = unitsDao.getById(unit.id) val basedUnit = unitsDao.getById(unit.id)
if (basedUnit == null) { if (basedUnit == null) {
@ -145,7 +146,7 @@ class UnitsRepository @Inject constructor(
} }
} }
suspend fun incrementCounter(unit: AbstractUnit) = withContext(Dispatchers.IO) { override suspend fun incrementCounter(unit: AbstractUnit) = withContext(Dispatchers.IO) {
val basedUnit = unitsDao.getById(unit.id) val basedUnit = unitsDao.getById(unit.id)
if (basedUnit == null) { if (basedUnit == null) {
@ -167,7 +168,7 @@ class UnitsRepository @Inject constructor(
} }
} }
suspend fun setPair(unit: AbstractUnit, pair: AbstractUnit) = withContext(Dispatchers.IO) { override suspend fun setPair(unit: AbstractUnit, pair: AbstractUnit) = withContext(Dispatchers.IO) {
val basedUnit = unitsDao.getById(unit.id) val basedUnit = unitsDao.getById(unit.id)
if (basedUnit == null) { if (basedUnit == null) {
@ -189,7 +190,7 @@ class UnitsRepository @Inject constructor(
} }
} }
suspend fun updateRates(unit: AbstractUnit): LocalDate? = withContext(Dispatchers.IO) { override suspend fun updateRates(unit: AbstractUnit): LocalDate? = withContext(Dispatchers.IO) {
var basedConversions = currencyRatesDao.getLatestRates(baseId = unit.id) var basedConversions = currencyRatesDao.getLatestRates(baseId = unit.id)
val epochDay = LocalDate.now().toEpochDay() val epochDay = LocalDate.now().toEpochDay()
@ -235,13 +236,13 @@ class UnitsRepository @Inject constructor(
?.let { LocalDate.ofEpochDay(it) } ?.let { LocalDate.ofEpochDay(it) }
} }
suspend fun filterUnits( override suspend fun filterUnits(
query: String, query: String,
unitGroup: UnitGroup?, unitGroup: UnitGroup?,
favoritesOnly: Boolean, favoritesOnly: Boolean,
hideBrokenUnits: Boolean, hideBrokenUnits: Boolean,
sorting: UnitsListSorting, sorting: UnitsListSorting,
shownUnitGroups: List<UnitGroup> = emptyList(), shownUnitGroups: List<UnitGroup>,
): Map<UnitGroup, List<AbstractUnit>> { ): Map<UnitGroup, List<AbstractUnit>> {
// Leave only shown unit groups // Leave only shown unit groups
var units: Sequence<AbstractUnit> = if (unitGroup == null) { var units: Sequence<AbstractUnit> = if (unitGroup == null) {

View File

@ -25,6 +25,7 @@ import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.emptyPreferences import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStoreFile import androidx.datastore.preferences.preferencesDataStoreFile
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@ -55,4 +56,9 @@ class DataStoreModule {
produceFile = { appContext.preferencesDataStoreFile(USER_PREFERENCES) } produceFile = { appContext.preferencesDataStoreFile(USER_PREFERENCES) }
) )
} }
@Provides
fun provideUserPreferencesRepository(dataStore: DataStore<Preferences>): UserPreferencesRepository {
return UserPreferencesRepositoryImpl(dataStore)
}
} }

View File

@ -18,80 +18,88 @@
package com.sadellie.unitto.data.userprefs package com.sadellie.unitto.data.userprefs
import androidx.compose.ui.graphics.Color
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.model.UnitsListSorting
import io.github.sadellie.themmo.MonetMode import com.sadellie.unitto.data.model.userprefs.AboutPreferences
import io.github.sadellie.themmo.ThemingMode import com.sadellie.unitto.data.model.userprefs.AddSubtractPreferences
import com.sadellie.unitto.data.model.userprefs.AppPreferences
import com.sadellie.unitto.data.model.userprefs.CalculatorPreferences
import com.sadellie.unitto.data.model.userprefs.ConverterPreferences
import com.sadellie.unitto.data.model.userprefs.DisplayPreferences
import com.sadellie.unitto.data.model.userprefs.FormattingPreferences
import com.sadellie.unitto.data.model.userprefs.GeneralPreferences
import com.sadellie.unitto.data.model.userprefs.StartingScreenPreferences
import com.sadellie.unitto.data.model.userprefs.UnitGroupsPreferences
data class AppPreferences( data class AppPreferencesImpl(
val themingMode: ThemingMode, override val themingMode: String,
val enableDynamicTheme: Boolean, override val enableDynamicTheme: Boolean,
val enableAmoledTheme: Boolean, override val enableAmoledTheme: Boolean,
val customColor: Color, override val customColor: Long,
val monetMode: MonetMode, override val monetMode: String,
val startingScreen: String, override val startingScreen: String,
val enableToolsExperiment: Boolean, override val enableToolsExperiment: Boolean,
val systemFont: Boolean, override val systemFont: Boolean,
) ) : AppPreferences
data class GeneralPreferences(
val enableVibrations: Boolean,
)
data class CalculatorPreferences( data class GeneralPreferencesImpl(
val radianMode: Boolean, override val enableVibrations: Boolean,
val enableVibrations: Boolean, ) : GeneralPreferences
val separator: Int,
val middleZero: Boolean,
val acButton: Boolean,
val partialHistoryView: Boolean,
val precision: Int,
val outputFormat: Int,
)
data class ConverterPreferences( data class CalculatorPreferencesImpl(
val enableVibrations: Boolean, override val radianMode: Boolean,
val separator: Int, override val enableVibrations: Boolean,
val middleZero: Boolean, override val separator: Int,
val acButton: Boolean, override val middleZero: Boolean,
val precision: Int, override val acButton: Boolean,
val outputFormat: Int, override val partialHistoryView: Boolean,
val unitConverterFormatTime: Boolean, override val precision: Int,
val unitConverterSorting: UnitsListSorting, override val outputFormat: Int,
val shownUnitGroups: List<UnitGroup>, ) : CalculatorPreferences
val unitConverterFavoritesOnly: Boolean,
val enableToolsExperiment: Boolean,
val latestLeftSideUnit: String,
val latestRightSideUnit: String,
)
data class DisplayPreferences( data class ConverterPreferencesImpl(
val systemFont: Boolean, override val enableVibrations: Boolean,
val middleZero: Boolean, override val separator: Int,
val acButton: Boolean, override val middleZero: Boolean,
) override val acButton: Boolean,
override val precision: Int,
override val outputFormat: Int,
override val unitConverterFormatTime: Boolean,
override val unitConverterSorting: UnitsListSorting,
override val shownUnitGroups: List<UnitGroup>,
override val unitConverterFavoritesOnly: Boolean,
override val enableToolsExperiment: Boolean,
override val latestLeftSideUnit: String,
override val latestRightSideUnit: String,
) : ConverterPreferences
data class FormattingPreferences( data class DisplayPreferencesImpl(
val digitsPrecision: Int, override val systemFont: Boolean,
val separator: Int, override val middleZero: Boolean,
val outputFormat: Int, override val acButton: Boolean,
) ) : DisplayPreferences
data class UnitGroupsPreferences( data class FormattingPreferencesImpl(
val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS, override val digitsPrecision: Int,
) override val separator: Int,
override val outputFormat: Int,
) : FormattingPreferences
data class AddSubtractPreferences( data class UnitGroupsPreferencesImpl(
val separator: Int, override val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS,
val enableVibrations: Boolean, ) : UnitGroupsPreferences
)
data class AboutPreferences( data class AddSubtractPreferencesImpl(
val enableToolsExperiment: Boolean, override val separator: Int,
) override val enableVibrations: Boolean,
) : AddSubtractPreferences
data class StartingScreenPreferences( data class AboutPreferencesImpl(
val startingScreen: String, override val enableToolsExperiment: Boolean,
) ) : AboutPreferences
data class StartingScreenPreferencesImpl(
override val startingScreen: String,
) : StartingScreenPreferences

View File

@ -18,7 +18,6 @@
package com.sadellie.unitto.data.userprefs package com.sadellie.unitto.data.userprefs
import androidx.compose.ui.graphics.Color
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.edit
@ -29,25 +28,34 @@ import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import com.sadellie.unitto.data.model.unit.AbstractUnit import com.sadellie.unitto.data.model.unit.AbstractUnit
import com.sadellie.unitto.data.model.userprefs.AboutPreferences
import com.sadellie.unitto.data.model.userprefs.AddSubtractPreferences
import com.sadellie.unitto.data.model.userprefs.AppPreferences
import com.sadellie.unitto.data.model.userprefs.CalculatorPreferences
import com.sadellie.unitto.data.model.userprefs.ConverterPreferences
import com.sadellie.unitto.data.model.userprefs.DisplayPreferences
import com.sadellie.unitto.data.model.userprefs.FormattingPreferences
import com.sadellie.unitto.data.model.userprefs.GeneralPreferences
import com.sadellie.unitto.data.model.userprefs.StartingScreenPreferences
import com.sadellie.unitto.data.model.userprefs.UnitGroupsPreferences
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import io.github.sadellie.themmo.MonetMode
import io.github.sadellie.themmo.ThemingMode
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import java.io.IOException import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
class UserPreferencesRepository @Inject constructor( class UserPreferencesRepositoryImpl @Inject constructor(
private val dataStore: DataStore<Preferences>, private val dataStore: DataStore<Preferences>,
) { ) : UserPreferencesRepository {
private val data = dataStore.data private val data = dataStore.data
.catch { if (it is IOException) emit(emptyPreferences()) else throw it } .catch { if (it is IOException) emit(emptyPreferences()) else throw it }
val appPrefs: Flow<AppPreferences> = data override val appPrefs: Flow<AppPreferences> = data
.map { preferences -> .map { preferences ->
AppPreferences( AppPreferencesImpl(
themingMode = preferences.getThemingMode(), themingMode = preferences.getThemingMode(),
enableDynamicTheme = preferences.getEnableDynamicTheme(), enableDynamicTheme = preferences.getEnableDynamicTheme(),
enableAmoledTheme = preferences.getEnableAmoledTheme(), enableAmoledTheme = preferences.getEnableAmoledTheme(),
@ -59,16 +67,16 @@ class UserPreferencesRepository @Inject constructor(
) )
} }
val generalPrefs: Flow<GeneralPreferences> = data override val generalPrefs: Flow<GeneralPreferences> = data
.map { preferences -> .map { preferences ->
GeneralPreferences( GeneralPreferencesImpl(
enableVibrations = preferences.getEnableVibrations(), enableVibrations = preferences.getEnableVibrations(),
) )
} }
val calculatorPrefs: Flow<CalculatorPreferences> = data override val calculatorPrefs: Flow<CalculatorPreferences> = data
.map { preferences -> .map { preferences ->
CalculatorPreferences( CalculatorPreferencesImpl(
radianMode = preferences.getRadianMode(), radianMode = preferences.getRadianMode(),
enableVibrations = preferences.getEnableVibrations(), enableVibrations = preferences.getEnableVibrations(),
separator = preferences.getSeparator(), separator = preferences.getSeparator(),
@ -80,9 +88,9 @@ class UserPreferencesRepository @Inject constructor(
) )
} }
val converterPrefs: Flow<ConverterPreferences> = data override val converterPrefs: Flow<ConverterPreferences> = data
.map { preferences -> .map { preferences ->
ConverterPreferences( ConverterPreferencesImpl(
enableVibrations = preferences.getEnableVibrations(), enableVibrations = preferences.getEnableVibrations(),
separator = preferences.getSeparator(), separator = preferences.getSeparator(),
middleZero = preferences.getMiddleZero(), middleZero = preferences.getMiddleZero(),
@ -99,175 +107,175 @@ class UserPreferencesRepository @Inject constructor(
) )
} }
val displayPrefs: Flow<DisplayPreferences> = data override val displayPrefs: Flow<DisplayPreferences> = data
.map { preferences -> .map { preferences ->
DisplayPreferences( DisplayPreferencesImpl(
systemFont = preferences.getSystemFont(), systemFont = preferences.getSystemFont(),
middleZero = preferences.getMiddleZero(), middleZero = preferences.getMiddleZero(),
acButton = preferences.getAcButton(), acButton = preferences.getAcButton(),
) )
} }
val formattingPrefs: Flow<FormattingPreferences> = data override val formattingPrefs: Flow<FormattingPreferences> = data
.map { preferences -> .map { preferences ->
FormattingPreferences( FormattingPreferencesImpl(
digitsPrecision = preferences.getDigitsPrecision(), digitsPrecision = preferences.getDigitsPrecision(),
separator = preferences.getSeparator(), separator = preferences.getSeparator(),
outputFormat = preferences.getOutputFormat(), outputFormat = preferences.getOutputFormat(),
) )
} }
val unitGroupsPrefs: Flow<UnitGroupsPreferences> = data override val unitGroupsPrefs: Flow<UnitGroupsPreferences> = data
.map { preferences -> .map { preferences ->
UnitGroupsPreferences( UnitGroupsPreferencesImpl(
shownUnitGroups = preferences.getShownUnitGroups(), shownUnitGroups = preferences.getShownUnitGroups(),
) )
} }
val addSubtractPrefs: Flow<AddSubtractPreferences> = data override val addSubtractPrefs: Flow<AddSubtractPreferences> = data
.map { preferences -> .map { preferences ->
AddSubtractPreferences( AddSubtractPreferencesImpl(
separator = preferences.getSeparator(), separator = preferences.getSeparator(),
enableVibrations = preferences.getEnableVibrations(), enableVibrations = preferences.getEnableVibrations(),
) )
} }
val aboutPrefs: Flow<AboutPreferences> = data override val aboutPrefs: Flow<AboutPreferences> = data
.map { preferences -> .map { preferences ->
AboutPreferences( AboutPreferencesImpl(
enableToolsExperiment = preferences.getEnableToolsExperiment() enableToolsExperiment = preferences.getEnableToolsExperiment()
) )
} }
val startingScreenPrefs: Flow<StartingScreenPreferences> = data override val startingScreenPrefs: Flow<StartingScreenPreferences> = data
.map { preferences -> .map { preferences ->
StartingScreenPreferences( StartingScreenPreferencesImpl(
startingScreen = preferences.getStartingScreen(), startingScreen = preferences.getStartingScreen(),
) )
} }
suspend fun updateDigitsPrecision(precision: Int) { override suspend fun updateDigitsPrecision(precision: Int) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.DIGITS_PRECISION] = precision preferences[PrefsKeys.DIGITS_PRECISION] = precision
} }
} }
suspend fun updateSeparator(separator: Int) { override suspend fun updateSeparator(separator: Int) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.SEPARATOR] = separator preferences[PrefsKeys.SEPARATOR] = separator
} }
} }
suspend fun updateOutputFormat(outputFormat: Int) { override suspend fun updateOutputFormat(outputFormat: Int) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.OUTPUT_FORMAT] = outputFormat preferences[PrefsKeys.OUTPUT_FORMAT] = outputFormat
} }
} }
suspend fun updateLatestPairOfUnits(unitFrom: AbstractUnit, unitTo: AbstractUnit) { override suspend fun updateLatestPairOfUnits(unitFrom: AbstractUnit, unitTo: AbstractUnit) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.LATEST_LEFT_SIDE] = unitFrom.id preferences[PrefsKeys.LATEST_LEFT_SIDE] = unitFrom.id
preferences[PrefsKeys.LATEST_RIGHT_SIDE] = unitTo.id preferences[PrefsKeys.LATEST_RIGHT_SIDE] = unitTo.id
} }
} }
suspend fun updateThemingMode(themingMode: ThemingMode) { override suspend fun updateThemingMode(themingMode: String) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.THEMING_MODE] = themingMode.name preferences[PrefsKeys.THEMING_MODE] = themingMode
} }
} }
suspend fun updateDynamicTheme(enabled: Boolean) { override suspend fun updateDynamicTheme(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.ENABLE_DYNAMIC_THEME] = enabled preferences[PrefsKeys.ENABLE_DYNAMIC_THEME] = enabled
} }
} }
suspend fun updateAmoledTheme(enabled: Boolean) { override suspend fun updateAmoledTheme(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.ENABLE_AMOLED_THEME] = enabled preferences[PrefsKeys.ENABLE_AMOLED_THEME] = enabled
} }
} }
suspend fun updateCustomColor(color: Color) { override suspend fun updateCustomColor(color: Long) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.CUSTOM_COLOR] = color.value.toLong() preferences[PrefsKeys.CUSTOM_COLOR] = color
} }
} }
suspend fun updateMonetMode(monetMode: MonetMode) { override suspend fun updateMonetMode(monetMode: String) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.MONET_MODE] = monetMode.name preferences[PrefsKeys.MONET_MODE] = monetMode
} }
} }
suspend fun updateStartingScreen(startingScreen: String) { override suspend fun updateStartingScreen(startingScreen: String) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.STARTING_SCREEN] = startingScreen preferences[PrefsKeys.STARTING_SCREEN] = startingScreen
} }
} }
suspend fun updateShownUnitGroups(shownUnitGroups: List<UnitGroup>) { override suspend fun updateShownUnitGroups(shownUnitGroups: List<UnitGroup>) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.SHOWN_UNIT_GROUPS] = shownUnitGroups.joinToString(",") preferences[PrefsKeys.SHOWN_UNIT_GROUPS] = shownUnitGroups.joinToString(",")
} }
} }
suspend fun updateVibrations(enabled: Boolean) { override suspend fun updateVibrations(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.ENABLE_VIBRATIONS] = enabled preferences[PrefsKeys.ENABLE_VIBRATIONS] = enabled
} }
} }
suspend fun updateMiddleZero(enabled: Boolean) { override suspend fun updateMiddleZero(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.MIDDLE_ZERO] = enabled preferences[PrefsKeys.MIDDLE_ZERO] = enabled
} }
} }
suspend fun updateToolsExperiment(enabled: Boolean) { override suspend fun updateToolsExperiment(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] = enabled preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] = enabled
} }
} }
suspend fun updateRadianMode(radianMode: Boolean) { override suspend fun updateRadianMode(radianMode: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.RADIAN_MODE] = radianMode preferences[PrefsKeys.RADIAN_MODE] = radianMode
} }
} }
suspend fun updateUnitConverterFavoritesOnly(enabled: Boolean) { override suspend fun updateUnitConverterFavoritesOnly(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] = enabled preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] = enabled
} }
} }
suspend fun updateUnitConverterFormatTime(enabled: Boolean) { override suspend fun updateUnitConverterFormatTime(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] = enabled preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] = enabled
} }
} }
suspend fun updateUnitConverterSorting(sorting: UnitsListSorting) { override suspend fun updateUnitConverterSorting(sorting: UnitsListSorting) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.UNIT_CONVERTER_SORTING] = sorting.name preferences[PrefsKeys.UNIT_CONVERTER_SORTING] = sorting.name
} }
} }
suspend fun updateSystemFont(enabled: Boolean) { override suspend fun updateSystemFont(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.SYSTEM_FONT] = enabled preferences[PrefsKeys.SYSTEM_FONT] = enabled
} }
} }
suspend fun updatePartialHistoryView(enabled: Boolean) { override suspend fun updatePartialHistoryView(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.PARTIAL_HISTORY_VIEW] = enabled preferences[PrefsKeys.PARTIAL_HISTORY_VIEW] = enabled
} }
} }
suspend fun updateAcButton(enabled: Boolean) { override suspend fun updateAcButton(enabled: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.AC_BUTTON] = enabled preferences[PrefsKeys.AC_BUTTON] = enabled
} }
@ -278,24 +286,20 @@ private fun Preferences.getEnableDynamicTheme(): Boolean {
return this[PrefsKeys.ENABLE_DYNAMIC_THEME] ?: true return this[PrefsKeys.ENABLE_DYNAMIC_THEME] ?: true
} }
private fun Preferences.getThemingMode(): ThemingMode { private fun Preferences.getThemingMode(): String {
return this[PrefsKeys.THEMING_MODE] return this[PrefsKeys.THEMING_MODE] ?: ""
?.letTryOrNull { ThemingMode.valueOf(it) }
?: ThemingMode.AUTO
} }
private fun Preferences.getEnableAmoledTheme(): Boolean { private fun Preferences.getEnableAmoledTheme(): Boolean {
return this[PrefsKeys.ENABLE_AMOLED_THEME] ?: false return this[PrefsKeys.ENABLE_AMOLED_THEME] ?: false
} }
private fun Preferences.getCustomColor(): Color { private fun Preferences.getCustomColor(): Long {
return this[PrefsKeys.CUSTOM_COLOR]?.letTryOrNull { Color(it.toULong()) } return this[PrefsKeys.CUSTOM_COLOR] ?: Long.MIN_VALUE
?: Color.Unspecified
} }
private fun Preferences.getMonetMode(): MonetMode { private fun Preferences.getMonetMode(): String {
return this[PrefsKeys.MONET_MODE]?.letTryOrNull { MonetMode.valueOf(it) } return this[PrefsKeys.MONET_MODE] ?: ""
?: MonetMode.TonalSpot
} }
private fun Preferences.getStartingScreen(): String { private fun Preferences.getStartingScreen(): String {

View File

@ -32,13 +32,14 @@ android {
dependencies { dependencies {
testImplementation(libs.junit.junit) testImplementation(libs.junit.junit)
testImplementation(libs.org.robolectric.robolectric) testImplementation(libs.org.robolectric.robolectric)
testImplementation(libs.org.jetbrains.kotlinx.kotlinx.coroutines.test)
androidTestImplementation(libs.androidx.compose.ui.test.junit4) androidTestImplementation(libs.androidx.compose.ui.test.junit4)
debugImplementation(libs.androidx.compose.ui.test.manifest) debugImplementation(libs.androidx.compose.ui.test.manifest)
implementation(project(":data:common")) implementation(project(":data:common"))
implementation(project(":data:userprefs"))
implementation(project(":data:database")) implementation(project(":data:database"))
implementation(project(":data:calculator"))
implementation(project(":data:model")) implementation(project(":data:model"))
implementation(project(":data:userprefs"))
implementation(project(":data:calculator"))
implementation(project(":data:evaluatto")) implementation(project(":data:evaluatto"))
} }

View File

@ -28,13 +28,13 @@ import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.addBracket import com.sadellie.unitto.core.ui.common.textfield.addBracket
import com.sadellie.unitto.core.ui.common.textfield.addTokens import com.sadellie.unitto.core.ui.common.textfield.addTokens
import com.sadellie.unitto.core.ui.common.textfield.deleteTokens import com.sadellie.unitto.core.ui.common.textfield.deleteTokens
import com.sadellie.unitto.data.calculator.CalculatorHistoryRepository
import com.sadellie.unitto.data.common.isExpression import com.sadellie.unitto.data.common.isExpression
import com.sadellie.unitto.data.common.setMinimumRequiredScale import com.sadellie.unitto.data.common.setMinimumRequiredScale
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.common.toStringWith import com.sadellie.unitto.data.common.toStringWith
import com.sadellie.unitto.data.common.trimZeros import com.sadellie.unitto.data.common.trimZeros
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.CalculatorHistoryRepository
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import io.github.sadellie.evaluatto.Expression import io.github.sadellie.evaluatto.Expression
import io.github.sadellie.evaluatto.ExpressionException import io.github.sadellie.evaluatto.ExpressionException

View File

@ -33,11 +33,11 @@ import com.sadellie.unitto.data.common.isExpression
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.repository.UnitsRepository
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import com.sadellie.unitto.data.model.unit.AbstractUnit import com.sadellie.unitto.data.model.unit.AbstractUnit
import com.sadellie.unitto.data.model.unit.DefaultUnit import com.sadellie.unitto.data.model.unit.DefaultUnit
import com.sadellie.unitto.data.model.unit.NumberBaseUnit import com.sadellie.unitto.data.model.unit.NumberBaseUnit
import com.sadellie.unitto.data.units.UnitsRepository
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import io.github.sadellie.evaluatto.Expression import io.github.sadellie.evaluatto.Expression
import io.github.sadellie.evaluatto.ExpressionException import io.github.sadellie.evaluatto.ExpressionException

View File

@ -31,5 +31,6 @@ android {
dependencies { dependencies {
testImplementation(libs.junit.junit) testImplementation(libs.junit.junit)
implementation(project(":data:model"))
implementation(project(":data:userprefs")) implementation(project(":data:userprefs"))
} }

View File

@ -23,7 +23,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow

View File

@ -59,7 +59,8 @@ import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.openLink import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.core.ui.showToast import com.sadellie.unitto.core.ui.showToast
import com.sadellie.unitto.data.userprefs.GeneralPreferences import com.sadellie.unitto.data.model.userprefs.GeneralPreferences
import com.sadellie.unitto.data.userprefs.GeneralPreferencesImpl
import com.sadellie.unitto.feature.settings.navigation.aboutRoute import com.sadellie.unitto.feature.settings.navigation.aboutRoute
import com.sadellie.unitto.feature.settings.navigation.calculatorSettingsRoute import com.sadellie.unitto.feature.settings.navigation.calculatorSettingsRoute
import com.sadellie.unitto.feature.settings.navigation.converterSettingsRoute import com.sadellie.unitto.feature.settings.navigation.converterSettingsRoute
@ -194,7 +195,7 @@ private fun PreviewSettingsScreen() {
var cacheSize by remember { mutableFloatStateOf(0.9f) } var cacheSize by remember { mutableFloatStateOf(0.9f) }
SettingsScreen( SettingsScreen(
userPrefs = GeneralPreferences( userPrefs = GeneralPreferencesImpl(
enableVibrations = true enableVibrations = true
), ),
navigateUp = {}, navigateUp = {},

View File

@ -22,7 +22,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.database.CurrencyRatesDao import com.sadellie.unitto.data.database.CurrencyRatesDao
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map

View File

@ -52,7 +52,8 @@ import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.openLink import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.core.ui.showToast import com.sadellie.unitto.core.ui.showToast
import com.sadellie.unitto.data.userprefs.AboutPreferences import com.sadellie.unitto.data.model.userprefs.AboutPreferences
import com.sadellie.unitto.data.userprefs.AboutPreferencesImpl
@Composable @Composable
internal fun AboutRoute( internal fun AboutRoute(
@ -194,7 +195,7 @@ private fun AboutScreen(
@Composable @Composable
fun PreviewAboutScreen() { fun PreviewAboutScreen() {
AboutScreen( AboutScreen(
prefs = AboutPreferences( prefs = AboutPreferencesImpl(
enableToolsExperiment = false enableToolsExperiment = false
), ),
navigateUpAction = {}, navigateUpAction = {},

View File

@ -21,7 +21,7 @@ package com.sadellie.unitto.feature.settings.about
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject

View File

@ -33,7 +33,8 @@ import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
import com.sadellie.unitto.core.ui.common.UnittoListItem import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.data.userprefs.CalculatorPreferences import com.sadellie.unitto.data.model.userprefs.CalculatorPreferences
import com.sadellie.unitto.data.userprefs.CalculatorPreferencesImpl
@Composable @Composable
internal fun CalculatorSettingsRoute( internal fun CalculatorSettingsRoute(
@ -80,7 +81,7 @@ private fun CalculatorSettingsScreen(
@Composable @Composable
private fun PreviewCalculatorSettingsScreen() { private fun PreviewCalculatorSettingsScreen() {
CalculatorSettingsScreen( CalculatorSettingsScreen(
prefs = CalculatorPreferences( prefs = CalculatorPreferencesImpl(
radianMode = false, radianMode = false,
enableVibrations = false, enableVibrations = false,
separator = Separator.SPACE, separator = Separator.SPACE,

View File

@ -21,7 +21,7 @@ package com.sadellie.unitto.feature.settings.calculator
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject

View File

@ -43,7 +43,8 @@ import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.userprefs.ConverterPreferences import com.sadellie.unitto.data.model.userprefs.ConverterPreferences
import com.sadellie.unitto.data.userprefs.ConverterPreferencesImpl
import com.sadellie.unitto.feature.settings.components.AlertDialogWithList import com.sadellie.unitto.feature.settings.components.AlertDialogWithList
@Composable @Composable
@ -131,7 +132,7 @@ private fun ConverterSettingsScreen(
@Composable @Composable
private fun PreviewConverterSettingsScreen() { private fun PreviewConverterSettingsScreen() {
ConverterSettingsScreen( ConverterSettingsScreen(
prefs = ConverterPreferences( prefs = ConverterPreferencesImpl(
enableVibrations = true, enableVibrations = true,
separator = Separator.SPACE, separator = Separator.SPACE,
middleZero = false, middleZero = false,

View File

@ -22,7 +22,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject

View File

@ -22,7 +22,7 @@ import androidx.compose.ui.graphics.Color
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import io.github.sadellie.themmo.MonetMode import io.github.sadellie.themmo.MonetMode
import io.github.sadellie.themmo.ThemingMode import io.github.sadellie.themmo.ThemingMode
@ -39,7 +39,7 @@ class DisplayViewModel @Inject constructor(
fun updateThemingMode(themingMode: ThemingMode) { fun updateThemingMode(themingMode: ThemingMode) {
viewModelScope.launch { viewModelScope.launch {
userPrefsRepository.updateThemingMode(themingMode) userPrefsRepository.updateThemingMode(themingMode.name)
} }
} }
@ -57,13 +57,13 @@ class DisplayViewModel @Inject constructor(
fun updateCustomColor(color: Color) { fun updateCustomColor(color: Color) {
viewModelScope.launch { viewModelScope.launch {
userPrefsRepository.updateCustomColor(color) userPrefsRepository.updateCustomColor(color.value.toLong())
} }
} }
fun updateMonetMode(monetMode: MonetMode) { fun updateMonetMode(monetMode: MonetMode) {
viewModelScope.launch { viewModelScope.launch {
userPrefsRepository.updateMonetMode(monetMode) userPrefsRepository.updateMonetMode(monetMode.name)
} }
} }

View File

@ -28,7 +28,7 @@ import com.sadellie.unitto.data.common.setMinimumRequiredScale
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.common.toStringWith import com.sadellie.unitto.data.common.toStringWith
import com.sadellie.unitto.data.common.trimZeros import com.sadellie.unitto.data.common.trimZeros
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine

View File

@ -21,7 +21,7 @@ package com.sadellie.unitto.feature.settings.startingscreen
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject

View File

@ -21,7 +21,7 @@ package com.sadellie.unitto.feature.settings.unitgroups
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch