mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 13:38:49 +03:00
Merge pull request #407 from vector-im/feature/pending_edits_ux
Feature/pending edits ux
This commit is contained in:
commit
6176520805
6 changed files with 64 additions and 23 deletions
|
@ -5,6 +5,7 @@ Features:
|
||||||
-
|
-
|
||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
|
- UI for pending edits (#193)
|
||||||
- UX image preview screen transition (#393)
|
- UX image preview screen transition (#393)
|
||||||
|
|
||||||
Other changes:
|
Other changes:
|
||||||
|
|
|
@ -83,21 +83,21 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor(
|
||||||
if (event.unsignedData?.relations?.annotations != null) {
|
if (event.unsignedData?.relations?.annotations != null) {
|
||||||
Timber.v("###REACTION Agreggation in room $roomId for event ${event.eventId}")
|
Timber.v("###REACTION Agreggation in room $roomId for event ${event.eventId}")
|
||||||
handleInitialAggregatedRelations(event, roomId, event.unsignedData.relations.annotations, realm)
|
handleInitialAggregatedRelations(event, roomId, event.unsignedData.relations.annotations, realm)
|
||||||
} else {
|
|
||||||
val content: MessageContent? = event.content.toModel()
|
EventAnnotationsSummaryEntity.where(realm, event.eventId
|
||||||
if (content?.relatesTo?.type == RelationType.REPLACE) {
|
?: "").findFirst()?.let {
|
||||||
Timber.v("###REPLACE in room $roomId for event ${event.eventId}")
|
TimelineEventEntity.where(realm, eventId = event.eventId
|
||||||
//A replace!
|
?: "").findFirst()?.let { tet ->
|
||||||
handleReplace(realm, event, content, roomId, isLocalEcho)
|
tet.annotations = it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventAnnotationsSummaryEntity.where(realm, event.eventId
|
val content: MessageContent? = event.content.toModel()
|
||||||
?: "").findFirst()?.let {
|
if (content?.relatesTo?.type == RelationType.REPLACE) {
|
||||||
TimelineEventEntity.where(realm, eventId = event.eventId
|
Timber.v("###REPLACE in room $roomId for event ${event.eventId}")
|
||||||
?: "").findFirst()?.let { tet ->
|
//A replace!
|
||||||
tet.annotations = it
|
handleReplace(realm, event, content, roomId, isLocalEcho)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,11 +178,12 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor(
|
||||||
Timber.v("###REPLACE new edit summary for ${targetEventId}, creating one (localEcho:$isLocalEcho)")
|
Timber.v("###REPLACE new edit summary for ${targetEventId}, creating one (localEcho:$isLocalEcho)")
|
||||||
//create the edit summary
|
//create the edit summary
|
||||||
val editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java)
|
val editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java)
|
||||||
editSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis()
|
|
||||||
editSummary.aggregatedContent = ContentMapper.map(newContent)
|
editSummary.aggregatedContent = ContentMapper.map(newContent)
|
||||||
if (isLocalEcho) {
|
if (isLocalEcho) {
|
||||||
|
editSummary.lastEditTs = 0
|
||||||
editSummary.sourceLocalEchoEvents.add(eventId)
|
editSummary.sourceLocalEchoEvents.add(eventId)
|
||||||
} else {
|
} else {
|
||||||
|
editSummary.lastEditTs = event.originServerTs ?: 0
|
||||||
editSummary.sourceEvents.add(eventId)
|
editSummary.sourceEvents.add(eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,13 +201,26 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor(
|
||||||
Timber.v("###REPLACE Receiving remote echo of edit (edit already done)")
|
Timber.v("###REPLACE Receiving remote echo of edit (edit already done)")
|
||||||
existingSummary.sourceLocalEchoEvents.remove(txId)
|
existingSummary.sourceLocalEchoEvents.remove(txId)
|
||||||
existingSummary.sourceEvents.add(event.eventId)
|
existingSummary.sourceEvents.add(event.eventId)
|
||||||
} else if (event.originServerTs ?: 0 > existingSummary.lastEditTs) {
|
} else if (
|
||||||
|
isLocalEcho // do not rely on ts for local echo, take it
|
||||||
|
|| event.originServerTs ?: 0 >= existingSummary.lastEditTs
|
||||||
|
) {
|
||||||
Timber.v("###REPLACE Computing aggregated edit summary (isLocalEcho:$isLocalEcho)")
|
Timber.v("###REPLACE Computing aggregated edit summary (isLocalEcho:$isLocalEcho)")
|
||||||
existingSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis()
|
if (!isLocalEcho) {
|
||||||
|
//Do not take local echo originServerTs here, could mess up ordering (keep old ts)
|
||||||
|
existingSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis()
|
||||||
|
}
|
||||||
existingSummary.aggregatedContent = ContentMapper.map(newContent)
|
existingSummary.aggregatedContent = ContentMapper.map(newContent)
|
||||||
existingSummary.sourceEvents.add(eventId)
|
if (isLocalEcho) {
|
||||||
|
existingSummary.sourceLocalEchoEvents.add(eventId)
|
||||||
|
} else {
|
||||||
|
existingSummary.sourceEvents.add(eventId)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//ignore this event for the summary
|
//ignore this event for the summary (back paginate)
|
||||||
|
if (!isLocalEcho) {
|
||||||
|
existingSummary.sourceEvents.add(eventId)
|
||||||
|
}
|
||||||
Timber.v("###REPLACE ignoring event for summary, it's to old $eventId")
|
Timber.v("###REPLACE ignoring event for summary, it's to old $eventId")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,11 +41,13 @@ import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.riotx.core.linkify.VectorLinkify
|
import im.vector.riotx.core.linkify.VectorLinkify
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
import im.vector.riotx.core.resources.ColorProvider
|
||||||
import im.vector.riotx.core.resources.StringProvider
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
import im.vector.riotx.core.resources.UserPreferencesProvider
|
||||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.helper.senderAvatar
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.*
|
import im.vector.riotx.features.home.room.detail.timeline.item.*
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
import im.vector.riotx.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||||
import im.vector.riotx.features.html.EventHtmlRenderer
|
import im.vector.riotx.features.html.EventHtmlRenderer
|
||||||
|
@ -63,7 +65,8 @@ class MessageItemFactory @Inject constructor(
|
||||||
private val emojiCompatFontProvider: EmojiCompatFontProvider,
|
private val emojiCompatFontProvider: EmojiCompatFontProvider,
|
||||||
private val imageContentRenderer: ImageContentRenderer,
|
private val imageContentRenderer: ImageContentRenderer,
|
||||||
private val messageInformationDataFactory: MessageInformationDataFactory,
|
private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||||
private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder) {
|
private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder,
|
||||||
|
private val userPreferencesProvider: UserPreferencesProvider) {
|
||||||
|
|
||||||
|
|
||||||
fun create(event: TimelineEvent,
|
fun create(event: TimelineEvent,
|
||||||
|
@ -89,7 +92,26 @@ class MessageItemFactory @Inject constructor(
|
||||||
|| event.isEncrypted() && event.root.content.toModel<EncryptedEventContent>()?.relatesTo?.type == RelationType.REPLACE
|
|| event.isEncrypted() && event.root.content.toModel<EncryptedEventContent>()?.relatesTo?.type == RelationType.REPLACE
|
||||||
) {
|
) {
|
||||||
// ignore replace event, the targeted id is already edited
|
// ignore replace event, the targeted id is already edited
|
||||||
return BlankItem_()
|
if (userPreferencesProvider.shouldShowHiddenEvents()) {
|
||||||
|
//These are just for debug to display hidden event, they should be filtered out in normal mode
|
||||||
|
val informationData = MessageInformationData(
|
||||||
|
eventId = event.root.eventId ?: "?",
|
||||||
|
senderId = event.root.senderId ?: "",
|
||||||
|
sendState = event.sendState,
|
||||||
|
time = "",
|
||||||
|
avatarUrl = event.senderAvatar(),
|
||||||
|
memberName = "",
|
||||||
|
showInformation = false
|
||||||
|
)
|
||||||
|
return NoticeItem_()
|
||||||
|
.avatarRenderer(avatarRenderer)
|
||||||
|
.informationData(informationData)
|
||||||
|
.noticeText("{ \"type\": ${event.root.getClearType()} }")
|
||||||
|
.highlighted(highlight)
|
||||||
|
.baseCallback(callback)
|
||||||
|
} else {
|
||||||
|
return BlankItem_()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// val all = event.root.toContent()
|
// val all = event.root.toContent()
|
||||||
// val ev = all.toModel<Event>()
|
// val ev = all.toModel<Event>()
|
||||||
|
|
|
@ -29,6 +29,7 @@ import androidx.core.view.children
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
import im.vector.riotx.core.resources.ColorProvider
|
||||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
|
@ -163,7 +164,8 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
||||||
|
|
||||||
protected fun renderSendState(root: View, textView: TextView?) {
|
protected fun renderSendState(root: View, textView: TextView?) {
|
||||||
root.isClickable = informationData.sendState.isSent()
|
root.isClickable = informationData.sendState.isSent()
|
||||||
textView?.setTextColor(colorProvider.getMessageTextColor(informationData.sendState))
|
val state = if (informationData.hasPendingEdits) SendState.UNSENT else informationData.sendState
|
||||||
|
textView?.setTextColor(colorProvider.getMessageTextColor(state))
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Holder(@IdRes stubId: Int) : BaseHolder(stubId) {
|
abstract class Holder(@IdRes stubId: Int) : BaseHolder(stubId) {
|
||||||
|
|
|
@ -30,8 +30,9 @@ data class MessageInformationData(
|
||||||
val memberName: CharSequence? = null,
|
val memberName: CharSequence? = null,
|
||||||
val showInformation: Boolean = true,
|
val showInformation: Boolean = true,
|
||||||
/*List of reactions (emoji,count,isSelected)*/
|
/*List of reactions (emoji,count,isSelected)*/
|
||||||
var orderedReactionList: List<ReactionInfoData>? = null,
|
val orderedReactionList: List<ReactionInfoData>? = null,
|
||||||
var hasBeenEdited: Boolean = false
|
val hasBeenEdited: Boolean = false,
|
||||||
|
val hasPendingEdits: Boolean = false
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,8 @@ class MessageInformationDataFactory @Inject constructor(private val timelineDate
|
||||||
?.map {
|
?.map {
|
||||||
ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty())
|
ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty())
|
||||||
},
|
},
|
||||||
hasBeenEdited = hasBeenEdited
|
hasBeenEdited = hasBeenEdited,
|
||||||
|
hasPendingEdits = event.annotations?.editSummary?.localEchos?.any() ?: false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue