分类迁移到设置

增加时间分类
This commit is contained in:
yovinchen 2024-11-26 23:49:02 +08:00
parent b794c8b91e
commit 316c2648ae
3 changed files with 290 additions and 166 deletions

View File

@ -7,67 +7,54 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.yovinchen.bookkeeping.model.BookkeepingRecord import com.yovinchen.bookkeeping.model.BookkeepingRecord
import com.yovinchen.bookkeeping.model.TransactionType import com.yovinchen.bookkeeping.model.TransactionType
import com.yovinchen.bookkeeping.ui.dialog.AddRecordDialog import com.yovinchen.bookkeeping.ui.dialog.AddRecordDialog
import com.yovinchen.bookkeeping.ui.dialog.CategoryManagementDialog
import com.yovinchen.bookkeeping.ui.dialog.RecordEditDialog import com.yovinchen.bookkeeping.ui.dialog.RecordEditDialog
import com.yovinchen.bookkeeping.viewmodel.HomeViewModel import com.yovinchen.bookkeeping.viewmodel.HomeViewModel
import java.time.YearMonth
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun HomeScreen( fun HomeScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier, viewModel: HomeViewModel = viewModel()
viewModel: HomeViewModel = viewModel()
) { ) {
val records by viewModel.filteredRecords.collectAsState() val filteredRecords by viewModel.filteredRecords.collectAsState()
val totalIncome by viewModel.totalIncome.collectAsState() val totalIncome by viewModel.totalIncome.collectAsState()
val totalExpense by viewModel.totalExpense.collectAsState() val totalExpense by viewModel.totalExpense.collectAsState()
val categories by viewModel.categories.collectAsState() val categories by viewModel.categories.collectAsState()
val selectedType by viewModel.selectedCategoryType.collectAsState()
val selectedRecordType by viewModel.selectedRecordType.collectAsState() val selectedRecordType by viewModel.selectedRecordType.collectAsState()
val selectedMonth by viewModel.selectedMonth.collectAsState()
var showAddDialog by remember { mutableStateOf(false) } var showAddDialog by remember { mutableStateOf(false) }
var showCategoryDialog by remember { mutableStateOf(false) }
var selectedRecord by remember { mutableStateOf<BookkeepingRecord?>(null) } var selectedRecord by remember { mutableStateOf<BookkeepingRecord?>(null) }
Scaffold( Scaffold(modifier = modifier.fillMaxSize(), floatingActionButton = {
modifier = modifier.fillMaxSize(), FloatingActionButton(onClick = { showAddDialog = true }) {
floatingActionButton = { Icon(Icons.Default.Add, contentDescription = "添加记录")
FloatingActionButton(
onClick = { showAddDialog = true }
) {
Icon(Icons.Default.Add, contentDescription = "添加记录")
}
},
floatingActionButtonPosition = FabPosition.End,
topBar = {
TopAppBar(
title = { Text("记账本") },
actions = {
IconButton(onClick = { showCategoryDialog = true }) {
Icon(Icons.Default.Settings, contentDescription = "类别管理")
}
}
)
} }
) { padding -> }, floatingActionButtonPosition = FabPosition.End, topBar = {
TopAppBar(title = { Text("记账本") })
}) { padding ->
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(padding) .padding(padding)
.background(MaterialTheme.colorScheme.background)
) { ) {
// 顶部统计信息 // 顶部统计信息
MonthlyStatistics( MonthlyStatistics(
@ -76,21 +63,90 @@ fun HomeScreen(
onIncomeClick = { viewModel.setSelectedRecordType(TransactionType.INCOME) }, onIncomeClick = { viewModel.setSelectedRecordType(TransactionType.INCOME) },
onExpenseClick = { viewModel.setSelectedRecordType(TransactionType.EXPENSE) }, onExpenseClick = { viewModel.setSelectedRecordType(TransactionType.EXPENSE) },
selectedType = selectedRecordType, selectedType = selectedRecordType,
onClearFilter = { viewModel.setSelectedRecordType(null) } onClearFilter = { viewModel.setSelectedRecordType(null) },
selectedMonth = selectedMonth,
onPreviousMonth = { viewModel.setSelectedMonth(selectedMonth.minusMonths(1)) },
onNextMonth = { viewModel.setSelectedMonth(selectedMonth.plusMonths(1)) }
) )
// 记录列表 // 记录列表
LazyColumn( LazyColumn(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp), contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
items(records) { record -> filteredRecords.forEach { (date, records) ->
RecordItem( item {
record = record, Surface(
onClick = { selectedRecord = record }, modifier = Modifier
onDelete = { viewModel.deleteRecord(record) } .fillMaxWidth()
) .padding(vertical = 4.dp),
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.7f),
shape = RoundedCornerShape(12.dp),
tonalElevation = 2.dp
) {
Column(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)
) {
// 日期标签
Text(
text = SimpleDateFormat(
"yyyy年MM月dd日 E", Locale.CHINESE
).format(date),
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(12.dp))
// 当天的记录
records.forEachIndexed { index, record ->
RecordItem(record = record,
onClick = { selectedRecord = record },
onDelete = { viewModel.deleteRecord(record) })
if (index < records.size - 1) {
HorizontalDivider(
modifier = Modifier.padding(vertical = 8.dp),
color = MaterialTheme.colorScheme.surfaceVariant,
thickness = 0.5.dp
)
}
}
Spacer(modifier = Modifier.height(8.dp))
// 当天统计
HorizontalDivider(
color = MaterialTheme.colorScheme.surfaceVariant,
thickness = 0.5.dp
)
val dayIncome = records.filter { it.type == TransactionType.INCOME }
.sumOf { it.amount }
val dayExpense =
records.filter { it.type == TransactionType.EXPENSE }
.sumOf { it.amount }
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 12.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "收入: ¥%.2f".format(dayIncome),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary
)
Text(
text = "支出: ¥%.2f".format(dayExpense),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error
)
}
}
}
}
} }
} }
} }
@ -98,9 +154,10 @@ fun HomeScreen(
// 添加记录对话框 // 添加记录对话框
if (showAddDialog) { if (showAddDialog) {
val selectedDateTime by viewModel.selectedDateTime.collectAsState() val selectedDateTime by viewModel.selectedDateTime.collectAsState()
val selectedCategoryType by viewModel.selectedCategoryType.collectAsState()
AddRecordDialog( AddRecordDialog(
onDismiss = { onDismiss = {
showAddDialog = false showAddDialog = false
viewModel.resetSelectedDateTime() viewModel.resetSelectedDateTime()
}, },
onConfirm = { type, amount, category, description -> onConfirm = { type, amount, category, description ->
@ -108,23 +165,10 @@ fun HomeScreen(
showAddDialog = false showAddDialog = false
}, },
categories = categories, categories = categories,
selectedType = selectedType, selectedType = selectedCategoryType,
onTypeChange = { viewModel.setSelectedCategoryType(it) }, onTypeChange = viewModel::setSelectedCategoryType,
selectedDateTime = selectedDateTime, selectedDateTime = selectedDateTime,
onDateTimeSelected = { viewModel.setSelectedDateTime(it) } onDateTimeSelected = viewModel::setSelectedDateTime
)
}
// 类别管理对话框
if (showCategoryDialog) {
CategoryManagementDialog(
onDismiss = { showCategoryDialog = false },
categories = categories,
onAddCategory = { name, type -> viewModel.addCategory(name, type) },
onDeleteCategory = { category -> viewModel.deleteCategory(category) },
onUpdateCategory = { category, newName -> viewModel.updateCategory(category, newName) },
selectedType = selectedType,
onTypeChange = { viewModel.setSelectedCategoryType(it) }
) )
} }
@ -151,6 +195,9 @@ fun MonthlyStatistics(
onExpenseClick: () -> Unit, onExpenseClick: () -> Unit,
selectedType: TransactionType?, selectedType: TransactionType?,
onClearFilter: () -> Unit, onClearFilter: () -> Unit,
selectedMonth: YearMonth,
onPreviousMonth: () -> Unit,
onNextMonth: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Card( Card(
@ -164,30 +211,42 @@ fun MonthlyStatistics(
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp) .padding(16.dp)
) { ) {
Text( // 月份选择器
text = "本月统计", Row(
style = MaterialTheme.typography.titleLarge, modifier = Modifier.fillMaxWidth(),
modifier = Modifier.padding(bottom = 8.dp) horizontalArrangement = Arrangement.SpaceBetween,
) verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = onPreviousMonth) {
Icon(Icons.AutoMirrored.Filled.KeyboardArrowLeft, "上个月")
}
Text(
text = "${selectedMonth.year}${selectedMonth.monthValue}",
style = MaterialTheme.typography.titleLarge
)
IconButton(onClick = onNextMonth) {
Icon(Icons.AutoMirrored.Filled.KeyboardArrowRight, "下个月")
}
}
Spacer(modifier = Modifier.height(16.dp))
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
) { ) {
// 收入统计 // 收入统计
Column( Column(modifier = Modifier
modifier = Modifier .weight(1f)
.weight(1f) .clickable { onIncomeClick() }
.clickable { onIncomeClick() } .background(
.background( if (selectedType == TransactionType.INCOME) MaterialTheme.colorScheme.primaryContainer
if (selectedType == TransactionType.INCOME) else Color.Transparent,
MaterialTheme.colorScheme.primaryContainer RoundedCornerShape(8.dp)
else )
Color.Transparent, .padding(8.dp)) {
RoundedCornerShape(8.dp)
)
.padding(8.dp)
) {
Text( Text(
text = "收入", text = "收入",
style = MaterialTheme.typography.titleMedium style = MaterialTheme.typography.titleMedium
@ -202,19 +261,15 @@ fun MonthlyStatistics(
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
// 支出统计 // 支出统计
Column( Column(modifier = Modifier
modifier = Modifier .weight(1f)
.weight(1f) .clickable { onExpenseClick() }
.clickable { onExpenseClick() } .background(
.background( if (selectedType == TransactionType.EXPENSE) MaterialTheme.colorScheme.primaryContainer
if (selectedType == TransactionType.EXPENSE) else Color.Transparent,
MaterialTheme.colorScheme.primaryContainer RoundedCornerShape(8.dp)
else )
Color.Transparent, .padding(8.dp)) {
RoundedCornerShape(8.dp)
)
.padding(8.dp)
) {
Text( Text(
text = "支出", text = "支出",
style = MaterialTheme.typography.titleMedium style = MaterialTheme.typography.titleMedium
@ -261,8 +316,7 @@ fun RecordItem(
) { ) {
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
Text( Text(
text = record.category, text = record.category, style = MaterialTheme.typography.titleMedium
style = MaterialTheme.typography.titleMedium
) )
if (record.description.isNotEmpty()) { if (record.description.isNotEmpty()) {
Text( Text(
@ -272,8 +326,9 @@ fun RecordItem(
) )
} }
Text( Text(
text = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) text = SimpleDateFormat(
.format(record.date), "yyyy-MM-dd HH:mm", Locale.getDefault()
).format(record.date),
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
@ -284,18 +339,14 @@ fun RecordItem(
) { ) {
Text( Text(
text = if (record.type == TransactionType.EXPENSE) "-" else "+", text = if (record.type == TransactionType.EXPENSE) "-" else "+",
color = if (record.type == TransactionType.EXPENSE) color = if (record.type == TransactionType.EXPENSE) MaterialTheme.colorScheme.error
MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary,
else
MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.titleMedium style = MaterialTheme.typography.titleMedium
) )
Text( Text(
text = String.format("%.2f", record.amount), text = String.format("%.2f", record.amount),
color = if (record.type == TransactionType.EXPENSE) color = if (record.type == TransactionType.EXPENSE) MaterialTheme.colorScheme.error
MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary,
else
MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
modifier = Modifier.padding(end = 8.dp) modifier = Modifier.padding(end = 8.dp)
) )

View File

@ -7,19 +7,38 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.yovinchen.bookkeeping.model.Category
import com.yovinchen.bookkeeping.model.ThemeMode import com.yovinchen.bookkeeping.model.ThemeMode
import com.yovinchen.bookkeeping.model.TransactionType
import com.yovinchen.bookkeeping.ui.components.ColorPicker import com.yovinchen.bookkeeping.ui.components.ColorPicker
import com.yovinchen.bookkeeping.ui.components.predefinedColors import com.yovinchen.bookkeeping.ui.components.predefinedColors
import com.yovinchen.bookkeeping.ui.dialog.CategoryManagementDialog
import com.yovinchen.bookkeeping.viewmodel.SettingsViewModel
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SettingsScreen( fun SettingsScreen(
currentTheme: ThemeMode, currentTheme: ThemeMode,
onThemeChange: (ThemeMode) -> Unit onThemeChange: (ThemeMode) -> Unit,
viewModel: SettingsViewModel = viewModel()
) { ) {
var showThemeDialog by remember { mutableStateOf(false) } var showThemeDialog by remember { mutableStateOf(false) }
var showCategoryDialog by remember { mutableStateOf(false) }
val categories by viewModel.categories.collectAsState()
val selectedType by viewModel.selectedCategoryType.collectAsState()
Column(modifier = Modifier.fillMaxSize()) { Column(modifier = Modifier.fillMaxSize()) {
// 类别管理设置项
ListItem(
headlineContent = { Text("类别管理") },
supportingContent = { Text("管理收入和支出类别") },
modifier = Modifier.clickable { showCategoryDialog = true }
)
Divider()
// 主题设置项 // 主题设置项
ListItem( ListItem(
headlineContent = { Text("主题设置") }, headlineContent = { Text("主题设置") },
@ -99,6 +118,19 @@ fun SettingsScreen(
) )
} }
} }
// 类别管理对话框
if (showCategoryDialog) {
CategoryManagementDialog(
onDismiss = { showCategoryDialog = false },
categories = categories,
onAddCategory = viewModel::addCategory,
onDeleteCategory = viewModel::deleteCategory,
onUpdateCategory = viewModel::updateCategory,
selectedType = selectedType,
onTypeChange = viewModel::setSelectedCategoryType
)
}
} }
@Composable @Composable

View File

@ -8,33 +8,19 @@ import com.yovinchen.bookkeeping.data.BookkeepingDatabase
import com.yovinchen.bookkeeping.model.BookkeepingRecord import com.yovinchen.bookkeeping.model.BookkeepingRecord
import com.yovinchen.bookkeeping.model.Category import com.yovinchen.bookkeeping.model.Category
import com.yovinchen.bookkeeping.model.TransactionType import com.yovinchen.bookkeeping.model.TransactionType
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.YearMonth
import java.util.Date import java.util.Date
import java.util.Calendar import java.util.Calendar
@OptIn(ExperimentalCoroutinesApi::class)
class HomeViewModel(application: Application) : AndroidViewModel(application) { class HomeViewModel(application: Application) : AndroidViewModel(application) {
private val TAG = "HomeViewModel" private val TAG = "HomeViewModel"
private val database = BookkeepingDatabase.getDatabase(application) private val dao = BookkeepingDatabase.getDatabase(application).bookkeepingDao()
private val dao = database.bookkeepingDao()
val records = dao.getAllRecords()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = emptyList()
)
private val _totalIncome = MutableStateFlow(0.0)
val totalIncome: StateFlow<Double> = _totalIncome.asStateFlow()
private val _totalExpense = MutableStateFlow(0.0)
val totalExpense: StateFlow<Double> = _totalExpense.asStateFlow()
private val _selectedCategoryType = MutableStateFlow(TransactionType.EXPENSE)
val selectedCategoryType: StateFlow<TransactionType> = _selectedCategoryType.asStateFlow()
private val _selectedRecordType = MutableStateFlow<TransactionType?>(null) private val _selectedRecordType = MutableStateFlow<TransactionType?>(null)
val selectedRecordType: StateFlow<TransactionType?> = _selectedRecordType.asStateFlow() val selectedRecordType: StateFlow<TransactionType?> = _selectedRecordType.asStateFlow()
@ -42,6 +28,19 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
private val _selectedDateTime = MutableStateFlow(LocalDateTime.now()) private val _selectedDateTime = MutableStateFlow(LocalDateTime.now())
val selectedDateTime: StateFlow<LocalDateTime> = _selectedDateTime.asStateFlow() val selectedDateTime: StateFlow<LocalDateTime> = _selectedDateTime.asStateFlow()
private val _selectedCategoryType = MutableStateFlow(TransactionType.EXPENSE)
val selectedCategoryType: StateFlow<TransactionType> = _selectedCategoryType.asStateFlow()
private val _selectedMonth = MutableStateFlow(YearMonth.now())
val selectedMonth: StateFlow<YearMonth> = _selectedMonth.asStateFlow()
private val records = dao.getAllRecords()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = emptyList()
)
val categories: StateFlow<List<Category>> = _selectedCategoryType val categories: StateFlow<List<Category>> = _selectedCategoryType
.flatMapLatest { type -> .flatMapLatest { type ->
dao.getCategoriesByType(type) dao.getCategoriesByType(type)
@ -52,38 +51,91 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
initialValue = emptyList() initialValue = emptyList()
) )
val filteredRecords = combine(records, selectedRecordType) { records, type -> val filteredRecords = combine(
when (type) { records,
null -> records.sortedByDescending { it.date } _selectedRecordType,
else -> records.filter { it.type == type }.sortedByDescending { it.date } _selectedMonth
} ) { records, selectedType, selectedMonth ->
records
.filter { record ->
val recordDate = record.date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate()
val recordYearMonth = YearMonth.from(recordDate)
val typeMatches = selectedType?.let { record.type == it } ?: true
val monthMatches = recordYearMonth == selectedMonth
typeMatches && monthMatches
}
.sortedByDescending { it.date }
.groupBy { record ->
val calendar = Calendar.getInstance().apply { time = record.date }
calendar.apply {
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.time
}
}.stateIn( }.stateIn(
scope = viewModelScope, viewModelScope,
started = SharingStarted.WhileSubscribed(5000), SharingStarted.WhileSubscribed(5000),
initialValue = emptyList() emptyMap()
) )
private val _uiState = MutableStateFlow(UiState()) val totalIncome = combine(
val uiState: StateFlow<UiState> = _uiState.asStateFlow() records,
_selectedMonth
) { records, selectedMonth ->
records
.filter { record ->
val recordDate = record.date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate()
val recordYearMonth = YearMonth.from(recordDate)
record.type == TransactionType.INCOME && recordYearMonth == selectedMonth
}
.sumOf { it.amount }
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
0.0
)
val totalExpense = combine(
records,
_selectedMonth
) { records, selectedMonth ->
records
.filter { record ->
val recordDate = record.date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate()
val recordYearMonth = YearMonth.from(recordDate)
record.type == TransactionType.EXPENSE && recordYearMonth == selectedMonth
}
.sumOf { it.amount }
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
0.0
)
private fun updateTotals() {
// 移除未使用的参数
}
init { init {
viewModelScope.launch { viewModelScope.launch {
records.collect { recordsList -> records.collect {
updateTotals(recordsList) updateTotals()
} }
} }
} }
private fun updateTotals(records: List<BookkeepingRecord>) {
_totalIncome.value = records
.filter { it.type == TransactionType.INCOME }
.sumOf { it.amount }
_totalExpense.value = records
.filter { it.type == TransactionType.EXPENSE }
.sumOf { it.amount }
}
fun addRecord(type: TransactionType, amount: Double, category: String, description: String) { fun addRecord(type: TransactionType, amount: Double, category: String, description: String) {
viewModelScope.launch { viewModelScope.launch {
val record = BookkeepingRecord( val record = BookkeepingRecord(
@ -102,37 +154,31 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
_selectedDateTime.value = dateTime _selectedDateTime.value = dateTime
} }
fun setSelectedCategoryType(type: TransactionType) {
_selectedCategoryType.value = type
}
fun setSelectedRecordType(type: TransactionType?) { fun setSelectedRecordType(type: TransactionType?) {
_selectedRecordType.value = type _selectedRecordType.value = type
} }
fun setSelectedCategoryType(type: TransactionType) {
_selectedCategoryType.value = type
}
fun setSelectedMonth(yearMonth: YearMonth) {
_selectedMonth.value = yearMonth
}
fun moveMonth(forward: Boolean) {
val current = _selectedMonth.value
_selectedMonth.value = if (forward) {
current.plusMonths(1)
} else {
current.minusMonths(1)
}
}
fun resetSelectedDateTime() { fun resetSelectedDateTime() {
_selectedDateTime.value = LocalDateTime.now() _selectedDateTime.value = LocalDateTime.now()
} }
fun addCategory(name: String, type: TransactionType) {
viewModelScope.launch {
val category = Category(name = name, type = type)
dao.insertCategory(category)
}
}
fun updateCategory(category: Category, newName: String) {
viewModelScope.launch {
dao.updateCategory(category.copy(name = newName))
}
}
fun deleteCategory(category: Category) {
viewModelScope.launch {
dao.deleteCategory(category)
}
}
fun updateRecord(record: BookkeepingRecord) { fun updateRecord(record: BookkeepingRecord) {
viewModelScope.launch { viewModelScope.launch {
dao.updateRecord(record) dao.updateRecord(record)
@ -167,11 +213,6 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
return dao.getRecordsByDateRange(start, end) return dao.getRecordsByDateRange(start, end)
} }
// 获取指定类别的记录
fun getRecordsByCategory(category: String): Flow<List<BookkeepingRecord>> {
return dao.getRecordsByCategory(category)
}
// 获取指定类型的记录 // 获取指定类型的记录
fun getRecordsByType(type: TransactionType): Flow<List<BookkeepingRecord>> { fun getRecordsByType(type: TransactionType): Flow<List<BookkeepingRecord>> {
return dao.getRecordsByType(type) return dao.getRecordsByType(type)