Auto commit Sat Mar 21 11:01:02 PM CDT 2026
This commit is contained in:
@@ -9,7 +9,6 @@ import com.mindmachine.mvp.data.SettingsRepository
|
||||
import com.mindmachine.mvp.data.UserProgramEntity
|
||||
import com.mindmachine.mvp.data.UserProgramRepository
|
||||
import com.mindmachine.mvp.domain.AppSettings
|
||||
import com.mindmachine.mvp.domain.CountdownPreference
|
||||
import com.mindmachine.mvp.domain.Presets
|
||||
import com.mindmachine.mvp.domain.RuntimeState
|
||||
import com.mindmachine.mvp.domain.SessionConfig
|
||||
@@ -59,15 +58,27 @@ class MainViewModel(
|
||||
|
||||
private var runJob: Job? = null
|
||||
private var elapsedBeforePauseSec: Float = 0f
|
||||
private var cachedUserPrograms: List<UserProgramEntity> = emptyList()
|
||||
private var cachedPrograms: List<UserProgramEntity> = emptyList()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
combine(settingsRepository.settings, userProgramRepository.userPrograms) { settings, userPrograms ->
|
||||
settings to userPrograms
|
||||
}.collect { (settings, userPrograms) ->
|
||||
cachedUserPrograms = userPrograms
|
||||
val userPresets = userPrograms.map {
|
||||
val builtInPrograms = Presets.builtIn.map { preset ->
|
||||
userPrograms.firstOrNull { it.id == preset.id } ?: UserProgramEntity(
|
||||
id = preset.id,
|
||||
name = preset.name,
|
||||
description = preset.description,
|
||||
timeline = TimelineProgramFactory.fromPreset(preset),
|
||||
sortOrder = preset.sortOrder,
|
||||
)
|
||||
}
|
||||
val mergedPrograms = (builtInPrograms + userPrograms.filterNot { program -> Presets.builtIn.any { it.id == program.id } })
|
||||
.sortedBy { it.sortOrder }
|
||||
cachedPrograms = mergedPrograms
|
||||
|
||||
val allPresets = mergedPrograms.map {
|
||||
TimelineProgramFactory.toPreset(
|
||||
id = it.id,
|
||||
name = it.name,
|
||||
@@ -77,7 +88,6 @@ class MainViewModel(
|
||||
isUserProgram = true,
|
||||
)
|
||||
}
|
||||
val allPresets = (Presets.builtIn + userPresets).sortedBy { it.sortOrder }
|
||||
|
||||
_ui.update { current ->
|
||||
val selectedId = settings.lastPresetId ?: current.selectedPreset.id
|
||||
@@ -88,7 +98,7 @@ class MainViewModel(
|
||||
presets = allPresets,
|
||||
selectedPreset = selectedPreset,
|
||||
config = current.config.copy(mode = settings.defaultModePreference),
|
||||
timeline = if (sameSelection) current.timeline else timelineForPreset(selectedPreset, userPrograms),
|
||||
timeline = if (sameSelection) current.timeline else timelineForProgramId(selectedPreset.id, mergedPrograms),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -106,7 +116,7 @@ class MainViewModel(
|
||||
it.copy(
|
||||
selectedPreset = preset,
|
||||
config = cfg.copy(durationSec = cfg.durationSec.coerceIn(60, 8 * 60 * 60)),
|
||||
timeline = timelineForPreset(preset, cachedUserPrograms),
|
||||
timeline = timelineForProgramId(preset.id, cachedPrograms),
|
||||
error = null,
|
||||
)
|
||||
}
|
||||
@@ -143,8 +153,8 @@ class MainViewModel(
|
||||
}
|
||||
|
||||
val state = _ui.value
|
||||
val id = if (state.selectedPreset.isUserProgram) state.selectedPreset.id else "user-${UUID.randomUUID()}"
|
||||
val sortOrder = cachedUserPrograms.find { it.id == id }?.sortOrder ?: nextSortOrder()
|
||||
val id = state.selectedPreset.id
|
||||
val sortOrder = cachedPrograms.find { it.id == id }?.sortOrder ?: nextSortOrder()
|
||||
|
||||
userProgramRepository.upsert(
|
||||
UserProgramEntity(
|
||||
@@ -176,13 +186,13 @@ class MainViewModel(
|
||||
fun deleteProgram(id: String) = viewModelScope.launch {
|
||||
userProgramRepository.delete(id)
|
||||
if (_ui.value.selectedPreset.id == id) {
|
||||
val fallback = Presets.builtIn.first()
|
||||
val fallback = _ui.value.presets.firstOrNull { it.id != id } ?: Presets.builtIn.first()
|
||||
settingsRepository.updateLastPreset(fallback.id)
|
||||
_ui.update {
|
||||
it.copy(
|
||||
selectedPreset = fallback,
|
||||
config = fallback.toConfig(it.settings.defaultModePreference),
|
||||
timeline = TimelineProgramFactory.fromPreset(fallback),
|
||||
timeline = timelineForProgramId(fallback.id, cachedPrograms),
|
||||
error = null,
|
||||
)
|
||||
}
|
||||
@@ -212,9 +222,10 @@ class MainViewModel(
|
||||
fun setCarrier(value: Float) = _ui.update { it.copy(config = it.config.copy(carrierFrequencyHz = value.coerceIn(80f, 400f)), error = null) }
|
||||
fun setDifference(value: Float) = _ui.update { it.copy(config = it.config.copy(binauralDifferenceHz = value.coerceIn(0.5f, 20f)), error = null) }
|
||||
|
||||
fun updateCountdown(pref: CountdownPreference) = viewModelScope.launch { settingsRepository.updateCountdown(pref) }
|
||||
fun updateCountdownSeconds(seconds: Int) = viewModelScope.launch { settingsRepository.updateCountdownSeconds(seconds) }
|
||||
fun updateDefaultMode(mode: SessionMode) = viewModelScope.launch { settingsRepository.updateDefaultMode(mode) }
|
||||
fun updateGuidance(value: Boolean) = viewModelScope.launch { settingsRepository.updateGuidance(value) }
|
||||
fun updateShowImmersiveProgressBar(value: Boolean) = viewModelScope.launch { settingsRepository.updateShowImmersiveProgressBar(value) }
|
||||
|
||||
fun startSession() {
|
||||
val state = _ui.value
|
||||
@@ -281,7 +292,7 @@ class MainViewModel(
|
||||
val clampedStartSec = startElapsedSec.coerceIn(0f, durationSec.toFloat())
|
||||
|
||||
if (includeCountdown) {
|
||||
val count = _ui.value.settings.countdownPreference.seconds
|
||||
val count = _ui.value.settings.countdownSeconds.coerceIn(0, 10)
|
||||
if (count > 0) {
|
||||
for (i in count downTo 1) {
|
||||
_ui.update {
|
||||
@@ -358,14 +369,18 @@ class MainViewModel(
|
||||
return (total - state.remainingSec).coerceIn(0f, total)
|
||||
}
|
||||
|
||||
private fun timelineForPreset(preset: SessionPreset, userPrograms: List<UserProgramEntity>): TimelineEditorState {
|
||||
return userPrograms.firstOrNull { it.id == preset.id }?.timeline ?: TimelineProgramFactory.fromPreset(preset)
|
||||
private fun timelineForProgramId(programId: String, programs: List<UserProgramEntity>): TimelineEditorState {
|
||||
val fromSaved = programs.firstOrNull { it.id == programId }?.timeline
|
||||
if (fromSaved != null) return fromSaved
|
||||
|
||||
val builtInPreset = Presets.builtIn.firstOrNull { it.id == programId }
|
||||
return if (builtInPreset != null) TimelineProgramFactory.fromPreset(builtInPreset) else TimelineEditorState.default()
|
||||
}
|
||||
|
||||
private fun nextSortOrder(): Int = (cachedUserPrograms.maxOfOrNull { it.sortOrder } ?: 999) + 1
|
||||
private fun nextSortOrder(): Int = (cachedPrograms.maxOfOrNull { it.sortOrder } ?: 999) + 1
|
||||
|
||||
private fun nextUntitledName(): String {
|
||||
val names = cachedUserPrograms.map { it.name.lowercase() }.toSet()
|
||||
val names = cachedPrograms.map { it.name.lowercase() }.toSet()
|
||||
var i = 1
|
||||
while (true) {
|
||||
val candidate = "Custom $i"
|
||||
|
||||
Reference in New Issue
Block a user