Files
L'électron rare 352eab18cc feat(launcher): refine bodyMesh + dataOnly modes
- bodyMesh keeps SC + data_feeds (audio + sonification) in addition
  to Multi-HMR worker headless + AV-Live-Body. Only oscope-of and
  the web UI are stopped.
- dataOnly now keeps the web UI (the user wants Hydra/control panel
  available even in the Metal-viz-only mode). Only oscope-of is
  stopped on transition.
- MenuBar shows Web UI row in both .full and .dataOnly, and a
  Data Feeds row in all three modes (with a distinct subtitle in
  bodyMesh that flags it as sonification-only).
- ModePicker subtitles updated to reflect the new contract.
2026-05-13 12:56:01 +02:00

104 lines
3.4 KiB
Swift

import AppKit
import SwiftUI
/// Fenetre modale affichee au demarrage pour choisir le mode (Full /
/// Data-only). L'utilisateur peut cocher "ne plus afficher" : la
/// preference est persistee dans UserDefaults (cle `skipModePicker`).
struct ModePickerView: View {
@ObservedObject var processManager: ProcessManager
let onChoice: (LaunchMode) -> Void
@State private var skipNextTime: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("AV-Live")
.font(.system(size: 22, weight: .semibold))
Text("Quel mode lancer ?")
.font(.subheadline)
.foregroundColor(.secondary)
HStack(spacing: 12) {
ModeCard(
title: "Full AV-Live",
subtitle: "SC + oscope-of + web UI + data_feeds",
icon: "waveform.path.ecg.rectangle",
color: .accentColor
) {
finish(.full)
}
ModeCard(
title: "Data-only",
subtitle: "SC + Metal viz + data_feeds + web UI\nPas d'oscope-of",
icon: "antenna.radiowaves.left.and.right",
color: .green
) {
finish(.dataOnly)
}
ModeCard(
title: "Body Mesh",
subtitle: "Multi-HMR + AV-Live-Body + SC + feeds\nPas de Metal viz, pas de web",
icon: "figure.walk",
color: .pink
) {
finish(.bodyMesh)
}
}
Divider()
Toggle("Ne plus afficher (utilisera le dernier mode choisi)",
isOn: $skipNextTime)
.font(.caption)
}
.padding(24)
.frame(width: 520)
.onAppear {
// Pre-coche selon la valeur persistee
skipNextTime = UserDefaults.standard.bool(forKey: "skipModePicker")
}
}
private func finish(_ choice: LaunchMode) {
processManager.mode = choice
UserDefaults.standard.set(skipNextTime, forKey: "skipModePicker")
onChoice(choice)
}
}
private struct ModeCard: View {
let title: String
let subtitle: String
let icon: String
let color: Color
let action: () -> Void
var body: some View {
Button(action: action) {
VStack(alignment: .leading, spacing: 8) {
Image(systemName: icon)
.font(.system(size: 28))
.foregroundColor(color)
Text(title)
.font(.headline)
Text(subtitle)
.font(.caption)
.foregroundColor(.secondary)
.lineLimit(3)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
}
.frame(maxWidth: .infinity, minHeight: 110, alignment: .topLeading)
.padding(16)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(color.opacity(0.08))
)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(color.opacity(0.4), lineWidth: 1)
)
}
.buttonStyle(.plain)
}
}