Compare commits

..

3 Commits

Author SHA1 Message Date
Rafal Wisniewski
bfbb1056d7 init 2026-04-30 09:58:14 +02:00
Rafal Wisniewski
43aec61c75 init 2026-04-29 15:59:17 +02:00
Rafal Wisniewski
e6c8cf5cd3 init 2026-04-29 15:58:20 +02:00
7 changed files with 44 additions and 81 deletions

View File

@@ -10,7 +10,9 @@ plugins {
android { android {
namespace = "cc.n0th1ng.tripmoney" namespace = "cc.n0th1ng.tripmoney"
compileSdk = 36 compileSdk = 36
buildFeatures {
buildConfig = true
}
defaultConfig { defaultConfig {
applicationId = "cc.n0th1ng.tripmoney" applicationId = "cc.n0th1ng.tripmoney"
minSdk = 24 minSdk = 24

View File

@@ -7,6 +7,7 @@ import androidx.room.Database
import androidx.room.Room import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverters import androidx.room.TypeConverters
import cc.n0th1ng.tripmoney.BuildConfig
import cc.n0th1ng.tripmoney.data.dao.CategoryDao import cc.n0th1ng.tripmoney.data.dao.CategoryDao
import cc.n0th1ng.tripmoney.data.dao.ExchangeRateDao import cc.n0th1ng.tripmoney.data.dao.ExchangeRateDao
import cc.n0th1ng.tripmoney.data.dao.ExpenseDao import cc.n0th1ng.tripmoney.data.dao.ExpenseDao
@@ -34,8 +35,7 @@ import javax.inject.Singleton
import kotlin.random.Random import kotlin.random.Random
@Database( @Database(
entities = [Trip::class, Expense::class, Category::class, ExchangeRate::class], entities = [Trip::class, Expense::class, Category::class, ExchangeRate::class], version = 1
version = 1
) )
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class TripDatabase : RoomDatabase() { abstract class TripDatabase : RoomDatabase() {
@@ -57,16 +57,19 @@ object DatabaseModule {
fun provideTripDatabase( fun provideTripDatabase(
@ApplicationContext context: Context @ApplicationContext context: Context
): TripDatabase { ): TripDatabase {
val db: TripDatabase = Room.inMemoryDatabaseBuilder( val builder = if (BuildConfig.DEBUG) Room.inMemoryDatabaseBuilder(
// val db: TripDatabase = Room.databaseBuilder( context = context, klass = TripDatabase::class.java
// name = "tripmoney_db", ) else Room.databaseBuilder(
name = "tripmoney_db",
context = context, context = context,
klass = TripDatabase::class.java, klass = TripDatabase::class.java,
) )
.allowMainThreadQueries() // TODO Remove in production!
.fallbackToDestructiveMigration() // TODO Handle schema changes during dev val db: TripDatabase =
builder.fallbackToDestructiveMigration() // TODO Handle schema changes during dev
.build() .build()
if (BuildConfig.DEBUG) {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
DatabasePrepopulator( DatabasePrepopulator(
tripDao = db.tripDao(), tripDao = db.tripDao(),
@@ -74,6 +77,8 @@ object DatabaseModule {
expenseDao = db.expenseDao() expenseDao = db.expenseDao()
).prepopulate() ).prepopulate()
} }
}
return db return db
} }
@@ -147,74 +152,46 @@ private class DatabasePrepopulator(
val sampleCategories = listOf( val sampleCategories = listOf(
Category( Category(
name = "Hotel", name = "Hotel", icon = Icons.HOTEL, color = colors.random()
icon = Icons.HOTEL,
color = colors.random()
), ),
Category( Category(
name = "Jedzenie", name = "Jedzenie", icon = Icons.RESTAURANT, color = colors.random()
icon = Icons.RESTAURANT,
color = colors.random()
), ),
Category( Category(
name = "Transport", name = "Transport", icon = Icons.FLIGHT, color = colors.random()
icon = Icons.FLIGHT,
color = colors.random()
), ),
Category( Category(
name = "Rozrywka", name = "Rozrywka", icon = Icons.ATTRACTION, color = colors.random()
icon = Icons.ATTRACTION,
color = colors.random()
), ),
Category( Category(
name = "Zakupy", name = "Zakupy", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy1", name = "Zakupy1", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy2", name = "Zakupy2", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy3", name = "Zakupy3", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy4", name = "Zakupy4", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy5", name = "Zakupy5", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy6", name = "Zakupy6", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy7", name = "Zakupy7", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy8", name = "Zakupy8", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
Category( Category(
name = "Zakupy9", name = "Zakupy9", icon = Icons.GROCERIES, color = colors.random()
icon = Icons.GROCERIES,
color = colors.random()
), ),
) )
@@ -240,8 +217,7 @@ private class DatabasePrepopulator(
note = if (i % 3 == 0) "Some note" else "", note = if (i % 3 == 0) "Some note" else "",
datetime = datetime, datetime = datetime,
rate = if (Random.nextBoolean()) Random.nextDouble( rate = if (Random.nextBoolean()) Random.nextDouble(
0.1, 0.1, 5.0
5.0
) else 1.0 ) else 1.0
) )
expense expense

View File

@@ -7,7 +7,6 @@ import androidx.room.Query
import androidx.room.RewriteQueriesToDropUnusedColumns import androidx.room.RewriteQueriesToDropUnusedColumns
import androidx.room.Transaction import androidx.room.Transaction
import androidx.room.Upsert import androidx.room.Upsert
import cc.n0th1ng.tripmoney.data.entity.Category
import cc.n0th1ng.tripmoney.data.entity.Expense import cc.n0th1ng.tripmoney.data.entity.Expense
import cc.n0th1ng.tripmoney.data.entity.ExpenseDto import cc.n0th1ng.tripmoney.data.entity.ExpenseDto
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -100,7 +99,7 @@ interface ExpenseDao {
WHERE trip.id = :tripId WHERE trip.id = :tripId
""" """
) )
fun budgetLeft(tripId: Int): Double? fun budgetLeft(tripId: Int): Flow<Double?>
@Delete @Delete
suspend fun delete(expense: Expense) suspend fun delete(expense: Expense)

View File

@@ -13,7 +13,6 @@ import cc.n0th1ng.tripmoney.data.entity.ExpenseDto
import cc.n0th1ng.tripmoney.utils.Currencies import cc.n0th1ng.tripmoney.utils.Currencies
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import java.util.OptionalDouble
import javax.inject.Inject import javax.inject.Inject
class ExpenseRepository @Inject constructor( class ExpenseRepository @Inject constructor(
@@ -21,7 +20,7 @@ class ExpenseRepository @Inject constructor(
private val exchangeRateRepository: ExchangeRateRepository private val exchangeRateRepository: ExchangeRateRepository
) { ) {
fun getBudgetLeft(tripId: Int): Double? { fun getBudgetLeft(tripId: Int): Flow<Double?> {
return expenseDao.budgetLeft(tripId) return expenseDao.budgetLeft(tripId)
} }

View File

@@ -1,6 +1,5 @@
package cc.n0th1ng.tripmoney.screens.settings package cc.n0th1ng.tripmoney.screens.settings
import android.content.Intent
import android.os.Build import android.os.Build
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.annotation.StringRes import androidx.annotation.StringRes
@@ -36,34 +35,23 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
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.compose.ui.unit.sp
import androidx.core.content.FileProvider
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import cc.n0th1ng.tripmoney.R.string
import cc.n0th1ng.tripmoney.R.*
import cc.n0th1ng.tripmoney.data.entity.Category
import cc.n0th1ng.tripmoney.data.entity.Trip import cc.n0th1ng.tripmoney.data.entity.Trip
import cc.n0th1ng.tripmoney.data.repository.AppTheme import cc.n0th1ng.tripmoney.data.repository.AppTheme
import cc.n0th1ng.tripmoney.navigation.Screens import cc.n0th1ng.tripmoney.navigation.Screens
import cc.n0th1ng.tripmoney.screens.listexpense.CategorySelectionDialog
import cc.n0th1ng.tripmoney.screens.listexpense.CurrencySelectionDialog import cc.n0th1ng.tripmoney.screens.listexpense.CurrencySelectionDialog
import cc.n0th1ng.tripmoney.screens.statistics.categories
import cc.n0th1ng.tripmoney.theme.TripMoneyTheme import cc.n0th1ng.tripmoney.theme.TripMoneyTheme
import cc.n0th1ng.tripmoney.utils.AllPreviews import cc.n0th1ng.tripmoney.utils.AllPreviews
import cc.n0th1ng.tripmoney.utils.Currencies import cc.n0th1ng.tripmoney.utils.Currencies
import cc.n0th1ng.tripmoney.utils.Icons
import cc.n0th1ng.tripmoney.utils.saveCsv
import cc.n0th1ng.tripmoney.utils.shareCsv import cc.n0th1ng.tripmoney.utils.shareCsv
import cc.n0th1ng.tripmoney.viewmodel.ExpenseAndCategoryViewModel import cc.n0th1ng.tripmoney.viewmodel.ExpenseAndCategoryViewModel
import cc.n0th1ng.tripmoney.viewmodel.SettingsViewModel import cc.n0th1ng.tripmoney.viewmodel.SettingsViewModel
import cc.n0th1ng.tripmoney.viewmodel.TripViewModel import cc.n0th1ng.tripmoney.viewmodel.TripViewModel
import com.composables.icons.materialsymbols.outlined.R import com.composables.icons.materialsymbols.outlined.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.nio.file.Files
@RequiresApi(Build.VERSION_CODES.S) @RequiresApi(Build.VERSION_CODES.S)
@Composable @Composable
@@ -168,7 +156,7 @@ fun SettingsScreen(
iconResource = R.drawable.materialsymbols_ic_label_outlined iconResource = R.drawable.materialsymbols_ic_label_outlined
) )
SettingsListItem( SettingsListItem(
onClick = onCategoriesClick, onClick = {},
stringResource(string.add_expense), stringResource(string.add_expense),
supportingText = stringResource(string.add_expense_settings), supportingText = stringResource(string.add_expense_settings),
iconResource = R.drawable.materialsymbols_ic_payments_outlined, iconResource = R.drawable.materialsymbols_ic_payments_outlined,

View File

@@ -60,11 +60,12 @@ fun StatisticsScreen() {
.collectAsState(emptyList()) .collectAsState(emptyList())
val summaryAmount by expenseAndCategoryViewModel.getSummaryAmount(currentTripId) val summaryAmount by expenseAndCategoryViewModel.getSummaryAmount(currentTripId)
.collectAsState(0.0) .collectAsState(0.0)
val moneyLeft by expenseAndCategoryViewModel.getBudgetLeft(currentTripId).collectAsState(null)
StatisticsScreen( StatisticsScreen(
summaryPerCategoryList, summaryPerCategoryList,
summaryAmount, summaryAmount,
Currencies.valueOf(currentTrip?.currency ?: Currencies.default().name), Currencies.valueOf(currentTrip?.currency ?: Currencies.default().name),
expenseAndCategoryViewModel.getBudgetLeft(currentTripId) moneyLeft
) )
} }

View File

@@ -29,9 +29,7 @@ import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVPrinter import org.apache.commons.csv.CSVPrinter
import java.io.File import java.io.File
import java.time.LocalDate import java.time.LocalDate
import java.util.OptionalDouble
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.mapValues
@HiltViewModel @HiltViewModel
@@ -42,7 +40,7 @@ open class ExpenseAndCategoryViewModel @Inject constructor(
private val tripRepo: TripRepository private val tripRepo: TripRepository
) : ViewModel() { ) : ViewModel() {
fun getBudgetLeft(tripId: Int): Double? { fun getBudgetLeft(tripId: Int): Flow<Double?> {
return expenseRepo.getBudgetLeft(tripId) return expenseRepo.getBudgetLeft(tripId)
} }