diff --git a/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java b/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java index 413aa0017..c7a2fc769 100644 --- a/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java +++ b/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java @@ -15,7 +15,9 @@ package com.keylesspalace.tusky.viewdata; +import android.os.Build; import android.support.annotation.Nullable; +import android.text.SpannableStringBuilder; import android.text.Spanned; import com.keylesspalace.tusky.entity.Attachment; @@ -47,6 +49,9 @@ public abstract class StatusViewData { public abstract boolean deepEquals(StatusViewData other); public static final class Concrete extends StatusViewData { + private static final char SOFT_HYPHEN = '\u00ad'; + private static final char ASCII_HYPHEN = '-'; + private final String id; private final Spanned content; private final boolean reblogged; @@ -92,10 +97,18 @@ public abstract class StatusViewData { Status.Application application, List statusEmojis, List accountEmojis, @Nullable Card card, boolean isCollapsible, boolean isCollapsed) { this.id = id; - this.content = content; + if (Build.VERSION.SDK_INT == 23) { + // https://github.com/tuskyapp/Tusky/issues/563 + this.content = replaceCrashingCharacters(content); + this.spoilerText = spoilerText == null ? null : replaceCrashingCharacters(spoilerText).toString(); + this.nickname = replaceCrashingCharacters(nickname).toString(); + } else { + this.content = content; + this.spoilerText = spoilerText; + this.nickname = nickname; + } this.reblogged = reblogged; this.favourited = favourited; - this.spoilerText = spoilerText; this.visibility = visibility; this.attachments = attachments; this.rebloggedByUsername = rebloggedByUsername; @@ -104,7 +117,6 @@ public abstract class StatusViewData { this.isExpanded = isExpanded; this.isShowingContent = isShowingContent; this.userFullName = userFullName; - this.nickname = nickname; this.avatar = avatar; this.createdAt = createdAt; this.reblogsCount = reblogsCount; @@ -288,6 +300,33 @@ public abstract class StatusViewData { Objects.equals(card, concrete.card) && isCollapsed == concrete.isCollapsed; } + + static Spanned replaceCrashingCharacters(Spanned content) { + return (Spanned) replaceCrashingCharacters((CharSequence) content); + } + + static CharSequence replaceCrashingCharacters(CharSequence content) { + Boolean replacing = false; + SpannableStringBuilder builder = null; + int length = content.length(); + + for (int index = 0; index < length; ++index) { + char character = content.charAt(index); + + // If there are more than one or two, switch to a map + if (character == SOFT_HYPHEN) { + if (!replacing) { + replacing = true; + builder = new SpannableStringBuilder(content, 0, index); + } + builder.append(ASCII_HYPHEN); + } else if (replacing) { + builder.append(character); + } + } + + return replacing ? builder : content; + } } public static final class Placeholder extends StatusViewData {