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) {
|
if (isContentFocused) {
|
||||||
DraggableMiniMarkdownToolbar(
|
DraggableMiniMarkdownToolbar(
|
||||||
@ -294,6 +295,8 @@ fun EditableFullScreenNoteView(
|
|||||||
isBoldActive = editorState.isBoldActive(),
|
isBoldActive = editorState.isBoldActive(),
|
||||||
isItalicActive = editorState.isItalicActive(),
|
isItalicActive = editorState.isItalicActive(),
|
||||||
isUnderlineActive = editorState.isUnderlineActive(),
|
isUnderlineActive = editorState.isUnderlineActive(),
|
||||||
|
canUndo = editorState.canUndo(),
|
||||||
|
canRedo = editorState.canRedo(),
|
||||||
|
|
||||||
onDrag = ::moveToolbar,
|
onDrag = ::moveToolbar,
|
||||||
onBold = {
|
onBold = {
|
||||||
@ -307,6 +310,12 @@ fun EditableFullScreenNoteView(
|
|||||||
onUnderline = {
|
onUnderline = {
|
||||||
ensureFocus()
|
ensureFocus()
|
||||||
editorState.toggleUnderline()
|
editorState.toggleUnderline()
|
||||||
|
},
|
||||||
|
onUndo = {
|
||||||
|
editorState.undo()
|
||||||
|
},
|
||||||
|
onRedo = {
|
||||||
|
editorState.redo()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,11 +25,15 @@ fun DraggableMiniMarkdownToolbar(
|
|||||||
isBoldActive: Boolean,
|
isBoldActive: Boolean,
|
||||||
isItalicActive: Boolean,
|
isItalicActive: Boolean,
|
||||||
isUnderlineActive: Boolean,
|
isUnderlineActive: Boolean,
|
||||||
|
canUndo: Boolean = false,
|
||||||
|
canRedo: Boolean = false,
|
||||||
|
|
||||||
// ACTIONS
|
// ACTIONS
|
||||||
onBold: () -> Unit,
|
onBold: () -> Unit,
|
||||||
onItalic: () -> Unit,
|
onItalic: () -> Unit,
|
||||||
onUnderline: () -> Unit
|
onUnderline: () -> Unit,
|
||||||
|
onUndo: () -> Unit = {},
|
||||||
|
onRedo: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
@ -80,6 +84,28 @@ fun DraggableMiniMarkdownToolbar(
|
|||||||
isActive = isUnderlineActive,
|
isActive = isUnderlineActive,
|
||||||
onClick = onUnderline
|
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(
|
private fun ToolbarIcon(
|
||||||
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
isActive: Boolean = false
|
isActive: Boolean = false,
|
||||||
|
enabled: Boolean = true
|
||||||
) {
|
) {
|
||||||
val activeBg = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f)
|
val activeBg = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f)
|
||||||
val activeColor = MaterialTheme.colorScheme.primary
|
val activeColor = MaterialTheme.colorScheme.primary
|
||||||
|
val disabledColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -104,12 +132,17 @@ private fun ToolbarIcon(
|
|||||||
) {
|
) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
modifier = Modifier.size(36.dp)
|
modifier = Modifier.size(36.dp),
|
||||||
|
enabled = enabled
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
contentDescription = null,
|
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)
|
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
|
STICKY TYPING STYLE
|
||||||
===================== */
|
===================== */
|
||||||
@ -37,6 +63,8 @@ class RichEditorState(initial: AnnotatedString) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snapshot()
|
||||||
|
|
||||||
// Build new annotated string by preserving old spans
|
// Build new annotated string by preserving old spans
|
||||||
val built = buildPreservingSpans(old, newValue)
|
val built = buildPreservingSpans(old, newValue)
|
||||||
|
|
||||||
@ -135,6 +163,7 @@ class RichEditorState(initial: AnnotatedString) {
|
|||||||
|
|
||||||
private fun toggleStyle(style: SpanStyle) {
|
private fun toggleStyle(style: SpanStyle) {
|
||||||
val sel = value.selection.normalized()
|
val sel = value.selection.normalized()
|
||||||
|
snapshot()
|
||||||
|
|
||||||
if (!sel.collapsed) applyStyleToSelection(style)
|
if (!sel.collapsed) applyStyleToSelection(style)
|
||||||
else toggleTypingStyle(style)
|
else toggleTypingStyle(style)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user