Calculator history (#2):

this is a squashed commit
This commit is contained in:
Sad Ellie 2023-02-17 15:58:17 +04:00
parent 31f59ca038
commit 39f4997c73
88 changed files with 1139 additions and 256 deletions

View File

@ -116,6 +116,7 @@ dependencies {
implementation(project(mapOf("path" to ":feature:tools"))) implementation(project(mapOf("path" to ":feature:tools")))
implementation(project(mapOf("path" to ":feature:epoch"))) implementation(project(mapOf("path" to ":feature:epoch")))
implementation(project(mapOf("path" to ":data:units"))) implementation(project(mapOf("path" to ":data:units")))
implementation(project(mapOf("path" to ":data:model")))
implementation(project(mapOf("path" to ":data:userprefs"))) implementation(project(mapOf("path" to ":data:userprefs")))
implementation(project(mapOf("path" to ":core:ui"))) implementation(project(mapOf("path" to ":core:ui")))
} }

View File

@ -1025,6 +1025,9 @@
<!--Calculator--> <!--Calculator-->
<string name="calculator">Calculator</string> <string name="calculator">Calculator</string>
<string name="calculator_support">Calculate, but don\'t convert</string> <string name="calculator_support">Calculate, but don\'t convert</string>
<string name="calculator_clear_history_label">Clear</string>
<string name="calculator_clear_history_title">Clear history</string>
<string name="calculator_clear_history_support">All expressions from history will be deleted forever. This action can\'t be undone!</string>
<!--Precision--> <!--Precision-->
<string name="precision_setting_support">Number of decimal places</string> <string name="precision_setting_support">Number of decimal places</string>

View File

@ -19,6 +19,7 @@
package com.sadellie.unitto.core.ui.common package com.sadellie.unitto.core.ui.common
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
@ -36,6 +37,7 @@ import androidx.compose.ui.Modifier
fun UnittoTopAppBar( fun UnittoTopAppBar(
title: String, title: String,
navigateUpAction: () -> Unit, navigateUpAction: () -> Unit,
actions: @Composable RowScope.() -> Unit = {},
content: @Composable (PaddingValues) -> Unit content: @Composable (PaddingValues) -> Unit
) { ) {
Scaffold( Scaffold(
@ -47,7 +49,8 @@ fun UnittoTopAppBar(
}, },
navigationIcon = { navigationIcon = {
NavigateUpButton { navigateUpAction() } NavigateUpButton { navigateUpAction() }
} },
actions = actions
) )
}, },
content = content content = content

1
data/calculator/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -1,6 +1,6 @@
/* /*
* Unitto is a unit converter for Android * Unitto is a unit converter for Android
* Copyright (c) 2022-2022 Elshan Agaev * Copyright (c) 2023 Elshan Agaev
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,12 +16,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.units.database plugins {
id("unitto.library")
import androidx.room.Database id("unitto.android.hilt")
import androidx.room.RoomDatabase }
@Database(entities = [MyBasedUnit::class], version = 1, exportSchema = false) android {
abstract class MyBasedUnitDatabase : RoomDatabase() { namespace = "com.sadellie.unitto.data.calculator"
abstract fun myBasedUnitDao(): MyBasedUnitDao }
dependencies {
implementation(project(mapOf("path" to ":data:model")))
implementation(project(mapOf("path" to ":data:database")))
} }

View File

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -0,0 +1,68 @@
/*
* 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.database.CalculatorHistoryEntity
import com.sadellie.unitto.data.model.HistoryItem
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import java.util.*
import javax.inject.Inject
class CalculatorHistoryRepository @Inject constructor(
private val calculatorHistoryDao: CalculatorHistoryDao
) {
/**
* Calculator history sorted by [CalculatorHistoryEntity.timestamp] from new to old (DESC).
*/
val historyFlow: Flow<List<HistoryItem>> = calculatorHistoryDao
.getAllDescending()
.map { it.toHistoryItemList() }
.flowOn(Dispatchers.IO)
suspend fun add(
expression: String,
result: String
) {
calculatorHistoryDao.insert(
CalculatorHistoryEntity(
timestamp = System.currentTimeMillis(),
expression = expression,
result = result
)
)
}
suspend fun clear() {
calculatorHistoryDao.clear()
}
private fun List<CalculatorHistoryEntity>.toHistoryItemList(): List<HistoryItem> {
return this.map {
HistoryItem(
date = Date(it.timestamp),
expression = it.expression,
result = it.result
)
}
}
}

1
data/common/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,29 @@
/*
* 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/>.
*/
plugins {
id("unitto.library")
}
android {
namespace = "com.sadellie.unitto.data.common"
}
dependencies {
implementation(project(mapOf("path" to ":core:base")))
}

View File

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -1,6 +1,6 @@
/* /*
* Unitto is a unit converter for Android * Unitto is a unit converter for Android
* Copyright (c) 2022 Elshan Agaev * Copyright (c) 2022-2023 Elshan Agaev
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data package com.sadellie.unitto.data.common
import com.sadellie.unitto.core.base.OutputFormat import com.sadellie.unitto.core.base.OutputFormat
import java.math.BigDecimal import java.math.BigDecimal

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data package com.sadellie.unitto.data.common
/** /**
* Compute Levenshtein Distance between this string and [secondString]. Doesn't matter which string is * Compute Levenshtein Distance between this string and [secondString]. Doesn't matter which string is

1
data/database/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,40 @@
/*
* 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/>.
*/
plugins {
id("unitto.library")
id("unitto.android.hilt")
}
android {
namespace = "com.sadellie.unitto.data.database"
// Long thingy
val schemaLocation = "$projectDir/schemas"
defaultConfig
.javaCompileOptions
.annotationProcessorOptions
.arguments["room.schemaLocation"] = schemaLocation
println("Exported Database schema to $schemaLocation")
}
dependencies {
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
kapt(libs.androidx.room.compiler)
}

View File

View File

@ -0,0 +1,52 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "96a05166e4b7d08a4595ac65138aff62",
"entities": [
{
"tableName": "units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`unitId` TEXT NOT NULL, `is_favorite` INTEGER, `paired_unit_id` TEXT, `frequency` INTEGER, PRIMARY KEY(`unitId`))",
"fields": [
{
"fieldPath": "unitId",
"columnName": "unitId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isFavorite",
"columnName": "is_favorite",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "pairedUnitId",
"columnName": "paired_unit_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "frequency",
"columnName": "frequency",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"unitId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '96a05166e4b7d08a4595ac65138aff62')"
]
}
}

View File

@ -0,0 +1,90 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "d5dca9e0346c3400b7ff5b31e85c7827",
"entities": [
{
"tableName": "units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`unitId` TEXT NOT NULL, `is_favorite` INTEGER, `paired_unit_id` TEXT, `frequency` INTEGER, PRIMARY KEY(`unitId`))",
"fields": [
{
"fieldPath": "unitId",
"columnName": "unitId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isFavorite",
"columnName": "is_favorite",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "pairedUnitId",
"columnName": "paired_unit_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "frequency",
"columnName": "frequency",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"unitId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "calculator_history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`entityId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `expression` TEXT NOT NULL, `result` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "entityId",
"columnName": "entityId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "expression",
"columnName": "expression",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "result",
"columnName": "result",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"entityId"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd5dca9e0346c3400b7ff5b31e85c7827')"
]
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -0,0 +1,37 @@
/*
* 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.database
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import kotlinx.coroutines.flow.Flow
@Dao
interface CalculatorHistoryDao {
@Query("SELECT * FROM calculator_history ORDER BY timestamp DESC")
fun getAllDescending(): Flow<List<CalculatorHistoryEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(vararg historyEntity: CalculatorHistoryEntity)
@Query("DELETE FROM calculator_history")
suspend fun clear()
}

View File

@ -0,0 +1,31 @@
/*
* 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.database
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "calculator_history")
class CalculatorHistoryEntity(
@PrimaryKey(autoGenerate = true) val entityId: Int = 0,
@ColumnInfo(name = "timestamp") val timestamp: Long,
@ColumnInfo(name = "expression") val expression: String,
@ColumnInfo(name = "result") val result: String
)

View File

@ -1,6 +1,6 @@
/* /*
* Unitto is a unit converter for Android * Unitto is a unit converter for Android
* Copyright (c) 2022-2022 Elshan Agaev * Copyright (c) 2022-2023 Elshan Agaev
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.units.database package com.sadellie.unitto.data.database
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
@ -24,10 +24,10 @@ import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
@Dao @Dao
interface MyBasedUnitDao { interface UnitsDao {
@Query("SELECT * FROM units") @Query("SELECT * FROM units")
suspend fun getAll(): List<MyBasedUnit> suspend fun getAll(): List<UnitsEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUnits(vararg units: MyBasedUnit) suspend fun insertUnits(vararg units: UnitsEntity)
} }

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.units.database package com.sadellie.unitto.data.database
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
@ -30,7 +30,7 @@ import androidx.room.PrimaryKey
* @param frequency Show the amount of time this unit was used * @param frequency Show the amount of time this unit was used
*/ */
@Entity(tableName = "units") @Entity(tableName = "units")
class MyBasedUnit( class UnitsEntity(
@PrimaryKey val unitId: String, @PrimaryKey val unitId: String,
@ColumnInfo(name = "is_favorite") val isFavorite: Boolean?, @ColumnInfo(name = "is_favorite") val isFavorite: Boolean?,
@ColumnInfo(name = "paired_unit_id") val pairedUnitId: String?, @ColumnInfo(name = "paired_unit_id") val pairedUnitId: String?,

View File

@ -1,6 +1,6 @@
/* /*
* Unitto is a unit converter for Android * Unitto is a unit converter for Android
* Copyright (c) 2022-2022 Elshan Agaev * Copyright (c) 2022-2023 Elshan Agaev
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,26 +16,26 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.units.database package com.sadellie.unitto.data.database
import javax.inject.Inject import javax.inject.Inject
class MyBasedUnitsRepository @Inject constructor (private val myBasedUnitDao: MyBasedUnitDao) { class UnitsRepository @Inject constructor (private val unitsDao: UnitsDao) {
/** /**
* Method to insert units. Will rewrite row if unit's id is already in database * Method to insert units. Will rewrite row if unit's id is already in database
* *
* @param unit Unit to add * @param unit Unit to add
*/ */
suspend fun insertUnits(unit: MyBasedUnit) { suspend fun insertUnits(unit: UnitsEntity) {
myBasedUnitDao.insertUnits(unit) unitsDao.insertUnits(unit)
} }
/** /**
* Method to get all units from units table * Method to get all units from units table
* *
* @return List of [MyBasedUnit] objects that represent one row in table * @return List of [UnitsEntity] objects that represent one row in table
*/ */
suspend fun getAll(): List<MyBasedUnit> { suspend fun getAll(): List<UnitsEntity> {
return myBasedUnitDao.getAll() return unitsDao.getAll()
} }
} }

View File

@ -0,0 +1,39 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2022-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.database
import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(
version = 2,
exportSchema = true,
entities = [
UnitsEntity::class,
CalculatorHistoryEntity::class
],
autoMigrations = [
AutoMigration (from = 1, to = 2)
]
)
abstract class UnittoDatabase : RoomDatabase() {
abstract fun unitsDao(): UnitsDao
abstract fun calculatorHistoryDao(): CalculatorHistoryDao
}

View File

@ -1,6 +1,6 @@
/* /*
* Unitto is a unit converter for Android * Unitto is a unit converter for Android
* Copyright (c) 2022-2022 Elshan Agaev * Copyright (c) 2022-2023 Elshan Agaev
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.units.database package com.sadellie.unitto.data.database
import android.content.Context import android.content.Context
import androidx.room.Room import androidx.room.Room
@ -33,30 +33,41 @@ import javax.inject.Singleton
*/ */
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
@Module @Module
class BasedUnitDatabaseModule { class UnittoDatabaseModule {
/** /**
* Tells Hilt to use this method to get [MyBasedUnitDao] * Tells Hilt to use this method to get [UnitsDao]
* *
* @param myBasedUnitDatabase Database for which we need DAO * @param unittoDatabase Database for which we need DAO
* @return Singleton of [MyBasedUnitDao] * @return Singleton of [UnitsDao]
*/ */
@Provides @Provides
fun provideMyBasedUnitDao(myBasedUnitDatabase: MyBasedUnitDatabase): MyBasedUnitDao { fun provideUnitsDao(unittoDatabase: UnittoDatabase): UnitsDao {
return myBasedUnitDatabase.myBasedUnitDao() return unittoDatabase.unitsDao()
} }
/** /**
* Tells Hilt to use this method to get [MyBasedUnitDatabase] * Tells Hilt to use this method to get [CalculatorHistoryDao]
*
* @param unittoDatabase Database for which we need DAO
* @return Singleton of [CalculatorHistoryDao]
*/
@Provides
fun provideCalculatorHistoryDao(unittoDatabase: UnittoDatabase): CalculatorHistoryDao {
return unittoDatabase.calculatorHistoryDao()
}
/**
* Tells Hilt to use this method to get [UnittoDatabase]
* *
* @param appContext Context * @param appContext Context
* @return Singleton of [MyBasedUnitDatabase] * @return Singleton of [UnittoDatabase]
*/ */
@Provides @Provides
@Singleton @Singleton
fun provideMyBasedUnitDatabase(@ApplicationContext appContext: Context): MyBasedUnitDatabase { fun provideUnittoDatabase(@ApplicationContext appContext: Context): UnittoDatabase {
return Room.databaseBuilder( return Room.databaseBuilder(
appContext.applicationContext, appContext.applicationContext,
MyBasedUnitDatabase::class.java, UnittoDatabase::class.java,
"unitto_database" "unitto_database"
).build() ).build()
} }

View File

@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

1
data/model/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

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/>.
*/
plugins {
id("unitto.library")
}
android {
namespace = "com.sadellie.unitto.data.model"
}
dependencies {
implementation(project(mapOf("path" to ":core:base")))
implementation(project(mapOf("path" to ":data:common")))
}

View File

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -16,11 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.model
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.sadellie.unitto.data.lev import com.sadellie.unitto.data.common.lev
import com.sadellie.unitto.data.unitgroups.UnitGroup
import java.math.BigDecimal import java.math.BigDecimal
/** /**

View File

@ -0,0 +1,27 @@
/*
* 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
import java.util.*
data class HistoryItem(
val date: Date,
val expression: String,
val result: String
)

View File

@ -16,13 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.model
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.sadellie.unitto.core.base.MAX_PRECISION import com.sadellie.unitto.core.base.MAX_PRECISION
import com.sadellie.unitto.data.setMinimumRequiredScale import com.sadellie.unitto.data.common.setMinimumRequiredScale
import com.sadellie.unitto.data.trimZeros import com.sadellie.unitto.data.common.trimZeros
import com.sadellie.unitto.data.unitgroups.UnitGroup
import java.math.BigDecimal import java.math.BigDecimal
/** /**

View File

@ -16,10 +16,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.model
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.sadellie.unitto.data.unitgroups.UnitGroup
import java.math.BigDecimal import java.math.BigDecimal
class NumberBaseUnit( class NumberBaseUnit(

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data.unitgroups package com.sadellie.unitto.data.model
import androidx.annotation.StringRes import androidx.annotation.StringRes

View File

@ -30,4 +30,5 @@ dependencies {
implementation(libs.org.burnoutcrew.composereorderable) implementation(libs.org.burnoutcrew.composereorderable)
implementation(project(mapOf("path" to ":core:base"))) implementation(project(mapOf("path" to ":core:base")))
implementation(project(mapOf("path" to ":data:model")))
} }

View File

@ -18,6 +18,8 @@
package com.sadellie.unitto.data.unitgroups package com.sadellie.unitto.data.unitgroups
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.UnitGroup
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock

View File

@ -30,9 +30,6 @@ dependencies {
implementation(libs.androidx.lifecycle.runtime.compose) implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.datastore) implementation(libs.androidx.datastore)
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
kapt(libs.androidx.room.compiler)
implementation(libs.com.squareup.moshi) implementation(libs.com.squareup.moshi)
implementation(libs.com.squareup.retrofit2) implementation(libs.com.squareup.retrofit2)
@ -40,6 +37,8 @@ dependencies {
implementation(libs.org.burnoutcrew.composereorderable) implementation(libs.org.burnoutcrew.composereorderable)
implementation(libs.com.github.sadellie.themmo) implementation(libs.com.github.sadellie.themmo)
implementation(project(mapOf("path" to ":data:unitgroups")))
implementation(project(mapOf("path" to ":core:base"))) implementation(project(mapOf("path" to ":core:base")))
implementation(project(mapOf("path" to ":data:database")))
implementation(project(mapOf("path" to ":data:common")))
implementation(project(mapOf("path" to ":data:model")))
} }

View File

@ -20,7 +20,9 @@ package com.sadellie.unitto.data.units
import android.content.Context import android.content.Context
import com.sadellie.unitto.core.base.MAX_PRECISION import com.sadellie.unitto.core.base.MAX_PRECISION
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.sortByLev
import com.sadellie.unitto.data.units.collections.accelerationCollection import com.sadellie.unitto.data.units.collections.accelerationCollection
import com.sadellie.unitto.data.units.collections.angleCollection import com.sadellie.unitto.data.units.collections.angleCollection
import com.sadellie.unitto.data.units.collections.areaCollection import com.sadellie.unitto.data.units.collections.areaCollection
@ -38,7 +40,7 @@ import com.sadellie.unitto.data.units.collections.speedCollection
import com.sadellie.unitto.data.units.collections.temperatureCollection import com.sadellie.unitto.data.units.collections.temperatureCollection
import com.sadellie.unitto.data.units.collections.timeCollection import com.sadellie.unitto.data.units.collections.timeCollection
import com.sadellie.unitto.data.units.collections.volumeCollection import com.sadellie.unitto.data.units.collections.volumeCollection
import com.sadellie.unitto.data.units.database.MyBasedUnit import com.sadellie.unitto.data.database.UnitsEntity
import java.math.BigDecimal import java.math.BigDecimal
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -153,19 +155,19 @@ class AllUnitsRepository @Inject constructor() {
* *
* @param context [Context] that is used to fill [AbstractUnit.renderedName]. Rendered names are used when * @param context [Context] that is used to fill [AbstractUnit.renderedName]. Rendered names are used when
* searching. * searching.
* @param allBasedUnits List from database. See: [MyBasedUnit]. * @param allUnits List from database. See: [UnitsEntity].
*/ */
fun loadFromDatabase(context: Context, allBasedUnits: List<MyBasedUnit>) { fun loadFromDatabase(context: Context, allUnits: List<UnitsEntity>) {
allUnits.forEach { this.allUnits.forEach {
// Loading unit names so that we can search through them // Loading unit names so that we can search through them
it.renderedName = context.getString(it.displayName) it.renderedName = context.getString(it.displayName)
it.renderedShortName = context.getString(it.shortName) it.renderedShortName = context.getString(it.shortName)
val based = allBasedUnits.firstOrNull { based -> based.unitId == it.unitId } val fromDb = allUnits.firstOrNull { fromDb -> fromDb.unitId == it.unitId }
// Loading paired units // Loading paired units
it.pairedUnit = based?.pairedUnitId it.pairedUnit = fromDb?.pairedUnitId
// Loading favorite state // Loading favorite state
it.isFavorite = based?.isFavorite ?: false it.isFavorite = fromDb?.isFavorite ?: false
it.counter = based?.frequency ?: 0 it.counter = fromDb?.frequency ?: 0
} }
} }

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sadellie.unitto.data package com.sadellie.unitto.data.units
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.units.R
import com.sadellie.unitto.data.unitgroups.UnitGroup
import java.math.BigDecimal import java.math.BigDecimal
internal val accelerationCollection: List<AbstractUnit> by lazy { internal val accelerationCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val angleCollection: List<AbstractUnit> by lazy { internal val angleCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val areaCollection: List<AbstractUnit> by lazy { internal val areaCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val currencyCollection: List<AbstractUnit> by lazy { internal val currencyCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val dataCollection: List<AbstractUnit> by lazy { internal val dataCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val dataTransferCollection: List<AbstractUnit> by lazy { internal val dataTransferCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val energyCollection: List<AbstractUnit> by lazy { internal val energyCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val fluxCollection: List<AbstractUnit> by lazy { internal val fluxCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val lengthCollection: List<AbstractUnit> by lazy { internal val lengthCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val massCollection: List<AbstractUnit> by lazy { internal val massCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.NumberBaseUnit
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.units.NumberBaseUnit import com.sadellie.unitto.data.units.R
import com.sadellie.unitto.data.unitgroups.UnitGroup
internal val numberBaseCollection: List<AbstractUnit> by lazy { internal val numberBaseCollection: List<AbstractUnit> by lazy {
listOf( listOf(

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val powerCollection: List<AbstractUnit> by lazy { internal val powerCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val pressureCollection: List<AbstractUnit> by lazy { internal val pressureCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val speedCollection: List<AbstractUnit> by lazy { internal val speedCollection: List<AbstractUnit> by lazy {

View File

@ -19,12 +19,12 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.core.base.MAX_PRECISION import com.sadellie.unitto.core.base.MAX_PRECISION
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.setMinimumRequiredScale import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.trimZeros import com.sadellie.unitto.data.common.setMinimumRequiredScale
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.common.trimZeros
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
import java.math.RoundingMode import java.math.RoundingMode

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val timeCollection: List<AbstractUnit> by lazy { internal val timeCollection: List<AbstractUnit> by lazy {

View File

@ -18,11 +18,11 @@
package com.sadellie.unitto.data.units.collections package com.sadellie.unitto.data.units.collections
import com.sadellie.unitto.data.units.R import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.units.MyUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.units.R
import java.math.BigDecimal import java.math.BigDecimal
internal val volumeCollection: List<AbstractUnit> by lazy { internal val volumeCollection: List<AbstractUnit> by lazy {

View File

@ -18,8 +18,8 @@
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.units
import com.sadellie.unitto.data.model.NumberBaseUnit
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import org.junit.After import org.junit.After
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test

View File

@ -18,7 +18,10 @@
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.units
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.MyUnit
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.sortByLev
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import java.math.BigDecimal import java.math.BigDecimal

View File

@ -18,7 +18,7 @@
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.units
import com.sadellie.unitto.data.lev import com.sadellie.unitto.data.common.lev
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test

View File

@ -18,7 +18,7 @@
package com.sadellie.unitto.data.units package com.sadellie.unitto.data.units
import com.sadellie.unitto.data.setMinimumRequiredScale import com.sadellie.unitto.data.common.setMinimumRequiredScale
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import java.math.BigDecimal import java.math.BigDecimal

View File

@ -29,7 +29,7 @@ dependencies {
implementation(libs.androidx.datastore) implementation(libs.androidx.datastore)
implementation(libs.com.github.sadellie.themmo) implementation(libs.com.github.sadellie.themmo)
implementation(project(mapOf("path" to ":data:units")))
implementation(project(mapOf("path" to ":data:unitgroups")))
implementation(project(mapOf("path" to ":core:base"))) implementation(project(mapOf("path" to ":core:base")))
implementation(project(mapOf("path" to ":data:model")))
implementation(project(mapOf("path" to ":data:units")))
} }

View File

@ -27,9 +27,9 @@ import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey
import com.sadellie.unitto.core.base.OutputFormat import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.Separator import com.sadellie.unitto.core.base.Separator
import com.sadellie.unitto.data.unitgroups.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import io.github.sadellie.themmo.ThemingMode import io.github.sadellie.themmo.ThemingMode
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow

View File

@ -32,7 +32,9 @@ dependencies {
implementation(libs.org.mariuszgromada.math.mxparser) implementation(libs.org.mariuszgromada.math.mxparser)
implementation(libs.com.github.sadellie.themmo) implementation(libs.com.github.sadellie.themmo)
implementation(project(mapOf("path" to ":data:common")))
implementation(project(mapOf("path" to ":data:userprefs"))) implementation(project(mapOf("path" to ":data:userprefs")))
implementation(project(mapOf("path" to ":data:unitgroups"))) implementation(project(mapOf("path" to ":data:database")))
implementation(project(mapOf("path" to ":data:units"))) implementation(project(mapOf("path" to ":data:calculator")))
implementation(project(mapOf("path" to ":data:model")))
} }

View File

@ -18,14 +18,30 @@
package com.sadellie.unitto.feature.calculator package com.sadellie.unitto.feature.calculator
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable
import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
@ -35,8 +51,15 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.ui.common.UnittoTopAppBar import com.sadellie.unitto.core.ui.common.UnittoTopAppBar
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium
import com.sadellie.unitto.data.model.HistoryItem
import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboard import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboard
import com.sadellie.unitto.feature.calculator.components.DragDownView
import com.sadellie.unitto.feature.calculator.components.HistoryList
import com.sadellie.unitto.feature.calculator.components.InputTextField import com.sadellie.unitto.feature.calculator.components.InputTextField
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.abs
import kotlin.math.roundToInt
@Composable @Composable
internal fun CalculatorRoute( internal fun CalculatorRoute(
@ -53,7 +76,8 @@ internal fun CalculatorRoute(
deleteSymbol = viewModel::deleteSymbol, deleteSymbol = viewModel::deleteSymbol,
onCursorChange = viewModel::onCursorChange, onCursorChange = viewModel::onCursorChange,
toggleAngleMode = viewModel::toggleCalculatorMode, toggleAngleMode = viewModel::toggleCalculatorMode,
evaluate = viewModel::evaluate evaluate = viewModel::evaluate,
clearHistory = viewModel::clearHistory
) )
} }
@ -66,57 +90,144 @@ private fun CalculatorScreen(
deleteSymbol: () -> Unit, deleteSymbol: () -> Unit,
onCursorChange: (IntRange) -> Unit, onCursorChange: (IntRange) -> Unit,
toggleAngleMode: () -> Unit, toggleAngleMode: () -> Unit,
evaluate: () -> Unit evaluate: () -> Unit,
clearHistory: () -> Unit
) { ) {
var showClearHistoryDialog by rememberSaveable { mutableStateOf(false) }
var draggedAmount by remember { mutableStateOf(0f) }
val dragAmountAnimated by animateFloatAsState(draggedAmount)
// val dragAmountAnimated = draggedAmount
var textThingyHeight by remember { mutableStateOf(0) }
var historyItemHeight by remember { mutableStateOf(0) }
UnittoTopAppBar( UnittoTopAppBar(
title = stringResource(R.string.calculator), title = stringResource(R.string.calculator),
navigateUpAction = navigateUpAction, navigateUpAction = navigateUpAction,
) { actions = {
Column(Modifier.padding(it)) { IconButton(
InputTextField( onClick = { showClearHistoryDialog = true },
modifier = Modifier.fillMaxWidth(), content = { Icon(Icons.Default.Delete, stringResource(R.string.calculator_clear_history_title)) }
value = TextFieldValue(
text = uiState.input,
selection = TextRange(uiState.selection.first, uiState.selection.last)
),
onCursorChange = onCursorChange,
pasteCallback = addSymbol
)
AnimatedVisibility(visible = uiState.output.isNotEmpty()) {
Text(
modifier = Modifier.fillMaxWidth(),
// Quick fix to prevent the UI from crashing
text = uiState.output,
textAlign = TextAlign.End,
softWrap = false,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
style = NumbersTextStyleDisplayMedium,
)
}
CalculatorKeyboard(
modifier = Modifier,
addSymbol = addSymbol,
clearSymbols = clearSymbols,
deleteSymbol = deleteSymbol,
toggleAngleMode = toggleAngleMode,
angleMode = uiState.angleMode,
evaluate = evaluate
) )
} }
) { paddingValues ->
DragDownView(
modifier = Modifier.padding(paddingValues),
drag = dragAmountAnimated.toInt(),
historyItemHeight = historyItemHeight,
historyList = {
HistoryList(
modifier = Modifier.fillMaxSize(),
historyItems = uiState.history,
historyItemHeightCallback = { historyItemHeight = it }
)
},
textFields = { maxDragAmount ->
Column(
Modifier
.onPlaced { textThingyHeight = it.size.height }
.draggable(
orientation = Orientation.Vertical,
state = rememberDraggableState { delta ->
draggedAmount = (draggedAmount + delta).coerceAtLeast(0f)
},
onDragStopped = {
// Snap to closest anchor (0, one history item, all history items)
draggedAmount = listOf(0, historyItemHeight, maxDragAmount)
.minBy { abs(draggedAmount.roundToInt() - it) }
.toFloat()
}
)
) {
InputTextField(
modifier = Modifier.fillMaxWidth(),
value = TextFieldValue(
text = uiState.input,
selection = TextRange(uiState.selection.first, uiState.selection.last)
),
onCursorChange = onCursorChange,
pasteCallback = addSymbol
)
Text(
modifier = Modifier.fillMaxWidth(),
text = uiState.output,
textAlign = TextAlign.End,
softWrap = false,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
style = NumbersTextStyleDisplayMedium,
)
}
},
numPad = {
CalculatorKeyboard(
modifier = Modifier,
addSymbol = addSymbol,
clearSymbols = clearSymbols,
deleteSymbol = deleteSymbol,
toggleAngleMode = toggleAngleMode,
angleMode = uiState.angleMode,
evaluate = evaluate
)
}
)
}
if (showClearHistoryDialog) {
AlertDialog(
icon = {
Icon(Icons.Default.Delete, stringResource(R.string.calculator_clear_history_title))
},
title = {
Text(stringResource(R.string.calculator_clear_history_title))
},
text = {
Text(stringResource(R.string.calculator_clear_history_support))
},
confirmButton = {
TextButton(onClick = clearHistory) { Text(stringResource(R.string.calculator_clear_history_label)) }
},
dismissButton = {
TextButton(onClick = { showClearHistoryDialog = false }) { Text(stringResource(R.string.cancel_label)) }
},
onDismissRequest = { showClearHistoryDialog = false }
)
} }
} }
@Preview @Preview
@Composable @Composable
private fun PreviewCalculatorScreen() { private fun PreviewCalculatorScreen() {
val dtf = SimpleDateFormat("dd.MM.yyyy HH:mm:ss", Locale.getDefault())
val historyItems = listOf(
"13.06.1989 23:59:15",
"13.06.1989 23:59:16",
"13.06.1989 23:59:17",
"14.06.1989 23:59:17",
"14.06.1989 23:59:18",
"14.07.1989 23:59:18",
"14.07.1989 23:59:19",
"14.07.2005 23:59:19",
).map {
HistoryItem(
date = dtf.parse(it)!!,
expression = "12345123451234512345123451234512345123451234512345123451234512345",
result = "67890"
)
}
CalculatorScreen( CalculatorScreen(
uiState = CalculatorUIState(), uiState = CalculatorUIState(
input = "12345",
output = "12345",
history = historyItems
),
navigateUpAction = {}, navigateUpAction = {},
addSymbol = {}, addSymbol = {},
clearSymbols = {}, clearSymbols = {},
deleteSymbol = {}, deleteSymbol = {},
onCursorChange = {}, onCursorChange = {},
toggleAngleMode = {}, toggleAngleMode = {},
evaluate = {} evaluate = {},
clearHistory = {}
) )
} }

View File

@ -18,9 +18,12 @@
package com.sadellie.unitto.feature.calculator package com.sadellie.unitto.feature.calculator
import com.sadellie.unitto.data.model.HistoryItem
internal data class CalculatorUIState( internal data class CalculatorUIState(
val input: String = "", val input: String = "",
val output: String = "", val output: String = "",
val selection: IntRange = 0..0, val selection: IntRange = 0..0,
val angleMode: AngleMode = AngleMode.RAD val angleMode: AngleMode = AngleMode.RAD,
val history: List<HistoryItem> = emptyList()
) )

View File

@ -24,9 +24,10 @@ import com.sadellie.unitto.core.base.KEY_LEFT_BRACKET
import com.sadellie.unitto.core.base.KEY_MINUS import com.sadellie.unitto.core.base.KEY_MINUS
import com.sadellie.unitto.core.base.KEY_MINUS_DISPLAY import com.sadellie.unitto.core.base.KEY_MINUS_DISPLAY
import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET
import com.sadellie.unitto.data.setMinimumRequiredScale import com.sadellie.unitto.data.calculator.CalculatorHistoryRepository
import com.sadellie.unitto.data.toStringWith import com.sadellie.unitto.data.common.setMinimumRequiredScale
import com.sadellie.unitto.data.trimZeros import com.sadellie.unitto.data.common.toStringWith
import com.sadellie.unitto.data.common.trimZeros
import com.sadellie.unitto.data.userprefs.UserPreferences import com.sadellie.unitto.data.userprefs.UserPreferences
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@ -47,7 +48,8 @@ import org.mariuszgromada.math.mxparser.mXparser as MathParser
@HiltViewModel @HiltViewModel
internal class CalculatorViewModel @Inject constructor( internal class CalculatorViewModel @Inject constructor(
userPrefsRepository: UserPreferencesRepository userPrefsRepository: UserPreferencesRepository,
private val calculatorHistoryRepository: CalculatorHistoryRepository
) : ViewModel() { ) : ViewModel() {
private val _userPrefs: StateFlow<UserPreferences> = private val _userPrefs: StateFlow<UserPreferences> =
userPrefsRepository.userPreferencesFlow.stateIn( userPrefsRepository.userPreferencesFlow.stateIn(
@ -60,15 +62,17 @@ internal class CalculatorViewModel @Inject constructor(
private val _output: MutableStateFlow<String> = MutableStateFlow("") private val _output: MutableStateFlow<String> = MutableStateFlow("")
private val _selection: MutableStateFlow<IntRange> = MutableStateFlow(IntRange(0, 0)) private val _selection: MutableStateFlow<IntRange> = MutableStateFlow(IntRange(0, 0))
private val _angleMode: MutableStateFlow<AngleMode> = MutableStateFlow(AngleMode.RAD) private val _angleMode: MutableStateFlow<AngleMode> = MutableStateFlow(AngleMode.RAD)
private val _history = calculatorHistoryRepository.historyFlow
val uiState = combine( val uiState = combine(
_input, _output, _selection, _angleMode _input, _output, _selection, _angleMode, _history
) { input, output, selection, angleMode -> ) { input, output, selection, angleMode, history ->
return@combine CalculatorUIState( return@combine CalculatorUIState(
input = input, input = input,
output = output, output = output,
selection = selection, selection = selection,
angleMode = angleMode angleMode = angleMode,
history = history
) )
}.stateIn( }.stateIn(
viewModelScope, SharingStarted.WhileSubscribed(5000L), CalculatorUIState() viewModelScope, SharingStarted.WhileSubscribed(5000L), CalculatorUIState()
@ -115,11 +119,28 @@ internal class CalculatorViewModel @Inject constructor(
fun evaluate() { fun evaluate() {
if (!Expression(_input.value.clean).checkSyntax()) return if (!Expression(_input.value.clean).checkSyntax()) return
// Input and output can change while saving in history. This way we cache it here (i think)
val input = _input.value
val output = _output.value
viewModelScope.launch(Dispatchers.IO) {
calculatorHistoryRepository.add(
expression = input,
result = output
)
}
_input.update { _output.value } _input.update { _output.value }
_selection.update { _input.value.length.._input.value.length } _selection.update { _input.value.length.._input.value.length }
_output.update { "" } _output.update { "" }
} }
fun clearHistory() {
viewModelScope.launch(Dispatchers.IO) {
calculatorHistoryRepository.clear()
}
}
fun onCursorChange(selection: IntRange) { fun onCursorChange(selection: IntRange) {
// When we paste, selection is set to the length of the pasted text (start and end) // When we paste, selection is set to the length of the pasted text (start and end)
if (selection.first > _input.value.length) return if (selection.first > _input.value.length) return

View File

@ -0,0 +1,92 @@
/*
* 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.feature.calculator.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.unit.offset
/**
* Screen layout where [historyList] can be seen only when you drag [textFields] down.
*
* @param modifier [Modifier] that will be applied to [SubcomposeLayout].
* @param drag Drag amount. Update this when dragging [textFields].
* @param historyItemHeight Height of one item in [historyList].
* @param textFields This part of the UI should be used as a handle. Offsets when dragging.
* @param numPad Composable with buttons. Offsets when drag amount is higher than [historyItemHeight]
* (otherwise will just shrink).
*/
@Composable
internal fun DragDownView(
modifier: Modifier,
drag: Int,
historyItemHeight: Int,
historyList: @Composable () -> Unit,
textFields: @Composable (maxDragAmount: Int) -> Unit,
numPad: @Composable () -> Unit
) {
SubcomposeLayout(modifier = modifier) { constraints ->
val showHistory = drag < historyItemHeight
val offset = if (showHistory) (drag - historyItemHeight).coerceAtLeast(0) else 0
val textFieldPlaceables = subcompose(DragDownContent.TextFields) {
textFields(constraints.maxHeight)
}.map { it.measure(constraints.offset(offset)) }
val textFieldsHeight = textFieldPlaceables.maxByOrNull { it.height }?.height ?: 0
val historyListPlaceables = subcompose(DragDownContent.HistoryList) {
historyList()
}.map {
it.measure(
constraints.copy(
maxHeight = drag.coerceAtMost(constraints.maxHeight - textFieldsHeight)
)
)
}
val padding = if (showHistory) drag.coerceAtLeast(0) else historyItemHeight
val numPadConstraints = constraints
.offset(offset)
.copy(maxHeight = constraints.maxHeight - textFieldsHeight - padding)
val numPadPlaceables = subcompose(DragDownContent.NumPad, numPad).map {
it.measure(numPadConstraints)
}
layout(constraints.maxWidth, constraints.maxHeight) {
var yPos = 0
historyListPlaceables.forEach {
it.place(0, yPos)
yPos += it.height
}
textFieldPlaceables.forEach {
it.place(0, yPos)
yPos += it.height
}
numPadPlaceables.forEach {
it.place(0, yPos)
yPos += it.height
}
}
}
}
private enum class DragDownContent { HistoryList, TextFields, NumPad }

View File

@ -0,0 +1,104 @@
/*
* 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.feature.calculator.components
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium
import com.sadellie.unitto.data.model.HistoryItem
import java.text.SimpleDateFormat
import java.util.*
@Composable
internal fun HistoryList(
modifier: Modifier,
historyItems: List<HistoryItem>,
historyItemHeightCallback: (Int) -> Unit
) {
LazyColumn(
modifier = modifier,
reverseLayout = true
) {
items(historyItems) { historyItem ->
Column(
Modifier.onPlaced { historyItemHeightCallback(it.size.height) }
) {
Text(
text = historyItem.expression,
maxLines = 1,
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState(), reverseScrolling = true),
style = NumbersTextStyleDisplayMedium,
textAlign = TextAlign.End
)
Text(
text = historyItem.result,
maxLines = 1,
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState(), reverseScrolling = true),
style = NumbersTextStyleDisplayMedium,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f),
textAlign = TextAlign.End
)
}
}
}
}
@Preview
@Composable
private fun PreviewHistoryList() {
val dtf = SimpleDateFormat("dd.MM.yyyy HH:mm:ss", Locale.getDefault())
val historyItems = listOf(
"13.06.1989 23:59:15",
"13.06.1989 23:59:16",
"13.06.1989 23:59:17",
"14.06.1989 23:59:17",
"14.06.1989 23:59:18",
"14.07.1989 23:59:18",
"14.07.1989 23:59:19",
"14.07.2005 23:59:19",
).map {
HistoryItem(
date = dtf.parse(it)!!,
expression = "12345".repeat(10),
result = "67890"
)
}
HistoryList(
modifier = Modifier.fillMaxWidth(),
historyItems = historyItems,
historyItemHeightCallback = {}
)
}

View File

@ -41,7 +41,9 @@ dependencies {
implementation(libs.com.squareup.moshi) implementation(libs.com.squareup.moshi)
implementation(libs.com.squareup.retrofit2) implementation(libs.com.squareup.retrofit2)
implementation(project(mapOf("path" to ":data:common")))
implementation(project(mapOf("path" to ":data:database")))
implementation(project(mapOf("path" to ":data:model")))
implementation(project(mapOf("path" to ":data:userprefs"))) implementation(project(mapOf("path" to ":data:userprefs")))
implementation(project(mapOf("path" to ":data:unitgroups")))
implementation(project(mapOf("path" to ":data:units"))) implementation(project(mapOf("path" to ":data:units")))
} }

View File

@ -19,7 +19,7 @@
package com.sadellie.unitto.feature.converter package com.sadellie.unitto.feature.converter
import com.sadellie.unitto.core.base.KEY_0 import com.sadellie.unitto.core.base.KEY_0
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
/** /**
* Represents current state of the ConverterScreen * Represents current state of the ConverterScreen

View File

@ -43,19 +43,20 @@ import com.sadellie.unitto.core.base.KEY_PLUS
import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET
import com.sadellie.unitto.core.base.KEY_SQRT import com.sadellie.unitto.core.base.KEY_SQRT
import com.sadellie.unitto.core.base.OPERATORS import com.sadellie.unitto.core.base.OPERATORS
import com.sadellie.unitto.data.combine import com.sadellie.unitto.data.common.setMinimumRequiredScale
import com.sadellie.unitto.data.setMinimumRequiredScale import com.sadellie.unitto.data.common.toStringWith
import com.sadellie.unitto.data.toStringWith import com.sadellie.unitto.data.common.trimZeros
import com.sadellie.unitto.data.trimZeros import com.sadellie.unitto.data.database.UnitsEntity
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.database.UnitsRepository
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.NumberBaseUnit
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.AllUnitsRepository import com.sadellie.unitto.data.units.AllUnitsRepository
import com.sadellie.unitto.data.units.MyUnitIDS import com.sadellie.unitto.data.units.MyUnitIDS
import com.sadellie.unitto.data.units.NumberBaseUnit import com.sadellie.unitto.data.units.combine
import com.sadellie.unitto.data.units.database.MyBasedUnit
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository
import com.sadellie.unitto.data.units.remote.CurrencyApi import com.sadellie.unitto.data.units.remote.CurrencyApi
import com.sadellie.unitto.data.units.remote.CurrencyUnitResponse import com.sadellie.unitto.data.units.remote.CurrencyUnitResponse
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
@ -77,8 +78,8 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class ConverterViewModel @Inject constructor( class ConverterViewModel @Inject constructor(
private val userPrefsRepository: com.sadellie.unitto.data.userprefs.UserPreferencesRepository, private val userPrefsRepository: UserPreferencesRepository,
private val basedUnitRepository: MyBasedUnitsRepository, private val unitRepository: UnitsRepository,
private val allUnitsRepository: AllUnitsRepository private val allUnitsRepository: AllUnitsRepository
) : ViewModel() { ) : ViewModel() {
@ -501,8 +502,8 @@ class ConverterViewModel @Inject constructor(
private fun incrementCounter(unit: AbstractUnit) { private fun incrementCounter(unit: AbstractUnit) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
basedUnitRepository.insertUnits( unitRepository.insertUnits(
MyBasedUnit( UnitsEntity(
unitId = unit.unitId, unitId = unit.unitId,
isFavorite = unit.isFavorite, isFavorite = unit.isFavorite,
pairedUnitId = unit.pairedUnit, pairedUnitId = unit.pairedUnit,
@ -515,8 +516,8 @@ class ConverterViewModel @Inject constructor(
private fun updatePairedUnit(unit: AbstractUnit) { private fun updatePairedUnit(unit: AbstractUnit) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
basedUnitRepository.insertUnits( unitRepository.insertUnits(
MyBasedUnit( UnitsEntity(
unitId = unit.unitId, unitId = unit.unitId,
isFavorite = unit.isFavorite, isFavorite = unit.isFavorite,
pairedUnitId = unit.pairedUnit, pairedUnitId = unit.pairedUnit,

View File

@ -42,8 +42,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.ui.Formatter import com.sadellie.unitto.core.ui.Formatter
import com.sadellie.unitto.core.ui.R import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.feature.converter.ConverterMode import com.sadellie.unitto.feature.converter.ConverterMode
/** /**

View File

@ -40,8 +40,8 @@ import com.sadellie.unitto.core.base.KEY_PLUS
import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET import com.sadellie.unitto.core.base.KEY_RIGHT_BRACKET
import com.sadellie.unitto.core.base.KEY_SQRT import com.sadellie.unitto.core.base.KEY_SQRT
import com.sadellie.unitto.data.units.AllUnitsRepository import com.sadellie.unitto.data.units.AllUnitsRepository
import com.sadellie.unitto.data.units.database.MyBasedUnitDatabase import com.sadellie.unitto.data.database.UnittoDatabase
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository import com.sadellie.unitto.data.database.UnitsRepository
import com.sadellie.unitto.data.userprefs.DataStoreModule import com.sadellie.unitto.data.userprefs.DataStoreModule
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertEquals
@ -72,7 +72,7 @@ class ConverterViewModelTest {
private val allUnitsRepository = AllUnitsRepository() private val allUnitsRepository = AllUnitsRepository()
private val database = Room.inMemoryDatabaseBuilder( private val database = Room.inMemoryDatabaseBuilder(
RuntimeEnvironment.getApplication(), RuntimeEnvironment.getApplication(),
MyBasedUnitDatabase::class.java UnittoDatabase::class.java
).build() ).build()
@Before @Before
@ -84,8 +84,8 @@ class ConverterViewModelTest {
RuntimeEnvironment.getApplication() RuntimeEnvironment.getApplication()
) )
), ),
basedUnitRepository = MyBasedUnitsRepository( unitRepository = UnitsRepository(
database.myBasedUnitDao() database.unitsDao()
), ),
allUnitsRepository = allUnitsRepository allUnitsRepository = allUnitsRepository
) )

View File

@ -31,7 +31,8 @@ dependencies {
implementation(libs.com.github.sadellie.themmo) implementation(libs.com.github.sadellie.themmo)
implementation(libs.org.burnoutcrew.composereorderable) implementation(libs.org.burnoutcrew.composereorderable)
implementation(project(mapOf("path" to ":data:model")))
implementation(project(mapOf("path" to ":data:unitgroups")))
implementation(project(mapOf("path" to ":data:userprefs"))) implementation(project(mapOf("path" to ":data:userprefs")))
implementation(project(mapOf("path" to ":data:licenses"))) implementation(project(mapOf("path" to ":data:licenses")))
implementation(project(mapOf("path" to ":data:unitgroups")))
} }

View File

@ -21,7 +21,7 @@ package com.sadellie.unitto.feature.settings
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.ui.Formatter import com.sadellie.unitto.core.ui.Formatter
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.unitgroups.UnitGroupsRepository import com.sadellie.unitto.data.unitgroups.UnitGroupsRepository
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel

View File

@ -28,6 +28,8 @@ android {
} }
dependencies { dependencies {
implementation(project(mapOf("path" to ":data:model")))
implementation(project(mapOf("path" to ":data:units"))) implementation(project(mapOf("path" to ":data:units")))
implementation(project(mapOf("path" to ":data:database")))
implementation(project(mapOf("path" to ":data:unitgroups"))) implementation(project(mapOf("path" to ":data:unitgroups")))
} }

View File

@ -45,7 +45,7 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.feature.unitslist.components.ChipsRow import com.sadellie.unitto.feature.unitslist.components.ChipsRow
import com.sadellie.unitto.feature.unitslist.components.SearchBar import com.sadellie.unitto.feature.unitslist.components.SearchBar
import com.sadellie.unitto.feature.unitslist.components.SearchPlaceholder import com.sadellie.unitto.feature.unitslist.components.SearchPlaceholder

View File

@ -33,9 +33,9 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.ui.Formatter import com.sadellie.unitto.core.ui.Formatter
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.NumberBaseUnit
import com.sadellie.unitto.data.units.NumberBaseUnit import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.feature.unitslist.components.SearchBar import com.sadellie.unitto.feature.unitslist.components.SearchBar
import com.sadellie.unitto.feature.unitslist.components.SearchPlaceholder import com.sadellie.unitto.feature.unitslist.components.SearchPlaceholder
import com.sadellie.unitto.feature.unitslist.components.UnitGroupHeader import com.sadellie.unitto.feature.unitslist.components.UnitGroupHeader

View File

@ -18,8 +18,8 @@
package com.sadellie.unitto.feature.unitslist package com.sadellie.unitto.feature.unitslist
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.UnitGroup
/** /**
* Second (unit list) screen UI state. * Second (unit list) screen UI state.

View File

@ -21,11 +21,11 @@ package com.sadellie.unitto.feature.unitslist
import android.app.Application import android.app.Application
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.database.UnitsEntity
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.database.UnitsRepository
import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.units.AllUnitsRepository import com.sadellie.unitto.data.units.AllUnitsRepository
import com.sadellie.unitto.data.units.database.MyBasedUnit
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository
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
@ -39,7 +39,7 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class SecondViewModel @Inject constructor( class SecondViewModel @Inject constructor(
private val basedUnitRepository: MyBasedUnitsRepository, private val unitRepository: UnitsRepository,
private val allUnitsRepository: AllUnitsRepository, private val allUnitsRepository: AllUnitsRepository,
private val mContext: Application, private val mContext: Application,
unitGroupsRepository: com.sadellie.unitto.data.unitgroups.UnitGroupsRepository, unitGroupsRepository: com.sadellie.unitto.data.unitgroups.UnitGroupsRepository,
@ -136,8 +136,8 @@ class SecondViewModel @Inject constructor(
// Changing unit in list to the opposite // Changing unit in list to the opposite
unit.isFavorite = !unit.isFavorite unit.isFavorite = !unit.isFavorite
// Updating it in database // Updating it in database
basedUnitRepository.insertUnits( unitRepository.insertUnits(
MyBasedUnit( UnitsEntity(
unitId = unit.unitId, unitId = unit.unitId,
isFavorite = unit.isFavorite, isFavorite = unit.isFavorite,
pairedUnitId = unit.pairedUnit, pairedUnitId = unit.pairedUnit,
@ -147,15 +147,15 @@ class SecondViewModel @Inject constructor(
} }
} }
private fun loadBasedUnits() { private fun loadUnits() {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
// Now we load units data from database // Now we load units data from database
val allBasedUnits = basedUnitRepository.getAll() val allUnits = unitRepository.getAll()
allUnitsRepository.loadFromDatabase(mContext, allBasedUnits) allUnitsRepository.loadFromDatabase(mContext, allUnits)
} }
} }
init { init {
loadBasedUnits() loadUnits()
} }
} }

View File

@ -46,8 +46,8 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.sadellie.unitto.data.unitgroups.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.feature.unitslist.R import com.sadellie.unitto.feature.unitslist.R
/** /**

View File

@ -24,7 +24,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.ui.common.Header import com.sadellie.unitto.core.ui.common.Header
import com.sadellie.unitto.data.unitgroups.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
@Composable @Composable
internal fun UnitGroupHeader(modifier: Modifier, unitGroup: UnitGroup) { internal fun UnitGroupHeader(modifier: Modifier, unitGroup: UnitGroup) {

View File

@ -53,7 +53,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.feature.unitslist.R import com.sadellie.unitto.feature.unitslist.R
/** /**

View File

@ -21,7 +21,7 @@ package com.sadellie.unitto.feature.unitslist.navigation
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import com.sadellie.unitto.data.units.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.units.AllUnitsRepository import com.sadellie.unitto.data.units.AllUnitsRepository
import com.sadellie.unitto.feature.unitslist.LeftSideScreen import com.sadellie.unitto.feature.unitslist.LeftSideScreen
import com.sadellie.unitto.feature.unitslist.RightSideScreen import com.sadellie.unitto.feature.unitslist.RightSideScreen

View File

@ -30,3 +30,7 @@ include(":data:userprefs")
include(":data:unitgroups") include(":data:unitgroups")
include(":data:licenses") include(":data:licenses")
include(":data:epoch") include(":data:epoch")
include(":data:calculator")
include(":data:database")
include(":data:model")
include(":data:common")