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:
parent
7c5bb4ff5b
commit
6013e1653b
@ -6,6 +6,7 @@ Features ✨:
|
|||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
- Show confirmation dialog before deleting a message (#967)
|
- Show confirmation dialog before deleting a message (#967)
|
||||||
|
- Open room member profile from reactions list and read receipts list (#875)
|
||||||
|
|
||||||
Other changes:
|
Other changes:
|
||||||
-
|
-
|
||||||
|
@ -1045,7 +1045,7 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onAvatarClicked(informationData: MessageInformationData) {
|
override fun onAvatarClicked(informationData: MessageInformationData) {
|
||||||
// roomDetailViewModel.handle(RoomDetailAction.RequestVerification(informationData.senderId))
|
// roomDetailViewModel.handle(RoomDetailAction.RequestVerification(informationData.userId))
|
||||||
openRoomMemberProfile(informationData.senderId)
|
openRoomMemberProfile(informationData.senderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1106,7 +1106,7 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
private fun handleActions(action: EventSharedAction) {
|
private fun handleActions(action: EventSharedAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is EventSharedAction.OpenUserProfile -> {
|
is EventSharedAction.OpenUserProfile -> {
|
||||||
openRoomMemberProfile(action.senderId)
|
openRoomMemberProfile(action.userId)
|
||||||
}
|
}
|
||||||
is EventSharedAction.AddReaction -> {
|
is EventSharedAction.AddReaction -> {
|
||||||
startActivityForResult(EmojiReactionPickerActivity.intent(requireContext(), action.eventId), REACTION_SELECT_REQUEST_CODE)
|
startActivityForResult(EmojiReactionPickerActivity.intent(requireContext(), action.eventId), REACTION_SELECT_REQUEST_CODE)
|
||||||
|
@ -33,6 +33,7 @@ abstract class DisplayReadReceiptItem : EpoxyModelWithHolder<DisplayReadReceiptI
|
|||||||
@EpoxyAttribute lateinit var matrixItem: MatrixItem
|
@EpoxyAttribute lateinit var matrixItem: MatrixItem
|
||||||
@EpoxyAttribute var timestamp: CharSequence? = null
|
@EpoxyAttribute var timestamp: CharSequence? = null
|
||||||
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
@EpoxyAttribute var userClicked: (() -> Unit)? = null
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
avatarRenderer.render(matrixItem, holder.avatarView)
|
avatarRenderer.render(matrixItem, holder.avatarView)
|
||||||
@ -43,6 +44,7 @@ abstract class DisplayReadReceiptItem : EpoxyModelWithHolder<DisplayReadReceiptI
|
|||||||
} ?: run {
|
} ?: run {
|
||||||
holder.timestampView.isVisible = false
|
holder.timestampView.isVisible = false
|
||||||
}
|
}
|
||||||
|
holder.view.setOnClickListener { userClicked?.invoke() }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
@ -27,6 +27,8 @@ import im.vector.riotx.core.di.ScreenComponent
|
|||||||
import im.vector.riotx.core.extensions.cleanup
|
import im.vector.riotx.core.extensions.cleanup
|
||||||
import im.vector.riotx.core.extensions.configureWith
|
import im.vector.riotx.core.extensions.configureWith
|
||||||
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
|
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 im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
|
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
|
* 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
|
@Inject lateinit var epoxyController: DisplayReadReceiptsController
|
||||||
|
|
||||||
@ -49,6 +51,8 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
|
|
||||||
private val displayReadReceiptArgs: DisplayReadReceiptArgs by args()
|
private val displayReadReceiptArgs: DisplayReadReceiptArgs by args()
|
||||||
|
|
||||||
|
private lateinit var sharedActionViewModel: MessageSharedActionViewModel
|
||||||
|
|
||||||
override fun injectWith(injector: ScreenComponent) {
|
override fun injectWith(injector: ScreenComponent) {
|
||||||
injector.inject(this)
|
injector.inject(this)
|
||||||
}
|
}
|
||||||
@ -57,16 +61,23 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
||||||
recyclerView.configureWith(epoxyController, hasFixedSize = false)
|
recyclerView.configureWith(epoxyController, hasFixedSize = false)
|
||||||
bottomSheetTitle.text = getString(R.string.seen_by)
|
bottomSheetTitle.text = getString(R.string.seen_by)
|
||||||
|
epoxyController.listener = this
|
||||||
epoxyController.setData(displayReadReceiptArgs.readReceipts)
|
epoxyController.setData(displayReadReceiptArgs.readReceipts)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
recyclerView.cleanup()
|
recyclerView.cleanup()
|
||||||
|
epoxyController.listener = null
|
||||||
super.onDestroyView()
|
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()
|
// we are not using state for this one as it's static, so no need to override invalidate()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -32,6 +32,8 @@ class DisplayReadReceiptsController @Inject constructor(private val dateFormatte
|
|||||||
private val avatarRender: AvatarRenderer)
|
private val avatarRender: AvatarRenderer)
|
||||||
: TypedEpoxyController<List<ReadReceiptData>>() {
|
: TypedEpoxyController<List<ReadReceiptData>>() {
|
||||||
|
|
||||||
|
var listener: Listener? = null
|
||||||
|
|
||||||
override fun buildModels(readReceipts: List<ReadReceiptData>) {
|
override fun buildModels(readReceipts: List<ReadReceiptData>) {
|
||||||
readReceipts.forEach {
|
readReceipts.forEach {
|
||||||
val timestamp = dateFormatter.formatRelativeDateTime(it.timestamp)
|
val timestamp = dateFormatter.formatRelativeDateTime(it.timestamp)
|
||||||
@ -40,7 +42,12 @@ class DisplayReadReceiptsController @Inject constructor(private val dateFormatte
|
|||||||
.matrixItem(it.toMatrixItem())
|
.matrixItem(it.toMatrixItem())
|
||||||
.avatarRenderer(avatarRender)
|
.avatarRenderer(avatarRender)
|
||||||
.timestamp(timestamp)
|
.timestamp(timestamp)
|
||||||
|
.userClicked { listener?.didSelectUser(it.userId) }
|
||||||
.addIf(session.myUserId != it.userId, this)
|
.addIf(session.myUserId != it.userId, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun didSelectUser(userId: String)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ sealed class EventSharedAction(@StringRes val titleRes: Int,
|
|||||||
object Separator :
|
object Separator :
|
||||||
EventSharedAction(0, 0)
|
EventSharedAction(0, 0)
|
||||||
|
|
||||||
data class OpenUserProfile(val senderId: String) :
|
data class OpenUserProfile(val userId: String) :
|
||||||
EventSharedAction(0, 0)
|
EventSharedAction(0, 0)
|
||||||
|
|
||||||
data class AddReaction(val eventId: String) :
|
data class AddReaction(val eventId: String) :
|
||||||
|
@ -36,6 +36,8 @@ abstract class ReactionInfoSimpleItem : EpoxyModelWithHolder<ReactionInfoSimpleI
|
|||||||
lateinit var authorDisplayName: CharSequence
|
lateinit var authorDisplayName: CharSequence
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var timeStamp: CharSequence? = null
|
var timeStamp: CharSequence? = null
|
||||||
|
@EpoxyAttribute
|
||||||
|
var userClicked: (() -> Unit)? = null
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
holder.emojiReactionView.text = reactionKey
|
holder.emojiReactionView.text = reactionKey
|
||||||
@ -46,6 +48,7 @@ abstract class ReactionInfoSimpleItem : EpoxyModelWithHolder<ReactionInfoSimpleI
|
|||||||
} ?: run {
|
} ?: run {
|
||||||
holder.timeStampView.isVisible = false
|
holder.timeStampView.isVisible = false
|
||||||
}
|
}
|
||||||
|
holder.view.setOnClickListener { userClicked?.invoke() }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
@ -27,6 +27,8 @@ import im.vector.riotx.core.di.ScreenComponent
|
|||||||
import im.vector.riotx.core.extensions.cleanup
|
import im.vector.riotx.core.extensions.cleanup
|
||||||
import im.vector.riotx.core.extensions.configureWith
|
import im.vector.riotx.core.extensions.configureWith
|
||||||
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
|
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.action.TimelineEventFragmentArgs
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
|
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
|
* 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)
|
private val viewModel: ViewReactionsViewModel by fragmentViewModel(ViewReactionsViewModel::class)
|
||||||
|
|
||||||
@Inject lateinit var viewReactionsViewModelFactory: ViewReactionsViewModel.Factory
|
@Inject lateinit var viewReactionsViewModelFactory: ViewReactionsViewModel.Factory
|
||||||
|
private lateinit var sharedActionViewModel: MessageSharedActionViewModel
|
||||||
|
|
||||||
@BindView(R.id.bottomSheetRecyclerView)
|
@BindView(R.id.bottomSheetRecyclerView)
|
||||||
lateinit var recyclerView: RecyclerView
|
lateinit var recyclerView: RecyclerView
|
||||||
@ -54,15 +57,22 @@ class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
||||||
recyclerView.configureWith(epoxyController, hasFixedSize = false)
|
recyclerView.configureWith(epoxyController, hasFixedSize = false)
|
||||||
bottomSheetTitle.text = context?.getString(R.string.reactions)
|
bottomSheetTitle.text = context?.getString(R.string.reactions)
|
||||||
|
epoxyController.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
recyclerView.cleanup()
|
recyclerView.cleanup()
|
||||||
|
epoxyController.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun didSelectUser(userId: String) {
|
||||||
|
sharedActionViewModel.post(EventSharedAction.OpenUserProfile(userId))
|
||||||
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) {
|
override fun invalidate() = withState(viewModel) {
|
||||||
epoxyController.setData(it)
|
epoxyController.setData(it)
|
||||||
super.invalidate()
|
super.invalidate()
|
||||||
|
@ -35,6 +35,8 @@ class ViewReactionsEpoxyController @Inject constructor(
|
|||||||
private val emojiCompatWrapper: EmojiCompatWrapper)
|
private val emojiCompatWrapper: EmojiCompatWrapper)
|
||||||
: TypedEpoxyController<DisplayReactionsViewState>() {
|
: TypedEpoxyController<DisplayReactionsViewState>() {
|
||||||
|
|
||||||
|
var listener: Listener? = null
|
||||||
|
|
||||||
override fun buildModels(state: DisplayReactionsViewState) {
|
override fun buildModels(state: DisplayReactionsViewState) {
|
||||||
when (state.mapReactionKeyToMemberList) {
|
when (state.mapReactionKeyToMemberList) {
|
||||||
is Incomplete -> {
|
is Incomplete -> {
|
||||||
@ -55,9 +57,14 @@ class ViewReactionsEpoxyController @Inject constructor(
|
|||||||
timeStamp(it.timestamp)
|
timeStamp(it.timestamp)
|
||||||
reactionKey(emojiCompatWrapper.safeEmojiSpanify(it.reactionKey))
|
reactionKey(emojiCompatWrapper.safeEmojiSpanify(it.reactionKey))
|
||||||
authorDisplayName(it.authorName ?: it.authorId)
|
authorDisplayName(it.authorName ?: it.authorId)
|
||||||
|
userClicked { listener?.didSelectUser(it.authorId) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun didSelectUser(userId: String)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:minHeight="40dp"
|
android:minHeight="40dp"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="40dp"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="8dp"
|
android:paddingStart="8dp"
|
||||||
android:minHeight="40dp"
|
|
||||||
android:paddingEnd="8dp">
|
android:paddingEnd="8dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
Loading…
x
Reference in New Issue
Block a user