You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
4.5 KiB
127 lines
4.5 KiB
import DesignSystem
|
|
import MusubiCore
|
|
import SwiftUI
|
|
|
|
struct ContentView: View {
|
|
let sourceList: SourceListModel
|
|
let coordinator: Coordinator
|
|
@AppStorage("detailTab") private var tab = DetailTab.screens
|
|
|
|
enum DetailTab: String { case screens, sound, intercom }
|
|
|
|
var body: some View {
|
|
NavigationSplitView {
|
|
SourceListView(sourceList: sourceList, audio: coordinator.audio)
|
|
.navigationSplitViewColumnWidth(min: 220, ideal: 260)
|
|
} detail: {
|
|
switch tab {
|
|
case .screens: ScreensView(coordinator: coordinator)
|
|
case .sound: SoundView(audio: coordinator.audio, sourceList: sourceList)
|
|
case .intercom: IntercomView(intercom: coordinator.intercom, sourceList: sourceList, audio: coordinator.audio)
|
|
}
|
|
}
|
|
.navigationTitle("Musubi")
|
|
.navigationSubtitle("NDI rein. Bild, Ton und Stimme raus.")
|
|
.toolbar {
|
|
ToolbarItem(placement: .navigation) {
|
|
if coordinator.settings.role == .control {
|
|
SceneMenu(coordinator: coordinator)
|
|
} else {
|
|
Text("Knoten").font(Theme.Font.caption).foregroundStyle(Theme.Color.nezumi)
|
|
}
|
|
}
|
|
ToolbarItem(placement: .principal) {
|
|
Picker("Ansicht", selection: $tab) {
|
|
Text("Bildschirme").tag(DetailTab.screens)
|
|
Text("Ton").tag(DetailTab.sound)
|
|
if coordinator.settings.role == .control {
|
|
Text("Intercom").tag(DetailTab.intercom)
|
|
}
|
|
}
|
|
.pickerStyle(.segmented)
|
|
.fixedSize()
|
|
}
|
|
if coordinator.outputs.isSleepBlocked {
|
|
ToolbarItem(placement: .primaryAction) {
|
|
Text("Ruhezustand blockiert")
|
|
.font(Theme.Font.caption)
|
|
.foregroundStyle(Theme.Color.nezumi)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct SourceListView: View {
|
|
let sourceList: SourceListModel
|
|
let audio: AudioController
|
|
|
|
var body: some View {
|
|
List {
|
|
Section("NDI") {
|
|
switch sourceList.state {
|
|
case .unavailable:
|
|
HintRow(text: "NDI lässt sich nicht starten. Prüfe die Installation des NDI SDK.")
|
|
case .idle, .searching:
|
|
if sourceList.sources.isEmpty {
|
|
HintRow(text: "Keine NDI-Quellen gefunden. Prüfe, ob das Technik-Netz an en7 hängt.")
|
|
} else {
|
|
ForEach(sourceList.sources, id: \.ndiName) { source in
|
|
SourceRow(source: source)
|
|
.draggable(source.ndiName)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Section("Mikrofone") {
|
|
ForEach(audio.matrix.inputDevices) { device in
|
|
Label {
|
|
Text(verbatim: device.name)
|
|
.font(Theme.Font.body)
|
|
.foregroundStyle(Theme.Color.washi)
|
|
} icon: {
|
|
Image(systemName: "mic").foregroundStyle(Theme.Color.nezumi)
|
|
}
|
|
.draggable("input:\(device.uid)")
|
|
}
|
|
}
|
|
}
|
|
.scrollContentBackground(.hidden)
|
|
.background(Theme.Color.kasumi)
|
|
.safeAreaInset(edge: .top, spacing: 0) {
|
|
Text("Quellen")
|
|
.font(Theme.Font.title)
|
|
.foregroundStyle(Theme.Color.washi)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.padding(Theme.Space.card)
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct HintRow: View {
|
|
let text: LocalizedStringKey
|
|
|
|
var body: some View {
|
|
Text(text)
|
|
.font(Theme.Font.caption)
|
|
.foregroundStyle(Theme.Color.nezumi)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
}
|
|
}
|
|
|
|
private struct SourceRow: View {
|
|
let source: Source
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: Theme.Space.unit / 2) {
|
|
Text(verbatim: source.label)
|
|
.font(Theme.Font.body)
|
|
.foregroundStyle(Theme.Color.washi)
|
|
Text(verbatim: source.ndiName)
|
|
.font(Theme.Font.caption.monospaced())
|
|
.foregroundStyle(Theme.Color.nezumi)
|
|
}
|
|
.padding(.vertical, Theme.Space.unit / 2)
|
|
}
|
|
}
|