Skip to content

Commit 2c3a693

Browse files
committed
adding the undo/redo functionality
1 parent 48f31b8 commit 2c3a693

File tree

5 files changed

+121
-3
lines changed

5 files changed

+121
-3
lines changed

app/src/main/kotlin/com/simplemobiletools/notes/activities/MainActivity.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ class MainActivity : SimpleActivity(), ViewPager.OnPageChangeListener {
132132
when (item.itemId) {
133133
R.id.open_note -> displayOpenNoteDialog()
134134
R.id.save_note -> saveNote()
135+
R.id.undo -> undo()
136+
R.id.redo -> redo()
135137
R.id.new_note -> displayNewNoteDialog()
136138
R.id.rename_note -> displayRenameDialog()
137139
R.id.share -> shareText()
@@ -287,11 +289,11 @@ class MainActivity : SimpleActivity(), ViewPager.OnPageChangeListener {
287289

288290
private fun openFile() {
289291
FilePickerDialog(this) {
290-
openFile(it, true, {
292+
openFile(it, true) {
291293
OpenFileDialog(this, it.path) {
292294
addNewNote(it)
293295
}
294-
})
296+
}
295297
}
296298
}
297299

@@ -524,6 +526,14 @@ class MainActivity : SimpleActivity(), ViewPager.OnPageChangeListener {
524526
invalidateOptionsMenu()
525527
}
526528

529+
private fun undo() {
530+
mAdapter?.undo(view_pager.currentItem)
531+
}
532+
533+
private fun redo() {
534+
mAdapter?.redo(view_pager.currentItem)
535+
}
536+
527537
private fun getNoteIndexWithId(id: Int): Int {
528538
for (i in 0 until mNotes.count()) {
529539
if (mNotes[i].id == id) {

app/src/main/kotlin/com/simplemobiletools/notes/adapters/NotesPagerAdapter.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class NotesPagerAdapter(fm: FragmentManager, val notes: List<Note>, val activity
4242

4343
fun focusEditText(position: Int) = fragments[position]?.focusEditText()
4444

45+
fun undo(position: Int) = fragments[position]?.undo()
46+
47+
fun redo(position: Int) = fragments[position]?.redo()
48+
4549
override fun finishUpdate(container: ViewGroup) {
4650
try {
4751
super.finishUpdate(container)

app/src/main/kotlin/com/simplemobiletools/notes/fragments/NoteFragment.kt

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import android.graphics.Typeface
44
import android.os.Bundle
55
import android.support.v4.app.Fragment
66
import android.text.Editable
7+
import android.text.Selection
78
import android.text.TextWatcher
9+
import android.text.style.UnderlineSpan
810
import android.text.util.Linkify
911
import android.util.TypedValue
1012
import android.view.Gravity
@@ -22,12 +24,18 @@ import com.simplemobiletools.notes.extensions.getTextSize
2224
import com.simplemobiletools.notes.extensions.updateWidget
2325
import com.simplemobiletools.notes.helpers.*
2426
import com.simplemobiletools.notes.models.Note
27+
import com.simplemobiletools.notes.models.TextHistory
28+
import com.simplemobiletools.notes.models.TextHistoryItem
2529
import kotlinx.android.synthetic.main.fragment_note.*
2630
import kotlinx.android.synthetic.main.fragment_note.view.*
2731
import kotlinx.android.synthetic.main.note_view_horiz_scrollable.view.*
2832
import java.io.File
2933

34+
// text history handling taken from https://gist.github.com/zeleven/0cfa738c1e8b65b23ff7df1fc30c9f7e
3035
class NoteFragment : Fragment() {
36+
private var textHistory = TextHistory()
37+
38+
private var isUndoOrRedo = false
3139
private var noteId = 0
3240
lateinit var note: Note
3341
lateinit var view: ViewGroup
@@ -161,11 +169,69 @@ class NoteFragment : Fragment() {
161169
notes_counter.text = words.count { it.isNotEmpty() }.toString()
162170
}
163171

172+
fun undo() {
173+
val edit = textHistory.getPrevious() ?: return
174+
175+
val text = view.notes_view.editableText
176+
val start = edit.start
177+
val end = start + if (edit.after != null) edit.after.length else 0
178+
179+
isUndoOrRedo = true
180+
text.replace(start, end, edit.before)
181+
isUndoOrRedo = false
182+
183+
for (span in text.getSpans(0, text.length, UnderlineSpan::class.java)) {
184+
text.removeSpan(span)
185+
}
186+
187+
Selection.setSelection(text, if (edit.before == null) {
188+
start
189+
} else {
190+
start + edit.before.length
191+
})
192+
}
193+
194+
fun redo() {
195+
val edit = textHistory.getNext() ?: return
196+
197+
val text = view.notes_view.editableText
198+
val start = edit.start
199+
val end = start + if (edit.before != null) edit.before.length else 0
200+
201+
isUndoOrRedo = true
202+
text.replace(start, end, edit.after)
203+
isUndoOrRedo = false
204+
205+
for (o in text.getSpans(0, text.length, UnderlineSpan::class.java)) {
206+
text.removeSpan(o)
207+
}
208+
209+
Selection.setSelection(text, if (edit.after == null) {
210+
start
211+
} else {
212+
start + edit.after.length
213+
})
214+
}
215+
216+
fun isUndoAvailable() = textHistory.position > 0
217+
218+
fun isRedoAvailable() = textHistory.position < textHistory.history.size
219+
164220
private var textWatcher: TextWatcher = object : TextWatcher {
221+
private var beforeChange: CharSequence? = null
222+
private var afterChange: CharSequence? = null
223+
165224
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
225+
if (!isUndoOrRedo) {
226+
beforeChange = s.subSequence(start, start + count)
227+
}
166228
}
167229

168-
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
230+
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
231+
if (!isUndoOrRedo) {
232+
afterChange = s.subSequence(start, start + count)
233+
textHistory.add(TextHistoryItem(start, beforeChange!!, afterChange!!))
234+
}
169235
}
170236

171237
override fun afterTextChanged(editable: Editable) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.simplemobiletools.notes.models
2+
3+
import java.util.*
4+
5+
class TextHistory {
6+
var position = 0
7+
val history = LinkedList<TextHistoryItem>()
8+
9+
fun getPrevious(): TextHistoryItem? {
10+
if (position == 0) {
11+
return null
12+
}
13+
position--
14+
return history[position]
15+
}
16+
17+
fun getNext(): TextHistoryItem? {
18+
if (position >= history.size) {
19+
return null
20+
}
21+
22+
val item = history[position]
23+
position++
24+
return item
25+
}
26+
27+
fun add(item: TextHistoryItem) {
28+
while (history.size > position) {
29+
history.removeLast()
30+
}
31+
32+
history.add(item)
33+
position++
34+
}
35+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.simplemobiletools.notes.models
2+
3+
data class TextHistoryItem(val start: Int, val before: CharSequence?, val after: CharSequence?)

0 commit comments

Comments
 (0)