TheNoiseClock/TheNoiseClock/Views/Noise/NoiseView.swift

134 lines
4.3 KiB
Swift

//
// NoiseView.swift
// TheNoiseClock
//
// Created by Matt Bruce on 9/7/25.
//
import SwiftUI
import AudioPlaybackKit
/// Main noise/audio player view
struct NoiseView: View {
// MARK: - Properties
@State private var viewModel = SoundViewModel()
@State private var selectedSound: Sound? {
didSet {
// Stop current playback when selecting a new sound
if let newSound = selectedSound, newSound != oldValue {
viewModel.selectSound(newSound)
}
}
}
// MARK: - Body
var body: some View {
GeometryReader { geometry in
let isLandscape = geometry.size.width > geometry.size.height
if isLandscape {
// Landscape layout: Player on left, sounds on right
landscapeLayout
} else {
// Portrait layout: Stacked vertically
portraitLayout
}
}
.animation(.easeInOut(duration: 0.3), value: selectedSound)
}
// MARK: - Computed Properties
private var soundControlView: some View {
SoundControlView(
isPlaying: viewModel.isPlaying,
selectedSound: selectedSound,
onPlay: { sound in
viewModel.playSound(sound)
},
onStop: {
viewModel.stopSound()
}
)
.transition(.opacity.combined(with: .scale))
}
// MARK: - Layouts
private var portraitLayout: some View {
VStack(spacing: 0) {
// Fixed header
VStack(alignment: .leading, spacing: UIConstants.Spacing.medium) {
Text("Ambient Sounds")
.sectionTitleStyle()
// Playback controls - always visible when sound is selected
if selectedSound != nil {
soundControlView
.centered()
}
}
.contentPadding(horizontal: UIConstants.Spacing.large)
.padding(.top, UIConstants.Spacing.large)
.background(Color(.systemBackground))
// Scrollable sound selection
ScrollView {
SoundCategoryView(
sounds: viewModel.availableSounds,
selectedSound: $selectedSound
)
.contentPadding(horizontal: UIConstants.Spacing.large, vertical: UIConstants.Spacing.large)
}
}
}
private var landscapeLayout: some View {
HStack(spacing: UIConstants.Spacing.large) {
// Left side: Player controls
VStack(alignment: .leading, spacing: UIConstants.Spacing.medium) {
Text("Ambient Sounds")
.sectionTitleStyle()
if selectedSound != nil {
soundControlView
} else {
// Placeholder when no sound selected
VStack(spacing: UIConstants.Spacing.small) {
Image(systemName: "music.note")
.font(.largeTitle)
.foregroundColor(.secondary)
Text("Select a sound to begin")
.font(.subheadline)
.foregroundColor(.secondary)
}
.frame(maxWidth: .infinity)
.padding(.vertical, UIConstants.Spacing.large)
}
Spacer()
}
.frame(maxWidth: 400) // Reasonable width for player section
.contentPadding(horizontal: UIConstants.Spacing.large)
.padding(.top, UIConstants.Spacing.large)
// Right side: Sound selection
VStack(spacing: 0) {
ScrollView {
SoundCategoryView(
sounds: viewModel.availableSounds,
selectedSound: $selectedSound
)
.contentPadding(horizontal: UIConstants.Spacing.large, vertical: UIConstants.Spacing.large)
}
}
}
.contentPadding(horizontal: UIConstants.Spacing.medium)
}
}
// MARK: - Preview
#Preview {
NoiseView()
}