This commit was merged in pull request #67.
This commit is contained in:
@@ -1,23 +1,37 @@
|
||||
package org.shahondin1624.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.russhwolf.settings.Settings
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.launch
|
||||
import org.shahondin1624.lib.functions.DataLoader
|
||||
import org.shahondin1624.model.EXAMPLE_CHARACTER
|
||||
import org.shahondin1624.model.charactermodel.ShadowrunCharacter
|
||||
|
||||
/**
|
||||
* ViewModel holding the current character as observable state.
|
||||
* Foundation for all editing stories (6.2-6.6) and interactive features.
|
||||
* Auto-saves to local storage on changes (debounced 500ms) and
|
||||
* auto-loads from storage on launch, falling back to EXAMPLE_CHARACTER.
|
||||
*/
|
||||
class CharacterViewModel : ViewModel() {
|
||||
|
||||
private val _character = MutableStateFlow(EXAMPLE_CHARACTER)
|
||||
private val settings = Settings()
|
||||
|
||||
private val _character = MutableStateFlow(loadCharacter())
|
||||
|
||||
/** Observable character state. */
|
||||
val character: StateFlow<ShadowrunCharacter> = _character.asStateFlow()
|
||||
|
||||
init {
|
||||
startAutoSave()
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the current character entirely.
|
||||
*/
|
||||
@@ -31,4 +45,60 @@ class CharacterViewModel : ViewModel() {
|
||||
fun updateCharacter(transform: (ShadowrunCharacter) -> ShadowrunCharacter) {
|
||||
_character.value = transform(_character.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current character immediately.
|
||||
*/
|
||||
fun saveNow() {
|
||||
saveCharacter(_character.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Load character from local storage, falling back to EXAMPLE_CHARACTER.
|
||||
*/
|
||||
private fun loadCharacter(): ShadowrunCharacter {
|
||||
return try {
|
||||
val json = settings.getStringOrNull(STORAGE_KEY)
|
||||
if (json != null) {
|
||||
DataLoader.deserialize(json)
|
||||
} else {
|
||||
EXAMPLE_CHARACTER
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// If deserialization fails (e.g., schema change), fall back to example
|
||||
EXAMPLE_CHARACTER
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save character to local storage as JSON.
|
||||
*/
|
||||
private fun saveCharacter(character: ShadowrunCharacter) {
|
||||
try {
|
||||
val json = DataLoader.serialize(character)
|
||||
settings.putString(STORAGE_KEY, json)
|
||||
} catch (e: Exception) {
|
||||
// Silently ignore save failures
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start auto-saving on character changes with 500ms debounce.
|
||||
* Drops the initial emission (load) to avoid unnecessary save.
|
||||
*/
|
||||
@OptIn(FlowPreview::class)
|
||||
private fun startAutoSave() {
|
||||
viewModelScope.launch {
|
||||
_character
|
||||
.drop(1) // Skip initial value (already saved or loaded)
|
||||
.debounce(500)
|
||||
.collect { character ->
|
||||
saveCharacter(character)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STORAGE_KEY = "shadowrun_character"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user