Refactoring (duplication in Message Item Factory) + cleaning

This commit is contained in:
Valere 2019-06-05 23:45:46 +02:00
parent 297f202005
commit e22b555b58
5 changed files with 69 additions and 112 deletions

View File

@ -46,7 +46,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
private val backgroundHandler: Handler = TimelineAsyncHelper.getBackgroundHandler() private val backgroundHandler: Handler = TimelineAsyncHelper.getBackgroundHandler()
) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener { ) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener {


interface Callback : ReactionPillCallback { interface Callback : ReactionPillCallback, AvatarCallback {
fun onEventVisible(event: TimelineEvent) fun onEventVisible(event: TimelineEvent)
fun onUrlClicked(url: String) fun onUrlClicked(url: String)
fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View)
@ -55,8 +55,6 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
fun onAudioMessageClicked(messageAudioContent: MessageAudioContent) fun onAudioMessageClicked(messageAudioContent: MessageAudioContent)
fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View) fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View)
fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View): Boolean fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View): Boolean
fun onAvatarClicked(informationData: MessageInformationData)
fun onMemberNameClicked(informationData: MessageInformationData)
fun onEditedDecorationClicked(informationData: MessageInformationData, editAggregatedSummary: EditAggregatedSummary?) fun onEditedDecorationClicked(informationData: MessageInformationData, editAggregatedSummary: EditAggregatedSummary?)
} }


@ -65,6 +63,11 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
fun onLongClickOnReactionPill(informationData: MessageInformationData, reaction: String) fun onLongClickOnReactionPill(informationData: MessageInformationData, reaction: String)
} }


interface AvatarCallback {
fun onAvatarClicked(informationData: MessageInformationData)
fun onMemberNameClicked(informationData: MessageInformationData)
}

private val collapsedEventIds = linkedSetOf<String>() private val collapsedEventIds = linkedSetOf<String>()
private val mergeItemCollapseStates = HashMap<String, Boolean>() private val mergeItemCollapseStates = HashMap<String, Boolean>()
private val modelCache = arrayListOf<CacheItemData?>() private val modelCache = arrayListOf<CacheItemData?>()

View File

@ -1,16 +1,12 @@
package im.vector.riotredesign.features.home.room.detail.timeline.action package im.vector.riotredesign.features.home.room.detail.timeline.action


import androidx.lifecycle.LifecycleOwner import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.airbnb.mvrx.* import com.airbnb.mvrx.*
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
import im.vector.riotredesign.core.extensions.localDateTime import im.vector.riotredesign.core.extensions.localDateTime
import im.vector.riotredesign.core.platform.VectorViewModel import im.vector.riotredesign.core.platform.VectorViewModel
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.koin.android.ext.android.get import org.koin.android.ext.android.get




@ -33,53 +29,41 @@ data class ReactionInfo(
*/ */
class ViewReactionViewModel(private val session: Session, class ViewReactionViewModel(private val session: Session,
private val timelineDateFormatter: TimelineDateFormatter, private val timelineDateFormatter: TimelineDateFormatter,
lifecycleOwner: LifecycleOwner?,
liveSummary: LiveData<List<EventAnnotationsSummary>>?,
initialState: DisplayReactionsViewState) : VectorViewModel<DisplayReactionsViewState>(initialState) { initialState: DisplayReactionsViewState) : VectorViewModel<DisplayReactionsViewState>(initialState) {


init { init {
loadReaction() loadReaction()
if (lifecycleOwner != null) {
liveSummary?.observe(lifecycleOwner, Observer {
it?.firstOrNull()?.let {
loadReaction()
}
})
}

} }


private fun loadReaction() = withState { state -> fun loadReaction() = withState { state ->


GlobalScope.launch { try {
try { val room = session.getRoom(state.roomId)
val room = session.getRoom(state.roomId) val event = room?.getTimeLineEvent(state.eventId)
val event = room?.getTimeLineEvent(state.eventId) if (event == null) {
if (event == null) { setState { copy(mapReactionKeyToMemberList = Fail(Throwable())) }
setState { copy(mapReactionKeyToMemberList = Fail(Throwable())) } return@withState
return@launch }
} var results = ArrayList<ReactionInfo>()
var results = ArrayList<ReactionInfo>() event.annotations?.reactionsSummary?.forEach { sum ->
event.annotations?.reactionsSummary?.forEach { sum ->


sum.sourceEvents.mapNotNull { room.getTimeLineEvent(it) }.forEach { sum.sourceEvents.mapNotNull { room.getTimeLineEvent(it) }.forEach {
val localDate = it.root.localDateTime() val localDate = it.root.localDateTime()
results.add(ReactionInfo(it.root.eventId!!, sum.key, it.root.sender results.add(ReactionInfo(it.root.eventId!!, sum.key, it.root.sender
?: "", it.senderName, timelineDateFormatter.formatMessageHour(localDate))) ?: "", it.senderName, timelineDateFormatter.formatMessageHour(localDate)))
}
}
setState {
copy(
mapReactionKeyToMemberList = Success(results.sortedBy { it.timestamp })
)
}
} catch (t: Throwable) {
setState {
copy(
mapReactionKeyToMemberList = Fail(t)
)
} }
} }
setState {
copy(
mapReactionKeyToMemberList = Success(results.sortedBy { it.timestamp })
)
}
} catch (t: Throwable) {
setState {
copy(
mapReactionKeyToMemberList = Fail(t)
)
}
} }
} }


@ -98,7 +82,18 @@ class ViewReactionViewModel(private val session: Session,
override fun create(viewModelContext: ViewModelContext, state: DisplayReactionsViewState): ViewReactionViewModel? { override fun create(viewModelContext: ViewModelContext, state: DisplayReactionsViewState): ViewReactionViewModel? {
val session = viewModelContext.activity.get<Session>() val session = viewModelContext.activity.get<Session>()
val eventId = (viewModelContext.args as TimelineEventFragmentArgs).eventId val eventId = (viewModelContext.args as TimelineEventFragmentArgs).eventId
return ViewReactionViewModel(session, viewModelContext.activity.get(), viewModelContext.activity, session.getRoom(state.roomId)?.getEventSummaryLive(eventId), state) val lifecycleOwner = (viewModelContext as FragmentViewModelContext).fragment<Fragment>()
val liveSummary = session.getRoom(state.roomId)?.getEventSummaryLive(eventId)
val viewReactionViewModel = ViewReactionViewModel(session, viewModelContext.activity.get(), state)
// This states observes the live summary
// When fragment context will be destroyed the observer will automatically removed
liveSummary?.observe(lifecycleOwner, Observer {
it?.firstOrNull()?.let {
viewReactionViewModel.loadReaction()
}
})

return viewReactionViewModel
} }





View File

@ -143,18 +143,11 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
callback: TimelineEventController.Callback?): MessageFileItem? { callback: TimelineEventController.Callback?): MessageFileItem? {
return MessageFileItem_() return MessageFileItem_()
.informationData(informationData) .informationData(informationData)
.avatarCallback(callback)
.filename(messageContent.body) .filename(messageContent.body)
.iconRes(R.drawable.filetype_audio) .iconRes(R.drawable.filetype_audio)
.reactionPillCallback(callback) .reactionPillCallback(callback)
.emojiTypeFace(emojiCompatFontProvider.typeface) .emojiTypeFace(emojiCompatFontProvider.typeface)
.avatarClickListener(
DebouncedClickListener(View.OnClickListener {
callback?.onAvatarClicked(informationData)
}))
.memberClickListener(
DebouncedClickListener(View.OnClickListener {
callback?.onMemberNameClicked(informationData)
}))
.cellClickListener( .cellClickListener(
DebouncedClickListener(View.OnClickListener { view: View -> DebouncedClickListener(View.OnClickListener { view: View ->
callback?.onEventCellClicked(informationData, messageContent, view) callback?.onEventCellClicked(informationData, messageContent, view)
@ -174,18 +167,11 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
callback: TimelineEventController.Callback?): MessageFileItem? { callback: TimelineEventController.Callback?): MessageFileItem? {
return MessageFileItem_() return MessageFileItem_()
.informationData(informationData) .informationData(informationData)
.avatarCallback(callback)
.filename(messageContent.body) .filename(messageContent.body)
.reactionPillCallback(callback) .reactionPillCallback(callback)
.emojiTypeFace(emojiCompatFontProvider.typeface) .emojiTypeFace(emojiCompatFontProvider.typeface)
.iconRes(R.drawable.filetype_attachment) .iconRes(R.drawable.filetype_attachment)
.avatarClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onAvatarClicked(informationData)
}))
.memberClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onMemberNameClicked(informationData)
}))
.cellClickListener( .cellClickListener(
DebouncedClickListener(View.OnClickListener { view -> DebouncedClickListener(View.OnClickListener { view ->
callback?.onEventCellClicked(informationData, messageContent, view) callback?.onEventCellClicked(informationData, messageContent, view)
@ -223,17 +209,10 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
return MessageImageVideoItem_() return MessageImageVideoItem_()
.playable(messageContent.info?.mimeType == "image/gif") .playable(messageContent.info?.mimeType == "image/gif")
.informationData(informationData) .informationData(informationData)
.avatarCallback(callback)
.mediaData(data) .mediaData(data)
.reactionPillCallback(callback) .reactionPillCallback(callback)
.emojiTypeFace(emojiCompatFontProvider.typeface) .emojiTypeFace(emojiCompatFontProvider.typeface)
.avatarClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onAvatarClicked(informationData)
}))
.memberClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onMemberNameClicked(informationData)
}))
.clickListener( .clickListener(
DebouncedClickListener(View.OnClickListener { view -> DebouncedClickListener(View.OnClickListener { view ->
callback?.onImageMessageClicked(messageContent, data, view) callback?.onImageMessageClicked(messageContent, data, view)
@ -271,17 +250,10 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
return MessageImageVideoItem_() return MessageImageVideoItem_()
.playable(true) .playable(true)
.informationData(informationData) .informationData(informationData)
.avatarCallback(callback)
.mediaData(thumbnailData) .mediaData(thumbnailData)
.reactionPillCallback(callback) .reactionPillCallback(callback)
.emojiTypeFace(emojiCompatFontProvider.typeface) .emojiTypeFace(emojiCompatFontProvider.typeface)
.avatarClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onAvatarClicked(informationData)
}))
.memberClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onMemberNameClicked(informationData)
}))
.cellClickListener( .cellClickListener(
DebouncedClickListener(View.OnClickListener { view -> DebouncedClickListener(View.OnClickListener { view ->
callback?.onEventCellClicked(informationData, messageContent, view) callback?.onEventCellClicked(informationData, messageContent, view)
@ -316,16 +288,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
} }
} }
.informationData(informationData) .informationData(informationData)
.avatarCallback(callback)
.reactionPillCallback(callback) .reactionPillCallback(callback)
.emojiTypeFace(emojiCompatFontProvider.typeface) .emojiTypeFace(emojiCompatFontProvider.typeface)
.avatarClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onAvatarClicked(informationData)
}))
.memberClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onMemberNameClicked(informationData)
}))
//click on the text //click on the text
.clickListener( .clickListener(
DebouncedClickListener(View.OnClickListener { view -> DebouncedClickListener(View.OnClickListener { view ->
@ -390,12 +355,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
return MessageTextItem_() return MessageTextItem_()
.message(message) .message(message)
.informationData(informationData) .informationData(informationData)
.avatarCallback(callback)
.reactionPillCallback(callback) .reactionPillCallback(callback)
.emojiTypeFace(emojiCompatFontProvider.typeface) .emojiTypeFace(emojiCompatFontProvider.typeface)
.avatarClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onAvatarClicked(informationData)
}))
.memberClickListener( .memberClickListener(
DebouncedClickListener(View.OnClickListener { view -> DebouncedClickListener(View.OnClickListener { view ->
callback?.onMemberNameClicked(informationData) callback?.onMemberNameClicked(informationData)
@ -430,16 +392,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
} }
} }
.informationData(informationData) .informationData(informationData)
.avatarCallback(callback)
.reactionPillCallback(callback) .reactionPillCallback(callback)
.emojiTypeFace(emojiCompatFontProvider.typeface) .emojiTypeFace(emojiCompatFontProvider.typeface)
.avatarClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onAvatarClicked(informationData)
}))
.memberClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onMemberNameClicked(informationData)
}))
.cellClickListener( .cellClickListener(
DebouncedClickListener(View.OnClickListener { view -> DebouncedClickListener(View.OnClickListener { view ->
callback?.onEventCellClicked(informationData, messageContent, view) callback?.onEventCellClicked(informationData, messageContent, view)
@ -454,14 +409,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
callback: TimelineEventController.Callback?): RedactedMessageItem? { callback: TimelineEventController.Callback?): RedactedMessageItem? {
return RedactedMessageItem_() return RedactedMessageItem_()
.informationData(informationData) .informationData(informationData)
.avatarClickListener( .avatarCallback(callback)
DebouncedClickListener(View.OnClickListener { view ->
callback?.onAvatarClicked(informationData)
}))
.memberClickListener(
DebouncedClickListener(View.OnClickListener { view ->
callback?.onMemberNameClicked(informationData)
}))
} }


private fun linkifyBody(body: CharSequence, callback: TimelineEventController.Callback?): CharSequence { private fun linkifyBody(body: CharSequence, callback: TimelineEventController.Callback?): CharSequence {

View File

@ -29,6 +29,7 @@ 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.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.utils.DebouncedClickListener
import im.vector.riotredesign.core.utils.DimensionUtils.dpToPx import im.vector.riotredesign.core.utils.DimensionUtils.dpToPx
import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.AvatarRenderer
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
@ -45,9 +46,6 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
@EpoxyAttribute @EpoxyAttribute
var cellClickListener: View.OnClickListener? = null var cellClickListener: View.OnClickListener? = null


@EpoxyAttribute
var avatarClickListener: View.OnClickListener? = null

@EpoxyAttribute @EpoxyAttribute
var memberClickListener: View.OnClickListener? = null var memberClickListener: View.OnClickListener? = null


@ -57,6 +55,17 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
@EpoxyAttribute @EpoxyAttribute
var reactionPillCallback: TimelineEventController.ReactionPillCallback? = null var reactionPillCallback: TimelineEventController.ReactionPillCallback? = null


@EpoxyAttribute
var avatarCallback: TimelineEventController.AvatarCallback?= null

private val _avatarClickListener = DebouncedClickListener(View.OnClickListener {
avatarCallback?.onAvatarClicked(informationData)
})
private val _memberNameClickListener = DebouncedClickListener(View.OnClickListener {
avatarCallback?.onMemberNameClicked(informationData)
})


var reactionClickListener: ReactionButton.ReactedListener = object : ReactionButton.ReactedListener { var reactionClickListener: ReactionButton.ReactedListener = object : ReactionButton.ReactedListener {
override fun onReacted(reactionButton: ReactionButton) { override fun onReacted(reactionButton: ReactionButton) {
reactionPillCallback?.onClickOnReactionPill(informationData, reactionButton.reactionString, true) reactionPillCallback?.onClickOnReactionPill(informationData, reactionButton.reactionString, true)
@ -81,9 +90,9 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
width = size width = size
} }
holder.avatarImageView.visibility = View.VISIBLE holder.avatarImageView.visibility = View.VISIBLE
holder.avatarImageView.setOnClickListener(avatarClickListener) holder.avatarImageView.setOnClickListener(_avatarClickListener)
holder.memberNameView.visibility = View.VISIBLE holder.memberNameView.visibility = View.VISIBLE
holder.memberNameView.setOnClickListener(memberClickListener) holder.memberNameView.setOnClickListener(_memberNameClickListener)
holder.timeView.visibility = View.VISIBLE holder.timeView.visibility = View.VISIBLE
holder.timeView.text = informationData.time holder.timeView.text = informationData.time
holder.memberNameView.text = informationData.memberName holder.memberNameView.text = informationData.memberName

View File

@ -11,8 +11,10 @@


<TextView <TextView
android:id="@+id/itemSimpleReactionInfoKey" android:id="@+id/itemSimpleReactionInfoKey"
android:layout_width="44dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:gravity="center" android:gravity="center"
android:lines="1" android:lines="1"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"