feat: add soft delete action

This commit is contained in:
dscyrescotti
2024-06-27 22:47:34 +07:00
parent 657fb3bf07
commit 12fd0cd942
3 changed files with 33 additions and 7 deletions

View File

@@ -27,13 +27,14 @@ struct MemosView: View {
init() { init() {
let standard = UserDefaults.standard let standard = UserDefaults.standard
var descriptors: [SortDescriptor<MemoObject>] = [] var descriptors: [SortDescriptor<MemoObject>] = []
var predicate: NSPredicate? var predicates: [NSPredicate] = [NSPredicate(format: "isTrash = NO")]
let sort = Sort(rawValue: standard.value(forKey: "memola.memo-objects.sort") as? String ?? "") ?? .recent let sort = Sort(rawValue: standard.value(forKey: "memola.memo-objects.sort") as? String ?? "") ?? .recent
let filter = Filter(rawValue: standard.value(forKey: "memola.memo-objects.filter") as? String ?? "") ?? .none let filter = Filter(rawValue: standard.value(forKey: "memola.memo-objects.filter") as? String ?? "") ?? .none
if filter == .favorites { if filter == .favorites {
predicate = NSPredicate(format: "isFavorite = YES") predicates.append(NSPredicate(format: "isFavorite = YES"))
} }
descriptors = sort.memoSortDescriptors descriptors = sort.memoSortDescriptors
let predicate = NSCompoundPredicate(type: .and, subpredicates: predicates)
_memoObjects = FetchRequest(sortDescriptors: descriptors, predicate: predicate) _memoObjects = FetchRequest(sortDescriptors: descriptors, predicate: predicate)
} }
@@ -156,6 +157,18 @@ struct MemosView: View {
Rectangle() Rectangle()
.frame(height: cellHeight) .frame(height: cellHeight)
.clipShape(RoundedRectangle(cornerRadius: 10)) .clipShape(RoundedRectangle(cornerRadius: 10))
.contextMenu {
Button {
openMemo(for: memoObject)
} label: {
Label("Open", systemImage: "doc.text")
}
Button(role: .destructive) {
markAsTrash(for: memoObject)
} label: {
Label("Delete", systemImage: "trash")
}
}
.overlay(alignment: .topTrailing) { .overlay(alignment: .topTrailing) {
Image(systemName: memoObject.isFavorite ? "star.fill" : "star") Image(systemName: memoObject.isFavorite ? "star.fill" : "star")
.foregroundStyle(memoObject.isFavorite ? .yellow : .white) .foregroundStyle(memoObject.isFavorite ? .yellow : .white)
@@ -165,10 +178,7 @@ struct MemosView: View {
.cornerRadius(5) .cornerRadius(5)
.contentShape(Rectangle()) .contentShape(Rectangle())
.onTapGesture { .onTapGesture {
memoObject.isFavorite.toggle() toggleFavorite(for: memoObject)
withPersistence(\.viewContext) { context in
try context.saveIfNeeded()
}
} }
.contentTransition(.symbolEffect(.replace)) .contentTransition(.symbolEffect(.replace))
.padding(5) .padding(5)
@@ -243,7 +253,7 @@ struct MemosView: View {
} }
func updatePredicate() { func updatePredicate() {
var predicates: [NSPredicate] = [] var predicates: [NSPredicate] = [NSPredicate(format: "isTrash = NO")]
if !query.isEmpty { if !query.isEmpty {
predicates.append(NSPredicate(format: "title contains[c] %@", query)) predicates.append(NSPredicate(format: "title contains[c] %@", query))
} }
@@ -252,4 +262,18 @@ struct MemosView: View {
} }
memoObjects.nsPredicate = NSCompoundPredicate(type: .and, subpredicates: predicates) memoObjects.nsPredicate = NSCompoundPredicate(type: .and, subpredicates: predicates)
} }
func toggleFavorite(for memo: MemoObject) {
memo.isFavorite.toggle()
withPersistence(\.viewContext) { context in
try context.saveIfNeeded()
}
}
func markAsTrash(for memo: MemoObject) {
memo.isTrash = true
withPersistence(\.viewContext) { context in
try context.saveIfNeeded()
}
}
} }

View File

@@ -15,6 +15,7 @@ final class MemoObject: NSManagedObject, Identifiable {
@NSManaged var createdAt: Date @NSManaged var createdAt: Date
@NSManaged var updatedAt: Date @NSManaged var updatedAt: Date
@NSManaged var isFavorite: Bool @NSManaged var isFavorite: Bool
@NSManaged var isTrash: Bool
@NSManaged var tool: ToolObject @NSManaged var tool: ToolObject
@NSManaged var canvas: CanvasObject @NSManaged var canvas: CanvasObject
} }

View File

@@ -30,6 +30,7 @@
<entity name="MemoObject" representedClassName="MemoObject" syncable="YES"> <entity name="MemoObject" representedClassName="MemoObject" syncable="YES">
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/> <attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="isFavorite" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/> <attribute name="isFavorite" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="isTrash" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="title" attributeType="String"/> <attribute name="title" attributeType="String"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/> <attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="canvas" maxCount="1" deletionRule="Cascade" destinationEntity="CanvasObject" inverseName="memo" inverseEntity="CanvasObject"/> <relationship name="canvas" maxCount="1" deletionRule="Cascade" destinationEntity="CanvasObject" inverseName="memo" inverseEntity="CanvasObject"/>