Christopher Hotchkiss Christopher Hotchkiss
Login

Code

remindwall / RWPureSwift / Sources / EditSettingsNew / BusSettings / AlertWindowEditor.swift

Back to remindwall — Current RemindWall

Download this file

import AppTypes
import SwiftUI

/// The one window editor every alert surface shares (TR1.4 review decision):
/// start/end time pickers plus weekday pills. Pure view - the owning feature
/// supplies the window and receives the edits.
public struct AlertWindowEditorView: View {
    let window: AlertWindow
    let onSetStart: (_ hour: Int, _ minute: Int) -> Void
    let onSetEnd: (_ hour: Int, _ minute: Int) -> Void
    let onToggleWeekday: (DaysOfWeek) -> Void

    public init(
        window: AlertWindow,
        onSetStart: @escaping (_ hour: Int, _ minute: Int) -> Void,
        onSetEnd: @escaping (_ hour: Int, _ minute: Int) -> Void,
        onToggleWeekday: @escaping (DaysOfWeek) -> Void
    ) {
        self.window = window
        self.onSetStart = onSetStart
        self.onSetEnd = onSetEnd
        self.onToggleWeekday = onToggleWeekday
    }

    public var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            DatePicker(
                "Start",
                selection: Binding(
                    get: { time(hour: window.startHour, minute: window.startMinute) },
                    set: { newDate in
                        let comps = Calendar.current.dateComponents([.hour, .minute], from: newDate)
                        onSetStart(comps.hour ?? 0, comps.minute ?? 0)
                    }
                ),
                displayedComponents: .hourAndMinute
            )
            DatePicker(
                "End",
                selection: Binding(
                    get: { time(hour: window.endHour, minute: window.endMinute) },
                    set: { newDate in
                        let comps = Calendar.current.dateComponents([.hour, .minute], from: newDate)
                        onSetEnd(comps.hour ?? 0, comps.minute ?? 0)
                    }
                ),
                displayedComponents: .hourAndMinute
            )
            HStack {
                ForEach(DaysOfWeek.allCases, id: \.rawValue) { day in
                    Button {
                        onToggleWeekday(day)
                    } label: {
                        Text(initial(day))
                            .font(.callout)
                            .frame(width: 32, height: 32)
                            .background(window.weekdays.contains(day) ? Color.accentColor : Color.gray.opacity(0.2))
                            .foregroundStyle(window.weekdays.contains(day) ? Color.white : Color.primary)
                            .clipShape(Circle())
                    }
                    .buttonStyle(.plain)
                    .accessibilityLabel(String(describing: day))
                    .accessibilityValue(window.weekdays.contains(day) ? "active" : "inactive")
                }
            }
        }
    }

    private func time(hour: Int, minute: Int) -> Date {
        var comps = DateComponents()
        comps.hour = hour
        comps.minute = minute
        return Calendar.current.date(from: comps) ?? Date()
    }

    private func initial(_ day: DaysOfWeek) -> String {
        switch day {
        case .Sunday: return "S"
        case .Monday: return "M"
        case .Tuesday: return "T"
        case .Wednesday: return "W"
        case .Thursday: return "T"
        case .Friday: return "F"
        case .Saturday: return "S"
        }
    }
}