Procházet zdrojové kódy

refactor: move autosave behavior into an AutosaveMenu view which also provides a note about the next date

Sam Jaffe před 1 týdnem
rodič
revize
339a9326ad

+ 5 - 1
Todos/TodosApp.swift

@@ -33,9 +33,11 @@ struct TodosApp: App {
     }
   }()
 
+  @State private var hasAutosave: Bool = false
+
   var body: some Scene {
     WindowGroup {
-      ContentView().onAppear {
+      ContentView(hasAutosave: $hasAutosave).onAppear {
         // Disable the tab bar options
         NSWindow.allowsAutomaticWindowTabbing = false
       }
@@ -55,6 +57,8 @@ struct TodosApp: App {
           .modelContainer(sharedModelContainer)
         ImportMenu()
           .modelContainer(sharedModelContainer)
+        AutosaveMenu(hasAutosave: $hasAutosave)
+          .modelContainer(sharedModelContainer)
       }
     }
 

+ 3 - 44
Todos/View/ContentView.swift

@@ -10,12 +10,10 @@ import SwiftData
 
 struct ContentView: View {
   @Environment(\.modelContext) private var modelContext
-  @AppStorage(UserDefaultsKeys.WeekStart) private var weekStart = Date()
-  let inPreview = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
 
   @Query(sort: \Project.sortOrder) private var items: [Project]
   @State private var selection: Project?
-  @State private var hasAutosave: Bool = false
+  @Binding var hasAutosave: Bool
 
   var body: some View {
     NavigationSplitView {
@@ -47,7 +45,6 @@ struct ContentView: View {
         ContentUnavailableView(header, systemImage: "doc.text.image.fill")
       }
     }
-    .onAppear(perform: autosave)
     .alert("Autosave", isPresented: $hasAutosave) {
       Button("OK") {
         hasAutosave = false
@@ -74,45 +71,6 @@ struct ContentView: View {
     try? self.modelContext.save()
   }
 
-  private func autosave() {
-    if inPreview {
-      // This isn't great, but we shouldn't be running this in a preview
-      // environment in the first place, so w/e.
-      return
-    }
-
-    let now = Date()
-    let sunday = Calendar.current.nextDate(after: weekStart,
-                                           matching: DateComponents(weekday: 1),
-                                           matchingPolicy: .nextTime)
-
-    if now <= sunday! {
-      return
-    }
-
-    let ymd = weekStart.formatted(.iso8601.year().month().day())
-    SaveController.save(items, toUrl: SaveController.filename(date: ymd))
-    weekStart = now
-    cleanup()
-    hasAutosave = true
-  }
-
-  private func cleanup() {
-    for item in items {
-      item.tasks.removeAll(where: { $0.status == .complete })
-      for task in item.tasks {
-        if task.status == .inProgress {
-          task.status = .todo
-        }
-
-        task.subtasks.removeAll(where: { $0.status == .complete })
-        for subtask in task.subtasks where subtask.status == .inProgress {
-          subtask.status = .todo
-        }
-      }
-    }
-  }
-
   private func deleteItem(item: Project) {
     if let selection = selection, selection == item {
       self.selection = nil
@@ -124,6 +82,7 @@ struct ContentView: View {
 }
 
 #Preview {
-  ContentView()
+  @Previewable @State var hasAutosave = false
+  ContentView(hasAutosave: $hasAutosave)
     .modelContainer(for: Project.self, inMemory: true)
 }

+ 75 - 0
Todos/View/Menu/AutosaveMenu.swift

@@ -0,0 +1,75 @@
+//
+//  SaveAndRefreshMenu.swift
+//  Todos
+//
+//  Created by Sam Jaffe on 3/9/26.
+//
+
+import SwiftUI
+import SwiftData
+internal import Combine
+
+struct AutosaveMenu: View {
+  @Environment(\.modelContext) private var modelContext
+  @AppStorage(UserDefaultsKeys.WeekStart) private var weekStart = Date()
+  let inPreview = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
+
+  @Query private var items: [Project]
+  @Binding var hasAutosave: Bool
+
+  var body: some View {
+    Button("Save and Cleanup") {
+      tryAutosave()
+    }
+    .keyboardShortcut("R", modifiers: [.command, .shift])
+//    .disabled(!shouldAutosave)
+
+    Text("     Next Autosave: after \(ymd(nextSunday(weekStart)))")
+      .onAppear(perform: tryAutosave)
+  }
+
+  func tryAutosave() {
+    if shouldAutosave && !inPreview {
+      saveAndCleanup(weekStart)
+      weekStart = Date()
+      hasAutosave = true
+    }
+  }
+
+  func nextSunday(_ date: Date) -> Date {
+    Calendar.current.nextDate(after: date,
+                              matching: DateComponents(weekday: 1),
+                              matchingPolicy: .nextTime)!
+  }
+
+  func ymd(_ date: Date) -> String {
+    date.formatted(.iso8601.year().month().day())
+  }
+
+  var shouldAutosave: Bool {
+    ymd(Date()) > ymd(nextSunday(weekStart))
+  }
+
+  func saveAndCleanup(_ date: Date) {
+    SaveController.save(items, toUrl: SaveController.filename(date: ymd(date)))
+
+    for item in items {
+      item.tasks.removeAll(where: { $0.status == .complete })
+      for task in item.tasks {
+        if task.status == .inProgress {
+          task.status = .todo
+        }
+
+        task.subtasks.removeAll(where: { $0.status == .complete })
+        for subtask in task.subtasks where subtask.status == .inProgress {
+          subtask.status = .todo
+        }
+      }
+    }
+  }
+}
+
+#Preview {
+  @Previewable @State var hasAutosave = true
+  AutosaveMenu(hasAutosave: $hasAutosave)
+}