mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-19 16:19:33 +01:00
Add spoiler format style.
This commit is contained in:
@@ -143,6 +143,7 @@ import org.thoughtcrime.securesms.components.reminder.ReminderView;
|
||||
import org.thoughtcrime.securesms.components.reminder.ServiceOutageReminder;
|
||||
import org.thoughtcrime.securesms.components.reminder.UnauthorizedReminder;
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.ConversationSettingsActivity;
|
||||
import org.thoughtcrime.securesms.components.spoiler.SpoilerAnnotation;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteDraft;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
||||
@@ -493,6 +494,7 @@ public class ConversationParentFragment extends Fragment
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
disposables.bindTo(getViewLifecycleOwner());
|
||||
menuProvider = new ConversationOptionsMenu.Provider(this, this, disposables);
|
||||
SpoilerAnnotation.resetRevealedSpoilers();
|
||||
|
||||
if (requireActivity() instanceof Callback) {
|
||||
callback = (Callback) requireActivity();
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package org.thoughtcrime.securesms.conversation
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.text.Annotation
|
||||
import android.text.Spannable
|
||||
import android.text.Spanned
|
||||
import android.text.style.CharacterStyle
|
||||
import android.text.style.StrikethroughSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.text.style.TypefaceSpan
|
||||
import org.thoughtcrime.securesms.components.spoiler.SpoilerAnnotation
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||
import org.thoughtcrime.securesms.util.PlaceholderURLSpan
|
||||
|
||||
@@ -39,7 +41,13 @@ object MessageStyler {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun style(messageRanges: BodyRangeList?, span: Spannable): Result {
|
||||
fun spoilerStyle(start: Int, length: Int, body: Spannable? = null): Annotation {
|
||||
return SpoilerAnnotation.spoilerAnnotation(arrayOf(start, length, body?.toString()).contentHashCode())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun style(messageRanges: BodyRangeList?, span: Spannable, hideSpoilerText: Boolean = true): Result {
|
||||
if (messageRanges == null) {
|
||||
return Result.none()
|
||||
}
|
||||
@@ -53,11 +61,18 @@ object MessageStyler {
|
||||
.filter { r -> r.start >= 0 && r.start < span.length && r.start + r.length >= 0 && r.start + r.length <= span.length }
|
||||
.forEach { range ->
|
||||
if (range.hasStyle()) {
|
||||
val styleSpan: CharacterStyle? = when (range.style) {
|
||||
val styleSpan: Any? = when (range.style) {
|
||||
BodyRangeList.BodyRange.Style.BOLD -> boldStyle()
|
||||
BodyRangeList.BodyRange.Style.ITALIC -> italicStyle()
|
||||
BodyRangeList.BodyRange.Style.STRIKETHROUGH -> strikethroughStyle()
|
||||
BodyRangeList.BodyRange.Style.MONOSPACE -> monoStyle()
|
||||
BodyRangeList.BodyRange.Style.SPOILER -> {
|
||||
val spoiler = spoilerStyle(range.start, range.length, span)
|
||||
if (hideSpoilerText) {
|
||||
span.setSpan(SpoilerAnnotation.SpoilerClickableSpan(spoiler), range.start, range.start + range.length, SPAN_FLAGS)
|
||||
}
|
||||
spoiler
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -83,34 +98,46 @@ object MessageStyler {
|
||||
@JvmStatic
|
||||
fun hasStyling(text: Spanned): Boolean {
|
||||
return text
|
||||
.getSpans(0, text.length, CharacterStyle::class.java)
|
||||
.any { s -> isSupportedCharacterStyle(s) && text.getSpanEnd(s) - text.getSpanStart(s) > 0 }
|
||||
.getSpans(0, text.length, Object::class.java)
|
||||
.any { s -> s.isSupportedStyle() && text.getSpanEnd(s) - text.getSpanStart(s) > 0 }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getStyling(text: CharSequence?): BodyRangeList? {
|
||||
val bodyRanges = if (text is Spanned) {
|
||||
text
|
||||
.getSpans(0, text.length, CharacterStyle::class.java)
|
||||
.filter { s -> isSupportedCharacterStyle(s) }
|
||||
.mapNotNull { span: CharacterStyle ->
|
||||
.getSpans(0, text.length, Object::class.java)
|
||||
.filter { s -> s.isSupportedStyle() }
|
||||
.mapNotNull { span ->
|
||||
val spanStart = text.getSpanStart(span)
|
||||
val spanLength = text.getSpanEnd(span) - spanStart
|
||||
|
||||
val style = when (span) {
|
||||
is StyleSpan -> if (span.style == Typeface.BOLD) BodyRangeList.BodyRange.Style.BOLD else BodyRangeList.BodyRange.Style.ITALIC
|
||||
val style: BodyRangeList.BodyRange.Style? = when (span) {
|
||||
is StyleSpan -> {
|
||||
when (span.style) {
|
||||
Typeface.BOLD -> BodyRangeList.BodyRange.Style.BOLD
|
||||
Typeface.ITALIC -> BodyRangeList.BodyRange.Style.ITALIC
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
is StrikethroughSpan -> BodyRangeList.BodyRange.Style.STRIKETHROUGH
|
||||
is TypefaceSpan -> BodyRangeList.BodyRange.Style.MONOSPACE
|
||||
is Annotation -> {
|
||||
if (SpoilerAnnotation.isSpoilerAnnotation(span)) {
|
||||
BodyRangeList.BodyRange.Style.SPOILER
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
else -> throw IllegalArgumentException("Provided text contains unsupported spans")
|
||||
}
|
||||
|
||||
if (spanLength > 0) {
|
||||
if (spanLength > 0 && style != null) {
|
||||
BodyRangeList.BodyRange.newBuilder().setStart(spanStart).setLength(spanLength).setStyle(style).build()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
@@ -122,8 +149,15 @@ object MessageStyler {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isSupportedCharacterStyle(style: CharacterStyle): Boolean {
|
||||
fun Any.isSupportedStyle(): Boolean {
|
||||
return when (this) {
|
||||
is CharacterStyle -> isSupportedCharacterStyle(this)
|
||||
is Annotation -> SpoilerAnnotation.isSpoilerAnnotation(this)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSupportedCharacterStyle(style: CharacterStyle): Boolean {
|
||||
return when (style) {
|
||||
is StyleSpan -> style.style == Typeface.ITALIC || style.style == Typeface.BOLD
|
||||
is StrikethroughSpan -> true
|
||||
|
||||
@@ -79,7 +79,7 @@ class DraftRepository(
|
||||
|
||||
updatedText = SpannableString(updated.body)
|
||||
MentionAnnotation.setMentionAnnotations(updatedText, updated.mentions)
|
||||
MessageStyler.style(bodyRanges.adjustBodyRanges(updated.bodyAdjustments), updatedText)
|
||||
MessageStyler.style(messageRanges = bodyRanges.adjustBodyRanges(updated.bodyAdjustments), span = updatedText, hideSpoilerText = false)
|
||||
}
|
||||
|
||||
DatabaseDraft(drafts, updatedText)
|
||||
|
||||
Reference in New Issue
Block a user