Merge branch 'develop' into feature/aris/threads

This commit is contained in:
ariskotsomitopoulos 2021-12-21 13:24:03 +02:00
commit 7048080ee0
19 changed files with 116 additions and 55 deletions

View file

@ -1,3 +1,28 @@
Changes in Element v1.3.12 (2021-12-20)
=======================================
Bugfixes 🐛
----------
- Fixing emoji related crashes on android 8.1.1 and below ([#4769](https://github.com/vector-im/element-android/issues/4769))
Changes in Element v1.3.11 (2021-12-17)
=======================================
Bugfixes 🐛
----------
- Fixing proximity sensor still being active after a call ([#2467](https://github.com/vector-im/element-android/issues/2467))
- Fix name and shield are truncated in the room detail screen ([#4700](https://github.com/vector-im/element-android/issues/4700))
- Call banner: center text vertically ([#4710](https://github.com/vector-im/element-android/issues/4710))
- Fixes unable to render messages by allowing them to render whilst the emoji library is initialising ([#4733](https://github.com/vector-im/element-android/issues/4733))
- Fix app crash uppon long press on a reply event ([#4742](https://github.com/vector-im/element-android/issues/4742))
- Fixes crash when launching rooms which contain emojis in the emote content on android 12+ ([#4743](https://github.com/vector-im/element-android/issues/4743))
Other changes
-------------
- Avoids leaking the activity windows when loading dialogs are displaying ([#4713](https://github.com/vector-im/element-android/issues/4713))
Changes in Element v1.3.10 (2021-12-14)
=======================================

View file

@ -1 +0,0 @@
Fixing proximity sensor still being active after a call

View file

@ -1 +0,0 @@
Call banner: center text vertically

View file

@ -1 +0,0 @@
Avoids leaking the activity windows when loading dialogs are displaying

View file

@ -1 +0,0 @@
Fix app crash uppon long press on a reply event

View file

@ -0,0 +1,2 @@
Main changes in this version: Bug fixes!
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.11

View file

@ -0,0 +1,2 @@
Main changes in this version: Bug fixes!
Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.12

View file

@ -31,7 +31,7 @@ android {
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
buildConfigField "String", "SDK_VERSION", "\"1.3.11\""
buildConfigField "String", "SDK_VERSION", "\"1.3.13\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
resValue "string", "git_sdk_revision", "\"${gitRevision()}\""

View file

@ -15,7 +15,7 @@ kapt {
// Note: 2 digits max for each value
ext.versionMajor = 1
ext.versionMinor = 3
ext.versionPatch = 11
ext.versionPatch = 13
static def getGitTimestamp() {
def cmd = 'git show -s --format=%ct'

View file

@ -24,6 +24,7 @@ import android.text.Spanned
import android.text.style.ForegroundColorSpan
import android.text.style.StrikethroughSpan
import android.text.style.UnderlineSpan
import androidx.emoji2.text.EmojiCompat
import im.vector.app.InstrumentedTest
import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldBeTrue
@ -32,12 +33,18 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class SpanUtilsTest : InstrumentedTest {
private val spanUtils = SpanUtils()
private val spanUtils = SpanUtils {
val emojiCompat = EmojiCompat.get()
emojiCompat.waitForInit()
emojiCompat.process(it) ?: it
}
private fun SpanUtils.canUseTextFuture(message: CharSequence): Boolean {
return getBindingOptions(message).canUseTextFuture
@ -122,4 +129,17 @@ class SpanUtilsTest : InstrumentedTest {
}
private fun trueIfAlwaysAllowed() = Build.VERSION.SDK_INT < Build.VERSION_CODES.P
private fun EmojiCompat.waitForInit() {
val latch = CountDownLatch(1)
registerInitCallback(object : EmojiCompat.InitCallback() {
override fun onInitialized() = latch.countDown()
override fun onFailed(throwable: Throwable?) {
latch.countDown()
throw RuntimeException(throwable)
}
})
EmojiCompat.init(context())
latch.await(30, TimeUnit.SECONDS)
}
}

View file

@ -23,8 +23,12 @@ import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
fun interface EmojiSpanify {
fun spanify(sequence: CharSequence): CharSequence
}
@Singleton
class EmojiCompatWrapper @Inject constructor(private val context: Context) {
class EmojiCompatWrapper @Inject constructor(private val context: Context) : EmojiSpanify {
private var initialized = false
@ -49,7 +53,7 @@ class EmojiCompatWrapper @Inject constructor(private val context: Context) {
})
}
fun safeEmojiSpanify(sequence: CharSequence): CharSequence {
override fun spanify(sequence: CharSequence): CharSequence {
if (initialized) {
try {
return EmojiCompat.get().process(sequence) ?: sequence

View file

@ -26,6 +26,8 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import im.vector.app.EmojiCompatWrapper
import im.vector.app.EmojiSpanify
import im.vector.app.core.dispatchers.CoroutineDispatchers
import im.vector.app.core.error.DefaultErrorFormatter
import im.vector.app.core.error.ErrorFormatter
@ -76,6 +78,9 @@ abstract class VectorBindModule {
@Binds
abstract fun bindDefaultClock(clock: DefaultClock): Clock
@Binds
abstract fun bindEmojiSpanify(emojiCompatWrapper: EmojiCompatWrapper): EmojiSpanify
}
@InstallIn(SingletonComponent::class)

View file

@ -620,7 +620,7 @@ class MessageItemFactory @Inject constructor(
val formattedBody = SpannableStringBuilder()
formattedBody.append("* ${informationData.memberName} ")
formattedBody.append(messageContent.getHtmlBody())
val bindingOptions = spanUtils.getBindingOptions(formattedBody)
val message = formattedBody.linkify(callback)
return MessageTextItem_()
@ -632,6 +632,7 @@ class MessageItemFactory @Inject constructor(
message(message)
}
}
.bindingOptions(bindingOptions)
.leftGuideline(avatarSizeProvider.leftGuideline)
.previewUrlRetriever(callback?.getPreviewUrlRetriever())
.imageContentRenderer(imageContentRenderer)

View file

@ -17,7 +17,7 @@
package im.vector.app.features.home.room.detail.timeline.format
import dagger.Lazy
import im.vector.app.EmojiCompatWrapper
import im.vector.app.EmojiSpanify
import im.vector.app.R
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.resources.StringProvider
@ -39,7 +39,7 @@ import javax.inject.Inject
class DisplayableEventFormatter @Inject constructor(
private val stringProvider: StringProvider,
private val colorProvider: ColorProvider,
private val emojiCompatWrapper: EmojiCompatWrapper,
private val emojiSpanify: EmojiSpanify,
private val noticeEventFormatter: NoticeEventFormatter,
private val htmlRenderer: Lazy<EventHtmlRenderer>
) {
@ -100,7 +100,7 @@ class DisplayableEventFormatter @Inject constructor(
}
EventType.REACTION -> {
timelineEvent.root.getClearContent().toModel<ReactionContent>()?.relatesTo?.let {
val emojiSpanned = emojiCompatWrapper.safeEmojiSpanify(stringProvider.getString(R.string.sent_a_reaction, it.key))
val emojiSpanned = emojiSpanify.spanify(stringProvider.getString(R.string.sent_a_reaction, it.key))
simpleFormat(senderName, emojiSpanned, appendAuthor)
} ?: span { }
}

View file

@ -20,7 +20,7 @@ import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Success
import im.vector.app.EmojiCompatWrapper
import im.vector.app.EmojiSpanify
import im.vector.app.R
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.ui.list.genericFooterItem
@ -32,8 +32,8 @@ import javax.inject.Inject
*/
class ViewReactionsEpoxyController @Inject constructor(
private val stringProvider: StringProvider,
private val emojiCompatWrapper: EmojiCompatWrapper) :
TypedEpoxyController<DisplayReactionsViewState>() {
private val emojiSpanify: EmojiSpanify) :
TypedEpoxyController<DisplayReactionsViewState>() {
var listener: Listener? = null
@ -56,7 +56,7 @@ class ViewReactionsEpoxyController @Inject constructor(
reactionInfoSimpleItem {
id(reactionInfo.eventId)
timeStamp(reactionInfo.timestamp)
reactionKey(host.emojiCompatWrapper.safeEmojiSpanify(reactionInfo.reactionKey))
reactionKey(host.emojiSpanify.spanify(reactionInfo.reactionKey))
authorDisplayName(reactionInfo.authorName ?: reactionInfo.authorId)
userClicked { host.listener?.didSelectUser(reactionInfo.authorId) }
}

View file

@ -45,6 +45,7 @@ fun CharSequence.findPillsAndProcess(scope: CoroutineScope, processBlock: (PillI
fun CharSequence.linkify(callback: TimelineEventController.UrlClickCallback?): CharSequence {
val text = this.toString()
// SpannableStringBuilder is used to avoid Epoxy throwing ImmutableModelException
val spannable = SpannableStringBuilder(this)
MatrixLinkify.addLinks(spannable, object : MatrixPermalinkSpan.Callback {
override fun onUrlClicked(url: String) {

View file

@ -16,18 +16,19 @@
package im.vector.app.features.html
import android.os.Build
import android.text.Spanned
import android.text.style.MetricAffectingSpan
import android.text.style.StrikethroughSpan
import android.text.style.UnderlineSpan
import androidx.emoji2.text.EmojiCompat
import im.vector.app.EmojiSpanify
import im.vector.app.features.home.room.detail.timeline.item.BindingOptions
import javax.inject.Inject
class SpanUtils @Inject constructor() {
class SpanUtils @Inject constructor(
private val emojiSpanify: EmojiSpanify
) {
fun getBindingOptions(charSequence: CharSequence): BindingOptions {
val emojiCharSequence = EmojiCompat.get().process(charSequence)
val emojiCharSequence = emojiSpanify.spanify(charSequence)
if (emojiCharSequence !is Spanned) {
return BindingOptions()
@ -39,13 +40,11 @@ class SpanUtils @Inject constructor() {
)
}
// Workaround for https://issuetracker.google.com/issues/188454876
/**
* TextFutures do not support StrikethroughSpan, UnderlineSpan or MetricAffectingSpan
* Workaround for https://issuetracker.google.com/issues/188454876
*/
private fun canUseTextFuture(spanned: Spanned): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
// On old devices, it works correctly
return true
}
return spanned
.getSpans(0, spanned.length, Any::class.java)
.all { it !is StrikethroughSpan && it !is UnderlineSpan && it !is MetricAffectingSpan }

View file

@ -24,7 +24,7 @@ import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.core.content.withStyledAttributes
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.EmojiCompatWrapper
import im.vector.app.EmojiSpanify
import im.vector.app.R
import im.vector.app.core.utils.DimensionConverter
import im.vector.app.core.utils.TextUtils
@ -39,9 +39,9 @@ import javax.inject.Inject
class ReactionButton @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0) :
LinearLayout(context, attrs, defStyleAttr), View.OnClickListener, View.OnLongClickListener {
LinearLayout(context, attrs, defStyleAttr), View.OnClickListener, View.OnLongClickListener {
@Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper
@Inject lateinit var emojiSpanify: EmojiSpanify
private val views: ReactionButtonBinding
@ -57,7 +57,7 @@ class ReactionButton @JvmOverloads constructor(context: Context,
set(value) {
field = value
// maybe cache this for performances?
val emojiSpanned = emojiCompatWrapper.safeEmojiSpanify(value)
val emojiSpanned = emojiSpanify.spanify(value)
views.reactionText.text = emojiSpanned
}

View file

@ -12,8 +12,8 @@
android:id="@+id/memberProfileInfoContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toTopOf="@id/memberProfileNameView"
app:layout_constraintTop_toTopOf="@id/memberProfileNameView">
@ -23,7 +23,7 @@
android:layout_height="128dp"
android:layout_marginBottom="16dp"
android:contentDescription="@string/avatar"
app:layout_constraintBottom_toTopOf="@id/memberProfileNameView"
app:layout_constraintBottom_toTopOf="@id/memberProfileLinearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -45,30 +45,36 @@
tools:src="@drawable/ic_presence_offline"
tools:visibility="visible" />
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/memberProfileDecorationImageView"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="@id/memberProfileNameView"
app:layout_constraintEnd_toStartOf="@id/memberProfileNameView"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/memberProfileNameView" />
<TextView
android:id="@+id/memberProfileNameView"
style="@style/Widget.Vector.TextView.Title"
android:layout_width="wrap_content"
<LinearLayout
android:id="@+id/memberProfileLinearLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textStyle="bold"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@id/memberProfileIdView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/memberProfileDecorationImageView"
app:layout_constraintTop_toBottomOf="@id/memberProfileAvatarView"
tools:text="@sample/users.json/data/displayName" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/memberProfileAvatarView">
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/memberProfileDecorationImageView"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="8dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp" />
<TextView
android:id="@+id/memberProfileNameView"
style="@style/Widget.Vector.TextView.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:gravity="center"
android:textStyle="bold"
tools:text="@sample/users.json/data/displayName" />
</LinearLayout>
<TextView
android:id="@+id/memberProfileIdView"
@ -82,7 +88,7 @@
app:layout_constraintBottom_toTopOf="@id/memberProfilePowerLevelView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/memberProfileNameView"
app:layout_constraintTop_toBottomOf="@id/memberProfileLinearLayout"
tools:text="@sample/users.json/data/id" />
<TextView