Open room member profile from reactions and read receipts. (#990)

Open room member profile from reactions and read receipts. Fixes #875
This commit is contained in:
Onuray Sahin 2020-02-12 17:57:49 +03:00 committed by GitHub
parent 7c5bb4ff5b
commit 6013e1653b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 49 additions and 6 deletions

View file

@ -6,6 +6,7 @@ Features ✨:
Improvements 🙌:
- Show confirmation dialog before deleting a message (#967)
- Open room member profile from reactions list and read receipts list (#875)
Other changes:
-

View file

@ -1045,7 +1045,7 @@ class RoomDetailFragment @Inject constructor(
}
override fun onAvatarClicked(informationData: MessageInformationData) {
// roomDetailViewModel.handle(RoomDetailAction.RequestVerification(informationData.senderId))
// roomDetailViewModel.handle(RoomDetailAction.RequestVerification(informationData.userId))
openRoomMemberProfile(informationData.senderId)
}
@ -1106,7 +1106,7 @@ class RoomDetailFragment @Inject constructor(
private fun handleActions(action: EventSharedAction) {
when (action) {
is EventSharedAction.OpenUserProfile -> {
openRoomMemberProfile(action.senderId)
openRoomMemberProfile(action.userId)
}
is EventSharedAction.AddReaction -> {
startActivityForResult(EmojiReactionPickerActivity.intent(requireContext(), action.eventId), REACTION_SELECT_REQUEST_CODE)

View file

@ -33,6 +33,7 @@ abstract class DisplayReadReceiptItem : EpoxyModelWithHolder<DisplayReadReceiptI
@EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute var timestamp: CharSequence? = null
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute var userClicked: (() -> Unit)? = null
override fun bind(holder: Holder) {
avatarRenderer.render(matrixItem, holder.avatarView)
@ -43,6 +44,7 @@ abstract class DisplayReadReceiptItem : EpoxyModelWithHolder<DisplayReadReceiptI
} ?: run {
holder.timestampView.isVisible = false
}
holder.view.setOnClickListener { userClicked?.invoke() }
}
class Holder : VectorEpoxyHolder() {

View file

@ -27,6 +27,8 @@ import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.riotx.features.home.room.detail.timeline.action.EventSharedAction
import im.vector.riotx.features.home.room.detail.timeline.action.MessageSharedActionViewModel
import im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
@ -40,7 +42,7 @@ data class DisplayReadReceiptArgs(
/**
* Bottom sheet displaying list of read receipts for a given event ordered by descending timestamp
*/
class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment() {
class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment(), DisplayReadReceiptsController.Listener {
@Inject lateinit var epoxyController: DisplayReadReceiptsController
@ -49,6 +51,8 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment() {
private val displayReadReceiptArgs: DisplayReadReceiptArgs by args()
private lateinit var sharedActionViewModel: MessageSharedActionViewModel
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
@ -57,16 +61,23 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
recyclerView.configureWith(epoxyController, hasFixedSize = false)
bottomSheetTitle.text = getString(R.string.seen_by)
epoxyController.listener = this
epoxyController.setData(displayReadReceiptArgs.readReceipts)
}
override fun onDestroyView() {
recyclerView.cleanup()
epoxyController.listener = null
super.onDestroyView()
}
override fun didSelectUser(userId: String) {
sharedActionViewModel.post(EventSharedAction.OpenUserProfile(userId))
}
// we are not using state for this one as it's static, so no need to override invalidate()
companion object {

View file

@ -32,6 +32,8 @@ class DisplayReadReceiptsController @Inject constructor(private val dateFormatte
private val avatarRender: AvatarRenderer)
: TypedEpoxyController<List<ReadReceiptData>>() {
var listener: Listener? = null
override fun buildModels(readReceipts: List<ReadReceiptData>) {
readReceipts.forEach {
val timestamp = dateFormatter.formatRelativeDateTime(it.timestamp)
@ -40,7 +42,12 @@ class DisplayReadReceiptsController @Inject constructor(private val dateFormatte
.matrixItem(it.toMatrixItem())
.avatarRenderer(avatarRender)
.timestamp(timestamp)
.userClicked { listener?.didSelectUser(it.userId) }
.addIf(session.myUserId != it.userId, this)
}
}
interface Listener {
fun didSelectUser(userId: String)
}
}

View file

@ -28,7 +28,7 @@ sealed class EventSharedAction(@StringRes val titleRes: Int,
object Separator :
EventSharedAction(0, 0)
data class OpenUserProfile(val senderId: String) :
data class OpenUserProfile(val userId: String) :
EventSharedAction(0, 0)
data class AddReaction(val eventId: String) :

View file

@ -36,6 +36,8 @@ abstract class ReactionInfoSimpleItem : EpoxyModelWithHolder<ReactionInfoSimpleI
lateinit var authorDisplayName: CharSequence
@EpoxyAttribute
var timeStamp: CharSequence? = null
@EpoxyAttribute
var userClicked: (() -> Unit)? = null
override fun bind(holder: Holder) {
holder.emojiReactionView.text = reactionKey
@ -46,6 +48,7 @@ abstract class ReactionInfoSimpleItem : EpoxyModelWithHolder<ReactionInfoSimpleI
} ?: run {
holder.timeStampView.isVisible = false
}
holder.view.setOnClickListener { userClicked?.invoke() }
}
class Holder : VectorEpoxyHolder() {

View file

@ -27,6 +27,8 @@ import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.riotx.features.home.room.detail.timeline.action.EventSharedAction
import im.vector.riotx.features.home.room.detail.timeline.action.MessageSharedActionViewModel
import im.vector.riotx.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
@ -35,11 +37,12 @@ import javax.inject.Inject
/**
* Bottom sheet displaying list of reactions for a given event ordered by timestamp
*/
class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment() {
class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment(), ViewReactionsEpoxyController.Listener {
private val viewModel: ViewReactionsViewModel by fragmentViewModel(ViewReactionsViewModel::class)
@Inject lateinit var viewReactionsViewModelFactory: ViewReactionsViewModel.Factory
private lateinit var sharedActionViewModel: MessageSharedActionViewModel
@BindView(R.id.bottomSheetRecyclerView)
lateinit var recyclerView: RecyclerView
@ -54,15 +57,22 @@ class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
recyclerView.configureWith(epoxyController, hasFixedSize = false)
bottomSheetTitle.text = context?.getString(R.string.reactions)
epoxyController.listener = this
}
override fun onDestroyView() {
recyclerView.cleanup()
epoxyController.listener = null
super.onDestroyView()
}
override fun didSelectUser(userId: String) {
sharedActionViewModel.post(EventSharedAction.OpenUserProfile(userId))
}
override fun invalidate() = withState(viewModel) {
epoxyController.setData(it)
super.invalidate()

View file

@ -35,6 +35,8 @@ class ViewReactionsEpoxyController @Inject constructor(
private val emojiCompatWrapper: EmojiCompatWrapper)
: TypedEpoxyController<DisplayReactionsViewState>() {
var listener: Listener? = null
override fun buildModels(state: DisplayReactionsViewState) {
when (state.mapReactionKeyToMemberList) {
is Incomplete -> {
@ -55,9 +57,14 @@ class ViewReactionsEpoxyController @Inject constructor(
timeStamp(it.timestamp)
reactionKey(emojiCompatWrapper.safeEmojiSpanify(it.reactionKey))
authorDisplayName(it.authorName ?: it.authorId)
userClicked { listener?.didSelectUser(it.authorId) }
}
}
}
}
}
interface Listener {
fun didSelectUser(userId: String)
}
}

View file

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="40dp"
android:orientation="horizontal"

View file

@ -3,10 +3,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="40dp"
android:orientation="horizontal"
android:paddingStart="8dp"
android:minHeight="40dp"
android:paddingEnd="8dp">
<TextView