Skip to content

Commit

Permalink
Merge pull request #887 from wordpress-mobile/feature/add-content-wat…
Browse files Browse the repository at this point in the history
…cher-for-aztec-text

Add content watcher for aztec text
  • Loading branch information
planarvoid authored Jan 2, 2020
2 parents 4720b41 + 807062a commit d2baefd
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.wordpress.aztec

import java.lang.ref.WeakReference

class AztecContentChangeWatcher {
private val observers = mutableListOf<WeakReference<AztecTextChangeObserver>>()
fun registerObserver(observer: AztecTextChangeObserver) {
if (observers.none { it.get() == observer }) {
observers.add(WeakReference(observer))
}
}

fun unregisterObserver(observer: AztecTextChangeObserver) {
observers.removeAll { it.get() == observer }
}

internal fun notifyContentChanged() {
val iterator = observers.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
val foundObserver = item.get()
if (foundObserver == null) {
iterator.remove()
} else {
foundObserver.onContentChanged()
}
}
}

interface AztecTextChangeObserver {
fun onContentChanged()
}
}
12 changes: 12 additions & 0 deletions aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown

private var focusOnVisible = true

val contentChangeWatcher = AztecContentChangeWatcher()

interface OnSelectionChangedListener {
fun onSelectionChanged(selStart: Int, selEnd: Int)
}
Expand Down Expand Up @@ -497,6 +499,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
// use HTML from the new text to set the state of the editText directly
fromHtml(toFormattedHtml(newText), false)

contentChangeWatcher.notifyContentChanged()

// re-enable MediaDeleted listener
enableMediaDeletedListener()
// re-enable this very filter
Expand Down Expand Up @@ -565,6 +569,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
setText("")
enableTextChangedListener()
}
contentChangeWatcher.notifyContentChanged()
}
return wasStyleRemoved
}
Expand Down Expand Up @@ -627,6 +632,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
}

override fun afterTextChanged(text: Editable) {
contentChangeWatcher.notifyContentChanged()
if (isTextChangedListenerDisabled()) {
return
}
Expand Down Expand Up @@ -1024,6 +1030,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
.forEach { it.toggle() }
}
}

contentChangeWatcher.notifyContentChanged()
}

fun contains(format: ITextFormat, selStart: Int = selectionStart, selEnd: Int = selectionEnd): Boolean {
Expand Down Expand Up @@ -1128,10 +1136,12 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown

fun redo() {
history.redo(this)
contentChangeWatcher.notifyContentChanged()
}

fun undo() {
history.undo(this)
contentChangeWatcher.notifyContentChanged()
}

// Helper ======================================================================================
Expand Down Expand Up @@ -1618,6 +1628,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
fromHtml(newHtml, false)
inlineFormatter.joinStyleSpans(0, length())
}
contentChangeWatcher.notifyContentChanged()
}
}

Expand All @@ -1643,6 +1654,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
} else {
linkFormatter.addLink(url, anchor, openInNewWindow, selectionStart, selectionEnd)
}
contentChangeWatcher.notifyContentChanged()
}

fun removeLink() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.wordpress.aztec

import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

@RunWith(JUnit4::class)
class AztecContentChangeWatcherTest {
private lateinit var aztecContentChangeWatcher: AztecContentChangeWatcher
@Before
fun setUp() {
aztecContentChangeWatcher = AztecContentChangeWatcher()
}

@Test
fun `notifies registered observer`() {
// Given
var contentChanged = false
setupRegisteredObserver {
contentChanged = true
}

// When
aztecContentChangeWatcher.notifyContentChanged()

// Then
assertTrue(contentChanged)
}

@Test
fun `does not notify unregistered observer`() {
// Given
var contentChanged = false
val observer = setupRegisteredObserver {
contentChanged = true
}

// When
aztecContentChangeWatcher.unregisterObserver(observer)
aztecContentChangeWatcher.notifyContentChanged()

// Then
assertFalse(contentChanged)
}

@Test
fun `observer is garbage collected and reference is lost`() {
// Given
var contentChanged = false
setupRegisteredObserver {
contentChanged = true
}
System.gc()

// When
aztecContentChangeWatcher.notifyContentChanged()

// Then
assertFalse(contentChanged)
}

private fun setupRegisteredObserver(onContentChanged: () -> Unit): AztecContentChangeWatcher.AztecTextChangeObserver {
val observer = object : AztecContentChangeWatcher.AztecTextChangeObserver {
override fun onContentChanged() {
onContentChanged()
}
}
aztecContentChangeWatcher.registerObserver(observer)
return observer
}
}

0 comments on commit d2baefd

Please sign in to comment.