127 lines
3.8 KiB
Swift
127 lines
3.8 KiB
Swift
import SwiftUI
|
|
|
|
struct ContentView: View {
|
|
@StateObject private var model = AppModel()
|
|
@State private var username = ""
|
|
@State private var password = ""
|
|
@State private var selectedTab: MainTab = .rooms
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
ZStack {
|
|
Theme.background.ignoresSafeArea()
|
|
|
|
if model.authState == .signedIn {
|
|
mainApp
|
|
} else {
|
|
AuthView(
|
|
model: model,
|
|
username: $username,
|
|
password: $password
|
|
)
|
|
}
|
|
}
|
|
.navigationTitle("Blastoise")
|
|
.toolbarColorScheme(.dark, for: .navigationBar)
|
|
.toolbarBackground(Theme.background, for: .navigationBar)
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.font(Theme.bodyFont)
|
|
.buttonBorderShape(.roundedRectangle(radius: Theme.corner))
|
|
}
|
|
.onChange(of: model.authState) { _, authState in
|
|
if authState == .signedIn {
|
|
password = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
private var mainApp: some View {
|
|
ScrollView {
|
|
VStack(spacing: 14) {
|
|
HeaderView(model: model)
|
|
PlayerDeckView(model: model)
|
|
tabStrip
|
|
selectedPanel
|
|
DebugFooterView(model: model)
|
|
}
|
|
.padding(.horizontal, 14)
|
|
.padding(.bottom, 18)
|
|
}
|
|
}
|
|
|
|
private var tabStrip: some View {
|
|
HStack(spacing: 8) {
|
|
ForEach(MainTab.allCases) { tab in
|
|
Button {
|
|
selectedTab = tab
|
|
if tab == .library {
|
|
Task { await model.loadLibraryIfNeeded() }
|
|
} else if tab == .playlists {
|
|
Task { await model.loadPlaylistsIfNeeded() }
|
|
}
|
|
} label: {
|
|
Label(tab.title, systemImage: tab.icon)
|
|
.labelStyle(.iconOnly)
|
|
.frame(width: 44, height: 40)
|
|
.background(selectedTab == tab ? Theme.accent : Theme.panel2)
|
|
.foregroundStyle(selectedTab == tab ? Theme.background : Theme.text)
|
|
.clipShape(RoundedRectangle(cornerRadius: Theme.corner))
|
|
}
|
|
.accessibilityLabel(tab.title)
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var selectedPanel: some View {
|
|
switch selectedTab {
|
|
case .rooms:
|
|
RoomsPanel(model: model)
|
|
case .queue:
|
|
QueuePanel(model: model)
|
|
case .people:
|
|
PeoplePanel(model: model)
|
|
case .library:
|
|
LibraryPanel(model: model)
|
|
case .playlists:
|
|
PlaylistsPanel(model: model)
|
|
case .debug:
|
|
DebugPanel(model: model)
|
|
}
|
|
}
|
|
}
|
|
|
|
private enum MainTab: String, CaseIterable, Identifiable {
|
|
case rooms
|
|
case queue
|
|
case people
|
|
case library
|
|
case playlists
|
|
case debug
|
|
|
|
var id: String { rawValue }
|
|
|
|
var title: String {
|
|
switch self {
|
|
case .rooms: return "Rooms"
|
|
case .queue: return "Queue"
|
|
case .people: return "People"
|
|
case .library: return "Library"
|
|
case .playlists: return "Lists"
|
|
case .debug: return "Debug"
|
|
}
|
|
}
|
|
|
|
var icon: String {
|
|
switch self {
|
|
case .rooms: return "radio"
|
|
case .queue: return "list.bullet"
|
|
case .people: return "person.2"
|
|
case .library: return "music.note.list"
|
|
case .playlists: return "rectangle.stack"
|
|
case .debug: return "waveform.path.ecg"
|
|
}
|
|
}
|
|
}
|