forked from GitHub-Mirror/riotX-android
Compare commits
13 Commits
feature/fi
...
feature/in
Author | SHA1 | Date | |
---|---|---|---|
982331e47c | |||
cbc08d834b | |||
0ab6b33fb6 | |||
1b394527b6 | |||
a8f1388721 | |||
166be4e289 | |||
b49ccefe63 | |||
825760d17e | |||
b5af62c3ea | |||
a51d96bf00 | |||
7e142d201d | |||
2be6058971 | |||
49d73f360e |
@ -5,15 +5,17 @@ Features:
|
||||
- Display read receipts in timeline (#81)
|
||||
|
||||
Improvements:
|
||||
-
|
||||
- Reactions: Reinstate the ability to react with non-unicode keys (#307)
|
||||
|
||||
Other changes:
|
||||
-
|
||||
-
|
||||
|
||||
Bugfix:
|
||||
- Fix text diff linebreak display (#441)
|
||||
- Date change message repeats for each redaction until a normal message (#358)
|
||||
- Slide-in reply icon is distorted (#423)
|
||||
- Regression / e2e replies not encrypted
|
||||
- Some video won't play
|
||||
|
||||
Translations:
|
||||
-
|
||||
|
@ -29,10 +29,11 @@ data class RoomSummary(
|
||||
val topic: String = "",
|
||||
val avatarUrl: String = "",
|
||||
val isDirect: Boolean = false,
|
||||
val latestEvent: TimelineEvent? = null,
|
||||
val latestPreviewableEvent: TimelineEvent? = null,
|
||||
val otherMemberIds: List<String> = emptyList(),
|
||||
val notificationCount: Int = 0,
|
||||
val highlightCount: Int = 0,
|
||||
val hasUnreadMessages: Boolean = false,
|
||||
val tags: List<RoomTag> = emptyList(),
|
||||
val membership: Membership = Membership.NONE,
|
||||
val versioningState: VersioningState = VersioningState.NONE
|
||||
|
@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||
import im.vector.matrix.android.api.session.room.read.ReadService
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import java.util.*
|
||||
@ -30,12 +31,12 @@ internal class RoomSummaryMapper @Inject constructor(
|
||||
val timelineEventMapper: TimelineEventMapper
|
||||
) {
|
||||
|
||||
fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
|
||||
fun map(roomSummaryEntity: RoomSummaryEntity, readService: ReadService?): RoomSummary {
|
||||
val tags = roomSummaryEntity.tags.map {
|
||||
RoomTag(it.tagName, it.tagOrder)
|
||||
}
|
||||
|
||||
val latestEvent = roomSummaryEntity.latestEvent?.let {
|
||||
val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let {
|
||||
timelineEventMapper.map(it)
|
||||
}
|
||||
if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) {
|
||||
@ -43,26 +44,30 @@ internal class RoomSummaryMapper @Inject constructor(
|
||||
//for now decrypt sync
|
||||
try {
|
||||
val result = cryptoService.decryptEvent(latestEvent.root, latestEvent.root.roomId + UUID.randomUUID().toString())
|
||||
latestEvent.root.mxDecryptionResult = OlmDecryptionResult(
|
||||
payload = result.clearEvent,
|
||||
senderKey = result.senderCurve25519Key,
|
||||
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
|
||||
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
|
||||
)
|
||||
latestEvent.root.mxDecryptionResult = OlmDecryptionResult(
|
||||
payload = result.clearEvent,
|
||||
senderKey = result.senderCurve25519Key,
|
||||
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
|
||||
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
|
||||
)
|
||||
} catch (e: MXCryptoError) {
|
||||
|
||||
}
|
||||
}
|
||||
val hasUnreadMessages = roomSummaryEntity.notificationCount > 0
|
||||
//avoid this call if we are sure there are unread events
|
||||
|| latestEvent?.root?.eventId?.let { readService?.isEventRead(it)?.not() } ?: false
|
||||
return RoomSummary(
|
||||
roomId = roomSummaryEntity.roomId,
|
||||
displayName = roomSummaryEntity.displayName ?: "",
|
||||
topic = roomSummaryEntity.topic ?: "",
|
||||
avatarUrl = roomSummaryEntity.avatarUrl ?: "",
|
||||
isDirect = roomSummaryEntity.isDirect,
|
||||
latestEvent = latestEvent,
|
||||
latestPreviewableEvent = latestEvent,
|
||||
otherMemberIds = roomSummaryEntity.otherMemberIds.toList(),
|
||||
highlightCount = roomSummaryEntity.highlightCount,
|
||||
notificationCount = roomSummaryEntity.notificationCount,
|
||||
hasUnreadMessages = hasUnreadMessages,
|
||||
tags = tags,
|
||||
membership = roomSummaryEntity.membership,
|
||||
versioningState = roomSummaryEntity.versioningState
|
||||
|
@ -26,7 +26,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||
var displayName: String? = "",
|
||||
var avatarUrl: String? = "",
|
||||
var topic: String? = "",
|
||||
var latestEvent: TimelineEventEntity? = null,
|
||||
var latestPreviewableEvent: TimelineEventEntity? = null,
|
||||
var heroes: RealmList<String> = RealmList(),
|
||||
var joinedMembersCount: Int? = 0,
|
||||
var invitedMembersCount: Int? = 0,
|
||||
|
@ -58,7 +58,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME)
|
||||
}
|
||||
return Transformations.map(liveRealmData) { results ->
|
||||
val roomSummaries = results.map { roomSummaryMapper.map(it) }
|
||||
val roomSummaries = results.map { roomSummaryMapper.map(it, this) }
|
||||
|
||||
if (roomSummaries.isEmpty()) {
|
||||
// Create a dummy RoomSummary to avoid Crash during Sign Out or clear cache
|
||||
@ -72,7 +72,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
override fun roomSummary(): RoomSummary? {
|
||||
return monarchy.fetchAllMappedSync(
|
||||
{ realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
|
||||
{ roomSummaryMapper.map(it) }
|
||||
{ roomSummaryMapper.map(it, this) }
|
||||
).firstOrNull()
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.VersioningState
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.room.read.ReadService
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
@ -69,7 +70,7 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
||||
.isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME)
|
||||
.notEqualTo(RoomSummaryEntityFields.VERSIONING_STATE_STR, VersioningState.UPGRADED_ROOM_JOINED.name)
|
||||
},
|
||||
{ roomSummaryMapper.map(it) }
|
||||
{ roomSummaryMapper.map(it, getRoom(it.roomId)) }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
||||
roomSummaryEntity.membership = membership
|
||||
}
|
||||
|
||||
val latestEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, includedTypes = PREVIEWABLE_TYPES)
|
||||
val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, includedTypes = PREVIEWABLE_TYPES)
|
||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
|
||||
|
||||
val otherRoomMembers = RoomMembers(realm, roomId)
|
||||
@ -98,7 +98,7 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
||||
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
|
||||
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
|
||||
roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
|
||||
roomSummaryEntity.latestEvent = latestEvent
|
||||
roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent
|
||||
roomSummaryEntity.otherMemberIds.clear()
|
||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
|
||||
|
||||
|
@ -69,15 +69,11 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv
|
||||
.also {
|
||||
saveLocalEcho(it)
|
||||
}
|
||||
val sendRelationWork = createSendRelationWork(event)
|
||||
val sendRelationWork = createSendEventWork(event, true)
|
||||
TimelineSendEventWorkCommon.postWork(context, roomId, sendRelationWork)
|
||||
return CancelableWork(context, sendRelationWork.id)
|
||||
}
|
||||
|
||||
private fun createSendRelationWork(event: Event): OneTimeWorkRequest {
|
||||
return createSendEventWork(event)
|
||||
}
|
||||
|
||||
override fun undoReaction(reaction: String, targetEventId: String, myUserId: String)/*: Cancelable*/ {
|
||||
|
||||
val params = FindReactionEventForUndoTask.Params(
|
||||
@ -134,42 +130,42 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv
|
||||
.also {
|
||||
saveLocalEcho(it)
|
||||
}
|
||||
if (cryptoService.isRoomEncrypted(roomId)) {
|
||||
return if (cryptoService.isRoomEncrypted(roomId)) {
|
||||
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
|
||||
val workRequest = createSendEventWork(event)
|
||||
val workRequest = createSendEventWork(event, false)
|
||||
TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
|
||||
return CancelableWork(context, encryptWork.id)
|
||||
CancelableWork(context, encryptWork.id)
|
||||
|
||||
} else {
|
||||
val workRequest = createSendEventWork(event)
|
||||
val workRequest = createSendEventWork(event, true)
|
||||
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
|
||||
return CancelableWork(context, workRequest.id)
|
||||
CancelableWork(context, workRequest.id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun editReply(replyToEdit: TimelineEvent,
|
||||
originalEvent: TimelineEvent,
|
||||
originalTimelineEvent: TimelineEvent,
|
||||
newBodyText: String,
|
||||
compatibilityBodyText: String): Cancelable {
|
||||
val event = eventFactory
|
||||
.createReplaceTextOfReply(roomId,
|
||||
replyToEdit,
|
||||
originalEvent,
|
||||
newBodyText, true, MessageType.MSGTYPE_TEXT, compatibilityBodyText)
|
||||
replyToEdit,
|
||||
originalTimelineEvent,
|
||||
newBodyText, true, MessageType.MSGTYPE_TEXT, compatibilityBodyText)
|
||||
.also {
|
||||
saveLocalEcho(it)
|
||||
}
|
||||
if (cryptoService.isRoomEncrypted(roomId)) {
|
||||
return if (cryptoService.isRoomEncrypted(roomId)) {
|
||||
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
|
||||
val workRequest = createSendEventWork(event)
|
||||
val workRequest = createSendEventWork(event, false)
|
||||
TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
|
||||
return CancelableWork(context, encryptWork.id)
|
||||
CancelableWork(context, encryptWork.id)
|
||||
|
||||
} else {
|
||||
val workRequest = createSendEventWork(event)
|
||||
val workRequest = createSendEventWork(event, true)
|
||||
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
|
||||
return CancelableWork(context, workRequest.id)
|
||||
CancelableWork(context, workRequest.id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,16 +183,16 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv
|
||||
saveLocalEcho(it)
|
||||
} ?: return null
|
||||
|
||||
if (cryptoService.isRoomEncrypted(roomId)) {
|
||||
return if (cryptoService.isRoomEncrypted(roomId)) {
|
||||
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
|
||||
val workRequest = createSendEventWork(event)
|
||||
val workRequest = createSendEventWork(event, false)
|
||||
TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
|
||||
return CancelableWork(context, encryptWork.id)
|
||||
CancelableWork(context, encryptWork.id)
|
||||
|
||||
} else {
|
||||
val workRequest = createSendEventWork(event)
|
||||
val workRequest = createSendEventWork(event, true)
|
||||
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
|
||||
return CancelableWork(context, workRequest.id)
|
||||
CancelableWork(context, workRequest.id)
|
||||
}
|
||||
|
||||
}
|
||||
@ -208,10 +204,10 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv
|
||||
return TimelineSendEventWorkCommon.createWork<EncryptEventWorker>(sendWorkData, true)
|
||||
}
|
||||
|
||||
private fun createSendEventWork(event: Event): OneTimeWorkRequest {
|
||||
private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest {
|
||||
val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event)
|
||||
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||
return TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, true)
|
||||
return TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain)
|
||||
}
|
||||
|
||||
override fun getEventSummaryLive(eventId: String): LiveData<EventAnnotationsSummary> {
|
||||
@ -220,7 +216,7 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv
|
||||
}
|
||||
return Transformations.map(liveEntity) { realmResults ->
|
||||
realmResults.firstOrNull()?.asDomain()
|
||||
?: EventAnnotationsSummary(eventId, emptyList(), null)
|
||||
?: EventAnnotationsSummary(eventId, emptyList(), null)
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,7 +229,7 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv
|
||||
private fun saveLocalEcho(event: Event) {
|
||||
monarchy.writeAsync { realm ->
|
||||
val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst()
|
||||
?: return@writeAsync
|
||||
?: return@writeAsync
|
||||
roomEntity.addSendingEvent(event)
|
||||
}
|
||||
}
|
||||
|
@ -113,12 +113,12 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
||||
private fun handleJoinedRoom(realm: Realm,
|
||||
roomId: String,
|
||||
roomSync: RoomSync,
|
||||
isInitalSync: Boolean): RoomEntity {
|
||||
isInitialSync: Boolean): RoomEntity {
|
||||
|
||||
Timber.v("Handle join sync for room $roomId")
|
||||
|
||||
if (roomSync.ephemeral != null && roomSync.ephemeral.events.isNotEmpty()) {
|
||||
handleEphemeral(realm, roomId, roomSync.ephemeral, isInitalSync)
|
||||
handleEphemeral(realm, roomId, roomSync.ephemeral, isInitialSync)
|
||||
}
|
||||
|
||||
if (roomSync.accountData != null && roomSync.accountData.events.isNullOrEmpty().not()) {
|
||||
|
@ -318,6 +318,8 @@ dependencies {
|
||||
|
||||
implementation 'diff_match_patch:diff_match_patch:current'
|
||||
|
||||
implementation "androidx.emoji:emoji-appcompat:1.0.0"
|
||||
|
||||
// TESTS
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
|
@ -19,10 +19,13 @@ package im.vector.riotx
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import androidx.core.provider.FontRequest
|
||||
import androidx.core.provider.FontsContractCompat
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import androidx.emoji.text.FontRequestEmojiCompatConfig
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
@ -105,6 +108,23 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
||||
)
|
||||
FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler())
|
||||
vectorConfiguration.initConfiguration()
|
||||
|
||||
//Use emoji compat for the benefit of emoji spans
|
||||
val config = FontRequestEmojiCompatConfig(this, fontRequest)
|
||||
.setReplaceAll(true) // we want to replace all emojis with selected font
|
||||
// .setEmojiSpanIndicatorEnabled(true)
|
||||
// .setEmojiSpanIndicatorColor(Color.GREEN)
|
||||
EmojiCompat.init(config)
|
||||
.registerInitCallback(object : EmojiCompat.InitCallback() {
|
||||
override fun onInitialized() {
|
||||
Timber.v("Emoji compat onInitialized success ")
|
||||
}
|
||||
|
||||
override fun onFailed(throwable: Throwable?) {
|
||||
Timber.e(throwable,"Failed to init EmojiCompat")
|
||||
}
|
||||
})
|
||||
|
||||
NotificationUtils.createNotificationChannels(applicationContext)
|
||||
if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
|
||||
val lastAuthenticatedSession = authenticator.getLastAuthenticatedSession()!!
|
||||
|
@ -658,7 +658,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
private fun observeSummaryState() {
|
||||
asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary ->
|
||||
if (summary.membership == Membership.INVITE) {
|
||||
summary.latestEvent?.root?.senderId?.let { senderId ->
|
||||
summary.latestPreviewableEvent?.root?.senderId?.let { senderId ->
|
||||
session.getUser(senderId)
|
||||
}?.also {
|
||||
setState { copy(asyncInviter = Success(it)) }
|
||||
|
@ -69,7 +69,7 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
val dividerItemDecoration = DividerItemDecoration(epoxyRecyclerView.context,
|
||||
LinearLayout.VERTICAL)
|
||||
epoxyRecyclerView.addItemDecoration(dividerItemDecoration)
|
||||
bottomSheetTitle.text = getString(R.string.read_receipts_list)
|
||||
bottomSheetTitle.text = getString(R.string.read_at)
|
||||
epoxyController.setData(displayReadReceiptArgs.readReceipts)
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,6 @@ import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.canReact
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.core.utils.isSingleEmoji
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||
|
||||
|
||||
@ -244,7 +243,7 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
||||
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment
|
||||
if (event.root.getClearType() != EventType.MESSAGE) return false
|
||||
//TODO if user is admin or moderator
|
||||
return event.annotations?.reactionsSummary?.any { isSingleEmoji(it.key) } ?: false
|
||||
return event.annotations?.reactionsSummary?.isNotEmpty() ?: false
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,12 +38,8 @@ abstract class ReactionInfoSimpleItem : EpoxyModelWithHolder<ReactionInfoSimpleI
|
||||
@EpoxyAttribute
|
||||
var timeStamp: CharSequence? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var emojiTypeFace: Typeface? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
holder.emojiReactionView.text = reactionKey
|
||||
holder.emojiReactionView.typeface = emojiTypeFace ?: Typeface.DEFAULT
|
||||
holder.displayNameView.text = authorDisplayName
|
||||
timeStamp?.let {
|
||||
holder.timeStampView.text = it
|
||||
|
@ -28,7 +28,6 @@ import com.airbnb.epoxy.EpoxyRecyclerView
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.riotx.EmojiCompatFontProvider
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||
@ -43,13 +42,12 @@ class ViewReactionBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
private val viewModel: ViewReactionViewModel by fragmentViewModel(ViewReactionViewModel::class)
|
||||
|
||||
@Inject lateinit var viewReactionViewModelFactory: ViewReactionViewModel.Factory
|
||||
@Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider
|
||||
|
||||
@BindView(R.id.bottom_sheet_display_reactions_list)
|
||||
lateinit var epoxyRecyclerView: EpoxyRecyclerView
|
||||
|
||||
private val epoxyController by lazy {
|
||||
ViewReactionsEpoxyController(requireContext(), emojiCompatFontProvider.typeface)
|
||||
ViewReactionsEpoxyController(requireContext())
|
||||
}
|
||||
|
||||
override fun injectWith(screenComponent: ScreenComponent) {
|
||||
|
@ -90,7 +90,7 @@ class ViewReactionViewModel @AssistedInject constructor(@Assisted
|
||||
.flatMapSingle { summaries ->
|
||||
Observable
|
||||
.fromIterable(summaries.reactionsSummary)
|
||||
.filter { reactionAggregatedSummary -> isSingleEmoji(reactionAggregatedSummary.key) }
|
||||
//.filter { reactionAggregatedSummary -> isSingleEmoji(reactionAggregatedSummary.key) }
|
||||
.toReactionInfoList()
|
||||
}
|
||||
.execute {
|
||||
|
@ -19,6 +19,7 @@ package im.vector.riotx.features.home.room.detail.timeline.action
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.text.format.DateUtils
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
@ -30,7 +31,7 @@ import im.vector.riotx.core.ui.list.genericLoaderItem
|
||||
/**
|
||||
* Epoxy controller for reaction event list
|
||||
*/
|
||||
class ViewReactionsEpoxyController(private val context: Context, private val emojiCompatTypeface: Typeface?)
|
||||
class ViewReactionsEpoxyController(private val context: Context)
|
||||
: TypedEpoxyController<DisplayReactionsViewState>() {
|
||||
|
||||
override fun buildModels(state: DisplayReactionsViewState) {
|
||||
@ -50,9 +51,8 @@ class ViewReactionsEpoxyController(private val context: Context, private val emo
|
||||
state.mapReactionKeyToMemberList()?.forEach {
|
||||
reactionInfoSimpleItem {
|
||||
id(it.eventId)
|
||||
emojiTypeFace(emojiCompatTypeface)
|
||||
timeStamp(it.timestamp)
|
||||
reactionKey(it.reactionKey)
|
||||
reactionKey(EmojiCompat.get().process(it.reactionKey))
|
||||
authorDisplayName(it.authorName ?: it.authorId)
|
||||
}
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
||||
idToRefInFlow.add(reactionButton.id)
|
||||
reactionButton.reactionString = reaction.key
|
||||
reactionButton.reactionCount = reaction.count
|
||||
reactionButton.emojiTypeFace = emojiTypeFace
|
||||
//reactionButton.emojiTypeFace = emojiTypeFace
|
||||
reactionButton.setChecked(reaction.addedByMe)
|
||||
reactionButton.isEnabled = reaction.synced
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|
||||
memberName = formattedMemberName,
|
||||
showInformation = showInformation,
|
||||
orderedReactionList = event.annotations?.reactionsSummary
|
||||
?.filter { isSingleEmoji(it.key) }
|
||||
//?.filter { isSingleEmoji(it.key) }
|
||||
?.map {
|
||||
ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty())
|
||||
},
|
||||
|
@ -25,14 +25,14 @@ class ChronologicalRoomComparator @Inject constructor() : Comparator<RoomSummary
|
||||
var rightTimestamp = 0L
|
||||
var leftTimestamp = 0L
|
||||
if (null != leftRoomSummary) {
|
||||
leftTimestamp = leftRoomSummary.latestEvent?.root?.originServerTs ?: 0
|
||||
leftTimestamp = leftRoomSummary.latestPreviewableEvent?.root?.originServerTs ?: 0
|
||||
}
|
||||
if (null != rightRoomSummary) {
|
||||
rightTimestamp = rightRoomSummary.latestEvent?.root?.originServerTs ?: 0
|
||||
rightTimestamp = rightRoomSummary.latestPreviewableEvent?.root?.originServerTs ?: 0
|
||||
}
|
||||
return if (rightRoomSummary?.latestEvent?.root == null) {
|
||||
return if (rightRoomSummary?.latestPreviewableEvent?.root == null) {
|
||||
-1
|
||||
} else if (leftRoomSummary?.latestEvent?.root == null) {
|
||||
} else if (leftRoomSummary?.latestPreviewableEvent?.root == null) {
|
||||
1
|
||||
} else {
|
||||
val deltaTimestamp = rightTimestamp - leftTimestamp
|
||||
|
@ -32,7 +32,7 @@ abstract class RoomCategoryItem : VectorEpoxyModel<RoomCategoryItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute lateinit var title: CharSequence
|
||||
@EpoxyAttribute var expanded: Boolean = false
|
||||
@EpoxyAttribute var unreadCount: Int = 0
|
||||
@EpoxyAttribute var unreadNotificationCount: Int = 0
|
||||
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
|
||||
@ -42,7 +42,7 @@ abstract class RoomCategoryItem : VectorEpoxyModel<RoomCategoryItem.Holder>() {
|
||||
val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also {
|
||||
DrawableCompat.setTint(it, tintColor)
|
||||
}
|
||||
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadCount, showHighlighted))
|
||||
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
|
||||
holder.titleView.setCompoundDrawablesWithIntrinsicBounds(expandedArrowDrawable, null, null, null)
|
||||
holder.titleView.text = title
|
||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||
|
@ -101,7 +101,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
||||
id(titleRes)
|
||||
title(stringProvider.getString(titleRes).toUpperCase())
|
||||
expanded(isExpanded)
|
||||
unreadCount(unreadCount)
|
||||
unreadNotificationCount(unreadCount)
|
||||
showHighlighted(showHighlighted)
|
||||
listener {
|
||||
mutateExpandedState()
|
||||
|
@ -16,9 +16,11 @@
|
||||
|
||||
package im.vector.riotx.features.home.room.list
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
@ -36,7 +38,8 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||
@EpoxyAttribute lateinit var lastFormattedEvent: CharSequence
|
||||
@EpoxyAttribute lateinit var lastEventTime: CharSequence
|
||||
@EpoxyAttribute var avatarUrl: String? = null
|
||||
@EpoxyAttribute var unreadCount: Int = 0
|
||||
@EpoxyAttribute var unreadNotificationCount: Int = 0
|
||||
@EpoxyAttribute var hasUnreadMessage: Boolean = false
|
||||
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
|
||||
@ -47,13 +50,15 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||
holder.titleView.text = roomName
|
||||
holder.lastEventTimeView.text = lastEventTime
|
||||
holder.lastEventView.text = lastFormattedEvent
|
||||
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadCount, showHighlighted))
|
||||
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
|
||||
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
|
||||
avatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val titleView by bind<TextView>(R.id.roomNameView)
|
||||
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
|
||||
val unreadIndentIndicator by bind<View>(R.id.roomUnreadIndicator)
|
||||
val lastEventView by bind<TextView>(R.id.roomLastEventView)
|
||||
val lastEventTimeView by bind<TextView>(R.id.roomLastEventTimeView)
|
||||
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package im.vector.riotx.features.home.room.list
|
||||
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
@ -38,7 +39,8 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
|
||||
private val dateFormatter: VectorDateFormatter,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val stringProvider: StringProvider,
|
||||
private val avatarRenderer: AvatarRenderer) {
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val session: Session) {
|
||||
|
||||
fun create(roomSummary: RoomSummary,
|
||||
joiningRoomsIds: Set<String>,
|
||||
@ -59,9 +61,9 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
|
||||
rejectingErrorRoomsIds: Set<String>,
|
||||
listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
|
||||
val secondLine = if (roomSummary.isDirect) {
|
||||
roomSummary.latestEvent?.root?.senderId
|
||||
roomSummary.latestPreviewableEvent?.root?.senderId
|
||||
} else {
|
||||
roomSummary.latestEvent?.root?.senderId?.let {
|
||||
roomSummary.latestPreviewableEvent?.root?.senderId?.let {
|
||||
stringProvider.getString(R.string.invited_by, it)
|
||||
}
|
||||
}
|
||||
@ -88,7 +90,7 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
|
||||
|
||||
var latestFormattedEvent: CharSequence = ""
|
||||
var latestEventTime: CharSequence = ""
|
||||
val latestEvent = roomSummary.latestEvent
|
||||
val latestEvent = roomSummary.latestPreviewableEvent
|
||||
if (latestEvent != null) {
|
||||
val date = latestEvent.root.localDateTime()
|
||||
val currentDate = DateProvider.currentLocalDateTime()
|
||||
@ -131,7 +133,8 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
|
||||
.roomName(roomSummary.displayName)
|
||||
.avatarUrl(roomSummary.avatarUrl)
|
||||
.showHighlighted(showHighlighted)
|
||||
.unreadCount(unreadCount)
|
||||
.unreadNotificationCount(unreadCount)
|
||||
.hasUnreadMessage(roomSummary.hasUnreadMessages)
|
||||
.listener { listener?.onRoomSelected(roomSummary) }
|
||||
}
|
||||
|
||||
|
@ -89,18 +89,44 @@ class VideoContentRenderer @Inject constructor(private val activeSessionHolder:
|
||||
})
|
||||
}
|
||||
} else {
|
||||
thumbnailView.isVisible = false
|
||||
loadingView.isVisible = false
|
||||
|
||||
val resolvedUrl = contentUrlResolver.resolveFullSize(data.url)
|
||||
|
||||
if (resolvedUrl == null) {
|
||||
thumbnailView.isVisible = false
|
||||
loadingView.isVisible = false
|
||||
errorView.isVisible = true
|
||||
errorView.setText(R.string.unknown_error)
|
||||
} else {
|
||||
videoView.isVisible = true
|
||||
videoView.setVideoPath(resolvedUrl)
|
||||
videoView.start()
|
||||
|
||||
//Temporary code, some remote videos are not played by videoview setVideoUri
|
||||
//So for now we download them then play
|
||||
thumbnailView.isVisible = true
|
||||
loadingView.isVisible = true
|
||||
|
||||
activeSessionHolder.getActiveSession()
|
||||
.downloadFile(
|
||||
FileService.DownloadMode.FOR_INTERNAL_USE,
|
||||
data.eventId,
|
||||
data.filename,
|
||||
data.url,
|
||||
null,
|
||||
object : MatrixCallback<File> {
|
||||
override fun onSuccess(data: File) {
|
||||
thumbnailView.isVisible = false
|
||||
loadingView.isVisible = false
|
||||
videoView.isVisible = true
|
||||
|
||||
videoView.setVideoPath(data.path)
|
||||
videoView.start()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
loadingView.isVisible = false
|
||||
errorView.isVisible = true
|
||||
errorView.text = errorFormatter.toHumanReadable(failure)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import android.widget.TextView
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.utils.TextUtils
|
||||
|
||||
@ -58,12 +59,6 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
|
||||
private var reactionSelector: View? = null
|
||||
|
||||
var emojiTypeFace: Typeface? = null
|
||||
set(value) {
|
||||
field = value
|
||||
emojiView?.typeface = value ?: Typeface.DEFAULT
|
||||
}
|
||||
|
||||
private var dotsView: DotsView
|
||||
private var circleView: CircleView
|
||||
var reactedListener: ReactedListener? = null
|
||||
@ -82,7 +77,9 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
var reactionString = "😀"
|
||||
set(value) {
|
||||
field = value
|
||||
emojiView?.text = field
|
||||
//maybe cache this for performances?
|
||||
val emojiSpanned = EmojiCompat.get().process(value)
|
||||
emojiView?.text = emojiSpanned
|
||||
}
|
||||
|
||||
private var animationScaleFactor: Float = 0.toFloat()
|
||||
@ -104,7 +101,7 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
|
||||
countTextView?.text = TextUtils.formatCountToShortDecimal(reactionCount)
|
||||
|
||||
emojiView?.typeface = this.emojiTypeFace ?: Typeface.DEFAULT
|
||||
// emojiView?.typeface = this.emojiTypeFace ?: Typeface.DEFAULT
|
||||
|
||||
val array = context.obtainStyledAttributes(attrs, R.styleable.ReactionButton, defStyleAttr, 0)
|
||||
|
||||
|
6
vector/src/main/res/drawable/pill_receipt_black.xml
Normal file
6
vector/src/main/res/drawable/pill_receipt_black.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="10dp" />
|
||||
<solid android:color="@color/riotx_header_panel_border_mobile_black" />
|
||||
</shape>
|
6
vector/src/main/res/drawable/pill_receipt_dark.xml
Normal file
6
vector/src/main/res/drawable/pill_receipt_dark.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="10dp" />
|
||||
<solid android:color="@color/riotx_header_panel_border_mobile_dark" />
|
||||
</shape>
|
6
vector/src/main/res/drawable/pill_receipt_light.xml
Normal file
6
vector/src/main/res/drawable/pill_receipt_light.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="10dp" />
|
||||
<solid android:color="@color/riotx_header_panel_border_mobile_light" />
|
||||
</shape>
|
@ -34,7 +34,9 @@
|
||||
android:id="@+id/videoMediaViewerThumbnailView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone"
|
||||
android:scaleType="centerInside"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ProgressBar
|
||||
@ -49,6 +51,7 @@
|
||||
android:id="@+id/videoMediaViewerVideoView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
|
@ -5,38 +5,26 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="40dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/readReceiptAvatar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/readReceiptName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="16sp"
|
||||
style="@style/BottomSheetItemTextMain"
|
||||
tools:text="@sample/matrix.json/data/displayName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/readReceiptDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="12sp"
|
||||
style="@style/BottomSheetItemTime"
|
||||
tools:text="10:44" />
|
||||
|
||||
</LinearLayout>
|
@ -10,12 +10,22 @@
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
|
||||
<View
|
||||
android:id="@+id/roomUnreadIndicator"
|
||||
android:layout_width="4dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/colorAccent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/roomAvatarImageView"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
@ -6,6 +6,7 @@
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:minHeight="40dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<TextView
|
||||
@ -22,25 +23,12 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemSimpleReactionInfoMemberName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="16sp"
|
||||
style="@style/BottomSheetItemTextMain"
|
||||
tools:text="@sample/matrix.json/data/displayName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemSimpleReactionInfoTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
style="@style/BottomSheetItemTime"
|
||||
tools:text="10:44" />
|
||||
|
||||
|
||||
|
@ -37,20 +37,23 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/reactionText"
|
||||
android:layout_width="20dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:minWidth="20dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="13sp"
|
||||
android:maxEms="10"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/reactionCount"
|
||||
tools:text="👍" />
|
||||
tools:text="* Party Parrot Again * 👀" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/reactionCount"
|
||||
@ -58,8 +61,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/reactionText"
|
||||
android:layout_marginStart="-4dp"
|
||||
android:layout_marginLeft="-4dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_marginLeft="2dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:gravity="center"
|
||||
|
@ -9,48 +9,55 @@
|
||||
<TextView
|
||||
android:id="@+id/receiptMore"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_height="18dp"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
android:background="?vctr_pill_receipt"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
tools:text="999+" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar5"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar4"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar3"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar2"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/receiptAvatar1"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
@ -88,6 +88,7 @@
|
||||
<attr name="vctr_pill_background_room_alias" format="reference" />
|
||||
<attr name="vctr_pill_text_color_user_id" format="reference" />
|
||||
<attr name="vctr_pill_text_color_room_alias" format="reference" />
|
||||
<attr name="vctr_pill_receipt" format="reference" />
|
||||
|
||||
<!-- Widget banner background -->
|
||||
<attr name="vctr_widget_banner_background" format="color" />
|
||||
|
@ -2,5 +2,6 @@
|
||||
<resources>
|
||||
|
||||
<!-- Strings not defined in Riot -->
|
||||
<string name="read_at">Read at</string>
|
||||
|
||||
</resources>
|
@ -319,4 +319,23 @@
|
||||
<item name="android:background">@drawable/vector_label_background_light</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomSheetItemTextMain">
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:ellipsize">end</item>
|
||||
<item name="android:lines">1</item>
|
||||
<item name="android:textColor">?riotx_text_primary</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomSheetItemTime">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:lines">1</item>
|
||||
<item name="android:textColor">?riotx_text_secondary</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -75,6 +75,8 @@
|
||||
|
||||
<item name="vctr_markdown_block_background_color">#FF4D4D4D</item>
|
||||
|
||||
<item name="vctr_pill_receipt">@drawable/pill_receipt_black</item>
|
||||
|
||||
<!-- activities background -->
|
||||
<item name="android:windowBackground">@color/riot_primary_background_color_black</item>
|
||||
<item name="vctr_bottom_nav_background_color">@color/primary_color_black</item>
|
||||
|
@ -163,6 +163,8 @@
|
||||
<item name="vctr_pill_text_color_user_id">@android:color/white</item>
|
||||
<item name="vctr_pill_text_color_room_alias">@color/riot_primary_text_color_dark</item>
|
||||
|
||||
<item name="vctr_pill_receipt">@drawable/pill_receipt_dark</item>
|
||||
|
||||
<item name="vctr_direct_chat_circle">@drawable/direct_chat_circle_dark</item>
|
||||
|
||||
<item name="vctr_widget_banner_background">#FF454545</item>
|
||||
|
@ -163,6 +163,8 @@
|
||||
<item name="vctr_pill_text_color_user_id">@color/riot_primary_text_color_light</item>
|
||||
<item name="vctr_pill_text_color_room_alias">@android:color/white</item>
|
||||
|
||||
<item name="vctr_pill_receipt">@drawable/pill_receipt_light</item>
|
||||
|
||||
<item name="vctr_direct_chat_circle">@drawable/direct_chat_circle_light</item>
|
||||
|
||||
<item name="vctr_widget_banner_background">#FFD3EFE1</item>
|
||||
|
Reference in New Issue
Block a user