bug: fix stroke glitching

This commit is contained in:
dscyrescotti
2024-05-22 21:37:55 +07:00
parent e1d911f2e1
commit c2b39ba358
5 changed files with 75 additions and 20 deletions

View File

@@ -13,6 +13,11 @@ struct MemolaApp: App {
WindowGroup { WindowGroup {
MemosView() MemosView()
.persistence(\.viewContext) .persistence(\.viewContext)
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willTerminateNotification)) { _ in
withPersistenceSync(\.backgroundContext) { context in
try context.saveIfNeeded()
}
}
} }
} }
} }

View File

@@ -153,8 +153,10 @@ extension GraphicContext {
func endStroke(at point: CGPoint) { func endStroke(at point: CGPoint) {
guard currentPoint != nil, let currentStroke else { return } guard currentPoint != nil, let currentStroke else { return }
currentStroke.finish(at: point) currentStroke.finish(at: point)
withPersistence(\.backgroundContext) { [currentStroke] context in let batchIndex = currentStroke.batchIndex
currentStroke.object?.bounds = currentStroke.bounds let quads = Array(currentStroke.quads[batchIndex..<currentStroke.quads.count])
currentStroke.saveQuads(for: quads)
withPersistence(\.backgroundContext) { context in
try context.saveIfNeeded() try context.saveIfNeeded()
if let stroke = currentStroke.object { if let stroke = currentStroke.object {
context.refresh(stroke, mergeChanges: false) context.refresh(stroke, mergeChanges: false)

View File

@@ -29,6 +29,7 @@ struct SolidPointStrokeGenerator: StrokeGenerator {
let control = CGPoint.middle(p1: start, p2: end) let control = CGPoint.middle(p1: start, p2: end)
addCurve(from: start, to: end, by: control, on: stroke) addCurve(from: start, to: end, by: control, on: stroke)
case 3: case 3:
stroke.removeQuads(from: stroke.quadIndex + 1)
let index = stroke.keyPoints.endIndex - 1 let index = stroke.keyPoints.endIndex - 1
var start = stroke.keyPoints[index - 2] var start = stroke.keyPoints[index - 2]
var end = CGPoint.middle(p1: stroke.keyPoints[index - 2], p2: stroke.keyPoints[index - 1]) var end = CGPoint.middle(p1: stroke.keyPoints[index - 2], p2: stroke.keyPoints[index - 1])
@@ -39,7 +40,7 @@ struct SolidPointStrokeGenerator: StrokeGenerator {
end = CGPoint.middle(p1: stroke.keyPoints[index - 1], p2: stroke.keyPoints[index]) end = CGPoint.middle(p1: stroke.keyPoints[index - 1], p2: stroke.keyPoints[index])
addCurve(from: start, to: end, by: control, on: stroke) addCurve(from: start, to: end, by: control, on: stroke)
default: default:
adjustKeyPoint(on: stroke) smoothOutPath(on: stroke)
let index = stroke.keyPoints.endIndex - 1 let index = stroke.keyPoints.endIndex - 1
let start = CGPoint.middle(p1: stroke.keyPoints[index - 2], p2: stroke.keyPoints[index - 1]) let start = CGPoint.middle(p1: stroke.keyPoints[index - 2], p2: stroke.keyPoints[index - 1])
let control = stroke.keyPoints[index - 1] let control = stroke.keyPoints[index - 1]
@@ -57,6 +58,27 @@ struct SolidPointStrokeGenerator: StrokeGenerator {
} }
} }
private func smoothOutPath(on stroke: Stroke) {
stroke.removeQuads(from: stroke.quadIndex + 1)
adjustKeyPoint(on: stroke)
switch stroke.keyPoints.endIndex {
case 4:
let index = stroke.keyPoints.endIndex - 2
let start = stroke.keyPoints[index - 2]
let end = CGPoint.middle(p1: stroke.keyPoints[index - 2], p2: stroke.keyPoints[index - 1])
let control = CGPoint.middle(p1: start, p2: end)
addCurve(from: start, to: end, by: control, on: stroke)
fallthrough
default:
let index = stroke.keyPoints.endIndex - 2
let start = CGPoint.middle(p1: stroke.keyPoints[index - 2], p2: stroke.keyPoints[index - 1])
let control = stroke.keyPoints[index - 1]
let end = CGPoint.middle(p1: stroke.keyPoints[index - 1], p2: stroke.keyPoints[index])
addCurve(from: start, to: end, by: control, on: stroke)
}
stroke.quadIndex = stroke.quads.endIndex - 1
}
private func adjustKeyPoint(on stroke: Stroke) { private func adjustKeyPoint(on stroke: Stroke) {
let index = stroke.keyPoints.endIndex - 1 let index = stroke.keyPoints.endIndex - 1
let prev = stroke.keyPoints[index - 1] let prev = stroke.keyPoints[index - 1]

View File

@@ -116,20 +116,38 @@ extension Stroke {
color: color color: color
) )
quads.append(quad) quads.append(quad)
withPersistence(\.backgroundContext) { [weak self, _quad = quad, object, bounds] context in }
let quad = QuadObject(\.backgroundContext)
quad.originX = _quad.originX.cgFloat func removeQuads(from index: Int) {
quad.originY = _quad.originY.cgFloat let dropCount = quads.endIndex - max(1, index)
quad.size = _quad.size.cgFloat quads.removeLast(dropCount)
quad.rotation = _quad.rotation.cgFloat let quads = Array(quads[batchIndex..<index])
quad.shape = _quad.shape batchIndex = index
quad.color = _quad.getColor() saveQuads(for: quads)
quad.stroke = object }
object?.quads.add(quad)
self?.bounds[0] = min(_quad.originX.cgFloat, bounds[0]) func saveQuads(for quads: [Quad]) {
self?.bounds[1] = min(_quad.originY.cgFloat, bounds[1]) var topLeft: CGPoint = CGPoint(x: bounds[0], y: bounds[1])
self?.bounds[2] = max(_quad.originX.cgFloat, bounds[2]) var bottomRight: CGPoint = CGPoint(x: bounds[2], y: bounds[3])
self?.bounds[3] = max(_quad.originY.cgFloat, bounds[3]) withPersistence(\.backgroundContext) { [weak self, object] context in
guard let self else { return }
for _quad in quads {
let quad = QuadObject(\.backgroundContext)
quad.originX = _quad.originX.cgFloat
quad.originY = _quad.originY.cgFloat
quad.size = _quad.size.cgFloat
quad.rotation = _quad.rotation.cgFloat
quad.shape = _quad.shape
quad.color = _quad.getColor()
quad.stroke = object
object?.quads.add(quad)
topLeft.x = min(quad.originX, topLeft.x)
topLeft.y = min(quad.originY, topLeft.y)
bottomRight.x = max(quad.originX, bottomRight.x)
bottomRight.y = max(quad.originY, bottomRight.y)
}
bounds = [topLeft.x, topLeft.y, bottomRight.x, bottomRight.y]
object?.bounds = bounds
} }
} }
} }

View File

@@ -128,9 +128,17 @@ struct Toolbar: View {
} }
func closeMemo() { func closeMemo() {
withPersistenceSync(\.viewContext) { context in DispatchQueue.global(qos: .userInitiated).async {
try context.saveIfNeeded() DispatchQueue.main.async {
canvas.state = .closing
}
withPersistenceSync(\.viewContext) { context in
try context.saveIfNeeded()
}
DispatchQueue.main.async {
canvas.state = .closed
dismiss()
}
} }
dismiss()
} }
} }