Skip to content
Closed
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
Expand Up @@ -225,6 +225,16 @@ private static void withinBlock(StringBuilder out, Spanned text, int start, int
out.append("<");
out.append(tagType);

AlignmentSpan.Standard[] alignments = text.getSpans(i, next, AlignmentSpan.Standard.class);
if (alignments.length > 0) {
Layout.Alignment align = alignments[alignments.length - 1].getAlignment();
if (align == Layout.Alignment.ALIGN_CENTER) {
out.append(" style=\"text-align: center\"");
} else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
out.append(" style=\"text-align: right\"");
}
}

if (isCheckboxListItem) {
EnrichedCheckboxListSpan[] checkboxSpans =
text.getSpans(i, next, EnrichedCheckboxListSpan.class);
Expand Down Expand Up @@ -462,16 +472,16 @@ private void handleStartTag(String tag, Attributes attributes) {
// so we can safely emit the linebreaks when we handle the close tag.
} else if (tag.equalsIgnoreCase("p")) {
isEmptyTag = true;
startBlockElement(mSpannableStringBuilder);
startBlockElement(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("ul")) {
isInOrderedList = false;
String dataType = attributes.getValue("", "data-type");
isInCheckboxList = "checkbox".equals(dataType);
startBlockElement(mSpannableStringBuilder);
startBlockElement(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("ol")) {
isInOrderedList = true;
currentOrderedListItemIndex = 0;
startBlockElement(mSpannableStringBuilder);
startBlockElement(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("li")) {
isEmptyTag = true;
startLi(mSpannableStringBuilder, attributes);
Expand All @@ -481,10 +491,10 @@ private void handleStartTag(String tag, Attributes attributes) {
start(mSpannableStringBuilder, new Italic());
} else if (tag.equalsIgnoreCase("blockquote")) {
isEmptyTag = true;
startBlockquote(mSpannableStringBuilder);
startBlockquote(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("codeblock")) {
isEmptyTag = true;
startCodeBlock(mSpannableStringBuilder);
startCodeBlock(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("a")) {
startA(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("u")) {
Expand All @@ -494,17 +504,17 @@ private void handleStartTag(String tag, Attributes attributes) {
} else if (tag.equalsIgnoreCase("strike")) {
start(mSpannableStringBuilder, new Strikethrough());
} else if (tag.equalsIgnoreCase("h1")) {
startHeading(mSpannableStringBuilder, 1);
startHeading(mSpannableStringBuilder, 1, attributes);
} else if (tag.equalsIgnoreCase("h2")) {
startHeading(mSpannableStringBuilder, 2);
startHeading(mSpannableStringBuilder, 2, attributes);
} else if (tag.equalsIgnoreCase("h3")) {
startHeading(mSpannableStringBuilder, 3);
startHeading(mSpannableStringBuilder, 3, attributes);
} else if (tag.equalsIgnoreCase("h4")) {
startHeading(mSpannableStringBuilder, 4);
startHeading(mSpannableStringBuilder, 4, attributes);
} else if (tag.equalsIgnoreCase("h5")) {
startHeading(mSpannableStringBuilder, 5);
startHeading(mSpannableStringBuilder, 5, attributes);
} else if (tag.equalsIgnoreCase("h6")) {
startHeading(mSpannableStringBuilder, 6);
startHeading(mSpannableStringBuilder, 6, attributes);
} else if (tag.equalsIgnoreCase("img")) {
startImg(mSpannableStringBuilder, attributes, mSpanFactory);
} else if (tag.equalsIgnoreCase("code")) {
Expand Down Expand Up @@ -573,9 +583,24 @@ private static void appendNewlines(Editable text, int minNewline) {
}
}

private static void startBlockElement(Editable text) {
private static void startBlockElement(Editable text, Attributes attributes) {
appendNewlines(text, 1);
start(text, new Newline(1));

if (attributes != null) {
String style = attributes.getValue("", "style");
if (style != null) {
if (style.contains("text-align: center")) {
start(text, new Alignment(Layout.Alignment.ALIGN_CENTER));
} else if (style.contains("text-align: right")) {
start(text, new Alignment(Layout.Alignment.ALIGN_OPPOSITE));
}
}
}
}

private static void startBlockElement(Editable text) {
startBlockElement(text, null);
}

private static void endBlockElement(Editable text) {
Expand All @@ -595,7 +620,7 @@ private static void handleBr(Editable text) {
}

private void startLi(Editable text, Attributes attributes) {
startBlockElement(text);
startBlockElement(text, attributes);

if (isInOrderedList) {
currentOrderedListItemIndex++;
Expand Down Expand Up @@ -625,8 +650,8 @@ private static <T> void endLi(Editable text, T style, EnrichedSpanFactory<T> spa
endBlockElement(text);
}

private void startBlockquote(Editable text) {
startBlockElement(text);
private void startBlockquote(Editable text, Attributes attributes) {
startBlockElement(text, attributes);
start(text, new Blockquote());
}

Expand All @@ -637,8 +662,8 @@ private static <T> void endBlockquote(
setParagraphSpanFromMark(text, last, spanFactory.createBlockQuoteSpan(style));
}

private void startCodeBlock(Editable text) {
startBlockElement(text);
private void startCodeBlock(Editable text, Attributes attributes) {
startBlockElement(text, attributes);
start(text, new CodeBlock());
}

Expand All @@ -648,8 +673,8 @@ private static <T> void endCodeBlock(Editable text, T style, EnrichedSpanFactory
setParagraphSpanFromMark(text, last, spanFactory.createCodeBlockSpan(style));
}

private void startHeading(Editable text, int level) {
startBlockElement(text);
private void startHeading(Editable text, int level, Attributes attributes) {
startBlockElement(text, attributes);

switch (level) {
case 1:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import android.graphics.Rect
import android.graphics.text.LineBreaker
import android.os.Build
import android.text.InputType
import android.text.Layout
import android.text.Spannable
import android.text.style.AlignmentSpan
import android.util.AttributeSet
import android.util.Log
import android.util.Patterns
Expand Down Expand Up @@ -475,6 +477,55 @@ class EnrichedTextInputView : AppCompatEditText {
)
}

fun setParagraphAlignment(alignment: String) {
val align =
when (alignment) {
"center" -> Layout.Alignment.ALIGN_CENTER
"right" -> Layout.Alignment.ALIGN_OPPOSITE
else -> Layout.Alignment.ALIGN_NORMAL
}

val targetRange = paragraphStyles?.getStyleRange() ?: return
runAsATransaction {
var start = targetRange.first
var end = targetRange.second
if (start == end) {
text?.insert(start, EnrichedConstants.ZWS_STRING)
end += 1
}
removeParagraphAlignment(start, end)
val span = AlignmentSpan.Standard(align)
(text as? Spannable)?.setSpan(span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
layoutManager.invalidateLayout()
selection?.validateStyles()
requestFocusProgrammatically()
}

fun getCurrentParagraphAlignment(): String {
val targetRange = paragraphStyles?.getStyleRange() ?: return "left"
val spannable = text as? Spannable ?: return "left"
val spans = spannable.getSpans(targetRange.first, targetRange.second, AlignmentSpan.Standard::class.java)
if (spans.isEmpty()) return "left"
val span = spans.last()
return when (span.alignment) {
Layout.Alignment.ALIGN_CENTER -> "center"
Layout.Alignment.ALIGN_OPPOSITE -> "right"
else -> "left"
}
}

private fun removeParagraphAlignment(
start: Int,
end: Int,
) {
val spannable = text as? Spannable ?: return
val spans = spannable.getSpans(start, end, AlignmentSpan.Standard::class.java)
for (span in spans) {
spannable.removeSpan(span)
}
}

fun setFontFamily(family: String?) {
if (family != fontFamily) {
fontFamily = family
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,13 @@ class EnrichedTextInputViewManager :
view?.requestHTML(requestId)
}

override fun setParagraphAlignment(
view: EnrichedTextInputView?,
alignment: String,
) {
view?.setParagraphAlignment(alignment)
}

override fun measure(
context: Context,
localData: ReadableMap?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ class EnrichedSelection(
for ((style, config) in EnrichedSpans.parametrizedStyles) {
state.setStart(style, getParametrizedStyleStart(config.clazz))
}

state.setAlignment(view.getCurrentParagraphAlignment())
}

fun getInlineSelection(): Pair<Int, Int> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ class EnrichedSpanState(
private set
var mentionStart: Int? = null
private set
var alignment: String? = null
private set

fun setAlignment(alignment: String) {
this.alignment = alignment
emitStateChangeEvent()
}

fun setBoldStart(start: Int?) {
this.boldStart = start
Expand Down Expand Up @@ -246,6 +253,7 @@ class EnrichedSpanState(
payload.putMap("image", getStyleState(activeStyles, EnrichedSpans.IMAGE))
payload.putMap("mention", getStyleState(activeStyles, EnrichedSpans.MENTION))
payload.putMap("checkboxList", getStyleState(activeStyles, EnrichedSpans.CHECKBOX_LIST))
payload.putString("alignment", this.alignment ?: view.getCurrentParagraphAlignment())

return payload
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class EnrichedSpanWatcher(
// Do not parse spannable and emit event if onChangeHtml is not provided
if (!view.shouldEmitHtml) return

// Emit event only if we change one of ours spans
if (what != null && what !is EnrichedInputSpan) return
// Emit event only if we change one of ours spans or alignment
if (what != null && what !is EnrichedInputSpan && what !is android.text.style.AlignmentSpan.Standard) return

val html = EnrichedParser.toHtml(s)
if (html == previousHtml) return
Expand Down
Loading