mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-03-18 23:44:01 +01:00
feat: add restore and delete actions
This commit is contained in:
@@ -10,6 +10,7 @@ import SwiftUI
|
||||
struct DashboardView: View {
|
||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass
|
||||
|
||||
@State var memo: MemoObject?
|
||||
@State var sidebarItem: SidebarItem? = .memos
|
||||
|
||||
var body: some View {
|
||||
@@ -18,12 +19,21 @@ struct DashboardView: View {
|
||||
} detail: {
|
||||
switch sidebarItem {
|
||||
case .memos:
|
||||
MemosView()
|
||||
MemosView(memo: $memo)
|
||||
case .trash:
|
||||
TrashView()
|
||||
TrashView(memo: $memo, sidebarItem: $sidebarItem)
|
||||
default:
|
||||
MemosView()
|
||||
MemosView(memo: $memo)
|
||||
}
|
||||
}
|
||||
.fullScreenCover(item: $memo) { memo in
|
||||
MemoView(memo: memo)
|
||||
.onDisappear {
|
||||
withPersistence(\.viewContext) { context in
|
||||
try context.saveIfNeeded()
|
||||
context.refreshAllObjects()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,11 @@ struct MemosView: View {
|
||||
|
||||
@FetchRequest var memoObjects: FetchedResults<MemoObject>
|
||||
|
||||
@State var memo: MemoObject?
|
||||
@State var query: String = ""
|
||||
@State var currentDate: Date = .now
|
||||
|
||||
@Binding var memo: MemoObject?
|
||||
|
||||
@AppStorage("memola.memo-objects.memos.sort") var sort: Sort = .recent
|
||||
@AppStorage("memola.memo-objects.memos.filter") var filter: Filter = .none
|
||||
|
||||
@@ -25,7 +26,8 @@ struct MemosView: View {
|
||||
query.isEmpty ? .memoEmpty : .memoNotFound
|
||||
}
|
||||
|
||||
init() {
|
||||
init(memo: Binding<MemoObject?>) {
|
||||
_memo = memo
|
||||
let standard = UserDefaults.standard
|
||||
var descriptors: [SortDescriptor<MemoObject>] = []
|
||||
var predicates: [NSPredicate] = [NSPredicate(format: "isTrash = NO")]
|
||||
@@ -115,15 +117,6 @@ struct MemosView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.fullScreenCover(item: $memo) { memo in
|
||||
MemoView(memo: memo)
|
||||
.onDisappear {
|
||||
withPersistence(\.viewContext) { context in
|
||||
try context.saveIfNeeded()
|
||||
context.refreshAllObjects()
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: sort) { oldValue, newValue in
|
||||
memoObjects.sortDescriptors = newValue.memoSortDescriptors
|
||||
}
|
||||
|
||||
@@ -13,18 +13,35 @@ struct TrashView: View {
|
||||
@FetchRequest var memoObjects: FetchedResults<MemoObject>
|
||||
|
||||
@State var query: String = ""
|
||||
@State var restoredMemo: MemoObject?
|
||||
@State var deletedMemo: MemoObject?
|
||||
|
||||
@Binding var memo: MemoObject?
|
||||
@Binding var sidebarItem: SidebarItem?
|
||||
|
||||
var placeholder: Placeholder.Info {
|
||||
query.isEmpty ? .trashEmpty : .trashNotFound
|
||||
}
|
||||
|
||||
init() {
|
||||
init(memo: Binding<MemoObject?>, sidebarItem: Binding<SidebarItem?>) {
|
||||
_memo = memo
|
||||
_sidebarItem = sidebarItem
|
||||
let descriptors = [SortDescriptor(\MemoObject.deletedAt, order: .reverse)]
|
||||
let predicate = NSPredicate(format: "isTrash = YES")
|
||||
_memoObjects = FetchRequest(sortDescriptors: descriptors, predicate: predicate)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
let restoresMemo = Binding<Bool> {
|
||||
restoredMemo != nil
|
||||
} set: { _ in
|
||||
restoredMemo = nil
|
||||
}
|
||||
let deletesMemo = Binding<Bool> {
|
||||
deletedMemo != nil
|
||||
} set: { _ in
|
||||
deletedMemo = nil
|
||||
}
|
||||
MemoGrid(memoObjects: memoObjects, placeholder: placeholder) { memoObject in
|
||||
memoCard(memoObject)
|
||||
}
|
||||
@@ -48,6 +65,31 @@ struct TrashView: View {
|
||||
.onChange(of: query) { oldValue, newValue in
|
||||
updatePredicate()
|
||||
}
|
||||
.alert("Restore Memo", isPresented: restoresMemo) {
|
||||
Button {
|
||||
restoreMemo(for: restoredMemo)
|
||||
} label: {
|
||||
Text("Restore")
|
||||
}
|
||||
Button {
|
||||
restoreAndOpenMemo(for: restoredMemo)
|
||||
} label: {
|
||||
Text("Restore and Open")
|
||||
}
|
||||
Button("Cancel", role: .cancel) { }
|
||||
} message: {
|
||||
Text("Would you like to restore this memo or restore and open it?")
|
||||
}
|
||||
.alert("Delete Memo Permanently", isPresented: deletesMemo) {
|
||||
Button(role: .destructive) {
|
||||
deleteMemo(for: deletedMemo)
|
||||
} label: {
|
||||
Text("Delete")
|
||||
}
|
||||
Button("Cancel", role: .cancel) { }
|
||||
} message: {
|
||||
Text("Are you sure you want to permanently delete this memo? This action cannot be undone.")
|
||||
}
|
||||
}
|
||||
|
||||
func memoCard(_ memoObject: MemoObject) -> some View {
|
||||
@@ -55,23 +97,25 @@ struct TrashView: View {
|
||||
card
|
||||
.contextMenu {
|
||||
Button {
|
||||
|
||||
restoreMemo(for: memoObject)
|
||||
} label: {
|
||||
Label("Restore", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
Button(role: .destructive) {
|
||||
|
||||
deletedMemo = memoObject
|
||||
} label: {
|
||||
Label("Delete Permanently", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
} details: {
|
||||
Text("Deleted on \(memoObject.deletedAt.formatted(date: .abbreviated, time: .standard))")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
if let deletedAt = memoObject.deletedAt {
|
||||
Text("Deleted on \(deletedAt.formatted(date: .abbreviated, time: .standard))")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
|
||||
restoredMemo = memoObject
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,4 +126,27 @@ struct TrashView: View {
|
||||
}
|
||||
memoObjects.nsPredicate = NSCompoundPredicate(type: .and, subpredicates: predicates)
|
||||
}
|
||||
|
||||
func restoreMemo(for memo: MemoObject?) {
|
||||
guard let memo else { return }
|
||||
memo.isTrash = false
|
||||
memo.deletedAt = nil
|
||||
withPersistence(\.viewContext) { context in
|
||||
try context.saveIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
func restoreAndOpenMemo(for memo: MemoObject?) {
|
||||
restoreMemo(for: memo)
|
||||
self.sidebarItem = .memos
|
||||
self.memo = memo
|
||||
}
|
||||
|
||||
func deleteMemo(for memo: MemoObject?) {
|
||||
guard let memo else { return }
|
||||
withPersistenceSync(\.viewContext) { context in
|
||||
context.delete(memo)
|
||||
try context.saveIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ final class MemoObject: NSManagedObject, Identifiable {
|
||||
@NSManaged var title: String
|
||||
@NSManaged var createdAt: Date
|
||||
@NSManaged var updatedAt: Date
|
||||
@NSManaged var deletedAt: Date
|
||||
@NSManaged var deletedAt: Date?
|
||||
@NSManaged var isFavorite: Bool
|
||||
@NSManaged var isTrash: Bool
|
||||
@NSManaged var tool: ToolObject
|
||||
|
||||
Reference in New Issue
Block a user