|
|
@@ -1,13 +1,6 @@
|
|
|
import SwiftUI
|
|
|
import AppKit
|
|
|
|
|
|
-private enum Provider: String, CaseIterable, Identifiable {
|
|
|
- case iCloud = "iCloud"
|
|
|
- case google = "Google"
|
|
|
-
|
|
|
- var id: String { rawValue }
|
|
|
-}
|
|
|
-
|
|
|
private struct NoteCollection: Identifiable, Hashable {
|
|
|
enum Kind: Hashable {
|
|
|
case notes
|
|
|
@@ -16,7 +9,6 @@ private struct NoteCollection: Identifiable, Hashable {
|
|
|
}
|
|
|
|
|
|
let id: UUID
|
|
|
- let provider: Provider
|
|
|
let name: String
|
|
|
let kind: Kind
|
|
|
}
|
|
|
@@ -44,13 +36,14 @@ struct NotesAppRootView: View {
|
|
|
@State private var selectedCollectionID: UUID? = NotesAppRootView.defaultCollectionID
|
|
|
@State private var selectedNoteID: UUID? = nil
|
|
|
@State private var editorFocus: EditorFocusField? = nil
|
|
|
+ @State private var showPermanentDeleteConfirmation = false
|
|
|
|
|
|
@StateObject private var store = NotesStore()
|
|
|
|
|
|
private var collections: [NoteCollection] = [
|
|
|
- NoteCollection(id: NotesAppRootView.defaultCollectionID, provider: .iCloud, name: "Notes", kind: .notes),
|
|
|
- NoteCollection(id: NotesAppRootView.archiveCollectionID, provider: .iCloud, name: "Archive", kind: .archive),
|
|
|
- NoteCollection(id: NotesAppRootView.recentlyDeletedCollectionID, provider: .iCloud, name: "Recently Deleted", kind: .recentlyDeleted)
|
|
|
+ NoteCollection(id: NotesAppRootView.defaultCollectionID, name: "Notes", kind: .notes),
|
|
|
+ NoteCollection(id: NotesAppRootView.archiveCollectionID, name: "Archive", kind: .archive),
|
|
|
+ NoteCollection(id: NotesAppRootView.recentlyDeletedCollectionID, name: "Recently Deleted", kind: .recentlyDeleted)
|
|
|
]
|
|
|
|
|
|
private var selectedCollection: NoteCollection? {
|
|
|
@@ -58,21 +51,16 @@ struct NotesAppRootView: View {
|
|
|
}
|
|
|
|
|
|
private var filteredNotes: [Note] {
|
|
|
- // Since this is a UI-first pass, we treat notes as belonging to the iCloud "Notes" collection only.
|
|
|
guard let selectedCollection else { return [] }
|
|
|
|
|
|
let scoped: [Note]
|
|
|
- if selectedCollection.provider != .iCloud {
|
|
|
- scoped = []
|
|
|
- } else {
|
|
|
- switch selectedCollection.kind {
|
|
|
- case .notes:
|
|
|
- scoped = store.notes.filter { !$0.isDeleted && !$0.isArchived }
|
|
|
- case .archive:
|
|
|
- scoped = store.notes.filter { !$0.isDeleted && $0.isArchived }
|
|
|
- case .recentlyDeleted:
|
|
|
- scoped = store.notes.filter { $0.isDeleted }
|
|
|
- }
|
|
|
+ switch selectedCollection.kind {
|
|
|
+ case .notes:
|
|
|
+ scoped = store.notes.filter { !$0.isDeleted && !$0.isArchived }
|
|
|
+ case .archive:
|
|
|
+ scoped = store.notes.filter { !$0.isDeleted && $0.isArchived }
|
|
|
+ case .recentlyDeleted:
|
|
|
+ scoped = store.notes.filter { $0.isDeleted }
|
|
|
}
|
|
|
|
|
|
let trimmed = searchText.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
|
|
@@ -121,8 +109,8 @@ struct NotesAppRootView: View {
|
|
|
store.notes[index].isDeleted = true
|
|
|
store.notes[index].deletedAt = Date()
|
|
|
|
|
|
- selectedCollectionID = NotesAppRootView.recentlyDeletedCollectionID
|
|
|
- self.selectedNoteID = store.notes[index].id
|
|
|
+ // Stay on the current sidebar section (e.g. Notes); clear selection since the note left this list.
|
|
|
+ self.selectedNoteID = nil
|
|
|
editorFocus = nil
|
|
|
}
|
|
|
|
|
|
@@ -176,8 +164,8 @@ struct NotesAppRootView: View {
|
|
|
guard let index = store.notes.firstIndex(where: { $0.id == selectedNoteID }) else { return }
|
|
|
|
|
|
store.notes[index].isArchived = true
|
|
|
- selectedCollectionID = NotesAppRootView.archiveCollectionID
|
|
|
- self.selectedNoteID = store.notes[index].id
|
|
|
+ // Stay on Notes; clear selection since archived notes no longer appear in this list.
|
|
|
+ self.selectedNoteID = nil
|
|
|
editorFocus = nil
|
|
|
}
|
|
|
|
|
|
@@ -237,7 +225,7 @@ struct NotesAppRootView: View {
|
|
|
.help("Restore Note")
|
|
|
.disabled(!canRestoreSelectedNote)
|
|
|
|
|
|
- Button(action: permanentlyDeleteSelectedNote) {
|
|
|
+ Button(action: { showPermanentDeleteConfirmation = true }) {
|
|
|
Image(systemName: "trash.slash")
|
|
|
.font(.system(size: 14, weight: .semibold))
|
|
|
}
|
|
|
@@ -288,6 +276,17 @@ struct NotesAppRootView: View {
|
|
|
.background(Color(nsColor: .textBackgroundColor))
|
|
|
}
|
|
|
.preferredColorScheme(.dark)
|
|
|
+ .onAppear {
|
|
|
+ store.purgeExpiredRecentlyDeletedIfNeeded()
|
|
|
+ }
|
|
|
+ .alert("Delete permanently?", isPresented: $showPermanentDeleteConfirmation) {
|
|
|
+ Button("Cancel", role: .cancel) {}
|
|
|
+ Button("Delete Permanently", role: .destructive) {
|
|
|
+ permanentlyDeleteSelectedNote()
|
|
|
+ }
|
|
|
+ } message: {
|
|
|
+ Text("This note will be permanently removed from this device. Notes in Recently Deleted are also removed automatically after 30 days. You cannot undo this action.")
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -298,7 +297,6 @@ private struct SidebarView: View {
|
|
|
@Binding var selectedCollectionID: UUID?
|
|
|
|
|
|
private func notesCount(for collection: NoteCollection) -> Int {
|
|
|
- if collection.provider != .iCloud { return 0 }
|
|
|
switch collection.kind {
|
|
|
case .notes:
|
|
|
return notes.filter { !$0.isDeleted && !$0.isArchived }.count
|
|
|
@@ -311,19 +309,17 @@ private struct SidebarView: View {
|
|
|
|
|
|
var body: some View {
|
|
|
List(selection: $selectedCollectionID) {
|
|
|
- ForEach(Provider.allCases) { provider in
|
|
|
- Section(header: Text(provider == .iCloud ? "iCloud" : "Google")) {
|
|
|
- ForEach(collections.filter { $0.provider == provider }) { collection in
|
|
|
- HStack(spacing: 8) {
|
|
|
- Text(collection.name)
|
|
|
- .foregroundStyle(.primary)
|
|
|
- Spacer(minLength: 8)
|
|
|
- Text("\(notesCount(for: collection))")
|
|
|
- .foregroundStyle(.secondary)
|
|
|
- .font(.system(size: 12, weight: .semibold))
|
|
|
- }
|
|
|
- .tag(collection.id)
|
|
|
+ Section(header: Text("Keep Notebook")) {
|
|
|
+ ForEach(collections) { collection in
|
|
|
+ HStack(spacing: 8) {
|
|
|
+ Text(collection.name)
|
|
|
+ .foregroundStyle(.primary)
|
|
|
+ Spacer(minLength: 8)
|
|
|
+ Text("\(notesCount(for: collection))")
|
|
|
+ .foregroundStyle(.secondary)
|
|
|
+ .font(.system(size: 12, weight: .semibold))
|
|
|
}
|
|
|
+ .tag(collection.id)
|
|
|
}
|
|
|
}
|
|
|
}
|