mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 21:48:50 +03:00
Merge branch 'release/1.3.11' into main
This commit is contained in:
commit
cab28ffe7e
20 changed files with 117 additions and 60 deletions
17
CHANGES.md
17
CHANGES.md
|
@ -1,3 +1,20 @@
|
||||||
|
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)
|
Changes in Element v1.3.10 (2021-12-14)
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
|
|
2
fastlane/metadata/android/en-US/changelogs/40103110.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/40103110.txt
Normal 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
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=b75392c5625a88bccd58a574552a5a323edca82dab5942d2d41097f809c6bcce
|
distributionSha256Sum=dd54e87b4d7aa8ff3c6afb0f7805aa121d4b70bca55b8c9b1b896eb103184582
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
@ -31,7 +31,7 @@ android {
|
||||||
// that the app's state is completely cleared between tests.
|
// that the app's state is completely cleared between tests.
|
||||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||||
|
|
||||||
buildConfigField "String", "SDK_VERSION", "\"1.3.10\""
|
buildConfigField "String", "SDK_VERSION", "\"1.3.11\""
|
||||||
|
|
||||||
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
|
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
|
||||||
resValue "string", "git_sdk_revision", "\"${gitRevision()}\""
|
resValue "string", "git_sdk_revision", "\"${gitRevision()}\""
|
||||||
|
|
|
@ -17,7 +17,7 @@ PARAM_KEYSTORE_PATH=$1
|
||||||
PARAM_APK=$2
|
PARAM_APK=$2
|
||||||
|
|
||||||
# Other params
|
# Other params
|
||||||
BUILD_TOOLS_VERSION="31.0.0-rc5"
|
BUILD_TOOLS_VERSION="31.0.0"
|
||||||
MIN_SDK_VERSION=21
|
MIN_SDK_VERSION=21
|
||||||
|
|
||||||
echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..."
|
echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..."
|
||||||
|
|
|
@ -23,7 +23,7 @@ PARAM_KS_PASS=$3
|
||||||
PARAM_KEY_PASS=$4
|
PARAM_KEY_PASS=$4
|
||||||
|
|
||||||
# Other params
|
# Other params
|
||||||
BUILD_TOOLS_VERSION="31.0.0-rc5"
|
BUILD_TOOLS_VERSION="31.0.0"
|
||||||
MIN_SDK_VERSION=21
|
MIN_SDK_VERSION=21
|
||||||
|
|
||||||
echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..."
|
echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..."
|
||||||
|
|
|
@ -15,7 +15,7 @@ kapt {
|
||||||
// Note: 2 digits max for each value
|
// Note: 2 digits max for each value
|
||||||
ext.versionMajor = 1
|
ext.versionMajor = 1
|
||||||
ext.versionMinor = 3
|
ext.versionMinor = 3
|
||||||
ext.versionPatch = 10
|
ext.versionPatch = 11
|
||||||
|
|
||||||
static def getGitTimestamp() {
|
static def getGitTimestamp() {
|
||||||
def cmd = 'git show -s --format=%ct'
|
def cmd = 'git show -s --format=%ct'
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.text.Spanned
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
import android.text.style.StrikethroughSpan
|
import android.text.style.StrikethroughSpan
|
||||||
import android.text.style.UnderlineSpan
|
import android.text.style.UnderlineSpan
|
||||||
|
import androidx.emoji2.text.EmojiCompat
|
||||||
import im.vector.app.InstrumentedTest
|
import im.vector.app.InstrumentedTest
|
||||||
import org.amshove.kluent.shouldBeEqualTo
|
import org.amshove.kluent.shouldBeEqualTo
|
||||||
import org.amshove.kluent.shouldBeTrue
|
import org.amshove.kluent.shouldBeTrue
|
||||||
|
@ -32,12 +33,18 @@ import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.junit.runners.JUnit4
|
import org.junit.runners.JUnit4
|
||||||
import org.junit.runners.MethodSorters
|
import org.junit.runners.MethodSorters
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@RunWith(JUnit4::class)
|
@RunWith(JUnit4::class)
|
||||||
@FixMethodOrder(MethodSorters.JVM)
|
@FixMethodOrder(MethodSorters.JVM)
|
||||||
class SpanUtilsTest : InstrumentedTest {
|
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 {
|
private fun SpanUtils.canUseTextFuture(message: CharSequence): Boolean {
|
||||||
return getBindingOptions(message).canUseTextFuture
|
return getBindingOptions(message).canUseTextFuture
|
||||||
|
@ -122,4 +129,17 @@ class SpanUtilsTest : InstrumentedTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun trueIfAlwaysAllowed() = Build.VERSION.SDK_INT < Build.VERSION_CODES.P
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,12 @@ import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
fun interface EmojiSpanify {
|
||||||
|
fun spanify(sequence: CharSequence): CharSequence
|
||||||
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class EmojiCompatWrapper @Inject constructor(private val context: Context) {
|
class EmojiCompatWrapper @Inject constructor(private val context: Context) : EmojiSpanify {
|
||||||
|
|
||||||
private var initialized = false
|
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) {
|
if (initialized) {
|
||||||
try {
|
try {
|
||||||
return EmojiCompat.get().process(sequence) ?: sequence
|
return EmojiCompat.get().process(sequence) ?: sequence
|
||||||
|
|
|
@ -26,6 +26,8 @@ import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.components.SingletonComponent
|
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.dispatchers.CoroutineDispatchers
|
||||||
import im.vector.app.core.error.DefaultErrorFormatter
|
import im.vector.app.core.error.DefaultErrorFormatter
|
||||||
import im.vector.app.core.error.ErrorFormatter
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
|
@ -76,6 +78,9 @@ abstract class VectorBindModule {
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindDefaultClock(clock: DefaultClock): Clock
|
abstract fun bindDefaultClock(clock: DefaultClock): Clock
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindEmojiSpanify(emojiCompatWrapper: EmojiCompatWrapper): EmojiSpanify
|
||||||
}
|
}
|
||||||
|
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
|
|
|
@ -151,6 +151,7 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
Timber.i("onDestroyView Fragment ${javaClass.simpleName}")
|
Timber.i("onDestroyView Fragment ${javaClass.simpleName}")
|
||||||
_binding = null
|
_binding = null
|
||||||
|
dismissLoadingDialog()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,9 @@ class CallProximityManager @Inject constructor(
|
||||||
if (wakeLock == null) {
|
if (wakeLock == null) {
|
||||||
wakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, generateWakeLockTag())
|
wakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, generateWakeLockTag())
|
||||||
}
|
}
|
||||||
wakeLock?.acquire(WAKE_LOCK_TIMEOUT_MILLIS)
|
wakeLock
|
||||||
|
?.takeIf { !it.isHeld }
|
||||||
|
?.acquire(WAKE_LOCK_TIMEOUT_MILLIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onProximityFar() {
|
private fun onProximityFar() {
|
||||||
|
|
|
@ -613,7 +613,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
val formattedBody = SpannableStringBuilder()
|
val formattedBody = SpannableStringBuilder()
|
||||||
formattedBody.append("* ${informationData.memberName} ")
|
formattedBody.append("* ${informationData.memberName} ")
|
||||||
formattedBody.append(messageContent.getHtmlBody())
|
formattedBody.append(messageContent.getHtmlBody())
|
||||||
|
val bindingOptions = spanUtils.getBindingOptions(formattedBody)
|
||||||
val message = formattedBody.linkify(callback)
|
val message = formattedBody.linkify(callback)
|
||||||
|
|
||||||
return MessageTextItem_()
|
return MessageTextItem_()
|
||||||
|
@ -625,6 +625,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
message(message)
|
message(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bindingOptions(bindingOptions)
|
||||||
.leftGuideline(avatarSizeProvider.leftGuideline)
|
.leftGuideline(avatarSizeProvider.leftGuideline)
|
||||||
.previewUrlRetriever(callback?.getPreviewUrlRetriever())
|
.previewUrlRetriever(callback?.getPreviewUrlRetriever())
|
||||||
.imageContentRenderer(imageContentRenderer)
|
.imageContentRenderer(imageContentRenderer)
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
package im.vector.app.features.home.room.detail.timeline.format
|
package im.vector.app.features.home.room.detail.timeline.format
|
||||||
|
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import im.vector.app.EmojiCompatWrapper
|
import im.vector.app.EmojiSpanify
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
@ -39,7 +39,7 @@ import javax.inject.Inject
|
||||||
class DisplayableEventFormatter @Inject constructor(
|
class DisplayableEventFormatter @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider,
|
private val colorProvider: ColorProvider,
|
||||||
private val emojiCompatWrapper: EmojiCompatWrapper,
|
private val emojiSpanify: EmojiSpanify,
|
||||||
private val noticeEventFormatter: NoticeEventFormatter,
|
private val noticeEventFormatter: NoticeEventFormatter,
|
||||||
private val htmlRenderer: Lazy<EventHtmlRenderer>
|
private val htmlRenderer: Lazy<EventHtmlRenderer>
|
||||||
) {
|
) {
|
||||||
|
@ -100,7 +100,7 @@ class DisplayableEventFormatter @Inject constructor(
|
||||||
}
|
}
|
||||||
EventType.REACTION -> {
|
EventType.REACTION -> {
|
||||||
timelineEvent.root.getClearContent().toModel<ReactionContent>()?.relatesTo?.let {
|
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)
|
simpleFormat(senderName, emojiSpanned, appendAuthor)
|
||||||
} ?: span { }
|
} ?: span { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import com.airbnb.epoxy.TypedEpoxyController
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Incomplete
|
import com.airbnb.mvrx.Incomplete
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import im.vector.app.EmojiCompatWrapper
|
import im.vector.app.EmojiSpanify
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.ui.list.genericFooterItem
|
import im.vector.app.core.ui.list.genericFooterItem
|
||||||
|
@ -32,8 +32,8 @@ import javax.inject.Inject
|
||||||
*/
|
*/
|
||||||
class ViewReactionsEpoxyController @Inject constructor(
|
class ViewReactionsEpoxyController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val emojiCompatWrapper: EmojiCompatWrapper) :
|
private val emojiSpanify: EmojiSpanify) :
|
||||||
TypedEpoxyController<DisplayReactionsViewState>() {
|
TypedEpoxyController<DisplayReactionsViewState>() {
|
||||||
|
|
||||||
var listener: Listener? = null
|
var listener: Listener? = null
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class ViewReactionsEpoxyController @Inject constructor(
|
||||||
reactionInfoSimpleItem {
|
reactionInfoSimpleItem {
|
||||||
id(reactionInfo.eventId)
|
id(reactionInfo.eventId)
|
||||||
timeStamp(reactionInfo.timestamp)
|
timeStamp(reactionInfo.timestamp)
|
||||||
reactionKey(host.emojiCompatWrapper.safeEmojiSpanify(reactionInfo.reactionKey))
|
reactionKey(host.emojiSpanify.spanify(reactionInfo.reactionKey))
|
||||||
authorDisplayName(reactionInfo.authorName ?: reactionInfo.authorId)
|
authorDisplayName(reactionInfo.authorName ?: reactionInfo.authorId)
|
||||||
userClicked { host.listener?.didSelectUser(reactionInfo.authorId) }
|
userClicked { host.listener?.didSelectUser(reactionInfo.authorId) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.app.features.home.room.detail.timeline.tools
|
package im.vector.app.features.home.room.detail.timeline.tools
|
||||||
|
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
import android.text.style.ClickableSpan
|
import android.text.style.ClickableSpan
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
@ -44,7 +45,8 @@ fun CharSequence.findPillsAndProcess(scope: CoroutineScope, processBlock: (PillI
|
||||||
|
|
||||||
fun CharSequence.linkify(callback: TimelineEventController.UrlClickCallback?): CharSequence {
|
fun CharSequence.linkify(callback: TimelineEventController.UrlClickCallback?): CharSequence {
|
||||||
val text = this.toString()
|
val text = this.toString()
|
||||||
val spannable = toSpannable()
|
// SpannableStringBuilder is used to avoid Epoxy throwing ImmutableModelException
|
||||||
|
val spannable = SpannableStringBuilder(this)
|
||||||
MatrixLinkify.addLinks(spannable, object : MatrixPermalinkSpan.Callback {
|
MatrixLinkify.addLinks(spannable, object : MatrixPermalinkSpan.Callback {
|
||||||
override fun onUrlClicked(url: String) {
|
override fun onUrlClicked(url: String) {
|
||||||
callback?.onUrlClicked(url, text)
|
callback?.onUrlClicked(url, text)
|
||||||
|
|
|
@ -21,13 +21,15 @@ import android.text.Spanned
|
||||||
import android.text.style.MetricAffectingSpan
|
import android.text.style.MetricAffectingSpan
|
||||||
import android.text.style.StrikethroughSpan
|
import android.text.style.StrikethroughSpan
|
||||||
import android.text.style.UnderlineSpan
|
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 im.vector.app.features.home.room.detail.timeline.item.BindingOptions
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SpanUtils @Inject constructor() {
|
class SpanUtils @Inject constructor(
|
||||||
|
private val emojiSpanify: EmojiSpanify
|
||||||
|
) {
|
||||||
fun getBindingOptions(charSequence: CharSequence): BindingOptions {
|
fun getBindingOptions(charSequence: CharSequence): BindingOptions {
|
||||||
val emojiCharSequence = EmojiCompat.get().process(charSequence)
|
val emojiCharSequence = emojiSpanify.spanify(charSequence)
|
||||||
|
|
||||||
if (emojiCharSequence !is Spanned) {
|
if (emojiCharSequence !is Spanned) {
|
||||||
return BindingOptions()
|
return BindingOptions()
|
||||||
|
|
|
@ -24,7 +24,7 @@ import android.widget.LinearLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.withStyledAttributes
|
import androidx.core.content.withStyledAttributes
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.EmojiCompatWrapper
|
import im.vector.app.EmojiSpanify
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.utils.DimensionConverter
|
import im.vector.app.core.utils.DimensionConverter
|
||||||
import im.vector.app.core.utils.TextUtils
|
import im.vector.app.core.utils.TextUtils
|
||||||
|
@ -39,9 +39,9 @@ import javax.inject.Inject
|
||||||
class ReactionButton @JvmOverloads constructor(context: Context,
|
class ReactionButton @JvmOverloads constructor(context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0) :
|
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
|
private val views: ReactionButtonBinding
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ class ReactionButton @JvmOverloads constructor(context: Context,
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
// maybe cache this for performances?
|
// maybe cache this for performances?
|
||||||
val emojiSpanned = emojiCompatWrapper.safeEmojiSpanify(value)
|
val emojiSpanned = emojiSpanify.spanify(value)
|
||||||
views.reactionText.text = emojiSpanned
|
views.reactionText.text = emojiSpanned
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,20 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?colorPrimary"
|
|
||||||
android:foreground="?attr/selectableItemBackground"
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
tools:background="?colorPrimary"
|
||||||
tools:parentTag="android.widget.FrameLayout">
|
tools:parentTag="android.widget.FrameLayout">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/currentCallsInfo"
|
android:id="@+id/currentCallsInfo"
|
||||||
style="@style/Widget.Vector.TextView.Body"
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:drawablePadding="10dp"
|
android:layout_gravity="center"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingTop="12dp"
|
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
android:paddingBottom="12dp"
|
android:textColor="?colorOnPrimary"
|
||||||
android:text="@string/call_only_active"
|
tools:text="@string/call_only_active" />
|
||||||
android:textColor="?colorOnPrimary" />
|
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
android:id="@+id/memberProfileInfoContainer"
|
android:id="@+id/memberProfileInfoContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:paddingEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
app:layout_constraintBottom_toTopOf="@id/memberProfileNameView"
|
app:layout_constraintBottom_toTopOf="@id/memberProfileNameView"
|
||||||
app:layout_constraintTop_toTopOf="@id/memberProfileNameView">
|
app:layout_constraintTop_toTopOf="@id/memberProfileNameView">
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
android:layout_height="128dp"
|
android:layout_height="128dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:contentDescription="@string/avatar"
|
android:contentDescription="@string/avatar"
|
||||||
app:layout_constraintBottom_toTopOf="@id/memberProfileNameView"
|
app:layout_constraintBottom_toTopOf="@id/memberProfileLinearLayout"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
@ -45,30 +45,36 @@
|
||||||
tools:src="@drawable/ic_presence_offline"
|
tools:src="@drawable/ic_presence_offline"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.ShieldImageView
|
<LinearLayout
|
||||||
android:id="@+id/memberProfileDecorationImageView"
|
android:id="@+id/memberProfileLinearLayout"
|
||||||
android:layout_width="30dp"
|
android:layout_width="0dp"
|
||||||
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"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:textStyle="bold"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintBottom_toTopOf="@id/memberProfileIdView"
|
app:layout_constraintBottom_toTopOf="@id/memberProfileIdView"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/memberProfileDecorationImageView"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/memberProfileAvatarView"
|
app:layout_constraintTop_toBottomOf="@id/memberProfileAvatarView">
|
||||||
tools:text="@sample/users.json/data/displayName" />
|
|
||||||
|
<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
|
<TextView
|
||||||
android:id="@+id/memberProfileIdView"
|
android:id="@+id/memberProfileIdView"
|
||||||
|
@ -82,7 +88,7 @@
|
||||||
app:layout_constraintBottom_toTopOf="@id/memberProfilePowerLevelView"
|
app:layout_constraintBottom_toTopOf="@id/memberProfilePowerLevelView"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="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" />
|
tools:text="@sample/users.json/data/id" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
Loading…
Reference in a new issue