Fitur undo redo
This commit is contained in:
parent
a61c5f45ad
commit
9715d958ae
@ -264,7 +264,8 @@ fun EditableFullScreenNoteView(
|
||||
}
|
||||
}
|
||||
|
||||
// Update bagian DraggableMiniMarkdownToolbar call:
|
||||
// GANTI SELURUH bagian DraggableMiniMarkdownToolbar di EditableFullScreenNoteView.kt
|
||||
// Letakkan kode ini di dalam Box setelah Scaffold, sebelum closing bracket
|
||||
|
||||
if (isContentFocused) {
|
||||
DraggableMiniMarkdownToolbar(
|
||||
@ -294,6 +295,8 @@ fun EditableFullScreenNoteView(
|
||||
isBoldActive = editorState.isBoldActive(),
|
||||
isItalicActive = editorState.isItalicActive(),
|
||||
isUnderlineActive = editorState.isUnderlineActive(),
|
||||
canUndo = editorState.canUndo(),
|
||||
canRedo = editorState.canRedo(),
|
||||
|
||||
onDrag = ::moveToolbar,
|
||||
onBold = {
|
||||
@ -307,6 +310,12 @@ fun EditableFullScreenNoteView(
|
||||
onUnderline = {
|
||||
ensureFocus()
|
||||
editorState.toggleUnderline()
|
||||
},
|
||||
onUndo = {
|
||||
editorState.undo()
|
||||
},
|
||||
onRedo = {
|
||||
editorState.redo()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -25,11 +25,15 @@ fun DraggableMiniMarkdownToolbar(
|
||||
isBoldActive: Boolean,
|
||||
isItalicActive: Boolean,
|
||||
isUnderlineActive: Boolean,
|
||||
canUndo: Boolean = false,
|
||||
canRedo: Boolean = false,
|
||||
|
||||
// ACTIONS
|
||||
onBold: () -> Unit,
|
||||
onItalic: () -> Unit,
|
||||
onUnderline: () -> Unit
|
||||
onUnderline: () -> Unit,
|
||||
onUndo: () -> Unit = {},
|
||||
onRedo: () -> Unit = {}
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
@ -80,6 +84,28 @@ fun DraggableMiniMarkdownToolbar(
|
||||
isActive = isUnderlineActive,
|
||||
onClick = onUnderline
|
||||
)
|
||||
|
||||
// Divider
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(1.dp)
|
||||
.height(24.dp)
|
||||
.background(MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f))
|
||||
)
|
||||
|
||||
// Undo
|
||||
ToolbarIcon(
|
||||
icon = Icons.Default.Undo,
|
||||
onClick = onUndo,
|
||||
enabled = canUndo
|
||||
)
|
||||
|
||||
// Redo
|
||||
ToolbarIcon(
|
||||
icon = Icons.Default.Redo,
|
||||
onClick = onRedo,
|
||||
enabled = canRedo
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,10 +114,12 @@ fun DraggableMiniMarkdownToolbar(
|
||||
private fun ToolbarIcon(
|
||||
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
||||
onClick: () -> Unit,
|
||||
isActive: Boolean = false
|
||||
isActive: Boolean = false,
|
||||
enabled: Boolean = true
|
||||
) {
|
||||
val activeBg = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f)
|
||||
val activeColor = MaterialTheme.colorScheme.primary
|
||||
val disabledColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
@ -104,12 +132,17 @@ private fun ToolbarIcon(
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.size(36.dp)
|
||||
modifier = Modifier.size(36.dp),
|
||||
enabled = enabled
|
||||
) {
|
||||
Icon(
|
||||
icon,
|
||||
contentDescription = null,
|
||||
tint = if (isActive) activeColor else MaterialTheme.colorScheme.onSurface,
|
||||
tint = when {
|
||||
!enabled -> disabledColor
|
||||
isActive -> activeColor
|
||||
else -> MaterialTheme.colorScheme.onSurface
|
||||
},
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@ -17,6 +17,32 @@ class RichEditorState(initial: AnnotatedString) {
|
||||
)
|
||||
)
|
||||
|
||||
/* =====================
|
||||
UNDO / REDO
|
||||
===================== */
|
||||
private val undoStack = mutableStateListOf<TextFieldValue>()
|
||||
private val redoStack = mutableStateListOf<TextFieldValue>()
|
||||
|
||||
private fun snapshot() {
|
||||
undoStack.add(value)
|
||||
redoStack.clear()
|
||||
}
|
||||
|
||||
fun canUndo() = undoStack.isNotEmpty()
|
||||
fun canRedo() = redoStack.isNotEmpty()
|
||||
|
||||
fun undo() {
|
||||
if (!canUndo()) return
|
||||
redoStack.add(value)
|
||||
value = undoStack.removeAt(undoStack.lastIndex)
|
||||
}
|
||||
|
||||
fun redo() {
|
||||
if (!canRedo()) return
|
||||
undoStack.add(value)
|
||||
value = redoStack.removeAt(redoStack.lastIndex)
|
||||
}
|
||||
|
||||
/* =====================
|
||||
STICKY TYPING STYLE
|
||||
===================== */
|
||||
@ -37,6 +63,8 @@ class RichEditorState(initial: AnnotatedString) {
|
||||
return
|
||||
}
|
||||
|
||||
snapshot()
|
||||
|
||||
// Build new annotated string by preserving old spans
|
||||
val built = buildPreservingSpans(old, newValue)
|
||||
|
||||
@ -135,6 +163,7 @@ class RichEditorState(initial: AnnotatedString) {
|
||||
|
||||
private fun toggleStyle(style: SpanStyle) {
|
||||
val sel = value.selection.normalized()
|
||||
snapshot()
|
||||
|
||||
if (!sel.collapsed) applyStyleToSelection(style)
|
||||
else toggleTypingStyle(style)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user