Feature/highlighter snap (#48)
* perf: fix Home and Library screen stutter by removing main thread file checks * feat(pdf): implement straight-line highlighter snap - Added "Straight Line" toggle to highlighter settings popup with persistent state. - Implemented "rubber-band" drawing effect for highlighters with cardinal direction snapping (0°, 90°, 180°, 270°). - Optimized gesture loops in Vertical and Paginated readers to respond instantly to setting toggles. - Rewrote eraser hit detection using point-to-line segment distance math for pixel-perfect erasure of straight lines.
This commit is contained in:
parent
6ea414c9b2
commit
8c7c8cb48e
8 changed files with 203 additions and 61 deletions
|
|
@ -417,7 +417,8 @@ internal fun PdfPageComposable(
|
|||
draggingBoxId: String? = null,
|
||||
isScrollLocked: Boolean = false,
|
||||
isVisible: Boolean = true,
|
||||
isStylusOnlyMode: Boolean = false
|
||||
isStylusOnlyMode: Boolean = false,
|
||||
isHighlighterSnapEnabled: Boolean = false
|
||||
) {
|
||||
SideEffect { Timber.tag("PdfDrawPerf").v("PdfPageComposable Recompose: Page $pageIndex") }
|
||||
val pdfDocumentItem = pdfDocument.item
|
||||
|
|
@ -2608,7 +2609,8 @@ internal fun PdfPageComposable(
|
|||
isScrolling,
|
||||
isVerticalScroll,
|
||||
selectedTool,
|
||||
isStylusOnlyMode
|
||||
isStylusOnlyMode,
|
||||
isHighlighterSnapEnabled
|
||||
) {
|
||||
val canDraw = isEditMode && selectedTool != InkType.TEXT && !isScrolling && !isVerticalScroll && actualBitmapWidthPx > 0 && actualBitmapHeightPx > 0
|
||||
|
||||
|
|
@ -4611,6 +4613,16 @@ class PdfDrawingState {
|
|||
currentPoints.clear()
|
||||
return finalAnnot
|
||||
}
|
||||
|
||||
fun updateDrag(point: PdfPoint) {
|
||||
if (currentPoints.isNotEmpty()) {
|
||||
val start = currentPoints.first()
|
||||
currentPoints.clear()
|
||||
currentPoints.add(start)
|
||||
currentPoints.add(point)
|
||||
currentAnnotation = currentAnnotation?.copy(points = currentPoints.toList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -222,7 +222,8 @@ internal fun PdfVerticalReader(
|
|||
isScrollLocked: Boolean = false,
|
||||
autoScrollSpeed: Float = 1.0f,
|
||||
onInteractionListener: () -> Unit = {},
|
||||
isStylusOnlyMode: Boolean = false
|
||||
isStylusOnlyMode: Boolean = false,
|
||||
isHighlighterSnapEnabled: Boolean = false
|
||||
) {
|
||||
SideEffect { Timber.tag("PdfDrawPerf").v("LIST: PdfVerticalReader Recomposing.") }
|
||||
var globalEraserPosition by remember { mutableStateOf<Offset?>(null) }
|
||||
|
|
@ -748,7 +749,13 @@ internal fun PdfVerticalReader(
|
|||
}
|
||||
}
|
||||
|
||||
val globalDrawingModifier = Modifier.pointerInput(isEditMode, layoutInfo, selectedTool, isStylusOnlyMode) {
|
||||
val globalDrawingModifier = Modifier.pointerInput(
|
||||
isEditMode,
|
||||
layoutInfo,
|
||||
selectedTool,
|
||||
isStylusOnlyMode,
|
||||
isHighlighterSnapEnabled
|
||||
) {
|
||||
if (!isEditMode) return@pointerInput
|
||||
if (selectedTool == InkType.TEXT) return@pointerInput
|
||||
|
||||
|
|
@ -864,7 +871,14 @@ internal fun PdfVerticalReader(
|
|||
onDoubleTapToZoom(offset)
|
||||
})
|
||||
}
|
||||
.pointerInput(totalDocHeight, isEditMode, selectedTool, isScrollLocked, isStylusOnlyMode) {
|
||||
.pointerInput(
|
||||
totalDocHeight,
|
||||
isEditMode,
|
||||
selectedTool,
|
||||
isScrollLocked,
|
||||
isStylusOnlyMode,
|
||||
isHighlighterSnapEnabled
|
||||
) {
|
||||
val tracker = VelocityTracker()
|
||||
val decay = exponentialDecay<Float>()
|
||||
val touchSlop = viewConfiguration.touchSlop
|
||||
|
|
|
|||
|
|
@ -89,7 +89,6 @@ import androidx.compose.foundation.text.BasicTextField
|
|||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.filled.MenuBook
|
||||
import androidx.compose.material.icons.filled.ArrowDownward
|
||||
import androidx.compose.material.icons.filled.ArrowUpward
|
||||
import androidx.compose.material.icons.filled.Brush
|
||||
|
|
@ -981,6 +980,8 @@ fun PdfViewerScreen(
|
|||
|
||||
var showToolSettings by remember { mutableStateOf(false) }
|
||||
|
||||
val isHighlighterSnapEnabled = toolSettings.isHighlighterSnapEnabled
|
||||
|
||||
val selectedTool = toolSettings.getActiveTool()
|
||||
|
||||
val lastPenTool = toolSettings.getLastPenTool()
|
||||
|
|
@ -999,6 +1000,9 @@ fun PdfViewerScreen(
|
|||
val isCurrentToolHighlighter =
|
||||
selectedTool == InkType.HIGHLIGHTER || selectedTool == InkType.HIGHLIGHTER_ROUND
|
||||
|
||||
val currentSnapEnabled by rememberUpdatedState(isHighlighterSnapEnabled)
|
||||
val currentIsHighlighter by rememberUpdatedState(isCurrentToolHighlighter)
|
||||
|
||||
val penPalette = remember(toolSettings.penPaletteArgb) { toolSettings.getPenPalette() }
|
||||
val highlighterPalette =
|
||||
remember(toolSettings.highlighterPaletteArgb) { toolSettings.getHighlighterPalette() }
|
||||
|
|
@ -1272,6 +1276,36 @@ fun PdfViewerScreen(
|
|||
}
|
||||
}
|
||||
|
||||
val calculateSnappedPoint = remember(pageAspectRatios) {
|
||||
{ pageIndex: Int, currentPoint: PdfPoint, startPoint: PdfPoint? ->
|
||||
if (startPoint == null) {
|
||||
currentPoint
|
||||
} else {
|
||||
val aspectRatio = pageAspectRatios.getOrElse(pageIndex) { 1f }
|
||||
|
||||
val dx = (currentPoint.x - startPoint.x) * aspectRatio
|
||||
val dy = (currentPoint.y - startPoint.y)
|
||||
|
||||
val angleRad = kotlin.math.atan2(dy, dx)
|
||||
val angleDeg = (angleRad * 180 / kotlin.math.PI)
|
||||
val absAngle = kotlin.math.abs(angleDeg)
|
||||
|
||||
val threshold = 10.0
|
||||
|
||||
val isHorizontal = absAngle < threshold || kotlin.math.abs(absAngle - 180.0) < threshold
|
||||
val isVertical = kotlin.math.abs(absAngle - 90.0) < threshold
|
||||
|
||||
if (isHorizontal) {
|
||||
currentPoint.copy(y = startPoint.y)
|
||||
} else if (isVertical) {
|
||||
currentPoint.copy(x = startPoint.x)
|
||||
} else {
|
||||
currentPoint
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val onDeletePage: () -> Unit = {
|
||||
coroutineScope.launch {
|
||||
if (currentBookId != null && currentPage in virtualPages.indices) {
|
||||
|
|
@ -2095,13 +2129,42 @@ fun PdfViewerScreen(
|
|||
}
|
||||
|
||||
fun isAnnotationHit(
|
||||
annotation: PdfAnnotation, hitPoint: PdfPoint, threshold: Float = 0.05f
|
||||
annotation: PdfAnnotation,
|
||||
hitPoint: PdfPoint,
|
||||
pageAspectRatio: Float,
|
||||
threshold: Float = 0.025f
|
||||
): Boolean {
|
||||
return annotation.points.any { p ->
|
||||
val dx = p.x - hitPoint.x
|
||||
val dy = p.y - hitPoint.y
|
||||
(dx * dx + dy * dy) < (threshold * threshold)
|
||||
if (annotation.points.isEmpty()) return false
|
||||
|
||||
if (annotation.points.size == 1) {
|
||||
val p = annotation.points[0]
|
||||
val dx = (p.x - hitPoint.x) * pageAspectRatio
|
||||
val dy = (p.y - hitPoint.y)
|
||||
return (dx * dx + dy * dy) < (threshold * threshold)
|
||||
}
|
||||
|
||||
for (i in 0 until annotation.points.size - 1) {
|
||||
val a = annotation.points[i]
|
||||
val b = annotation.points[i + 1]
|
||||
|
||||
val pax = (hitPoint.x - a.x) * pageAspectRatio
|
||||
val pay = (hitPoint.y - a.y)
|
||||
val bax = (b.x - a.x) * pageAspectRatio
|
||||
val bay = (b.y - a.y)
|
||||
|
||||
val segmentLenSq = (bax * bax + bay * bay).coerceAtLeast(1e-6f)
|
||||
val t = (pax * bax + pay * bay) / segmentLenSq
|
||||
val tClamped = t.coerceIn(0f, 1f)
|
||||
|
||||
val closestX = bax * tClamped
|
||||
val closestY = bay * tClamped
|
||||
|
||||
val distSq = (pax - closestX) * (pax - closestX) + (pay - closestY) * (pay - closestY)
|
||||
|
||||
if (distSq < (threshold * threshold)) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun startTts(pageToReadOverride: Int? = null) {
|
||||
|
|
@ -3407,10 +3470,10 @@ fun PdfViewerScreen(
|
|||
{ point: PdfPoint ->
|
||||
if (currentSelectedTool == InkType.TEXT) {
|
||||
} else if (currentSelectedTool == InkType.ERASER) {
|
||||
val existing =
|
||||
allAnnotations[pageIndex] ?: emptyList()
|
||||
val aspectRatio = pageAspectRatios.getOrElse(pageIndex) { 1f }
|
||||
val existing = allAnnotations[pageIndex] ?: emptyList()
|
||||
val toRemove = existing.filter {
|
||||
isAnnotationHit(it, point)
|
||||
isAnnotationHit(it, point, aspectRatio)
|
||||
}
|
||||
if (toRemove.isNotEmpty()) {
|
||||
val batch =
|
||||
|
|
@ -3427,10 +3490,13 @@ fun PdfViewerScreen(
|
|||
allAnnotations + (pageIndex to newList)
|
||||
}
|
||||
} else {
|
||||
val pointWithTime = point.copy(
|
||||
timestamp = System.currentTimeMillis()
|
||||
)
|
||||
drawingState.onDraw(pointWithTime)
|
||||
if (currentIsHighlighter && currentSnapEnabled) {
|
||||
val startPoint = drawingState.currentAnnotation?.points?.firstOrNull()
|
||||
val effectivePoint = calculateSnappedPoint(pageIndex, point, startPoint)
|
||||
drawingState.updateDrag(effectivePoint.copy(timestamp = System.currentTimeMillis()))
|
||||
} else {
|
||||
drawingState.onDraw(point.copy(timestamp = System.currentTimeMillis()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3451,13 +3517,10 @@ fun PdfViewerScreen(
|
|||
if (currentSelectedTool == InkType.TEXT) {
|
||||
} else if (currentSelectedTool == InkType.ERASER) {
|
||||
erasedAnnotationsFromStroke.clear()
|
||||
|
||||
val existing = allAnnotations[pageIndex]
|
||||
?: emptyList()
|
||||
val aspectRatio = pageAspectRatios.getOrElse(pageIndex) { 1f }
|
||||
val existing = allAnnotations[pageIndex] ?: emptyList()
|
||||
val toRemove = existing.filter {
|
||||
isAnnotationHit(
|
||||
it, point
|
||||
)
|
||||
isAnnotationHit(it, point, aspectRatio)
|
||||
}
|
||||
if (toRemove.isNotEmpty()) {
|
||||
val batch =
|
||||
|
|
@ -3581,6 +3644,7 @@ fun PdfViewerScreen(
|
|||
},
|
||||
richTextController = richTextController,
|
||||
isStylusOnlyMode = isStylusOnlyMode,
|
||||
isHighlighterSnapEnabled = isHighlighterSnapEnabled,
|
||||
isEditMode = isDrawingActive,
|
||||
textBoxes = textBoxes.filter { it.pageIndex == pageIndex },
|
||||
selectedTextBoxId = selectedTextBoxId,
|
||||
|
|
@ -3791,10 +3855,10 @@ fun PdfViewerScreen(
|
|||
} else if (currentSelectedTool == InkType.ERASER) {
|
||||
erasedAnnotationsFromStroke.clear()
|
||||
|
||||
val existing =
|
||||
allAnnotations[pageIndex] ?: emptyList()
|
||||
val aspectRatio = pageAspectRatios.getOrElse(pageIndex) { 1f }
|
||||
val existing = allAnnotations[pageIndex] ?: emptyList()
|
||||
val toRemove = existing.filter {
|
||||
isAnnotationHit(it, point)
|
||||
isAnnotationHit(it, point, aspectRatio)
|
||||
}
|
||||
if (toRemove.isNotEmpty()) {
|
||||
val batch =
|
||||
|
|
@ -3826,13 +3890,13 @@ fun PdfViewerScreen(
|
|||
}
|
||||
}
|
||||
|
||||
val onDrawStable = remember {
|
||||
val onDrawStable = remember(isHighlighterSnapEnabled, isCurrentToolHighlighter, calculateSnappedPoint) {
|
||||
{ pageIndex: Int, point: PdfPoint ->
|
||||
if (currentSelectedTool == InkType.ERASER) {
|
||||
val existing =
|
||||
allAnnotations[pageIndex] ?: emptyList()
|
||||
val aspectRatio = pageAspectRatios.getOrElse(pageIndex) { 1f }
|
||||
val existing = allAnnotations[pageIndex] ?: emptyList()
|
||||
val toRemove = existing.filter {
|
||||
isAnnotationHit(it, point)
|
||||
isAnnotationHit(it, point, aspectRatio)
|
||||
}
|
||||
if (toRemove.isNotEmpty()) {
|
||||
val batch =
|
||||
|
|
@ -3846,10 +3910,13 @@ fun PdfViewerScreen(
|
|||
allAnnotations + (pageIndex to newList)
|
||||
}
|
||||
} else {
|
||||
val pointWithTime = point.copy(
|
||||
timestamp = System.currentTimeMillis()
|
||||
)
|
||||
drawingState.onDraw(pointWithTime)
|
||||
if (currentIsHighlighter && currentSnapEnabled) {
|
||||
val startPoint = drawingState.currentAnnotation?.points?.firstOrNull()
|
||||
val effectivePoint = calculateSnappedPoint(pageIndex, point, startPoint)
|
||||
drawingState.updateDrag(effectivePoint.copy(timestamp = System.currentTimeMillis()))
|
||||
} else {
|
||||
drawingState.onDraw(point.copy(timestamp = System.currentTimeMillis()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3898,6 +3965,7 @@ fun PdfViewerScreen(
|
|||
allAnnotations = allAnnotationsProvider,
|
||||
drawingState = drawingState,
|
||||
onDrawStart = onDrawStartStable,
|
||||
isHighlighterSnapEnabled = isHighlighterSnapEnabled,
|
||||
onDraw = onDrawStable,
|
||||
onDrawEnd = {
|
||||
val finalAnnotation = drawingState.onDrawEnd()
|
||||
|
|
@ -5198,7 +5266,10 @@ fun PdfViewerScreen(
|
|||
} else {
|
||||
annotationSettingsRepo.updatePenPalette(newPalette)
|
||||
}
|
||||
})
|
||||
},
|
||||
isHighlighterSnapEnabled = isHighlighterSnapEnabled,
|
||||
onSnapToggle = { annotationSettingsRepo.updateHighlighterSnap(it) }
|
||||
)
|
||||
}
|
||||
|
||||
snapPreviewLocation?.let { location ->
|
||||
|
|
@ -5357,7 +5428,7 @@ fun PdfViewerScreen(
|
|||
saveStylusOnlyMode(context, isStylusOnlyMode)
|
||||
},
|
||||
onToolClick = { clickedTool ->
|
||||
if (clickedTool == InkType.ERASER) {
|
||||
if (clickedTool == InkType.ERASER || clickedTool == InkType.TEXT) {
|
||||
annotationSettingsRepo.updateSelectedTool(
|
||||
clickedTool
|
||||
)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ fun PenIcon(
|
|||
isSelected: Boolean = false,
|
||||
strokeWidth: Float = 0.005f,
|
||||
forcedInkType: InkType? = null,
|
||||
inkColor: Color? = null
|
||||
inkColor: Color? = null,
|
||||
isSnappingEnabled: Boolean = false
|
||||
) {
|
||||
val animatedColor by animateColorAsState(targetValue = color, label = "color")
|
||||
|
||||
|
|
@ -129,10 +130,11 @@ fun PenIcon(
|
|||
drawInkSquiggle(
|
||||
type = type,
|
||||
forcedInkType = forcedInkType,
|
||||
color = animatedInkColor, // Use the specific ink color
|
||||
color = animatedInkColor,
|
||||
progress = inkProgress,
|
||||
startPoint = Offset(tipX, tipY),
|
||||
baseStrokeWidth = strokeWidth
|
||||
baseStrokeWidth = strokeWidth,
|
||||
isStraight = isSnappingEnabled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -413,7 +415,8 @@ private fun DrawScope.drawInkSquiggle(
|
|||
color: Color,
|
||||
progress: Float,
|
||||
startPoint: Offset,
|
||||
baseStrokeWidth: Float
|
||||
baseStrokeWidth: Float,
|
||||
isStraight: Boolean = false
|
||||
) {
|
||||
val x = startPoint.x
|
||||
val y = startPoint.y - 2f
|
||||
|
|
@ -422,13 +425,17 @@ private fun DrawScope.drawInkSquiggle(
|
|||
|
||||
if (type == PenType.HIGHLIGHTER || type == PenType.HIGHLIGHTER_ROUND) {
|
||||
val waveWidth = 70f
|
||||
val amplitude = 20f
|
||||
|
||||
cubicTo(
|
||||
x + waveWidth * 0.35f, y - amplitude,
|
||||
x + waveWidth * 0.65f, y + amplitude,
|
||||
x + waveWidth, y
|
||||
)
|
||||
if (isStraight) {
|
||||
lineTo(x + waveWidth, y)
|
||||
} else {
|
||||
val amplitude = 20f
|
||||
cubicTo(
|
||||
x + waveWidth * 0.35f, y - amplitude,
|
||||
x + waveWidth * 0.65f, y + amplitude,
|
||||
x + waveWidth, y
|
||||
)
|
||||
}
|
||||
} else {
|
||||
cubicTo(
|
||||
x + 35f, y - 40f,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.SliderDefaults
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.SwitchDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -103,7 +105,9 @@ fun ToolSettingsPopup(
|
|||
onColorChanged: (Color) -> Unit,
|
||||
onThicknessChanged: (Float) -> Unit,
|
||||
onPaletteChange: (List<Color>) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
isHighlighterSnapEnabled: Boolean = false,
|
||||
onSnapToggle: (Boolean) -> Unit = {}
|
||||
) {
|
||||
val isHighlighter = selectedTool == InkType.HIGHLIGHTER || selectedTool == InkType.HIGHLIGHTER_ROUND
|
||||
|
||||
|
|
@ -157,10 +161,9 @@ fun ToolSettingsPopup(
|
|||
tonalElevation = 0.dp
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(20.dp), // Reduced padding
|
||||
modifier = Modifier.padding(20.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// Pen Type Selector
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -179,7 +182,8 @@ fun ToolSettingsPopup(
|
|||
inkColor = highlighterColor,
|
||||
isSelected = selectedTool == InkType.HIGHLIGHTER,
|
||||
strokeWidth = activeToolThickness,
|
||||
onClick = { onToolTypeChanged(InkType.HIGHLIGHTER) }
|
||||
onClick = { onToolTypeChanged(InkType.HIGHLIGHTER) },
|
||||
isSnappingEnabled = isHighlighterSnapEnabled
|
||||
)
|
||||
|
||||
PenItem(
|
||||
|
|
@ -189,7 +193,8 @@ fun ToolSettingsPopup(
|
|||
inkColor = highlighterRoundColor,
|
||||
isSelected = selectedTool == InkType.HIGHLIGHTER_ROUND,
|
||||
strokeWidth = activeToolThickness,
|
||||
onClick = { onToolTypeChanged(InkType.HIGHLIGHTER_ROUND) }
|
||||
onClick = { onToolTypeChanged(InkType.HIGHLIGHTER_ROUND) },
|
||||
isSnappingEnabled = isHighlighterSnapEnabled
|
||||
)
|
||||
} else {
|
||||
PenItem(
|
||||
|
|
@ -224,6 +229,32 @@ fun ToolSettingsPopup(
|
|||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
if (isHighlighter) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = "Straight Line",
|
||||
color = Color.White,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Switch(
|
||||
checked = isHighlighterSnapEnabled,
|
||||
onCheckedChange = onSnapToggle,
|
||||
colors = SwitchDefaults.colors(
|
||||
checkedThumbColor = Color.White,
|
||||
checkedTrackColor = activeColor.copy(alpha = 1f),
|
||||
uncheckedThumbColor = Color.Gray,
|
||||
uncheckedTrackColor = Color(0xFF424242)
|
||||
),
|
||||
modifier = Modifier.scale(0.8f)
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
// THICKNESS SLIDER
|
||||
StyledPropertySlider(
|
||||
value = activeToolThickness,
|
||||
|
|
@ -811,7 +842,8 @@ private fun PenItem(
|
|||
strokeWidth: Float,
|
||||
onClick: () -> Unit,
|
||||
forcedInkType: InkType? = null,
|
||||
inkColor: Color? = null
|
||||
inkColor: Color? = null,
|
||||
isSnappingEnabled: Boolean = false
|
||||
) {
|
||||
val scale by animateFloatAsState(
|
||||
targetValue = if (isSelected) 1.15f else 0.9f, label = "scale"
|
||||
|
|
@ -834,7 +866,8 @@ private fun PenItem(
|
|||
isSelected = isSelected,
|
||||
strokeWidth = strokeWidth,
|
||||
forcedInkType = forcedInkType,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
isSnappingEnabled = isSnappingEnabled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ data class AnnotationToolSettings(
|
|||
"#8C64B5F6".toColorInt(), // Blue
|
||||
"#8CE1BEE7".toColorInt(), // Purple
|
||||
),
|
||||
val textStyle: TextStyleConfig = TextStyleConfig()
|
||||
val textStyle: TextStyleConfig = TextStyleConfig(),
|
||||
val isHighlighterSnapEnabled: Boolean = false
|
||||
) {
|
||||
fun getActiveTool(): InkType = try {
|
||||
InkType.valueOf(selectedToolName)
|
||||
|
|
@ -180,6 +181,10 @@ class AnnotationSettingsRepository(context: Context) {
|
|||
saveSettings(_settings.value.copy(highlighterPaletteArgb = colors.map { it.toArgb() }))
|
||||
}
|
||||
|
||||
fun updateHighlighterSnap(enabled: Boolean) {
|
||||
saveSettings(_settings.value.copy(isHighlighterSnapEnabled = enabled))
|
||||
}
|
||||
|
||||
fun updateTextStyle(style: TextStyleConfig) {
|
||||
saveSettings(_settings.value.copy(textStyle = style))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue