1package com.peachpasswords.ui.vault23import androidx.lifecycle.SavedStateHandle4import androidx.lifecycle.ViewModel5import androidx.lifecycle.viewModelScope6import com.peachpasswords.vault.VaultEntry7import com.peachpasswords.vault.VaultRepository8import dagger.hilt.android.lifecycle.HiltViewModel9import kotlinx.coroutines.Job10import kotlinx.coroutines.delay11import kotlinx.coroutines.flow.MutableStateFlow12import kotlinx.coroutines.flow.SharingStarted13import kotlinx.coroutines.flow.StateFlow14import kotlinx.coroutines.flow.asStateFlow15import kotlinx.coroutines.flow.map16import kotlinx.coroutines.flow.stateIn17import kotlinx.coroutines.launch18import javax.inject.Inject1920212223242526272829@HiltViewModel30class NotesModeViewModel @Inject constructor(31 private val vault: VaultRepository,32 savedStateHandle: SavedStateHandle,33) : ViewModel() {34 private val id: String = savedStateHandle.get<String>("id").orEmpty()3536 val entry: StateFlow<VaultEntry?> =37 vault.entries.map { list -> list.firstOrNull { it.id == id } }38 .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), vault.getEntry(id))3940 private val _savedPulse = MutableStateFlow(0L)41 42 val savedPulse: StateFlow<Long> = _savedPulse.asStateFlow()4344 private var saveJob: Job? = null4546 47 fun onContentChanged(plainText: String) =48 scheduleSave { it.copy(notes = plainText.ifBlank { null }) }4950 51525354 fun onTitleChanged(title: String) =55 scheduleSave { it.copy(title = title) }5657 58 fun saveTitleNow(title: String) {59 saveJob?.cancel()60 commit { it.copy(title = title) }61 }6263 private fun scheduleSave(patch: (VaultEntry) -> VaultEntry) {64 saveJob?.cancel()65 saveJob = viewModelScope.launch {66 delay(800)67 commit(patch)68 }69 }7071 private fun commit(patch: (VaultEntry) -> VaultEntry) {72 val current = entry.value ?: return73 viewModelScope.launch {74 runCatching { vault.updateEntry(patch(current)) }75 .onSuccess { _savedPulse.value = System.currentTimeMillis() }76 }77 }78}