moodlit-native/Sources/Features/Sequences/CreateSequenceSheet.swift
till bbfdff7e3c μ-7.0: Initial moodlit-native Skelett (Pure-Native iOS+macOS)
Pure-Native SwiftUI-App für Moodlit. Pendant zur SvelteKit-Web-App
auf moodlit.mana.how; konsumiert ManaCore + ManaTokens + ManaAuthUI
aus den Schwester-Repos.

Stack:
- SwiftUI Universal (iOS 18 / macOS 15), Swift 6 strict concurrency
- mana-swift-core + mana-swift-ui (lokale SPM-Pakete via XcodeGen)
- Bundle ev.mana.moodlit, Team QP3GLU8PH3, App-Group group.ev.mana.moodlit

Features:
- 24 Mood-Presets als Swift-Konstanten (Port von default-moods.ts)
- Custom-Moods + Sequenzen via MoodlitAPI (Actor mit JWT-Bearer-Calls
  über AuthenticatedTransport, automatischer 401-Retry)
- MoodPlayerView mit Idle-Timer-Off, Status-Bar-Hidden, Timer-Auto-
  Close, Favorite-Toggle, Play/Pause, Auto-Hide-Controls
- SequencePlayerView mit Crossfade-Rotation durch alle Sequence-Moods
  (Net new ggü. Web — dort ist Sequence-Playback nicht verkabelt)
- AnimatedMoodView rendert alle 21 AnimationTypes als 30-fps Timeline-
  View mit sin/cos-modulierten Filter-Effekten
- Cards-Pattern Auth-Gate: Presets ohne Login sichtbar, Custom-
  Creation triggert ManaAuthGate.require → Login-Sheet
- Theme: ManaTheme.twilight Forward (Violett #7c3aed)

Build verified:
- xcodebuild iOS Simulator (iPhone 17) → BUILD SUCCEEDED
- xcodebuild macOS → BUILD SUCCEEDED

Offen (μ-7.1+): Apple-Dev-Portal-Setup (Bundle, Capabilities), TestFlight,
Widget, Settings-UI (Brightness/Speed), Hex-Color-Picker mit Text-Input,
Visual-Polish der per-Animation Effekte.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 15:01:04 +02:00

70 lines
2 KiB
Swift

import SwiftUI
/// Sequence-Erstellungs-Form mit Mood-Multipicker.
public struct CreateSequenceSheet: View {
let onCreate: (_ name: String, _ moodIds: [String], _ durationSec: Int) -> Void
@Environment(\.dismiss) private var dismiss
@Environment(MoodStore.self) private var store
@State private var name = ""
@State private var durationSec = 30
@State private var selectedMoodIds: Set<String> = []
public init(onCreate: @escaping (_ name: String, _ moodIds: [String], _ durationSec: Int) -> Void) {
self.onCreate = onCreate
}
public var body: some View {
NavigationStack {
Form {
Section("Name") {
TextField("Sequenz-Name", text: $name)
}
Section("Dauer pro Mood") {
Stepper("\(durationSec) Sekunden", value: $durationSec, in: 5...600, step: 5)
}
Section("Moods (\(selectedMoodIds.count) ausgewählt)") {
ForEach(store.allMoods) { mood in
HStack {
Image(systemName: selectedMoodIds.contains(mood.id) ? "checkmark.circle.fill" : "circle")
.foregroundStyle(selectedMoodIds.contains(mood.id) ? MoodlitTheme.primary : MoodlitTheme.mutedForeground)
Text(mood.name)
Spacer()
Text(mood.animation.displayName)
.font(.caption2)
.foregroundStyle(MoodlitTheme.mutedForeground)
}
.contentShape(Rectangle())
.onTapGesture { toggle(mood.id) }
}
}
}
.navigationTitle("Neue Sequenz")
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Abbrechen") { dismiss() }
}
ToolbarItem(placement: .confirmationAction) {
Button("Erstellen") {
let trimmed = name.trimmingCharacters(in: .whitespacesAndNewlines)
onCreate(trimmed, Array(selectedMoodIds), durationSec)
}
.disabled(name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || selectedMoodIds.isEmpty)
}
}
}
}
private func toggle(_ id: String) {
if selectedMoodIds.contains(id) {
selectedMoodIds.remove(id)
} else {
selectedMoodIds.insert(id)
}
}
}