aboutsummaryrefslogtreecommitdiff
path: root/Map/State
diff options
context:
space:
mode:
authorRuben Beltran del Rio <ruben@unlimited.pizza>2021-02-03 23:53:12 +0100
committerRuben Beltran del Rio <ruben@unlimited.pizza>2021-02-03 23:53:12 +0100
commit5e8ff4850c4827125fe12788dd5b153c4f636f48 (patch)
treef37c90338f33e7ddc84cc855a20dca1ca503476e /Map/State
parent1b85f723b48d38cf345bb9a4f3fd01aa6039b50b (diff)
Add code for first release
Diffstat (limited to 'Map/State')
-rw-r--r--Map/State/AppState.swift103
-rw-r--r--Map/State/Persistence.swift42
-rw-r--r--Map/State/Store.swift18
3 files changed, 163 insertions, 0 deletions
diff --git a/Map/State/AppState.swift b/Map/State/AppState.swift
new file mode 100644
index 0000000..e10efea
--- /dev/null
+++ b/Map/State/AppState.swift
@@ -0,0 +1,103 @@
+import Cocoa
+import Foundation
+import SwiftUI
+
+struct AppState {
+ var selectedMap: Map? = nil
+ var mapBeingDeleted: Map? = nil
+}
+
+enum AppAction {
+ case selectMap(map: Map?)
+ case deleteMap(map: Map)
+ case exportMapAsImage(map: Map, evolution: StageType)
+ case exportMapAsText(map: Map)
+}
+
+func appStateReducer(state: inout AppState, action: AppAction) {
+
+ switch action {
+
+ case .selectMap(let map):
+ state.selectedMap = map
+
+ case .deleteMap(let map):
+ let context = PersistenceController.shared.container.viewContext
+
+ context.delete(map)
+ try? context.save()
+
+ case .exportMapAsImage(let map, let evolution):
+ let window = NSWindow(
+ contentRect: .init(
+ origin: .zero,
+ size: .init(
+ width: NSScreen.main!.frame.width,
+ height: NSScreen.main!.frame.height)),
+ styleMask: [.closable],
+ backing: .buffered,
+ defer: false)
+
+ window.title = map.title ?? "Untitled Map"
+ window.isOpaque = true
+ window.center()
+ window.isMovableByWindowBackground = true
+ window.makeKeyAndOrderFront(nil)
+
+ let renderView = MapRenderView(map: map, evolution: Stage.stages(evolution))
+
+ let view = NSHostingView(rootView: renderView)
+ window.contentView = view
+
+ let imageRepresentation = view.bitmapImageRepForCachingDisplay(in: view.bounds)!
+ view.cacheDisplay(in: view.bounds, to: imageRepresentation)
+ let image = NSImage(cgImage: imageRepresentation.cgImage!, size: view.bounds.size)
+
+ let dialog = NSSavePanel()
+
+ dialog.title = "Save Map"
+ dialog.showsResizeIndicator = false
+ dialog.canCreateDirectories = true
+ dialog.showsHiddenFiles = false
+ dialog.allowedFileTypes = ["png"]
+ dialog.nameFieldStringValue = map.title ?? "Untitled Map"
+
+ if dialog.runModal() == NSApplication.ModalResponse.OK {
+ let result = dialog.url
+
+ if result != nil {
+
+ image.writePNG(toURL: result!)
+ print("saved at \(result!)")
+ }
+ } else {
+ print("Cancel")
+ }
+ window.orderOut(nil)
+
+ case .exportMapAsText(let map):
+ let dialog = NSSavePanel()
+
+ dialog.title = "Save Map Text"
+ dialog.showsResizeIndicator = false
+ dialog.canCreateDirectories = true
+ dialog.showsHiddenFiles = false
+ dialog.allowedFileTypes = ["txt"]
+ dialog.nameFieldStringValue = map.title ?? "Untitled Map"
+
+ if let content = map.content {
+
+ if dialog.runModal() == NSApplication.ModalResponse.OK {
+ let result = dialog.url
+
+ if let result = result {
+ try? content.write(to: result, atomically: true, encoding: String.Encoding.utf8)
+ }
+ } else {
+ print("Cancel")
+ }
+ }
+ }
+}
+
+typealias AppStore = Store<AppState, AppAction>
diff --git a/Map/State/Persistence.swift b/Map/State/Persistence.swift
new file mode 100644
index 0000000..1eb09e8
--- /dev/null
+++ b/Map/State/Persistence.swift
@@ -0,0 +1,42 @@
+import CoreData
+
+struct PersistenceController {
+ static let shared = PersistenceController()
+
+ static var preview: PersistenceController = {
+ let result = PersistenceController(inMemory: true)
+ let viewContext = result.container.viewContext
+ for _ in 0..<10 {
+ let newMap = Map(context: viewContext)
+ newMap.uuid = UUID()
+ newMap.createdAt = Date()
+ newMap.title = "Map \(newMap.createdAt!.format())"
+ newMap.content = ""
+ }
+ do {
+ try viewContext.save()
+ } catch {
+ let nsError = error as NSError
+ fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
+ }
+ return result
+ }()
+
+ let container: NSPersistentCloudKitContainer
+
+ init(inMemory: Bool = false) {
+ container = NSPersistentCloudKitContainer(name: "Map")
+
+ container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
+ container.viewContext.automaticallyMergesChangesFromParent = true
+
+ if inMemory {
+ container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
+ }
+ container.loadPersistentStores(completionHandler: { (storeDescription, error) in
+ if let error = error as NSError? {
+ fatalError("Unresolved error \(error), \(error.userInfo)")
+ }
+ })
+ }
+}
diff --git a/Map/State/Store.swift b/Map/State/Store.swift
new file mode 100644
index 0000000..7860f33
--- /dev/null
+++ b/Map/State/Store.swift
@@ -0,0 +1,18 @@
+import Foundation
+
+final class Store<State, Action>: ObservableObject {
+ @Published private(set) var state: State
+
+ private let reducer: Reducer<State, Action>
+
+ init(initialState: State, reducer: @escaping Reducer<State, Action>) {
+ self.state = initialState
+ self.reducer = reducer
+ }
+
+ func send(_ action: Action) {
+ reducer(&state, action)
+ }
+}
+
+typealias Reducer<State, Action> = (inout State, Action) -> Void