Skip to content
This repository was archived by the owner on Sep 27, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package io.element.android.wysiwyg

import android.content.ClipData
import android.content.ClipDescription
import android.content.ClipboardManager
import android.content.Context
import android.graphics.Typeface
import android.net.Uri
import android.text.Editable
import android.text.style.BulletSpan
import android.text.style.ReplacementSpan
import android.text.style.StyleSpan
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.InputContentInfo
import android.widget.EditText
import android.widget.TextView
import androidx.core.text.getSpans
Expand Down Expand Up @@ -462,6 +468,79 @@ class EditorEditTextInputTests {
confirmVerified(textWatcher)
}

@Test
fun testPasteImage() {
val imageUri = Uri.parse("content://fakeImage")
val contentWatcher = spyk<(uri: Uri) -> Unit>({ })
onView(withId(R.id.rich_text_edit_text))
.perform(EditorActions.addContentWatcher(arrayOf("image/*"), contentWatcher))

scenarioRule.scenario.onActivity { activity ->
val editor = activity.findViewById<EditorEditText>(R.id.rich_text_edit_text)
val clipboardManager =
activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clpData = ClipData.newRawUri("image", imageUri)
clipboardManager.setPrimaryClip(clpData)
editor.onTextContextMenuItem(android.R.id.paste)
}
verify(exactly = 1) {
contentWatcher.invoke(match { it == imageUri })
}

confirmVerified(contentWatcher)
}

@Test
fun testPastePlainText() {
val clipData = ClipData.newPlainText("text", ipsum)
val contentWatcher = spyk<(uri: Uri) -> Unit>({ })
val textWatcher = spyk<(text: Editable?) -> Unit>({ })
onView(withId(R.id.rich_text_edit_text))
.perform(EditorActions.addTextWatcher(textWatcher))
pasteFromClipboard(clipData, false)

pasteFromClipboard(clipData, true)

verify(exactly = 2) {
textWatcher.invoke(match { it.toString() == ipsum + ipsum })
}

confirmVerified(contentWatcher)
}

@Test
fun testPasteHtlmText() {
val html = "<bold>$ipsum</bold>"
val clipData = ClipData.newHtmlText("html", ipsum, html)
val contentWatcher = spyk<(uri: Uri) -> Unit>({ })
val textWatcher = spyk<(text: Editable?) -> Unit>({ })
onView(withId(R.id.rich_text_edit_text))
.perform(EditorActions.addTextWatcher(textWatcher))
pasteFromClipboard(clipData, false)

pasteFromClipboard(clipData, true)

verify(exactly = 2) {
// In future when we support parsing/loading of pasted html into the model
// we can make more assertions on that the corrrect formating is applied
textWatcher.invoke(match { it.toString() == ipsum + ipsum })
}

confirmVerified(contentWatcher)
}


private fun pasteFromClipboard(clipData: ClipData, pasteAsPlainText: Boolean){
scenarioRule.scenario.onActivity { activity ->
val editor = activity.findViewById<EditorEditText>(R.id.rich_text_edit_text)
val clipboardManager =
activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboardManager.setPrimaryClip(clipData)
val itemId = if (pasteAsPlainText) android.R.id.pasteAsPlainText else android.R.id.paste
editor.onTextContextMenuItem(itemId)
}
}

@Test
fun getMarkdownTranslatesDomToMarkdown() {
scenarioRule.scenario.onActivity { activity ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.element.android.wysiwyg.test.utils

import android.net.Uri
import android.text.Editable
import android.view.View
import androidx.core.view.ViewCompat
import androidx.core.widget.addTextChangedListener
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
Expand Down Expand Up @@ -201,6 +203,27 @@ object Editor {
}
}

class AddContentWatcher(
private val contentTypes: Array<String>,
private val contentWatcher: (Uri) -> Unit,
) : ViewAction {
override fun getConstraints(): Matcher<View> = isDisplayed()

override fun getDescription(): String = "Add a content watcher"

override fun perform(uiController: UiController?, view: View?) {
val editor = view as? EditorEditText ?: return

ViewCompat.setOnReceiveContentListener(
editor,
contentTypes,
UriContentListener{
contentWatcher(it)
}
)
}
}

class TestCrash(
private val errorCollector: RustErrorCollector?
) : ViewAction {
Expand Down Expand Up @@ -232,7 +255,8 @@ object EditorActions {
fun undo() = Editor.Undo
fun redo() = Editor.Redo
fun toggleFormat(format: InlineFormat) = Editor.ToggleFormat(format)
fun addTextWatcher(watcher : (Editable?) -> Unit) = Editor.AddTextWatcher(watcher)
fun addTextWatcher(watcher: (Editable?) -> Unit) = Editor.AddTextWatcher(watcher)
fun addContentWatcher(contentTypes: Array<String>, watcher: (Uri) -> Unit) = Editor.AddContentWatcher(contentTypes, watcher)
fun testCrash(
errorCollector: RustErrorCollector? = null
) = Editor.TestCrash(errorCollector)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.element.android.wysiwyg.test.utils

import android.content.ClipData
import android.net.Uri
import android.view.View
import androidx.core.view.ContentInfoCompat
import androidx.core.view.OnReceiveContentListener

class UriContentListener(
private val onContent: (uri: Uri) -> Unit
) : OnReceiveContentListener {
override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
val split = payload.partition { item -> item.uri != null }
val uriContent = split.first
val remaining = split.second

if (uriContent != null) {
val clip: ClipData = uriContent.clip
for (i in 0 until clip.itemCount) {
val uri = clip.getItemAt(i).uri
// ... app-specific logic to handle the URI ...
onContent(uri)
}
}
// Return anything that we didn't handle ourselves. This preserves the default platform
// behavior for text and anything else for which we are not implementing custom handling.
return remaining
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ class EditorEditText : TextInputEditText {
android.R.id.paste, android.R.id.pasteAsPlainText -> {
val clipBoardManager =
context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val copiedString = clipBoardManager.primaryClip?.getItemAt(0)?.text ?: return false
// Only special-case paste behaviour if it is text content, otherwise default to EditText implementation
// which calls ViewCompat.performReceiveContent and fires the expected listeners.
val copiedString = clipBoardManager.primaryClip?.getItemAt(0)?.text ?: return super.onTextContextMenuItem(id)
val result = viewModel.processInput(EditorInputAction.ReplaceText(copiedString))

if (result != null) {
Expand Down