crossmate

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

BundledBrowseView.swift (2248B)


      1 import SwiftUI
      2 
      3 struct BundledBrowseView: View {
      4     let onSelected: (String) -> Void
      5 
      6     private var bundles: [PuzzleCatalog.PuzzleBundle] {
      7         PuzzleCatalog.bundles()
      8     }
      9 
     10     var body: some View {
     11         List(bundles) { bundle in
     12             NavigationLink {
     13                 PuzzleListView(puzzles: bundle.puzzles, onSelected: onSelected)
     14                     .navigationTitle(bundle.name)
     15                     .navigationBarTitleDisplayMode(.inline)
     16             } label: {
     17                 VStack(alignment: .leading, spacing: 2) {
     18                     Text(bundle.name)
     19                     Text("^[\(bundle.puzzles.count) puzzle](inflect: true)")
     20                         .font(.subheadline)
     21                         .foregroundStyle(.secondary)
     22                 }
     23             }
     24         }
     25     }
     26 }
     27 
     28 struct DebugBrowseView: View {
     29     let onSelected: (String) -> Void
     30 
     31     private var puzzles: [PuzzleCatalog.Entry] {
     32         PuzzleCatalog.debugPuzzles()
     33     }
     34 
     35     var body: some View {
     36         PuzzleListView(puzzles: puzzles, onSelected: onSelected)
     37     }
     38 }
     39 
     40 /// A list of individual puzzles, each showing a grid preview alongside its
     41 /// title and publisher.
     42 private struct PuzzleListView: View {
     43     let puzzles: [PuzzleCatalog.Entry]
     44     let onSelected: (String) -> Void
     45 
     46     var body: some View {
     47         List(puzzles) { entry in
     48             Button {
     49                 if let source = try? entry.loadSource() {
     50                     onSelected(source)
     51                 }
     52             } label: {
     53                 HStack(spacing: 12) {
     54                     GridThumbnailView(
     55                         width: entry.gridWidth,
     56                         height: entry.gridHeight,
     57                         cells: entry.blockCells.map { $0 ? .block : .empty }
     58                     )
     59                     VStack(alignment: .leading, spacing: 2) {
     60                         Text(entry.title)
     61                         if let publisher = entry.publisher, !publisher.isEmpty {
     62                             Text(publisher)
     63                                 .font(.subheadline)
     64                                 .foregroundStyle(.secondary)
     65                         }
     66                     }
     67                 }
     68             }
     69             .buttonStyle(.plain)
     70         }
     71     }
     72 }