Skip to content

Commit 1785cae

Browse files
committed
Update
1 parent 4ce61b9 commit 1785cae

2 files changed

Lines changed: 32 additions & 24 deletions

File tree

app/src/main/java/com/tool/tree/TextEditorActivity.kt

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,15 @@ class TextEditorActivity : AppCompatActivity() {
105105
private val progressBarDialog by lazy { ProgressBarDialog(this) }
106106

107107
// --- Undo / Redo ---
108-
// Lưu lại toàn bộ nội dung tại mỗi "đợt" chỉnh sửa (gộp các ký tự gõ liên tục thành một
109-
// bước, thay vì lưu theo từng ký tự) để nút Undo/Redo hoạt động tự nhiên như trình soạn
110-
// thảo thông thường. EditText mặc định của Android không có sẵn undo/redo công khai nên
111-
// phải tự quản lý 2 stack này.
112-
private val undoStack = ArrayDeque<String>()
113-
private val redoStack = ArrayDeque<String>()
114-
private var pendingUndoSnapshot: String? = null
108+
// Lưu lại toàn bộ nội dung và vị trí con trỏ tại mỗi "đợt" chỉnh sửa (gộp các ký tự gõ
109+
// liên tục thành một bước, thay vì lưu theo từng ký tự) để nút Undo/Redo hoạt động tự nhiên
110+
// như trình soạn thảo thông thường. EditText mặc định của Android không có sẵn undo/redo
111+
// công khai nên phải tự quản lý 2 stack này.
112+
private data class EditorSnapshot(val text: String, val cursor: Int)
113+
114+
private val undoStack = ArrayDeque<EditorSnapshot>()
115+
private val redoStack = ArrayDeque<EditorSnapshot>()
116+
private var pendingUndoSnapshot: EditorSnapshot? = null
115117
private var isApplyingHistory = false
116118
private var undoButton: ImageButton? = null
117119
private var redoButton: ImageButton? = null
@@ -127,6 +129,7 @@ class TextEditorActivity : AppCompatActivity() {
127129

128130
val toolbar = findViewById<View>(R.id.toolbar) as Toolbar
129131
setSupportActionBar(toolbar)
132+
supportActionBar?.setDisplayShowTitleEnabled(false)
130133
// Bỏ nút back (mũi tên) trên toolbar theo yêu cầu — việc thoát trang giờ thực hiện qua
131134
// mục "Thoát" trong menu (xem onOptionsItemSelected). Nút back cứng/gesture của hệ
132135
// thống vẫn hoạt động bình thường nhờ onBackPressedDispatcher bên dưới.
@@ -308,7 +311,10 @@ class TextEditorActivity : AppCompatActivity() {
308311
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
309312
if (isApplyingHistory) return
310313
if (pendingUndoSnapshot == null) {
311-
pendingUndoSnapshot = s?.toString().orEmpty()
314+
// Chụp nội dung VÀ vị trí con trỏ ngay trước khi thay đổi xảy ra —
315+
// đây là trạng thái cần quay lại khi người dùng bấm Undo.
316+
val cursor = binding.editorContent.selectionStart.coerceAtLeast(0)
317+
pendingUndoSnapshot = EditorSnapshot(s?.toString().orEmpty(), cursor)
312318
}
313319
}
314320

@@ -328,7 +334,7 @@ class TextEditorActivity : AppCompatActivity() {
328334
val snapshot = pendingUndoSnapshot ?: return
329335
pendingUndoSnapshot = null
330336
val current = binding.editorContent.text?.toString().orEmpty()
331-
if (snapshot == current) return
337+
if (snapshot.text == current) return
332338

333339
if (undoStack.size >= UNDO_HISTORY_LIMIT) {
334340
undoStack.removeFirst()
@@ -339,9 +345,10 @@ class TextEditorActivity : AppCompatActivity() {
339345

340346
private fun performUndo() {
341347
undoHandler.removeCallbacks(commitPendingUndoRunnable)
342-
val current = binding.editorContent.text?.toString().orEmpty()
348+
val currentText = binding.editorContent.text?.toString().orEmpty()
349+
val currentCursor = binding.editorContent.selectionStart.coerceAtLeast(0)
343350

344-
val target: String
351+
val target: EditorSnapshot
345352
val pending = pendingUndoSnapshot
346353
if (pending != null) {
347354
// Đang có một đợt gõ chưa kịp "chốt" vào undoStack — hoàn tác thẳng về mốc đó.
@@ -352,8 +359,8 @@ class TextEditorActivity : AppCompatActivity() {
352359
target = undoStack.removeLast()
353360
}
354361

355-
redoStack.addLast(current)
356-
applyHistoryText(target)
362+
redoStack.addLast(EditorSnapshot(currentText, currentCursor))
363+
applyHistorySnapshot(target)
357364
refreshUndoRedoButtons()
358365
}
359366

@@ -362,22 +369,23 @@ class TextEditorActivity : AppCompatActivity() {
362369
undoHandler.removeCallbacks(commitPendingUndoRunnable)
363370
pendingUndoSnapshot = null
364371

365-
val current = binding.editorContent.text?.toString().orEmpty()
372+
val currentText = binding.editorContent.text?.toString().orEmpty()
373+
val currentCursor = binding.editorContent.selectionStart.coerceAtLeast(0)
366374
val target = redoStack.removeLast()
367375

368376
if (undoStack.size >= UNDO_HISTORY_LIMIT) {
369377
undoStack.removeFirst()
370378
}
371-
undoStack.addLast(current)
372-
applyHistoryText(target)
379+
undoStack.addLast(EditorSnapshot(currentText, currentCursor))
380+
applyHistorySnapshot(target)
373381
refreshUndoRedoButtons()
374382
}
375383

376-
private fun applyHistoryText(text: String) {
384+
private fun applyHistorySnapshot(snapshot: EditorSnapshot) {
377385
isApplyingHistory = true
378386
val editText = binding.editorContent
379-
editText.setText(text)
380-
editText.setSelection(text.length.coerceAtLeast(0))
387+
editText.setText(snapshot.text)
388+
editText.setSelection(snapshot.cursor.coerceIn(0, snapshot.text.length))
381389
isApplyingHistory = false
382390
}
383391

app/src/main/res/layout/dialog_loading.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@
3232

3333
<Button
3434
android:id="@+id/dialog_cancel_button"
35-
android:layout_width="wrap_content"
36-
android:layout_height="wrap_content"
35+
style="@style/dialogWarningBtn"
36+
android:layout_weight="1"
37+
android:visibility="gone"
3738
android:layout_gravity="center_horizontal"
38-
android:layout_marginTop="16dp"
39-
android:text="@string/btn_cancel"
40-
android:visibility="gone" />
39+
android:text="@string/btn_cancel" />
40+
4141
</LinearLayout>
4242
</FrameLayout>

0 commit comments

Comments
 (0)