feat: 新建记录标题预填拍摄日期并支持联动
This commit is contained in:
parent
94e81bffb1
commit
0d83fef3a9
@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.number
|
||||
import kotlinx.datetime.todayIn
|
||||
import java.io.File
|
||||
import kotlin.time.Clock
|
||||
@ -58,6 +59,9 @@ class RecordEditViewModel(
|
||||
private val _uiState = MutableStateFlow(RecordEditUiState())
|
||||
val uiState: StateFlow<RecordEditUiState> = _uiState.asStateFlow()
|
||||
|
||||
/** 用户是否手动编辑过标题;为 false 时标题随拍摄日期联动 */
|
||||
private var titleManuallyEdited = false
|
||||
|
||||
init {
|
||||
if (recordId != null) {
|
||||
loadExistingRecord(recordId)
|
||||
@ -69,11 +73,14 @@ class RecordEditViewModel(
|
||||
private fun initNewRecord() {
|
||||
requireNotNull(photoPath) { "新建模式必须提供 photoPath" }
|
||||
val file = File(photoPath)
|
||||
val today = Clock.System.todayIn(TimeZone.currentSystemDefault())
|
||||
_uiState.value = RecordEditUiState(
|
||||
loading = false,
|
||||
title = formatLocalDate(today),
|
||||
shootDate = today,
|
||||
photoUri = "file://${file.absolutePath}",
|
||||
photoAbsolutePath = file.absolutePath,
|
||||
canSave = false,
|
||||
canSave = true,
|
||||
isExistingRecord = false
|
||||
)
|
||||
}
|
||||
@ -83,6 +90,7 @@ class RecordEditViewModel(
|
||||
val record = repository.observeById(id).first()
|
||||
if (record != null) {
|
||||
val absFile = repository.absoluteFileOf(record.photoPath)
|
||||
titleManuallyEdited = true
|
||||
_uiState.value = RecordEditUiState(
|
||||
loading = false,
|
||||
title = record.title,
|
||||
@ -102,6 +110,7 @@ class RecordEditViewModel(
|
||||
}
|
||||
|
||||
fun onTitleChange(value: String) {
|
||||
titleManuallyEdited = true
|
||||
_uiState.update { it.copy(title = value, canSave = value.isNotBlank() && it.photoAbsolutePath != null) }
|
||||
}
|
||||
|
||||
@ -110,7 +119,13 @@ class RecordEditViewModel(
|
||||
}
|
||||
|
||||
fun onShootDateChange(date: LocalDate) {
|
||||
_uiState.update { it.copy(shootDate = date) }
|
||||
_uiState.update {
|
||||
if (titleManuallyEdited) {
|
||||
it.copy(shootDate = date)
|
||||
} else {
|
||||
it.copy(shootDate = date, title = formatLocalDate(date))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onLinkedDateChange(date: LocalDate) {
|
||||
@ -155,3 +170,12 @@ class RecordEditViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将日期格式化为 `yyyy-MM-dd`,用于新建记录的默认标题和编辑页的日期显示。
|
||||
*
|
||||
* @param date 待格式化的日期
|
||||
*/
|
||||
internal fun formatLocalDate(date: LocalDate): String {
|
||||
return "${date.year}-${date.month.number.toString().padStart(2, '0')}-${date.day.toString().padStart(2, '0')}"
|
||||
}
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
package plus.rua.project
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.datetime.LocalDate
|
||||
import java.io.File
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* 新建记录标题预填与拍摄日期联动的单元测试。
|
||||
*
|
||||
* 新建模式的被测路径不会触发 DAO 调用,[FakeDateRecordDao] 返回空数据即可。
|
||||
*/
|
||||
class RecordEditViewModelTest {
|
||||
|
||||
private fun newViewModel(): RecordEditViewModel {
|
||||
val repository = DateRecorderRepository(FakeDateRecordDao(), File("build/tmp/record_edit_test"))
|
||||
return RecordEditViewModel(repository, photoPath = "/tmp/fake_photo.jpg", recordId = null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun newRecord_prefillsTitleWithShootDate_andCanSave() {
|
||||
val vm = newViewModel()
|
||||
val state = vm.uiState.value
|
||||
assertEquals(formatLocalDate(state.shootDate), state.title)
|
||||
assertTrue(state.canSave)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shootDateChange_updatesTitle_whenTitleNotManuallyEdited() {
|
||||
val vm = newViewModel()
|
||||
vm.onShootDateChange(LocalDate(2026, 3, 5))
|
||||
assertEquals("2026-03-05", vm.uiState.value.title)
|
||||
assertTrue(vm.uiState.value.canSave)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shootDateChange_keepsTitle_whenTitleManuallyEdited() {
|
||||
val vm = newViewModel()
|
||||
vm.onTitleChange("我的记录")
|
||||
vm.onShootDateChange(LocalDate(2026, 3, 5))
|
||||
assertEquals("我的记录", vm.uiState.value.title)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun titleCleared_disablesSave() {
|
||||
val vm = newViewModel()
|
||||
vm.onTitleChange("")
|
||||
assertFalse(vm.uiState.value.canSave)
|
||||
}
|
||||
}
|
||||
|
||||
private class FakeDateRecordDao : DateRecordDao {
|
||||
override fun getByIdFlow(id: Long): Flow<DateRecord?> = flowOf(null)
|
||||
override fun getAllFlow(): Flow<List<DateRecord>> = flowOf(emptyList())
|
||||
override suspend fun insert(record: DateRecord): Long = 0
|
||||
override suspend fun update(record: DateRecord) = Unit
|
||||
override suspend fun deleteByIds(ids: List<Long>): Int = 0
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user