Auto commit Thu Mar 19 08:01:01 PM CDT 2026

This commit is contained in:
Tretzi
2026-03-19 20:01:01 -05:00
parent c7518b7e9c
commit 3846f97fb2
17 changed files with 497 additions and 156 deletions

View File

@@ -8,9 +8,8 @@ import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.background
import com.mindmachine.mvp.session.TimelineEditorScreen
import com.mindmachine.mvp.session.TimelineModel
import com.mindmachine.mvp.session.TimelineParameterControl
import com.mindmachine.mvp.session.DurationSliderCard
import com.mindmachine.mvp.session.SetupTimelineEditor
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -194,13 +193,6 @@ fun App(vm: MainViewModel = viewModel()) {
nav.navigate("active")
},
onHolder = { nav.navigate("holder") },
onOpenTimelineEditor = { nav.navigate("timeline") },
)
}
composable("timeline") {
TimelineEditorScreen(
vm = vm,
onBack = { nav.popBackStack() }
)
}
composable("active") {
@@ -267,13 +259,9 @@ fun SetupScreen(
vm: MainViewModel,
onStart: () -> Unit,
onHolder: () -> Unit,
onOpenTimelineEditor: () -> Unit,
) {
val ui by vm.ui.collectAsStateWithLifecycle()
val cfg = ui.config
var model by remember(ui.selectedPreset.id, cfg.durationSec) {
mutableStateOf(TimelineModel.createForPreset(ui.selectedPreset, cfg.durationSec))
}
val scrollState = rememberScrollState()
val containerModifier = Modifier
.fillMaxSize()
@@ -282,32 +270,27 @@ fun SetupScreen(
.safeDrawingPadding()
.padding(horizontal = 16.dp, vertical = 12.dp)
TimelineParameterControl(
model = model,
onParameterChanged = { id: String, newValue: Float ->
model = model.updateParameterValue(id, newValue)
when (id) {
"flash_interval" -> vm.setFlashIntervalMs((newValue * 1000f).roundToInt())
"carrier_frequency" -> vm.setCarrier(newValue)
"binaural_difference" -> vm.setDifference(newValue)
}
},
modifier = containerModifier,
showTimeline = true,
onTimelineChanged = { newDuration ->
vm.setDurationMin((newDuration / 60f).roundToInt())
}
)
// Additional controls
Column(
Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(10.dp)
modifier = containerModifier,
verticalArrangement = Arrangement.spacedBy(14.dp),
) {
OutlinedButton(onClick = onOpenTimelineEditor, modifier = Modifier.fillMaxWidth()) {
Text("Open Timeline Editor")
}
Text(
ui.selectedPreset.name,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onBackground,
)
DurationSliderCard(
durationSec = ui.timeline.durationSec,
onDurationSecChanged = { vm.setDurationSec(it) },
)
// Integrated timeline editor (no separate screen).
SetupTimelineEditor(
state = ui.timeline,
onStateChanged = vm::updateTimeline,
)
TextButton(onClick = onHolder) { Text("Holder Guidance") }
if (ui.error != null) Text(ui.error!!, color = MaterialTheme.colorScheme.error)
Button(onClick = onStart, modifier = Modifier.fillMaxWidth().height(52.dp)) { Text("Start") }
@@ -359,7 +342,8 @@ fun ActiveSessionScreen(vm: MainViewModel, onFinish: () -> Unit, onBackToSetup:
val flashFrame by rememberSplitFlashFrame(
isRunning = ui.runtimeState == RuntimeState.RUNNING,
mode = ui.config.mode,
flashIntervalMs = ui.config.flashIntervalMs,
flashOnMs = ui.runtimeParams.flashOnMs,
flashOffMs = ui.runtimeParams.flashOffMs,
)
Box(
@@ -471,15 +455,16 @@ private fun FlashColor.toComposeColor(): Color = when (this) {
private fun rememberSplitFlashFrame(
isRunning: Boolean,
mode: SessionMode,
flashIntervalMs: Int,
) = produceState(initialValue = SplitFlashFrame(FlashColor.BLACK, FlashColor.BLACK), isRunning, mode, flashIntervalMs) {
flashOnMs: Int,
flashOffMs: Int,
) = produceState(initialValue = SplitFlashFrame(FlashColor.BLACK, FlashColor.BLACK), isRunning, mode, flashOnMs, flashOffMs) {
if (!isRunning || mode == SessionMode.AUDIO_ONLY) {
value = SplitFlashFrame(FlashColor.BLACK, FlashColor.BLACK)
return@produceState
}
while (true) {
withFrameNanos { frameTimeNanos ->
value = computeSplitFlashFrame(frameTimeNanos, flashIntervalMs)
value = computeSplitFlashFrame(frameTimeNanos, flashOnMs, flashOffMs)
}
}
}