diff --git a/Memola.xcodeproj/project.pbxproj b/Memola.xcodeproj/project.pbxproj index 384123b..cf282ed 100644 --- a/Memola.xcodeproj/project.pbxproj +++ b/Memola.xcodeproj/project.pbxproj @@ -64,9 +64,13 @@ ECA738F62BE612B700A4542E /* MTLDevice++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738F52BE612B700A4542E /* MTLDevice++.swift */; }; ECA738FC2BE61C5200A4542E /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738FB2BE61C5200A4542E /* Persistence.swift */; }; ECA739012BE61D9C00A4542E /* MemolaModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = ECA738FF2BE61D9C00A4542E /* MemolaModel.xcdatamodeld */; }; - ECA739052BE61E3100A4542E /* Memo.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA739042BE61E3100A4542E /* Memo.swift */; }; ECA739082BE623F300A4542E /* PenToolView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA739072BE623F300A4542E /* PenToolView.swift */; }; ECEC01A82BEE11BA006DA24C /* QuadShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECEC01A72BEE11BA006DA24C /* QuadShape.swift */; }; + ECFA15202BEF21EF00455818 /* MemoObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA151F2BEF21EF00455818 /* MemoObject.swift */; }; + ECFA15222BEF21F500455818 /* CanvasObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15212BEF21F500455818 /* CanvasObject.swift */; }; + ECFA15242BEF223300455818 /* GraphicContextObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15232BEF223300455818 /* GraphicContextObject.swift */; }; + ECFA15262BEF224900455818 /* StrokeObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15252BEF224900455818 /* StrokeObject.swift */; }; + ECFA15282BEF225000455818 /* QuadObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15272BEF225000455818 /* QuadObject.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -128,9 +132,13 @@ ECA738F52BE612B700A4542E /* MTLDevice++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MTLDevice++.swift"; sourceTree = ""; }; ECA738FB2BE61C5200A4542E /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; ECA739002BE61D9C00A4542E /* MemolaModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MemolaModel.xcdatamodel; sourceTree = ""; }; - ECA739042BE61E3100A4542E /* Memo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Memo.swift; sourceTree = ""; }; ECA739072BE623F300A4542E /* PenToolView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenToolView.swift; sourceTree = ""; }; ECEC01A72BEE11BA006DA24C /* QuadShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuadShape.swift; sourceTree = ""; }; + ECFA151F2BEF21EF00455818 /* MemoObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoObject.swift; sourceTree = ""; }; + ECFA15212BEF21F500455818 /* CanvasObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CanvasObject.swift; sourceTree = ""; }; + ECFA15232BEF223300455818 /* GraphicContextObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphicContextObject.swift; sourceTree = ""; }; + ECFA15252BEF224900455818 /* StrokeObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StrokeObject.swift; sourceTree = ""; }; + ECFA15272BEF225000455818 /* QuadObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuadObject.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -226,7 +234,6 @@ ECA7387B2BE5EF3500A4542E /* Memo */ = { isa = PBXGroup; children = ( - ECA739042BE61E3100A4542E /* Memo.swift */, ECA7387C2BE5EF4B00A4542E /* MemoView.swift */, ECA739072BE623F300A4542E /* PenToolView.swift */, ); @@ -453,6 +460,7 @@ ECA738FA2BE61B1700A4542E /* Persistence */ = { isa = PBXGroup; children = ( + ECFA151E2BEF21BE00455818 /* Objects */, ECA739022BE61DE700A4542E /* Core */, ); path = Persistence; @@ -491,6 +499,18 @@ path = Core; sourceTree = ""; }; + ECFA151E2BEF21BE00455818 /* Objects */ = { + isa = PBXGroup; + children = ( + ECFA151F2BEF21EF00455818 /* MemoObject.swift */, + ECFA15212BEF21F500455818 /* CanvasObject.swift */, + ECFA15232BEF223300455818 /* GraphicContextObject.swift */, + ECFA15252BEF224900455818 /* StrokeObject.swift */, + ECFA15272BEF225000455818 /* QuadObject.swift */, + ); + path = Objects; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -569,14 +589,17 @@ ECA7389C2BE601AF00A4542E /* GridVertex.swift in Sources */, ECA738A82BE6025900A4542E /* GraphicUniforms.swift in Sources */, ECA738E62BE611FD00A4542E /* CGRect++.swift in Sources */, + ECFA15262BEF224900455818 /* StrokeObject.swift in Sources */, ECA738E82BE6120F00A4542E /* Color++.swift in Sources */, ECA738FC2BE61C5200A4542E /* Persistence.swift in Sources */, ECA7387A2BE5EF0400A4542E /* MemosView.swift in Sources */, ECA738BA2BE60DEF00A4542E /* HistoryAction.swift in Sources */, + ECFA15222BEF21F500455818 /* CanvasObject.swift in Sources */, ECA738AA2BE6026D00A4542E /* Uniforms.swift in Sources */, ECA7387D2BE5EF4B00A4542E /* MemoView.swift in Sources */, ECA738DA2BE60FF100A4542E /* CacheRenderPass.swift in Sources */, ECA738CD2BE60F2F00A4542E /* GridContext.swift in Sources */, + ECFA15202BEF21EF00455818 /* MemoObject.swift in Sources */, ECA738C62BE60E9D00A4542E /* EraserPenStyle.swift in Sources */, ECA738EA2BE6122E00A4542E /* CGPoint++.swift in Sources */, ECA738A62BE6023F00A4542E /* GridUniforms.swift in Sources */, @@ -594,11 +617,11 @@ ECA738952BE6012D00A4542E /* ViewPort.metal in Sources */, ECA739012BE61D9C00A4542E /* MemolaModel.xcdatamodeld in Sources */, ECA738F02BE6127700A4542E /* CGSize++.swift in Sources */, + ECFA15242BEF223300455818 /* GraphicContextObject.swift in Sources */, ECA738EC2BE6124E00A4542E /* CGAffineTransform++.swift in Sources */, ECA738E22BE610D000A4542E /* GraphicRenderPass.swift in Sources */, ECA738DC2BE6108D00A4542E /* StrokeRenderPass.swift in Sources */, ECA738F42BE612A000A4542E /* Array++.swift in Sources */, - ECA739052BE61E3100A4542E /* Memo.swift in Sources */, EC4538892BEBCAE000A86FEC /* Quad.swift in Sources */, ECA7388F2BE600DA00A4542E /* Grid.metal in Sources */, ECA738C92BE60EF700A4542E /* GraphicContext.swift in Sources */, @@ -607,6 +630,7 @@ ECA738B32BE60D9E00A4542E /* CanvasView.swift in Sources */, ECA738C42BE60E8800A4542E /* MarkerPenStyle.swift in Sources */, ECA738BF2BE60E3400A4542E /* Pen.swift in Sources */, + ECFA15282BEF225000455818 /* QuadObject.swift in Sources */, ECA738932BE6011100A4542E /* Stroke.metal in Sources */, ECA738B62BE60DCD00A4542E /* History.swift in Sources */, ECA738D22BE60F7B00A4542E /* Stroke.swift in Sources */, diff --git a/Memola/Canvas/Contexts/GraphicContext.swift b/Memola/Canvas/Contexts/GraphicContext.swift index 6775eb7..5e5b67a 100644 --- a/Memola/Canvas/Contexts/GraphicContext.swift +++ b/Memola/Canvas/Contexts/GraphicContext.swift @@ -10,11 +10,9 @@ import MetalKit import CoreData import Foundation -@objc(GraphicContext) -final class GraphicContext: NSManagedObject { - @NSManaged var id: UUID - @NSManaged var canvas: Canvas? - @NSManaged var strokes: NSMutableOrderedSet +final class GraphicContext: @unchecked Sendable { + var strokes: [Stroke] = [] + var object: GraphicContextObject? var currentStroke: Stroke? var previousStroke: Stroke? @@ -24,8 +22,7 @@ final class GraphicContext: NSManagedObject { var vertexCount: Int = 4 var vertexBuffer: MTLBuffer? - override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { - super.init(entity: entity, insertInto: context) + init() { setViewPortVertices() } @@ -40,21 +37,37 @@ final class GraphicContext: NSManagedObject { } func undoGraphic() { - guard let stroke = strokes.lastObject as? Stroke else { return } - strokes.remove(stroke) - stroke.graphicContext = nil + guard !strokes.isEmpty else { return } + let stroke = strokes.removeLast() + Persistence.backgroundContext.perform { + stroke.object?.graphicContext = nil + Persistence.saveIfNeededInBackground() + } previousStroke = nil - Persistence.saveIfNeeded() } func redoGraphic(for event: HistoryEvent) { switch event { case .stroke(let stroke): - strokes.add(stroke) - stroke.graphicContext = self + strokes.append(stroke) + Persistence.backgroundContext.perform { [weak self] in + stroke.object?.graphicContext = self?.object + Persistence.saveIfNeededInBackground() + } previousStroke = nil } - Persistence.saveIfNeeded() + } +} + +extension GraphicContext { + func load() { + guard let object else { return } + self.strokes = object.strokes.compactMap { stroke -> Stroke? in + guard let stroke = stroke as? StrokeObject else { return nil } + let _stroke = Stroke(object: stroke) + _stroke.loadVertices() + return _stroke + } } } @@ -76,15 +89,24 @@ extension GraphicContext: Drawable { extension GraphicContext { func beginStroke(at point: CGPoint, pen: Pen) -> Stroke { - let stroke = Stroke(context: Persistence.context) - stroke.id = UUID() - stroke.color = pen.color - stroke.style = pen.strokeStyle.rawValue - stroke.thickness = pen.thickness - stroke.createdAt = .now - stroke.quads = [] - stroke.graphicContext = self - strokes.add(stroke) + let stroke = Stroke( + color: pen.color, + style: pen.strokeStyle.rawValue, + createdAt: .now, + thickness: pen.thickness + ) + Persistence.backgroundContext.perform { [graphicContext = object, _stroke = stroke] in + let stroke = StrokeObject(context: Persistence.backgroundContext) + stroke.color = _stroke.color + stroke.style = _stroke.style + stroke.thickness = _stroke.thickness + stroke.createdAt = _stroke.createdAt + stroke.quads = [] + stroke.graphicContext = graphicContext + graphicContext?.strokes.add(stroke) + _stroke.object = stroke + } + strokes.append(stroke) currentStroke = stroke currentPoint = point currentStroke?.begin(at: point) @@ -101,19 +123,31 @@ extension GraphicContext { func endStroke(at point: CGPoint) { guard currentPoint != nil, let currentStroke else { return } currentStroke.finish(at: point) - Persistence.saveIfNeeded() + let saveIndex = currentStroke.batchIndex + let quads = Array(currentStroke.quads[saveIndex.. 80 @@ -42,16 +44,21 @@ final class Canvas: NSManagedObject, Identifiable { // MARK: - Actions extension Canvas { func load() { - state = .loading - let start = Date().formatted(.dateTime.minute().second().secondFraction(.fractional(5))) - for stroke in graphicContext.strokes { - if let stroke = stroke as? Stroke { - stroke.loadVertices() + Persistence.backgroundContext.perform { [weak self, canvasID] in + DispatchQueue.main.async { [weak self] in + self?.state = .loading + } + guard let canvas = Persistence.backgroundContext.object(with: canvasID) as? CanvasObject else { + return + } + let graphicContext = canvas.graphicContext + self?.graphicContext.object = graphicContext + self?.graphicContext.load() + Persistence.backgroundContext.refresh(canvas, mergeChanges: false) + DispatchQueue.main.async { [weak self] in + self?.state = .loaded } } - let end = Date().formatted(.dateTime.minute().second().secondFraction(.fractional(5))) - NSLog("[Memola] - Loaded from \(start) to \(end)") - state = .loaded } } @@ -104,7 +111,7 @@ extension Canvas { } func getNewlyAddedStroke() -> Stroke? { - graphicContext.strokes.lastObject as? Stroke + graphicContext.strokes.last } } diff --git a/Memola/Canvas/Geometries/Primitives/Quad.swift b/Memola/Canvas/Geometries/Primitives/Quad.swift index f5f5742..029fbb0 100644 --- a/Memola/Canvas/Geometries/Primitives/Quad.swift +++ b/Memola/Canvas/Geometries/Primitives/Quad.swift @@ -8,15 +8,28 @@ import CoreData import Foundation -@objc(Quad) -class Quad: NSManagedObject { - @NSManaged var id: UUID - @NSManaged var originX: CGFloat - @NSManaged var originY: CGFloat - @NSManaged var size: CGFloat - @NSManaged var rotation: CGFloat - @NSManaged var shape: Int16 - @NSManaged var stroke: Stroke? +struct Quad { + var originX: CGFloat + var originY: CGFloat + var size: CGFloat + var rotation: CGFloat + var shape: Int16 + + init(object: QuadObject) { + self.originX = object.originX + self.originY = object.originY + self.size = object.size + self.rotation = object.rotation + self.shape = object.shape + } + + init(origin: CGPoint, size: CGFloat, rotation: CGFloat, shape: Int16) { + self.originX = origin.x + self.originY = origin.y + self.size = size + self.rotation = rotation + self.shape = shape + } var origin: CGPoint { get { CGPoint(x: originX, y: originY) } diff --git a/Memola/Canvas/Geometries/Stroke/Generators/SolidPointStrokeGenerator.swift b/Memola/Canvas/Geometries/Stroke/Generators/SolidPointStrokeGenerator.swift index 30d8c31..94d8e4a 100644 --- a/Memola/Canvas/Geometries/Stroke/Generators/SolidPointStrokeGenerator.swift +++ b/Memola/Canvas/Geometries/Stroke/Generators/SolidPointStrokeGenerator.swift @@ -132,42 +132,15 @@ struct SolidPointStrokeGenerator: StrokeGenerator { } } - #warning("TODO: remove later") - private func addLine(from start: CGPoint, to end: CGPoint, on stroke: Stroke) { - let distance = end.distance(to: start) - let segments = max(distance / stroke.penStyle.anyPenStyle.stepRate, 2) - for i in 0.. Quad { - let quad = Quad(context: Persistence.context) - quad.id = UUID() - quad.origin = point - quad.rotation = rotation - quad.size = thickness - quad.shape = shape.rawValue - quads.add(quad) - quad.stroke = self + let quad = Quad( + origin: point, + size: thickness, + rotation: rotation, + shape: shape.rawValue + ) + quads.append(quad) return quad } + + func removeQuads(from index: Int) { + let dropCount = quads.endIndex - max(1, index) + quads.removeLast(dropCount) + let quads = Array(quads[batchIndex.. Bool { diff --git a/Memola/Features/Memo/Memo.swift b/Memola/Features/Memo/Memo.swift deleted file mode 100644 index 5194b38..0000000 --- a/Memola/Features/Memo/Memo.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// Memo.swift -// Memola -// -// Created by Dscyre Scotti on 5/4/24. -// - -import CoreData -import Foundation - -@objc(Memo) -final class Memo: NSManagedObject { - @NSManaged var id: UUID - @NSManaged var title: String - @NSManaged var data: Data - @NSManaged var createdAt: Date - @NSManaged var updatedAt: Date - @NSManaged var canvas: Canvas -} - -extension Memo: Identifiable { } diff --git a/Memola/Features/Memo/MemoView.swift b/Memola/Features/Memo/MemoView.swift index 0673109..c6e2277 100644 --- a/Memola/Features/Memo/MemoView.swift +++ b/Memola/Features/Memo/MemoView.swift @@ -6,15 +6,22 @@ // import SwiftUI +import CoreData struct MemoView: View { @Environment(\.dismiss) var dismiss @Environment(\.managedObjectContext) var managedObjectContext @StateObject var tool = Tool() + @StateObject var canvas: Canvas @StateObject var history = History() - @EnvironmentObject var canvas: Canvas + let memo: MemoObject + + init(memo: MemoObject) { + self.memo = memo + self._canvas = StateObject(wrappedValue: Canvas(size: memo.canvas.size, canvasID: memo.canvas.objectID)) + } var body: some View { CanvasView() diff --git a/Memola/Features/Memos/MemosView.swift b/Memola/Features/Memos/MemosView.swift index c0972d9..57e70aa 100644 --- a/Memola/Features/Memos/MemosView.swift +++ b/Memola/Features/Memos/MemosView.swift @@ -10,9 +10,9 @@ import SwiftUI struct MemosView: View { @Environment(\.managedObjectContext) var managedObjectContext - @FetchRequest(sortDescriptors: []) var memos: FetchedResults + @FetchRequest(sortDescriptors: []) var memoObjects: FetchedResults - @State var memo: Memo? + @State var memo: MemoObject? var body: some View { NavigationStack { @@ -30,15 +30,14 @@ struct MemosView: View { } } .fullScreenCover(item: $memo) { memo in - MemoView() - .environmentObject(memo.canvas) + MemoView(memo: memo) } } var memoGrid: some View { ScrollView { LazyVGrid(columns: .init(repeating: GridItem(.flexible()), count: 3)) { - ForEach(memos) { memo in + ForEach(memoObjects) { memo in memoCard(memo) } } @@ -46,47 +45,44 @@ struct MemosView: View { } } - func memoCard(_ memo: Memo) -> some View { + func memoCard(_ memoObject: MemoObject) -> some View { VStack(alignment: .leading) { Rectangle() .frame(height: 150) - Text(memo.title) + Text(memoObject.title) } .onTapGesture { - openMemo(for: memo) + openMemo(for: memoObject) } } func createMemo(title: String) { do { - let memo = Memo(context: managedObjectContext) - memo.id = UUID() - memo.title = title - memo.createdAt = .now - memo.updatedAt = .now + let memoObject = MemoObject(context: managedObjectContext) + memoObject.title = title + memoObject.createdAt = .now + memoObject.updatedAt = .now - let canvas = Canvas(context: managedObjectContext) - canvas.id = UUID() - canvas.width = 4_000 - canvas.height = 4_000 + let canvasObject = CanvasObject(context: managedObjectContext) + canvasObject.width = 4_000 + canvasObject.height = 4_000 - let graphicContext = GraphicContext(context: managedObjectContext) - graphicContext.id = UUID() - graphicContext.strokes = [] + let graphicContextObject = GraphicContextObject(context: managedObjectContext) + graphicContextObject.strokes = [] - memo.canvas = canvas - canvas.memo = memo - canvas.graphicContext = graphicContext - graphicContext.canvas = canvas + memoObject.canvas = canvasObject + canvasObject.memo = memoObject + canvasObject.graphicContext = graphicContextObject + graphicContextObject.canvas = canvasObject try managedObjectContext.save() - openMemo(for: memo) + openMemo(for: memoObject) } catch { NSLog("[Memola] - \(error.localizedDescription)") } } - func openMemo(for memo: Memo) { + func openMemo(for memo: MemoObject) { self.memo = memo } } diff --git a/Memola/Persistence/Core/Persistence.swift b/Memola/Persistence/Core/Persistence.swift index 9005f5f..e87f914 100644 --- a/Memola/Persistence/Core/Persistence.swift +++ b/Memola/Persistence/Core/Persistence.swift @@ -21,7 +21,9 @@ class Persistence { static var backgroundContext: NSManagedObjectContext = { let context = shared.persistentContainer.newBackgroundContext() - context.automaticallyMergesChangesFromParent = true + context.undoManager = nil + +// context.automaticallyMergesC hangesFromParent = true return context }() @@ -87,4 +89,24 @@ class Persistence { } } } + + static func saveIfNeededInBackground() { + if backgroundContext.hasChanges { + do { + try backgroundContext.save() + } catch { + NSLog("[Memola] - \(error.localizedDescription)") + } + } + } +} + +extension Persistence { + static func background(_ task: @escaping (NSManagedObjectContext) async throws -> Void, errorHandler: ((Error) async -> Void)? = nil) async { + do { + try await task(backgroundContext) + } catch { + await errorHandler?(error) + } + } } diff --git a/Memola/Persistence/Objects/CanvasObject.swift b/Memola/Persistence/Objects/CanvasObject.swift new file mode 100644 index 0000000..6204db1 --- /dev/null +++ b/Memola/Persistence/Objects/CanvasObject.swift @@ -0,0 +1,22 @@ +// +// CanvasObject.swift +// Memola +// +// Created by Dscyre Scotti on 5/11/24. +// + +import CoreData +import Foundation + + +@objc(CanvasObject) +final class CanvasObject: NSManagedObject { + @NSManaged var width: CGFloat + @NSManaged var height: CGFloat + @NSManaged var memo: MemoObject? + @NSManaged var graphicContext: GraphicContextObject + + var size: CGSize { + CGSize(width: width, height: height) + } +} diff --git a/Memola/Persistence/Objects/GraphicContextObject.swift b/Memola/Persistence/Objects/GraphicContextObject.swift new file mode 100644 index 0000000..f62a765 --- /dev/null +++ b/Memola/Persistence/Objects/GraphicContextObject.swift @@ -0,0 +1,15 @@ +// +// GraphicContextObject.swift +// Memola +// +// Created by Dscyre Scotti on 5/11/24. +// + +import CoreData +import Foundation + +@objc(GraphicContextObject) +final class GraphicContextObject: NSManagedObject { + @NSManaged var canvas: CanvasObject? + @NSManaged var strokes: NSMutableOrderedSet +} diff --git a/Memola/Persistence/Objects/MemoObject.swift b/Memola/Persistence/Objects/MemoObject.swift new file mode 100644 index 0000000..d3a6b61 --- /dev/null +++ b/Memola/Persistence/Objects/MemoObject.swift @@ -0,0 +1,18 @@ +// +// MemoObject.swift +// Memola +// +// Created by Dscyre Scotti on 5/11/24. +// + +import CoreData +import Foundation + +@objc(MemoObject) +final class MemoObject: NSManagedObject, Identifiable { + @NSManaged var title: String + @NSManaged var data: Data + @NSManaged var createdAt: Date + @NSManaged var updatedAt: Date + @NSManaged var canvas: CanvasObject +} diff --git a/Memola/Persistence/Objects/QuadObject.swift b/Memola/Persistence/Objects/QuadObject.swift new file mode 100644 index 0000000..f1c051f --- /dev/null +++ b/Memola/Persistence/Objects/QuadObject.swift @@ -0,0 +1,19 @@ +// +// QuadObject.swift +// Memola +// +// Created by Dscyre Scotti on 5/11/24. +// + +import CoreData +import Foundation + +@objc(QuadObject) +final class QuadObject: NSManagedObject { + @NSManaged var originX: CGFloat + @NSManaged var originY: CGFloat + @NSManaged var size: CGFloat + @NSManaged var rotation: CGFloat + @NSManaged var shape: Int16 + @NSManaged var stroke: StrokeObject? +} diff --git a/Memola/Persistence/Objects/StrokeObject.swift b/Memola/Persistence/Objects/StrokeObject.swift new file mode 100644 index 0000000..ffa049b --- /dev/null +++ b/Memola/Persistence/Objects/StrokeObject.swift @@ -0,0 +1,19 @@ +// +// StrokeObject.swift +// Memola +// +// Created by Dscyre Scotti on 5/11/24. +// + +import CoreData +import Foundation + +@objc(StrokeObject) +final class StrokeObject: NSManagedObject { + @NSManaged var color: [CGFloat] + @NSManaged var style: Int16 + @NSManaged var createdAt: Date + @NSManaged var thickness: CGFloat + @NSManaged var quads: NSMutableOrderedSet + @NSManaged var graphicContext: GraphicContextObject? +} diff --git a/Memola/Resources/Models/MemolaModel.xcdatamodeld/MemolaModel.xcdatamodel/contents b/Memola/Resources/Models/MemolaModel.xcdatamodeld/MemolaModel.xcdatamodel/contents index 2d521cc..095d1d2 100644 --- a/Memola/Resources/Models/MemolaModel.xcdatamodeld/MemolaModel.xcdatamodel/contents +++ b/Memola/Resources/Models/MemolaModel.xcdatamodeld/MemolaModel.xcdatamodel/contents @@ -1,40 +1,35 @@ - + - - - + + - - - - + + + - + - - + - - + - + - + - - - + + \ No newline at end of file