From e22b555b58f5a79ed5669a9d64a3bf4b346078e4 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 5 Jun 2019 23:45:46 +0200 Subject: [PATCH] Refactoring (duplication in Message Item Factory) + cleaning --- .../timeline/TimelineEventController.kt | 9 ++- .../timeline/action/ViewReactionViewModel.kt | 81 +++++++++---------- .../timeline/factory/MessageItemFactory.kt | 68 ++-------------- .../detail/timeline/item/AbsMessageItem.kt | 19 +++-- .../res/layout/item_simple_reaction_info.xml | 4 +- 5 files changed, 69 insertions(+), 112 deletions(-) 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 175702cf..2861ae6a 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 @@ -46,7 +46,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter, private val backgroundHandler: Handler = TimelineAsyncHelper.getBackgroundHandler() ) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener { - interface Callback : ReactionPillCallback { + interface Callback : ReactionPillCallback, AvatarCallback { fun onEventVisible(event: TimelineEvent) fun onUrlClicked(url: String) fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) @@ -55,8 +55,6 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter, fun onAudioMessageClicked(messageAudioContent: MessageAudioContent) fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View) fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent, view: View): Boolean - fun onAvatarClicked(informationData: MessageInformationData) - fun onMemberNameClicked(informationData: MessageInformationData) fun onEditedDecorationClicked(informationData: MessageInformationData, editAggregatedSummary: EditAggregatedSummary?) } @@ -65,6 +63,11 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter, fun onLongClickOnReactionPill(informationData: MessageInformationData, reaction: String) } + interface AvatarCallback { + fun onAvatarClicked(informationData: MessageInformationData) + fun onMemberNameClicked(informationData: MessageInformationData) + } + private val collapsedEventIds = linkedSetOf() private val mergeItemCollapseStates = HashMap() private val modelCache = arrayListOf() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/ViewReactionViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/ViewReactionViewModel.kt index a5e7fdd8..88548865 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/ViewReactionViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/ViewReactionViewModel.kt @@ -1,16 +1,12 @@ package im.vector.riotredesign.features.home.room.detail.timeline.action -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LiveData +import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import com.airbnb.mvrx.* 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.platform.VectorViewModel 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 @@ -33,53 +29,41 @@ data class ReactionInfo( */ class ViewReactionViewModel(private val session: Session, private val timelineDateFormatter: TimelineDateFormatter, - lifecycleOwner: LifecycleOwner?, - liveSummary: LiveData>?, initialState: DisplayReactionsViewState) : VectorViewModel(initialState) { init { loadReaction() - if (lifecycleOwner != null) { - liveSummary?.observe(lifecycleOwner, Observer { - it?.firstOrNull()?.let { - loadReaction() - } - }) - } - } - private fun loadReaction() = withState { state -> + fun loadReaction() = withState { state -> - GlobalScope.launch { - try { - val room = session.getRoom(state.roomId) - val event = room?.getTimeLineEvent(state.eventId) - if (event == null) { - setState { copy(mapReactionKeyToMemberList = Fail(Throwable())) } - return@launch - } - var results = ArrayList() - event.annotations?.reactionsSummary?.forEach { sum -> + try { + val room = session.getRoom(state.roomId) + val event = room?.getTimeLineEvent(state.eventId) + if (event == null) { + setState { copy(mapReactionKeyToMemberList = Fail(Throwable())) } + return@withState + } + var results = ArrayList() + event.annotations?.reactionsSummary?.forEach { sum -> - sum.sourceEvents.mapNotNull { room.getTimeLineEvent(it) }.forEach { - val localDate = it.root.localDateTime() - results.add(ReactionInfo(it.root.eventId!!, sum.key, it.root.sender - ?: "", it.senderName, timelineDateFormatter.formatMessageHour(localDate))) - } - } - setState { - copy( - mapReactionKeyToMemberList = Success(results.sortedBy { it.timestamp }) - ) - } - } catch (t: Throwable) { - setState { - copy( - mapReactionKeyToMemberList = Fail(t) - ) + sum.sourceEvents.mapNotNull { room.getTimeLineEvent(it) }.forEach { + val localDate = it.root.localDateTime() + results.add(ReactionInfo(it.root.eventId!!, sum.key, it.root.sender + ?: "", it.senderName, timelineDateFormatter.formatMessageHour(localDate))) } } + 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? { val session = viewModelContext.activity.get() 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() + 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 } 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 7571fead..3390f4c2 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 @@ -143,18 +143,11 @@ class MessageItemFactory(private val colorProvider: ColorProvider, callback: TimelineEventController.Callback?): MessageFileItem? { return MessageFileItem_() .informationData(informationData) + .avatarCallback(callback) .filename(messageContent.body) .iconRes(R.drawable.filetype_audio) .reactionPillCallback(callback) .emojiTypeFace(emojiCompatFontProvider.typeface) - .avatarClickListener( - DebouncedClickListener(View.OnClickListener { - callback?.onAvatarClicked(informationData) - })) - .memberClickListener( - DebouncedClickListener(View.OnClickListener { - callback?.onMemberNameClicked(informationData) - })) .cellClickListener( DebouncedClickListener(View.OnClickListener { view: View -> callback?.onEventCellClicked(informationData, messageContent, view) @@ -174,18 +167,11 @@ class MessageItemFactory(private val colorProvider: ColorProvider, callback: TimelineEventController.Callback?): MessageFileItem? { return MessageFileItem_() .informationData(informationData) + .avatarCallback(callback) .filename(messageContent.body) .reactionPillCallback(callback) .emojiTypeFace(emojiCompatFontProvider.typeface) .iconRes(R.drawable.filetype_attachment) - .avatarClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onAvatarClicked(informationData) - })) - .memberClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onMemberNameClicked(informationData) - })) .cellClickListener( DebouncedClickListener(View.OnClickListener { view -> callback?.onEventCellClicked(informationData, messageContent, view) @@ -223,17 +209,10 @@ class MessageItemFactory(private val colorProvider: ColorProvider, return MessageImageVideoItem_() .playable(messageContent.info?.mimeType == "image/gif") .informationData(informationData) + .avatarCallback(callback) .mediaData(data) .reactionPillCallback(callback) .emojiTypeFace(emojiCompatFontProvider.typeface) - .avatarClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onAvatarClicked(informationData) - })) - .memberClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onMemberNameClicked(informationData) - })) .clickListener( DebouncedClickListener(View.OnClickListener { view -> callback?.onImageMessageClicked(messageContent, data, view) @@ -271,17 +250,10 @@ class MessageItemFactory(private val colorProvider: ColorProvider, return MessageImageVideoItem_() .playable(true) .informationData(informationData) + .avatarCallback(callback) .mediaData(thumbnailData) .reactionPillCallback(callback) .emojiTypeFace(emojiCompatFontProvider.typeface) - .avatarClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onAvatarClicked(informationData) - })) - .memberClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onMemberNameClicked(informationData) - })) .cellClickListener( DebouncedClickListener(View.OnClickListener { view -> callback?.onEventCellClicked(informationData, messageContent, view) @@ -316,16 +288,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider, } } .informationData(informationData) + .avatarCallback(callback) .reactionPillCallback(callback) .emojiTypeFace(emojiCompatFontProvider.typeface) - .avatarClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onAvatarClicked(informationData) - })) - .memberClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onMemberNameClicked(informationData) - })) //click on the text .clickListener( DebouncedClickListener(View.OnClickListener { view -> @@ -390,12 +355,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider, return MessageTextItem_() .message(message) .informationData(informationData) + .avatarCallback(callback) .reactionPillCallback(callback) .emojiTypeFace(emojiCompatFontProvider.typeface) - .avatarClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onAvatarClicked(informationData) - })) .memberClickListener( DebouncedClickListener(View.OnClickListener { view -> callback?.onMemberNameClicked(informationData) @@ -430,16 +392,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider, } } .informationData(informationData) + .avatarCallback(callback) .reactionPillCallback(callback) .emojiTypeFace(emojiCompatFontProvider.typeface) - .avatarClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onAvatarClicked(informationData) - })) - .memberClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onMemberNameClicked(informationData) - })) .cellClickListener( DebouncedClickListener(View.OnClickListener { view -> callback?.onEventCellClicked(informationData, messageContent, view) @@ -454,14 +409,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, callback: TimelineEventController.Callback?): RedactedMessageItem? { return RedactedMessageItem_() .informationData(informationData) - .avatarClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onAvatarClicked(informationData) - })) - .memberClickListener( - DebouncedClickListener(View.OnClickListener { view -> - callback?.onMemberNameClicked(informationData) - })) + .avatarCallback(callback) } private fun linkifyBody(body: CharSequence, callback: TimelineEventController.Callback?): CharSequence { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt index a3f43baf..7749e152 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt @@ -29,6 +29,7 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute import im.vector.riotredesign.R +import im.vector.riotredesign.core.utils.DebouncedClickListener import im.vector.riotredesign.core.utils.DimensionUtils.dpToPx import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController @@ -45,9 +46,6 @@ abstract class AbsMessageItem : BaseEventItem() { @EpoxyAttribute var cellClickListener: View.OnClickListener? = null - @EpoxyAttribute - var avatarClickListener: View.OnClickListener? = null - @EpoxyAttribute var memberClickListener: View.OnClickListener? = null @@ -57,6 +55,17 @@ abstract class AbsMessageItem : BaseEventItem() { @EpoxyAttribute 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 { override fun onReacted(reactionButton: ReactionButton) { reactionPillCallback?.onClickOnReactionPill(informationData, reactionButton.reactionString, true) @@ -81,9 +90,9 @@ abstract class AbsMessageItem : BaseEventItem() { width = size } holder.avatarImageView.visibility = View.VISIBLE - holder.avatarImageView.setOnClickListener(avatarClickListener) + holder.avatarImageView.setOnClickListener(_avatarClickListener) holder.memberNameView.visibility = View.VISIBLE - holder.memberNameView.setOnClickListener(memberClickListener) + holder.memberNameView.setOnClickListener(_memberNameClickListener) holder.timeView.visibility = View.VISIBLE holder.timeView.text = informationData.time holder.memberNameView.text = informationData.memberName diff --git a/vector/src/main/res/layout/item_simple_reaction_info.xml b/vector/src/main/res/layout/item_simple_reaction_info.xml index 0b84aedc..0458b171 100644 --- a/vector/src/main/res/layout/item_simple_reaction_info.xml +++ b/vector/src/main/res/layout/item_simple_reaction_info.xml @@ -11,8 +11,10 @@