Skip to content

Commit

Permalink
Merge pull request #1092 from wordpress-mobile/feature/improve-perfor…
Browse files Browse the repository at this point in the history
…mance-of-to-html-method

Improve performance of toHtml method by moving it to background thread
  • Loading branch information
AmandaRiu authored Nov 1, 2024
2 parents 0c56aec + 600046e commit cbb43e3
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 7 deletions.
3 changes: 2 additions & 1 deletion aztec/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ dependencies {

testImplementation "junit:junit:$jUnitVersion"
testImplementation "org.robolectric:robolectric:$robolectricVersion"
testImplementation 'androidx.test:core:1.4.0'
testImplementation 'androidx.test:core:1.6.1'

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutinesVersion"

implementation 'org.apache.commons:commons-lang3:3.8.1'

Expand Down
2 changes: 1 addition & 1 deletion aztec/src/main/kotlin/org/wordpress/aztec/Aztec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ open class Aztec private constructor(
}

@JvmStatic
fun with(visualEditor: AztecText, toolbar: AztecToolbar, toolbarClickListener: IAztecToolbarClickListener): Aztec {
fun with(visualEditor: AztecText, toolbar: IAztecToolbar, toolbarClickListener: IAztecToolbarClickListener): Aztec {
return Aztec(visualEditor, null, toolbar, toolbarClickListener)
}
}
Expand Down
32 changes: 32 additions & 0 deletions aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,24 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
return super.getText()!!
}

/**
* The getText method returns mutable version of the content. This means that it can change
* when being worked on. Call this method when you want your Editable to be immutable.
*/
fun getTextCopy(): Editable {
val copy = SpannableStringBuilder(text.toString())

val spans: Array<Any> = text.getSpans(0, text.length, Any::class.java)

for (span in spans) {
val spanStart = text.getSpanStart(span)
val spanEnd = text.getSpanEnd(span)
val flags = text.getSpanFlags(span)
copy.setSpan(span, spanStart, spanEnd, flags)
}
return copy
}

@SuppressLint("ResourceType")
private fun init(attrs: AttributeSet?) {
disableTextChangedListener()
Expand Down Expand Up @@ -1631,6 +1649,10 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
return toHtml(text, withCursorTag)
}

suspend fun toHtmlAsync(withCursorTag: Boolean = false): String {
return toHtmlAsync(getTextCopy(), withCursorTag)
}

// general function accepts any Spannable and converts it to regular or "calypso" html
// depending on the mode
fun toHtml(content: Spannable, withCursorTag: Boolean = false): String {
Expand All @@ -1645,6 +1667,10 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
}
}

suspend fun toHtmlAsync(content: Editable, withCursorTag: Boolean = false): String {
return toPlainHtmlAsync(content, withCursorTag)
}

// platform agnostic HTML
// default behavior returns HTML from this text
fun toPlainHtml(withCursorTag: Boolean = false): String {
Expand All @@ -1664,6 +1690,12 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
}
}

suspend fun toPlainHtmlAsync(content: Editable, withCursorTag: Boolean = false): String {
return withContext(Dispatchers.Default) {
parseHtml(content, withCursorTag)
}
}

private fun parseHtml(content: Spannable, withCursorTag: Boolean): String {
val parser = AztecParser(alignmentRendering, plugins)
val output: SpannableStringBuilder
Expand Down
105 changes: 105 additions & 0 deletions aztec/src/test/kotlin/org/wordpress/aztec/AsyncAztecTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package org.wordpress.aztec

import android.app.Activity
import android.view.MenuItem
import android.widget.PopupMenu
import android.widget.ToggleButton
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.wordpress.aztec.source.SourceViewEditText
import org.wordpress.aztec.toolbar.AztecToolbar
import org.wordpress.aztec.toolbar.ToolbarAction
import org.wordpress.aztec.toolbar.ToolbarItems

@RunWith(RobolectricTestRunner::class)
class AsyncAztecTest {
lateinit var editText: AztecText
lateinit var sourceText: SourceViewEditText
lateinit var toolbar: AztecToolbar
lateinit var buttonQuote: ToggleButton
lateinit var menuHeading: PopupMenu
lateinit var menuHeading1: MenuItem
lateinit var menuHeading2: MenuItem
lateinit var menuParagraph: MenuItem
lateinit var buttonPreformat: ToggleButton
lateinit var buttonBold: ToggleButton

/**
* Initialize variables.
*/
@Before
fun init() {
val activity = Robolectric.buildActivity(Activity::class.java).create().visible().get()
editText = AztecText(activity)
editText.setCalypsoMode(false)
sourceText = SourceViewEditText(activity)
sourceText.setCalypsoMode(false)
toolbar = AztecToolbar(activity)
toolbar.setToolbarItems(
ToolbarItems.BasicLayout(
ToolbarAction.HEADING,
ToolbarAction.PREFORMAT,
ToolbarAction.LIST,
ToolbarAction.QUOTE,
ToolbarAction.BOLD,
ToolbarAction.ITALIC,
ToolbarAction.LINK,
ToolbarAction.UNDERLINE,
ToolbarAction.STRIKETHROUGH,
ToolbarAction.ALIGN_LEFT,
ToolbarAction.ALIGN_CENTER,
ToolbarAction.ALIGN_RIGHT,
ToolbarAction.HORIZONTAL_RULE,
ToolbarAction.HTML
))
toolbar.setEditor(editText, sourceText)
buttonQuote = toolbar.findViewById<ToggleButton>(R.id.format_bar_button_quote)
menuHeading = toolbar.getHeadingMenu() as PopupMenu
menuHeading1 = menuHeading.menu.getItem(1)
menuHeading2 = menuHeading.menu.getItem(2)
menuParagraph = menuHeading.menu.getItem(0)
buttonPreformat = toolbar.findViewById<ToggleButton>(R.id.format_bar_button_pre)
buttonBold = toolbar.findViewById<ToggleButton>(R.id.format_bar_button_bold)
activity.setContentView(editText)
}

@Test
@Throws(Exception::class)
fun asyncToHtmlWorksOnCurrentVersion() = runTest {
editText.append("One two three")
val textCopy = editText.getTextCopy()
Assert.assertEquals("One two three", editText.toHtmlAsync(textCopy))
val jobs = mutableListOf<Job>()
jobs.add(launch {
Assert.assertEquals("One two three", editText.toHtmlAsync(textCopy))
})
toolbar.onMenuItemClick(menuHeading1)
val textCopy2 = editText.getTextCopy()
jobs.add(launch {
Assert.assertEquals("<h1>One two three</h1>", editText.toHtmlAsync(textCopy2))
})
toolbar.onMenuItemClick(menuParagraph)
val textCopy3 = editText.getTextCopy()
jobs.add(launch {
Assert.assertEquals("One two three", editText.toHtmlAsync(textCopy3))
})
val from = editText.editableText.indexOf("two")
editText.setSelection(from, from + 3)
editText.toggleFormatting(AztecTextFormat.FORMAT_BOLD)
val textCopy4 = editText.getTextCopy()
jobs.add(launch {
Assert.assertEquals("One <strong>two</strong> three", editText.toHtmlAsync(textCopy4))
})
jobs.forEach {
it.join()
Assert.assertTrue(it.isCompleted)
}
}
}
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ ext {
ext {
// mixed
gradlePluginVersion = '3.3.1'
kotlinCoroutinesVersion = '1.6.4'
kotlinCoroutinesVersion = '1.8.1'
tagSoupVersion = '1.2.1'
glideVersion = '4.10.0'
picassoVersion = '2.5.2'
robolectricVersion = '4.11'
jUnitVersion = '4.12'
robolectricVersion = '4.13'
jUnitVersion = '4.13.2'
jSoupVersion = '1.15.3'
wordpressUtilsVersion = '3.5.0'
espressoVersion = '3.0.1'
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pluginManagement {
gradle.ext.kotlinVersion = '1.9.24'
gradle.ext.agpVersion = '8.1.0'
gradle.ext.agpVersion = '8.5.0'
gradle.ext.automatticPublishToS3Version = '0.8.0'
gradle.ext.dependencyAnalysisVersion = '1.33.0'

Expand Down

0 comments on commit cbb43e3

Please sign in to comment.