crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

NewGameSheet.swift (3527B)


      1 import SwiftUI
      2 
      3 struct NewGameSheet: View {
      4     let store: GameStore
      5 
      6     @Environment(\.dismiss) private var dismiss
      7     @Environment(NYTAuthService.self) private var nytAuth
      8     @AppStorage("lastPuzzleSource") private var storedSource: PuzzleSource = .bundled
      9     @AppStorage("debugMode") private var debugMode = false
     10     @State private var selection: PuzzleSource = .bundled
     11     @State private var duplicateSource: String?
     12     @State private var createError: String?
     13 
     14     private var availableSources: [PuzzleSource] {
     15         var sources: [PuzzleSource] = [.bundled]
     16         if debugMode {
     17             sources.append(.debug)
     18         }
     19         sources.append(.imported)
     20         if nytAuth.isSignedIn {
     21             sources.append(.nyt)
     22         }
     23         return sources
     24     }
     25 
     26     var body: some View {
     27         NavigationStack {
     28             VStack(spacing: 0) {
     29                 Picker("Source", selection: $selection) {
     30                     ForEach(availableSources) { source in
     31                         Text(source.title).tag(source)
     32                     }
     33                 }
     34                 .pickerStyle(.segmented)
     35                 .padding()
     36 
     37                 Group {
     38                     switch selection {
     39                     case .bundled:
     40                         BundledBrowseView(onSelected: handleSelected)
     41                     case .debug:
     42                         DebugBrowseView(onSelected: handleSelected)
     43                     case .imported:
     44                         ImportedBrowseView(onSelected: handleSelected)
     45                     case .nyt:
     46                         NYTBrowseView(onSelected: handleSelected)
     47                     }
     48                 }
     49             }
     50             .navigationTitle("New Puzzle")
     51             .navigationBarTitleDisplayMode(.inline)
     52             .toolbar {
     53                 ToolbarItem(placement: .cancellationAction) {
     54                     Button("Cancel") { dismiss() }
     55                 }
     56             }
     57         }
     58         .onAppear {
     59             selection = availableSources.contains(storedSource) ? storedSource : .bundled
     60         }
     61         .onChange(of: selection) { _, newValue in
     62             storedSource = newValue
     63         }
     64         .alert(
     65             "Puzzle Already in Library",
     66             isPresented: .init(
     67                 get: { duplicateSource != nil },
     68                 set: { if !$0 { duplicateSource = nil } }
     69             ),
     70             presenting: duplicateSource
     71         ) { source in
     72             Button("Create Copy") {
     73                 create(from: source)
     74             }
     75             Button("Cancel", role: .cancel) {}
     76         } message: { _ in
     77             Text("You already have a game for this puzzle. Cancel and resume it from the library, or create a new copy.")
     78         }
     79         .alert(
     80             "Couldn't Create Game",
     81             isPresented: .init(
     82                 get: { createError != nil },
     83                 set: { if !$0 { createError = nil } }
     84             ),
     85             presenting: createError
     86         ) { _ in
     87             Button("OK", role: .cancel) {}
     88         } message: { message in
     89             Text(message)
     90         }
     91     }
     92 
     93     private func handleSelected(_ source: String) {
     94         if store.findGameID(matching: source) != nil {
     95             duplicateSource = source
     96         } else {
     97             create(from: source)
     98         }
     99     }
    100 
    101     private func create(from source: String) {
    102         do {
    103             _ = try store.createGame(from: source)
    104             dismiss()
    105         } catch {
    106             createError = error.localizedDescription
    107         }
    108     }
    109 }