From 53bdd58c1b0a158db5284241eec1934a0516770b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Jun 2019 09:53:09 +0200 Subject: [PATCH 1/6] Fix UI issue on BugReportActivity (send button not visible) --- .../core/platform/VectorBaseActivity.kt | 2 +- .../features/rageshake/BugReportActivity.kt | 99 +++++-------------- .../main/res/layout/activity_bug_report.xml | 85 ++++++---------- vector/src/main/res/menu/bug_report.xml | 2 +- vector/src/main/res/values/theme_dark.xml | 2 +- vector/src/main/res/values/theme_light.xml | 2 +- vector/src/main/res/values/theme_status.xml | 2 +- 7 files changed, 62 insertions(+), 132 deletions(-) diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt index 3507788b..8700e236 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt @@ -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 diff --git a/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReportActivity.kt index 48f81021..6f71fb0c 100755 --- a/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReportActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReportActivity.kt @@ -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 - } } diff --git a/vector/src/main/res/layout/activity_bug_report.xml b/vector/src/main/res/layout/activity_bug_report.xml index 2afeaa41..4ccb9c5e 100644 --- a/vector/src/main/res/layout/activity_bug_report.xml +++ b/vector/src/main/res/layout/activity_bug_report.xml @@ -7,6 +7,7 @@ @@ -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" /> + android:text="@string/send_bug_report_logs_description" + android:textColor="?riotx_text_primary" /> - + 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" /> - - - - - - + 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" /> - - - - - - - - - - - + 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" /> \ No newline at end of file diff --git a/vector/src/main/res/menu/bug_report.xml b/vector/src/main/res/menu/bug_report.xml index c37895bb..3c9ac242 100755 --- a/vector/src/main/res/menu/bug_report.xml +++ b/vector/src/main/res/menu/bug_report.xml @@ -2,7 +2,7 @@ + tools:context=".features.rageshake.BugReportActivity"> @android:color/white - @android:color/white + @color/riotx_accent @android:color/white diff --git a/vector/src/main/res/values/theme_light.xml b/vector/src/main/res/values/theme_light.xml index 926ad850..269a51bb 100644 --- a/vector/src/main/res/values/theme_light.xml +++ b/vector/src/main/res/values/theme_light.xml @@ -136,7 +136,7 @@ @android:color/black - @android:color/white + @color/riotx_accent @android:color/white diff --git a/vector/src/main/res/values/theme_status.xml b/vector/src/main/res/values/theme_status.xml index 59ab34e8..a1f4bf4a 100644 --- a/vector/src/main/res/values/theme_status.xml +++ b/vector/src/main/res/values/theme_status.xml @@ -94,7 +94,7 @@ @color/accent_color_status - @android:color/white + @color/riotx_accent @android:color/white From 273c8a19b8853d295010faad0481f82ba2b17915 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Jun 2019 10:30:56 +0200 Subject: [PATCH 2/6] Fix UI issue notification troubleshot screen --- ...otificationTroubleshootRecyclerViewAdapter.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vector/src/main/java/im/vector/riotredesign/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt b/vector/src/main/java/im/vector/riotredesign/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt index 696383f8..779ab8fc 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt @@ -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 { - 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 { + TroubleshootTest.TestStatus.SUCCESS -> { progressBar.visibility = View.INVISIBLE statusIconImage.visibility = View.VISIBLE statusIconImage.setImageResource(R.drawable.unit_test_ok) From a53e40e1ee7c5ba779dd0f97f69531ac0c989bef Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Jun 2019 12:25:50 +0200 Subject: [PATCH 3/6] Create MessageInformationDataFactory for reusability --- .../riotredesign/features/home/HomeModule.kt | 14 +++- .../timeline/factory/EncryptedItemFactory.kt | 53 +++++++------ .../timeline/factory/MessageItemFactory.kt | 51 ++---------- .../timeline/factory/TimelineItemFactory.kt | 2 +- .../util/MessageInformationDataFactory.kt | 77 +++++++++++++++++++ 5 files changed, 121 insertions(+), 76 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/util/MessageInformationDataFactory.kt diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt index 22d52787..7f85269a 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt @@ -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(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) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt index 4e892183..92294f19 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt @@ -16,28 +16,28 @@ 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 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.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?): 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 +46,21 @@ 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) + + // TODO Handle click on this event } - else -> null + else -> null } } -} \ No newline at end of file +} diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt index a4b31251..cc733382 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -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 { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt index c4609f88..a39998f3 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt @@ -53,7 +53,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, // Crypto EventType.ENCRYPTION -> encryptionItemFactory.create(event) - EventType.ENCRYPTED -> encryptedItemFactory.create(event) + EventType.ENCRYPTED -> encryptedItemFactory.create(event, nextEvent) // Unhandled event types (yet) EventType.STATE_ROOM_THIRD_PARTY_INVITE, diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/util/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/util/MessageInformationDataFactory.kt new file mode 100644 index 00000000..0ee5cd2f --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/util/MessageInformationDataFactory.kt @@ -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 + ) + } +} \ No newline at end of file From 5bfa67b4425db92ebfec408b436a6e78c2b3db80 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Jun 2019 12:45:24 +0200 Subject: [PATCH 4/6] Handle click on encrypted message --- .../home/room/detail/RoomDetailFragment.kt | 6 +++++- .../detail/timeline/TimelineEventController.kt | 1 + .../timeline/factory/EncryptedItemFactory.kt | 18 +++++++++++++++--- .../timeline/factory/TimelineItemFactory.kt | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index 1cabc032..3bf34534 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -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") diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt index 5b325c4a..1b060883 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt index 92294f19..7f2aca51 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt @@ -16,6 +16,7 @@ package im.vector.riotredesign.features.home.room.detail.timeline.factory +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 @@ -23,6 +24,8 @@ 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.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 @@ -32,7 +35,9 @@ class EncryptedItemFactory(private val messageInformationDataFactory: MessageInf private val colorProvider: ColorProvider, private val stringProvider: StringProvider) { - fun create(event: TimelineEvent, nextEvent: TimelineEvent?): VectorEpoxyModel<*>? { + fun create(event: TimelineEvent, + nextEvent: TimelineEvent?, + callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? { event.root.eventId ?: return null return when { @@ -57,8 +62,15 @@ class EncryptedItemFactory(private val messageInformationDataFactory: MessageInf return MessageTextItem_() .message(spannableStr) .informationData(informationData) - - // TODO Handle click on this event + .avatarCallback(callback) + .cellClickListener( + DebouncedClickListener(View.OnClickListener { view -> + callback?.onEncryptedMessageClicked(informationData, view) + })) + .longClickListener { view -> + return@longClickListener callback?.onEventLongClicked(informationData, null, view) + ?: false + } } else -> null } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt index a39998f3..d47fc9e1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt @@ -53,7 +53,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, // Crypto EventType.ENCRYPTION -> encryptionItemFactory.create(event) - EventType.ENCRYPTED -> encryptedItemFactory.create(event, nextEvent) + EventType.ENCRYPTED -> encryptedItemFactory.create(event, nextEvent, callback) // Unhandled event types (yet) EventType.STATE_ROOM_THIRD_PARTY_INVITE, From 7fe662598bd060543d07dec79a508ee5d8ab4ee2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Jun 2019 12:56:08 +0200 Subject: [PATCH 5/6] Handle click on encryption message --- .../room/detail/timeline/factory/EncryptionItemFactory.kt | 7 +++++-- .../room/detail/timeline/factory/TimelineItemFactory.kt | 2 +- .../features/home/room/detail/timeline/item/NoticeItem.kt | 4 +--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt index d0ca0ffc..6dc83c24 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt @@ -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() ?: return null stringProvider.getString(R.string.notice_end_to_end, senderName, content.algorithm) } - else -> null + else -> null } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt index d47fc9e1..deff306d 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt @@ -52,7 +52,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, EventType.CALL_ANSWER -> noticeItemFactory.create(event, callback) // Crypto - EventType.ENCRYPTION -> encryptionItemFactory.create(event) + EventType.ENCRYPTION -> encryptionItemFactory.create(event, callback) EventType.ENCRYPTED -> encryptedItemFactory.create(event, nextEvent, callback) // Unhandled event types (yet) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt index d190875f..72ea0330 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt @@ -38,11 +38,9 @@ abstract class NoticeItem : BaseEventItem() { 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 From 02f84a3b539e776f89edc0016c4041dd1bff2e73 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Jun 2019 13:14:39 +0200 Subject: [PATCH 6/6] View source of encrypted event --- .../android/api/session/room/timeline/TimelineEvent.kt | 6 +++--- .../room/detail/timeline/action/MessageMenuViewModel.kt | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt index 9ba481a4..76217027 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt @@ -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 } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt index f74a953e..0e27beb6 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt @@ -123,7 +123,11 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel