Merge remote-tracking branch 'origin/Florian'

# Conflicts:
#	Ledger/app/src/main/java/at/xaxa/ledger/ui/home/HomeUI.kt
This commit is contained in:
Xaver 2025-01-14 10:33:15 +01:00
commit 9845a7fd75
16 changed files with 199 additions and 49 deletions

View File

@ -1,6 +1,8 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("com.google.devtools.ksp") version "1.9.0-1.0.12"
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10"
}
android {
@ -50,6 +52,11 @@ android {
}
dependencies {
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
ksp(libs.androidx.room.compiler)
//implementation(libs.androidx.room.common)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
@ -59,9 +66,8 @@ dependencies {
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.room.common)
implementation(libs.androidx.room.ktx)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.lifecycle.runtime.compose.android)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

View File

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".LedgerApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"

View File

@ -6,8 +6,8 @@ import at.xaxa.ledger.data.db.LedgerDatabase
class LedgerApplication : Application(){
val entryRepository by lazy {
/*EntryRepository(
DatabaseInstance.getDatabase(this).LedgerDao()
)*/
EntryRepository(
LedgerDatabase.getDatabase(this).ledgerDao()
)
}
}

View File

@ -5,5 +5,5 @@ class Entry (
val name: String,
val amount: Float,
val date: Long,
val categoryName: Int
val categoryID: Int
)

View File

@ -8,28 +8,28 @@ import kotlinx.coroutines.flow.map
class EntryRepository(private val ledgerDao: LedgerDao){
/*
fun getAllEntries(): Flow<List<Entry>> {
return ledgerDao.getAllEntries().map {
it.map {entry -> Entry(entry._id, entry.name, entry.amount, entry.date, entry.categoryName) }
it.map {entry -> Entry(entry._id, entry.name, entry.amount, entry.date, entry.categoryID) }
}
}
suspend fun findEntryById(id: Int): Entry {
val entry = LedgerDao.findEntryById(id)
val entry = ledgerDao.findEntryById(id)
return Entry(
entry._id, entry.name, entry.amount, entry.date, entry.categoryName
entry._id, entry.name, entry.amount, entry.date, entry.categoryID
)
}
suspend fun insertEntry(entry: Entry) {
LedgerDao.addEntry(EntryEntity(_id=0, entry.name, entry.amount, entry.date, entry.categoryName))
ledgerDao.addEntry(EntryEntity(_id=0, entry.name, entry.amount, entry.date, entry.categoryID))
}
suspend fun updateEntry(entry: Entry) {
LedgerDao.updateEntry(EntryEntity(entry.id, entry.name, entry.amount, entry.date, entry.categoryName))
ledgerDao.updateEntry(EntryEntity(entry.id, entry.name, entry.amount, entry.date, entry.categoryID))
}
suspend fun deleteEntry(entry: Entry) {
ledgerDao.deleteEntry(EntryEntity(_id = entry.id, entry.name, entry.amount, entry.date, entry.categoryID))
}
suspend fun deletePokemon(entry: Entry) {
LedgerDao.deleteEntry(EntryEntity(_id = entry.id, entry.name, entry.amount, entry.date, entry.categoryName))
}*/
}

View File

@ -7,6 +7,6 @@ import androidx.room.PrimaryKey
data class CategoryEntity(
@PrimaryKey(autoGenerate = true)
val _id: Int = 0,
val categoryname: String,
val categoryName: String,
val icon: Int
)

View File

@ -1,20 +0,0 @@
import android.content.Context
import androidx.room.Room
import at.xaxa.ledger.data.db.LedgerDatabase
object DatabaseInstance {
@Volatile
private var INSTANCE: LedgerDatabase? = null
fun getDatabase(context: Context): LedgerDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
LedgerDatabase::class.java,
"ledger_database"
).build()
INSTANCE = instance
instance
}
}
}

View File

@ -3,12 +3,12 @@ package at.xaxa.ledger.data.db.Entry
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "transaction")
@Entity(tableName = "_transaction")
data class EntryEntity(
@PrimaryKey(autoGenerate = true)
val _id: Int = 0,
val name: String,
val amount: Float,
val date: Long,
val categoryName: Int
val categoryID: Int,
)

View File

@ -0,0 +1,15 @@
package at.xaxa.ledger.data.db
import androidx.room.Embedded
import androidx.room.Relation
import at.xaxa.ledger.data.db.Entry.EntryEntity
import at.xaxa.ledger.data.db.Category.CategoryEntity
data class EntryCategoryRelation(
@Embedded val entry: EntryEntity,
@Relation(
parentColumn = "categoryID",
entityColumn = "_id"
)
val category: CategoryEntity
)

View File

@ -5,6 +5,7 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import at.xaxa.ledger.data.db.Category.CategoryEntity
import at.xaxa.ledger.data.db.Entry.EntryEntity
@ -13,20 +14,24 @@ import kotlinx.coroutines.flow.Flow
@Dao
interface LedgerDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addCategory(entryEntity: CategoryEntity)
suspend fun addCategory(categoryEntity: CategoryEntity)
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addEntry(entryEntity: EntryEntity)
@Transaction
@Query("SELECT * FROM _transaction WHERE categoryID = :categoryID")
suspend fun getEntryWithCategoryID(categoryID: String): List<EntryCategoryRelation>
@Update
suspend fun updateCategory(category: CharCategory)
suspend fun updateCategory(categoryEntity: CategoryEntity)
@Update
suspend fun updateEntry(entryEntity: EntryEntity)
@Delete
suspend fun deleteCategory(category: CharCategory)
suspend fun deleteCategory(categoryEntity: CategoryEntity)
@Delete
@ -41,10 +46,11 @@ interface LedgerDao {
fun getAllCategory(): Flow<List<CategoryEntity>>
@Query("SELECT * FROM transaction WHERE _id = :id")
@Query("SELECT * FROM _transaction WHERE _id = :id")
suspend fun findEntryById(id: Int) : EntryEntity
@Query("SELECT * FROM transaction")
@Query("SELECT * FROM _transaction")
fun getAllEntries(): Flow<List<EntryEntity>>
}

View File

@ -1,12 +1,34 @@
package at.xaxa.ledger.data.db
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import at.xaxa.ledger.data.db.Category.CategoryEntity
import at.xaxa.ledger.data.db.Entry.EntryEntity
@Database(entities = [EntryEntity::class, CategoryEntity::class], version = 1, exportSchema = false)
abstract class LedgerDatabase : RoomDatabase() {
/*abstract fun entryDao(): EntryDao
abstract fun categoryDao(): CategoryDao*/
abstract fun ledgerDao(): LedgerDao
companion object {
@Volatile
private var Instance: LedgerDatabase? = null
fun getDatabase(context: Context): LedgerDatabase {
return Instance ?: synchronized(this){
val instance =
Room.databaseBuilder(
context.applicationContext,
LedgerDatabase::class.java,
"ledger_database"
).fallbackToDestructiveMigration()
.build()
Instance = instance
return instance
}
}
}
}

View File

@ -1,5 +1,26 @@
package at.xaxa.ledger.ui
object AppViewModelProvider {
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import at.xaxa.ledger.LedgerApplication
import at.xaxa.ledger.ui.edit.EditViewModel
import at.xaxa.ledger.ui.home.HomeViewModel
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
HomeViewModel((this[APPLICATION_KEY] as LedgerApplication).entryRepository)
}
/*initializer {
AddViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LedgerApplication).entryRepository)
}*/
initializer {
EditViewModel(this.createSavedStateHandle(), (this[APPLICATION_KEY] as LedgerApplication).entryRepository)
}
}
}

View File

@ -1,2 +1,54 @@
package at.xaxa.ledger.ui.edit
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import at.xaxa.ledger.data.Entry
import at.xaxa.ledger.data.EntryRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
data class EditUI(
val entry: Entry = Entry(0, "", 0.0f, 0, 0)
)
class EditViewModel(private val savedStateHandle: SavedStateHandle,
private val entryRepository: EntryRepository) : ViewModel() {
private val entryId: Int = checkNotNull(savedStateHandle["entryId"])
var editUiState by mutableStateOf(EditUI())
private set
init {
viewModelScope.launch {
val entry = withContext(Dispatchers.IO) {
entryRepository.findEntryById(entryId)
}
editUiState = EditUI(entry)
}
}
fun updateEntry(entry: Entry) {
editUiState = editUiState.copy(entry=entry)
}
fun onDeleteEntry(entry: Entry) {
viewModelScope.launch {
entryRepository.deleteEntry(entry)
}
}
fun saveEntry() {
viewModelScope.launch {
entryRepository.updateEntry(editUiState.entry)
}
}
}

View File

@ -13,17 +13,22 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import at.xaxa.ledger.ui.ButtonSuccess
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import at.xaxa.ledger.ui.AppViewModelProvider
import at.xaxa.ledger.ui.HeaderCard
import at.xaxa.ledger.ui.HorizontalCard
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Home(modifier: Modifier = Modifier, onCardClick: (Int) -> Unit) {
fun Home(modifier: Modifier = Modifier, onCardClick: (Int) -> Unit, HomeViewModel : HomeViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val state by HomeViewModel.entryUIState.entry.collectAsState(initial = emptyList())
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally

View File

@ -1,2 +1,38 @@
package at.xaxa.ledger.ui.home
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import at.xaxa.ledger.data.Entry
import at.xaxa.ledger.data.EntryRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
data class EntryListUIState(val entry: Flow<List<Entry>> = flowOf(emptyList()))
class HomeViewModel(private val repository: EntryRepository): ViewModel() {
var entryUIState by mutableStateOf(EntryListUIState())
init{
viewModelScope.launch {
val entries = withContext(Dispatchers.IO){
repository.getAllEntries()
}
entryUIState = EntryListUIState(entries)
}
}
/* val entryUIState = repository.getAllEntries()
.map {EntryListUIState(it)}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = EntryListUIState(emptyList())
)*/
}

View File

@ -9,11 +9,16 @@ lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.9.3"
composeBom = "2024.04.01"
roomCommon = "2.6.1"
roomCompiler = "2.6.1"
roomKtx = "2.6.1"
navigationCompose = "2.8.5"
lifecycleRuntimeComposeAndroid = "2.8.7"
roomRuntime = "2.6.1"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomCompiler" }
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomRuntime" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
@ -30,6 +35,7 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3"
androidx-room-common = { group = "androidx.room", name = "room-common", version.ref = "roomCommon" }
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "roomKtx" }
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
androidx-lifecycle-runtime-compose-android = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose-android", version.ref = "lifecycleRuntimeComposeAndroid" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }