Skip to content
Open
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
118 changes: 118 additions & 0 deletions .maestro/enrichedInput/flows/custom_style_colors_visual.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
appId: swmansion.enriched.example
---
# Validates custom colors on plain text, inline styles, and paragraph styles.
- launchApp

- tapOn:
id: 'toggle-screen-button'

- tapOn:
id: 'editor-input'

# Section 1: Plain text with colors

- tapOn:
id: 'toolbar-text-color'
- tapOn:
id: 'color-swatch-FF0000'
- inputText: 'Red text'
- tapOn:
id: 'toolbar-text-color'
- tapOn:
id: 'color-swatch-clear'
- inputText: ' '

- tapOn:
id: 'toolbar-bg-color'
- tapOn:
id: 'color-swatch-FFFF00'
- inputText: 'Yellow back'
- tapOn:
id: 'toolbar-bg-color'
- tapOn:
id: 'color-swatch-clear'
- inputText: ' '

- tapOn:
id: 'toolbar-text-color'
- tapOn:
id: 'color-swatch-FF0000'
- tapOn:
id: 'toolbar-bg-color'
- tapOn:
id: 'color-swatch-FFFF00'
- inputText: 'Red+Yellow'
- tapOn:
id: 'toolbar-text-color'
- tapOn:
id: 'color-swatch-clear'
- tapOn:
id: 'toolbar-bg-color'
- tapOn:
id: 'color-swatch-clear'
- inputText: ' '

# Section 2: Inline styles + color

- tapOn:
id: 'toolbar-bold'
- tapOn:
id: 'toolbar-text-color'
- tapOn:
id: 'color-swatch-FF0000'
- inputText: 'Bold red'
- tapOn:
id: 'toolbar-bold'
- tapOn:
id: 'toolbar-text-color'
- tapOn:
id: 'color-swatch-clear'
- inputText: ' '

- tapOn:
id: 'toolbar-italic'
- tapOn:
id: 'toolbar-bg-color'
- tapOn:
id: 'color-swatch-FFFF00'
- inputText: 'Italic yellow back'
- tapOn:
id: 'toolbar-italic'
- tapOn:
id: 'toolbar-bg-color'
- tapOn:
id: 'color-swatch-clear'
- inputText: ' '
- pressKey: Enter

# Section 3: Paragraph styles + color

- tapOn:
id: 'toolbar-heading-5'
- tapOn:
id: 'toolbar-text-color'
- tapOn:
id: 'color-swatch-FF0000'
- inputText: 'H5 red'
- pressKey: Enter
- tapOn:
id: 'toolbar-text-color'
- tapOn:
id: 'color-swatch-clear'

- tapOn:
id: 'toolbar-quote'
- tapOn:
id: 'toolbar-bg-color'
- tapOn:
id: 'color-swatch-FFFF00'
- inputText: 'Quote yellow back'
- tapOn:
id: 'toolbar-bg-color'
- tapOn:
id: 'color-swatch-clear'

- runFlow:
file: '../subflows/capture_or_assert_screenshot.yaml'
env:
SCREENSHOT_NAME: 'custom_style_colors'
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions .maestro/enrichedText/flows/custom_style_colors_visual.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
appId: swmansion.enriched.example
---
# Validates that custom style colors are displayed correctly
- launchApp

- tapOn:
id: 'toggle-screen-button'

- tapOn:
id: 'toggle-enriched-text-screen-button'

- runFlow:
file: '../subflows/set_enriched_text_value.yaml'
env:
VALUE: >
<html>
<p><span style="color: #FF5733;">Standard 6-digit Hex text</span></p>
<p><span style="background-color: #000000; color: #FFFFFF;">White text on black background</span></p>
<p><span style="background-color: #00FF0040;">25% transparent green background</span></p>
<p><span style="color: #0000FF80;">50% transparent blue text</span></p>
<p><span style="color: #F00;">Red 3-digit shorthand text</span></p>
<h6><span style="background-color: #0F0; color: #000;">Black text on green</span></h6>
</html>

- runFlow:
file: '../subflows/capture_or_assert_screenshot.yaml'
env:
SCREENSHOT_NAME: 'custom_style_colors_visual'
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions .maestro/scripts/setup-android-emulator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ until adb -s "$SERIAL" shell getprop sys.boot_completed 2>/dev/null | grep -q "^
done

adb -s "$SERIAL" shell pm disable-user --user 0 com.google.android.inputmethod.latin
adb -s "$SERIAL" shell settings put secure spell_checker_enabled 0

echo "Emulator ready: $AVD_NAME ($SERIAL)"
echo "DEVICE_ID=$SERIAL"
15 changes: 15 additions & 0 deletions .maestro/scripts/setup-ios-simulator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ if [ -z "$UDID" ]; then
exit 1
fi

# disable automatic text manipulation: auto-correction, spelling-check and auto-capitalization
SIM_PREFS_DIR="$HOME/Library/Developer/CoreSimulator/Devices/$UDID/data/Library/Preferences"
mkdir -p "$SIM_PREFS_DIR"

PLIST="$SIM_PREFS_DIR/com.apple.keyboard.preferences.plist"

/usr/libexec/PlistBuddy -c "Add :KeyboardAutocorrection bool false" "$PLIST" 2>/dev/null || \
/usr/libexec/PlistBuddy -c "Set :KeyboardAutocorrection bool false" "$PLIST"

/usr/libexec/PlistBuddy -c "Add :KeyboardCheckSpelling bool false" "$PLIST" 2>/dev/null || \
/usr/libexec/PlistBuddy -c "Set :KeyboardCheckSpelling bool false" "$PLIST"

/usr/libexec/PlistBuddy -c "Add :KeyboardAutocapitalization bool false" "$PLIST" 2>/dev/null || \
/usr/libexec/PlistBuddy -c "Set :KeyboardAutocapitalization bool false" "$PLIST"

STATE=$(xcrun simctl list devices | grep "$UDID" | grep -oE '\(Booted\)|\(Shutdown\)' || true)
if [ "$STATE" != "(Booted)" ]; then
echo "Booting '$DEVICE_NAME' ($UDID)..."
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.swmansion.enriched.common

import android.text.Spannable
import com.swmansion.enriched.common.spans.EnrichedAlignmentSpan
import com.swmansion.enriched.common.spans.interfaces.EnrichedInlineSpan

// Higher priority spans are processed first, so styles with lower priorities are painted on top of previously applied styles.
// For example, inline styles are applied on top of paragraph styles, allowing them to override paragraph-level styling.
// Alignment styles are applied last, ensuring they position the final, fully styled text.
object EnrichedSpanFlags {
private const val ALIGNMENT_SPAN_PRIORITY = 0
private const val INLINE_SPAN_PRIORITY = 1
private const val PARAGRAPH_SPAN_PRIORITY = 2

@JvmStatic
@JvmOverloads
fun forSpan(
span: Any?,
baseFlags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE,
): Int {
val priority =
when (span) {
is EnrichedAlignmentSpan -> ALIGNMENT_SPAN_PRIORITY
is EnrichedInlineSpan -> INLINE_SPAN_PRIORITY
else -> PARAGRAPH_SPAN_PRIORITY
}
return applyPriority(baseFlags, priority)
}

private fun applyPriority(
flags: Int,
priority: Int,
): Int {
// Cleaning up priority bits
val cleared = flags and Spannable.SPAN_PRIORITY.inv()
// Injecting priority bits
return cleared or ((priority shl Spannable.SPAN_PRIORITY_SHIFT) and Spannable.SPAN_PRIORITY)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.text.TextUtils;
import android.text.style.ParagraphStyle;
import com.swmansion.enriched.common.EnrichedConstants;
import com.swmansion.enriched.common.EnrichedSpanFlags;
import com.swmansion.enriched.common.spans.EnrichedAlignmentSpan;
import com.swmansion.enriched.common.spans.EnrichedBoldSpan;
import com.swmansion.enriched.common.spans.EnrichedCheckboxListSpan;
Expand Down Expand Up @@ -467,10 +468,7 @@ public Spanned convert() {
if (end == start) {
mSpannableStringBuilder.removeSpan(obj[i]);
} else {
// TODO: verify if Spannable.SPAN_EXCLUSIVE_EXCLUSIVE does not break anything.
// Previously it was SPAN_PARAGRAPH. I've changed that in order to fix ranges for list
// items.
mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mSpannableStringBuilder.setSpan(obj[i], start, end, EnrichedSpanFlags.forSpan(obj[i]));
}
}

Expand Down Expand Up @@ -505,7 +503,7 @@ public Spanned convert() {

mSpannableStringBuilder.removeSpan(zeroWidthSpaceSpan);
mSpannableStringBuilder.setSpan(
zeroWidthSpaceSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
zeroWidthSpaceSpan, start, end, EnrichedSpanFlags.forSpan(zeroWidthSpaceSpan));
}

return mSpannableStringBuilder;
Expand Down Expand Up @@ -802,7 +800,7 @@ private static void setSpanFromMark(Spannable text, Object mark, Object... spans
int len = text.length();
if (where != len) {
for (Object span : spans) {
text.setSpan(span, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(span, where, len, EnrichedSpanFlags.forSpan(span));
}
}
}
Expand All @@ -825,7 +823,7 @@ private static void setParagraphSpanFromMark(Editable text, Object mark, Object.

if (where != len) {
for (Object span : spans) {
text.setSpan(span, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(span, where, len, EnrichedSpanFlags.forSpan(span));
}
}
}
Expand All @@ -850,11 +848,9 @@ private static <T> void startImg(

int len = text.length();
text.append("");
text.setSpan(
spanFactory.createImageSpan(src, Integer.parseInt(width), Integer.parseInt(height)),
len,
text.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Object imageSpan =
spanFactory.createImageSpan(src, Integer.parseInt(width), Integer.parseInt(height));
text.setSpan(imageSpan, len, text.length(), EnrichedSpanFlags.forSpan(imageSpan));
}

private static void startA(Editable text, Attributes attributes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
import com.swmansion.enriched.common.EnrichedConstants
import com.swmansion.enriched.common.EnrichedSpanFlags
import com.swmansion.enriched.common.GumboNormalizer
import com.swmansion.enriched.common.parser.EnrichedParser
import com.swmansion.enriched.common.pixelFromSpOrDp
Expand Down Expand Up @@ -277,7 +278,7 @@ class EnrichedTextView : AppCompatTextView {

spannable.removeSpan(span)
val newSpan = span.rebuildWithStyle(enrichedStyle)
spannable.setSpan(newSpan, start, end, flags)
spannable.setSpan(newSpan, start, end, EnrichedSpanFlags.forSpan(newSpan, flags))
modified = true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
import com.swmansion.enriched.common.EnrichedConstants
import com.swmansion.enriched.common.EnrichedSpanFlags
import com.swmansion.enriched.common.GumboNormalizer
import com.swmansion.enriched.common.parser.EnrichedParser
import com.swmansion.enriched.common.pixelFromSpOrDp
Expand Down Expand Up @@ -1108,7 +1109,7 @@ class EnrichedTextInputView :

spannable.removeSpan(span)
val newSpan = span.rebuildWithStyle(htmlStyle)
spannable.setSpan(newSpan, start, end, flags)
spannable.setSpan(newSpan, start, end, EnrichedSpanFlags.forSpan(newSpan, flags))
}

if (shouldEmitStateChange) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,13 @@ class EnrichedTextInputViewManager :
view?.setTextAlignment(alignment)
}

override fun setStyle(
view: EnrichedTextInputView?,
styleJSON: String,
) {
// TODO: Implement
}
Comment thread
kacperzolkiewski marked this conversation as resolved.

override fun measure(
context: Context,
localData: ReadableMap?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.text.Editable
import android.text.Spannable
import android.text.SpannableStringBuilder
import com.swmansion.enriched.common.EnrichedConstants
import com.swmansion.enriched.common.EnrichedSpanFlags
import com.swmansion.enriched.textinput.EnrichedTextInputView
import com.swmansion.enriched.textinput.spans.EnrichedInputAlignmentSpan
import com.swmansion.enriched.textinput.spans.EnrichedInputCheckboxListSpan
Expand All @@ -24,12 +25,8 @@ class AlignmentStyles(
flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE,
) {
val (safeStart, safeEnd) = spannable.getSafeSpanBoundaries(start, end)
spannable.setSpan(
EnrichedInputAlignmentSpan(cssValue),
safeStart,
safeEnd,
flags,
)
val span = EnrichedInputAlignmentSpan(cssValue)
spannable.setSpan(span, safeStart, safeEnd, EnrichedSpanFlags.forSpan(span, flags))
}

private fun toCssValue(alignment: String): String =
Expand Down Expand Up @@ -302,7 +299,9 @@ class AlignmentStyles(
// INCLUSIVE_EXCLUSIVE is intentional here: autoStretchAlignmentSpan will convert
// it to EXCLUSIVE_EXCLUSIVE once the merge is complete.
val (safeStart, safeEnd) = s.getSafeSpanBoundaries(paraStart, paraEnd)
dominantTopSpan?.let { s.setSpan(it, safeStart, safeEnd, Spannable.SPAN_INCLUSIVE_EXCLUSIVE) }
dominantTopSpan?.let {
s.setSpan(it, safeStart, safeEnd, EnrichedSpanFlags.forSpan(it, Spannable.SPAN_INCLUSIVE_EXCLUSIVE))
}
return cursorPosition
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.swmansion.enriched.textinput.styles

import android.text.Editable
import android.text.Spannable
import com.swmansion.enriched.common.EnrichedSpanFlags
import com.swmansion.enriched.textinput.EnrichedTextInputView
import com.swmansion.enriched.textinput.spans.EnrichedSpans
import com.swmansion.enriched.textinput.utils.getSafeSpanBoundaries
Expand Down Expand Up @@ -41,7 +42,7 @@ class InlineStyles(

val span = type.getDeclaredConstructor(HtmlStyle::class.java).newInstance(view.htmlStyle)
val (safeStart, safeEnd) = spannable.getSafeSpanBoundaries(minimum, maximum)
spannable.setSpan(span, safeStart, safeEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
spannable.setSpan(span, safeStart, safeEnd, EnrichedSpanFlags.forSpan(span))
}

private fun <T> setAndMergeSpans(
Expand Down
Loading