| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- //
- // AlarmAudioSection.swift
- // LoopFollow
- //
- // Created by Jonas Björkert on 2025-05-12.
- // Copyright © 2025 Jon Fawcett. All rights reserved.
- //
- import SwiftUI
- struct AlarmAudioSection: View {
- @Binding var alarm: Alarm
- var hideRepeat: Bool = false
- @State private var showingTonePicker = false
- var body: some View {
- Section(header: Text("Alert Sound")) {
- Button {
- showingTonePicker = true
- } label: {
- HStack {
- Text("Tone")
- Spacer()
- Text(alarm.soundFile.displayName)
- .foregroundColor(.secondary)
- Image(systemName: "chevron.right")
- .foregroundColor(.secondary)
- }
- }
- .buttonStyle(.plain)
- .sheet(isPresented: $showingTonePicker) {
- TonePickerSheet(selected: $alarm.soundFile)
- }
- AlarmEnumMenuPicker(
- title: "Play",
- selection: $alarm.playSoundOption,
- allowed: PlaySoundOption.allowed(for: alarm.activeOption)
- )
- if !hideRepeat {
- AlarmEnumMenuPicker(
- title: "Repeat",
- selection: $alarm.repeatSoundOption,
- allowed: RepeatSoundOption.allowed(for: alarm.activeOption)
- )
- }
- }.onChange(of: alarm.activeOption) { newActive in
- let playAllowed = PlaySoundOption.allowed(for: newActive)
- if !playAllowed.contains(alarm.playSoundOption) {
- alarm.playSoundOption = playAllowed.last!
- }
- let repeatAllowed = RepeatSoundOption.allowed(for: newActive)
- if !repeatAllowed.contains(alarm.repeatSoundOption) {
- alarm.repeatSoundOption = repeatAllowed.last!
- }
- }
- }
- }
- struct AlarmEnumMenuPicker<E: CaseIterable & Hashable & DayNightDisplayable>: View {
- let title: String
- @Binding var selection: E
- var allowed: [E]
- var body: some View {
- HStack {
- Text(title)
- Spacer()
- Picker("", selection: $selection) {
- ForEach(allowed, id: \.self) { opt in
- Text(opt.displayName).tag(opt)
- }
- }
- // if the current selection became invalid, snap to the first allowed
- .onAppear { validate() }
- .onChange(of: allowed) { _ in validate() }
- }
- }
- private func validate() {
- if !allowed.contains(selection), let first = allowed.first {
- selection = first
- }
- }
- }
- extension AlarmEnumMenuPicker where E: CaseIterable {
- init(title: String, selection: Binding<E>) {
- self.title = title
- _selection = selection
- allowed = Array(E.allCases)
- }
- }
- private struct TonePickerSheet: View {
- @Binding var selected: SoundFile
- @Environment(\.dismiss) private var dismiss
- var body: some View {
- NavigationView {
- List {
- ForEach(SoundFile.allCases) { tone in
- Button {
- selected = tone
- AlarmSound.setSoundFile(str: tone.rawValue)
- AlarmSound.stop()
- AlarmSound.playTest()
- } label: {
- HStack {
- Text(tone.displayName)
- if tone == selected {
- Spacer()
- Image(systemName: "checkmark")
- .foregroundColor(.accentColor)
- }
- }
- }
- }
- }
- .navigationTitle("Choose Tone")
- .toolbar {
- ToolbarItem(placement: .confirmationAction) {
- Button("Done") {
- AlarmSound.stop()
- dismiss()
- }
- }
- }
- }
- }
- }
|