diff --git a/.maestro/flows/extending_paragraph_style_on_paste_after_copy.yaml b/.maestro/flows/extending_paragraph_style_on_paste_after_copy.yaml new file mode 100644 index 00000000..9b8dde96 --- /dev/null +++ b/.maestro/flows/extending_paragraph_style_on_paste_after_copy.yaml @@ -0,0 +1,45 @@ +appId: swmansion.enriched.example +tags: + - android-only +--- +- launchApp +- tapOn: + id: "toggle-screen-button" + +- tapOn: + id: "focus-button" + +- inputText: "EADING" +- doubleTapOn: + id: "editor-input" + point: "10%, 50%" + +- tapOn: + id: "android:id/floating_toolbar_menu_item_text" + text: "Copy" + +# Dismiss toolbar with Copy/Cut etc. options +- tapOn: + id: "editor-input" +- tapOn: + id: "clear-button" +- tapOn: + id: "focus-button" + +- tapOn: + id: "toolbar-heading-1" + +- inputText: "H" + +- longPressOn: + id: "editor-input" + point: "50%, 50%" + +- tapOn: + id: "android:id/floating_toolbar_menu_item_text" + text: "Paste" + +- runFlow: + file: "../subflows/capture_or_assert_screenshot.yaml" + env: + SCREENSHOT_NAME: "extending_paragraph_style_on_paste_after_copy" diff --git a/.maestro/flows/extending_paragraph_style_on_paste_after_cut.yaml b/.maestro/flows/extending_paragraph_style_on_paste_after_cut.yaml new file mode 100644 index 00000000..323f0869 --- /dev/null +++ b/.maestro/flows/extending_paragraph_style_on_paste_after_cut.yaml @@ -0,0 +1,38 @@ +appId: swmansion.enriched.example +tags: + - android-only +--- +# TODO: run with --update-screenshots to update the screenshots after fixing the issue with Cut +- launchApp +- tapOn: + id: "toggle-screen-button" + +- tapOn: + id: "focus-button" + +- inputText: "EADING" +- doubleTapOn: + id: "editor-input" + point: "10%, 50%" + +- tapOn: + id: "android:id/floating_toolbar_menu_item_text" + text: "Cut" + +- tapOn: + id: "toolbar-heading-1" + +- inputText: "H" + +- longPressOn: + id: "editor-input" + point: "50%, 50%" + +- tapOn: + id: "android:id/floating_toolbar_menu_item_text" + text: "Paste" + +- runFlow: + file: "../subflows/capture_or_assert_screenshot.yaml" + env: + SCREENSHOT_NAME: "extending_paragraph_style_on_paste_after_cut" diff --git a/.maestro/screenshots/android/extending_paragraph_style_on_paste_after_copy.png b/.maestro/screenshots/android/extending_paragraph_style_on_paste_after_copy.png new file mode 100644 index 00000000..f717ac4f Binary files /dev/null and b/.maestro/screenshots/android/extending_paragraph_style_on_paste_after_copy.png differ diff --git a/.maestro/screenshots/android/extending_paragraph_style_on_paste_after_cut.png b/.maestro/screenshots/android/extending_paragraph_style_on_paste_after_cut.png new file mode 100644 index 00000000..b0b6bfa2 Binary files /dev/null and b/.maestro/screenshots/android/extending_paragraph_style_on_paste_after_cut.png differ diff --git a/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannable.kt b/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannable.kt index 1433e78d..ebc5e83c 100644 --- a/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannable.kt +++ b/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannable.kt @@ -66,6 +66,10 @@ fun Spannable.mergeSpannables( val isNewLineStart = startBlockSpans.isNotEmpty() || startParagraphSpans.isNotEmpty() val isNewLineEnd = endBlockSpans.isNotEmpty() || endParagraphSpans.isNotEmpty() + val pastedHasOwnStyles = + spannable.getSpans(0, spannable.length, EnrichedBlockSpan::class.java).isNotEmpty() || + spannable.getSpans(0, spannable.length, EnrichedParagraphSpan::class.java).isNotEmpty() + if (isNewLineStart && start != paragraphStart) { builder.insert(start, "\n") finalStart = start + 1 @@ -78,5 +82,25 @@ fun Spannable.mergeSpannables( builder.replace(finalStart, finalEnd, spannable) + // Manually extend existing paragraph/block spans to cover the pasted text. + if (!pastedHasOwnStyles) { + val pasteEnd = finalStart + spannable.length + + val affectedParagraphSpans = builder.getSpans(finalStart, finalStart, EnrichedParagraphSpan::class.java) + val affectedBlockSpans = builder.getSpans(finalStart, finalStart, EnrichedBlockSpan::class.java) + val affectedSpans = affectedBlockSpans.toList() + affectedParagraphSpans.toList() + + for (span in affectedSpans) { + val spanStart = builder.getSpanStart(span) + val spanEnd = builder.getSpanEnd(span) + if (spanStart == -1 || spanEnd >= pasteEnd) continue + + val (_, newParagraphEnd) = builder.getParagraphBounds(spanStart, pasteEnd) + val flags = builder.getSpanFlags(span) + builder.removeSpan(span) + builder.setSpan(span, spanStart, newParagraphEnd, flags) + } + } + return builder }