Message state: adjust some ui

This commit is contained in:
ganfra 2021-03-10 17:57:15 +01:00
parent fad4140924
commit bbb5dd06a2
7 changed files with 148 additions and 125 deletions

View file

@ -50,17 +50,8 @@ class MessageColorProvider @Inject constructor(
SendState.FAILED_UNKNOWN_DEVICES -> colorProvider.getColorFromAttribute(R.attr.vctr_unsent_message_text_color) SendState.FAILED_UNKNOWN_DEVICES -> colorProvider.getColorFromAttribute(R.attr.vctr_unsent_message_text_color)
} }
} else { } else {
// When not in developer mode, we do not use special color for the encrypting state // When not in developer mode, we use only one color
when (sendState) { colorProvider.getColorFromAttribute(R.attr.vctr_message_text_color)
SendState.UNKNOWN,
SendState.UNSENT,
SendState.ENCRYPTING,
SendState.SENDING,
SendState.SENT,
SendState.SYNCED -> colorProvider.getColorFromAttribute(R.attr.vctr_message_text_color)
SendState.UNDELIVERED,
SendState.FAILED_UNKNOWN_DEVICES -> colorProvider.getColorFromAttribute(R.attr.vctr_unsent_message_text_color)
}
} }
} }
} }

View file

@ -35,6 +35,7 @@ import im.vector.app.features.home.room.detail.timeline.item.E2EDecoration
import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod
import im.vector.app.features.home.room.detail.timeline.tools.linkify import im.vector.app.features.home.room.detail.timeline.tools.linkify
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.room.send.SendState
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -65,23 +66,23 @@ class MessageActionsEpoxyController @Inject constructor(
// Send state // Send state
val sendState = state.sendState() val sendState = state.sendState()
if (sendState?.isSending().orFalse()) { if (sendState?.hasFailed().orFalse()) {
bottomSheetSendStateItem {
id("send_state")
showProgress(true)
text(stringProvider.getString(R.string.event_status_sending_message))
}
} else if (sendState?.hasFailed().orFalse()) {
bottomSheetSendStateItem { bottomSheetSendStateItem {
id("send_state") id("send_state")
showProgress(false) showProgress(false)
text(stringProvider.getString(R.string.unable_to_send_message)) text(stringProvider.getString(R.string.unable_to_send_message))
drawableStart(R.drawable.ic_warning_badge) drawableStart(R.drawable.ic_warning_badge)
} }
} else if (sendState != SendState.SYNCED) {
bottomSheetSendStateItem {
id("send_state")
showProgress(true)
text(stringProvider.getString(R.string.event_status_sending_message))
}
} }
when (state.informationData.e2eDecoration) { when (state.informationData.e2eDecoration) {
E2EDecoration.WARN_IN_CLEAR -> { E2EDecoration.WARN_IN_CLEAR -> {
bottomSheetSendStateItem { bottomSheetSendStateItem {
id("e2e_clear") id("e2e_clear")
showProgress(false) showProgress(false)

View file

@ -18,10 +18,10 @@ package im.vector.app.features.home.room.detail.timeline.action
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory
import dagger.Lazy import dagger.Lazy
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.canReact import im.vector.app.core.extensions.canReact
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
@ -229,99 +229,19 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
} }
private fun actionsForEvent(timelineEvent: TimelineEvent, actionPermissions: ActionPermissions): List<EventSharedAction> { private fun actionsForEvent(timelineEvent: TimelineEvent, actionPermissions: ActionPermissions): List<EventSharedAction> {
val eventId = timelineEvent.eventId
val messageContent = timelineEvent.getLastMessageContent() val messageContent = timelineEvent.getLastMessageContent()
val msgType = messageContent?.msgType val msgType = messageContent?.msgType
return arrayListOf<EventSharedAction>().apply { return arrayListOf<EventSharedAction>().apply {
if (timelineEvent.root.sendState.hasFailed()) { when {
if (canRetry(timelineEvent, actionPermissions)) { timelineEvent.root.sendState.hasFailed() -> {
add(EventSharedAction.Resend(eventId)) addActionsForFailedState(timelineEvent, actionPermissions, messageContent, msgType)
} }
add(EventSharedAction.Remove(eventId)) timelineEvent.root.sendState.isSending() -> {
if (vectorPreferences.developerMode()) { addActionsForSendingState(timelineEvent)
addViewSourceItems(timelineEvent)
} }
} else if (timelineEvent.root.sendState.isSending()) { timelineEvent.root.sendState == SendState.SYNCED -> {
// TODO is uploading attachment? addActionsForSyncedState(timelineEvent, actionPermissions, messageContent, msgType)
if (canCancel(timelineEvent)) {
add(EventSharedAction.Cancel(eventId))
}
} else if (timelineEvent.root.sendState == SendState.SYNCED) {
if (!timelineEvent.root.isRedacted()) {
if (canReply(timelineEvent, messageContent, actionPermissions)) {
add(EventSharedAction.Reply(eventId))
}
if (canEdit(timelineEvent, session.myUserId, actionPermissions)) {
add(EventSharedAction.Edit(eventId))
}
if (canRedact(timelineEvent, actionPermissions)) {
add(EventSharedAction.Redact(eventId, askForReason = informationData.senderId != session.myUserId))
}
if (canCopy(msgType)) {
// TODO copy images? html? see ClipBoard
add(EventSharedAction.Copy(messageContent!!.body))
}
if (timelineEvent.canReact() && actionPermissions.canReact) {
add(EventSharedAction.AddReaction(eventId))
}
if (canQuote(timelineEvent, messageContent, actionPermissions)) {
add(EventSharedAction.Quote(eventId))
}
if (canViewReactions(timelineEvent)) {
add(EventSharedAction.ViewReactions(informationData))
}
if (timelineEvent.hasBeenEdited()) {
add(EventSharedAction.ViewEditHistory(informationData))
}
if (canShare(msgType)) {
add(EventSharedAction.Share(timelineEvent.eventId, messageContent!!))
}
if (canSave(msgType) && messageContent is MessageWithAttachmentContent) {
add(EventSharedAction.Save(timelineEvent.eventId, messageContent))
}
if (timelineEvent.root.sendState == SendState.SENT) {
// TODO Can be redacted
// TODO sent by me or sufficient power level
}
}
if (vectorPreferences.developerMode()) {
if (timelineEvent.isEncrypted() && timelineEvent.root.mCryptoError != null) {
val keysBackupService = session.cryptoService().keysBackupService()
if (keysBackupService.state == KeysBackupState.NotTrusted
|| (keysBackupService.state == KeysBackupState.ReadyToBackUp
&& keysBackupService.canRestoreKeys())
) {
add(EventSharedAction.UseKeyBackup)
}
if (session.cryptoService().getCryptoDeviceInfo(session.myUserId).size > 1
|| timelineEvent.senderInfo.userId != session.myUserId) {
add(EventSharedAction.ReRequestKey(timelineEvent.eventId))
}
}
addViewSourceItems(timelineEvent)
}
add(EventSharedAction.CopyPermalink(eventId))
if (session.myUserId != timelineEvent.root.senderId) {
// not sent by me
if (timelineEvent.root.getClearType() == EventType.MESSAGE) {
add(EventSharedAction.ReportContent(eventId, timelineEvent.root.senderId))
}
add(EventSharedAction.Separator)
add(EventSharedAction.IgnoreUser(timelineEvent.root.senderId))
} }
} }
} }
@ -336,6 +256,116 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
} }
} }
private fun ArrayList<EventSharedAction>.addActionsForFailedState(timelineEvent: TimelineEvent,
actionPermissions: ActionPermissions,
messageContent: MessageContent?,
msgType: String?) {
val eventId = timelineEvent.eventId
if (canRetry(timelineEvent, actionPermissions)) {
add(EventSharedAction.Resend(eventId))
}
add(EventSharedAction.Remove(eventId))
if (canEdit(timelineEvent, session.myUserId, actionPermissions)) {
add(EventSharedAction.Edit(eventId))
}
if (canCopy(msgType)) {
// TODO copy images? html? see ClipBoard
add(EventSharedAction.Copy(messageContent!!.body))
}
if (vectorPreferences.developerMode()) {
addViewSourceItems(timelineEvent)
}
}
private fun ArrayList<EventSharedAction>.addActionsForSendingState(timelineEvent: TimelineEvent) {
// TODO is uploading attachment?
if (canCancel(timelineEvent)) {
add(EventSharedAction.Cancel(timelineEvent.eventId))
}
}
private fun ArrayList<EventSharedAction>.addActionsForSyncedState(timelineEvent: TimelineEvent,
actionPermissions: ActionPermissions,
messageContent: MessageContent?,
msgType: String?) {
val eventId = timelineEvent.eventId
if (!timelineEvent.root.isRedacted()) {
if (canReply(timelineEvent, messageContent, actionPermissions)) {
add(EventSharedAction.Reply(eventId))
}
if (canEdit(timelineEvent, session.myUserId, actionPermissions)) {
add(EventSharedAction.Edit(eventId))
}
if (canRedact(timelineEvent, actionPermissions)) {
add(EventSharedAction.Redact(eventId, askForReason = informationData.senderId != session.myUserId))
}
if (canCopy(msgType)) {
// TODO copy images? html? see ClipBoard
add(EventSharedAction.Copy(messageContent!!.body))
}
if (timelineEvent.canReact() && actionPermissions.canReact) {
add(EventSharedAction.AddReaction(eventId))
}
if (canQuote(timelineEvent, messageContent, actionPermissions)) {
add(EventSharedAction.Quote(eventId))
}
if (canViewReactions(timelineEvent)) {
add(EventSharedAction.ViewReactions(informationData))
}
if (timelineEvent.hasBeenEdited()) {
add(EventSharedAction.ViewEditHistory(informationData))
}
if (canShare(msgType)) {
add(EventSharedAction.Share(timelineEvent.eventId, messageContent!!))
}
if (canSave(msgType) && messageContent is MessageWithAttachmentContent) {
add(EventSharedAction.Save(timelineEvent.eventId, messageContent))
}
if (timelineEvent.root.sendState == SendState.SENT) {
// TODO Can be redacted
// TODO sent by me or sufficient power level
}
}
if (vectorPreferences.developerMode()) {
if (timelineEvent.isEncrypted() && timelineEvent.root.mCryptoError != null) {
val keysBackupService = session.cryptoService().keysBackupService()
if (keysBackupService.state == KeysBackupState.NotTrusted
|| (keysBackupService.state == KeysBackupState.ReadyToBackUp
&& keysBackupService.canRestoreKeys())
) {
add(EventSharedAction.UseKeyBackup)
}
if (session.cryptoService().getCryptoDeviceInfo(session.myUserId).size > 1
|| timelineEvent.senderInfo.userId != session.myUserId) {
add(EventSharedAction.ReRequestKey(timelineEvent.eventId))
}
}
addViewSourceItems(timelineEvent)
}
add(EventSharedAction.CopyPermalink(eventId))
if (session.myUserId != timelineEvent.root.senderId) {
// not sent by me
if (timelineEvent.root.getClearType() == EventType.MESSAGE) {
add(EventSharedAction.ReportContent(eventId, timelineEvent.root.senderId))
}
add(EventSharedAction.Separator)
add(EventSharedAction.IgnoreUser(timelineEvent.root.senderId))
}
}
private fun canCancel(@Suppress("UNUSED_PARAMETER") event: TimelineEvent): Boolean { private fun canCancel(@Suppress("UNUSED_PARAMETER") event: TimelineEvent): Boolean {
return true return true
} }

View file

@ -5,7 +5,7 @@
android:id="@+id/messageStatusInfo" android:id="@+id/messageStatusInfo"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="64dp" android:layout_marginStart="16dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginBottom="4dp"> android:layout_marginBottom="4dp">

View file

@ -136,8 +136,8 @@
<im.vector.app.core.ui.views.SendStateImageView <im.vector.app.core.ui.views.SendStateImageView
android:id="@+id/messageSendStateImageView" android:id="@+id/messageSendStateImageView"
android:layout_width="wrap_content" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="wrap_content" android:layout_height="@dimen/item_event_message_state_size"
android:layout_alignBottom="@+id/viewStubContainer" android:layout_alignBottom="@+id/viewStubContainer"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
@ -150,8 +150,8 @@
<ProgressBar <ProgressBar
android:id="@+id/eventSendingIndicator" android:id="@+id/eventSendingIndicator"
android:layout_width="16dp" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="16dp" android:layout_height="@dimen/item_event_message_state_size"
android:layout_alignBottom="@+id/viewStubContainer" android:layout_alignBottom="@+id/viewStubContainer"
android:indeterminateTint="?riotx_text_secondary" android:indeterminateTint="?riotx_text_secondary"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"

View file

@ -9,7 +9,7 @@
<TextView <TextView
android:id="@+id/receiptMore" android:id="@+id/receiptMore"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="18dp" android:layout_height="@dimen/item_event_message_state_size"
android:background="@drawable/pill_receipt" android:background="@drawable/pill_receipt"
android:gravity="center" android:gravity="center"
android:importantForAccessibility="no" android:importantForAccessibility="no"
@ -20,8 +20,8 @@
<ImageView <ImageView
android:id="@+id/receiptAvatar5" android:id="@+id/receiptAvatar5"
android:layout_width="18dp" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="18dp" android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp" android:layout_marginStart="2dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:importantForAccessibility="no" android:importantForAccessibility="no"
@ -30,8 +30,8 @@
<ImageView <ImageView
android:id="@+id/receiptAvatar4" android:id="@+id/receiptAvatar4"
android:layout_width="18dp" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="18dp" android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp" android:layout_marginStart="2dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:importantForAccessibility="no" android:importantForAccessibility="no"
@ -40,8 +40,8 @@
<ImageView <ImageView
android:id="@+id/receiptAvatar3" android:id="@+id/receiptAvatar3"
android:layout_width="18dp" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="18dp" android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp" android:layout_marginStart="2dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:importantForAccessibility="no" android:importantForAccessibility="no"
@ -50,8 +50,8 @@
<ImageView <ImageView
android:id="@+id/receiptAvatar2" android:id="@+id/receiptAvatar2"
android:layout_width="18dp" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="18dp" android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp" android:layout_marginStart="2dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:importantForAccessibility="no" android:importantForAccessibility="no"
@ -60,8 +60,8 @@
<ImageView <ImageView
android:id="@+id/receiptAvatar1" android:id="@+id/receiptAvatar1"
android:layout_width="18dp" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="18dp" android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp" android:layout_marginStart="2dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:importantForAccessibility="no" android:importantForAccessibility="no"

View file

@ -13,6 +13,7 @@
<dimen name="navigation_view_height">196dp</dimen> <dimen name="navigation_view_height">196dp</dimen>
<dimen name="navigation_avatar_top_margin">44dp</dimen> <dimen name="navigation_avatar_top_margin">44dp</dimen>
<dimen name="item_decoration_left_margin">72dp</dimen> <dimen name="item_decoration_left_margin">72dp</dimen>
<dimen name="item_event_message_state_size">16dp</dimen>
<dimen name="chat_avatar_size">40dp</dimen> <dimen name="chat_avatar_size">40dp</dimen>
<dimen name="member_list_avatar_size">60dp</dimen> <dimen name="member_list_avatar_size">60dp</dimen>