Fix CopyStrokesAction ID tracking and cache grid bitmap
- CopyStrokesAction: use insertAll return value (List<Long>) to get inserted IDs directly instead of fragile takeLast(n) re-fetch - StrokeDao.insertAll now returns List<Long> - Grid bitmap cached separately from stroke bitmap, redrawn only on zoom/pan/resize changes. Eliminates per-frame grid line rendering during active drawing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ interface StrokeDao {
|
|||||||
suspend fun insert(stroke: Stroke): Long
|
suspend fun insert(stroke: Stroke): Long
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
suspend fun insertAll(strokes: List<Stroke>)
|
suspend fun insertAll(strokes: List<Stroke>): List<Long>
|
||||||
|
|
||||||
@Query("SELECT * FROM strokes WHERE page_id = :pageId ORDER BY stroke_order ASC")
|
@Query("SELECT * FROM strokes WHERE page_id = :pageId ORDER BY stroke_order ASC")
|
||||||
suspend fun getByPageId(pageId: Long): List<Stroke>
|
suspend fun getByPageId(pageId: Long): List<Stroke>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class PageRepository(
|
|||||||
|
|
||||||
suspend fun deleteStrokes(ids: List<Long>) = strokeDao.deleteByIds(ids)
|
suspend fun deleteStrokes(ids: List<Long>) = strokeDao.deleteByIds(ids)
|
||||||
|
|
||||||
suspend fun insertStrokes(strokes: List<Stroke>) = strokeDao.insertAll(strokes)
|
suspend fun insertStrokes(strokes: List<Stroke>): List<Long> = strokeDao.insertAll(strokes)
|
||||||
|
|
||||||
suspend fun getNextStrokeOrder(pageId: Long): Int =
|
suspend fun getNextStrokeOrder(pageId: Long): Int =
|
||||||
(strokeDao.getMaxStrokeOrder(pageId) ?: 0) + 1
|
(strokeDao.getMaxStrokeOrder(pageId) ?: 0) + 1
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
private var backingCanvas: Canvas? = null
|
private var backingCanvas: Canvas? = null
|
||||||
private var bitmapDirty = true
|
private var bitmapDirty = true
|
||||||
|
|
||||||
|
// --- Cached grid bitmap (redrawn only on zoom/pan/resize) ---
|
||||||
|
private var gridBitmap: android.graphics.Bitmap? = null
|
||||||
|
private var gridCanvas: Canvas? = null
|
||||||
|
private var gridDirty = true
|
||||||
|
|
||||||
// --- In-progress stroke ---
|
// --- In-progress stroke ---
|
||||||
private var currentPath: Path? = null
|
private var currentPath: Path? = null
|
||||||
private var currentPaint: Paint? = null
|
private var currentPaint: Paint? = null
|
||||||
@@ -257,6 +262,7 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
super.onSizeChanged(w, h, oldw, oldh)
|
super.onSizeChanged(w, h, oldw, oldh)
|
||||||
rebuildViewMatrix()
|
rebuildViewMatrix()
|
||||||
bitmapDirty = true
|
bitmapDirty = true
|
||||||
|
gridDirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDraw(canvas: Canvas) {
|
override fun onDraw(canvas: Canvas) {
|
||||||
@@ -273,8 +279,9 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw grid in screen space with pixel-snapped positions
|
// Draw cached grid
|
||||||
drawGridScreenSpace(canvas)
|
ensureGrid()
|
||||||
|
gridBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) }
|
||||||
|
|
||||||
// Draw completed strokes from backing bitmap (screen resolution)
|
// Draw completed strokes from backing bitmap (screen resolution)
|
||||||
ensureBacking()
|
ensureBacking()
|
||||||
@@ -376,6 +383,25 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ensureGrid() {
|
||||||
|
val w = width
|
||||||
|
val h = height
|
||||||
|
if (w <= 0 || h <= 0) return
|
||||||
|
|
||||||
|
if (gridBitmap == null || gridBitmap!!.width != w || gridBitmap!!.height != h) {
|
||||||
|
gridBitmap?.recycle()
|
||||||
|
gridBitmap = androidx.core.graphics.createBitmap(w, h)
|
||||||
|
gridCanvas = Canvas(gridBitmap!!)
|
||||||
|
gridDirty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gridDirty) {
|
||||||
|
gridBitmap!!.eraseColor(android.graphics.Color.TRANSPARENT)
|
||||||
|
drawGridScreenSpace(gridCanvas!!)
|
||||||
|
gridDirty = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun drawGridScreenSpace(canvas: Canvas) {
|
private fun drawGridScreenSpace(canvas: Canvas) {
|
||||||
val pageW = canvasState.pageSize.widthPt.toFloat()
|
val pageW = canvasState.pageSize.widthPt.toFloat()
|
||||||
val pageH = canvasState.pageSize.heightPt.toFloat()
|
val pageH = canvasState.pageSize.heightPt.toFloat()
|
||||||
@@ -1024,6 +1050,7 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
|
|
||||||
viewMatrix.invert(inverseMatrix)
|
viewMatrix.invert(inverseMatrix)
|
||||||
bitmapDirty = true
|
bitmapDirty = true
|
||||||
|
gridDirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun screenToCanonical(screenX: Float, screenY: Float): FloatArray {
|
private fun screenToCanonical(screenX: Float, screenY: Float): FloatArray {
|
||||||
|
|||||||
@@ -86,12 +86,10 @@ class CopyStrokesAction(
|
|||||||
createdAt = System.currentTimeMillis(),
|
createdAt = System.currentTimeMillis(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
repository.insertStrokes(copies)
|
val ids = repository.insertStrokes(copies)
|
||||||
// Re-fetch to get assigned IDs
|
insertedIds.addAll(ids)
|
||||||
val allStrokes = repository.getStrokes(pageId)
|
val inserted = copies.zip(ids) { stroke, id -> stroke.copy(id = id) }
|
||||||
val newIds = allStrokes.takeLast(copies.size)
|
onExecute(inserted)
|
||||||
insertedIds.addAll(newIds.map { it.id })
|
|
||||||
onExecute(newIds)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun undo() {
|
override suspend fun undo() {
|
||||||
|
|||||||
Reference in New Issue
Block a user