mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Merge pull request #187 from vector-im/feature/issues_fix
Add a few feature
This commit is contained in:
commit
b1f5b3ad96
19 changed files with 224 additions and 227 deletions
|
@ -19,7 +19,6 @@ package im.vector.matrix.android.api.session.room.timeline
|
|||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
|
||||
/**
|
||||
|
@ -63,7 +62,8 @@ data class TimelineEvent(
|
|||
return metadata[key] as T?
|
||||
}
|
||||
|
||||
fun isEncrypted() : Boolean {
|
||||
return EventType.ENCRYPTED == root.getClearType()
|
||||
fun isEncrypted(): Boolean {
|
||||
// warning: Do not use getClearType here
|
||||
return EventType.ENCRYPTED == root.type
|
||||
}
|
||||
}
|
||||
|
|
|
@ -332,7 +332,7 @@ abstract class VectorBaseActivity : BaseMvRxActivity() {
|
|||
open fun getMenuRes() = -1
|
||||
|
||||
@AttrRes
|
||||
open fun getMenuTint() = R.attr.vctr_icon_tint_on_dark_action_bar_color
|
||||
open fun getMenuTint() = R.attr.vctr_icon_tint_on_light_action_bar_color
|
||||
|
||||
/**
|
||||
* Return a object containing other themes for this activity
|
||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.riotredesign.features.home.room.detail.timeline.factory.*
|
|||
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||
import im.vector.riotredesign.features.home.room.list.RoomSummaryController
|
||||
import im.vector.riotredesign.features.html.EventHtmlRenderer
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
@ -69,15 +70,22 @@ class HomeModule {
|
|||
val eventHtmlRenderer = EventHtmlRenderer(GlideApp.with(fragment), fragment.requireContext(), get())
|
||||
val noticeEventFormatter = get<NoticeEventFormatter>(parameters = { parametersOf(fragment) })
|
||||
val timelineMediaSizeProvider = TimelineMediaSizeProvider()
|
||||
val messageItemFactory = MessageItemFactory(colorProvider, timelineMediaSizeProvider,
|
||||
timelineDateFormatter, eventHtmlRenderer, get(), get())
|
||||
val messageInformationDataFactory = MessageInformationDataFactory(timelineDateFormatter, colorProvider)
|
||||
val messageItemFactory = MessageItemFactory(colorProvider,
|
||||
timelineMediaSizeProvider,
|
||||
eventHtmlRenderer,
|
||||
get(),
|
||||
messageInformationDataFactory,
|
||||
get())
|
||||
|
||||
val encryptedItemFactory = EncryptedItemFactory(messageInformationDataFactory, colorProvider, get())
|
||||
|
||||
val timelineItemFactory = TimelineItemFactory(
|
||||
messageItemFactory = messageItemFactory,
|
||||
noticeItemFactory = NoticeItemFactory(noticeEventFormatter),
|
||||
defaultItemFactory = DefaultItemFactory(),
|
||||
encryptionItemFactory = EncryptionItemFactory(get()),
|
||||
encryptedItemFactory = EncryptedItemFactory(get())
|
||||
encryptedItemFactory = encryptedItemFactory
|
||||
)
|
||||
TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider)
|
||||
}
|
||||
|
|
|
@ -542,6 +542,10 @@ class RoomDetailFragment :
|
|||
roomDetailViewModel.process(RoomDetailActions.EventDisplayed(event))
|
||||
}
|
||||
|
||||
override fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View) {
|
||||
vectorBaseActivity.notImplemented("encrypted message click")
|
||||
}
|
||||
|
||||
override fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) {
|
||||
val intent = ImageMediaViewerActivity.newIntent(vectorBaseActivity, mediaData)
|
||||
startActivity(intent)
|
||||
|
@ -576,7 +580,7 @@ class RoomDetailFragment :
|
|||
}
|
||||
|
||||
override fun onAvatarClicked(informationData: MessageInformationData) {
|
||||
vectorBaseActivity.notImplemented()
|
||||
vectorBaseActivity.notImplemented("Click on user avatar")
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
|
|
|
@ -49,6 +49,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
|
|||
interface Callback : ReactionPillCallback, AvatarCallback, BaseCallback {
|
||||
fun onEventVisible(event: TimelineEvent)
|
||||
fun onUrlClicked(url: String)
|
||||
fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View)
|
||||
fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View)
|
||||
fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View)
|
||||
fun onFileMessageClicked(messageFileContent: MessageFileContent)
|
||||
|
|
|
@ -123,7 +123,11 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
|
|||
|
||||
this.add(SimpleAction(VIEW_SOURCE, R.string.view_source, R.drawable.ic_view_source, JSONObject(event.root.toContent()).toString(4)))
|
||||
if (event.isEncrypted()) {
|
||||
this.add(SimpleAction(VIEW_DECRYPTED_SOURCE, R.string.view_decrypted_source, R.drawable.ic_view_source, parcel.eventId))
|
||||
val decryptedContent = event.root.mClearEvent?.toContent()?.let {
|
||||
JSONObject(it).toString(4)
|
||||
} ?: viewModelContext.activity.getString(R.string.encryption_information_decryption_error)
|
||||
|
||||
this.add(SimpleAction(VIEW_DECRYPTED_SOURCE, R.string.view_decrypted_source, R.drawable.ic_view_source, decryptedContent))
|
||||
}
|
||||
this.add(SimpleAction(ACTION_COPY_PERMALINK, R.string.permalink, R.drawable.ic_permalink, parcel.eventId))
|
||||
|
||||
|
|
|
@ -16,28 +16,33 @@
|
|||
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.factory
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.StyleSpan
|
||||
import android.view.View
|
||||
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotredesign.core.resources.ColorProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_
|
||||
import im.vector.riotredesign.core.utils.DebouncedClickListener
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||
import me.gujun.android.span.span
|
||||
|
||||
// This class handles timeline event who haven't been successfully decrypted
|
||||
class EncryptedItemFactory(private val stringProvider: StringProvider) {
|
||||
// This class handles timeline events who haven't been successfully decrypted
|
||||
class EncryptedItemFactory(private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val stringProvider: StringProvider) {
|
||||
|
||||
fun create(event: TimelineEvent,
|
||||
nextEvent: TimelineEvent?,
|
||||
callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? {
|
||||
event.root.eventId ?: return null
|
||||
|
||||
fun create(timelineEvent: TimelineEvent): VectorEpoxyModel<*>? {
|
||||
return when {
|
||||
EventType.ENCRYPTED == timelineEvent.root.getClearType() -> {
|
||||
val cryptoError = timelineEvent.root.mCryptoError
|
||||
EventType.ENCRYPTED == event.root.getClearType() -> {
|
||||
val cryptoError = event.root.mCryptoError
|
||||
val errorDescription =
|
||||
if (cryptoError?.code == MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE) {
|
||||
stringProvider.getString(R.string.notice_crypto_error_unkwown_inbound_session_id)
|
||||
|
@ -46,22 +51,28 @@ class EncryptedItemFactory(private val stringProvider: StringProvider) {
|
|||
}
|
||||
|
||||
val message = stringProvider.getString(R.string.notice_crypto_unable_to_decrypt, errorDescription)
|
||||
val spannableStr = SpannableString(message)
|
||||
spannableStr.setSpan(StyleSpan(Typeface.ITALIC), 0, message.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
val spannableStr = span(message) {
|
||||
textStyle = "italic"
|
||||
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
|
||||
}
|
||||
|
||||
// TODO This is not correct format for error, change it
|
||||
val informationData = MessageInformationData(
|
||||
eventId = timelineEvent.root.eventId ?: "?",
|
||||
senderId = timelineEvent.root.sender ?: "",
|
||||
sendState = timelineEvent.sendState,
|
||||
avatarUrl = timelineEvent.senderAvatar(),
|
||||
memberName = timelineEvent.senderName(),
|
||||
showInformation = false
|
||||
)
|
||||
return NoticeItem_()
|
||||
.noticeText(spannableStr)
|
||||
val informationData = messageInformationDataFactory.create(event, nextEvent)
|
||||
|
||||
return MessageTextItem_()
|
||||
.message(spannableStr)
|
||||
.informationData(informationData)
|
||||
.avatarCallback(callback)
|
||||
.cellClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
callback?.onEncryptedMessageClicked(informationData, view)
|
||||
}))
|
||||
.longClickListener { view ->
|
||||
return@longClickListener callback?.onEventLongClicked(informationData, null, view)
|
||||
?: false
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
|||
import im.vector.matrix.android.internal.crypto.model.event.EncryptionEventContent
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
|
@ -31,7 +32,8 @@ import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem
|
|||
|
||||
class EncryptionItemFactory(private val stringProvider: StringProvider) {
|
||||
|
||||
fun create(event: TimelineEvent): NoticeItem? {
|
||||
fun create(event: TimelineEvent,
|
||||
callback: TimelineEventController.BaseCallback?): NoticeItem? {
|
||||
val text = buildNoticeText(event.root, event.senderName) ?: return null
|
||||
val informationData = MessageInformationData(
|
||||
eventId = event.root.eventId ?: "?",
|
||||
|
@ -44,6 +46,7 @@ class EncryptionItemFactory(private val stringProvider: StringProvider) {
|
|||
return NoticeItem_()
|
||||
.noticeText(text)
|
||||
.informationData(informationData)
|
||||
.baseCallback(callback)
|
||||
}
|
||||
|
||||
private fun buildNoticeText(event: Event, senderName: String?): CharSequence? {
|
||||
|
@ -52,7 +55,7 @@ class EncryptionItemFactory(private val stringProvider: StringProvider) {
|
|||
val content = event.content.toModel<EncryptionEventContent>() ?: return null
|
||||
stringProvider.getString(R.string.notice_end_to_end, senderName, content.algorithm)
|
||||
}
|
||||
else -> null
|
||||
else -> null
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import android.text.style.RelativeSizeSpan
|
|||
import android.view.View
|
||||
import im.vector.matrix.android.api.permalinks.MatrixLinkify
|
||||
import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.RelationType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary
|
||||
|
@ -35,16 +34,14 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
|||
import im.vector.riotredesign.EmojiCompatFontProvider
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotredesign.core.extensions.localDateTime
|
||||
import im.vector.riotredesign.core.linkify.VectorLinkify
|
||||
import im.vector.riotredesign.core.resources.ColorProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.core.utils.DebouncedClickListener
|
||||
import im.vector.riotredesign.features.home.getColorFromUserId
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.*
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||
import im.vector.riotredesign.features.html.EventHtmlRenderer
|
||||
import im.vector.riotredesign.features.media.ImageContentRenderer
|
||||
import im.vector.riotredesign.features.media.VideoContentRenderer
|
||||
|
@ -52,50 +49,18 @@ import me.gujun.android.span.span
|
|||
|
||||
class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
private val timelineMediaSizeProvider: TimelineMediaSizeProvider,
|
||||
private val timelineDateFormatter: TimelineDateFormatter,
|
||||
private val htmlRenderer: EventHtmlRenderer,
|
||||
private val stringProvider: StringProvider,
|
||||
private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||
private val emojiCompatFontProvider: EmojiCompatFontProvider) {
|
||||
|
||||
fun create(event: TimelineEvent,
|
||||
nextEvent: TimelineEvent?,
|
||||
callback: TimelineEventController.Callback?
|
||||
): VectorEpoxyModel<*>? {
|
||||
event.root.eventId ?: return null
|
||||
|
||||
val eventId = event.root.eventId ?: return null
|
||||
|
||||
val date = event.root.localDateTime()
|
||||
val nextDate = nextEvent?.root?.localDateTime()
|
||||
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
||||
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
||||
?: false
|
||||
|
||||
val showInformation = addDaySeparator
|
||||
|| event.senderAvatar != nextEvent?.senderAvatar
|
||||
|| event.senderName != nextEvent?.senderName
|
||||
|| nextEvent?.root?.getClearType() != EventType.MESSAGE
|
||||
|| isNextMessageReceivedMoreThanOneHourAgo
|
||||
|
||||
val time = timelineDateFormatter.formatMessageHour(date)
|
||||
val avatarUrl = event.senderAvatar
|
||||
val memberName = event.senderName ?: event.root.sender ?: ""
|
||||
val formattedMemberName = span(memberName) {
|
||||
textColor = colorProvider.getColor(getColorFromUserId(event.root.sender
|
||||
?: ""))
|
||||
}
|
||||
val hasBeenEdited = event.annotations?.editSummary != null
|
||||
val informationData = MessageInformationData(eventId = eventId,
|
||||
senderId = event.root.sender ?: "",
|
||||
sendState = event.sendState,
|
||||
time = time,
|
||||
avatarUrl = avatarUrl,
|
||||
memberName = formattedMemberName,
|
||||
showInformation = showInformation,
|
||||
orderedReactionList = event.annotations?.reactionsSummary?.map {
|
||||
ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty())
|
||||
},
|
||||
hasBeenEdited = hasBeenEdited
|
||||
)
|
||||
val informationData = messageInformationDataFactory.create(event, nextEvent)
|
||||
|
||||
if (event.root.unsignedData?.redactedEvent != null) {
|
||||
//message is redacted
|
||||
|
@ -117,13 +82,11 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
|||
return when (messageContent) {
|
||||
is MessageEmoteContent -> buildEmoteMessageItem(messageContent,
|
||||
informationData,
|
||||
hasBeenEdited,
|
||||
event.annotations?.editSummary,
|
||||
callback)
|
||||
is MessageTextContent -> buildTextMessageItem(event.sendState,
|
||||
messageContent,
|
||||
informationData,
|
||||
hasBeenEdited,
|
||||
event.annotations?.editSummary,
|
||||
callback
|
||||
)
|
||||
|
@ -266,7 +229,6 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
|||
private fun buildTextMessageItem(sendState: SendState,
|
||||
messageContent: MessageTextContent,
|
||||
informationData: MessageInformationData,
|
||||
hasBeenEdited: Boolean,
|
||||
editSummary: EditAggregatedSummary?,
|
||||
callback: TimelineEventController.Callback?): MessageTextItem? {
|
||||
|
||||
|
@ -278,7 +240,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
|||
|
||||
return MessageTextItem_()
|
||||
.apply {
|
||||
if (hasBeenEdited) {
|
||||
if (informationData.hasBeenEdited) {
|
||||
val spannable = annotateWithEdited(linkifiedBody, callback, informationData, editSummary)
|
||||
message(spannable)
|
||||
} else {
|
||||
|
@ -368,7 +330,6 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
|||
|
||||
private fun buildEmoteMessageItem(messageContent: MessageEmoteContent,
|
||||
informationData: MessageInformationData,
|
||||
hasBeenEdited: Boolean,
|
||||
editSummary: EditAggregatedSummary?,
|
||||
callback: TimelineEventController.Callback?): MessageTextItem? {
|
||||
|
||||
|
@ -378,7 +339,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
|||
}
|
||||
return MessageTextItem_()
|
||||
.apply {
|
||||
if (hasBeenEdited) {
|
||||
if (informationData.hasBeenEdited) {
|
||||
val spannable = annotateWithEdited(message, callback, informationData, editSummary)
|
||||
message(spannable)
|
||||
} else {
|
||||
|
|
|
@ -52,8 +52,8 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
|||
EventType.CALL_ANSWER -> noticeItemFactory.create(event, callback)
|
||||
|
||||
// Crypto
|
||||
EventType.ENCRYPTION -> encryptionItemFactory.create(event)
|
||||
EventType.ENCRYPTED -> encryptedItemFactory.create(event)
|
||||
EventType.ENCRYPTION -> encryptionItemFactory.create(event, callback)
|
||||
EventType.ENCRYPTED -> encryptedItemFactory.create(event, nextEvent, callback)
|
||||
|
||||
// Unhandled event types (yet)
|
||||
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
||||
|
|
|
@ -38,11 +38,9 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
|||
var baseCallback: TimelineEventController.BaseCallback? = null
|
||||
|
||||
private var longClickListener = View.OnLongClickListener {
|
||||
baseCallback?.onEventLongClicked(informationData, null, it)
|
||||
baseCallback != null
|
||||
return@OnLongClickListener baseCallback?.onEventLongClicked(informationData, null, it) == true
|
||||
}
|
||||
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.noticeTextView.text = noticeText
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.util
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.riotredesign.core.extensions.localDateTime
|
||||
import im.vector.riotredesign.core.resources.ColorProvider
|
||||
import im.vector.riotredesign.features.home.getColorFromUserId
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.ReactionInfoData
|
||||
import me.gujun.android.span.span
|
||||
|
||||
/**
|
||||
* This class compute if data of an event (such has avatar, display name, ...) should be displayed, depending on the previous event in the timeline
|
||||
*/
|
||||
class MessageInformationDataFactory(private val timelineDateFormatter: TimelineDateFormatter,
|
||||
private val colorProvider: ColorProvider) {
|
||||
|
||||
fun create(event: TimelineEvent, nextEvent: TimelineEvent?): MessageInformationData {
|
||||
// Non nullability has been tested before
|
||||
val eventId = event.root.eventId!!
|
||||
|
||||
val date = event.root.localDateTime()
|
||||
|
||||
val nextDate = nextEvent?.root?.localDateTime()
|
||||
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
||||
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
||||
?: false
|
||||
val showInformation =
|
||||
addDaySeparator
|
||||
|| event.senderAvatar != nextEvent?.senderAvatar
|
||||
|| event.senderName != nextEvent?.senderName
|
||||
|| (nextEvent?.root?.getClearType() != EventType.MESSAGE && nextEvent?.root?.getClearType() != EventType.ENCRYPTED)
|
||||
|| isNextMessageReceivedMoreThanOneHourAgo
|
||||
|
||||
val time = timelineDateFormatter.formatMessageHour(date)
|
||||
val avatarUrl = event.senderAvatar()
|
||||
val memberName = event.senderName ?: event.root.sender ?: ""
|
||||
val formattedMemberName = span(memberName) {
|
||||
textColor = colorProvider.getColor(getColorFromUserId(event.root.sender
|
||||
?: ""))
|
||||
}
|
||||
|
||||
val hasBeenEdited = event.annotations?.editSummary != null
|
||||
|
||||
return MessageInformationData(
|
||||
eventId = eventId,
|
||||
senderId = event.root.sender ?: "",
|
||||
sendState = event.sendState,
|
||||
time = time,
|
||||
avatarUrl = avatarUrl,
|
||||
memberName = formattedMemberName,
|
||||
showInformation = showInformation,
|
||||
orderedReactionList = event.annotations?.reactionsSummary?.map {
|
||||
ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty())
|
||||
},
|
||||
hasBeenEdited = hasBeenEdited
|
||||
)
|
||||
}
|
||||
}
|
|
@ -19,10 +19,8 @@ package im.vector.riotredesign.features.rageshake
|
|||
import android.text.TextUtils
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.BindView
|
||||
import butterknife.OnCheckedChanged
|
||||
import butterknife.OnTextChanged
|
||||
import im.vector.riotredesign.R
|
||||
|
@ -35,48 +33,17 @@ import timber.log.Timber
|
|||
*/
|
||||
class BugReportActivity : VectorBaseActivity() {
|
||||
|
||||
/* ==========================================================================================
|
||||
* UI
|
||||
* ========================================================================================== */
|
||||
|
||||
@BindView(R.id.bug_report_edit_text)
|
||||
lateinit var mBugReportText: EditText
|
||||
|
||||
@BindView(R.id.bug_report_button_include_logs)
|
||||
lateinit var mIncludeLogsButton: CheckBox
|
||||
|
||||
@BindView(R.id.bug_report_button_include_crash_logs)
|
||||
lateinit var mIncludeCrashLogsButton: CheckBox
|
||||
|
||||
@BindView(R.id.bug_report_button_include_screenshot)
|
||||
lateinit var mIncludeScreenShotButton: CheckBox
|
||||
|
||||
@BindView(R.id.bug_report_screenshot_preview)
|
||||
lateinit var mScreenShotPreview: ImageView
|
||||
|
||||
@BindView(R.id.bug_report_progress_view)
|
||||
lateinit var mProgressBar: ProgressBar
|
||||
|
||||
@BindView(R.id.bug_report_progress_text_view)
|
||||
lateinit var mProgressTextView: TextView
|
||||
|
||||
@BindView(R.id.bug_report_scrollview)
|
||||
lateinit var mScrollView: View
|
||||
|
||||
@BindView(R.id.bug_report_mask_view)
|
||||
lateinit var mMaskView: View
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_bug_report
|
||||
|
||||
override fun initUiAndData() {
|
||||
configureToolbar(bugReportToolbar)
|
||||
|
||||
if (BugReporter.screenshot != null) {
|
||||
mScreenShotPreview.setImageBitmap(BugReporter.screenshot)
|
||||
bug_report_screenshot_preview.setImageBitmap(BugReporter.screenshot)
|
||||
} else {
|
||||
mScreenShotPreview.isVisible = false
|
||||
mIncludeScreenShotButton.isChecked = false
|
||||
mIncludeScreenShotButton.isEnabled = false
|
||||
bug_report_screenshot_preview.isVisible = false
|
||||
bug_report_button_include_screenshot.isChecked = false
|
||||
bug_report_button_include_screenshot.isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,8 +51,8 @@ class BugReportActivity : VectorBaseActivity() {
|
|||
|
||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||
menu.findItem(R.id.ic_action_send_bug_report)?.let {
|
||||
val isValid = mBugReportText.text.toString().trim().length > 10
|
||||
&& !mMaskView.isVisible
|
||||
val isValid = bug_report_edit_text.text.toString().trim().length > 10
|
||||
&& !bug_report_mask_view.isVisible
|
||||
|
||||
it.isEnabled = isValid
|
||||
it.icon.alpha = if (isValid) 255 else 100
|
||||
|
@ -109,22 +76,22 @@ class BugReportActivity : VectorBaseActivity() {
|
|||
* Send the bug report
|
||||
*/
|
||||
private fun sendBugReport() {
|
||||
mScrollView.alpha = 0.3f
|
||||
mMaskView.isVisible = true
|
||||
bug_report_scrollview.alpha = 0.3f
|
||||
bug_report_mask_view.isVisible = true
|
||||
|
||||
invalidateOptionsMenu()
|
||||
|
||||
mProgressTextView.isVisible = true
|
||||
mProgressTextView.text = getString(R.string.send_bug_report_progress, 0.toString() + "")
|
||||
bug_report_progress_text_view.isVisible = true
|
||||
bug_report_progress_text_view.text = getString(R.string.send_bug_report_progress, "0")
|
||||
|
||||
mProgressBar.isVisible = true
|
||||
mProgressBar.progress = 0
|
||||
bug_report_progress_view.isVisible = true
|
||||
bug_report_progress_view.progress = 0
|
||||
|
||||
BugReporter.sendBugReport(this,
|
||||
mIncludeLogsButton.isChecked,
|
||||
mIncludeCrashLogsButton.isChecked,
|
||||
mIncludeScreenShotButton.isChecked,
|
||||
mBugReportText.text.toString(),
|
||||
bug_report_button_include_logs.isChecked,
|
||||
bug_report_button_include_crash_logs.isChecked,
|
||||
bug_report_button_include_screenshot.isChecked,
|
||||
bug_report_edit_text.text.toString(),
|
||||
object : BugReporter.IMXBugReportListener {
|
||||
override fun onUploadFailed(reason: String?) {
|
||||
try {
|
||||
|
@ -136,10 +103,10 @@ class BugReportActivity : VectorBaseActivity() {
|
|||
Timber.e(e, "## onUploadFailed() : failed to display the toast " + e.message)
|
||||
}
|
||||
|
||||
mMaskView.isVisible = false
|
||||
mProgressBar.isVisible = false
|
||||
mProgressTextView.isVisible = false
|
||||
mScrollView.alpha = 1.0f
|
||||
bug_report_mask_view.isVisible = false
|
||||
bug_report_progress_view.isVisible = false
|
||||
bug_report_progress_text_view.isVisible = false
|
||||
bug_report_scrollview.alpha = 1.0f
|
||||
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
@ -149,17 +116,10 @@ class BugReportActivity : VectorBaseActivity() {
|
|||
}
|
||||
|
||||
override fun onProgress(progress: Int) {
|
||||
var progress = progress
|
||||
if (progress > 100) {
|
||||
Timber.e("## onProgress() : progress > 100")
|
||||
progress = 100
|
||||
} else if (progress < 0) {
|
||||
Timber.e("## onProgress() : progress < 0")
|
||||
progress = 0
|
||||
}
|
||||
val myProgress = progress.coerceIn(0, 100)
|
||||
|
||||
mProgressBar.progress = progress
|
||||
mProgressTextView.text = getString(R.string.send_bug_report_progress, progress.toString() + "")
|
||||
bug_report_progress_view.progress = myProgress
|
||||
bug_report_progress_text_view.text = getString(R.string.send_bug_report_progress, "$myProgress")
|
||||
}
|
||||
|
||||
override fun onUploadSucceed() {
|
||||
|
@ -174,7 +134,6 @@ class BugReportActivity : VectorBaseActivity() {
|
|||
} catch (e: Exception) {
|
||||
Timber.e(e, "## onUploadSucceed() : failed to dismiss the dialog " + e.message)
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -190,7 +149,7 @@ class BugReportActivity : VectorBaseActivity() {
|
|||
|
||||
@OnCheckedChanged(R.id.bug_report_button_include_screenshot)
|
||||
internal fun onSendScreenshotChanged() {
|
||||
mScreenShotPreview.isVisible = mIncludeScreenShotButton.isChecked && BugReporter.screenshot != null
|
||||
bug_report_screenshot_preview.isVisible = bug_report_button_include_screenshot.isChecked && BugReporter.screenshot != null
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
@ -199,12 +158,4 @@ class BugReportActivity : VectorBaseActivity() {
|
|||
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
* Companion
|
||||
* ========================================================================================== */
|
||||
|
||||
companion object {
|
||||
private val LOG_TAG = BugReportActivity::class.java.simpleName
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.widget.Button
|
|||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
|
@ -67,24 +68,23 @@ class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList<Troublesh
|
|||
fun bind(test: TroubleshootTest) {
|
||||
|
||||
val context = itemView.context
|
||||
titleText.setTextColor(ThemeUtils.getColor(context, android.R.attr.textColorTertiary))
|
||||
descriptionText.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_default_text_hint_color))
|
||||
titleText.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_primary))
|
||||
descriptionText.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
||||
|
||||
when (test.status) {
|
||||
TroubleshootTest.TestStatus.NOT_STARTED -> {
|
||||
titleText.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_default_text_hint_color))
|
||||
descriptionText.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_default_text_hint_color))
|
||||
titleText.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
||||
|
||||
progressBar.visibility = View.INVISIBLE
|
||||
statusIconImage.visibility = View.VISIBLE
|
||||
statusIconImage.setImageResource(R.drawable.unit_test)
|
||||
}
|
||||
TroubleshootTest.TestStatus.RUNNING -> {
|
||||
TroubleshootTest.TestStatus.RUNNING -> {
|
||||
progressBar.visibility = View.VISIBLE
|
||||
statusIconImage.visibility = View.INVISIBLE
|
||||
|
||||
}
|
||||
TroubleshootTest.TestStatus.FAILED -> {
|
||||
TroubleshootTest.TestStatus.FAILED -> {
|
||||
progressBar.visibility = View.INVISIBLE
|
||||
statusIconImage.visibility = View.VISIBLE
|
||||
statusIconImage.setImageResource(R.drawable.unit_test_ko)
|
||||
|
@ -93,9 +93,9 @@ class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList<Troublesh
|
|||
statusIconImage.imageTintList = null
|
||||
}
|
||||
|
||||
descriptionText.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_highlighted_message_text_color))
|
||||
descriptionText.setTextColor(ContextCompat.getColor(context, R.color.riotx_notice))
|
||||
}
|
||||
TroubleshootTest.TestStatus.SUCCESS -> {
|
||||
TroubleshootTest.TestStatus.SUCCESS -> {
|
||||
progressBar.visibility = View.INVISIBLE
|
||||
statusIconImage.visibility = View.VISIBLE
|
||||
statusIconImage.setImageResource(R.drawable.unit_test_ok)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/bugReportToolbar"
|
||||
style="@style/VectorToolbarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="4dp" />
|
||||
|
@ -28,6 +29,7 @@
|
|||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:text="@string/send_bug_report_progress"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
@ -65,7 +67,8 @@
|
|||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:text="@string/send_bug_report_description" />
|
||||
android:text="@string/send_bug_report_description"
|
||||
android:textColor="?riotx_text_primary" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/VectorTextInputLayout"
|
||||
|
@ -96,6 +99,7 @@
|
|||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:text="@string/send_bug_report_description_in_english"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
|
@ -106,67 +110,41 @@
|
|||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:text="@string/send_bug_report_logs_description" />
|
||||
android:text="@string/send_bug_report_logs_description"
|
||||
android:textColor="?riotx_text_primary" />
|
||||
|
||||
<LinearLayout
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/bug_report_button_include_logs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:checked="true"
|
||||
android:text="@string/send_bug_report_include_logs" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/bug_report_button_include_logs"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="@string/send_bug_report_include_logs" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/bug_report_button_include_crash_logs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:checked="true"
|
||||
android:text="@string/send_bug_report_include_crash_logs" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/bug_report_button_include_crash_logs"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="@string/send_bug_report_include_crash_logs" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/bug_report_button_include_screenshot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/bug_report_button_include_screenshot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="@string/send_bug_report_include_screenshot" />
|
||||
</LinearLayout>
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:checked="true"
|
||||
android:text="@string/send_bug_report_include_screenshot" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/bug_report_screenshot_preview"
|
||||
|
@ -189,5 +167,6 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
|
@ -2,7 +2,7 @@
|
|||
<menu 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"
|
||||
tools:context="org.matrix.vector.activity.RoomActivity">
|
||||
tools:context=".features.rageshake.BugReportActivity">
|
||||
|
||||
<item
|
||||
android:id="@+id/ic_action_send_bug_report"
|
||||
|
|
|
@ -135,7 +135,7 @@
|
|||
|
||||
<!-- icon colors -->
|
||||
<item name="vctr_settings_icon_tint_color">@android:color/white</item>
|
||||
<item name="vctr_icon_tint_on_light_action_bar_color">@android:color/white</item>
|
||||
<item name="vctr_icon_tint_on_light_action_bar_color">@color/riotx_accent</item>
|
||||
<item name="vctr_icon_tint_on_dark_action_bar_color">@android:color/white</item>
|
||||
|
||||
<!-- theses colours are requested a background cannot be set by an ?att on android < 5 -->
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
|
||||
<!-- icon colors -->
|
||||
<item name="vctr_settings_icon_tint_color">@android:color/black</item>
|
||||
<item name="vctr_icon_tint_on_light_action_bar_color">@android:color/white</item>
|
||||
<item name="vctr_icon_tint_on_light_action_bar_color">@color/riotx_accent</item>
|
||||
<item name="vctr_icon_tint_on_dark_action_bar_color">@android:color/white</item>
|
||||
|
||||
<!-- theses colours are requested a background cannot be set by an ?att on android < 5 -->
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
|
||||
<!-- icon colors -->
|
||||
<item name="vctr_settings_icon_tint_color">@color/accent_color_status</item>
|
||||
<item name="vctr_icon_tint_on_light_action_bar_color">@android:color/white</item>
|
||||
<item name="vctr_icon_tint_on_light_action_bar_color">@color/riotx_accent</item>
|
||||
<item name="vctr_icon_tint_on_dark_action_bar_color">@android:color/white</item>
|
||||
|
||||
<!-- theses colours are requested a background cannot be set by an ?att on android < 5 -->
|
||||
|
|
Loading…
Reference in a new issue