// // AppSelectionSheet.swift // Severed // import FamilyControls import SwiftUI /// App/category/website selection for a rule. Wraps Apple's /// `FamilyActivityPicker` (the system-sanctioned way to choose apps without /// seeing their identities) and adds the reference app's Block / Allow Only /// mode switch. struct AppSelectionSheet: View { @Binding var draft: RuleDraft @Environment(\.dismiss) private var dismiss @State private var selection: FamilyActivitySelection @State private var mode: SelectionMode init(draft: Binding) { self._draft = draft self._selection = State( initialValue: AppSelectionCodec.decode(draft.wrappedValue.selectionData) ) self._mode = State(initialValue: draft.wrappedValue.selectionMode) } var body: some View { VStack(spacing: 0) { HStack { CircleIconButton(systemImage: "chevron.left") { dismiss() } .accessibilityIdentifier("selectionBackButton") Spacer() CircleIconButton(systemImage: "checkmark", tint: .black) { save() } .background(Theme.accent, in: Circle()) .accessibilityIdentifier("confirmSelectionButton") } .overlay( Text("Selected") .font(.system(size: 18, weight: .semibold)) .foregroundStyle(.white) ) .padding(.horizontal, 20) .padding(.top, 18) Picker("Mode", selection: $mode) { ForEach(SelectionMode.allCases, id: \.self) { mode in Text(mode.displayName).tag(mode) } } .pickerStyle(.segmented) .padding(.horizontal, 20) .padding(.top, 16) .accessibilityIdentifier("selectionModePicker") FamilyActivityPicker(selection: $selection) .padding(.top, 4) VStack(spacing: 10) { Text(selectionSummary) .font(.system(size: 14)) .foregroundStyle(Theme.textSecondary) .accessibilityIdentifier("selectionCountLabel") Button { save() } label: { Text("Save") .font(.system(size: 17, weight: .semibold)) .foregroundStyle(.black) .frame(maxWidth: .infinity) .frame(height: 54) .background(.white, in: RoundedRectangle(cornerRadius: 27)) } .buttonStyle(.plain) .accessibilityIdentifier("saveSelectionButton") } .padding(.horizontal, 20) .padding(.bottom, 16) } .background(Theme.background) } private var selectionSummary: String { let count = AppSelectionCodec.count(of: selection) return count == 1 ? "1 App Selected" : "\(count) Apps Selected" } private func save() { draft.selectionData = AppSelectionCodec.encode(selection) draft.selectionCount = AppSelectionCodec.count(of: selection) draft.selectionMode = mode dismiss() } }