diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 94f488ed1706f2184d15015ddbe14fa11dae40ff..1bc233e75ea7e67ecacfafd76a0d260a89cd5e47 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -98,6 +98,10 @@ android { setTargetCompatibility(JavaVersion.VERSION_1_8) } + testOptions { + unitTests.isIncludeAndroidResources = true + } + lintOptions { isWarningsAsErrors = true setLintConfig(file("../lint.xml")) @@ -182,4 +186,7 @@ dependencies { } testImplementation("junit", "junit", "4.12") + testImplementation("org.robolectric", "robolectric", "4.1") { + exclude(group = "org.threeten", module = "threetenbp") + } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt b/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt index 405b5685694b6f1e3bb2699fb365eb4fd306cf5f..a1c31e5203a1bd5013793b5e23118210b165a357 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt @@ -38,12 +38,11 @@ import de.kuschku.quasseldroid.util.compatibility.AndroidLoggingHandler import de.kuschku.quasseldroid.util.compatibility.AndroidStreamChannelFactory import de.kuschku.quasseldroid.util.ui.LocaleHelper -class Quasseldroid : DaggerApplication() { +open class Quasseldroid : DaggerApplication() { override fun applicationInjector(): AndroidInjector<Quasseldroid> = DaggerAppComponent.builder().create(this) - override fun onCreate() { - super.onCreate() + protected open fun init() { if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. @@ -232,6 +231,11 @@ class Quasseldroid : DaggerApplication() { } } + override fun onCreate() { + super.onCreate() + init() + } + override fun attachBaseContext(base: Context) { super.attachBaseContext(LocaleHelper.setLocale(base)) } diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt index c684f5a6235640e56a1a5c14c47092c9b3515951..c3b1ae0e3d1441d1d396b10e3426eb5e2ef32260 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt @@ -351,7 +351,7 @@ class QuasselNotificationBackend @Inject constructor( selfColor = selfColor )) } - val content = contentFormatter.formatContent(it.content, false, it.networkId) + val content = contentFormatter.formatContent(it.content, false, false, it.networkId) NotificationMessage( messageId = it.messageId, diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt index 2636c2c552afeda6d71dbedd313d022f5c9e4036..6e6ab231d71a597840ce75b508bfa10329e93da8 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt @@ -250,6 +250,12 @@ class MessageListFragment : ServiceBoundFragment() { 1 -> actionMode?.menu?.findItem(R.id.action_user_info)?.isVisible = true else -> actionMode?.menu?.findItem(R.id.action_user_info)?.isVisible = false } + } else { + val value = viewModel.expandedMessages.value + viewModel.expandedMessages.onNext( + if (value.contains(msg.original.messageId)) value - msg.original.messageId + else value + msg.original.messageId + ) } } adapter.setOnLongClickListener { msg -> @@ -289,14 +295,6 @@ class MessageListFragment : ServiceBoundFragment() { } adapter.setOnUrlLongClickListener(LinkLongClickMenuHelper()) - adapter.setOnExpansionListener { - val value = viewModel.expandedMessages.value - viewModel.expandedMessages.onNext( - if (value.contains(it.messageId)) value - it.messageId - else value + it.messageId - ) - } - messageList.adapter = adapter messageList.layoutManager = linearLayoutManager messageList.itemAnimator = null diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt index 35b7214c49001caa9548c70bf1baf5011e222711..10de33940a827296e6fc66e2629a265cfadf77e4 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt @@ -259,6 +259,7 @@ class QuasselMessageRenderer @Inject constructor( } val content = contentFormatter.formatContent(message.content.content, monochromeForeground, + message.isExpanded, message.content.networkId) val nickName = HostmaskHelper.nick(message.content.sender) val senderColorIndex = SenderColorUtil.senderColor(nickName) @@ -317,6 +318,7 @@ class QuasselMessageRenderer @Inject constructor( contentFormatter.formatNick(message.content.sender, self, monochromeForeground, false), contentFormatter.formatContent(message.content.content, monochromeForeground, + message.isExpanded, message.content.networkId) ), avatarUrls = AvatarHelper.avatar(messageSettings, message.content, avatarSize), @@ -337,6 +339,7 @@ class QuasselMessageRenderer @Inject constructor( contentFormatter.formatNick(message.content.sender, self, monochromeForeground, false), contentFormatter.formatContent(message.content.content, monochromeForeground, + message.isExpanded, message.content.networkId) ), hasDayChange = message.hasDayChange, @@ -448,6 +451,7 @@ class QuasselMessageRenderer @Inject constructor( ), contentFormatter.formatContent(message.content.content, monochromeForeground, + message.isExpanded, message.content.networkId) ) }, @@ -483,6 +487,7 @@ class QuasselMessageRenderer @Inject constructor( ), contentFormatter.formatContent(message.content.content, monochromeForeground, + message.isExpanded, message.content.networkId) ) }, @@ -518,6 +523,7 @@ class QuasselMessageRenderer @Inject constructor( false), contentFormatter.formatContent(reason, monochromeForeground, + message.isExpanded, message.content.networkId) ) }, @@ -554,6 +560,7 @@ class QuasselMessageRenderer @Inject constructor( false), contentFormatter.formatContent(reason, monochromeForeground, + message.isExpanded, message.content.networkId) ) }, @@ -623,6 +630,7 @@ class QuasselMessageRenderer @Inject constructor( dayChange = formatDayChange(message), combined = contentFormatter.formatContent(message.content.content, monochromeForeground, + message.isExpanded, message.content.networkId), hasDayChange = message.hasDayChange, isMarkerLine = message.isMarkerLine, @@ -635,6 +643,7 @@ class QuasselMessageRenderer @Inject constructor( dayChange = formatDayChange(message), combined = contentFormatter.formatContent(message.content.content, monochromeForeground, + message.isExpanded, message.content.networkId), hasDayChange = message.hasDayChange, isMarkerLine = message.isMarkerLine, @@ -657,6 +666,7 @@ class QuasselMessageRenderer @Inject constructor( dayChange = formatDayChange(message), combined = contentFormatter.formatContent(message.content.content, monochromeForeground, + message.isExpanded, message.content.networkId), hasDayChange = message.hasDayChange, isMarkerLine = message.isMarkerLine, diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/ContentFormatter.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/ContentFormatter.kt index 392d0f12624ad04f83752af3f6ddf56e6d92f30b..116acfa76781b1dd13e97d0be6a540913d42033d 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/ContentFormatter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/ContentFormatter.kt @@ -24,10 +24,7 @@ import android.graphics.Typeface import android.text.SpannableString import android.text.Spanned import android.text.TextPaint -import android.text.style.ClickableSpan -import android.text.style.ForegroundColorSpan -import android.text.style.StyleSpan -import android.text.style.URLSpan +import android.text.style.* import android.view.View import androidx.annotation.ColorInt import de.kuschku.libquassel.protocol.NetworkId @@ -37,6 +34,8 @@ import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.settings.MessageSettings import de.kuschku.quasseldroid.ui.chat.ChatActivity import de.kuschku.quasseldroid.util.helper.styledAttributes +import de.kuschku.quasseldroid.util.irc.format.spans.IrcBackgroundColorSpan +import de.kuschku.quasseldroid.util.irc.format.spans.IrcForegroundColorSpan import de.kuschku.quasseldroid.util.ui.SpanFormatter import org.intellij.lang.annotations.Language import javax.inject.Inject @@ -110,10 +109,34 @@ class ContentFormatter @Inject constructor( fun formatContent(content: String, highlight: Boolean = false, + showSpoilers: Boolean = false, networkId: NetworkId?): CharSequence { val formattedText = ircFormatDeserializer.formatString(content, messageSettings.colorizeMirc) val text = SpannableString(formattedText) + if (showSpoilers) { + val spans = mutableMapOf<Triple<Int, Int, Int>, MutableList<Any>>() + for (span in text.getSpans(0, text.length, IrcForegroundColorSpan::class.java)) { + val from = text.getSpanStart(span) + val to = text.getSpanEnd(span) + spans.getOrPut(Triple(from, to, span.getForegroundColor()), ::mutableListOf).add(span) + } + for (span in text.getSpans(0, text.length, IrcBackgroundColorSpan::class.java)) { + val from = text.getSpanStart(span) + val to = text.getSpanEnd(span) + spans.getOrPut(Triple(from, to, span.getBackgroundColor()), ::mutableListOf).add(span) + } + for (group in spans.values) { + if (group.size > 1 && + group.any { it is ForegroundColorSpan } && + group.any { it is BackgroundColorSpan }) { + for (span in group) { + text.removeSpan(span) + } + } + } + } + for (result in urlPattern.findAll(formattedText)) { val group = result.groups[1] if (group != null) { diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/IrcFormatDeserializer.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/IrcFormatDeserializer.kt index 9f12844d9f42aa927b66df1e93f54800312756db..a390248aed26cf0115b8406802c66cf28256922e 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/IrcFormatDeserializer.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/IrcFormatDeserializer.kt @@ -32,34 +32,37 @@ import javax.inject.Inject * A helper class to turn mIRC formatted Strings into Android’s SpannableStrings with the same * color and format codes */ -class IrcFormatDeserializer @Inject constructor(context: Context) { - private val mircColors = listOf( - R.color.mircColor00, R.color.mircColor01, R.color.mircColor02, R.color.mircColor03, - R.color.mircColor04, R.color.mircColor05, R.color.mircColor06, R.color.mircColor07, - R.color.mircColor08, R.color.mircColor09, R.color.mircColor10, R.color.mircColor11, - R.color.mircColor12, R.color.mircColor13, R.color.mircColor14, R.color.mircColor15, - R.color.mircColor16, R.color.mircColor17, R.color.mircColor18, R.color.mircColor19, - R.color.mircColor20, R.color.mircColor21, R.color.mircColor22, R.color.mircColor23, - R.color.mircColor24, R.color.mircColor25, R.color.mircColor26, R.color.mircColor27, - R.color.mircColor28, R.color.mircColor29, R.color.mircColor30, R.color.mircColor31, - R.color.mircColor32, R.color.mircColor33, R.color.mircColor34, R.color.mircColor35, - R.color.mircColor36, R.color.mircColor37, R.color.mircColor38, R.color.mircColor39, - R.color.mircColor40, R.color.mircColor41, R.color.mircColor42, R.color.mircColor43, - R.color.mircColor44, R.color.mircColor45, R.color.mircColor46, R.color.mircColor47, - R.color.mircColor48, R.color.mircColor49, R.color.mircColor50, R.color.mircColor51, - R.color.mircColor52, R.color.mircColor53, R.color.mircColor54, R.color.mircColor55, - R.color.mircColor56, R.color.mircColor57, R.color.mircColor58, R.color.mircColor59, - R.color.mircColor60, R.color.mircColor61, R.color.mircColor62, R.color.mircColor63, - R.color.mircColor64, R.color.mircColor65, R.color.mircColor66, R.color.mircColor67, - R.color.mircColor68, R.color.mircColor69, R.color.mircColor70, R.color.mircColor71, - R.color.mircColor72, R.color.mircColor73, R.color.mircColor74, R.color.mircColor75, - R.color.mircColor76, R.color.mircColor77, R.color.mircColor78, R.color.mircColor79, - R.color.mircColor80, R.color.mircColor81, R.color.mircColor82, R.color.mircColor83, - R.color.mircColor84, R.color.mircColor85, R.color.mircColor86, R.color.mircColor87, - R.color.mircColor88, R.color.mircColor89, R.color.mircColor90, R.color.mircColor91, - R.color.mircColor92, R.color.mircColor93, R.color.mircColor94, R.color.mircColor95, - R.color.mircColor96, R.color.mircColor97, R.color.mircColor98 - ).map(context::getColorCompat).toIntArray() +class IrcFormatDeserializer(private val mircColors: IntArray) { + @Inject + constructor(context: Context) : this( + mircColors = listOf( + R.color.mircColor00, R.color.mircColor01, R.color.mircColor02, R.color.mircColor03, + R.color.mircColor04, R.color.mircColor05, R.color.mircColor06, R.color.mircColor07, + R.color.mircColor08, R.color.mircColor09, R.color.mircColor10, R.color.mircColor11, + R.color.mircColor12, R.color.mircColor13, R.color.mircColor14, R.color.mircColor15, + R.color.mircColor16, R.color.mircColor17, R.color.mircColor18, R.color.mircColor19, + R.color.mircColor20, R.color.mircColor21, R.color.mircColor22, R.color.mircColor23, + R.color.mircColor24, R.color.mircColor25, R.color.mircColor26, R.color.mircColor27, + R.color.mircColor28, R.color.mircColor29, R.color.mircColor30, R.color.mircColor31, + R.color.mircColor32, R.color.mircColor33, R.color.mircColor34, R.color.mircColor35, + R.color.mircColor36, R.color.mircColor37, R.color.mircColor38, R.color.mircColor39, + R.color.mircColor40, R.color.mircColor41, R.color.mircColor42, R.color.mircColor43, + R.color.mircColor44, R.color.mircColor45, R.color.mircColor46, R.color.mircColor47, + R.color.mircColor48, R.color.mircColor49, R.color.mircColor50, R.color.mircColor51, + R.color.mircColor52, R.color.mircColor53, R.color.mircColor54, R.color.mircColor55, + R.color.mircColor56, R.color.mircColor57, R.color.mircColor58, R.color.mircColor59, + R.color.mircColor60, R.color.mircColor61, R.color.mircColor62, R.color.mircColor63, + R.color.mircColor64, R.color.mircColor65, R.color.mircColor66, R.color.mircColor67, + R.color.mircColor68, R.color.mircColor69, R.color.mircColor70, R.color.mircColor71, + R.color.mircColor72, R.color.mircColor73, R.color.mircColor74, R.color.mircColor75, + R.color.mircColor76, R.color.mircColor77, R.color.mircColor78, R.color.mircColor79, + R.color.mircColor80, R.color.mircColor81, R.color.mircColor82, R.color.mircColor83, + R.color.mircColor84, R.color.mircColor85, R.color.mircColor86, R.color.mircColor87, + R.color.mircColor88, R.color.mircColor89, R.color.mircColor90, R.color.mircColor91, + R.color.mircColor92, R.color.mircColor93, R.color.mircColor94, R.color.mircColor95, + R.color.mircColor96, R.color.mircColor97, R.color.mircColor98 + ).map(context::getColorCompat).toIntArray() + ) /** * Function to handle mIRC formatted strings @@ -274,6 +277,8 @@ class IrcFormatDeserializer @Inject constructor(context: Context) { i++ } + plainText.append(str.substring(str.length - normalCount, str.length)) + // End all formatting tags if (bold != null) { if (colorize) bold.apply(plainText, plainText.length) @@ -296,7 +301,6 @@ class IrcFormatDeserializer @Inject constructor(context: Context) { if (hexColor != null) { if (colorize) hexColor.apply(plainText, plainText.length) } - plainText.append(str.substring(str.length - normalCount, str.length)) return plainText } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcBackgroundColorSpan.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcBackgroundColorSpan.kt index a7abfdf30d022fe337bea765164da22d5147ef69..7e3647364657339cf23030ce634ef1515894fca9 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcBackgroundColorSpan.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcBackgroundColorSpan.kt @@ -27,10 +27,26 @@ sealed class IrcBackgroundColorSpan<T : IrcBackgroundColorSpan<T>>(@ColorInt col class MIRC(private val mircColor: Int, @ColorInt color: Int) : IrcBackgroundColorSpan<MIRC>(color), Copyable<MIRC> { override fun copy() = MIRC(mircColor, backgroundColor) + override fun toString(): String { + return "IrcBackgroundColorSpan.MIRC(mircColor=$mircColor, color=${backgroundColor.toString(16)})" + } + + override fun equals(other: Any?) = when (other) { + is IrcBackgroundColorSpan.MIRC -> other.mircColor == mircColor + else -> false + } } class HEX(@ColorInt color: Int) : IrcBackgroundColorSpan<HEX>(color), Copyable<HEX> { override fun copy() = HEX(backgroundColor) + override fun toString(): String { + return "IrcBackgroundColorSpan.HEX(color=${backgroundColor.toString(16)})" + } + + override fun equals(other: Any?) = when (other) { + is IrcBackgroundColorSpan.HEX -> other.backgroundColor == backgroundColor + else -> false + } } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcBoldSpan.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcBoldSpan.kt index 1b77aa2c33947c22ca7c74075fff77d22e474979..c7c15509cec75f76f1de59388d33f8d2dfe0f8fa 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcBoldSpan.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcBoldSpan.kt @@ -24,4 +24,5 @@ import android.text.style.StyleSpan class IrcBoldSpan : StyleSpan(Typeface.BOLD), Copyable<IrcBoldSpan> { override fun copy() = IrcBoldSpan() + override fun equals(other: Any?) = other is IrcBoldSpan } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcForegroundColorSpan.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcForegroundColorSpan.kt index 6e327b829dd74df520360cd195bb168ad442b08d..c5d44080213b14ca5787e5236f8979088fe79d26 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcForegroundColorSpan.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcForegroundColorSpan.kt @@ -24,13 +24,31 @@ import androidx.annotation.ColorInt sealed class IrcForegroundColorSpan<T : IrcForegroundColorSpan<T>>(@ColorInt color: Int) : ForegroundColorSpan(color), Copyable<T> { + + class MIRC(private val mircColor: Int, @ColorInt color: Int) : IrcForegroundColorSpan<MIRC>(color), Copyable<MIRC> { override fun copy() = MIRC(mircColor, foregroundColor) + override fun toString(): String { + return "IrcForegroundColorSpan.MIRC(mircColor=$mircColor, color=${foregroundColor.toString(16)})" + } + + override fun equals(other: Any?) = when (other) { + is MIRC -> other.mircColor == mircColor + else -> false + } } class HEX(@ColorInt color: Int) : IrcForegroundColorSpan<HEX>(color), Copyable<HEX> { override fun copy() = HEX(foregroundColor) + override fun toString(): String { + return "IrcBackgroundColorSpan.HEX(color=${foregroundColor.toString(16)})" + } + + override fun equals(other: Any?) = when (other) { + is HEX -> other.foregroundColor == foregroundColor + else -> false + } } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcItalicSpan.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcItalicSpan.kt index 045a8691820aee9b7d823e988a2d2bbd39e58d9d..da4bdf1a60e3a0bb644692ff1a51337393e0e672 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcItalicSpan.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcItalicSpan.kt @@ -24,4 +24,5 @@ import android.text.style.StyleSpan class IrcItalicSpan : StyleSpan(Typeface.ITALIC), Copyable<IrcItalicSpan> { override fun copy() = IrcItalicSpan() + override fun equals(other: Any?) = other is IrcBoldSpan } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcMonospaceSpan.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcMonospaceSpan.kt index ffc54118a1d606f103842d8e0a94e09c40c458a8..ceee6d13979d6d6f9809774e1bc51aace9453cf8 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcMonospaceSpan.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcMonospaceSpan.kt @@ -23,4 +23,5 @@ import android.text.style.TypefaceSpan class IrcMonospaceSpan : TypefaceSpan("monospace"), Copyable<IrcMonospaceSpan> { override fun copy() = IrcMonospaceSpan() + override fun equals(other: Any?) = other is IrcBoldSpan } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcStrikethroughSpan.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcStrikethroughSpan.kt index 4d2d336fbc32163dad59f73e9553bbd347dcba9f..3d6a2b6de21633c577bbae0f5056add39672837b 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcStrikethroughSpan.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcStrikethroughSpan.kt @@ -23,4 +23,5 @@ import android.text.style.StrikethroughSpan class IrcStrikethroughSpan : StrikethroughSpan(), Copyable<IrcStrikethroughSpan> { override fun copy() = IrcStrikethroughSpan() + override fun equals(other: Any?) = other is IrcBoldSpan } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcUnderlineSpan.kt b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcUnderlineSpan.kt index 244c3ea3c4b62c01ad6554ab97e7f7cfeb2d6303..419db043933b99cd1f5bc7446b38a8c9f3adb8f2 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcUnderlineSpan.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/irc/format/spans/IrcUnderlineSpan.kt @@ -23,4 +23,5 @@ import android.text.style.UnderlineSpan class IrcUnderlineSpan : UnderlineSpan(), Copyable<IrcUnderlineSpan> { override fun copy() = IrcUnderlineSpan() + override fun equals(other: Any?) = other is IrcBoldSpan } diff --git a/app/src/test/java/de/kuschku/quasseldroid/QuasseldroidTest.kt b/app/src/test/java/de/kuschku/quasseldroid/QuasseldroidTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..5f0b57dc69da0df35c280e5de7a147931f5362b7 --- /dev/null +++ b/app/src/test/java/de/kuschku/quasseldroid/QuasseldroidTest.kt @@ -0,0 +1,26 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid + +class QuasseldroidTest : Quasseldroid() { + override fun init() { + applicationInjector().inject(this) + } +} diff --git a/app/src/test/java/de/kuschku/quasseldroid/util/irc/format/IrcFormatDeserializerTest.kt b/app/src/test/java/de/kuschku/quasseldroid/util/irc/format/IrcFormatDeserializerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..93e7a85759f242ba92b57d186d4d8869ab636f64 --- /dev/null +++ b/app/src/test/java/de/kuschku/quasseldroid/util/irc/format/IrcFormatDeserializerTest.kt @@ -0,0 +1,202 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.util.irc.format + +import android.text.Spanned +import android.text.SpannedString +import de.kuschku.quasseldroid.QuasseldroidTest +import de.kuschku.quasseldroid.util.irc.format.spans.IrcBackgroundColorSpan +import de.kuschku.quasseldroid.util.irc.format.spans.IrcForegroundColorSpan +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@Config(application = QuasseldroidTest::class) +@RunWith(RobolectricTestRunner::class) +class IrcFormatDeserializerTest { + lateinit var deserializer: IrcFormatDeserializer + + @Before + fun setUp() { + deserializer = IrcFormatDeserializer(mircColors = colors) + } + + @Test + fun testMissingEndTag() { + val text = SpannedString.valueOf(deserializer.formatString( + "\u000301,01weeeeeeeeee", + colorize = true + )) + assertEquals( + listOf( + SpanInfo( + from = 0, + to = 11, + flags = Spanned.SPAN_INCLUSIVE_EXCLUSIVE, + span = IrcForegroundColorSpan.MIRC(mircColor = 1, color = colors[1]) + ), + SpanInfo( + from = 0, + to = 11, + flags = Spanned.SPAN_INCLUSIVE_EXCLUSIVE, + span = IrcBackgroundColorSpan.MIRC(mircColor = 1, color = colors[1]) + ) + ), + text.allSpans<Any>() + ) + } + + inline fun <reified T> Spanned.allSpans(): List<SpanInfo> = + getSpans(0, length, T::class.java).map { + SpanInfo( + from = getSpanStart(it), + to = getSpanEnd(it), + flags = getSpanFlags(it), + span = it + ) + } + + data class SpanInfo( + val from: Int, + val to: Int, + val flags: Int, + val span: Any? + ) + + companion object { + val colors = intArrayOf( + 0x00ffffff, + 0x00000000, + 0x00000080, + 0x00008000, + 0x00ff0000, + 0x00800000, + 0x00800080, + 0x00ffa500, + 0x00ffff00, + 0x0000ff00, + 0x00008080, + 0x0000ffff, + 0x004169e1, + 0x00ff00ff, + 0x00808080, + 0x00c0c0c0, + + 0x00470000, + 0x00740000, + 0x00b50000, + 0x00ff0000, + 0x00ff5959, + 0x00ff9c9c, + + 0x00472100, + 0x00743a00, + 0x00b56300, + 0x00ff8c00, + 0x00ffb459, + 0x00ffd39c, + + 0x00474700, + 0x00747400, + 0x00b5b500, + 0x00ffff00, + 0x00ffff71, + 0x00ffff9c, + + 0x00324700, + 0x00517400, + 0x007db500, + 0x00b2ff00, + 0x00cfff60, + 0x00e2ff9c, + + 0x00004700, + 0x00007400, + 0x0000b500, + 0x0000ff00, + 0x006fff6f, + 0x009cff9c, + + 0x0000472c, + 0x00007449, + 0x0000b571, + 0x0000ffa0, + 0x0065ffc9, + 0x009cffdb, + + 0x00004747, + 0x00007474, + 0x0000b5b5, + 0x0000ffff, + 0x006dffff, + 0x009cffff, + + 0x00002747, + 0x00004074, + 0x000063b5, + 0x00008cff, + 0x0059b4ff, + 0x009cd3ff, + + 0x00000047, + 0x00000074, + 0x000000b5, + 0x000000ff, + 0x005959ff, + 0x009c9cff, + + 0x002e0047, + 0x004b0074, + 0x007500b5, + 0x00a500ff, + 0x00c459ff, + 0x00dc9cff, + + 0x00470047, + 0x00740074, + 0x00b500b5, + 0x00ff00ff, + 0x00ff66ff, + 0x00ff9cff, + + 0x0047002a, + 0x00740045, + 0x00b5006b, + 0x00ff0098, + 0x00ff59bc, + 0x00ff94d3, + + 0x00000000, + 0x00131313, + 0x00282828, + 0x00363636, + 0x004d4d4d, + 0x00656565, + 0x00818181, + 0x009f9f9f, + 0x00bcbcbc, + 0x00e2e2e2, + 0x00ffffff + ) + } +} diff --git a/gradle.properties b/gradle.properties index bf7e5319a66eb5f9f920e2f2168da74a37d77a1c..9450fb27e58f74bd03a6d7ecaafa99f49a186751 100644 --- a/gradle.properties +++ b/gradle.properties @@ -33,7 +33,7 @@ android.enableD8=true # Enable new Android R8 Optimizer android.enableR8=true # Enable gradle build cache -org.gradle.caching=false +org.gradle.caching=true # Enable android build cache android.enableBuildCache=true # Enable AndroidX